@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,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: ap stop <agent-name>
|
|
3
|
+
*
|
|
4
|
+
* Explicitly terminates a running agent by:
|
|
5
|
+
* 1. Looking up the agent session by name
|
|
6
|
+
* 2a. For TUI agents: killing its tmux session (if alive)
|
|
7
|
+
* 2b. For headless agents (tmuxSession === ''): sending SIGTERM to the process tree
|
|
8
|
+
* 3. Marking it as completed in the SessionStore
|
|
9
|
+
* 4. Optionally removing its worktree and branch (--clean-worktree)
|
|
10
|
+
*
|
|
11
|
+
* Completed agents: ap stop <name> without --clean-worktree throws a helpful error.
|
|
12
|
+
* With --clean-worktree, completed agents skip the kill step and proceed to cleanup.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { unlink } from "node:fs/promises";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { loadConfig } from "../config.ts";
|
|
18
|
+
import { AgentError, ValidationError } from "../errors.ts";
|
|
19
|
+
import { jsonOutput } from "../json.ts";
|
|
20
|
+
import { printSuccess, printWarning } from "../logging/color.ts";
|
|
21
|
+
import { createMailStore } from "../mail/store.ts";
|
|
22
|
+
import { openSessionStore } from "../sessions/compat.ts";
|
|
23
|
+
import type { MergeReadyPayload } from "../types.ts";
|
|
24
|
+
import { readPidFile } from "../utils/pid.ts";
|
|
25
|
+
import { removeWorktree } from "../worktree/manager.ts";
|
|
26
|
+
import { isProcessAlive, isSessionAlive, killProcessTree, killSession } from "../worktree/tmux.ts";
|
|
27
|
+
|
|
28
|
+
export interface StopOptions {
|
|
29
|
+
force?: boolean;
|
|
30
|
+
cleanWorktree?: boolean;
|
|
31
|
+
json?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Dependency injection for testing. Uses real implementations when omitted. */
|
|
35
|
+
export interface StopDeps {
|
|
36
|
+
_tmux?: {
|
|
37
|
+
isSessionAlive: (name: string) => Promise<boolean>;
|
|
38
|
+
killSession: (name: string) => Promise<void>;
|
|
39
|
+
};
|
|
40
|
+
_worktree?: {
|
|
41
|
+
remove: (
|
|
42
|
+
repoRoot: string,
|
|
43
|
+
path: string,
|
|
44
|
+
options?: { force?: boolean; forceBranch?: boolean },
|
|
45
|
+
) => Promise<void>;
|
|
46
|
+
};
|
|
47
|
+
_process?: {
|
|
48
|
+
isAlive: (pid: number) => boolean;
|
|
49
|
+
killTree: (pid: number) => Promise<void>;
|
|
50
|
+
};
|
|
51
|
+
_git?: {
|
|
52
|
+
deleteBranch: (repoRoot: string, branch: string) => Promise<boolean>;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Build the lead_completed nudge subject based on whether the lead actually sent
|
|
58
|
+
* merge_ready before exiting (agentplate-41fe). The merge_ready close-gate
|
|
59
|
+
* (commit 3e21338) prevents leads from running `sr close` without it, but a
|
|
60
|
+
* lead can still exit (process termination, watchdog kill, manual `ap stop`)
|
|
61
|
+
* without ever having sent one. The coordinator's surfacing of this nudge
|
|
62
|
+
* needs to distinguish those two cases.
|
|
63
|
+
*/
|
|
64
|
+
function buildLeadCompletedSubject(agentName: string, mailDbPath: string): string {
|
|
65
|
+
let mergeReadyBranches: string[] = [];
|
|
66
|
+
let mergeReadyCount = 0;
|
|
67
|
+
try {
|
|
68
|
+
const store = createMailStore(mailDbPath);
|
|
69
|
+
try {
|
|
70
|
+
const messages = store.getAll({ from: agentName, type: "merge_ready" });
|
|
71
|
+
mergeReadyCount = messages.length;
|
|
72
|
+
for (const msg of messages) {
|
|
73
|
+
if (msg.payload === null) continue;
|
|
74
|
+
try {
|
|
75
|
+
const parsed = JSON.parse(msg.payload) as Partial<MergeReadyPayload>;
|
|
76
|
+
if (typeof parsed.branch === "string" && parsed.branch.length > 0) {
|
|
77
|
+
mergeReadyBranches.push(parsed.branch);
|
|
78
|
+
}
|
|
79
|
+
} catch {
|
|
80
|
+
// Skip messages with unparseable payloads
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
} finally {
|
|
84
|
+
store.close();
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
// If the mail store can't be opened (corrupt db, permissions), fall back
|
|
88
|
+
// to the historical ambiguous phrasing rather than blocking the stop.
|
|
89
|
+
return `Lead ${agentName} completed — check mail for merge_ready/worker_done`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (mergeReadyCount === 0) {
|
|
93
|
+
return `Lead ${agentName} exited — no merge_ready sent, needs coordinator follow-up`;
|
|
94
|
+
}
|
|
95
|
+
// Dedupe in case a lead resent merge_ready for the same branch
|
|
96
|
+
mergeReadyBranches = Array.from(new Set(mergeReadyBranches));
|
|
97
|
+
if (mergeReadyBranches.length === 0) {
|
|
98
|
+
return `Lead ${agentName} sent ${mergeReadyCount} merge_ready (branch unknown)`;
|
|
99
|
+
}
|
|
100
|
+
if (mergeReadyBranches.length === 1) {
|
|
101
|
+
return `Lead ${agentName} sent merge_ready for branch ${mergeReadyBranches[0]}`;
|
|
102
|
+
}
|
|
103
|
+
return `Lead ${agentName} sent ${mergeReadyBranches.length} merge_ready (branches: ${mergeReadyBranches.join(", ")})`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Delete a git branch (best-effort, non-fatal). */
|
|
107
|
+
async function deleteBranchBestEffort(repoRoot: string, branch: string): Promise<boolean> {
|
|
108
|
+
try {
|
|
109
|
+
const proc = Bun.spawn(["git", "branch", "-D", branch], {
|
|
110
|
+
cwd: repoRoot,
|
|
111
|
+
stdout: "pipe",
|
|
112
|
+
stderr: "pipe",
|
|
113
|
+
});
|
|
114
|
+
const exitCode = await proc.exited;
|
|
115
|
+
return exitCode === 0;
|
|
116
|
+
} catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Entry point for `ap stop <agent-name>`.
|
|
123
|
+
*
|
|
124
|
+
* @param agentName - Name of the agent to stop
|
|
125
|
+
* @param opts - Command options
|
|
126
|
+
* @param deps - Optional dependency injection for testing (tmux, worktree, process, git)
|
|
127
|
+
*/
|
|
128
|
+
export async function stopCommand(
|
|
129
|
+
agentName: string,
|
|
130
|
+
opts: StopOptions,
|
|
131
|
+
deps: StopDeps = {},
|
|
132
|
+
): Promise<void> {
|
|
133
|
+
if (!agentName || agentName.trim().length === 0) {
|
|
134
|
+
throw new ValidationError("Missing required argument: <agent-name>", {
|
|
135
|
+
field: "agentName",
|
|
136
|
+
value: "",
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const json = opts.json ?? false;
|
|
141
|
+
const force = opts.force ?? false;
|
|
142
|
+
const cleanWorktree = opts.cleanWorktree ?? false;
|
|
143
|
+
|
|
144
|
+
const tmux = deps._tmux ?? { isSessionAlive, killSession };
|
|
145
|
+
const worktree = deps._worktree ?? { remove: removeWorktree };
|
|
146
|
+
const proc = deps._process ?? { isAlive: isProcessAlive, killTree: killProcessTree };
|
|
147
|
+
const git = deps._git ?? { deleteBranch: deleteBranchBestEffort };
|
|
148
|
+
|
|
149
|
+
const cwd = process.cwd();
|
|
150
|
+
const config = await loadConfig(cwd);
|
|
151
|
+
const projectRoot = config.project.root;
|
|
152
|
+
const agentplateDir = join(projectRoot, ".agentplate");
|
|
153
|
+
|
|
154
|
+
const { store } = openSessionStore(agentplateDir);
|
|
155
|
+
try {
|
|
156
|
+
const session = store.getByName(agentName);
|
|
157
|
+
if (!session) {
|
|
158
|
+
throw new AgentError(`Agent "${agentName}" not found`, { agentName });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const isAlreadyCompleted = session.state === "completed";
|
|
162
|
+
|
|
163
|
+
// Completed agents without --clean-worktree: throw with helpful message
|
|
164
|
+
if (isAlreadyCompleted && !cleanWorktree) {
|
|
165
|
+
throw new AgentError(
|
|
166
|
+
`Agent "${agentName}" is already completed. Use --clean-worktree to remove its worktree.`,
|
|
167
|
+
{ agentName },
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const isZombie = session.state === "zombie";
|
|
172
|
+
// Headless task-scoped agents (Phase 3 spawn-per-turn): tmuxSession is ""
|
|
173
|
+
// and session.pid is null between turns. The live PID for an in-flight
|
|
174
|
+
// turn is published at .agentplate/agents/<name>/turn.pid. Sapling RPC
|
|
175
|
+
// agents still use session.pid for their long-lived process.
|
|
176
|
+
const isHeadless = session.tmuxSession === "";
|
|
177
|
+
const turnPidPath = join(agentplateDir, "agents", agentName, "turn.pid");
|
|
178
|
+
|
|
179
|
+
let tmuxKilled = false;
|
|
180
|
+
let pidKilled = false;
|
|
181
|
+
|
|
182
|
+
// Skip kill operations for already-completed agents (process/tmux already gone)
|
|
183
|
+
if (!isAlreadyCompleted) {
|
|
184
|
+
if (isHeadless) {
|
|
185
|
+
// Prefer the per-turn PID file (Phase 3) — this catches an in-flight
|
|
186
|
+
// claude turn for any task-scoped capability. Fall back to the
|
|
187
|
+
// session row's pid for legacy/long-lived headless runtimes (Sapling).
|
|
188
|
+
const turnPid = await readPidFile(turnPidPath);
|
|
189
|
+
const targetPid = turnPid ?? session.pid;
|
|
190
|
+
if (targetPid !== null && proc.isAlive(targetPid)) {
|
|
191
|
+
await proc.killTree(targetPid);
|
|
192
|
+
pidKilled = true;
|
|
193
|
+
}
|
|
194
|
+
// Reap the turn.pid file so a subsequent ap stop / mail injector
|
|
195
|
+
// doesn't see a stale entry. Idempotent.
|
|
196
|
+
try {
|
|
197
|
+
await unlink(turnPidPath);
|
|
198
|
+
} catch {
|
|
199
|
+
// already gone — non-fatal
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
// TUI agent: kill via tmux session
|
|
203
|
+
const alive = await tmux.isSessionAlive(session.tmuxSession);
|
|
204
|
+
if (alive) {
|
|
205
|
+
await tmux.killSession(session.tmuxSession);
|
|
206
|
+
tmuxKilled = true;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Mark session as completed via the guarded transition. `completed` is
|
|
211
|
+
// reachable from every non-completed state (including zombie, so `ap
|
|
212
|
+
// stop` can promote a watchdog-flagged zombie to a clean completion),
|
|
213
|
+
// so the only way this rejects is if state is already `completed` —
|
|
214
|
+
// which is the no-op we want anyway. Race-safe under agentplate-a993.
|
|
215
|
+
store.tryTransitionState(agentName, "completed");
|
|
216
|
+
store.updateLastActivity(agentName);
|
|
217
|
+
|
|
218
|
+
// Auto-nudge coordinator when a lead truly completes so it wakes up
|
|
219
|
+
// to process merge_ready / worker_done messages without waiting for
|
|
220
|
+
// user input. Fires from `ap stop` (real completion signal) rather
|
|
221
|
+
// than the per-turn Stop hook, which was spamming the coordinator
|
|
222
|
+
// (agentplate-49a7).
|
|
223
|
+
if (session.capability === "lead") {
|
|
224
|
+
try {
|
|
225
|
+
const mailDbPath = join(agentplateDir, "mail.db");
|
|
226
|
+
const subject = buildLeadCompletedSubject(agentName, mailDbPath);
|
|
227
|
+
const nudgesDir = join(agentplateDir, "pending-nudges");
|
|
228
|
+
const { mkdir } = await import("node:fs/promises");
|
|
229
|
+
await mkdir(nudgesDir, { recursive: true });
|
|
230
|
+
const markerPath = join(nudgesDir, "coordinator.json");
|
|
231
|
+
const marker = {
|
|
232
|
+
from: agentName,
|
|
233
|
+
reason: "lead_completed",
|
|
234
|
+
subject,
|
|
235
|
+
messageId: `auto-nudge-${agentName}-${Date.now()}`,
|
|
236
|
+
createdAt: new Date().toISOString(),
|
|
237
|
+
};
|
|
238
|
+
await Bun.write(markerPath, `${JSON.stringify(marker, null, "\t")}\n`);
|
|
239
|
+
} catch {
|
|
240
|
+
// Non-fatal: nudge failure should not break stop
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Optionally remove worktree and branch (best-effort, non-fatal)
|
|
246
|
+
let worktreeRemoved = false;
|
|
247
|
+
let branchDeleted = false;
|
|
248
|
+
if (cleanWorktree) {
|
|
249
|
+
if (session.worktreePath) {
|
|
250
|
+
try {
|
|
251
|
+
await worktree.remove(projectRoot, session.worktreePath, {
|
|
252
|
+
force,
|
|
253
|
+
forceBranch: false,
|
|
254
|
+
});
|
|
255
|
+
worktreeRemoved = true;
|
|
256
|
+
} catch (err) {
|
|
257
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
258
|
+
if (!json) printWarning("Failed to remove worktree", msg);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Delete the branch after removing the worktree (best-effort, non-fatal)
|
|
263
|
+
if (session.branchName) {
|
|
264
|
+
try {
|
|
265
|
+
branchDeleted = await git.deleteBranch(projectRoot, session.branchName);
|
|
266
|
+
} catch {
|
|
267
|
+
branchDeleted = false;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (json) {
|
|
273
|
+
jsonOutput("stop", {
|
|
274
|
+
stopped: true,
|
|
275
|
+
agentName,
|
|
276
|
+
sessionId: session.id,
|
|
277
|
+
capability: session.capability,
|
|
278
|
+
tmuxKilled,
|
|
279
|
+
pidKilled,
|
|
280
|
+
worktreeRemoved,
|
|
281
|
+
branchDeleted,
|
|
282
|
+
force,
|
|
283
|
+
wasZombie: isZombie,
|
|
284
|
+
wasCompleted: isAlreadyCompleted,
|
|
285
|
+
});
|
|
286
|
+
} else {
|
|
287
|
+
printSuccess("Agent stopped", agentName);
|
|
288
|
+
if (!isAlreadyCompleted) {
|
|
289
|
+
if (isHeadless) {
|
|
290
|
+
if (pidKilled) {
|
|
291
|
+
process.stdout.write(` Process tree killed: PID ${session.pid}\n`);
|
|
292
|
+
} else {
|
|
293
|
+
process.stdout.write(` Process was already dead (PID ${session.pid})\n`);
|
|
294
|
+
}
|
|
295
|
+
} else {
|
|
296
|
+
if (tmuxKilled) {
|
|
297
|
+
process.stdout.write(` Tmux session killed: ${session.tmuxSession}\n`);
|
|
298
|
+
} else {
|
|
299
|
+
process.stdout.write(` Tmux session was already dead\n`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (isZombie) {
|
|
304
|
+
process.stdout.write(` Zombie agent cleaned up (state → completed)\n`);
|
|
305
|
+
}
|
|
306
|
+
if (isAlreadyCompleted) {
|
|
307
|
+
process.stdout.write(` Agent was already completed (skipped kill)\n`);
|
|
308
|
+
}
|
|
309
|
+
if (cleanWorktree && worktreeRemoved) {
|
|
310
|
+
process.stdout.write(` Worktree removed: ${session.worktreePath}\n`);
|
|
311
|
+
}
|
|
312
|
+
if (cleanWorktree && branchDeleted) {
|
|
313
|
+
process.stdout.write(` Branch deleted: ${session.branchName}\n`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} finally {
|
|
317
|
+
store.close();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { isRunningAsRoot } from "./sling.ts";
|
|
3
|
+
import { buildSupervisorBeacon, supervisorCommand } from "./supervisor.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Tests for supervisor command functions.
|
|
7
|
+
*
|
|
8
|
+
* Session persistence is now handled by SessionStore (SQLite).
|
|
9
|
+
* Those tests live in src/sessions/store.test.ts and src/sessions/compat.test.ts.
|
|
10
|
+
* Here we test beacon generation.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
describe("buildSupervisorBeacon", () => {
|
|
14
|
+
test("contains agent name and taskId from opts", () => {
|
|
15
|
+
const beacon = buildSupervisorBeacon({
|
|
16
|
+
name: "supervisor-1",
|
|
17
|
+
taskId: "task-abc123",
|
|
18
|
+
depth: 1,
|
|
19
|
+
parent: "coordinator",
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
expect(beacon).toContain("supervisor-1");
|
|
23
|
+
expect(beacon).toContain("task-abc123");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("contains [AGENTPLATE] prefix", () => {
|
|
27
|
+
const beacon = buildSupervisorBeacon({
|
|
28
|
+
name: "supervisor-1",
|
|
29
|
+
taskId: "task-1",
|
|
30
|
+
depth: 1,
|
|
31
|
+
parent: "coordinator",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
expect(beacon).toContain("[AGENTPLATE]");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("contains (supervisor) designation", () => {
|
|
38
|
+
const beacon = buildSupervisorBeacon({
|
|
39
|
+
name: "supervisor-1",
|
|
40
|
+
taskId: "task-1",
|
|
41
|
+
depth: 1,
|
|
42
|
+
parent: "coordinator",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
expect(beacon).toContain("(supervisor)");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("contains depth and parent info from opts", () => {
|
|
49
|
+
const beacon = buildSupervisorBeacon({
|
|
50
|
+
name: "supervisor-1",
|
|
51
|
+
taskId: "task-1",
|
|
52
|
+
depth: 2,
|
|
53
|
+
parent: "lead-cli",
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
expect(beacon).toContain("Depth: 2");
|
|
57
|
+
expect(beacon).toContain("Parent: lead-cli");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("contains startup instructions", () => {
|
|
61
|
+
const beacon = buildSupervisorBeacon({
|
|
62
|
+
name: "supervisor-1",
|
|
63
|
+
taskId: "task-1",
|
|
64
|
+
depth: 1,
|
|
65
|
+
parent: "coordinator",
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Should include loam prime
|
|
69
|
+
expect(beacon).toContain("loam prime");
|
|
70
|
+
|
|
71
|
+
// Should include mail check with agent name
|
|
72
|
+
expect(beacon).toContain("ap mail check --agent supervisor-1");
|
|
73
|
+
|
|
74
|
+
// Should include bd show with taskId
|
|
75
|
+
expect(beacon).toContain("bd show task-1");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("contains ISO timestamp", () => {
|
|
79
|
+
const before = new Date();
|
|
80
|
+
const beacon = buildSupervisorBeacon({
|
|
81
|
+
name: "supervisor-1",
|
|
82
|
+
taskId: "task-1",
|
|
83
|
+
depth: 1,
|
|
84
|
+
parent: "coordinator",
|
|
85
|
+
});
|
|
86
|
+
const after = new Date();
|
|
87
|
+
|
|
88
|
+
// Extract timestamp from beacon (format: [AGENTPLATE] {name} (supervisor) {timestamp} task:{taskId})
|
|
89
|
+
const timestampMatch = beacon.match(/\(supervisor\)\s+(\S+)\s+task:/);
|
|
90
|
+
expect(timestampMatch).toBeTruthy();
|
|
91
|
+
|
|
92
|
+
if (timestampMatch?.[1]) {
|
|
93
|
+
const timestamp = new Date(timestampMatch[1]);
|
|
94
|
+
expect(timestamp.getTime()).toBeGreaterThanOrEqual(before.getTime());
|
|
95
|
+
expect(timestamp.getTime()).toBeLessThanOrEqual(after.getTime());
|
|
96
|
+
|
|
97
|
+
// Verify ISO format (should parse correctly)
|
|
98
|
+
expect(timestamp.toISOString()).toBeTruthy();
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe("supervisorCommand", () => {
|
|
104
|
+
test("--help prints help containing required keywords", async () => {
|
|
105
|
+
const originalWrite = process.stdout.write;
|
|
106
|
+
let output = "";
|
|
107
|
+
process.stdout.write = ((chunk: string) => {
|
|
108
|
+
output += chunk;
|
|
109
|
+
return true;
|
|
110
|
+
}) as typeof process.stdout.write;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
await supervisorCommand(["--help"]);
|
|
114
|
+
expect(output).toContain("supervisor");
|
|
115
|
+
expect(output).toContain("start");
|
|
116
|
+
expect(output).toContain("stop");
|
|
117
|
+
expect(output).toContain("status");
|
|
118
|
+
} finally {
|
|
119
|
+
process.stdout.write = originalWrite;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("-h prints help", async () => {
|
|
124
|
+
const originalWrite = process.stdout.write;
|
|
125
|
+
let output = "";
|
|
126
|
+
process.stdout.write = ((chunk: string) => {
|
|
127
|
+
output += chunk;
|
|
128
|
+
return true;
|
|
129
|
+
}) as typeof process.stdout.write;
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
await supervisorCommand(["-h"]);
|
|
133
|
+
expect(output).toContain("supervisor");
|
|
134
|
+
} finally {
|
|
135
|
+
process.stdout.write = originalWrite;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("empty args [] shows help", async () => {
|
|
140
|
+
const originalWrite = process.stdout.write;
|
|
141
|
+
let output = "";
|
|
142
|
+
process.stdout.write = ((chunk: string) => {
|
|
143
|
+
output += chunk;
|
|
144
|
+
return true;
|
|
145
|
+
}) as typeof process.stdout.write;
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
await supervisorCommand([]);
|
|
149
|
+
expect(output).toContain("supervisor");
|
|
150
|
+
} finally {
|
|
151
|
+
process.stdout.write = originalWrite;
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("unknown subcommand throws ValidationError with bad value in message", async () => {
|
|
156
|
+
expect(async () => {
|
|
157
|
+
await supervisorCommand(["invalid-subcommand"]);
|
|
158
|
+
}).toThrow(/invalid-subcommand/);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test("start without --task throws ValidationError", async () => {
|
|
162
|
+
expect(async () => {
|
|
163
|
+
await supervisorCommand(["start", "--name", "supervisor-1"]);
|
|
164
|
+
}).toThrow(/--task/);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("start without --name throws ValidationError", async () => {
|
|
168
|
+
expect(async () => {
|
|
169
|
+
await supervisorCommand(["start", "--task", "task-1"]);
|
|
170
|
+
}).toThrow(/--name/);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("stop without --name throws ValidationError", async () => {
|
|
174
|
+
expect(async () => {
|
|
175
|
+
await supervisorCommand(["stop"]);
|
|
176
|
+
}).toThrow(/--name/);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe("isRunningAsRoot (imported from sling)", () => {
|
|
181
|
+
test("is accessible from supervisor test file", () => {
|
|
182
|
+
expect(isRunningAsRoot(() => 0)).toBe(true);
|
|
183
|
+
expect(isRunningAsRoot(() => 1000)).toBe(false);
|
|
184
|
+
});
|
|
185
|
+
});
|