@cluesmith/codev 3.2.4 → 3.3.1
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-D3XaKpZW.js} +46 -44
- package/dashboard-dist/assets/index-D3XaKpZW.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 +154 -0
- package/dist/agent-farm/cli.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 +34 -0
- package/dist/agent-farm/commands/reset.d.ts.map +1 -0
- package/dist/agent-farm/commands/reset.js +309 -0
- package/dist/agent-farm/commands/reset.js.map +1 -0
- package/dist/agent-farm/commands/send.d.ts.map +1 -1
- package/dist/agent-farm/commands/send.js +49 -8
- package/dist/agent-farm/commands/send.js.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.d.ts +105 -6
- package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.js +289 -66
- 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 +80 -8
- package/dist/agent-farm/commands/status.js.map +1 -1
- package/dist/agent-farm/commands/tower.d.ts.map +1 -1
- package/dist/agent-farm/commands/tower.js +13 -0
- package/dist/agent-farm/commands/tower.js.map +1 -1
- 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 +64 -0
- package/dist/agent-farm/lib/reconnect-backoff.d.ts.map +1 -0
- package/dist/agent-farm/lib/reconnect-backoff.js +57 -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 +225 -30
- package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
- package/dist/agent-farm/servers/canvas-relay.d.ts +60 -0
- package/dist/agent-farm/servers/canvas-relay.d.ts.map +1 -0
- package/dist/agent-farm/servers/canvas-relay.js +376 -0
- package/dist/agent-farm/servers/canvas-relay.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 +19 -0
- package/dist/agent-farm/servers/overview.d.ts.map +1 -1
- package/dist/agent-farm/servers/overview.js +100 -4
- package/dist/agent-farm/servers/overview.js.map +1 -1
- 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-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/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 +78 -16
- 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 +826 -145
- package/dist/agent-farm/servers/tower-routes.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +188 -34
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.d.ts +23 -2
- package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.js +134 -127
- 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 +64 -1
- package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-utils.js +168 -1
- package/dist/agent-farm/servers/tower-utils.js.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.d.ts +6 -1
- package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.js +95 -57
- 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/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/agent-farm/utils/message-format.d.ts +8 -0
- package/dist/agent-farm/utils/message-format.d.ts.map +1 -1
- package/dist/agent-farm/utils/message-format.js +20 -0
- package/dist/agent-farm/utils/message-format.js.map +1 -1
- package/dist/agent-farm/utils/server-utils.d.ts +80 -4
- package/dist/agent-farm/utils/server-utils.d.ts.map +1 -1
- package/dist/agent-farm/utils/server-utils.js +286 -5
- package/dist/agent-farm/utils/server-utils.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/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 +272 -28
- 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.map +1 -1
- package/dist/commands/doctor.js +71 -19
- package/dist/commands/doctor.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.js +21 -28
- 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/lib/config.d.ts +69 -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/forge-contracts.d.ts +9 -0
- package/dist/lib/forge-contracts.d.ts.map +1 -1
- package/dist/lib/forge-contracts.js.map +1 -1
- package/dist/lib/github.d.ts +15 -1
- package/dist/lib/github.d.ts.map +1 -1
- package/dist/lib/github.js +18 -1
- package/dist/lib/github.js.map +1 -1
- 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/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/attach-replay.d.ts +39 -0
- package/dist/terminal/attach-replay.d.ts.map +1 -0
- package/dist/terminal/attach-replay.js +76 -0
- package/dist/terminal/attach-replay.js.map +1 -0
- package/dist/terminal/pty-manager.d.ts +2 -0
- package/dist/terminal/pty-manager.d.ts.map +1 -1
- package/dist/terminal/pty-manager.js +51 -23
- package/dist/terminal/pty-manager.js.map +1 -1
- package/dist/terminal/pty-session.d.ts +201 -1
- package/dist/terminal/pty-session.d.ts.map +1 -1
- package/dist/terminal/pty-session.js +327 -46
- 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 +53 -0
- package/dist/terminal/session-manager.d.ts.map +1 -1
- package/dist/terminal/session-manager.js +94 -9
- package/dist/terminal/session-manager.js.map +1 -1
- package/dist/terminal/session-screen.d.ts +116 -0
- package/dist/terminal/session-screen.d.ts.map +1 -0
- package/dist/terminal/session-screen.js +180 -0
- package/dist/terminal/session-screen.js.map +1 -0
- 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 +17 -8
- package/dist/terminal/shellper-process.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 +13 -8
- package/scripts/forge/gitea/pr-view.sh +4 -1
- package/scripts/forge/github/pr-view.sh +1 -1
- package/scripts/forge/gitlab/pr-view.sh +4 -1
- package/skeleton/.claude/skills/afx/SKILL.md +68 -1
- package/skeleton/.claude/skills/arch-init/SKILL.md +22 -9
- package/skeleton/.claude/skills/arch-save/SKILL.md +183 -0
- package/skeleton/.claude/skills/codev/SKILL.md +31 -0
- package/skeleton/.claude/skills/runnable-worktrees/SKILL.md +119 -0
- package/skeleton/.codex/skills/afx/SKILL.md +68 -1
- package/skeleton/.codex/skills/arch-init/SKILL.md +22 -9
- package/skeleton/.codex/skills/arch-save/SKILL.md +183 -0
- package/skeleton/.codex/skills/codev/SKILL.md +31 -0
- package/skeleton/.codex/skills/runnable-worktrees/SKILL.md +119 -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 +31 -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 +2 -3
- package/skeleton/protocols/pir/prompts/plan.md +1 -4
- package/skeleton/protocols/pir/prompts/review.md +2 -2
- 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 +262 -0
- package/skeleton/resources/commands/consult.md +236 -8
- package/skeleton/resources/commands/overview.md +1 -0
- package/skeleton/roles/architect.md +67 -317
- package/skeleton/roles/builder.md +76 -191
- package/skeleton/templates/AGENTS.md +2 -0
- package/skeleton/templates/CLAUDE.md +2 -0
- package/templates/3d-viewer.html +32 -4
- package/templates/open.html +58 -12
- package/templates/tower.html +65 -9
- package/templates/vendor/three-3MFLoader.js +1478 -0
- package/templates/vendor/three-STLLoader.js +410 -0
- package/templates/vendor/three-TrackballControls.js +828 -0
- package/templates/vendor/three-fflate.module.js +2474 -0
- package/templates/vendor/three.module.js +53044 -0
- 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 -116
- 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,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mailbox repository (Spec 1313 — mailbox-first delivery).
|
|
3
|
+
*
|
|
4
|
+
* Pure, unit-testable data operations over the `mailbox` table. Every `afx send`
|
|
5
|
+
* is persisted here *before* the send response returns, so nothing is lost to a
|
|
6
|
+
* Tower crash, restart, or shutdown. This module is deliberately decoupled from
|
|
7
|
+
* delivery: it never writes to a PTY and never runs the render-gate. The delivery
|
|
8
|
+
* orchestration (Phase 4) wires against these proven operations.
|
|
9
|
+
*
|
|
10
|
+
* Design notes:
|
|
11
|
+
* - Functions take an explicit `db` handle first (matching `db/consolidate.ts`),
|
|
12
|
+
* which keeps them trivially testable against any better-sqlite3 database.
|
|
13
|
+
* - Timestamps are epoch-ms integers supplied by the caller (defaulting to
|
|
14
|
+
* `Date.now()`), so ordering and age math are deterministic and test-injectable.
|
|
15
|
+
* - `workspace_path` is treated as an opaque addressing key: callers pass a
|
|
16
|
+
* canonical path (the send boundary canonicalizes in Phase 4), mirroring how
|
|
17
|
+
* `cron_tasks` scopes by workspace. This module does not canonicalize.
|
|
18
|
+
* - The lifecycle state machine (`held → delivered | superseded | dismissed`) is
|
|
19
|
+
* enforced here: every transition targets only `held` rows, so a terminal row
|
|
20
|
+
* can never revert (no `delivered → held`) and `supersede` only replaces a row
|
|
21
|
+
* that is still `held`.
|
|
22
|
+
*/
|
|
23
|
+
import type Database from 'better-sqlite3';
|
|
24
|
+
import type { DbMailbox, MailboxReason } from './types.js';
|
|
25
|
+
/**
|
|
26
|
+
* Fields a caller supplies to persist a new held row. The repository fills in the
|
|
27
|
+
* id, `held` status, `escalated=0`, and the timestamps.
|
|
28
|
+
*/
|
|
29
|
+
export interface EnqueueInput {
|
|
30
|
+
workspacePath: string;
|
|
31
|
+
toAgent: string;
|
|
32
|
+
/** Raw message body (never logged). */
|
|
33
|
+
body: string;
|
|
34
|
+
/** Exact bytes written to the PTY on delivery. */
|
|
35
|
+
formattedMessage: string;
|
|
36
|
+
/** Last-known PTY hint; the recipient is the agent, not this terminal. */
|
|
37
|
+
terminalId?: string | null;
|
|
38
|
+
fromAgent?: string | null;
|
|
39
|
+
fromWorkspace?: string | null;
|
|
40
|
+
/** Stage the text without submitting (no trailing Enter). */
|
|
41
|
+
noEnter?: boolean;
|
|
42
|
+
/** Initial why-held reason; null if it will be delivered immediately. */
|
|
43
|
+
reason?: MailboxReason | null;
|
|
44
|
+
/** Cron-only coalescing key; null for direct sends. */
|
|
45
|
+
supersedeKey?: string | null;
|
|
46
|
+
/**
|
|
47
|
+
* Delayed-send due time in epoch-ms (Spec 1313 round 3 — `--delay`). null means
|
|
48
|
+
* deliver-ASAP (every non-delayed send). A row is deliverable only once
|
|
49
|
+
* `not_before IS NULL OR not_before <= now`; a delayed send persists this at REQUEST
|
|
50
|
+
* time so the delay is durable across a Tower restart.
|
|
51
|
+
*/
|
|
52
|
+
notBefore?: number | null;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Persist a new `held` row and return it. This is the persist-first step: the row
|
|
56
|
+
* exists (and survives a crash) before any delivery is attempted.
|
|
57
|
+
*/
|
|
58
|
+
export declare function enqueue(db: Database.Database, input: EnqueueInput, now?: number): DbMailbox;
|
|
59
|
+
/** Fetch a single row by id, or null if it does not exist. */
|
|
60
|
+
export declare function getById(db: Database.Database, id: string): DbMailbox | null;
|
|
61
|
+
/**
|
|
62
|
+
* List all currently-held rows, oldest first. Scoped to `workspacePath` when
|
|
63
|
+
* provided, else workspace-wide (for `afx inbox`). `id` breaks created_at ties
|
|
64
|
+
* for deterministic ordering.
|
|
65
|
+
*/
|
|
66
|
+
export declare function listHeld(db: Database.Database, workspacePath?: string): DbMailbox[];
|
|
67
|
+
/**
|
|
68
|
+
* ELIGIBLE held rows addressed to a specific agent, in enqueue order (`created_at ASC`).
|
|
69
|
+
* This is the per-agent drain order a delivery pass walks.
|
|
70
|
+
*
|
|
71
|
+
* Spec 1313 round 3 (`--delay`): a row is deliverable only when
|
|
72
|
+
* `not_before IS NULL OR not_before <= now` — a pre-due delayed send is EXCLUDED here, so it
|
|
73
|
+
* neither delivers early nor blocks a later normal message (the drainer picks `held[0]`, the
|
|
74
|
+
* oldest ELIGIBLE row). It becomes eligible on the first pass at/after its due time. `now`
|
|
75
|
+
* defaults to `Date.now()` and is injectable for deterministic tests.
|
|
76
|
+
*/
|
|
77
|
+
export declare function findHeldForAgent(db: Database.Database, workspacePath: string, toAgent: string, now?: number): DbMailbox[];
|
|
78
|
+
/**
|
|
79
|
+
* Held rows whose escalation age ({@link ESCALATION_START_SQL} → now) has crossed `maxAgeMs`
|
|
80
|
+
* and that have NOT yet been escalated. Tower-global (every workspace) — the drainer's
|
|
81
|
+
* escalation pass walks these once per tick to flip `escalated` and emit the visibility
|
|
82
|
+
* broadcast. Bounded by the (small) held set, so a full scan is fine. Oldest effective-start
|
|
83
|
+
* escalates first.
|
|
84
|
+
*
|
|
85
|
+
* Spec 1313 round 3: a PRE-DUE delayed row never escalates — its effective start is its
|
|
86
|
+
* future `not_before`, which cannot be `< cutoff` (cutoff = now − maxAgeMs ≤ now), so the
|
|
87
|
+
* age filter excludes it by construction. A delayed row escalates only after it has been
|
|
88
|
+
* deliverable-but-stuck (past its due time) for the window.
|
|
89
|
+
*/
|
|
90
|
+
export declare function findEscalatable(db: Database.Database, maxAgeMs: number, now?: number): DbMailbox[];
|
|
91
|
+
/** Per-agent held tally within a workspace (drives the overview's live indicator). */
|
|
92
|
+
export interface HeldAgentCount {
|
|
93
|
+
toAgent: string;
|
|
94
|
+
count: number;
|
|
95
|
+
/** True if any of this agent's held rows has crossed the escalation age. */
|
|
96
|
+
escalated: boolean;
|
|
97
|
+
}
|
|
98
|
+
/** Workspace-level held summary: total, whether any row is escalated, and the per-agent split. */
|
|
99
|
+
export interface WorkspaceHeldSummary {
|
|
100
|
+
total: number;
|
|
101
|
+
escalated: boolean;
|
|
102
|
+
byAgent: HeldAgentCount[];
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Count currently-held rows for a workspace, grouped by recipient agent, with an
|
|
106
|
+
* escalation flag. Counts only — **no message bodies** are read or returned, so this is
|
|
107
|
+
* safe to fold into the overview payload that the dashboard/VSCode indicator renders
|
|
108
|
+
* (spec: the indicator is count-only; bodies live only in `afx inbox`). Aggregated in
|
|
109
|
+
* SQL so cost is bounded by the (small) held set, not the row bodies.
|
|
110
|
+
*
|
|
111
|
+
* ELIGIBLE rows only (Spec 1313 round 3): a PRE-DUE delayed send (`not_before` in the
|
|
112
|
+
* future) is "scheduled, not stuck" and must NOT inflate the attention count/indicator —
|
|
113
|
+
* this is the same `not_before IS NULL OR not_before <= now` eligibility every other
|
|
114
|
+
* count/alarm surface uses (`findHeldForAgent`, `findEscalatable`, `findStarvingAgents`),
|
|
115
|
+
* so `afx status` / the dashboard badge report deliverable-but-stuck mail, not scheduled
|
|
116
|
+
* sends. (Pre-due rows are still visible in `afx inbox`, which lists ALL held rows and
|
|
117
|
+
* labels these "scheduled" — only the count/alarm surfaces exclude them.) The `escalated`
|
|
118
|
+
* flag was already pre-due-safe (a pre-due row never escalates); this aligns the raw count.
|
|
119
|
+
*/
|
|
120
|
+
export declare function heldSummaryForWorkspace(db: Database.Database, workspacePath: string, now?: number): WorkspaceHeldSummary;
|
|
121
|
+
/**
|
|
122
|
+
* Transition a held row to `delivered` (clearing its why-held reason and stamping
|
|
123
|
+
* `resolved_at`). Returns true if it transitioned; false if the row was already
|
|
124
|
+
* terminal or does not exist — so a re-delivery attempt (backstop racing a submit
|
|
125
|
+
* trigger) is a safe no-op and can never revert or double-deliver a row.
|
|
126
|
+
*/
|
|
127
|
+
export declare function markDelivered(db: Database.Database, id: string, now?: number): boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Refresh the why-held `reason` on a still-held row (informational — the value
|
|
130
|
+
* `afx inbox` shows and the send response reports). Only touches `held` rows, so
|
|
131
|
+
* it can never relabel or resurrect a terminal row. Returns true if a held row was
|
|
132
|
+
* updated. The delivery pass calls this so a held row's reason tracks the current
|
|
133
|
+
* gate verdict (e.g. `busy` → `no-live-pty` when the terminal dies).
|
|
134
|
+
*/
|
|
135
|
+
export declare function setHeldReason(db: Database.Database, id: string, reason: MailboxReason | null, now?: number): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Flag a still-held row as escalated — **visibility only, NEVER affects delivery**. The
|
|
138
|
+
* drainer's escalation pass calls this when a row crosses the escalation age, then emits
|
|
139
|
+
* the escalation broadcast; the row still delivers only on a later clean gate pass.
|
|
140
|
+
* Held-only and idempotent (the `escalated = 0` guard), so a terminal or already-escalated
|
|
141
|
+
* row is untouched. Returns true if it flipped.
|
|
142
|
+
*/
|
|
143
|
+
export declare function markEscalated(db: Database.Database, id: string, now?: number): boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Supersede-key prefix for architect starvation notices (Spec 1313 round 3, change 3). A
|
|
146
|
+
* notice row carries `${NOTICE_SUPERSEDE_PREFIX}<starving-agent>` so (a) one pending notice
|
|
147
|
+
* per starving agent coalesces via {@link supersede}, and (b) notice rows are recognizable by
|
|
148
|
+
* prefix and EXCLUDED from {@link findStarvingAgents} — a notice can never itself trigger a
|
|
149
|
+
* notice ("no notice about a notice"). Cron uses bare task names as keys, which never collide
|
|
150
|
+
* with this prefix.
|
|
151
|
+
*/
|
|
152
|
+
export declare const NOTICE_SUPERSEDE_PREFIX = "mailbox-notice:";
|
|
153
|
+
/** Per-agent aggregate over an agent's ELIGIBLE, non-notice held rows (Spec 1313 round 3). */
|
|
154
|
+
export interface StarvingAgent {
|
|
155
|
+
workspacePath: string;
|
|
156
|
+
toAgent: string;
|
|
157
|
+
/**
|
|
158
|
+
* Escalation-start ({@link ESCALATION_START_SQL}) of the OLDEST eligible held row — the
|
|
159
|
+
* moment this agent's oldest deliverable mail became stuck. Its age is `now - stuckSince`.
|
|
160
|
+
*/
|
|
161
|
+
stuckSince: number;
|
|
162
|
+
/** How many eligible non-notice rows are held for this agent. */
|
|
163
|
+
count: number;
|
|
164
|
+
/** Representative why-held reason (held rows for one agent share the gate's verdict). */
|
|
165
|
+
reason: MailboxReason | null;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Per-agent view of currently-STARVING mail (Spec 1313 round 3, change 3): agents with at
|
|
169
|
+
* least one ELIGIBLE (`not_before IS NULL OR not_before <= now`) held row that is NOT itself a
|
|
170
|
+
* notice ({@link NOTICE_SUPERSEDE_PREFIX}). Tower-global (every workspace), aggregated in SQL
|
|
171
|
+
* so cost is bounded by the (small) held set. The drainer's notice pass compares each agent's
|
|
172
|
+
* `stuckSince` against the owner-notice threshold to decide whether to alarm, and uses the
|
|
173
|
+
* membership of the returned set to decide when a prior notice can be cleared (agent no longer
|
|
174
|
+
* has any eligible non-notice held row → drained). PRE-DUE delayed rows are excluded (not
|
|
175
|
+
* stuck), so a scheduled send never trips the alarm nor keeps one alive.
|
|
176
|
+
*/
|
|
177
|
+
export declare function findStarvingAgents(db: Database.Database, now?: number): StarvingAgent[];
|
|
178
|
+
/**
|
|
179
|
+
* Dismiss every still-`held` row matching `(workspacePath, supersedeKey)` (Spec 1313 round 3).
|
|
180
|
+
* Used to clear a pending architect notice once its starving agent recovers (the notice is
|
|
181
|
+
* moot). Audit-preserving (soft transition), and a no-op on an already-delivered notice.
|
|
182
|
+
* Returns the number of rows dismissed.
|
|
183
|
+
*/
|
|
184
|
+
export declare function dismissHeldWithKey(db: Database.Database, workspacePath: string, supersedeKey: string, now?: number): number;
|
|
185
|
+
/**
|
|
186
|
+
* Dismiss every still-`held` row addressed to an agent (Spec 1313 round 3, take-now B). Called
|
|
187
|
+
* when an agent is cleaned up (`afx cleanup`) so its orphaned held rows stop pinning
|
|
188
|
+
* `heldCount`/escalated forever — the terminal-row prune only removes delivered/superseded/
|
|
189
|
+
* dismissed rows, never held ones. Audit-preserving. Returns the number of rows dismissed.
|
|
190
|
+
*/
|
|
191
|
+
export declare function dismissHeldForAgent(db: Database.Database, workspacePath: string, toAgent: string, now?: number): number;
|
|
192
|
+
/**
|
|
193
|
+
* Transition a held row to `dismissed` (operator-cleared via `afx inbox dismiss`).
|
|
194
|
+
* The why-held reason is preserved for audit. Returns true if it transitioned;
|
|
195
|
+
* a dismissed row is never delivered.
|
|
196
|
+
*/
|
|
197
|
+
export declare function dismiss(db: Database.Database, id: string, now?: number): boolean;
|
|
198
|
+
/**
|
|
199
|
+
* Count currently-`held` rows sharing `(workspacePath, supersedeKey)`. Cron reads
|
|
200
|
+
* this immediately before {@link supersede} — with no `await` between the two calls,
|
|
201
|
+
* so on better-sqlite3's synchronous, single-threaded handle the pair cannot
|
|
202
|
+
* interleave with another run — to log an honest outcome: a newer run that finds a
|
|
203
|
+
* prior held row of the same task reports `superseded`, otherwise `held`. The
|
|
204
|
+
* `(supersede_key)` index keeps this cheap.
|
|
205
|
+
*/
|
|
206
|
+
export declare function countHeldWithKey(db: Database.Database, workspacePath: string, supersedeKey: string): number;
|
|
207
|
+
/**
|
|
208
|
+
* Replace the held row sharing `(workspacePath, supersedeKey)` — if any — with a
|
|
209
|
+
* fresh held row carrying the same key, atomically. Only `held` rows are
|
|
210
|
+
* superseded (a delivered/dismissed row is untouched), so a newer cron run
|
|
211
|
+
* collapses a stale backlog without disturbing history. When no held row matches,
|
|
212
|
+
* this is just an enqueue. Returns the newly-enqueued replacement row.
|
|
213
|
+
*/
|
|
214
|
+
export declare function supersede(db: Database.Database, workspacePath: string, supersedeKey: string, input: EnqueueInput, now?: number): DbMailbox;
|
|
215
|
+
/**
|
|
216
|
+
* Delete terminal rows (delivered/superseded/dismissed) whose `resolved_at` is
|
|
217
|
+
* older than `retentionDays`. Held rows are never removed — the `status != 'held'`
|
|
218
|
+
* and `resolved_at IS NOT NULL` guards make that impossible even if a held row
|
|
219
|
+
* somehow carried a stale timestamp. Returns the number of rows deleted.
|
|
220
|
+
*/
|
|
221
|
+
export declare function pruneTerminal(db: Database.Database, retentionDays: number, now?: number): number;
|
|
222
|
+
//# sourceMappingURL=mailbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailbox.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/db/mailbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mailbox repository (Spec 1313 — mailbox-first delivery).
|
|
3
|
+
*
|
|
4
|
+
* Pure, unit-testable data operations over the `mailbox` table. Every `afx send`
|
|
5
|
+
* is persisted here *before* the send response returns, so nothing is lost to a
|
|
6
|
+
* Tower crash, restart, or shutdown. This module is deliberately decoupled from
|
|
7
|
+
* delivery: it never writes to a PTY and never runs the render-gate. The delivery
|
|
8
|
+
* orchestration (Phase 4) wires against these proven operations.
|
|
9
|
+
*
|
|
10
|
+
* Design notes:
|
|
11
|
+
* - Functions take an explicit `db` handle first (matching `db/consolidate.ts`),
|
|
12
|
+
* which keeps them trivially testable against any better-sqlite3 database.
|
|
13
|
+
* - Timestamps are epoch-ms integers supplied by the caller (defaulting to
|
|
14
|
+
* `Date.now()`), so ordering and age math are deterministic and test-injectable.
|
|
15
|
+
* - `workspace_path` is treated as an opaque addressing key: callers pass a
|
|
16
|
+
* canonical path (the send boundary canonicalizes in Phase 4), mirroring how
|
|
17
|
+
* `cron_tasks` scopes by workspace. This module does not canonicalize.
|
|
18
|
+
* - The lifecycle state machine (`held → delivered | superseded | dismissed`) is
|
|
19
|
+
* enforced here: every transition targets only `held` rows, so a terminal row
|
|
20
|
+
* can never revert (no `delivered → held`) and `supersede` only replaces a row
|
|
21
|
+
* that is still `held`.
|
|
22
|
+
*/
|
|
23
|
+
import { randomUUID } from 'node:crypto';
|
|
24
|
+
const INSERT_SQL = `
|
|
25
|
+
INSERT INTO mailbox (
|
|
26
|
+
id, workspace_path, to_agent, terminal_id, from_agent, from_workspace,
|
|
27
|
+
body, formatted_message, no_enter, status, reason, supersede_key,
|
|
28
|
+
escalated, not_before, created_at, updated_at, resolved_at
|
|
29
|
+
) VALUES (
|
|
30
|
+
@id, @workspace_path, @to_agent, @terminal_id, @from_agent, @from_workspace,
|
|
31
|
+
@body, @formatted_message, @no_enter, @status, @reason, @supersede_key,
|
|
32
|
+
@escalated, @not_before, @created_at, @updated_at, @resolved_at
|
|
33
|
+
)
|
|
34
|
+
`;
|
|
35
|
+
function buildRow(input, now) {
|
|
36
|
+
return {
|
|
37
|
+
id: randomUUID(),
|
|
38
|
+
workspace_path: input.workspacePath,
|
|
39
|
+
to_agent: input.toAgent,
|
|
40
|
+
terminal_id: input.terminalId ?? null,
|
|
41
|
+
from_agent: input.fromAgent ?? null,
|
|
42
|
+
from_workspace: input.fromWorkspace ?? null,
|
|
43
|
+
body: input.body,
|
|
44
|
+
formatted_message: input.formattedMessage,
|
|
45
|
+
no_enter: input.noEnter ? 1 : 0,
|
|
46
|
+
status: 'held',
|
|
47
|
+
reason: input.reason ?? null,
|
|
48
|
+
supersede_key: input.supersedeKey ?? null,
|
|
49
|
+
escalated: 0,
|
|
50
|
+
not_before: input.notBefore ?? null,
|
|
51
|
+
created_at: now,
|
|
52
|
+
updated_at: now,
|
|
53
|
+
resolved_at: null,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Persist a new `held` row and return it. This is the persist-first step: the row
|
|
58
|
+
* exists (and survives a crash) before any delivery is attempted.
|
|
59
|
+
*/
|
|
60
|
+
export function enqueue(db, input, now = Date.now()) {
|
|
61
|
+
const row = buildRow(input, now);
|
|
62
|
+
db.prepare(INSERT_SQL).run(row);
|
|
63
|
+
return row;
|
|
64
|
+
}
|
|
65
|
+
/** Fetch a single row by id, or null if it does not exist. */
|
|
66
|
+
export function getById(db, id) {
|
|
67
|
+
const row = db.prepare('SELECT * FROM mailbox WHERE id = ?').get(id);
|
|
68
|
+
return row ?? null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* List all currently-held rows, oldest first. Scoped to `workspacePath` when
|
|
72
|
+
* provided, else workspace-wide (for `afx inbox`). `id` breaks created_at ties
|
|
73
|
+
* for deterministic ordering.
|
|
74
|
+
*/
|
|
75
|
+
export function listHeld(db, workspacePath) {
|
|
76
|
+
if (workspacePath !== undefined) {
|
|
77
|
+
return db
|
|
78
|
+
.prepare("SELECT * FROM mailbox WHERE workspace_path = ? AND status = 'held' ORDER BY created_at ASC, id ASC")
|
|
79
|
+
.all(workspacePath);
|
|
80
|
+
}
|
|
81
|
+
return db
|
|
82
|
+
.prepare("SELECT * FROM mailbox WHERE status = 'held' ORDER BY created_at ASC, id ASC")
|
|
83
|
+
.all();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* ELIGIBLE held rows addressed to a specific agent, in enqueue order (`created_at ASC`).
|
|
87
|
+
* This is the per-agent drain order a delivery pass walks.
|
|
88
|
+
*
|
|
89
|
+
* Spec 1313 round 3 (`--delay`): a row is deliverable only when
|
|
90
|
+
* `not_before IS NULL OR not_before <= now` — a pre-due delayed send is EXCLUDED here, so it
|
|
91
|
+
* neither delivers early nor blocks a later normal message (the drainer picks `held[0]`, the
|
|
92
|
+
* oldest ELIGIBLE row). It becomes eligible on the first pass at/after its due time. `now`
|
|
93
|
+
* defaults to `Date.now()` and is injectable for deterministic tests.
|
|
94
|
+
*/
|
|
95
|
+
export function findHeldForAgent(db, workspacePath, toAgent, now = Date.now()) {
|
|
96
|
+
return db
|
|
97
|
+
.prepare("SELECT * FROM mailbox WHERE workspace_path = ? AND to_agent = ? AND status = 'held' AND (not_before IS NULL OR not_before <= ?) ORDER BY created_at ASC, id ASC")
|
|
98
|
+
.all(workspacePath, toAgent, now);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* SQL for a held row's escalation-age START — the moment it became *deliverable-but-stuck*.
|
|
102
|
+
* For a normal row that is `created_at` (born held then). For a delayed row (`not_before`
|
|
103
|
+
* set) it is the DUE time, so a still-scheduled row's clock has not started (Spec 1313 round
|
|
104
|
+
* 3: "measure escalation age from max(created_at, not_before)"). `not_before` is always ≥
|
|
105
|
+
* `created_at` when set (due = created + delay), so MAX == COALESCE(not_before, created_at);
|
|
106
|
+
* MAX is kept so a hand-written earlier not_before can never move the start before enqueue.
|
|
107
|
+
*/
|
|
108
|
+
const ESCALATION_START_SQL = 'MAX(created_at, COALESCE(not_before, created_at))';
|
|
109
|
+
/**
|
|
110
|
+
* Held rows whose escalation age ({@link ESCALATION_START_SQL} → now) has crossed `maxAgeMs`
|
|
111
|
+
* and that have NOT yet been escalated. Tower-global (every workspace) — the drainer's
|
|
112
|
+
* escalation pass walks these once per tick to flip `escalated` and emit the visibility
|
|
113
|
+
* broadcast. Bounded by the (small) held set, so a full scan is fine. Oldest effective-start
|
|
114
|
+
* escalates first.
|
|
115
|
+
*
|
|
116
|
+
* Spec 1313 round 3: a PRE-DUE delayed row never escalates — its effective start is its
|
|
117
|
+
* future `not_before`, which cannot be `< cutoff` (cutoff = now − maxAgeMs ≤ now), so the
|
|
118
|
+
* age filter excludes it by construction. A delayed row escalates only after it has been
|
|
119
|
+
* deliverable-but-stuck (past its due time) for the window.
|
|
120
|
+
*/
|
|
121
|
+
export function findEscalatable(db, maxAgeMs, now = Date.now()) {
|
|
122
|
+
const cutoff = now - maxAgeMs;
|
|
123
|
+
return db
|
|
124
|
+
.prepare(`SELECT * FROM mailbox WHERE status = 'held' AND escalated = 0 AND ${ESCALATION_START_SQL} < ? ORDER BY ${ESCALATION_START_SQL} ASC, id ASC`)
|
|
125
|
+
.all(cutoff);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Count currently-held rows for a workspace, grouped by recipient agent, with an
|
|
129
|
+
* escalation flag. Counts only — **no message bodies** are read or returned, so this is
|
|
130
|
+
* safe to fold into the overview payload that the dashboard/VSCode indicator renders
|
|
131
|
+
* (spec: the indicator is count-only; bodies live only in `afx inbox`). Aggregated in
|
|
132
|
+
* SQL so cost is bounded by the (small) held set, not the row bodies.
|
|
133
|
+
*
|
|
134
|
+
* ELIGIBLE rows only (Spec 1313 round 3): a PRE-DUE delayed send (`not_before` in the
|
|
135
|
+
* future) is "scheduled, not stuck" and must NOT inflate the attention count/indicator —
|
|
136
|
+
* this is the same `not_before IS NULL OR not_before <= now` eligibility every other
|
|
137
|
+
* count/alarm surface uses (`findHeldForAgent`, `findEscalatable`, `findStarvingAgents`),
|
|
138
|
+
* so `afx status` / the dashboard badge report deliverable-but-stuck mail, not scheduled
|
|
139
|
+
* sends. (Pre-due rows are still visible in `afx inbox`, which lists ALL held rows and
|
|
140
|
+
* labels these "scheduled" — only the count/alarm surfaces exclude them.) The `escalated`
|
|
141
|
+
* flag was already pre-due-safe (a pre-due row never escalates); this aligns the raw count.
|
|
142
|
+
*/
|
|
143
|
+
export function heldSummaryForWorkspace(db, workspacePath, now = Date.now()) {
|
|
144
|
+
const rows = db
|
|
145
|
+
.prepare("SELECT to_agent AS toAgent, COUNT(*) AS count, MAX(escalated) AS esc FROM mailbox WHERE workspace_path = ? AND status = 'held' AND (not_before IS NULL OR not_before <= ?) GROUP BY to_agent")
|
|
146
|
+
.all(workspacePath, now);
|
|
147
|
+
let total = 0;
|
|
148
|
+
let escalated = false;
|
|
149
|
+
const byAgent = rows.map((r) => {
|
|
150
|
+
total += r.count;
|
|
151
|
+
const rowEsc = r.esc === 1;
|
|
152
|
+
if (rowEsc)
|
|
153
|
+
escalated = true;
|
|
154
|
+
return { toAgent: r.toAgent, count: r.count, escalated: rowEsc };
|
|
155
|
+
});
|
|
156
|
+
return { total, escalated, byAgent };
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Transition a held row to `delivered` (clearing its why-held reason and stamping
|
|
160
|
+
* `resolved_at`). Returns true if it transitioned; false if the row was already
|
|
161
|
+
* terminal or does not exist — so a re-delivery attempt (backstop racing a submit
|
|
162
|
+
* trigger) is a safe no-op and can never revert or double-deliver a row.
|
|
163
|
+
*/
|
|
164
|
+
export function markDelivered(db, id, now = Date.now()) {
|
|
165
|
+
const info = db
|
|
166
|
+
.prepare("UPDATE mailbox SET status = 'delivered', reason = NULL, updated_at = ?, resolved_at = ? WHERE id = ? AND status = 'held'")
|
|
167
|
+
.run(now, now, id);
|
|
168
|
+
return info.changes > 0;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Refresh the why-held `reason` on a still-held row (informational — the value
|
|
172
|
+
* `afx inbox` shows and the send response reports). Only touches `held` rows, so
|
|
173
|
+
* it can never relabel or resurrect a terminal row. Returns true if a held row was
|
|
174
|
+
* updated. The delivery pass calls this so a held row's reason tracks the current
|
|
175
|
+
* gate verdict (e.g. `busy` → `no-live-pty` when the terminal dies).
|
|
176
|
+
*/
|
|
177
|
+
export function setHeldReason(db, id, reason, now = Date.now()) {
|
|
178
|
+
const info = db
|
|
179
|
+
.prepare("UPDATE mailbox SET reason = ?, updated_at = ? WHERE id = ? AND status = 'held'")
|
|
180
|
+
.run(reason, now, id);
|
|
181
|
+
return info.changes > 0;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Flag a still-held row as escalated — **visibility only, NEVER affects delivery**. The
|
|
185
|
+
* drainer's escalation pass calls this when a row crosses the escalation age, then emits
|
|
186
|
+
* the escalation broadcast; the row still delivers only on a later clean gate pass.
|
|
187
|
+
* Held-only and idempotent (the `escalated = 0` guard), so a terminal or already-escalated
|
|
188
|
+
* row is untouched. Returns true if it flipped.
|
|
189
|
+
*/
|
|
190
|
+
export function markEscalated(db, id, now = Date.now()) {
|
|
191
|
+
const info = db
|
|
192
|
+
.prepare("UPDATE mailbox SET escalated = 1, updated_at = ? WHERE id = ? AND status = 'held' AND escalated = 0")
|
|
193
|
+
.run(now, id);
|
|
194
|
+
return info.changes > 0;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Supersede-key prefix for architect starvation notices (Spec 1313 round 3, change 3). A
|
|
198
|
+
* notice row carries `${NOTICE_SUPERSEDE_PREFIX}<starving-agent>` so (a) one pending notice
|
|
199
|
+
* per starving agent coalesces via {@link supersede}, and (b) notice rows are recognizable by
|
|
200
|
+
* prefix and EXCLUDED from {@link findStarvingAgents} — a notice can never itself trigger a
|
|
201
|
+
* notice ("no notice about a notice"). Cron uses bare task names as keys, which never collide
|
|
202
|
+
* with this prefix.
|
|
203
|
+
*/
|
|
204
|
+
export const NOTICE_SUPERSEDE_PREFIX = 'mailbox-notice:';
|
|
205
|
+
/**
|
|
206
|
+
* Per-agent view of currently-STARVING mail (Spec 1313 round 3, change 3): agents with at
|
|
207
|
+
* least one ELIGIBLE (`not_before IS NULL OR not_before <= now`) held row that is NOT itself a
|
|
208
|
+
* notice ({@link NOTICE_SUPERSEDE_PREFIX}). Tower-global (every workspace), aggregated in SQL
|
|
209
|
+
* so cost is bounded by the (small) held set. The drainer's notice pass compares each agent's
|
|
210
|
+
* `stuckSince` against the owner-notice threshold to decide whether to alarm, and uses the
|
|
211
|
+
* membership of the returned set to decide when a prior notice can be cleared (agent no longer
|
|
212
|
+
* has any eligible non-notice held row → drained). PRE-DUE delayed rows are excluded (not
|
|
213
|
+
* stuck), so a scheduled send never trips the alarm nor keeps one alive.
|
|
214
|
+
*/
|
|
215
|
+
export function findStarvingAgents(db, now = Date.now()) {
|
|
216
|
+
return db
|
|
217
|
+
.prepare(`SELECT workspace_path AS workspacePath, to_agent AS toAgent,
|
|
218
|
+
MIN(${ESCALATION_START_SQL}) AS stuckSince,
|
|
219
|
+
COUNT(*) AS count,
|
|
220
|
+
MAX(reason) AS reason
|
|
221
|
+
FROM mailbox
|
|
222
|
+
WHERE status = 'held'
|
|
223
|
+
AND (not_before IS NULL OR not_before <= ?)
|
|
224
|
+
AND (supersede_key IS NULL OR supersede_key NOT LIKE ?)
|
|
225
|
+
GROUP BY workspace_path, to_agent`)
|
|
226
|
+
.all(now, `${NOTICE_SUPERSEDE_PREFIX}%`);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Dismiss every still-`held` row matching `(workspacePath, supersedeKey)` (Spec 1313 round 3).
|
|
230
|
+
* Used to clear a pending architect notice once its starving agent recovers (the notice is
|
|
231
|
+
* moot). Audit-preserving (soft transition), and a no-op on an already-delivered notice.
|
|
232
|
+
* Returns the number of rows dismissed.
|
|
233
|
+
*/
|
|
234
|
+
export function dismissHeldWithKey(db, workspacePath, supersedeKey, now = Date.now()) {
|
|
235
|
+
const info = db
|
|
236
|
+
.prepare("UPDATE mailbox SET status = 'dismissed', updated_at = ?, resolved_at = ? WHERE workspace_path = ? AND supersede_key = ? AND status = 'held'")
|
|
237
|
+
.run(now, now, workspacePath, supersedeKey);
|
|
238
|
+
return info.changes;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Dismiss every still-`held` row addressed to an agent (Spec 1313 round 3, take-now B). Called
|
|
242
|
+
* when an agent is cleaned up (`afx cleanup`) so its orphaned held rows stop pinning
|
|
243
|
+
* `heldCount`/escalated forever — the terminal-row prune only removes delivered/superseded/
|
|
244
|
+
* dismissed rows, never held ones. Audit-preserving. Returns the number of rows dismissed.
|
|
245
|
+
*/
|
|
246
|
+
export function dismissHeldForAgent(db, workspacePath, toAgent, now = Date.now()) {
|
|
247
|
+
const info = db
|
|
248
|
+
.prepare("UPDATE mailbox SET status = 'dismissed', updated_at = ?, resolved_at = ? WHERE workspace_path = ? AND to_agent = ? AND status = 'held'")
|
|
249
|
+
.run(now, now, workspacePath, toAgent);
|
|
250
|
+
return info.changes;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Transition a held row to `dismissed` (operator-cleared via `afx inbox dismiss`).
|
|
254
|
+
* The why-held reason is preserved for audit. Returns true if it transitioned;
|
|
255
|
+
* a dismissed row is never delivered.
|
|
256
|
+
*/
|
|
257
|
+
export function dismiss(db, id, now = Date.now()) {
|
|
258
|
+
const info = db
|
|
259
|
+
.prepare("UPDATE mailbox SET status = 'dismissed', updated_at = ?, resolved_at = ? WHERE id = ? AND status = 'held'")
|
|
260
|
+
.run(now, now, id);
|
|
261
|
+
return info.changes > 0;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Count currently-`held` rows sharing `(workspacePath, supersedeKey)`. Cron reads
|
|
265
|
+
* this immediately before {@link supersede} — with no `await` between the two calls,
|
|
266
|
+
* so on better-sqlite3's synchronous, single-threaded handle the pair cannot
|
|
267
|
+
* interleave with another run — to log an honest outcome: a newer run that finds a
|
|
268
|
+
* prior held row of the same task reports `superseded`, otherwise `held`. The
|
|
269
|
+
* `(supersede_key)` index keeps this cheap.
|
|
270
|
+
*/
|
|
271
|
+
export function countHeldWithKey(db, workspacePath, supersedeKey) {
|
|
272
|
+
const row = db
|
|
273
|
+
.prepare("SELECT COUNT(*) AS n FROM mailbox WHERE workspace_path = ? AND supersede_key = ? AND status = 'held'")
|
|
274
|
+
.get(workspacePath, supersedeKey);
|
|
275
|
+
return row.n;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Replace the held row sharing `(workspacePath, supersedeKey)` — if any — with a
|
|
279
|
+
* fresh held row carrying the same key, atomically. Only `held` rows are
|
|
280
|
+
* superseded (a delivered/dismissed row is untouched), so a newer cron run
|
|
281
|
+
* collapses a stale backlog without disturbing history. When no held row matches,
|
|
282
|
+
* this is just an enqueue. Returns the newly-enqueued replacement row.
|
|
283
|
+
*/
|
|
284
|
+
export function supersede(db, workspacePath, supersedeKey, input, now = Date.now()) {
|
|
285
|
+
const run = db.transaction(() => {
|
|
286
|
+
db.prepare("UPDATE mailbox SET status = 'superseded', updated_at = ?, resolved_at = ? WHERE workspace_path = ? AND supersede_key = ? AND status = 'held'").run(now, now, workspacePath, supersedeKey);
|
|
287
|
+
return enqueue(db, { ...input, workspacePath, supersedeKey }, now);
|
|
288
|
+
});
|
|
289
|
+
return run();
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Delete terminal rows (delivered/superseded/dismissed) whose `resolved_at` is
|
|
293
|
+
* older than `retentionDays`. Held rows are never removed — the `status != 'held'`
|
|
294
|
+
* and `resolved_at IS NOT NULL` guards make that impossible even if a held row
|
|
295
|
+
* somehow carried a stale timestamp. Returns the number of rows deleted.
|
|
296
|
+
*/
|
|
297
|
+
export function pruneTerminal(db, retentionDays, now = Date.now()) {
|
|
298
|
+
const cutoff = now - retentionDays * 24 * 60 * 60 * 1000;
|
|
299
|
+
const info = db
|
|
300
|
+
.prepare("DELETE FROM mailbox WHERE status != 'held' AND resolved_at IS NOT NULL AND resolved_at < ?")
|
|
301
|
+
.run(cutoff);
|
|
302
|
+
return info.changes;
|
|
303
|
+
}
|
|
304
|
+
//# sourceMappingURL=mailbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailbox.js","sourceRoot":"","sources":["../../../src/agent-farm/db/mailbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,5 +19,5 @@ export declare const LOCAL_SCHEMA = "\n-- Schema versioning\nCREATE TABLE IF NOT
|
|
|
19
19
|
* Global registry schema (global.db)
|
|
20
20
|
* Stores terminal sessions and migrations across all workspaces
|
|
21
21
|
*/
|
|
22
|
-
export declare const GLOBAL_SCHEMA = "\n-- Schema versioning\nCREATE TABLE IF NOT EXISTS _migrations (\n version INTEGER PRIMARY KEY,\n applied_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\n-- Terminal sessions (Spec 0090 TICK-001)\n-- Tracks all terminal sessions across all workspaces for persistence and reconciliation\nCREATE TABLE IF NOT EXISTS terminal_sessions (\n id TEXT PRIMARY KEY, -- terminal UUID from PtyManager\n workspace_path TEXT NOT NULL, -- workspace this terminal belongs to\n type TEXT NOT NULL -- 'architect', 'builder', 'shell'\n CHECK(type IN ('architect', 'builder', 'shell')),\n role_id TEXT, -- builder ID or shell ID (null for architect)\n pid INTEGER, -- process ID of the terminal\n shellper_socket TEXT, -- Unix socket path for shellper process\n shellper_pid INTEGER, -- shellper process PID\n shellper_start_time INTEGER, -- shellper process start time (epoch ms)\n label TEXT, -- custom display label (Spec 468)\n cwd TEXT, -- working directory of the terminal (Bugfix #506)\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE INDEX IF NOT EXISTS idx_terminal_sessions_workspace ON terminal_sessions(workspace_path);\nCREATE INDEX IF NOT EXISTS idx_terminal_sessions_type ON terminal_sessions(type);\n\n-- File tabs (Spec 0099 Phase 4)\nCREATE TABLE IF NOT EXISTS file_tabs (\n id TEXT PRIMARY KEY,\n workspace_path TEXT NOT NULL,\n file_path TEXT NOT NULL,\n created_at INTEGER NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_file_tabs_workspace ON file_tabs(workspace_path);\n\n-- Known workspaces (persistent workspace registry)\nCREATE TABLE IF NOT EXISTS known_workspaces (\n workspace_path TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n last_launched_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\n-- Cron tasks (Spec 399)\n-- Tracks scheduled task state across all workspaces\nCREATE TABLE IF NOT EXISTS cron_tasks (\n id TEXT PRIMARY KEY,\n workspace_path TEXT NOT NULL,\n task_name TEXT NOT NULL,\n last_run INTEGER,\n last_result TEXT,\n last_output TEXT,\n enabled INTEGER NOT NULL DEFAULT 1,\n UNIQUE(workspace_path, task_name)\n);\n\n-- ===========================================================================\n-- Issue #1118: tables absorbed from the retired per-workspace state.db.\n-- architect/utils/annotations move as-is; builders is RESHAPED to be\n-- workspace-scoped (composite PK), mirroring architect (Bugfix #826) \u2014 builder\n-- ids are <protocol>-<issueNumber>, unique within a workspace but reused across\n-- repos, so a single shared table must disambiguate by workspace_path.\n-- ===========================================================================\n\n-- Architect sessions (Spec 755 multi-architect; Bugfix #826 workspace-scoped;\n-- Issue #832 session_id). id is the architect's name ('main', siblings).\nCREATE TABLE IF NOT EXISTS architect (\n workspace_path TEXT NOT NULL,\n id TEXT NOT NULL,\n pid INTEGER NOT NULL,\n port INTEGER NOT NULL,\n cmd TEXT NOT NULL,\n started_at TEXT NOT NULL DEFAULT (datetime('now')),\n terminal_id TEXT,\n session_id TEXT,\n PRIMARY KEY (workspace_path, id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_architect_workspace ON architect(workspace_path);\n\n-- Builder sessions. Issue #1118: workspace_path + composite PK so the same\n-- builder id can exist in multiple workspaces without collision.\nCREATE TABLE IF NOT EXISTS builders (\n workspace_path TEXT NOT NULL,\n id TEXT NOT NULL,\n name TEXT NOT NULL,\n port INTEGER NOT NULL DEFAULT 0,\n pid INTEGER NOT NULL DEFAULT 0,\n status TEXT NOT NULL DEFAULT 'spawning'\n CHECK(status IN ('spawning', 'implementing', 'blocked', 'pr', 'complete')),\n phase TEXT NOT NULL DEFAULT '',\n worktree TEXT NOT NULL,\n branch TEXT NOT NULL,\n type TEXT NOT NULL DEFAULT 'spec'\n CHECK(type IN ('spec', 'task', 'protocol', 'shell', 'worktree', 'bugfix', 'pir')),\n task_text TEXT,\n protocol_name TEXT,\n issue_number TEXT,\n terminal_id TEXT,\n spawned_by_architect TEXT,\n started_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (workspace_path, id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_builders_status ON builders(status);\nCREATE INDEX IF NOT EXISTS idx_builders_port ON builders(port);\n\nCREATE TRIGGER IF NOT EXISTS builders_updated_at\n AFTER UPDATE ON builders\n FOR EACH ROW\n BEGIN\n UPDATE builders SET updated_at = datetime('now')\n WHERE workspace_path = NEW.workspace_path AND id = NEW.id;\n END;\n\n-- Utility terminals (UUID-keyed; moved as-is).\nCREATE TABLE IF NOT EXISTS utils (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n port INTEGER NOT NULL DEFAULT 0,\n pid INTEGER NOT NULL DEFAULT 0,\n terminal_id TEXT,\n started_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\n-- Annotations / file viewers (UUID-keyed; moved as-is).\nCREATE TABLE IF NOT EXISTS annotations (\n id TEXT PRIMARY KEY,\n file TEXT NOT NULL,\n port INTEGER NOT NULL DEFAULT 0,\n pid INTEGER NOT NULL DEFAULT 0,\n parent_type TEXT NOT NULL CHECK(parent_type IN ('architect', 'builder', 'util')),\n parent_id TEXT,\n started_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n";
|
|
22
|
+
export declare const GLOBAL_SCHEMA = "\n-- Schema versioning\nCREATE TABLE IF NOT EXISTS _migrations (\n version INTEGER PRIMARY KEY,\n applied_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\n-- Terminal sessions (Spec 0090 TICK-001)\n-- Tracks all terminal sessions across all workspaces for persistence and reconciliation\nCREATE TABLE IF NOT EXISTS terminal_sessions (\n id TEXT PRIMARY KEY, -- terminal UUID from PtyManager\n workspace_path TEXT NOT NULL, -- workspace this terminal belongs to\n type TEXT NOT NULL -- 'architect', 'builder', 'shell'\n CHECK(type IN ('architect', 'builder', 'shell')),\n role_id TEXT, -- builder ID or shell ID (null for architect)\n pid INTEGER, -- process ID of the terminal\n shellper_socket TEXT, -- Unix socket path for shellper process\n shellper_pid INTEGER, -- shellper process PID\n shellper_start_time INTEGER, -- shellper process start time (epoch ms)\n label TEXT, -- custom display label (Spec 468)\n cwd TEXT, -- working directory of the terminal (Bugfix #506)\n command TEXT, -- launch command; render-gate identity seam (Spec 1313)\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE INDEX IF NOT EXISTS idx_terminal_sessions_workspace ON terminal_sessions(workspace_path);\nCREATE INDEX IF NOT EXISTS idx_terminal_sessions_type ON terminal_sessions(type);\n\n-- File tabs (Spec 0099 Phase 4)\nCREATE TABLE IF NOT EXISTS file_tabs (\n id TEXT PRIMARY KEY,\n workspace_path TEXT NOT NULL,\n file_path TEXT NOT NULL,\n created_at INTEGER NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_file_tabs_workspace ON file_tabs(workspace_path);\n\n-- Known workspaces (persistent workspace registry)\nCREATE TABLE IF NOT EXISTS known_workspaces (\n workspace_path TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n last_launched_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\n-- Cron tasks (Spec 399)\n-- Tracks scheduled task state across all workspaces\nCREATE TABLE IF NOT EXISTS cron_tasks (\n id TEXT PRIMARY KEY,\n workspace_path TEXT NOT NULL,\n task_name TEXT NOT NULL,\n last_run INTEGER,\n last_result TEXT,\n last_output TEXT,\n enabled INTEGER NOT NULL DEFAULT 1,\n UNIQUE(workspace_path, task_name)\n);\n\n-- ===========================================================================\n-- Issue #1118: tables absorbed from the retired per-workspace state.db.\n-- architect/utils/annotations move as-is; builders is RESHAPED to be\n-- workspace-scoped (composite PK), mirroring architect (Bugfix #826) \u2014 builder\n-- ids are <protocol>-<issueNumber>, unique within a workspace but reused across\n-- repos, so a single shared table must disambiguate by workspace_path.\n-- ===========================================================================\n\n-- Architect sessions (Spec 755 multi-architect; Bugfix #826 workspace-scoped;\n-- Issue #832 session_id). id is the architect's name ('main', siblings).\nCREATE TABLE IF NOT EXISTS architect (\n workspace_path TEXT NOT NULL,\n id TEXT NOT NULL,\n pid INTEGER NOT NULL,\n port INTEGER NOT NULL,\n cmd TEXT NOT NULL,\n started_at TEXT NOT NULL DEFAULT (datetime('now')),\n terminal_id TEXT,\n session_id TEXT,\n PRIMARY KEY (workspace_path, id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_architect_workspace ON architect(workspace_path);\n\n-- Builder sessions. Issue #1118: workspace_path + composite PK so the same\n-- builder id can exist in multiple workspaces without collision.\nCREATE TABLE IF NOT EXISTS builders (\n workspace_path TEXT NOT NULL,\n id TEXT NOT NULL,\n name TEXT NOT NULL,\n port INTEGER NOT NULL DEFAULT 0,\n pid INTEGER NOT NULL DEFAULT 0,\n status TEXT NOT NULL DEFAULT 'spawning'\n CHECK(status IN ('spawning', 'implementing', 'blocked', 'pr', 'complete')),\n phase TEXT NOT NULL DEFAULT '',\n worktree TEXT NOT NULL,\n branch TEXT NOT NULL,\n type TEXT NOT NULL DEFAULT 'spec'\n CHECK(type IN ('spec', 'task', 'protocol', 'shell', 'worktree', 'bugfix', 'pir')),\n task_text TEXT,\n protocol_name TEXT,\n issue_number TEXT,\n terminal_id TEXT,\n spawned_by_architect TEXT,\n started_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (workspace_path, id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_builders_status ON builders(status);\nCREATE INDEX IF NOT EXISTS idx_builders_port ON builders(port);\n\nCREATE TRIGGER IF NOT EXISTS builders_updated_at\n AFTER UPDATE ON builders\n FOR EACH ROW\n BEGIN\n UPDATE builders SET updated_at = datetime('now')\n WHERE workspace_path = NEW.workspace_path AND id = NEW.id;\n END;\n\n-- Utility terminals (UUID-keyed; moved as-is).\nCREATE TABLE IF NOT EXISTS utils (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n port INTEGER NOT NULL DEFAULT 0,\n pid INTEGER NOT NULL DEFAULT 0,\n terminal_id TEXT,\n started_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\n-- Annotations / file viewers (UUID-keyed; moved as-is).\nCREATE TABLE IF NOT EXISTS annotations (\n id TEXT PRIMARY KEY,\n file TEXT NOT NULL,\n port INTEGER NOT NULL DEFAULT 0,\n pid INTEGER NOT NULL DEFAULT 0,\n parent_type TEXT NOT NULL CHECK(parent_type IN ('architect', 'builder', 'util')),\n parent_id TEXT,\n started_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\n-- Mailbox (Spec 1313): durable home for every 'afx send'.\n-- Persist-first delivery \u2014 a row is written before the send response returns, so\n-- nothing is lost to a Tower crash/restart/shutdown (the retired in-memory\n-- SendBuffer lost held messages on both). Rows address AGENTS (to_agent within\n-- workspace_path), not PTYs, so a respawned terminal drains its predecessor's\n-- mail. Delivery is authorized elsewhere by the render-gate (Phases 2/4); this\n-- table is pure durable state. Timestamps are epoch-ms integers (not SQLite\n-- datetime) so ordering and age math are trivial. Additive new table \u2014 fresh\n-- installs get it here; existing installs get it from migration v15.\nCREATE TABLE IF NOT EXISTS mailbox (\n id TEXT PRIMARY KEY, -- uuid\n workspace_path TEXT NOT NULL, -- addressing scope\n to_agent TEXT NOT NULL, -- recipient agent identity (drains across respawn)\n terminal_id TEXT, -- last-known PTY hint (nullable; not the identity)\n from_agent TEXT,\n from_workspace TEXT,\n body TEXT NOT NULL, -- raw message (never logged)\n formatted_message TEXT NOT NULL, -- what gets written to the PTY\n no_enter INTEGER NOT NULL DEFAULT 0,\n status TEXT NOT NULL DEFAULT 'held'\n CHECK(status IN ('held', 'delivered', 'superseded', 'dismissed')),\n reason TEXT CHECK(reason IN ('busy', 'no-profile', 'no-live-pty')), -- why-held; null once delivered\n supersede_key TEXT, -- cron-only; null for direct sends\n escalated INTEGER NOT NULL DEFAULT 0, -- set once escalation age crossed (visibility only)\n not_before INTEGER, -- epoch ms; delayed-send due time (Spec 1313 round 3, --delay). null = deliver ASAP; a row is deliverable only when not_before IS NULL OR not_before <= now\n created_at INTEGER NOT NULL, -- epoch ms (enqueue order per agent)\n updated_at INTEGER NOT NULL,\n resolved_at INTEGER -- delivered/superseded/dismissed timestamp\n);\n\nCREATE INDEX IF NOT EXISTS idx_mailbox_workspace_status ON mailbox(workspace_path, status);\nCREATE INDEX IF NOT EXISTS idx_mailbox_agent_drain ON mailbox(workspace_path, to_agent, status);\nCREATE INDEX IF NOT EXISTS idx_mailbox_supersede ON mailbox(supersede_key);\n";
|
|
23
23
|
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/db/schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,0gGAqFxB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/db/schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,0gGAqFxB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,4nPA4KzB,CAAC"}
|
|
@@ -125,6 +125,7 @@ CREATE TABLE IF NOT EXISTS terminal_sessions (
|
|
|
125
125
|
shellper_start_time INTEGER, -- shellper process start time (epoch ms)
|
|
126
126
|
label TEXT, -- custom display label (Spec 468)
|
|
127
127
|
cwd TEXT, -- working directory of the terminal (Bugfix #506)
|
|
128
|
+
command TEXT, -- launch command; render-gate identity seam (Spec 1313)
|
|
128
129
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
129
130
|
);
|
|
130
131
|
|
|
@@ -241,5 +242,39 @@ CREATE TABLE IF NOT EXISTS annotations (
|
|
|
241
242
|
parent_id TEXT,
|
|
242
243
|
started_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
243
244
|
);
|
|
245
|
+
|
|
246
|
+
-- Mailbox (Spec 1313): durable home for every 'afx send'.
|
|
247
|
+
-- Persist-first delivery — a row is written before the send response returns, so
|
|
248
|
+
-- nothing is lost to a Tower crash/restart/shutdown (the retired in-memory
|
|
249
|
+
-- SendBuffer lost held messages on both). Rows address AGENTS (to_agent within
|
|
250
|
+
-- workspace_path), not PTYs, so a respawned terminal drains its predecessor's
|
|
251
|
+
-- mail. Delivery is authorized elsewhere by the render-gate (Phases 2/4); this
|
|
252
|
+
-- table is pure durable state. Timestamps are epoch-ms integers (not SQLite
|
|
253
|
+
-- datetime) so ordering and age math are trivial. Additive new table — fresh
|
|
254
|
+
-- installs get it here; existing installs get it from migration v15.
|
|
255
|
+
CREATE TABLE IF NOT EXISTS mailbox (
|
|
256
|
+
id TEXT PRIMARY KEY, -- uuid
|
|
257
|
+
workspace_path TEXT NOT NULL, -- addressing scope
|
|
258
|
+
to_agent TEXT NOT NULL, -- recipient agent identity (drains across respawn)
|
|
259
|
+
terminal_id TEXT, -- last-known PTY hint (nullable; not the identity)
|
|
260
|
+
from_agent TEXT,
|
|
261
|
+
from_workspace TEXT,
|
|
262
|
+
body TEXT NOT NULL, -- raw message (never logged)
|
|
263
|
+
formatted_message TEXT NOT NULL, -- what gets written to the PTY
|
|
264
|
+
no_enter INTEGER NOT NULL DEFAULT 0,
|
|
265
|
+
status TEXT NOT NULL DEFAULT 'held'
|
|
266
|
+
CHECK(status IN ('held', 'delivered', 'superseded', 'dismissed')),
|
|
267
|
+
reason TEXT CHECK(reason IN ('busy', 'no-profile', 'no-live-pty')), -- why-held; null once delivered
|
|
268
|
+
supersede_key TEXT, -- cron-only; null for direct sends
|
|
269
|
+
escalated INTEGER NOT NULL DEFAULT 0, -- set once escalation age crossed (visibility only)
|
|
270
|
+
not_before INTEGER, -- epoch ms; delayed-send due time (Spec 1313 round 3, --delay). null = deliver ASAP; a row is deliverable only when not_before IS NULL OR not_before <= now
|
|
271
|
+
created_at INTEGER NOT NULL, -- epoch ms (enqueue order per agent)
|
|
272
|
+
updated_at INTEGER NOT NULL,
|
|
273
|
+
resolved_at INTEGER -- delivered/superseded/dismissed timestamp
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
CREATE INDEX IF NOT EXISTS idx_mailbox_workspace_status ON mailbox(workspace_path, status);
|
|
277
|
+
CREATE INDEX IF NOT EXISTS idx_mailbox_agent_drain ON mailbox(workspace_path, to_agent, status);
|
|
278
|
+
CREATE INDEX IF NOT EXISTS idx_mailbox_supersede ON mailbox(supersede_key);
|
|
244
279
|
`;
|
|
245
280
|
//# sourceMappingURL=schema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/agent-farm/db/schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqF3B,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/agent-farm/db/schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqF3B,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4K5B,CAAC"}
|