@ag-eco/agentplate-cli 0.13.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/LICENSE +21 -0
- package/README.md +462 -0
- package/agents/ap-co-creation.md +90 -0
- package/agents/builder.md +144 -0
- package/agents/coordinator.md +377 -0
- package/agents/lead.md +435 -0
- package/agents/merger.md +164 -0
- package/agents/monitor.md +214 -0
- package/agents/orchestrator.md +239 -0
- package/agents/reviewer.md +140 -0
- package/agents/scout.md +125 -0
- package/agents/supervisor.md +427 -0
- package/package.json +66 -0
- package/src/agents/capabilities.test.ts +85 -0
- package/src/agents/capabilities.ts +125 -0
- package/src/agents/checkpoint.test.ts +88 -0
- package/src/agents/checkpoint.ts +101 -0
- package/src/agents/copilot-hooks-deployer.test.ts +162 -0
- package/src/agents/copilot-hooks-deployer.ts +93 -0
- package/src/agents/guard-rules.test.ts +372 -0
- package/src/agents/guard-rules.ts +97 -0
- package/src/agents/headless-mail-injector.test.ts +709 -0
- package/src/agents/headless-mail-injector.ts +377 -0
- package/src/agents/headless-prompt.test.ts +102 -0
- package/src/agents/headless-prompt.ts +68 -0
- package/src/agents/hooks-deployer.test.ts +3119 -0
- package/src/agents/hooks-deployer.ts +804 -0
- package/src/agents/identity.test.ts +604 -0
- package/src/agents/identity.ts +384 -0
- package/src/agents/lifecycle.test.ts +196 -0
- package/src/agents/lifecycle.ts +183 -0
- package/src/agents/mail-poll-detect.test.ts +153 -0
- package/src/agents/mail-poll-detect.ts +73 -0
- package/src/agents/manifest.test.ts +1026 -0
- package/src/agents/manifest.ts +376 -0
- package/src/agents/overlay.test.ts +1058 -0
- package/src/agents/overlay.ts +490 -0
- package/src/agents/scope-detect.test.ts +190 -0
- package/src/agents/scope-detect.ts +146 -0
- package/src/agents/turn-lock.test.ts +181 -0
- package/src/agents/turn-lock.ts +235 -0
- package/src/agents/turn-runner-dispatch.test.ts +182 -0
- package/src/agents/turn-runner-dispatch.ts +105 -0
- package/src/agents/turn-runner.test.ts +2312 -0
- package/src/agents/turn-runner.ts +1383 -0
- package/src/beads/client.test.ts +217 -0
- package/src/beads/client.ts +230 -0
- package/src/beads/molecules.test.ts +338 -0
- package/src/beads/molecules.ts +198 -0
- package/src/commands/agents.test.ts +328 -0
- package/src/commands/agents.ts +299 -0
- package/src/commands/clean.test.ts +797 -0
- package/src/commands/clean.ts +791 -0
- package/src/commands/completions.test.ts +348 -0
- package/src/commands/completions.ts +981 -0
- package/src/commands/coordinator.test.ts +2975 -0
- package/src/commands/coordinator.ts +1841 -0
- package/src/commands/costs.test.ts +1183 -0
- package/src/commands/costs.ts +599 -0
- package/src/commands/dashboard.test.ts +954 -0
- package/src/commands/dashboard.ts +1212 -0
- package/src/commands/discover.test.ts +288 -0
- package/src/commands/discover.ts +202 -0
- package/src/commands/doctor.test.ts +303 -0
- package/src/commands/doctor.ts +311 -0
- package/src/commands/ecosystem.test.ts +226 -0
- package/src/commands/ecosystem.ts +248 -0
- package/src/commands/errors.test.ts +654 -0
- package/src/commands/errors.ts +197 -0
- package/src/commands/feed.test.ts +709 -0
- package/src/commands/feed.ts +260 -0
- package/src/commands/group.test.ts +475 -0
- package/src/commands/group.ts +546 -0
- package/src/commands/hooks.test.ts +458 -0
- package/src/commands/hooks.ts +263 -0
- package/src/commands/init.test.ts +1011 -0
- package/src/commands/init.ts +967 -0
- package/src/commands/inspect.test.ts +1239 -0
- package/src/commands/inspect.ts +648 -0
- package/src/commands/log.test.ts +1913 -0
- package/src/commands/log.ts +958 -0
- package/src/commands/logs.test.ts +801 -0
- package/src/commands/logs.ts +483 -0
- package/src/commands/mail.test.ts +1501 -0
- package/src/commands/mail.ts +848 -0
- package/src/commands/merge.test.ts +864 -0
- package/src/commands/merge.ts +381 -0
- package/src/commands/metrics.test.ts +458 -0
- package/src/commands/metrics.ts +129 -0
- package/src/commands/monitor.test.ts +191 -0
- package/src/commands/monitor.ts +409 -0
- package/src/commands/nudge.test.ts +579 -0
- package/src/commands/nudge.ts +646 -0
- package/src/commands/orchestrator.ts +42 -0
- package/src/commands/prime.test.ts +612 -0
- package/src/commands/prime.ts +359 -0
- package/src/commands/replay.test.ts +757 -0
- package/src/commands/replay.ts +231 -0
- package/src/commands/run.test.ts +469 -0
- package/src/commands/run.ts +353 -0
- package/src/commands/serve/agent-actions.test.ts +210 -0
- package/src/commands/serve/agent-actions.ts +192 -0
- package/src/commands/serve/build.test.ts +202 -0
- package/src/commands/serve/build.ts +206 -0
- package/src/commands/serve/coordinator-actions.test.ts +339 -0
- package/src/commands/serve/coordinator-actions.ts +410 -0
- package/src/commands/serve/dev.test.ts +168 -0
- package/src/commands/serve/dev.ts +117 -0
- package/src/commands/serve/mail-actions.test.ts +312 -0
- package/src/commands/serve/mail-actions.ts +167 -0
- package/src/commands/serve/rest.test.ts +1680 -0
- package/src/commands/serve/rest.ts +1130 -0
- package/src/commands/serve/static.ts +51 -0
- package/src/commands/serve/ws.test.ts +361 -0
- package/src/commands/serve/ws.ts +332 -0
- package/src/commands/serve.test.ts +459 -0
- package/src/commands/serve.ts +654 -0
- package/src/commands/sling.test.ts +1583 -0
- package/src/commands/sling.ts +1351 -0
- package/src/commands/spec.test.ts +179 -0
- package/src/commands/spec.ts +105 -0
- package/src/commands/status.test.ts +614 -0
- package/src/commands/status.ts +403 -0
- package/src/commands/stop.test.ts +964 -0
- package/src/commands/stop.ts +319 -0
- package/src/commands/supervisor.test.ts +185 -0
- package/src/commands/supervisor.ts +537 -0
- package/src/commands/trace.test.ts +762 -0
- package/src/commands/trace.ts +205 -0
- package/src/commands/update.test.ts +466 -0
- package/src/commands/update.ts +263 -0
- package/src/commands/upgrade.test.ts +48 -0
- package/src/commands/upgrade.ts +240 -0
- package/src/commands/watch.test.ts +257 -0
- package/src/commands/watch.ts +308 -0
- package/src/commands/worktree.test.ts +1297 -0
- package/src/commands/worktree.ts +451 -0
- package/src/config.test.ts +1535 -0
- package/src/config.ts +1064 -0
- package/src/doctor/agents.test.ts +523 -0
- package/src/doctor/agents.ts +399 -0
- package/src/doctor/config-check.test.ts +191 -0
- package/src/doctor/config-check.ts +183 -0
- package/src/doctor/consistency.test.ts +807 -0
- package/src/doctor/consistency.ts +347 -0
- package/src/doctor/databases.test.ts +350 -0
- package/src/doctor/databases.ts +243 -0
- package/src/doctor/dependencies.test.ts +296 -0
- package/src/doctor/dependencies.ts +272 -0
- package/src/doctor/ecosystem.test.ts +308 -0
- package/src/doctor/ecosystem.ts +156 -0
- package/src/doctor/logs.test.ts +253 -0
- package/src/doctor/logs.ts +295 -0
- package/src/doctor/merge-queue.test.ts +315 -0
- package/src/doctor/merge-queue.ts +167 -0
- package/src/doctor/providers.test.ts +409 -0
- package/src/doctor/providers.ts +250 -0
- package/src/doctor/serve.test.ts +95 -0
- package/src/doctor/serve.ts +86 -0
- package/src/doctor/structure.test.ts +423 -0
- package/src/doctor/structure.ts +285 -0
- package/src/doctor/types.ts +43 -0
- package/src/doctor/version.test.ts +241 -0
- package/src/doctor/version.ts +132 -0
- package/src/doctor/watchdog.test.ts +167 -0
- package/src/doctor/watchdog.ts +214 -0
- package/src/e2e/init-sling-lifecycle.test.ts +283 -0
- package/src/errors.test.ts +350 -0
- package/src/errors.ts +217 -0
- package/src/events/store.test.ts +660 -0
- package/src/events/store.ts +369 -0
- package/src/events/tailer.test.ts +719 -0
- package/src/events/tailer.ts +332 -0
- package/src/events/tool-filter.test.ts +330 -0
- package/src/events/tool-filter.ts +126 -0
- package/src/index.ts +533 -0
- package/src/insights/analyzer.test.ts +466 -0
- package/src/insights/analyzer.ts +203 -0
- package/src/insights/quality-gates.test.ts +141 -0
- package/src/insights/quality-gates.ts +156 -0
- package/src/json.test.ts +72 -0
- package/src/json.ts +53 -0
- package/src/loam/client.test.ts +752 -0
- package/src/loam/client.ts +664 -0
- package/src/logging/color.test.ts +252 -0
- package/src/logging/color.ts +105 -0
- package/src/logging/format.test.ts +110 -0
- package/src/logging/format.ts +255 -0
- package/src/logging/logger.test.ts +814 -0
- package/src/logging/logger.ts +266 -0
- package/src/logging/reporter.test.ts +259 -0
- package/src/logging/reporter.ts +110 -0
- package/src/logging/sanitizer.test.ts +190 -0
- package/src/logging/sanitizer.ts +57 -0
- package/src/logging/theme.ts +140 -0
- package/src/mail/broadcast.test.ts +204 -0
- package/src/mail/broadcast.ts +92 -0
- package/src/mail/client.test.ts +774 -0
- package/src/mail/client.ts +236 -0
- package/src/mail/store.test.ts +898 -0
- package/src/mail/store.ts +425 -0
- package/src/merge/lock.test.ts +149 -0
- package/src/merge/lock.ts +140 -0
- package/src/merge/predict.test.ts +387 -0
- package/src/merge/predict.ts +249 -0
- package/src/merge/queue.test.ts +426 -0
- package/src/merge/queue.ts +246 -0
- package/src/merge/resolver.test.ts +1993 -0
- package/src/merge/resolver.ts +926 -0
- package/src/metrics/pricing.test.ts +258 -0
- package/src/metrics/pricing.ts +135 -0
- package/src/metrics/store.test.ts +978 -0
- package/src/metrics/store.ts +501 -0
- package/src/metrics/summary.test.ts +398 -0
- package/src/metrics/summary.ts +178 -0
- package/src/metrics/transcript.test.ts +483 -0
- package/src/metrics/transcript.ts +114 -0
- package/src/runtimes/__fixtures__/claude-stream-fixture.ts +22 -0
- package/src/runtimes/aider.test.ts +124 -0
- package/src/runtimes/aider.ts +147 -0
- package/src/runtimes/amp.test.ts +164 -0
- package/src/runtimes/amp.ts +154 -0
- package/src/runtimes/claude.test.ts +1474 -0
- package/src/runtimes/claude.ts +579 -0
- package/src/runtimes/codex.test.ts +805 -0
- package/src/runtimes/codex.ts +273 -0
- package/src/runtimes/connections.test.ts +214 -0
- package/src/runtimes/connections.ts +103 -0
- package/src/runtimes/copilot.test.ts +707 -0
- package/src/runtimes/copilot.ts +316 -0
- package/src/runtimes/cursor.test.ts +497 -0
- package/src/runtimes/cursor.ts +205 -0
- package/src/runtimes/gemini.test.ts +537 -0
- package/src/runtimes/gemini.ts +243 -0
- package/src/runtimes/goose.test.ts +133 -0
- package/src/runtimes/goose.ts +157 -0
- package/src/runtimes/headless-connection.test.ts +264 -0
- package/src/runtimes/headless-connection.ts +158 -0
- package/src/runtimes/opencode.test.ts +325 -0
- package/src/runtimes/opencode.ts +188 -0
- package/src/runtimes/pi-guards.test.ts +486 -0
- package/src/runtimes/pi-guards.ts +367 -0
- package/src/runtimes/pi.test.ts +789 -0
- package/src/runtimes/pi.ts +305 -0
- package/src/runtimes/registry.test.ts +196 -0
- package/src/runtimes/registry.ts +99 -0
- package/src/runtimes/sapling.test.ts +1267 -0
- package/src/runtimes/sapling.ts +710 -0
- package/src/runtimes/types.ts +266 -0
- package/src/schema-consistency.test.ts +246 -0
- package/src/sessions/compat.test.ts +281 -0
- package/src/sessions/compat.ts +105 -0
- package/src/sessions/store.test.ts +1748 -0
- package/src/sessions/store.ts +858 -0
- package/src/test-helpers.test.ts +124 -0
- package/src/test-helpers.ts +145 -0
- package/src/test-setup.test.ts +31 -0
- package/src/test-setup.ts +28 -0
- package/src/tools/loam/api.ts +368 -0
- package/src/tools/loam/cli.ts +278 -0
- package/src/tools/loam/commands/add.ts +52 -0
- package/src/tools/loam/commands/archive.ts +214 -0
- package/src/tools/loam/commands/audit.ts +276 -0
- package/src/tools/loam/commands/compact.ts +1062 -0
- package/src/tools/loam/commands/completions.ts +79 -0
- package/src/tools/loam/commands/config.ts +381 -0
- package/src/tools/loam/commands/delete-domain.ts +121 -0
- package/src/tools/loam/commands/delete.ts +316 -0
- package/src/tools/loam/commands/diff.ts +200 -0
- package/src/tools/loam/commands/doctor.ts +1113 -0
- package/src/tools/loam/commands/edit.ts +226 -0
- package/src/tools/loam/commands/init.ts +31 -0
- package/src/tools/loam/commands/learn.ts +179 -0
- package/src/tools/loam/commands/move.ts +323 -0
- package/src/tools/loam/commands/onboard.ts +374 -0
- package/src/tools/loam/commands/outcome.ts +185 -0
- package/src/tools/loam/commands/prime.ts +688 -0
- package/src/tools/loam/commands/prune.ts +614 -0
- package/src/tools/loam/commands/query.ts +218 -0
- package/src/tools/loam/commands/rank.ts +180 -0
- package/src/tools/loam/commands/ready.ts +189 -0
- package/src/tools/loam/commands/record.ts +1210 -0
- package/src/tools/loam/commands/restore.ts +166 -0
- package/src/tools/loam/commands/search.ts +327 -0
- package/src/tools/loam/commands/setup.ts +887 -0
- package/src/tools/loam/commands/status.ts +103 -0
- package/src/tools/loam/commands/sync.ts +298 -0
- package/src/tools/loam/commands/update.ts +19 -0
- package/src/tools/loam/commands/upgrade.ts +93 -0
- package/src/tools/loam/commands/validate.ts +190 -0
- package/src/tools/loam/index.ts +62 -0
- package/src/tools/loam/log.ts +127 -0
- package/src/tools/loam/registry/builtins.ts +409 -0
- package/src/tools/loam/registry/custom.ts +431 -0
- package/src/tools/loam/registry/init.ts +55 -0
- package/src/tools/loam/registry/template.ts +40 -0
- package/src/tools/loam/registry/type-registry.ts +113 -0
- package/src/tools/loam/schemas/config-schema.ts +489 -0
- package/src/tools/loam/schemas/config.ts +245 -0
- package/src/tools/loam/schemas/index.ts +18 -0
- package/src/tools/loam/schemas/record-schema.ts +191 -0
- package/src/tools/loam/schemas/record.ts +115 -0
- package/src/tools/loam/utils/active-work.ts +205 -0
- package/src/tools/loam/utils/anchor-validity.ts +80 -0
- package/src/tools/loam/utils/archive.ts +146 -0
- package/src/tools/loam/utils/audit.ts +667 -0
- package/src/tools/loam/utils/bm25.ts +238 -0
- package/src/tools/loam/utils/budget.ts +142 -0
- package/src/tools/loam/utils/config.ts +344 -0
- package/src/tools/loam/utils/dir-anchors.ts +62 -0
- package/src/tools/loam/utils/domain-rules.ts +114 -0
- package/src/tools/loam/utils/expertise.ts +393 -0
- package/src/tools/loam/utils/format-helpers.ts +96 -0
- package/src/tools/loam/utils/format.ts +1234 -0
- package/src/tools/loam/utils/git-context.ts +50 -0
- package/src/tools/loam/utils/git.ts +183 -0
- package/src/tools/loam/utils/hooks.ts +299 -0
- package/src/tools/loam/utils/index.ts +52 -0
- package/src/tools/loam/utils/json-output.ts +13 -0
- package/src/tools/loam/utils/lock.ts +76 -0
- package/src/tools/loam/utils/markers.ts +48 -0
- package/src/tools/loam/utils/numeric-flags.ts +20 -0
- package/src/tools/loam/utils/palette.ts +44 -0
- package/src/tools/loam/utils/prime-ranking.ts +135 -0
- package/src/tools/loam/utils/recipe-discovery.ts +195 -0
- package/src/tools/loam/utils/runtime-flags.ts +28 -0
- package/src/tools/loam/utils/scoring.ts +94 -0
- package/src/tools/loam/utils/version.ts +116 -0
- package/src/tools/sprout/commands/block.ts +64 -0
- package/src/tools/sprout/commands/blocked.ts +86 -0
- package/src/tools/sprout/commands/close.ts +129 -0
- package/src/tools/sprout/commands/completions.ts +198 -0
- package/src/tools/sprout/commands/config.ts +238 -0
- package/src/tools/sprout/commands/create.ts +164 -0
- package/src/tools/sprout/commands/dep.ts +148 -0
- package/src/tools/sprout/commands/doctor.ts +979 -0
- package/src/tools/sprout/commands/init.ts +83 -0
- package/src/tools/sprout/commands/label.ts +178 -0
- package/src/tools/sprout/commands/list.ts +210 -0
- package/src/tools/sprout/commands/migrate.ts +133 -0
- package/src/tools/sprout/commands/onboard.ts +207 -0
- package/src/tools/sprout/commands/plan-show.ts +278 -0
- package/src/tools/sprout/commands/plan.ts +2526 -0
- package/src/tools/sprout/commands/prime.ts +399 -0
- package/src/tools/sprout/commands/ready.ts +245 -0
- package/src/tools/sprout/commands/search.ts +221 -0
- package/src/tools/sprout/commands/show.ts +277 -0
- package/src/tools/sprout/commands/stats.ts +146 -0
- package/src/tools/sprout/commands/sync.ts +134 -0
- package/src/tools/sprout/commands/tpl.ts +364 -0
- package/src/tools/sprout/commands/unblock.ts +115 -0
- package/src/tools/sprout/commands/update.ts +257 -0
- package/src/tools/sprout/commands/upgrade.ts +91 -0
- package/src/tools/sprout/config-schema.ts +152 -0
- package/src/tools/sprout/config.ts +355 -0
- package/src/tools/sprout/filter.ts +107 -0
- package/src/tools/sprout/format.ts +43 -0
- package/src/tools/sprout/id.ts +22 -0
- package/src/tools/sprout/index.ts +204 -0
- package/src/tools/sprout/log.ts +76 -0
- package/src/tools/sprout/markers.ts +22 -0
- package/src/tools/sprout/output.ts +121 -0
- package/src/tools/sprout/plan-backref.ts +93 -0
- package/src/tools/sprout/plan-context.ts +81 -0
- package/src/tools/sprout/plan-domain.ts +139 -0
- package/src/tools/sprout/plan-lifecycle.ts +65 -0
- package/src/tools/sprout/plan-loam.ts +207 -0
- package/src/tools/sprout/plan-schema.ts +209 -0
- package/src/tools/sprout/sort.ts +31 -0
- package/src/tools/sprout/store.ts +172 -0
- package/src/tools/sprout/types.ts +118 -0
- package/src/tools/sprout/validation.ts +119 -0
- package/src/tools/sprout/version.ts +1 -0
- package/src/tools/sprout/yaml.ts +387 -0
- package/src/tools/trellis/commands/archive.ts +87 -0
- package/src/tools/trellis/commands/completions.ts +610 -0
- package/src/tools/trellis/commands/config.ts +382 -0
- package/src/tools/trellis/commands/create.ts +252 -0
- package/src/tools/trellis/commands/diff.ts +150 -0
- package/src/tools/trellis/commands/doctor.ts +771 -0
- package/src/tools/trellis/commands/emit.ts +365 -0
- package/src/tools/trellis/commands/history.ts +83 -0
- package/src/tools/trellis/commands/import.ts +198 -0
- package/src/tools/trellis/commands/init.ts +81 -0
- package/src/tools/trellis/commands/list.ts +103 -0
- package/src/tools/trellis/commands/onboard.ts +156 -0
- package/src/tools/trellis/commands/pin.ts +172 -0
- package/src/tools/trellis/commands/prime.ts +193 -0
- package/src/tools/trellis/commands/render.ts +122 -0
- package/src/tools/trellis/commands/schema.ts +353 -0
- package/src/tools/trellis/commands/show.ts +115 -0
- package/src/tools/trellis/commands/stats.ts +65 -0
- package/src/tools/trellis/commands/sync.ts +112 -0
- package/src/tools/trellis/commands/tree.ts +123 -0
- package/src/tools/trellis/commands/update.ts +330 -0
- package/src/tools/trellis/commands/upgrade.ts +95 -0
- package/src/tools/trellis/commands/validate.ts +166 -0
- package/src/tools/trellis/config-schema.ts +81 -0
- package/src/tools/trellis/config.ts +108 -0
- package/src/tools/trellis/frontmatter.ts +348 -0
- package/src/tools/trellis/id.ts +24 -0
- package/src/tools/trellis/index.ts +209 -0
- package/src/tools/trellis/markers.ts +28 -0
- package/src/tools/trellis/output.ts +84 -0
- package/src/tools/trellis/render.ts +212 -0
- package/src/tools/trellis/store.ts +144 -0
- package/src/tools/trellis/types.ts +82 -0
- package/src/tools/trellis/validate.ts +199 -0
- package/src/tools/trellis/yaml.ts +309 -0
- package/src/tracker/beads.test.ts +454 -0
- package/src/tracker/beads.ts +56 -0
- package/src/tracker/factory.test.ts +90 -0
- package/src/tracker/factory.ts +65 -0
- package/src/tracker/sprout.test.ts +461 -0
- package/src/tracker/sprout.ts +182 -0
- package/src/tracker/types.ts +52 -0
- package/src/trellis/client.test.ts +107 -0
- package/src/trellis/client.ts +179 -0
- package/src/types.ts +970 -0
- package/src/utils/bin.test.ts +10 -0
- package/src/utils/bin.ts +37 -0
- package/src/utils/browser.test.ts +49 -0
- package/src/utils/browser.ts +48 -0
- package/src/utils/fs.test.ts +119 -0
- package/src/utils/fs.ts +62 -0
- package/src/utils/pid.test.ts +152 -0
- package/src/utils/pid.ts +130 -0
- package/src/utils/process-scan.test.ts +53 -0
- package/src/utils/process-scan.ts +76 -0
- package/src/utils/time.test.ts +43 -0
- package/src/utils/time.ts +37 -0
- package/src/utils/version.test.ts +33 -0
- package/src/utils/version.ts +70 -0
- package/src/version.ts +5 -0
- package/src/watchdog/daemon.test.ts +3721 -0
- package/src/watchdog/daemon.ts +1257 -0
- package/src/watchdog/health.test.ts +830 -0
- package/src/watchdog/health.ts +434 -0
- package/src/watchdog/triage.test.ts +205 -0
- package/src/watchdog/triage.ts +205 -0
- package/src/worktree/manager.test.ts +720 -0
- package/src/worktree/manager.ts +405 -0
- package/src/worktree/process.test.ts +172 -0
- package/src/worktree/process.ts +131 -0
- package/src/worktree/tmux.test.ts +1616 -0
- package/src/worktree/tmux.ts +721 -0
- package/templates/CLAUDE.md.tmpl +100 -0
- package/templates/copilot-hooks.json.tmpl +13 -0
- package/templates/hooks.json.tmpl +109 -0
- package/templates/overlay.md.tmpl +88 -0
- package/ui/dist/apple-touch-icon-bdy6teep.png +0 -0
- package/ui/dist/chunk-8s31f05k.css +1 -0
- package/ui/dist/chunk-vm5rz679.js +300 -0
- package/ui/dist/favicon-nzb39vza.svg +4 -0
- package/ui/dist/index.html +17 -0
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdir, mkdtemp } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { stripAnsi } from "../logging/color.ts";
|
|
6
|
+
import { createSessionStore } from "../sessions/store.ts";
|
|
7
|
+
import { cleanupTempDir, createTempGitRepo } from "../test-helpers.ts";
|
|
8
|
+
import type { AgentSession } from "../types.ts";
|
|
9
|
+
import {
|
|
10
|
+
gatherStatus,
|
|
11
|
+
invalidateStatusCache,
|
|
12
|
+
printStatus,
|
|
13
|
+
type StatusData,
|
|
14
|
+
statusCommand,
|
|
15
|
+
type VerboseAgentDetail,
|
|
16
|
+
} from "./status.ts";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Tests for the --verbose flag in agentplate status.
|
|
20
|
+
*
|
|
21
|
+
* printStatus is tested by capturing process.stdout.write output.
|
|
22
|
+
* We spy on stdout.write because printStatus uses it directly.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
function makeAgent(overrides: Partial<AgentSession> = {}): AgentSession {
|
|
26
|
+
return {
|
|
27
|
+
id: "sess-001",
|
|
28
|
+
agentName: "test-builder",
|
|
29
|
+
capability: "builder",
|
|
30
|
+
worktreePath: "/tmp/worktrees/test-builder",
|
|
31
|
+
branchName: "agentplate/test-builder/task-1",
|
|
32
|
+
taskId: "task-1",
|
|
33
|
+
tmuxSession: "agentplate-test-builder",
|
|
34
|
+
state: "working",
|
|
35
|
+
pid: 12345,
|
|
36
|
+
parentAgent: null,
|
|
37
|
+
depth: 0,
|
|
38
|
+
runId: null,
|
|
39
|
+
startedAt: new Date(Date.now() - 60_000).toISOString(),
|
|
40
|
+
lastActivity: new Date().toISOString(),
|
|
41
|
+
escalationLevel: 0,
|
|
42
|
+
stalledSince: null,
|
|
43
|
+
transcriptPath: null,
|
|
44
|
+
...overrides,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function makeStatusData(overrides: Partial<StatusData> = {}): StatusData {
|
|
49
|
+
return {
|
|
50
|
+
agents: [makeAgent()],
|
|
51
|
+
worktrees: [],
|
|
52
|
+
tmuxSessions: [{ name: "agentplate-test-builder", pid: 12345 }],
|
|
53
|
+
unreadMailCount: 0,
|
|
54
|
+
unreadMailScope: "orchestrator",
|
|
55
|
+
mergeQueueCount: 0,
|
|
56
|
+
recentMetricsCount: 0,
|
|
57
|
+
...overrides,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
describe("printStatus", () => {
|
|
62
|
+
let chunks: string[];
|
|
63
|
+
let originalWrite: typeof process.stdout.write;
|
|
64
|
+
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
chunks = [];
|
|
67
|
+
originalWrite = process.stdout.write;
|
|
68
|
+
process.stdout.write = ((chunk: string) => {
|
|
69
|
+
chunks.push(chunk);
|
|
70
|
+
return true;
|
|
71
|
+
}) as typeof process.stdout.write;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
afterEach(() => {
|
|
75
|
+
process.stdout.write = originalWrite;
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
function output(): string {
|
|
79
|
+
return chunks.join("");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
test("non-verbose: does not show worktree path or logs dir", () => {
|
|
83
|
+
const data = makeStatusData();
|
|
84
|
+
printStatus(data);
|
|
85
|
+
const out = output();
|
|
86
|
+
|
|
87
|
+
expect(out).toContain("test-builder");
|
|
88
|
+
expect(out).toContain("[builder]");
|
|
89
|
+
expect(out).not.toContain("Worktree:");
|
|
90
|
+
expect(out).not.toContain("Logs:");
|
|
91
|
+
expect(out).not.toContain("Mail sent:");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("Mail line names the scope agent so per-agent scope is unambiguous", () => {
|
|
95
|
+
const data = makeStatusData({ unreadMailCount: 3, unreadMailScope: "lead-1" });
|
|
96
|
+
printStatus(data);
|
|
97
|
+
expect(stripAnsi(output())).toContain("Mail: 3 unread (to lead-1)");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("verbose: shows worktree path, logs dir, and mail timestamps", () => {
|
|
101
|
+
const detail: VerboseAgentDetail = {
|
|
102
|
+
worktreePath: "/tmp/worktrees/test-builder",
|
|
103
|
+
logsDir: "/tmp/.agentplate/logs/test-builder",
|
|
104
|
+
lastMailSent: "2025-01-15T10:00:00.000Z",
|
|
105
|
+
lastMailReceived: "2025-01-15T10:05:00.000Z",
|
|
106
|
+
capability: "builder",
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const data = makeStatusData({
|
|
110
|
+
verboseDetails: { "test-builder": detail },
|
|
111
|
+
});
|
|
112
|
+
printStatus(data);
|
|
113
|
+
const out = output();
|
|
114
|
+
|
|
115
|
+
expect(out).toContain("Worktree: /tmp/worktrees/test-builder");
|
|
116
|
+
expect(out).toContain("Logs: /tmp/.agentplate/logs/test-builder");
|
|
117
|
+
expect(out).toContain("Mail sent: 2025-01-15T10:00:00.000Z");
|
|
118
|
+
expect(out).toContain("received: 2025-01-15T10:05:00.000Z");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("verbose: shows 'none' for null mail timestamps", () => {
|
|
122
|
+
const detail: VerboseAgentDetail = {
|
|
123
|
+
worktreePath: "/tmp/worktrees/test-builder",
|
|
124
|
+
logsDir: "/tmp/.agentplate/logs/test-builder",
|
|
125
|
+
lastMailSent: null,
|
|
126
|
+
lastMailReceived: null,
|
|
127
|
+
capability: "builder",
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const data = makeStatusData({
|
|
131
|
+
verboseDetails: { "test-builder": detail },
|
|
132
|
+
});
|
|
133
|
+
printStatus(data);
|
|
134
|
+
const out = output();
|
|
135
|
+
|
|
136
|
+
expect(out).toContain("Mail sent: none");
|
|
137
|
+
expect(out).toContain("received: none");
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("verbose: zombie agents do not get verbose detail", () => {
|
|
141
|
+
const agent = makeAgent({ state: "zombie", agentName: "zombie-agent" });
|
|
142
|
+
const detail: VerboseAgentDetail = {
|
|
143
|
+
worktreePath: "/tmp/worktrees/zombie-agent",
|
|
144
|
+
logsDir: "/tmp/.agentplate/logs/zombie-agent",
|
|
145
|
+
lastMailSent: null,
|
|
146
|
+
lastMailReceived: null,
|
|
147
|
+
capability: "builder",
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const data = makeStatusData({
|
|
151
|
+
agents: [agent],
|
|
152
|
+
verboseDetails: { "zombie-agent": detail },
|
|
153
|
+
});
|
|
154
|
+
printStatus(data);
|
|
155
|
+
const out = output();
|
|
156
|
+
|
|
157
|
+
// Zombie agents are filtered from the active list
|
|
158
|
+
expect(out).toContain("0 active");
|
|
159
|
+
expect(out).not.toContain("Worktree:");
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("verbose with multiple agents: each gets its own detail", () => {
|
|
163
|
+
const agent1 = makeAgent({ agentName: "builder-1", tmuxSession: "agentplate-builder-1" });
|
|
164
|
+
const agent2 = makeAgent({
|
|
165
|
+
agentName: "scout-1",
|
|
166
|
+
capability: "scout",
|
|
167
|
+
tmuxSession: "agentplate-scout-1",
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const data = makeStatusData({
|
|
171
|
+
agents: [agent1, agent2],
|
|
172
|
+
tmuxSessions: [
|
|
173
|
+
{ name: "agentplate-builder-1", pid: 100 },
|
|
174
|
+
{ name: "agentplate-scout-1", pid: 200 },
|
|
175
|
+
],
|
|
176
|
+
verboseDetails: {
|
|
177
|
+
"builder-1": {
|
|
178
|
+
worktreePath: "/tmp/wt/builder-1",
|
|
179
|
+
logsDir: "/tmp/logs/builder-1",
|
|
180
|
+
lastMailSent: "2025-01-15T10:00:00.000Z",
|
|
181
|
+
lastMailReceived: null,
|
|
182
|
+
capability: "builder",
|
|
183
|
+
},
|
|
184
|
+
"scout-1": {
|
|
185
|
+
worktreePath: "/tmp/wt/scout-1",
|
|
186
|
+
logsDir: "/tmp/logs/scout-1",
|
|
187
|
+
lastMailSent: null,
|
|
188
|
+
lastMailReceived: "2025-01-15T11:00:00.000Z",
|
|
189
|
+
capability: "scout",
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
printStatus(data);
|
|
194
|
+
const out = output();
|
|
195
|
+
|
|
196
|
+
expect(out).toContain("Worktree: /tmp/wt/builder-1");
|
|
197
|
+
expect(out).toContain("Worktree: /tmp/wt/scout-1");
|
|
198
|
+
expect(out).toContain("Logs: /tmp/logs/builder-1");
|
|
199
|
+
expect(out).toContain("Logs: /tmp/logs/scout-1");
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe("--verbose --json", () => {
|
|
204
|
+
test("verboseDetails is included in StatusData when present", () => {
|
|
205
|
+
const detail: VerboseAgentDetail = {
|
|
206
|
+
worktreePath: "/tmp/wt/agent",
|
|
207
|
+
logsDir: "/tmp/logs/agent",
|
|
208
|
+
lastMailSent: "2025-01-15T10:00:00.000Z",
|
|
209
|
+
lastMailReceived: null,
|
|
210
|
+
capability: "builder",
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const data: StatusData = {
|
|
214
|
+
agents: [],
|
|
215
|
+
worktrees: [],
|
|
216
|
+
tmuxSessions: [],
|
|
217
|
+
unreadMailCount: 0,
|
|
218
|
+
unreadMailScope: "orchestrator",
|
|
219
|
+
mergeQueueCount: 0,
|
|
220
|
+
recentMetricsCount: 0,
|
|
221
|
+
verboseDetails: { agent: detail },
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const json = JSON.parse(JSON.stringify(data)) as StatusData;
|
|
225
|
+
expect(json.verboseDetails).toBeDefined();
|
|
226
|
+
expect(json.verboseDetails?.agent?.worktreePath).toBe("/tmp/wt/agent");
|
|
227
|
+
expect(json.verboseDetails?.agent?.lastMailSent).toBe("2025-01-15T10:00:00.000Z");
|
|
228
|
+
expect(json.verboseDetails?.agent?.lastMailReceived).toBeNull();
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test("verboseDetails is omitted from JSON when undefined", () => {
|
|
232
|
+
const data: StatusData = {
|
|
233
|
+
agents: [],
|
|
234
|
+
worktrees: [],
|
|
235
|
+
tmuxSessions: [],
|
|
236
|
+
unreadMailCount: 0,
|
|
237
|
+
unreadMailScope: "orchestrator",
|
|
238
|
+
mergeQueueCount: 0,
|
|
239
|
+
recentMetricsCount: 0,
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const json = JSON.stringify(data);
|
|
243
|
+
expect(json).not.toContain("verboseDetails");
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
describe("run scoping", () => {
|
|
248
|
+
let chunks: string[];
|
|
249
|
+
let originalWrite: typeof process.stdout.write;
|
|
250
|
+
|
|
251
|
+
beforeEach(() => {
|
|
252
|
+
chunks = [];
|
|
253
|
+
originalWrite = process.stdout.write;
|
|
254
|
+
process.stdout.write = ((chunk: string) => {
|
|
255
|
+
chunks.push(chunk);
|
|
256
|
+
return true;
|
|
257
|
+
}) as typeof process.stdout.write;
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
afterEach(() => {
|
|
261
|
+
process.stdout.write = originalWrite;
|
|
262
|
+
invalidateStatusCache();
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
function output(): string {
|
|
266
|
+
return chunks.join("");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
test("printStatus shows run ID when currentRunId is set", () => {
|
|
270
|
+
const data = makeStatusData({ currentRunId: "run-123" });
|
|
271
|
+
printStatus(data);
|
|
272
|
+
expect(stripAnsi(output())).toContain("Run: run-123");
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
test("printStatus does not show run line when currentRunId is undefined", () => {
|
|
276
|
+
const data = makeStatusData();
|
|
277
|
+
printStatus(data);
|
|
278
|
+
expect(output()).not.toContain("Run:");
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
test("printStatus does not show run line when currentRunId is null", () => {
|
|
282
|
+
const data = makeStatusData({ currentRunId: null });
|
|
283
|
+
printStatus(data);
|
|
284
|
+
expect(output()).not.toContain("Run:");
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
test("help text includes --all", async () => {
|
|
288
|
+
const helpChunks: string[] = [];
|
|
289
|
+
const origWrite = process.stdout.write;
|
|
290
|
+
process.stdout.write = ((chunk: string) => {
|
|
291
|
+
helpChunks.push(chunk);
|
|
292
|
+
return true;
|
|
293
|
+
}) as typeof process.stdout.write;
|
|
294
|
+
|
|
295
|
+
try {
|
|
296
|
+
await statusCommand(["--help"]);
|
|
297
|
+
} finally {
|
|
298
|
+
process.stdout.write = origWrite;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const out = helpChunks.join("");
|
|
302
|
+
expect(out).toContain("--all");
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
test("gatherStatus includes null-runId sessions when run-scoped", async () => {
|
|
306
|
+
// Use a real git repo so listWorktrees() doesn't throw
|
|
307
|
+
const tempDir = await createTempGitRepo();
|
|
308
|
+
const agentplateDir = join(tempDir, ".agentplate");
|
|
309
|
+
await mkdir(agentplateDir, { recursive: true });
|
|
310
|
+
|
|
311
|
+
// Seed sessions.db with three sessions:
|
|
312
|
+
// coordinator: runId=null
|
|
313
|
+
// builder-1: runId="run-001" (in-scope)
|
|
314
|
+
// builder-2: runId="run-002" (out-of-scope)
|
|
315
|
+
const store = createSessionStore(join(agentplateDir, "sessions.db"));
|
|
316
|
+
const now = new Date().toISOString();
|
|
317
|
+
for (const session of [
|
|
318
|
+
makeAgent({
|
|
319
|
+
agentName: "coordinator",
|
|
320
|
+
capability: "coordinator",
|
|
321
|
+
runId: null,
|
|
322
|
+
tmuxSession: "agentplate-fake-coordinator",
|
|
323
|
+
}),
|
|
324
|
+
makeAgent({
|
|
325
|
+
id: "sess-002",
|
|
326
|
+
agentName: "builder-1",
|
|
327
|
+
capability: "builder",
|
|
328
|
+
runId: "run-001",
|
|
329
|
+
tmuxSession: "agentplate-fake-builder-1",
|
|
330
|
+
}),
|
|
331
|
+
makeAgent({
|
|
332
|
+
id: "sess-003",
|
|
333
|
+
agentName: "builder-2",
|
|
334
|
+
capability: "builder",
|
|
335
|
+
runId: "run-002",
|
|
336
|
+
tmuxSession: "agentplate-fake-builder-2",
|
|
337
|
+
}),
|
|
338
|
+
] as AgentSession[]) {
|
|
339
|
+
session.startedAt = now;
|
|
340
|
+
session.lastActivity = now;
|
|
341
|
+
store.upsert(session);
|
|
342
|
+
}
|
|
343
|
+
store.close();
|
|
344
|
+
|
|
345
|
+
try {
|
|
346
|
+
const result = await gatherStatus(tempDir, "orchestrator", false, "run-001");
|
|
347
|
+
const names = result.agents.map((a) => a.agentName);
|
|
348
|
+
|
|
349
|
+
// coordinator (null runId) must appear
|
|
350
|
+
expect(names).toContain("coordinator");
|
|
351
|
+
// in-scope builder must appear
|
|
352
|
+
expect(names).toContain("builder-1");
|
|
353
|
+
// out-of-scope builder must NOT appear
|
|
354
|
+
expect(names).not.toContain("builder-2");
|
|
355
|
+
} finally {
|
|
356
|
+
await cleanupTempDir(tempDir);
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
describe("headless agent alive markers", () => {
|
|
362
|
+
let chunks: string[];
|
|
363
|
+
let originalWrite: typeof process.stdout.write;
|
|
364
|
+
|
|
365
|
+
beforeEach(() => {
|
|
366
|
+
chunks = [];
|
|
367
|
+
originalWrite = process.stdout.write;
|
|
368
|
+
process.stdout.write = ((chunk: string) => {
|
|
369
|
+
chunks.push(chunk);
|
|
370
|
+
return true;
|
|
371
|
+
}) as typeof process.stdout.write;
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
afterEach(() => {
|
|
375
|
+
process.stdout.write = originalWrite;
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
function output(): string {
|
|
379
|
+
return chunks.join("");
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
test("printStatus shows green marker for headless agent with alive PID", () => {
|
|
383
|
+
// Use own process PID — guaranteed alive
|
|
384
|
+
const alivePid = process.pid;
|
|
385
|
+
const agent = makeAgent({
|
|
386
|
+
agentName: "headless-builder",
|
|
387
|
+
tmuxSession: "", // headless: no tmux
|
|
388
|
+
pid: alivePid,
|
|
389
|
+
state: "working",
|
|
390
|
+
});
|
|
391
|
+
const data = makeStatusData({
|
|
392
|
+
agents: [agent],
|
|
393
|
+
tmuxSessions: [], // no tmux sessions
|
|
394
|
+
});
|
|
395
|
+
printStatus(data);
|
|
396
|
+
const out = output();
|
|
397
|
+
// Green marker is ">" — check it appears in the output
|
|
398
|
+
expect(out).toContain("headless-builder");
|
|
399
|
+
expect(out).toContain(">");
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
test("printStatus shows red marker for headless agent with dead PID", () => {
|
|
403
|
+
const deadPid = 2_147_483_647; // max int, virtually guaranteed non-existent
|
|
404
|
+
const agent = makeAgent({
|
|
405
|
+
agentName: "dead-headless-builder",
|
|
406
|
+
tmuxSession: "", // headless: no tmux
|
|
407
|
+
pid: deadPid,
|
|
408
|
+
state: "working",
|
|
409
|
+
});
|
|
410
|
+
const data = makeStatusData({
|
|
411
|
+
agents: [agent],
|
|
412
|
+
tmuxSessions: [],
|
|
413
|
+
});
|
|
414
|
+
printStatus(data);
|
|
415
|
+
const out = output();
|
|
416
|
+
expect(out).toContain("dead-headless-builder");
|
|
417
|
+
expect(out).toContain("x");
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
test("printStatus uses tmux check (not PID) for tmux-based agents", () => {
|
|
421
|
+
const agent = makeAgent({
|
|
422
|
+
agentName: "tmux-builder",
|
|
423
|
+
tmuxSession: "agentplate-test-builder",
|
|
424
|
+
pid: process.pid, // alive PID, but should use tmux check
|
|
425
|
+
state: "working",
|
|
426
|
+
});
|
|
427
|
+
// tmuxSessions empty → tmux dead → red marker
|
|
428
|
+
const data = makeStatusData({
|
|
429
|
+
agents: [agent],
|
|
430
|
+
tmuxSessions: [],
|
|
431
|
+
});
|
|
432
|
+
printStatus(data);
|
|
433
|
+
const out = output();
|
|
434
|
+
expect(out).toContain("x");
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
describe("--watch deprecation", () => {
|
|
439
|
+
test("help text marks --watch as deprecated", async () => {
|
|
440
|
+
const chunks: string[] = [];
|
|
441
|
+
const originalWrite = process.stdout.write;
|
|
442
|
+
process.stdout.write = ((chunk: string) => {
|
|
443
|
+
chunks.push(chunk);
|
|
444
|
+
return true;
|
|
445
|
+
}) as typeof process.stdout.write;
|
|
446
|
+
|
|
447
|
+
try {
|
|
448
|
+
await statusCommand(["--help"]);
|
|
449
|
+
} finally {
|
|
450
|
+
process.stdout.write = originalWrite;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const out = chunks.join("");
|
|
454
|
+
expect(out).toContain("deprecated");
|
|
455
|
+
expect(out).toContain("ap dashboard");
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
test("--watch writes deprecation notice to stderr", async () => {
|
|
459
|
+
const stderrChunks: string[] = [];
|
|
460
|
+
const originalStderr = process.stderr.write;
|
|
461
|
+
process.stderr.write = ((chunk: string) => {
|
|
462
|
+
stderrChunks.push(chunk);
|
|
463
|
+
return true;
|
|
464
|
+
}) as typeof process.stderr.write;
|
|
465
|
+
|
|
466
|
+
// statusCommand with --watch will fail at loadConfig (no .agentplate/)
|
|
467
|
+
// but the deprecation notice is written before that. We just verify
|
|
468
|
+
// the notice was emitted.
|
|
469
|
+
const tmpDir = await mkdtemp(join(tmpdir(), "status-deprecation-"));
|
|
470
|
+
const originalCwd = process.cwd();
|
|
471
|
+
process.chdir(tmpDir);
|
|
472
|
+
|
|
473
|
+
try {
|
|
474
|
+
await statusCommand(["--watch"]);
|
|
475
|
+
} catch {
|
|
476
|
+
// Expected: loadConfig fails without .agentplate/
|
|
477
|
+
} finally {
|
|
478
|
+
process.stderr.write = originalStderr;
|
|
479
|
+
process.chdir(originalCwd);
|
|
480
|
+
await cleanupTempDir(tmpDir);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const err = stderrChunks.join("");
|
|
484
|
+
expect(err).toContain("--watch is deprecated");
|
|
485
|
+
expect(err).toContain("ap dashboard");
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
describe("gatherStatus reconciliation", () => {
|
|
490
|
+
afterEach(() => {
|
|
491
|
+
invalidateStatusCache();
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
test("booting agent with dead tmux becomes zombie", async () => {
|
|
495
|
+
const tempDir = await createTempGitRepo();
|
|
496
|
+
const agentplateDir = join(tempDir, ".agentplate");
|
|
497
|
+
await mkdir(agentplateDir, { recursive: true });
|
|
498
|
+
|
|
499
|
+
const store = createSessionStore(join(agentplateDir, "sessions.db"));
|
|
500
|
+
const now = new Date().toISOString();
|
|
501
|
+
const session = makeAgent({
|
|
502
|
+
agentName: "boot-builder",
|
|
503
|
+
capability: "builder",
|
|
504
|
+
state: "booting",
|
|
505
|
+
tmuxSession: "agentplate-boot-builder",
|
|
506
|
+
runId: null,
|
|
507
|
+
});
|
|
508
|
+
session.startedAt = now;
|
|
509
|
+
session.lastActivity = now;
|
|
510
|
+
store.upsert(session);
|
|
511
|
+
store.close();
|
|
512
|
+
|
|
513
|
+
try {
|
|
514
|
+
// No real tmux running, so getCachedTmuxSessions() returns empty array
|
|
515
|
+
// evaluateHealth ZFC Rule 1: tmux dead → zombie
|
|
516
|
+
const result = await gatherStatus(tempDir, "orchestrator", false, undefined);
|
|
517
|
+
const agent = result.agents.find((a) => a.agentName === "boot-builder");
|
|
518
|
+
expect(agent).toBeDefined();
|
|
519
|
+
expect(agent?.state).toBe("zombie");
|
|
520
|
+
} finally {
|
|
521
|
+
await cleanupTempDir(tempDir);
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
test("completed agents skip reconciliation", async () => {
|
|
526
|
+
const tempDir = await createTempGitRepo();
|
|
527
|
+
const agentplateDir = join(tempDir, ".agentplate");
|
|
528
|
+
await mkdir(agentplateDir, { recursive: true });
|
|
529
|
+
|
|
530
|
+
const store = createSessionStore(join(agentplateDir, "sessions.db"));
|
|
531
|
+
const now = new Date().toISOString();
|
|
532
|
+
const session = makeAgent({
|
|
533
|
+
agentName: "done-builder",
|
|
534
|
+
capability: "builder",
|
|
535
|
+
state: "completed",
|
|
536
|
+
tmuxSession: "agentplate-done-builder",
|
|
537
|
+
runId: null,
|
|
538
|
+
});
|
|
539
|
+
session.startedAt = now;
|
|
540
|
+
session.lastActivity = now;
|
|
541
|
+
store.upsert(session);
|
|
542
|
+
store.close();
|
|
543
|
+
|
|
544
|
+
try {
|
|
545
|
+
const result = await gatherStatus(tempDir, "orchestrator", false, undefined);
|
|
546
|
+
const agent = result.agents.find((a) => a.agentName === "done-builder");
|
|
547
|
+
expect(agent).toBeDefined();
|
|
548
|
+
expect(agent?.state).toBe("completed");
|
|
549
|
+
} finally {
|
|
550
|
+
await cleanupTempDir(tempDir);
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
test("working agent with dead tmux becomes zombie", async () => {
|
|
555
|
+
const tempDir = await createTempGitRepo();
|
|
556
|
+
const agentplateDir = join(tempDir, ".agentplate");
|
|
557
|
+
await mkdir(agentplateDir, { recursive: true });
|
|
558
|
+
|
|
559
|
+
const store = createSessionStore(join(agentplateDir, "sessions.db"));
|
|
560
|
+
const now = new Date().toISOString();
|
|
561
|
+
const session = makeAgent({
|
|
562
|
+
agentName: "working-builder",
|
|
563
|
+
capability: "builder",
|
|
564
|
+
state: "working",
|
|
565
|
+
tmuxSession: "agentplate-working-builder",
|
|
566
|
+
runId: null,
|
|
567
|
+
});
|
|
568
|
+
session.startedAt = now;
|
|
569
|
+
session.lastActivity = now;
|
|
570
|
+
store.upsert(session);
|
|
571
|
+
store.close();
|
|
572
|
+
|
|
573
|
+
try {
|
|
574
|
+
// No real tmux session → tmux dead → zombie via evaluateHealth ZFC Rule 1
|
|
575
|
+
const result = await gatherStatus(tempDir, "orchestrator", false, undefined);
|
|
576
|
+
const agent = result.agents.find((a) => a.agentName === "working-builder");
|
|
577
|
+
expect(agent).toBeDefined();
|
|
578
|
+
expect(agent?.state).toBe("zombie");
|
|
579
|
+
} finally {
|
|
580
|
+
await cleanupTempDir(tempDir);
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
describe("subprocess caching (invalidateStatusCache)", () => {
|
|
586
|
+
afterEach(() => {
|
|
587
|
+
invalidateStatusCache();
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
test("invalidateStatusCache is exported and callable", () => {
|
|
591
|
+
// Should not throw
|
|
592
|
+
invalidateStatusCache();
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
test("invalidateStatusCache resets cache so gatherStatus re-fetches on next call", async () => {
|
|
596
|
+
const tempDir = await createTempGitRepo();
|
|
597
|
+
const agentplateDir = join(tempDir, ".agentplate");
|
|
598
|
+
await mkdir(agentplateDir, { recursive: true });
|
|
599
|
+
|
|
600
|
+
try {
|
|
601
|
+
// First call populates the cache
|
|
602
|
+
const result1 = await gatherStatus(tempDir, "orchestrator", false, undefined);
|
|
603
|
+
// Invalidate cache
|
|
604
|
+
invalidateStatusCache();
|
|
605
|
+
// Second call must succeed (re-fetches, no stale cache issues)
|
|
606
|
+
const result2 = await gatherStatus(tempDir, "orchestrator", false, undefined);
|
|
607
|
+
// Both results should have the same structure
|
|
608
|
+
expect(Array.isArray(result1.worktrees)).toBe(true);
|
|
609
|
+
expect(Array.isArray(result2.worktrees)).toBe(true);
|
|
610
|
+
} finally {
|
|
611
|
+
await cleanupTempDir(tempDir);
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
});
|