@cluesmith/codev 3.2.3 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard-dist/assets/index-BZRTEMtH.css +32 -0
- package/dashboard-dist/assets/{index-BZ1x7x1X.js → index-JCbkpAcV.js} +33 -33
- package/dashboard-dist/assets/index-JCbkpAcV.js.map +1 -0
- package/dashboard-dist/index.html +2 -2
- package/dist/agent-farm/cli.d.ts.map +1 -1
- package/dist/agent-farm/cli.js +173 -0
- package/dist/agent-farm/cli.js.map +1 -1
- package/dist/agent-farm/commands/attach.js +2 -2
- package/dist/agent-farm/commands/attach.js.map +1 -1
- package/dist/agent-farm/commands/cleanup.d.ts.map +1 -1
- package/dist/agent-farm/commands/cleanup.js +16 -0
- package/dist/agent-farm/commands/cleanup.js.map +1 -1
- package/dist/agent-farm/commands/inbox.d.ts +42 -0
- package/dist/agent-farm/commands/inbox.d.ts.map +1 -0
- package/dist/agent-farm/commands/inbox.js +129 -0
- package/dist/agent-farm/commands/inbox.js.map +1 -0
- package/dist/agent-farm/commands/interrupt.d.ts +20 -0
- package/dist/agent-farm/commands/interrupt.d.ts.map +1 -0
- package/dist/agent-farm/commands/interrupt.js +65 -0
- package/dist/agent-farm/commands/interrupt.js.map +1 -0
- package/dist/agent-farm/commands/reset/constants.d.ts +52 -0
- package/dist/agent-farm/commands/reset/constants.d.ts.map +1 -0
- package/dist/agent-farm/commands/reset/constants.js +52 -0
- package/dist/agent-farm/commands/reset/constants.js.map +1 -0
- package/dist/agent-farm/commands/reset/context.d.ts +230 -0
- package/dist/agent-farm/commands/reset/context.d.ts.map +1 -0
- package/dist/agent-farm/commands/reset/context.js +428 -0
- package/dist/agent-farm/commands/reset/context.js.map +1 -0
- package/dist/agent-farm/commands/reset/index.d.ts +192 -0
- package/dist/agent-farm/commands/reset/index.d.ts.map +1 -0
- package/dist/agent-farm/commands/reset/index.js +488 -0
- package/dist/agent-farm/commands/reset/index.js.map +1 -0
- package/dist/agent-farm/commands/reset/receipt.d.ts +97 -0
- package/dist/agent-farm/commands/reset/receipt.d.ts.map +1 -0
- package/dist/agent-farm/commands/reset/receipt.js +149 -0
- package/dist/agent-farm/commands/reset/receipt.js.map +1 -0
- package/dist/agent-farm/commands/reset/reorient.d.ts +117 -0
- package/dist/agent-farm/commands/reset/reorient.d.ts.map +1 -0
- package/dist/agent-farm/commands/reset/reorient.js +313 -0
- package/dist/agent-farm/commands/reset/reorient.js.map +1 -0
- package/dist/agent-farm/commands/reset.d.ts +19 -0
- package/dist/agent-farm/commands/reset.d.ts.map +1 -0
- package/dist/agent-farm/commands/reset.js +292 -0
- package/dist/agent-farm/commands/reset.js.map +1 -0
- package/dist/agent-farm/commands/send.d.ts +2 -2
- package/dist/agent-farm/commands/send.d.ts.map +1 -1
- package/dist/agent-farm/commands/send.js +52 -11
- package/dist/agent-farm/commands/send.js.map +1 -1
- package/dist/agent-farm/commands/setup.d.ts +4 -1
- package/dist/agent-farm/commands/setup.d.ts.map +1 -1
- package/dist/agent-farm/commands/setup.js +8 -4
- package/dist/agent-farm/commands/setup.js.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.d.ts +116 -6
- package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.js +345 -74
- package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
- package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn.js +13 -1
- package/dist/agent-farm/commands/spawn.js.map +1 -1
- package/dist/agent-farm/commands/status.d.ts.map +1 -1
- package/dist/agent-farm/commands/status.js +105 -9
- package/dist/agent-farm/commands/status.js.map +1 -1
- package/dist/agent-farm/commands/tower-sweep-husks.d.ts +6 -0
- package/dist/agent-farm/commands/tower-sweep-husks.d.ts.map +1 -0
- package/dist/agent-farm/commands/tower-sweep-husks.js +77 -0
- package/dist/agent-farm/commands/tower-sweep-husks.js.map +1 -0
- package/dist/agent-farm/commands/tower.d.ts.map +1 -1
- package/dist/agent-farm/commands/tower.js +34 -0
- package/dist/agent-farm/commands/tower.js.map +1 -1
- package/dist/agent-farm/commands/whoami.d.ts +65 -0
- package/dist/agent-farm/commands/whoami.d.ts.map +1 -0
- package/dist/agent-farm/commands/whoami.js +196 -0
- package/dist/agent-farm/commands/whoami.js.map +1 -0
- package/dist/agent-farm/db/index.d.ts +1 -1
- package/dist/agent-farm/db/index.d.ts.map +1 -1
- package/dist/agent-farm/db/index.js +80 -1
- package/dist/agent-farm/db/index.js.map +1 -1
- package/dist/agent-farm/db/mailbox.d.ts +222 -0
- package/dist/agent-farm/db/mailbox.d.ts.map +1 -0
- package/dist/agent-farm/db/mailbox.js +304 -0
- package/dist/agent-farm/db/mailbox.js.map +1 -0
- package/dist/agent-farm/db/schema.d.ts +1 -1
- package/dist/agent-farm/db/schema.d.ts.map +1 -1
- package/dist/agent-farm/db/schema.js +35 -0
- package/dist/agent-farm/db/schema.js.map +1 -1
- package/dist/agent-farm/db/types.d.ts +45 -0
- package/dist/agent-farm/db/types.d.ts.map +1 -1
- package/dist/agent-farm/db/types.js.map +1 -1
- package/dist/agent-farm/lib/builder-lookup.d.ts +1 -1
- package/dist/agent-farm/lib/builder-lookup.js +2 -2
- package/dist/agent-farm/lib/builder-lookup.js.map +1 -1
- package/dist/agent-farm/lib/reconnect-backoff.d.ts +54 -0
- package/dist/agent-farm/lib/reconnect-backoff.d.ts.map +1 -0
- package/dist/agent-farm/lib/reconnect-backoff.js +47 -0
- package/dist/agent-farm/lib/reconnect-backoff.js.map +1 -0
- package/dist/agent-farm/lib/tower-client.d.ts +16 -6
- package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
- package/dist/agent-farm/lib/tower-client.js +37 -6
- package/dist/agent-farm/lib/tower-client.js.map +1 -1
- package/dist/agent-farm/lib/tunnel-client.d.ts +69 -1
- package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -1
- package/dist/agent-farm/lib/tunnel-client.js +218 -27
- package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
- package/dist/agent-farm/servers/architect-session-holder.d.ts +133 -0
- package/dist/agent-farm/servers/architect-session-holder.d.ts.map +1 -0
- package/dist/agent-farm/servers/architect-session-holder.js +268 -0
- package/dist/agent-farm/servers/architect-session-holder.js.map +1 -0
- package/dist/agent-farm/servers/cron-delivery.d.ts +72 -0
- package/dist/agent-farm/servers/cron-delivery.d.ts.map +1 -0
- package/dist/agent-farm/servers/cron-delivery.js +80 -0
- package/dist/agent-farm/servers/cron-delivery.js.map +1 -0
- package/dist/agent-farm/servers/delayed-send.d.ts +85 -0
- package/dist/agent-farm/servers/delayed-send.d.ts.map +1 -0
- package/dist/agent-farm/servers/delayed-send.js +165 -0
- package/dist/agent-farm/servers/delayed-send.js.map +1 -0
- package/dist/agent-farm/servers/gate-profiles.d.ts +67 -0
- package/dist/agent-farm/servers/gate-profiles.d.ts.map +1 -0
- package/dist/agent-farm/servers/gate-profiles.js +113 -0
- package/dist/agent-farm/servers/gate-profiles.js.map +1 -0
- package/dist/agent-farm/servers/mailbox-delivery.d.ts +370 -0
- package/dist/agent-farm/servers/mailbox-delivery.d.ts.map +1 -0
- package/dist/agent-farm/servers/mailbox-delivery.js +617 -0
- package/dist/agent-farm/servers/mailbox-delivery.js.map +1 -0
- package/dist/agent-farm/servers/mailbox-wiring.d.ts +125 -0
- package/dist/agent-farm/servers/mailbox-wiring.d.ts.map +1 -0
- package/dist/agent-farm/servers/mailbox-wiring.js +425 -0
- package/dist/agent-farm/servers/mailbox-wiring.js.map +1 -0
- package/dist/agent-farm/servers/message-write.d.ts +53 -1
- package/dist/agent-farm/servers/message-write.d.ts.map +1 -1
- package/dist/agent-farm/servers/message-write.js +63 -0
- package/dist/agent-farm/servers/message-write.js.map +1 -1
- package/dist/agent-farm/servers/overview.d.ts.map +1 -1
- package/dist/agent-farm/servers/overview.js +23 -4
- package/dist/agent-farm/servers/overview.js.map +1 -1
- package/dist/agent-farm/servers/process-census.d.ts +41 -0
- package/dist/agent-farm/servers/process-census.d.ts.map +1 -0
- package/dist/agent-farm/servers/process-census.js +62 -0
- package/dist/agent-farm/servers/process-census.js.map +1 -0
- package/dist/agent-farm/servers/render-gate.d.ts +141 -0
- package/dist/agent-farm/servers/render-gate.d.ts.map +1 -0
- package/dist/agent-farm/servers/render-gate.js +251 -0
- package/dist/agent-farm/servers/render-gate.js.map +1 -0
- package/dist/agent-farm/servers/session-log-sweep.d.ts +93 -0
- package/dist/agent-farm/servers/session-log-sweep.d.ts.map +1 -0
- package/dist/agent-farm/servers/session-log-sweep.js +165 -0
- package/dist/agent-farm/servers/session-log-sweep.js.map +1 -0
- package/dist/agent-farm/servers/session-submit.d.ts +90 -0
- package/dist/agent-farm/servers/session-submit.d.ts.map +1 -0
- package/dist/agent-farm/servers/session-submit.js +127 -0
- package/dist/agent-farm/servers/session-submit.js.map +1 -0
- package/dist/agent-farm/servers/shellper-husk-sweep.d.ts +87 -0
- package/dist/agent-farm/servers/shellper-husk-sweep.d.ts.map +1 -0
- package/dist/agent-farm/servers/shellper-husk-sweep.js +129 -0
- package/dist/agent-farm/servers/shellper-husk-sweep.js.map +1 -0
- package/dist/agent-farm/servers/tower-cron.d.ts +10 -7
- package/dist/agent-farm/servers/tower-cron.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-cron.js +58 -53
- package/dist/agent-farm/servers/tower-cron.js.map +1 -1
- package/dist/agent-farm/servers/tower-instances.d.ts +14 -2
- package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-instances.js +128 -19
- package/dist/agent-farm/servers/tower-instances.js.map +1 -1
- package/dist/agent-farm/servers/tower-messages.d.ts +38 -1
- package/dist/agent-farm/servers/tower-messages.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-messages.js +106 -1
- package/dist/agent-farm/servers/tower-messages.js.map +1 -1
- package/dist/agent-farm/servers/tower-routes.d.ts +16 -4
- package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-routes.js +807 -99
- package/dist/agent-farm/servers/tower-routes.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +241 -15
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.d.ts +17 -2
- package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.js +139 -124
- package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
- package/dist/agent-farm/servers/tower-tunnel.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-tunnel.js +63 -4
- package/dist/agent-farm/servers/tower-tunnel.js.map +1 -1
- package/dist/agent-farm/servers/tower-types.d.ts +2 -1
- package/dist/agent-farm/servers/tower-types.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-utils.d.ts +99 -1
- package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-utils.js +242 -6
- package/dist/agent-farm/servers/tower-utils.js.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.js +6 -21
- package/dist/agent-farm/servers/tower-websocket.js.map +1 -1
- package/dist/agent-farm/servers/write-queue.d.ts +35 -0
- package/dist/agent-farm/servers/write-queue.d.ts.map +1 -0
- package/dist/agent-farm/servers/write-queue.js +56 -0
- package/dist/agent-farm/servers/write-queue.js.map +1 -0
- package/dist/agent-farm/state.d.ts +6 -1
- package/dist/agent-farm/state.d.ts.map +1 -1
- package/dist/agent-farm/state.js +5 -2
- package/dist/agent-farm/state.js.map +1 -1
- package/dist/agent-farm/types.d.ts +39 -0
- package/dist/agent-farm/types.d.ts.map +1 -1
- package/dist/agent-farm/utils/agent-names.d.ts +2 -2
- package/dist/agent-farm/utils/agent-names.d.ts.map +1 -1
- package/dist/agent-farm/utils/agent-names.js +3 -3
- package/dist/agent-farm/utils/agent-names.js.map +1 -1
- package/dist/agent-farm/utils/architect-name.d.ts +2 -2
- package/dist/agent-farm/utils/architect-name.d.ts.map +1 -1
- package/dist/agent-farm/utils/architect-name.js +3 -3
- package/dist/agent-farm/utils/architect-name.js.map +1 -1
- package/dist/agent-farm/utils/config.d.ts +13 -0
- package/dist/agent-farm/utils/config.d.ts.map +1 -1
- package/dist/agent-farm/utils/config.js +33 -1
- package/dist/agent-farm/utils/config.js.map +1 -1
- package/dist/agent-farm/utils/harness.d.ts +103 -7
- package/dist/agent-farm/utils/harness.d.ts.map +1 -1
- package/dist/agent-farm/utils/harness.js +126 -19
- package/dist/agent-farm/utils/harness.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -32
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt.d.ts +3 -2
- package/dist/commands/adopt.d.ts.map +1 -1
- package/dist/commands/adopt.js +7 -6
- package/dist/commands/adopt.js.map +1 -1
- package/dist/commands/consult/agy-auth-cache.d.ts +97 -0
- package/dist/commands/consult/agy-auth-cache.d.ts.map +1 -0
- package/dist/commands/consult/agy-auth-cache.js +320 -0
- package/dist/commands/consult/agy-auth-cache.js.map +1 -0
- package/dist/commands/consult/cli-options.d.ts +34 -0
- package/dist/commands/consult/cli-options.d.ts.map +1 -0
- package/dist/commands/consult/cli-options.js +67 -0
- package/dist/commands/consult/cli-options.js.map +1 -0
- package/dist/commands/consult/index.d.ts +56 -2
- package/dist/commands/consult/index.d.ts.map +1 -1
- package/dist/commands/consult/index.js +330 -27
- package/dist/commands/consult/index.js.map +1 -1
- package/dist/commands/consult/metrics.d.ts +42 -0
- package/dist/commands/consult/metrics.d.ts.map +1 -1
- package/dist/commands/consult/metrics.js +129 -9
- package/dist/commands/consult/metrics.js.map +1 -1
- package/dist/commands/doctor.d.ts +28 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +258 -22
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts +3 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +7 -6
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/porch/checks.d.ts +23 -0
- package/dist/commands/porch/checks.d.ts.map +1 -1
- package/dist/commands/porch/checks.js +60 -0
- package/dist/commands/porch/checks.js.map +1 -1
- package/dist/commands/porch/config.d.ts +20 -0
- package/dist/commands/porch/config.d.ts.map +1 -1
- package/dist/commands/porch/config.js +20 -0
- package/dist/commands/porch/config.js.map +1 -1
- package/dist/commands/porch/index.d.ts.map +1 -1
- package/dist/commands/porch/index.js +32 -36
- package/dist/commands/porch/index.js.map +1 -1
- package/dist/commands/porch/next.d.ts.map +1 -1
- package/dist/commands/porch/next.js +2 -41
- package/dist/commands/porch/next.js.map +1 -1
- package/dist/commands/update.d.ts +4 -4
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +9 -11
- package/dist/commands/update.js.map +1 -1
- package/dist/lib/config.d.ts +70 -3
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +67 -3
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/consult-lanes.d.ts +149 -0
- package/dist/lib/consult-lanes.d.ts.map +1 -0
- package/dist/lib/consult-lanes.js +360 -0
- package/dist/lib/consult-lanes.js.map +1 -0
- package/dist/lib/default-branch.d.ts +1 -1
- package/dist/lib/default-branch.js +1 -1
- package/dist/lib/github.js +1 -1
- package/dist/lib/github.js.map +1 -1
- package/dist/lib/gitignore.d.ts +25 -2
- package/dist/lib/gitignore.d.ts.map +1 -1
- package/dist/lib/gitignore.js +70 -0
- package/dist/lib/gitignore.js.map +1 -1
- package/dist/lib/migration-backup-audit.d.ts +64 -0
- package/dist/lib/migration-backup-audit.d.ts.map +1 -0
- package/dist/lib/migration-backup-audit.js +145 -0
- package/dist/lib/migration-backup-audit.js.map +1 -0
- package/dist/lib/prompt-behavior-metrics.d.ts +67 -0
- package/dist/lib/prompt-behavior-metrics.d.ts.map +1 -0
- package/dist/lib/prompt-behavior-metrics.js +290 -0
- package/dist/lib/prompt-behavior-metrics.js.map +1 -0
- package/dist/lib/protocol-drift-audit.d.ts +118 -0
- package/dist/lib/protocol-drift-audit.d.ts.map +1 -0
- package/dist/lib/protocol-drift-audit.js +217 -0
- package/dist/lib/protocol-drift-audit.js.map +1 -0
- package/dist/lib/scaffold.d.ts +10 -3
- package/dist/lib/scaffold.d.ts.map +1 -1
- package/dist/lib/scaffold.js +29 -26
- package/dist/lib/scaffold.js.map +1 -1
- package/dist/lib/skeleton.d.ts +22 -1
- package/dist/lib/skeleton.d.ts.map +1 -1
- package/dist/lib/skeleton.js +120 -0
- package/dist/lib/skeleton.js.map +1 -1
- package/dist/lib/test-env.d.ts +74 -0
- package/dist/lib/test-env.d.ts.map +1 -0
- package/dist/lib/test-env.js +92 -0
- package/dist/lib/test-env.js.map +1 -0
- package/dist/terminal/pty-manager.d.ts +9 -0
- package/dist/terminal/pty-manager.d.ts.map +1 -1
- package/dist/terminal/pty-manager.js +32 -6
- package/dist/terminal/pty-manager.js.map +1 -1
- package/dist/terminal/pty-session.d.ts +156 -4
- package/dist/terminal/pty-session.d.ts.map +1 -1
- package/dist/terminal/pty-session.js +307 -42
- package/dist/terminal/pty-session.js.map +1 -1
- package/dist/terminal/ring-buffer.d.ts +39 -6
- package/dist/terminal/ring-buffer.d.ts.map +1 -1
- package/dist/terminal/ring-buffer.js +74 -6
- package/dist/terminal/ring-buffer.js.map +1 -1
- package/dist/terminal/session-manager.d.ts +129 -0
- package/dist/terminal/session-manager.d.ts.map +1 -1
- package/dist/terminal/session-manager.js +337 -44
- package/dist/terminal/session-manager.js.map +1 -1
- package/dist/terminal/session-screen.d.ts +91 -0
- package/dist/terminal/session-screen.d.ts.map +1 -0
- package/dist/terminal/session-screen.js +135 -0
- package/dist/terminal/session-screen.js.map +1 -0
- package/dist/terminal/shellper-client.d.ts +19 -4
- package/dist/terminal/shellper-client.d.ts.map +1 -1
- package/dist/terminal/shellper-client.js +70 -8
- package/dist/terminal/shellper-client.js.map +1 -1
- package/dist/terminal/shellper-main.js +2 -1
- package/dist/terminal/shellper-main.js.map +1 -1
- package/dist/terminal/shellper-process.d.ts +1 -1
- package/dist/terminal/shellper-process.d.ts.map +1 -1
- package/dist/terminal/shellper-process.js +33 -9
- package/dist/terminal/shellper-process.js.map +1 -1
- package/dist/terminal/shellper-protocol.d.ts +40 -2
- package/dist/terminal/shellper-protocol.d.ts.map +1 -1
- package/dist/terminal/shellper-protocol.js +72 -5
- package/dist/terminal/shellper-protocol.js.map +1 -1
- package/dist/terminal/shellper-replay-buffer.d.ts +69 -7
- package/dist/terminal/shellper-replay-buffer.d.ts.map +1 -1
- package/dist/terminal/shellper-replay-buffer.js +167 -31
- package/dist/terminal/shellper-replay-buffer.js.map +1 -1
- package/package.json +11 -9
- package/skeleton/.claude/skills/afx/SKILL.md +27 -1
- package/skeleton/.claude/skills/arch-init/SKILL.md +135 -0
- package/skeleton/.claude/skills/arch-save/SKILL.md +183 -0
- package/skeleton/.claude/skills/codev/SKILL.md +33 -2
- package/skeleton/.claude/skills/runnable-worktrees/SKILL.md +119 -0
- package/skeleton/.codex/skills/afx/SKILL.md +170 -0
- package/skeleton/.codex/skills/arch-init/SKILL.md +135 -0
- package/skeleton/.codex/skills/arch-save/SKILL.md +183 -0
- package/skeleton/.codex/skills/codev/SKILL.md +90 -0
- package/skeleton/.codex/skills/consult/SKILL.md +96 -0
- package/skeleton/.codex/skills/generate-image/SKILL.md +45 -0
- package/skeleton/.codex/skills/porch/SKILL.md +60 -0
- package/skeleton/.codex/skills/runnable-worktrees/SKILL.md +119 -0
- package/skeleton/.codex/skills/update-arch-docs/SKILL.md +132 -0
- package/skeleton/protocols/air/builder-prompt.md +28 -47
- package/skeleton/protocols/air/consult-types/impl-review.md +17 -34
- package/skeleton/protocols/air/consult-types/pr-review.md +14 -37
- package/skeleton/protocols/air/prompts/implement.md +20 -73
- package/skeleton/protocols/air/prompts/pr.md +22 -54
- package/skeleton/protocols/air/protocol.md +40 -71
- package/skeleton/protocols/aspir/builder-prompt.md +29 -66
- package/skeleton/protocols/aspir/consult-types/impl-review.md +17 -44
- package/skeleton/protocols/aspir/consult-types/phase-review.md +17 -44
- package/skeleton/protocols/aspir/consult-types/plan-review.md +14 -38
- package/skeleton/protocols/aspir/consult-types/pr-review.md +13 -39
- package/skeleton/protocols/aspir/consult-types/spec-review.md +13 -33
- package/skeleton/protocols/aspir/prompts/implement.md +27 -196
- package/skeleton/protocols/aspir/prompts/plan.md +21 -85
- package/skeleton/protocols/aspir/prompts/review.md +29 -228
- package/skeleton/protocols/aspir/prompts/specify.md +25 -111
- package/skeleton/protocols/aspir/protocol.json +10 -0
- package/skeleton/protocols/aspir/protocol.md +36 -82
- package/skeleton/protocols/bugfix/builder-prompt.md +23 -45
- package/skeleton/protocols/bugfix/consult-types/impl-review.md +21 -45
- package/skeleton/protocols/bugfix/consult-types/pr-review.md +18 -52
- package/skeleton/protocols/bugfix/prompts/fix.md +16 -61
- package/skeleton/protocols/bugfix/prompts/investigate.md +18 -62
- package/skeleton/protocols/bugfix/prompts/pr.md +22 -57
- package/skeleton/protocols/bugfix/protocol.md +44 -50
- package/skeleton/protocols/experiment/builder-prompt.md +25 -58
- package/skeleton/protocols/experiment/protocol.md +22 -188
- package/skeleton/protocols/experiment/templates/notes.md +11 -71
- package/skeleton/protocols/maintain/builder-prompt.md +24 -45
- package/skeleton/protocols/maintain/consult-types/impl-review.md +17 -44
- package/skeleton/protocols/maintain/consult-types/pr-review.md +13 -39
- package/skeleton/protocols/maintain/prompts/maintain.md +1 -1
- package/skeleton/protocols/maintain/protocol.md +32 -266
- package/skeleton/protocols/maintain/templates/maintenance-run.md +11 -0
- package/skeleton/protocols/pir/builder-prompt.md +30 -64
- package/skeleton/protocols/pir/consult-types/impl-review.md +17 -50
- package/skeleton/protocols/pir/consult-types/pr-review.md +11 -40
- package/skeleton/protocols/pir/prompts/implement.md +1 -2
- package/skeleton/protocols/pir/prompts/plan.md +0 -3
- package/skeleton/protocols/pir/prompts/review.md +1 -1
- package/skeleton/protocols/pir/protocol.md +54 -177
- package/skeleton/protocols/research/builder-prompt.md +27 -58
- package/skeleton/protocols/research/protocol.md +28 -153
- package/skeleton/protocols/spike/builder-prompt.md +30 -48
- package/skeleton/protocols/spike/protocol.md +24 -107
- package/skeleton/protocols/spike/templates/findings.md +9 -39
- package/skeleton/protocols/spir/builder-prompt.md +33 -62
- package/skeleton/protocols/spir/consult-types/impl-review.md +17 -44
- package/skeleton/protocols/spir/consult-types/phase-review.md +17 -44
- package/skeleton/protocols/spir/consult-types/plan-review.md +14 -38
- package/skeleton/protocols/spir/consult-types/pr-review.md +13 -39
- package/skeleton/protocols/spir/consult-types/spec-review.md +13 -33
- package/skeleton/protocols/spir/prompts/implement.md +26 -195
- package/skeleton/protocols/spir/prompts/plan.md +20 -84
- package/skeleton/protocols/spir/prompts/review.md +28 -227
- package/skeleton/protocols/spir/prompts/specify.md +24 -110
- package/skeleton/protocols/spir/protocol.json +10 -0
- package/skeleton/protocols/spir/protocol.md +84 -633
- package/skeleton/protocols/spir/templates/plan.md +28 -147
- package/skeleton/protocols/spir/templates/review.md +21 -80
- package/skeleton/protocols/spir/templates/spec.md +24 -118
- package/skeleton/resources/commands/agent-farm.md +348 -0
- package/skeleton/resources/commands/codev.md +5 -0
- package/skeleton/resources/commands/consult.md +262 -8
- package/skeleton/resources/commands/overview.md +1 -0
- package/skeleton/roles/architect.md +67 -306
- package/skeleton/roles/builder.md +77 -191
- package/skeleton/templates/AGENTS.md +2 -0
- package/skeleton/templates/CLAUDE.md +2 -0
- package/templates/tower.html +39 -2
- package/dashboard-dist/assets/index-BZ1x7x1X.js.map +0 -1
- package/dashboard-dist/assets/index-DB1KBSNE.css +0 -32
- package/dist/agent-farm/servers/send-buffer.d.ts +0 -59
- package/dist/agent-farm/servers/send-buffer.d.ts.map +0 -1
- package/dist/agent-farm/servers/send-buffer.js +0 -103
- package/dist/agent-farm/servers/send-buffer.js.map +0 -1
- package/skeleton/porch/prompts/defend.md +0 -108
- package/skeleton/porch/prompts/diagnose.md +0 -70
- package/skeleton/porch/prompts/evaluate.md +0 -132
- package/skeleton/porch/prompts/fix.md +0 -59
- package/skeleton/porch/prompts/implement.md +0 -88
- package/skeleton/porch/prompts/plan.md +0 -74
- package/skeleton/porch/prompts/pr.md +0 -84
- package/skeleton/porch/prompts/review.md +0 -249
- package/skeleton/porch/prompts/specify.md +0 -53
- package/skeleton/porch/prompts/test.md +0 -63
- package/skeleton/protocols/aspir/templates/plan.md +0 -184
- package/skeleton/protocols/aspir/templates/review.md +0 -120
- package/skeleton/protocols/aspir/templates/spec.md +0 -154
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mailbox delivery orchestration (Spec 1313, Phase 4).
|
|
3
|
+
*
|
|
4
|
+
* The single gate-checked delivery path: **persist → serialize → gate → deliver |
|
|
5
|
+
* hold**. Both the send request (`handleSend`, after it enqueues) and the periodic
|
|
6
|
+
* backstop drainer route every GATED delivery through {@link deliverAgentMail}, so for
|
|
7
|
+
* gate-checked delivery a message body reaches a PTY in exactly one place — and only
|
|
8
|
+
* onto a prompt the render-gate has proven empty. This is what eliminates corruption by
|
|
9
|
+
* construction for that path: a message can never fuse with a draft, because it is never
|
|
10
|
+
* delivered while one exists; and there is no force path.
|
|
11
|
+
*
|
|
12
|
+
* TWO deliberate exceptions write a body OUTSIDE this path, both explicit human
|
|
13
|
+
* gate-bypasses documented at their `tower-routes.ts` call sites: immediate `--interrupt`
|
|
14
|
+
* (Ctrl+C then the message) and `--escape` (a bare ESC). They are the operator's "I am at
|
|
15
|
+
* this terminal now" actions and take the separate per-terminal submission lock
|
|
16
|
+
* (`session-submit.ts`), not the per-agent serializer here — every autonomous/scheduled/
|
|
17
|
+
* held send, by contrast, delivers through this gate.
|
|
18
|
+
*
|
|
19
|
+
* This module replaces the in-memory `SendBuffer` (retired in this phase): held
|
|
20
|
+
* messages now live in the durable `mailbox` table, so nothing is lost to a Tower
|
|
21
|
+
* crash/restart, and shutdown no longer force-flushes onto the line.
|
|
22
|
+
*
|
|
23
|
+
* Everything the delivery logic touches at the edges — resolving the live session
|
|
24
|
+
* for an agent, resolving its classifier profile (incl. the wrapped-launch
|
|
25
|
+
* fallback), running the gate, writing, broadcasting — is injected via
|
|
26
|
+
* {@link DeliveryPorts}, so the orchestration is unit-testable without a live Tower.
|
|
27
|
+
*/
|
|
28
|
+
import path from 'node:path';
|
|
29
|
+
import { findHeldForAgent, getById, listHeld, markDelivered, setHeldReason, pruneTerminal, findEscalatable, markEscalated, findStarvingAgents, } from '../db/mailbox.js';
|
|
30
|
+
import { KeyedSerializer } from './write-queue.js';
|
|
31
|
+
/**
|
|
32
|
+
* A gate outcome the render gate CANNOT bound to a decision — an unrecognized app
|
|
33
|
+
* (`no-profile`) or a recognized app whose composer region can't be found
|
|
34
|
+
* (`no-region-end`/`no-composer-marker` = a drifted TUI layout or an unrenderable #1047
|
|
35
|
+
* ring). A sustained streak of these means the mail will NEVER deliver on its own, so it
|
|
36
|
+
* is the class {@link MailboxDrainer.recordStreak} escalates to liveness telemetry; a
|
|
37
|
+
* `busy`/`user-text` streak is deliberately excluded (a human legitimately at the line).
|
|
38
|
+
* Shared by `recordStreak` and the cooldown branch of {@link MailboxDrainer.tick} so a
|
|
39
|
+
* skipped tick and a real pass agree on what counts as classifier-stuck (CMAP round 3).
|
|
40
|
+
*/
|
|
41
|
+
function isClassifierStuck(reason, detail) {
|
|
42
|
+
return reason === 'no-profile' || detail === 'no-region-end' || detail === 'no-composer-marker';
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Composite key identifying an agent within a workspace, used to dedupe the
|
|
46
|
+
* backstop's per-agent work and to key the liveness-telemetry streak map (which
|
|
47
|
+
* Phase 7 consumes). Joined on a NUL — a byte that can appear in neither a
|
|
48
|
+
* filesystem path nor an agent id — so the key is collision-proof (a space
|
|
49
|
+
* separator would be ambiguous for paths/ids that contain spaces). Kept explicit
|
|
50
|
+
* (visible `\0`) and shared so callers never hand-roll the separator.
|
|
51
|
+
*/
|
|
52
|
+
export function agentKey(workspacePath, toAgent) {
|
|
53
|
+
return `${workspacePath}\0${toAgent}`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A cheap, MONOTONE token of the session's rendered state plus the classify inputs
|
|
57
|
+
* (dimensions + resolved app). `bytesWritten` advances on ANY new output and never falls
|
|
58
|
+
* (Spec 1313 render-gate round 2 — the fix for the non-monotone `currentSeq:partialBytes`
|
|
59
|
+
* pair, which aliased once #1205's partial trim made `partialBytes` decrease), and the
|
|
60
|
+
* geometry catches a resize that reflows the screen without new output. So two samples that
|
|
61
|
+
* match mean the classified screen is byte-for-byte unchanged. Two consumers rely on that:
|
|
62
|
+
* 1. gate→write TOCTOU re-validation — sampled before the async classify and re-checked
|
|
63
|
+
* after, so a keystroke landing during the classify holds instead of writing onto the
|
|
64
|
+
* new draft;
|
|
65
|
+
* 2. the drainer's verdict memo ({@link CachedVerdict}) — a cached verdict is reused only
|
|
66
|
+
* while this token is unchanged, so a static screen is classified once instead of
|
|
67
|
+
* re-checked every 1.5 s backstop tick.
|
|
68
|
+
*/
|
|
69
|
+
function ringToken(session, profile) {
|
|
70
|
+
return `${session.bytesWritten}:${session.info.cols}x${session.info.rows}:${profile.app}`;
|
|
71
|
+
}
|
|
72
|
+
/** Reconstruct the delivered-message broadcast frame from a persisted row. */
|
|
73
|
+
export function broadcastForRow(row, now) {
|
|
74
|
+
return {
|
|
75
|
+
type: 'message',
|
|
76
|
+
from: {
|
|
77
|
+
project: row.from_workspace ? path.basename(row.from_workspace) : undefined,
|
|
78
|
+
agent: row.from_agent ?? undefined,
|
|
79
|
+
},
|
|
80
|
+
to: { project: path.basename(row.workspace_path), agent: row.to_agent },
|
|
81
|
+
content: row.body,
|
|
82
|
+
metadata: { source: 'mailbox' },
|
|
83
|
+
timestamp: now,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Run one delivery pass for a single agent against the live gate.
|
|
88
|
+
*
|
|
89
|
+
* Delivers the **oldest** held message when — and only when — the composer is a
|
|
90
|
+
* render-verified empty prompt; the rest wait for the next clean gate (the just-
|
|
91
|
+
* delivered message's Enter submits and makes the line busy, so at most one lands
|
|
92
|
+
* per pass — never a blob). When it cannot deliver, it refreshes every held row's
|
|
93
|
+
* `reason` to the current gate verdict so `afx inbox` and the send response stay
|
|
94
|
+
* accurate. Idempotent and race-safe: `markDelivered` only transitions a still-held
|
|
95
|
+
* row, so a backstop tick racing a request-path delivery can never double-send.
|
|
96
|
+
*/
|
|
97
|
+
export async function deliverAgentMail(ports, db, workspacePath, toAgent, memo) {
|
|
98
|
+
// Spec 1313 round 3: ELIGIBLE held rows only — a pre-due delayed send (`not_before > now`)
|
|
99
|
+
// is excluded, so it neither delivers early nor blocks a later normal message. An agent
|
|
100
|
+
// whose only mail is pre-due looks "empty" here (reason null → not stuck), and the row
|
|
101
|
+
// becomes eligible on the first pass at/after its due time (backstop granularity is fine —
|
|
102
|
+
// the delay is a lower bound).
|
|
103
|
+
const held = findHeldForAgent(db, workspacePath, toAgent, ports.now());
|
|
104
|
+
if (held.length === 0)
|
|
105
|
+
return { delivered: [], reason: null };
|
|
106
|
+
const hold = (reason) => {
|
|
107
|
+
for (const row of held) {
|
|
108
|
+
if (row.reason !== reason)
|
|
109
|
+
setHeldReason(db, row.id, reason, ports.now());
|
|
110
|
+
}
|
|
111
|
+
return { delivered: [], reason };
|
|
112
|
+
};
|
|
113
|
+
const session = ports.getSessionForAgent(workspacePath, toAgent);
|
|
114
|
+
if (!session)
|
|
115
|
+
return hold('no-live-pty');
|
|
116
|
+
const profile = ports.resolveProfile(session);
|
|
117
|
+
if (!profile)
|
|
118
|
+
return hold('no-profile');
|
|
119
|
+
// Sample the ring's change-token BEFORE the (possibly memoized) classify, so we can
|
|
120
|
+
// re-validate afterward that the screen didn't move under us (below).
|
|
121
|
+
const tokenBefore = ringToken(session, profile);
|
|
122
|
+
// Verdict memo (Spec 1313 render-gate follow-up). The 1.5 s backstop re-checks every held
|
|
123
|
+
// agent's screen each tick; for a STATIC screen that classify is pure waste. Reuse the
|
|
124
|
+
// cached verdict while BOTH the live session instance AND the token are unchanged — the token
|
|
125
|
+
// advances on ANY new output, so a match means the screen is byte-for-byte what we already
|
|
126
|
+
// classified, and the session guard closes the PTY-respawn aliasing route (a replacement
|
|
127
|
+
// session is a DIFFERENT object); the monotone token closes the old `RingBuffer.clear()` route
|
|
128
|
+
// (see {@link CachedVerdict}). A memo hit does NO await, so the post-classify re-validation
|
|
129
|
+
// below (`ringToken(...) !== tokenBefore`) passes trivially: no keystroke can land in a
|
|
130
|
+
// classify window that never opened. The memo is owned + bounded by the drainer's backstop
|
|
131
|
+
// {@link MailboxDrainer.tick} (pruned to the held-agent set each tick); every OTHER caller —
|
|
132
|
+
// the request/cron paths and the fast scheduleDrain trigger — passes none and classifies
|
|
133
|
+
// fresh, so an event-driven re-check is never served a cached verdict.
|
|
134
|
+
const cacheKey = agentKey(workspacePath, toAgent);
|
|
135
|
+
const cached = memo?.get(cacheKey);
|
|
136
|
+
let verdict;
|
|
137
|
+
if (cached && cached.session === session && cached.token === tokenBefore) {
|
|
138
|
+
verdict = cached.verdict;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
verdict = await ports.classify(session, profile);
|
|
142
|
+
memo?.set(cacheKey, { session, token: tokenBefore, verdict });
|
|
143
|
+
}
|
|
144
|
+
if (!verdict.clean) {
|
|
145
|
+
// Carry the gate detail so a sustained classifier-stuck streak (a drifted profile
|
|
146
|
+
// or an unrenderable frame) escalates to liveness telemetry instead of holding silently.
|
|
147
|
+
const reason = verdict.reason ?? 'busy';
|
|
148
|
+
for (const row of held) {
|
|
149
|
+
if (row.reason !== reason)
|
|
150
|
+
setHeldReason(db, row.id, reason, ports.now());
|
|
151
|
+
}
|
|
152
|
+
return { delivered: [], reason, detail: verdict.detail };
|
|
153
|
+
}
|
|
154
|
+
// Re-validate the SCREEN before writing (Spec 1313 render-gate diff review). The classify
|
|
155
|
+
// above may have awaited (the mirror flushes its parser, and xterm yields between parse
|
|
156
|
+
// slices); if the screen advanced since we sampled `tokenBefore`, a draft may have started
|
|
157
|
+
// under us and the clean verdict is now stale. Writing then would fuse the message into that
|
|
158
|
+
// draft — the exact false-clean the gate prevents. Hold instead; it delivers on the next
|
|
159
|
+
// clean tick. (On a memo hit no await occurred, so the token is unchanged and this passes
|
|
160
|
+
// trivially.)
|
|
161
|
+
if (ringToken(session, profile) !== tokenBefore)
|
|
162
|
+
return hold('busy');
|
|
163
|
+
// Clean, verified-empty prompt → deliver the oldest held message. Await the
|
|
164
|
+
// write's paced completion so a serialized follow-up delivery never begins
|
|
165
|
+
// until this message's text + Enter is fully on the wire.
|
|
166
|
+
const row = held[0];
|
|
167
|
+
// Re-validate at the delivery instant (Spec 1313 iter-1 review, Codex). The held
|
|
168
|
+
// list and the gate verdict were read before this point, and dismiss/supersede are
|
|
169
|
+
// independent DB writes NOT routed through the per-agent delivery serializer — so a
|
|
170
|
+
// resolve that landed in the gate→write window must not still put bytes on the wire.
|
|
171
|
+
// better-sqlite3 is synchronous, so this re-read reflects any dismiss/supersede
|
|
172
|
+
// committed up to now; the irreducible residual (a resolve during the paced write
|
|
173
|
+
// itself) is the accepted gate→write race in the spec's Risks table.
|
|
174
|
+
const current = getById(db, row.id);
|
|
175
|
+
if (!current || current.status !== 'held') {
|
|
176
|
+
ports.onHeldStateChange(); // the held set changed under us → refresh the indicator
|
|
177
|
+
return { delivered: [], reason: null };
|
|
178
|
+
}
|
|
179
|
+
// Fast-path an already-dead session (#1198: a dead shellper socket still reports
|
|
180
|
+
// status 'running', and its writes are dropped). This t=0 precheck avoids a pointless
|
|
181
|
+
// paced write when the PTY is unwritable before we even start; it is NOT the whole
|
|
182
|
+
// guard — a socket that dies DURING the paced text→…→Enter sequence is invisible here
|
|
183
|
+
// and surfaces instead as a dropped-write `false` from writeMessage (handled below).
|
|
184
|
+
// Either way the row is held ("an errored PTY write leaves the row held"), never marked
|
|
185
|
+
// delivered off the paced-write timer.
|
|
186
|
+
if (!session.writable)
|
|
187
|
+
return hold('no-live-pty');
|
|
188
|
+
// Default false so an unobserved result is the SAFE failure mode (hold, never a false
|
|
189
|
+
// delivery); the try either assigns the real boolean or throws past this point.
|
|
190
|
+
let written = false;
|
|
191
|
+
try {
|
|
192
|
+
written = await ports.writeMessage(session, current.formatted_message, current.no_enter === 1);
|
|
193
|
+
}
|
|
194
|
+
finally {
|
|
195
|
+
// Invalidate the memo on EVERY write outcome — a clean `true`, a dropped-write `false`, OR a
|
|
196
|
+
// rejection — and BEFORE the markDelivered/held decisions below (CMAP round 3 moved it above the
|
|
197
|
+
// guard; round 4 — Codex — made it rejection-safe via this finally). The write is what makes the
|
|
198
|
+
// cached CLEAN verdict stale (it put the submitted line + a fresh prompt on the wire, or some of
|
|
199
|
+
// its bytes), regardless of whether the row then transitions, holds, or the write completes
|
|
200
|
+
// cleanly. Ways a leftover CLEAN would leak, all closed here: (a) a dismiss/supersede lands during
|
|
201
|
+
// the paced write → markDelivered returns false and we early-return below, bytes already out;
|
|
202
|
+
// (b) a dropped write reports `false` (Spec 1313 integration review — silent-loss fix) after
|
|
203
|
+
// putting SOME bytes on the wire, e.g. the text landed but the Enter dropped → we hold below;
|
|
204
|
+
// (c) writeMessage REJECTS after partial bytes — its port contract (`boolean | Promise<boolean>`)
|
|
205
|
+
// permits a binding to throw, and a bare throw would skip a delete placed after the await. In
|
|
206
|
+
// every case a leftover CLEAN would let a follow-up held message memo-hit the SAME token (PTY
|
|
207
|
+
// INPUT does not advance the ring — only OUTPUT does) and write onto the not-yet-echoed line, so
|
|
208
|
+
// the memo must die here. The deeper input-echo-lag window — a fresh classify racing the echo — is
|
|
209
|
+
// the pre-existing gate→write INPUT race in the review's Technical Debt.
|
|
210
|
+
memo?.delete(cacheKey);
|
|
211
|
+
}
|
|
212
|
+
// A dropped PTY write (#1198) means zero-or-partial bytes reached the terminal — the exact silent
|
|
213
|
+
// loss this spec exists to prevent (Spec 1313 integration review — Codex). The t=0 `writable`
|
|
214
|
+
// precheck above cannot catch a socket that dies mid-pace (the text/lines/Enter fire across
|
|
215
|
+
// setTimeout gaps), so writeMessage threads the per-write result: `false` → no complete submit
|
|
216
|
+
// landed. Hold the row (`no-live-pty`, retried on the next clean gate pass) instead of marking it
|
|
217
|
+
// delivered. Any bytes already on the wire only make the line dirty; the render gate then holds on
|
|
218
|
+
// that draft until the session recovers or is torn down — it can never be marked delivered on a
|
|
219
|
+
// dead PTY.
|
|
220
|
+
if (!written)
|
|
221
|
+
return hold('no-live-pty');
|
|
222
|
+
// markDelivered is guarded (held→delivered only). If it did NOT transition, the row
|
|
223
|
+
// was dismissed/superseded during the paced write — accept that terminal state and
|
|
224
|
+
// do not broadcast a delivery for it.
|
|
225
|
+
if (!markDelivered(db, row.id, ports.now())) {
|
|
226
|
+
ports.onHeldStateChange();
|
|
227
|
+
return { delivered: [], reason: null };
|
|
228
|
+
}
|
|
229
|
+
ports.broadcast(broadcastForRow(current, ports.now()));
|
|
230
|
+
ports.onHeldStateChange(); // a held row left the set → refresh the indicator count
|
|
231
|
+
ports.log(`[mailbox] delivered ${row.id} → ${toAgent} @ ${path.basename(workspacePath)}`);
|
|
232
|
+
return { delivered: [row.id], reason: null };
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Shared per-agent delivery serializer (Spec 1313, Phase 4). Every live caller —
|
|
236
|
+
* the `afx send` request path and the backstop drainer — funnels delivery for a
|
|
237
|
+
* given agent through this one instance, so a `pick → gate → write → mark`
|
|
238
|
+
* critical section can never overlap another for the same agent. That is what
|
|
239
|
+
* makes the spike `w1a` blob (two concurrent sends fusing into one submit)
|
|
240
|
+
* impossible: the second delivery cannot even read the gate until the first has
|
|
241
|
+
* fully written its text + Enter (see {@link KeyedSerializer}).
|
|
242
|
+
*/
|
|
243
|
+
const deliverySerializer = new KeyedSerializer();
|
|
244
|
+
/**
|
|
245
|
+
* {@link deliverAgentMail}, serialized per agent through the shared
|
|
246
|
+
* {@link KeyedSerializer}. This is the entry point every live caller must use;
|
|
247
|
+
* the bare `deliverAgentMail` is exported only so unit tests can drive a single
|
|
248
|
+
* pass deterministically.
|
|
249
|
+
*/
|
|
250
|
+
export function deliverAgentMailSerialized(ports, db, workspacePath, toAgent, memo) {
|
|
251
|
+
return deliverySerializer.run(agentKey(workspacePath, toAgent), () => deliverAgentMail(ports, db, workspacePath, toAgent, memo));
|
|
252
|
+
}
|
|
253
|
+
const DEFAULT_BACKSTOP_INTERVAL_MS = 1500;
|
|
254
|
+
// Spec 1313 (baked decision 7): terminal rows are pruned after a bounded window,
|
|
255
|
+
// default 30 days, configurable via `.codev/config.json` (mailbox.retentionDays) —
|
|
256
|
+
// `startMailboxDrainer` reads it and passes it in. This constant is the fallback
|
|
257
|
+
// when the drainer is constructed without an explicit value (e.g. unit tests).
|
|
258
|
+
const DEFAULT_PRUNE_RETENTION_DAYS = 30;
|
|
259
|
+
// Spec 1313 (Phase 7): a held row older than this crosses the escalation age — the
|
|
260
|
+
// drainer flags it `escalated` and emits the visibility broadcast (NEVER delivers).
|
|
261
|
+
// Default 60s (matches today's max-age); `startMailboxDrainer` overrides from config.
|
|
262
|
+
const DEFAULT_ESCALATION_MS = 60_000;
|
|
263
|
+
// Spec 1313 (Phase 7): after this many consecutive not-clean gate verdicts for an agent
|
|
264
|
+
// whose reason is `no-profile`, the drainer logs a loud liveness warning — a sustained
|
|
265
|
+
// no-profile streak means the session's app is unrecognized (broken/unknown classifier),
|
|
266
|
+
// so its mail will never deliver. The threshold filters transient boot/relaunch screens,
|
|
267
|
+
// which resolve well before it.
|
|
268
|
+
const LIVENESS_STREAK_THRESHOLD = 10;
|
|
269
|
+
// Spec 1313 round 3 (change 3): the owner-notice threshold is a small MULTIPLE of the
|
|
270
|
+
// escalation age — a row must be deliverable-but-stuck for this much longer than the basic
|
|
271
|
+
// `escalated` flag before its owner architect is alarmed, so a briefly-busy line does not
|
|
272
|
+
// spam owners. Derived from escalationMs (default 60s → 180s), so it scales with the
|
|
273
|
+
// configured `mailbox.escalationSeconds` without a separate config knob.
|
|
274
|
+
const DEFAULT_OWNER_NOTICE_MULTIPLE = 3;
|
|
275
|
+
/**
|
|
276
|
+
* The poll backstop that replaces `SendBuffer`'s flush timer. On each tick it walks
|
|
277
|
+
* every agent with held mail and runs {@link deliverAgentMail}, so a message held
|
|
278
|
+
* on a busy line delivers on the first tick after the line clears (Phase 5 adds the
|
|
279
|
+
* fast submit/quiescence triggers on top). It also prunes terminal rows on boot and
|
|
280
|
+
* per tick, and tracks a per-agent consecutive-not-clean streak for liveness
|
|
281
|
+
* telemetry (Phase 7 surfaces it as a loud log/broadcast). Shutdown just stops the
|
|
282
|
+
* timer — nothing is force-flushed, because every held row is already persisted.
|
|
283
|
+
*/
|
|
284
|
+
export class MailboxDrainer {
|
|
285
|
+
timer;
|
|
286
|
+
ticking = false;
|
|
287
|
+
ports;
|
|
288
|
+
db;
|
|
289
|
+
intervalMs;
|
|
290
|
+
retentionDays;
|
|
291
|
+
escalationMs;
|
|
292
|
+
ownerNoticeMs;
|
|
293
|
+
notCleanStreak = new Map();
|
|
294
|
+
// Spec 1313 round 3 (change 3): agents for which an owner starvation notice has already been
|
|
295
|
+
// raised this Tower lifetime — so the notice fires ONCE per episode, not once per tick. An
|
|
296
|
+
// entry is cleared when the agent's eligible held set drains (its starvation is over), which
|
|
297
|
+
// also fires `clearHeldOwnerNotice`. In-memory (like the streak map); after a restart a still-
|
|
298
|
+
// starving agent re-notifies once, and `supersede` keeps that to a single pending row.
|
|
299
|
+
notifiedAgents = new Set();
|
|
300
|
+
// Spec 1313 Phase 5: agents with a fast-trigger drain already queued. A burst of
|
|
301
|
+
// submit/quiescence signals for one agent coalesces onto the same pending promise
|
|
302
|
+
// (one gate check, not one per trigger); the slot is released when the pass begins.
|
|
303
|
+
scheduledDrains = new Map();
|
|
304
|
+
// Spec 1313 render-gate verdict memo: a cached gate verdict per agent, keyed on the session
|
|
305
|
+
// instance + monotone change-token, so a STATIC held screen skips its re-classify every tick.
|
|
306
|
+
// Owned here so it stays bounded — {@link tick} prunes it to the current held-agent set. (The
|
|
307
|
+
// CMAP-round-1 big-ring backstop backoff that used to sit alongside this is retired in round 2:
|
|
308
|
+
// with the persistent bounded mirror, a classify is O(viewport) regardless of history, so there
|
|
309
|
+
// is no expensive whole-ring render left to throttle — every tick just re-classifies cheaply.)
|
|
310
|
+
verdictMemo = new Map();
|
|
311
|
+
// Lifecycle generation (CMAP round 2 — Codex/Claude): the drainer instance is REUSED across
|
|
312
|
+
// stop()/start() (mailbox-wiring `ensureDrainer`), and the tests do start/stop/start. Bumped on
|
|
313
|
+
// stop() so an in-flight tick/scheduleDrain that resumes after a restart bails before mutating
|
|
314
|
+
// this generation's state.
|
|
315
|
+
generation = 0;
|
|
316
|
+
constructor(opts = {}) {
|
|
317
|
+
this.intervalMs = opts.intervalMs ?? DEFAULT_BACKSTOP_INTERVAL_MS;
|
|
318
|
+
this.retentionDays = opts.pruneRetentionDays ?? DEFAULT_PRUNE_RETENTION_DAYS;
|
|
319
|
+
this.escalationMs = opts.escalationMs ?? DEFAULT_ESCALATION_MS;
|
|
320
|
+
this.ownerNoticeMs = opts.ownerNoticeMs ?? this.escalationMs * DEFAULT_OWNER_NOTICE_MULTIPLE;
|
|
321
|
+
}
|
|
322
|
+
start(ports, db) {
|
|
323
|
+
if (this.timer)
|
|
324
|
+
clearInterval(this.timer);
|
|
325
|
+
this.ports = ports;
|
|
326
|
+
this.db = db;
|
|
327
|
+
pruneTerminal(db, this.retentionDays, ports.now()); // boot prune
|
|
328
|
+
this.timer = setInterval(() => void this.tick(), this.intervalMs);
|
|
329
|
+
if (typeof this.timer.unref === 'function')
|
|
330
|
+
this.timer.unref();
|
|
331
|
+
}
|
|
332
|
+
stop() {
|
|
333
|
+
if (this.timer)
|
|
334
|
+
clearInterval(this.timer);
|
|
335
|
+
this.timer = undefined;
|
|
336
|
+
this.ports = undefined;
|
|
337
|
+
this.db = undefined;
|
|
338
|
+
// Drop all per-agent transient state (CMAP round 1/2 — Codex/Claude): the drainer instance is
|
|
339
|
+
// REUSED across stop()/start(), so a restart must not carry a stale verdict/streak/backoff, nor
|
|
340
|
+
// let a post-restart trigger coalesce onto a dead scheduled-drain promise. NB clearing
|
|
341
|
+
// `scheduledDrains` does NOT cancel an already-running drain — its promise captured the old
|
|
342
|
+
// ports/db and runs to completion; it only stops a new trigger from coalescing onto it. Two
|
|
343
|
+
// guards make that resumption safe (CMAP round 3): (1) the `generation` bump below — checked by
|
|
344
|
+
// both `tick` and `scheduleDrain` right after each await — stops an in-flight pass from re-seeding
|
|
345
|
+
// THIS generation's freshly-cleared streak/scheduled-drain slot. (The verdict memo can still be
|
|
346
|
+
// seeded from INSIDE a resumed `deliverAgentMail`, before that check, but that is benign: the memo
|
|
347
|
+
// is bound to its session instance + change token and re-pruned to the held-agent set at the top of
|
|
348
|
+
// every tick, so a cross-generation entry is self-correcting, not a leak.) And (2) both passes now
|
|
349
|
+
// run their work under a try/catch, so a throw on the old (closed) DB is logged, not an
|
|
350
|
+
// unhandledRejection that would exit(1). (Pre-round-3, `tick` had no catch, so a closed-DB throw
|
|
351
|
+
// there was NOT harmless.)
|
|
352
|
+
this.verdictMemo.clear();
|
|
353
|
+
this.notCleanStreak.clear();
|
|
354
|
+
this.scheduledDrains.clear();
|
|
355
|
+
this.notifiedAgents.clear();
|
|
356
|
+
this.generation++;
|
|
357
|
+
}
|
|
358
|
+
/** Per-agent consecutive not-clean count (liveness telemetry; Phase 7 reads this). */
|
|
359
|
+
get streaks() {
|
|
360
|
+
return this.notCleanStreak;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Agent keys that currently hold a cached gate verdict (render-gate memo).
|
|
364
|
+
* Observability/test only: {@link tick} prunes this to the current held-agent set, so
|
|
365
|
+
* it never grows past the number of agents holding mail.
|
|
366
|
+
*/
|
|
367
|
+
get memoizedAgents() {
|
|
368
|
+
return [...this.verdictMemo.keys()];
|
|
369
|
+
}
|
|
370
|
+
/** One backstop pass. Guarded against re-entry so a slow gate can't overlap ticks. */
|
|
371
|
+
async tick() {
|
|
372
|
+
const ports = this.ports;
|
|
373
|
+
const db = this.db;
|
|
374
|
+
if (!ports || !db || this.ticking)
|
|
375
|
+
return;
|
|
376
|
+
this.ticking = true;
|
|
377
|
+
const gen = this.generation; // bail if stop() runs mid-tick (the drainer instance is reused)
|
|
378
|
+
try {
|
|
379
|
+
const agents = new Map();
|
|
380
|
+
for (const row of listHeld(db)) {
|
|
381
|
+
agents.set(agentKey(row.workspace_path, row.to_agent), {
|
|
382
|
+
workspacePath: row.workspace_path,
|
|
383
|
+
toAgent: row.to_agent,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
// Prune the verdict memo to the current held-agent set before the pass: an agent whose
|
|
387
|
+
// mail all delivered/dismissed is no longer walked here, so its cached verdict would
|
|
388
|
+
// otherwise leak for the life of the process. Bounds the memo to |held agents|.
|
|
389
|
+
for (const key of this.verdictMemo.keys()) {
|
|
390
|
+
if (!agents.has(key))
|
|
391
|
+
this.verdictMemo.delete(key);
|
|
392
|
+
}
|
|
393
|
+
for (const [key, { workspacePath, toAgent }] of agents) {
|
|
394
|
+
if (this.generation !== gen)
|
|
395
|
+
return; // stop() ran mid-tick → bail before more work
|
|
396
|
+
// Isolate each agent's pass (CMAP round 3 — Claude): a throw from classify/writeMessage/DB
|
|
397
|
+
// for ONE agent must not abort the others, and — critically — must never escape this
|
|
398
|
+
// setInterval-invoked tick, where the tower-server `unhandledRejection` handler would
|
|
399
|
+
// exit(1) and take Tower + every terminal down. scheduleDrain already wraps its drain the
|
|
400
|
+
// same way; this mirrors it so the round-2 stop() comment's "throws harmlessly" is true
|
|
401
|
+
// for the backstop tick too, not just the scheduled drain.
|
|
402
|
+
try {
|
|
403
|
+
// Every tick re-classifies cheaply now (Spec 1313 round 2): the persistent mirror makes a
|
|
404
|
+
// classify O(viewport), independent of history, so there is no expensive whole-ring render
|
|
405
|
+
// to throttle — the CMAP-round-1 big-ring cooldown is retired. The verdict memo still skips
|
|
406
|
+
// the re-classify for a STATIC screen (unchanged token); a moving screen just re-checks.
|
|
407
|
+
const outcome = await deliverAgentMailSerialized(ports, db, workspacePath, toAgent, this.verdictMemo);
|
|
408
|
+
if (this.generation !== gen)
|
|
409
|
+
return; // stop() landed during the await → do NOT mutate the
|
|
410
|
+
// NEW generation's freshly-cleared streak map
|
|
411
|
+
this.recordStreak(key, outcome);
|
|
412
|
+
}
|
|
413
|
+
catch (err) {
|
|
414
|
+
ports.log(`[mailbox] backstop delivery failed for ${toAgent}: ${String(err)}`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (this.generation !== gen)
|
|
418
|
+
return; // stop() ran during the loop → skip escalation/prune
|
|
419
|
+
this.escalateOverdue(ports, db);
|
|
420
|
+
this.noticeOverdue(ports, db);
|
|
421
|
+
pruneTerminal(db, this.retentionDays, ports.now());
|
|
422
|
+
}
|
|
423
|
+
catch (err) {
|
|
424
|
+
// Backstop for escalateOverdue/pruneTerminal (DB ops) or anything the per-agent guard missed:
|
|
425
|
+
// a tick runs under setInterval, so an unhandled throw becomes an unhandledRejection → exit(1)
|
|
426
|
+
// (tower-server). Log and let the next tick retry (CMAP round 3 — Claude).
|
|
427
|
+
ports?.log(`[mailbox] backstop tick failed: ${String(err)}`);
|
|
428
|
+
}
|
|
429
|
+
finally {
|
|
430
|
+
this.ticking = false;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Escalation pass (Spec 1313, Phase 7). Flags every held row that has crossed the
|
|
435
|
+
* escalation age (`escalationMs`, default 60s) as `escalated` and emits the
|
|
436
|
+
* `onEscalation` visibility broadcast + a loud log. **VISIBILITY ONLY — it never
|
|
437
|
+
* delivers.** `findEscalatable` returns only not-yet-escalated held rows and
|
|
438
|
+
* `markEscalated` is idempotent, so each row escalates (and broadcasts) exactly
|
|
439
|
+
* once; the row still delivers only on a later clean gate pass, and the attention
|
|
440
|
+
* state clears when it resolves (the row leaves the held set).
|
|
441
|
+
*/
|
|
442
|
+
escalateOverdue(ports, db) {
|
|
443
|
+
const now = ports.now();
|
|
444
|
+
let escalatedAny = false;
|
|
445
|
+
for (const row of findEscalatable(db, this.escalationMs, now)) {
|
|
446
|
+
if (!markEscalated(db, row.id, now))
|
|
447
|
+
continue;
|
|
448
|
+
escalatedAny = true;
|
|
449
|
+
// Age from the escalation START (max(created_at, not_before)) so a delayed row's clock
|
|
450
|
+
// runs from its DUE time, not its enqueue time (Spec 1313 round 3). For a normal row
|
|
451
|
+
// not_before is null → this is created_at, unchanged from before.
|
|
452
|
+
const ageMs = now - Math.max(row.created_at, row.not_before ?? row.created_at);
|
|
453
|
+
ports.onEscalation({
|
|
454
|
+
workspacePath: row.workspace_path,
|
|
455
|
+
toAgent: row.to_agent,
|
|
456
|
+
mailboxId: row.id,
|
|
457
|
+
ageMs,
|
|
458
|
+
reason: row.reason,
|
|
459
|
+
});
|
|
460
|
+
ports.log(`[mailbox] ESCALATED ${row.id.slice(0, 8)}… → ${row.to_agent} @ ${path.basename(row.workspace_path)} ` +
|
|
461
|
+
`(held ${Math.round(ageMs / 1000)}s, reason ${row.reason ?? 'held'}) — visibility only, not delivered`);
|
|
462
|
+
}
|
|
463
|
+
// A row's escalated flag flipped → the overview-derived `mailboxEscalated` attention
|
|
464
|
+
// bit changed. Fire the held-state-change event too (in addition to the per-row
|
|
465
|
+
// `mailbox-escalation` above) so a client that refetches /api/overview on
|
|
466
|
+
// `overview-changed` picks up the new attention state and never shows a stale flag.
|
|
467
|
+
if (escalatedAny)
|
|
468
|
+
ports.onHeldStateChange();
|
|
469
|
+
}
|
|
470
|
+
/** Agents with a pending owner starvation notice this lifetime (test/observability). */
|
|
471
|
+
get notifiedOwnerAgents() {
|
|
472
|
+
return [...this.notifiedAgents];
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Owner starvation-notice pass (Spec 1313 round 3, change 3). When an agent's OLDEST eligible
|
|
476
|
+
* held row has been deliverable-but-stuck past the owner-notice threshold, alarm the agent's
|
|
477
|
+
* OWNER exactly once per episode via {@link DeliveryPorts.escalateHeldToOwner} — the live
|
|
478
|
+
* binding resolves the recipient architect (spawning → workspace `main` → first-registered),
|
|
479
|
+
* skips agents that are themselves architects, and enqueues ONE coalesced, gate-delivered
|
|
480
|
+
* notice. When a previously-notified agent's eligible held set drains, the pending notice is
|
|
481
|
+
* cleared via {@link DeliveryPorts.clearHeldOwnerNotice}. VISIBILITY ONLY — never delivers.
|
|
482
|
+
*
|
|
483
|
+
* The two spec guards hold by construction: {@link findStarvingAgents} excludes PRE-DUE
|
|
484
|
+
* delayed rows (a scheduled send is not stuck) and NOTICE rows themselves (a notice can never
|
|
485
|
+
* trigger a notice). The once-per-episode guard is {@link notifiedAgents}, armed ONLY after a
|
|
486
|
+
* notice is actually enqueued (an `escalateHeldToOwner` that no-ops — no architect yet, or the
|
|
487
|
+
* recipient is itself an architect — leaves the guard unset and retries next tick);
|
|
488
|
+
* `escalateHeldToOwner` additionally coalesces via a supersede key, so even a post-restart
|
|
489
|
+
* re-notify stays a single pending row.
|
|
490
|
+
*/
|
|
491
|
+
noticeOverdue(ports, db) {
|
|
492
|
+
// No notice wiring (a unit fake without these ports) → nothing to do.
|
|
493
|
+
if (!ports.escalateHeldToOwner && !ports.clearHeldOwnerNotice)
|
|
494
|
+
return;
|
|
495
|
+
const now = ports.now();
|
|
496
|
+
const cutoff = now - this.ownerNoticeMs;
|
|
497
|
+
const withEligibleHeld = new Set();
|
|
498
|
+
for (const agent of findStarvingAgents(db, now)) {
|
|
499
|
+
const key = agentKey(agent.workspacePath, agent.toAgent);
|
|
500
|
+
withEligibleHeld.add(key);
|
|
501
|
+
if (agent.stuckSince <= cutoff && !this.notifiedAgents.has(key)) {
|
|
502
|
+
// Arm the once-per-episode guard ONLY when a notice was actually enqueued. The binding
|
|
503
|
+
// no-ops (returns false) when the recipient is itself an architect or no architect is
|
|
504
|
+
// registered yet; marking the agent notified on that no-op would suppress the alarm for
|
|
505
|
+
// the rest of the episode even after an architect appears. A falsy/absent return leaves
|
|
506
|
+
// the key unset so the next tick retries.
|
|
507
|
+
const enqueued = ports.escalateHeldToOwner?.({
|
|
508
|
+
workspacePath: agent.workspacePath,
|
|
509
|
+
toAgent: agent.toAgent,
|
|
510
|
+
reason: agent.reason,
|
|
511
|
+
ageMs: now - agent.stuckSince,
|
|
512
|
+
heldCount: agent.count,
|
|
513
|
+
});
|
|
514
|
+
if (enqueued)
|
|
515
|
+
this.notifiedAgents.add(key);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
// A previously-notified agent with no eligible non-notice held row left has drained
|
|
519
|
+
// (delivered/dismissed, or only pre-due scheduled rows remain) → clear the moot notice.
|
|
520
|
+
for (const key of [...this.notifiedAgents]) {
|
|
521
|
+
if (withEligibleHeld.has(key))
|
|
522
|
+
continue;
|
|
523
|
+
this.notifiedAgents.delete(key);
|
|
524
|
+
const [ws, agent] = key.split('\0');
|
|
525
|
+
ports.clearHeldOwnerNotice?.(ws, agent);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Update the per-agent liveness streak from a delivery outcome (Phase 7 surfaces
|
|
530
|
+
* it): a delivered or empty pass clears the streak; a held pass grows it. Shared by
|
|
531
|
+
* the backstop {@link tick} and the fast {@link scheduleDrain} trigger so both feed
|
|
532
|
+
* the same telemetry.
|
|
533
|
+
*/
|
|
534
|
+
recordStreak(key, outcome) {
|
|
535
|
+
if (outcome.delivered.length > 0 || outcome.reason === null) {
|
|
536
|
+
this.notCleanStreak.delete(key);
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
const next = (this.notCleanStreak.get(key) ?? 0) + 1;
|
|
540
|
+
this.notCleanStreak.set(key, next);
|
|
541
|
+
// Liveness telemetry (Spec 1313, Phase 7 — spec line 91; extended in the render-gate
|
|
542
|
+
// hardening): a sustained streak that the gate CANNOT verify means the mail will
|
|
543
|
+
// NEVER deliver on its own — surface it instead of holding silently. Two such classes:
|
|
544
|
+
// • `no-profile` — the app is unrecognized (a net-new or drifted classifier);
|
|
545
|
+
// • a classifier-stuck gate detail — a recognized app whose composer can't be bounded
|
|
546
|
+
// (`no-region-end`/`no-composer-marker` = a drifted TUI layout or an unrenderable
|
|
547
|
+
// frame — e.g. a pathological #1047 ring whose whole-render yields no bounded
|
|
548
|
+
// composer; this is the liveness net that replaced the removed over-ceiling hold).
|
|
549
|
+
// Scoped to those on purpose: a `busy`/`user-text` streak is a human legitimately at the
|
|
550
|
+
// line (Constraint 1 — must not false-alarm), and `no-live-pty` is no session at all.
|
|
551
|
+
// Reported once at the crossing (not per tick); the threshold filters transient boot/
|
|
552
|
+
// relaunch screens. The pure module only reports the crossing — the live binding
|
|
553
|
+
// ({@link DeliveryPorts.onLiveness}) applies the spec's "with recent output" gate and
|
|
554
|
+
// does the loud log + broadcast, so an idle unknown session does not false-alarm.
|
|
555
|
+
if (isClassifierStuck(outcome.reason, outcome.detail) && next === LIVENESS_STREAK_THRESHOLD) {
|
|
556
|
+
const [ws, agent] = key.split('\0');
|
|
557
|
+
this.ports?.onLiveness({ workspacePath: ws, toAgent: agent, streak: next });
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Fast, event-driven delivery trigger (Spec 1313, Phase 5). A submit (Enter) or
|
|
562
|
+
* output-quiescence signal for a session schedules a single coalesced delivery pass
|
|
563
|
+
* for that agent, so a held message delivers within a microtask of the line
|
|
564
|
+
* clearing instead of waiting up to one backstop interval.
|
|
565
|
+
*
|
|
566
|
+
* Triggers are schedulers, never authority (spec Constraint): this runs the SAME
|
|
567
|
+
* gated {@link deliverAgentMailSerialized} the backstop does, so a spurious trigger
|
|
568
|
+
* on a still-busy screen simply re-holds, and a missed trigger only defers delivery
|
|
569
|
+
* to the next backstop tick — a trigger can never corrupt anything.
|
|
570
|
+
*
|
|
571
|
+
* Coalescing: while a pass is already queued for an agent, further triggers return
|
|
572
|
+
* the same in-flight promise (the gate runs once, not once per trigger). The slot is
|
|
573
|
+
* released just before the pass runs, so a trigger arriving *during* a pass queues
|
|
574
|
+
* exactly one follow-up; the per-agent {@link KeyedSerializer} keeps passes from
|
|
575
|
+
* overlapping. No-op (resolved) until the drainer is started, and never rejects — a
|
|
576
|
+
* gate/write error is logged and left for the backstop, mirroring the tick.
|
|
577
|
+
*/
|
|
578
|
+
scheduleDrain(workspacePath, toAgent) {
|
|
579
|
+
const ports = this.ports;
|
|
580
|
+
const db = this.db;
|
|
581
|
+
if (!ports || !db)
|
|
582
|
+
return Promise.resolve();
|
|
583
|
+
const gen = this.generation; // bail if stop() runs before this queued drain executes
|
|
584
|
+
const key = agentKey(workspacePath, toAgent);
|
|
585
|
+
const existing = this.scheduledDrains.get(key);
|
|
586
|
+
if (existing)
|
|
587
|
+
return existing;
|
|
588
|
+
const run = Promise.resolve().then(async () => {
|
|
589
|
+
// Bail before touching ANY shared state if the generation moved (stopped/restarted before we
|
|
590
|
+
// ran → old ports/db), and release our coalescing slot only if it is still OURS (CMAP round 3
|
|
591
|
+
// — Codex). The old code deleted `scheduledDrains[key]` unconditionally and BEFORE the
|
|
592
|
+
// generation check: a stop()/start()+new scheduleDrain for the same key installs a NEW-
|
|
593
|
+
// generation run in that slot, and the unconditional delete would drop that live slot.
|
|
594
|
+
if (this.generation !== gen)
|
|
595
|
+
return;
|
|
596
|
+
if (this.scheduledDrains.get(key) === run)
|
|
597
|
+
this.scheduledDrains.delete(key);
|
|
598
|
+
try {
|
|
599
|
+
// NB: the fast trigger classifies FRESH (no verdict memo). A submit/quiescence
|
|
600
|
+
// trigger fires precisely because the ring just changed, so it must re-check the
|
|
601
|
+
// gate — the memo is the backstop tick's optimization for a STATIC ring, not this
|
|
602
|
+
// event-driven re-check. tick owns and prunes the memo alone.
|
|
603
|
+
const outcome = await deliverAgentMailSerialized(ports, db, workspacePath, toAgent);
|
|
604
|
+
if (this.generation !== gen)
|
|
605
|
+
return; // stop() landed during the await → do NOT mutate the
|
|
606
|
+
// NEW generation's freshly-cleared streak map
|
|
607
|
+
this.recordStreak(key, outcome);
|
|
608
|
+
}
|
|
609
|
+
catch (err) {
|
|
610
|
+
ports.log(`[mailbox] scheduled drain failed for ${toAgent}: ${String(err)}`);
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
this.scheduledDrains.set(key, run);
|
|
614
|
+
return run;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
//# sourceMappingURL=mailbox-delivery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailbox-delivery.js","sourceRoot":"","sources":["../../../src/agent-farm/servers/mailbox-delivery.ts"],"names":[],"mappings":"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"}
|