Compare commits

...

6 Commits

Author SHA1 Message Date
root
e3c445bbeb auto-repair: commit 3 uncommitted file(s) — 2026-05-20 2026-05-20 06:00:03 +00:00
Claude Opus 4.6
fe5896be2d feat: initial Telepathy Elixir port — GenServer + JMAP fetch loop
Adds the Telepathy email communication layer as an OTP subtree:

- Telepathy.JMAP: GenServer that discovers Fastmail JMAP session,
  periodically polls inbox for new emails, and provides send_email/3.
  Uses :httpc (no external HTTP dep). Deduplicates via seen_ids MapSet
  seeded from existing MessageStore entries.

- Telepathy.MessageStore: JSONL-backed message persistence, compatible
  with the existing Python messages.jsonl format. Supports store, unread,
  mark_read, list, count operations.

- Telepathy.Supervisor: rest_for_one supervisor (MessageStore then JMAP).

- Conditionally enabled via config (:telepathy, :enabled). Disabled in
  test env. Can be disabled at runtime via TELEPATHY_ENABLED=false.

Validated against live Fastmail: session discovery, inbox fetch (20
emails), message storage all working.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-19 06:11:13 +00:00
Claude Opus 4.6
244feb4d7e application: add graceful shutdown config for Bandit
Configures Bandit with 615s drain timeout and 620s OTP shutdown window
so in-flight Claude CLI calls (up to 600s) complete before systemd kills
the process on restart.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 21:31:47 +00:00
Claude Opus 4.6
11a9026597 heartbeat: notify Michael by email when each queued task completes
Adds notify_task_complete/3 called after every queue task resolves
(done, blocked, or failed). Posts to Telepathy's POST /email endpoint.
Also adds :inets and :ssl to extra_applications so :httpc is available.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 21:21:49 +00:00
Amp YOLO
6271e973a6 queue+heartbeat: distinguish blocked from done (fix the false-done bug)
Long-standing complement to the 767ab4d dispatcher fix. Even with
permissions unblocked, the model can still self-report obstacles
(refusals, missing services, runtime errors) by returning prose
like I need permission... or could you approve.... The
previous heartbeat marked any successful CLI call as done
regardless of what the text said, so blocked tasks vanished from
visibility and identical intents re-queued day after day.

Changes:

- Queue: new block/2 client function + handle_cast({:block, ...})
  mirroring the existing complete/fail pair. Adds a third terminal
  state blocked alongside done/failed. Persists the model output
  text as result so callers (sitrep, reflection) can see what the
  obstacle actually was.

- Heartbeat.process_queue: on dispatcher success, classify the
  result string with blocked_result?/1. The heuristic is
  conservative — only explicit opening-position self-reports in
  the first 400 chars (I need permission, I am unable to,
  permission denied, blocked on writes, etc.). Anything else
  defaults to done. Routes through Queue.block instead of
  Queue.complete when matched, with a warning log.

- Tests: added block marks a task as blocked test alongside
  existing fail test in queue_test.exs. 9/9 queue tests + 39/39
  full suite green.

Pending tasks counter (Queue.size/0) still counts only pending,
so blocked tasks do not re-trigger Heartbeat processing — they
sit terminal until something explicitly re-queues the intent.
This is the right behavior: avoid the loop, surface the obstacle.
2026-05-16 23:08:46 +00:00
Amp YOLO
e70916102c build: untrack _build/ and deps/ (already in .gitignore)
Build artifacts and downloaded deps were committed before .gitignore
existed and have stayed tracked since. Any recompile (like yesterdays
dispatcher fix landing) dirties them and the next morning auto-repair
commits the BEAM diff as if it were work. git rm -r --cached makes
the existing .gitignore actually do its job.
2026-05-16 22:53:02 +00:00
996 changed files with 844 additions and 32285 deletions

View File

