Commit Graph

10 Commits

Author SHA1 Message Date
steve 76ada04442 refactor(cli): wire commandRole into dispatch; doc + comment cleanup
Resolve final-review findings: commandRole is now the single source of
truth (Run resolves role once and threads it to handlers, replacing
hardcoded openStore roles). Tighten crypto/SKILL/SPEC/USER-MANUAL wording
and document init's agent-key-on-first-init-only semantics.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 07:18:27 +01:00
steve add9515b5c docs: document two-key privilege model
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 23:11:18 +01:00
steve a837b25d73 feat(admin): Phase 4 — doctor, admin completeness, and bubbletea TUI
Adds the admin/diagnostics surface from SPEC §7.2:

- doctor [--account]: per-account IMAP + (RW) SMTP connectivity/auth checks via
  new mail.CheckIMAP/CheckSMTP (connect+auth only, no mail). Exit non-zero on any
  failure; secrets never printed.
- store.UpdateAccount: partial edit, re-encrypts password/secrets only when a
  non-empty value is supplied (blank keeps existing). RecentAuditFor(account).
- config set/get (validates audit_retention_days), audit list [--account][--limit],
  account edit (flag partial-update) / remove [--yes].
- internal/tui: bubbletea AccountForm with pure, fully-tested Fields (validation +
  store.Account assembly + edit prefill). init / bare `account add` / `account edit
  --name X` drop into the TUI; flag forms remain for scripting.

Built test-first; full suite green incl -race. Validated live against the mxlogin
(password) and Gmail (app-password) accounts. Live validation caught a real bug:
doctor authenticated with empty passwords because it iterated ListAccounts (which
strips secrets) — fixed to re-fetch via GetAccount, locked in by a regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:09:43 +01:00
steve 193815dd25 docs: Phase 3 decision — Gmail via app password; OAuth2 deferred
Evaluated OAuth2 (SPEC §10) and chose not to build it this phase. A self-built,
unverified OAuth app suffers Google's 7-day refresh-token expiry in Testing
status (or the unverified-warning + restricted-scope verification cost in
Production). For a single-user personal tool, a Gmail App Password (2FA) is
strictly simpler and reuses the IMAP/SMTP password auth from Phases 1–2.

Validated live against a real Gmail account over app-password auth: list/get/
search, send, and a full SMTP-out → IMAP-in round-trip. No code changes were
required; the speculative OAuth store fields started mid-session were reverted.
OAuth2 remains a clean future addition (schema columns already present).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:16:20 +01:00
steve c99eaedafd feat(send): Phase 2 send path — SMTP, MIME, reply threading, outbound policy
Adds the `send` agent command and everything behind it:

- store: Account carries SMTP host/port/security (NULL-safe scan/insert/select);
  admin `account add` gains --smtp-* flags (applied for RW accounts).
- policy: OutboundRule.Check(recipients) → (ok, reason); RO ⇒ ro_mode,
  whitelist-out blocks the whole send if any recipient fails (no partial send).
- mail: Header.References; OutgoingMessage + BuildMIME (plain text + attachments,
  In-Reply-To/References threading, Bcc envelope-only); SendSMTP (tls/starttls,
  SASL PLAIN, envelope send) via emersion/go-smtp.
- cli: SendCmd gates outbound, resolves --reply-to under the inbound filter
  (filtered/absent source ⇒ not_found), reads attachments, audits, emits the
  JSON envelope; repeatable --to/--cc/--bcc/--attach flags wired into the router.

Implemented test-first; full suite passes incl -race. Validated live against
friday.mxlogin.com: real send to me@stevecliff.com, RO + whitelist-out blocks,
and --reply-to threading off a live INBOX message. test-creds.md gitignored.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 17:39:07 +01:00
steve 3224a87b6e docs: status report — live validation done, header-only fetch resolved
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 07:52:42 +01:00
steve a1440719ae docs: Phase 1 status report
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 00:19:05 +01:00
steve 04d3b61bb0 Plan: Phase 1 — foundation & read path implementation plan
TDD task-by-task plan for the read-only emcli: crypto, encrypted store,
seen-set read state, policy filtering, IMAP read, and the agent
list/get/search/ack commands with flag-based admin. Phases 2-4 (send,
OAuth2, TUI) to follow as their own plans.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 21:17:29 +01:00
steve e3f8afbc7c Spec: replace read pointer with per-message seen-set model
Reading state is now a per-(account,folder) floor plus an acked set of
UIDs above it, instead of a single monotonic pointer. This makes
acknowledgement per-message and order-independent so concurrent
subagents can process and ack out of order. Internal compaction collapses
contiguous acked runs into the floor to bound storage. Adds stateless
search and ack commands; reads no longer mutate state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 21:01:34 +01:00
steve 79b62b24c2 Initial commit: PRD and SPEC for emcli
emcli is a Go CLI that mediates an AI agent's email access, enforcing
per-account read/send restrictions so credentials never reach the agent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:36:13 +01:00