@ -1 +0,0 @@
{application,bandit,[{modules,['Elixir.Bandit','Elixir.Bandit.Adapter','Elixir.Bandit.Application','Elixir.Bandit.Clock','Elixir.Bandit.Compression','Elixir.Bandit.DelegatingHandler','Elixir.Bandit.Extractor','Elixir.Bandit.HTTP1.Handler','Elixir.Bandit.HTTP1.Socket','Elixir.Bandit.HTTP2.Connection','Elixir.Bandit.HTTP2.Errors','Elixir.Bandit.HTTP2.Errors.ConnectionError','Elixir.Bandit.HTTP2.Errors.StreamError','Elixir.Bandit.HTTP2.FlowControl','Elixir.Bandit.HTTP2.Frame','Elixir.Bandit.HTTP2.Frame.Continuation','Elixir.Bandit.HTTP2.Frame.Data','Elixir.Bandit.HTTP2.Frame.Flags','Elixir.Bandit.HTTP2.Frame.Goaway','Elixir.Bandit.HTTP2.Frame.Headers','Elixir.Bandit.HTTP2.Frame.Ping','Elixir.Bandit.HTTP2.Frame.Priority','Elixir.Bandit.HTTP2.Frame.PushPromise','Elixir.Bandit.HTTP2.Frame.RstStream','Elixir.Bandit.HTTP2.Frame.Serializable','Elixir.Bandit.HTTP2.Frame.Serializable.Bandit.HTTP2.Frame.Continuation','Elixir.Bandit.HTTP2.Frame.Serializable.Bandit.HTTP2.Frame.Data','Elixir.Bandit.HTTP2.Frame.Serializable.Bandit.HTTP2.Frame.Goaway','Elixir.Bandit.HTTP2.Frame.Serializable.Bandit.HTTP2.Frame.Headers','Elixir.Bandit.HTTP2.Frame.Serializable.Bandit.HTTP2.Frame.Ping','Elixir.Bandit.HTTP2.Frame.Serializable.Bandit.HTTP2.Frame.Priority','Elixir.Bandit.HTTP2.Frame.Serializable.Bandit.HTTP2.Frame.RstStream','Elixir.Bandit.HTTP2.Frame.Serializable.Bandit.HTTP2.Frame.Settings','Elixir.Bandit.HTTP2.Frame.Serializable.Bandit.HTTP2.Frame.WindowUpdate','Elixir.Bandit.HTTP2.Frame.Settings','Elixir.Bandit.HTTP2.Frame.Unknown','Elixir.Bandit.HTTP2.Frame.WindowUpdate','Elixir.Bandit.HTTP2.Handler','Elixir.Bandit.HTTP2.Settings','Elixir.Bandit.HTTP2.Stream','Elixir.Bandit.HTTP2.StreamCollection','Elixir.Bandit.HTTP2.StreamProcess','Elixir.Bandit.HTTPError','Elixir.Bandit.HTTPTransport','Elixir.Bandit.HTTPTransport.Bandit.HTTP1.Socket','Elixir.Bandit.HTTPTransport.Bandit.HTTP2.Stream','Elixir.Bandit.Headers','Elixir.Bandit.InitialHandler','Elixir.Bandit.Logger','Elixir.Bandit.PhoenixAdapter','Elixir.Bandit.Pipeline','Elixir.Bandit.PrimitiveOps.WebSocket','Elixir.Bandit.SocketHelpers','Elixir.Bandit.Telemetry','Elixir.Bandit.Trace','Elixir.Bandit.TransportError','Elixir.Bandit.WebSocket.Connection','Elixir.Bandit.WebSocket.Frame','Elixir.Bandit.WebSocket.Frame.Binary','Elixir.Bandit.WebSocket.Frame.ConnectionClose','Elixir.Bandit.WebSocket.Frame.Continuation','Elixir.Bandit.WebSocket.Frame.Ping','Elixir.Bandit.WebSocket.Frame.Pong','Elixir.Bandit.WebSocket.Frame.Serializable','Elixir.Bandit.WebSocket.Frame.Serializable.Bandit.WebSocket.Frame.Binary','Elixir.Bandit.WebSocket.Frame.Serializable.Bandit.WebSocket.Frame.ConnectionClose','Elixir.Bandit.WebSocket.Frame.Serializable.Bandit.WebSocket.Frame.Continuation','Elixir.Bandit.WebSocket.Frame.Serializable.Bandit.WebSocket.Frame.Ping','Elixir.Bandit.WebSocket.Frame.Serializable.Bandit.WebSocket.Frame.Pong','Elixir.Bandit.WebSocket.Frame.Serializable.Bandit.WebSocket.Frame.Text','Elixir.Bandit.WebSocket.Frame.Text','Elixir.Bandit.WebSocket.Handler','Elixir.Bandit.WebSocket.Handshake','Elixir.Bandit.WebSocket.PerMessageDeflate','Elixir.Bandit.WebSocket.Socket','Elixir.Bandit.WebSocket.Socket.ThousandIsland.Socket','Elixir.Bandit.WebSocket.UpgradeValidation']},{optional_applications,[]},{applications,[kernel,stdlib,elixir,logger,thousand_island,plug,websock,hpax,telemetry]},{description,"A pure-Elixir HTTP server built for Plug & WebSock apps"},{registered,[]},{vsn,"1.10.3"},{mod,{'Elixir.Bandit.Application',[]}}]}.

View File

@ -1 +0,0 @@
{application,hpax,[{modules,['Elixir.HPAX','Elixir.HPAX.Huffman','Elixir.HPAX.Table','Elixir.HPAX.Types']},{optional_applications,[]},{applications,[kernel,stdlib,elixir]},{description,"Implementation of the HPACK protocol (RFC 7541) for Elixir"},{registered,[]},{vsn,"1.0.3"}]}.

Some files were not shown because too many files have changed in this diff Show More