@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,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: ap trace <target> [--json] [--since <ts>] [--until <ts>] [--limit <n>]
|
|
3
|
+
*
|
|
4
|
+
* Shows a chronological timeline of events for an agent or task.
|
|
5
|
+
* Target can be an agent name or a task ID (resolved to agent name via SessionStore).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { Command } from "commander";
|
|
10
|
+
import { loadConfig } from "../config.ts";
|
|
11
|
+
import { ValidationError } from "../errors.ts";
|
|
12
|
+
import { createEventStore } from "../events/store.ts";
|
|
13
|
+
import { jsonOutput } from "../json.ts";
|
|
14
|
+
import { accent, color } from "../logging/color.ts";
|
|
15
|
+
import {
|
|
16
|
+
buildEventDetail,
|
|
17
|
+
formatAbsoluteTime,
|
|
18
|
+
formatDate,
|
|
19
|
+
formatRelativeTime,
|
|
20
|
+
} from "../logging/format.ts";
|
|
21
|
+
import { eventLabel, renderHeader } from "../logging/theme.ts";
|
|
22
|
+
import { openSessionStore } from "../sessions/compat.ts";
|
|
23
|
+
import type { StoredEvent } from "../types.ts";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Detect whether a target string looks like a task ID.
|
|
27
|
+
* Task IDs follow the pattern: word-alphanumeric (e.g., "agentplate-rj1k", "myproject-abc1").
|
|
28
|
+
*/
|
|
29
|
+
function looksLikeTaskId(target: string): boolean {
|
|
30
|
+
return /^[a-z][a-z0-9]*-[a-z0-9]{3,}$/i.test(target);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Print events as a formatted timeline with ANSI colors.
|
|
35
|
+
*/
|
|
36
|
+
function printTimeline(events: StoredEvent[], agentName: string, useAbsoluteTime: boolean): void {
|
|
37
|
+
const w = process.stdout.write.bind(process.stdout);
|
|
38
|
+
|
|
39
|
+
w(`${renderHeader(`Timeline for ${accent(agentName)}`)}\n`);
|
|
40
|
+
|
|
41
|
+
if (events.length === 0) {
|
|
42
|
+
w(`${color.dim("No events found.")}\n`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
w(`${color.dim(`${events.length} event${events.length === 1 ? "" : "s"}`)}\n\n`);
|
|
47
|
+
|
|
48
|
+
let lastDate = "";
|
|
49
|
+
|
|
50
|
+
for (const event of events) {
|
|
51
|
+
// Print date separator when the date changes
|
|
52
|
+
const date = formatDate(event.createdAt);
|
|
53
|
+
if (date && date !== lastDate) {
|
|
54
|
+
if (lastDate !== "") {
|
|
55
|
+
w("\n");
|
|
56
|
+
}
|
|
57
|
+
w(`${color.dim(`--- ${date} ---`)}\n`);
|
|
58
|
+
lastDate = date;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const timeStr = useAbsoluteTime
|
|
62
|
+
? formatAbsoluteTime(event.createdAt)
|
|
63
|
+
: formatRelativeTime(event.createdAt);
|
|
64
|
+
|
|
65
|
+
const label = eventLabel(event.eventType);
|
|
66
|
+
|
|
67
|
+
const levelColorFn =
|
|
68
|
+
event.level === "error" ? color.red : event.level === "warn" ? color.yellow : null;
|
|
69
|
+
const applyLevel = (text: string) => (levelColorFn ? levelColorFn(text) : text);
|
|
70
|
+
|
|
71
|
+
const detail = buildEventDetail(event);
|
|
72
|
+
const detailSuffix = detail ? ` ${color.dim(detail)}` : "";
|
|
73
|
+
|
|
74
|
+
const agentLabel = event.agentName !== agentName ? ` ${color.dim(`[${event.agentName}]`)}` : "";
|
|
75
|
+
|
|
76
|
+
w(
|
|
77
|
+
`${color.dim(timeStr.padStart(10))} ` +
|
|
78
|
+
`${applyLevel(label.color(color.bold(label.full)))}` +
|
|
79
|
+
`${agentLabel}${detailSuffix}\n`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface TraceOpts {
|
|
85
|
+
json?: boolean;
|
|
86
|
+
since?: string;
|
|
87
|
+
until?: string;
|
|
88
|
+
limit?: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function executeTrace(target: string, opts: TraceOpts): Promise<void> {
|
|
92
|
+
const json = opts.json ?? false;
|
|
93
|
+
const sinceStr = opts.since;
|
|
94
|
+
const untilStr = opts.until;
|
|
95
|
+
const limitStr = opts.limit;
|
|
96
|
+
const limit = limitStr ? Number.parseInt(limitStr, 10) : 100;
|
|
97
|
+
|
|
98
|
+
if (Number.isNaN(limit) || limit < 1) {
|
|
99
|
+
throw new ValidationError("--limit must be a positive integer", {
|
|
100
|
+
field: "limit",
|
|
101
|
+
value: limitStr,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Validate timestamps if provided
|
|
106
|
+
if (sinceStr !== undefined && Number.isNaN(new Date(sinceStr).getTime())) {
|
|
107
|
+
throw new ValidationError("--since must be a valid ISO 8601 timestamp", {
|
|
108
|
+
field: "since",
|
|
109
|
+
value: sinceStr,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (untilStr !== undefined && Number.isNaN(new Date(untilStr).getTime())) {
|
|
113
|
+
throw new ValidationError("--until must be a valid ISO 8601 timestamp", {
|
|
114
|
+
field: "until",
|
|
115
|
+
value: untilStr,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const cwd = process.cwd();
|
|
120
|
+
const config = await loadConfig(cwd);
|
|
121
|
+
const agentplateDir = join(config.project.root, ".agentplate");
|
|
122
|
+
|
|
123
|
+
// Resolve target to agent name
|
|
124
|
+
let agentName = target;
|
|
125
|
+
|
|
126
|
+
if (looksLikeTaskId(target)) {
|
|
127
|
+
// Try to resolve task ID to agent name via SessionStore
|
|
128
|
+
const { store: sessionStore } = openSessionStore(agentplateDir);
|
|
129
|
+
try {
|
|
130
|
+
const allSessions = sessionStore.getAll();
|
|
131
|
+
const matchingSession = allSessions.find((s) => s.taskId === target);
|
|
132
|
+
if (matchingSession) {
|
|
133
|
+
agentName = matchingSession.agentName;
|
|
134
|
+
} else {
|
|
135
|
+
// No session found for this task ID; treat it as an agent name anyway
|
|
136
|
+
// (the event query will return empty results if no events match)
|
|
137
|
+
agentName = target;
|
|
138
|
+
}
|
|
139
|
+
} finally {
|
|
140
|
+
sessionStore.close();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Open event store and query events
|
|
145
|
+
const eventsDbPath = join(agentplateDir, "events.db");
|
|
146
|
+
const eventsFile = Bun.file(eventsDbPath);
|
|
147
|
+
if (!(await eventsFile.exists())) {
|
|
148
|
+
if (json) {
|
|
149
|
+
jsonOutput("trace", { events: [] });
|
|
150
|
+
} else {
|
|
151
|
+
process.stdout.write("No events data yet.\n");
|
|
152
|
+
}
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const eventStore = createEventStore(eventsDbPath);
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
const events = eventStore.getByAgent(agentName, {
|
|
160
|
+
since: sinceStr,
|
|
161
|
+
until: untilStr,
|
|
162
|
+
limit,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
if (json) {
|
|
166
|
+
jsonOutput("trace", { events });
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Use absolute time if --since is specified, relative otherwise
|
|
171
|
+
const useAbsoluteTime = sinceStr !== undefined;
|
|
172
|
+
printTimeline(events, agentName, useAbsoluteTime);
|
|
173
|
+
} finally {
|
|
174
|
+
eventStore.close();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function createTraceCommand(): Command {
|
|
179
|
+
return new Command("trace")
|
|
180
|
+
.description("Chronological event timeline for agent or task")
|
|
181
|
+
.argument("<target>", "Agent name or task ID")
|
|
182
|
+
.option("--json", "Output as JSON array of StoredEvent objects")
|
|
183
|
+
.option("--since <timestamp>", "Start time filter (ISO 8601)")
|
|
184
|
+
.option("--until <timestamp>", "End time filter (ISO 8601)")
|
|
185
|
+
.option("--limit <n>", "Max events to show (default: 100)")
|
|
186
|
+
.action(async (target: string, opts: TraceOpts) => {
|
|
187
|
+
await executeTrace(target, opts);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export async function traceCommand(args: string[]): Promise<void> {
|
|
192
|
+
const cmd = createTraceCommand();
|
|
193
|
+
cmd.exitOverride();
|
|
194
|
+
try {
|
|
195
|
+
await cmd.parseAsync(args, { from: "user" });
|
|
196
|
+
} catch (err: unknown) {
|
|
197
|
+
if (err && typeof err === "object" && "code" in err) {
|
|
198
|
+
const code = (err as { code: string }).code;
|
|
199
|
+
if (code === "commander.helpDisplayed" || code === "commander.version") {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
throw err;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { readdir } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { cleanupTempDir, createTempGitRepo } from "../test-helpers.ts";
|
|
5
|
+
import type { Spawner } from "./init.ts";
|
|
6
|
+
import {
|
|
7
|
+
AGENTPLATE_GITIGNORE,
|
|
8
|
+
AGENTPLATE_README,
|
|
9
|
+
buildAgentManifest,
|
|
10
|
+
buildHooksJson,
|
|
11
|
+
initCommand,
|
|
12
|
+
} from "./init.ts";
|
|
13
|
+
import { executeUpdate } from "./update.ts";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Tests for `ap update` — refresh .agentplate/ managed files.
|
|
17
|
+
*
|
|
18
|
+
* Uses real temp git repos. Suppresses stdout to keep test output clean.
|
|
19
|
+
* Requires a pre-initialized .agentplate/ directory (via initCommand).
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** No-op spawner that treats all ecosystem tools as "not installed". */
|
|
23
|
+
const noopSpawner: Spawner = async () => ({ exitCode: 1, stdout: "", stderr: "not found" });
|
|
24
|
+
|
|
25
|
+
const AGENT_DEF_FILES = [
|
|
26
|
+
"ap-co-creation.md",
|
|
27
|
+
"builder.md",
|
|
28
|
+
"coordinator.md",
|
|
29
|
+
"lead.md",
|
|
30
|
+
"merger.md",
|
|
31
|
+
"monitor.md",
|
|
32
|
+
"orchestrator.md",
|
|
33
|
+
"reviewer.md",
|
|
34
|
+
"scout.md",
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
/** Resolve the source agents directory (same logic as init.ts). */
|
|
38
|
+
const SOURCE_AGENTS_DIR = join(import.meta.dir, "..", "..", "agents");
|
|
39
|
+
|
|
40
|
+
describe("executeUpdate: not initialized", () => {
|
|
41
|
+
let tempDir: string;
|
|
42
|
+
let originalCwd: string;
|
|
43
|
+
let originalWrite: typeof process.stdout.write;
|
|
44
|
+
|
|
45
|
+
beforeEach(async () => {
|
|
46
|
+
tempDir = await createTempGitRepo();
|
|
47
|
+
originalCwd = process.cwd();
|
|
48
|
+
process.chdir(tempDir);
|
|
49
|
+
|
|
50
|
+
originalWrite = process.stdout.write;
|
|
51
|
+
process.stdout.write = (() => true) as typeof process.stdout.write;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
afterEach(async () => {
|
|
55
|
+
process.chdir(originalCwd);
|
|
56
|
+
process.stdout.write = originalWrite;
|
|
57
|
+
await cleanupTempDir(tempDir);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("errors when .agentplate/config.yaml does not exist", async () => {
|
|
61
|
+
await expect(executeUpdate({})).rejects.toThrow("Not initialized");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("error message hints to run ap init", async () => {
|
|
65
|
+
try {
|
|
66
|
+
await executeUpdate({});
|
|
67
|
+
expect.unreachable("Should have thrown");
|
|
68
|
+
} catch (err) {
|
|
69
|
+
expect((err as Error).message).toContain("ap init");
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("executeUpdate: refresh all (no flags)", () => {
|
|
75
|
+
let tempDir: string;
|
|
76
|
+
let originalCwd: string;
|
|
77
|
+
let originalWrite: typeof process.stdout.write;
|
|
78
|
+
|
|
79
|
+
beforeEach(async () => {
|
|
80
|
+
tempDir = await createTempGitRepo();
|
|
81
|
+
originalCwd = process.cwd();
|
|
82
|
+
process.chdir(tempDir);
|
|
83
|
+
|
|
84
|
+
originalWrite = process.stdout.write;
|
|
85
|
+
process.stdout.write = (() => true) as typeof process.stdout.write;
|
|
86
|
+
|
|
87
|
+
// Initialize .agentplate/
|
|
88
|
+
await initCommand({ _spawner: noopSpawner });
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
afterEach(async () => {
|
|
92
|
+
process.chdir(originalCwd);
|
|
93
|
+
process.stdout.write = originalWrite;
|
|
94
|
+
await cleanupTempDir(tempDir);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("refreshes all managed files when no flags given", async () => {
|
|
98
|
+
// Tamper with agent defs
|
|
99
|
+
const scoutPath = join(tempDir, ".agentplate", "agent-defs", "scout.md");
|
|
100
|
+
await Bun.write(scoutPath, "# tampered\n");
|
|
101
|
+
|
|
102
|
+
// Tamper with manifest
|
|
103
|
+
await Bun.write(join(tempDir, ".agentplate", "agent-manifest.json"), "{}");
|
|
104
|
+
|
|
105
|
+
// Tamper with hooks
|
|
106
|
+
await Bun.write(join(tempDir, ".agentplate", "hooks.json"), "{}");
|
|
107
|
+
|
|
108
|
+
// Tamper with gitignore
|
|
109
|
+
await Bun.write(join(tempDir, ".agentplate", ".gitignore"), "# old\n");
|
|
110
|
+
|
|
111
|
+
// Tamper with readme
|
|
112
|
+
await Bun.write(join(tempDir, ".agentplate", "README.md"), "# old\n");
|
|
113
|
+
|
|
114
|
+
await executeUpdate({});
|
|
115
|
+
|
|
116
|
+
// Verify all files restored
|
|
117
|
+
const scoutContent = await Bun.file(scoutPath).text();
|
|
118
|
+
const sourceScout = await Bun.file(join(SOURCE_AGENTS_DIR, "scout.md")).text();
|
|
119
|
+
expect(scoutContent).toBe(sourceScout);
|
|
120
|
+
|
|
121
|
+
const manifestContent = await Bun.file(
|
|
122
|
+
join(tempDir, ".agentplate", "agent-manifest.json"),
|
|
123
|
+
).text();
|
|
124
|
+
const expectedManifest = `${JSON.stringify(buildAgentManifest(), null, "\t")}\n`;
|
|
125
|
+
expect(manifestContent).toBe(expectedManifest);
|
|
126
|
+
|
|
127
|
+
const hooksContent = await Bun.file(join(tempDir, ".agentplate", "hooks.json")).text();
|
|
128
|
+
expect(hooksContent).toBe(buildHooksJson());
|
|
129
|
+
|
|
130
|
+
const gitignoreContent = await Bun.file(join(tempDir, ".agentplate", ".gitignore")).text();
|
|
131
|
+
expect(gitignoreContent).toBe(AGENTPLATE_GITIGNORE);
|
|
132
|
+
|
|
133
|
+
const readmeContent = await Bun.file(join(tempDir, ".agentplate", "README.md")).text();
|
|
134
|
+
expect(readmeContent).toBe(AGENTPLATE_README);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("does not touch config.yaml", async () => {
|
|
138
|
+
const configPath = join(tempDir, ".agentplate", "config.yaml");
|
|
139
|
+
const originalConfig = await Bun.file(configPath).text();
|
|
140
|
+
|
|
141
|
+
await executeUpdate({});
|
|
142
|
+
|
|
143
|
+
const afterUpdate = await Bun.file(configPath).text();
|
|
144
|
+
expect(afterUpdate).toBe(originalConfig);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("does not touch databases", async () => {
|
|
148
|
+
// Create fake database files
|
|
149
|
+
const mailDbPath = join(tempDir, ".agentplate", "mail.db");
|
|
150
|
+
const sessionsDbPath = join(tempDir, ".agentplate", "sessions.db");
|
|
151
|
+
await Bun.write(mailDbPath, "fake-mail-db");
|
|
152
|
+
await Bun.write(sessionsDbPath, "fake-sessions-db");
|
|
153
|
+
|
|
154
|
+
await executeUpdate({});
|
|
155
|
+
|
|
156
|
+
const mailDb = await Bun.file(mailDbPath).text();
|
|
157
|
+
expect(mailDb).toBe("fake-mail-db");
|
|
158
|
+
|
|
159
|
+
const sessionsDb = await Bun.file(sessionsDbPath).text();
|
|
160
|
+
expect(sessionsDb).toBe("fake-sessions-db");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("handles already-up-to-date files gracefully (idempotent)", async () => {
|
|
164
|
+
// Run update twice — second should report nothing changed
|
|
165
|
+
await executeUpdate({});
|
|
166
|
+
|
|
167
|
+
// Capture JSON output of second run
|
|
168
|
+
let captured = "";
|
|
169
|
+
const restoreWrite = process.stdout.write;
|
|
170
|
+
process.stdout.write = ((chunk: unknown) => {
|
|
171
|
+
captured += String(chunk);
|
|
172
|
+
return true;
|
|
173
|
+
}) as typeof process.stdout.write;
|
|
174
|
+
|
|
175
|
+
await executeUpdate({ json: true });
|
|
176
|
+
|
|
177
|
+
process.stdout.write = restoreWrite;
|
|
178
|
+
|
|
179
|
+
const parsed = JSON.parse(captured.trim()) as Record<string, unknown>;
|
|
180
|
+
expect(parsed.success).toBe(true);
|
|
181
|
+
|
|
182
|
+
const agentDefs = parsed.agentDefs as { updated: string[]; unchanged: string[] };
|
|
183
|
+
expect(agentDefs.updated).toHaveLength(0);
|
|
184
|
+
expect(agentDefs.unchanged.length).toBeGreaterThan(0);
|
|
185
|
+
|
|
186
|
+
expect(parsed.manifest).toEqual({ updated: false });
|
|
187
|
+
expect(parsed.hooks).toEqual({ updated: false });
|
|
188
|
+
expect(parsed.gitignore).toEqual({ updated: false });
|
|
189
|
+
expect(parsed.readme).toEqual({ updated: false });
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe("executeUpdate: granular flags", () => {
|
|
194
|
+
let tempDir: string;
|
|
195
|
+
let originalCwd: string;
|
|
196
|
+
let originalWrite: typeof process.stdout.write;
|
|
197
|
+
|
|
198
|
+
beforeEach(async () => {
|
|
199
|
+
tempDir = await createTempGitRepo();
|
|
200
|
+
originalCwd = process.cwd();
|
|
201
|
+
process.chdir(tempDir);
|
|
202
|
+
|
|
203
|
+
originalWrite = process.stdout.write;
|
|
204
|
+
process.stdout.write = (() => true) as typeof process.stdout.write;
|
|
205
|
+
|
|
206
|
+
await initCommand({ _spawner: noopSpawner });
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
afterEach(async () => {
|
|
210
|
+
process.chdir(originalCwd);
|
|
211
|
+
process.stdout.write = originalWrite;
|
|
212
|
+
await cleanupTempDir(tempDir);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test("--agents only refreshes agent-defs", async () => {
|
|
216
|
+
// Tamper with agent def and manifest
|
|
217
|
+
await Bun.write(join(tempDir, ".agentplate", "agent-defs", "scout.md"), "# tampered\n");
|
|
218
|
+
await Bun.write(join(tempDir, ".agentplate", "agent-manifest.json"), "{}");
|
|
219
|
+
await Bun.write(join(tempDir, ".agentplate", "hooks.json"), "{}");
|
|
220
|
+
|
|
221
|
+
await executeUpdate({ agents: true });
|
|
222
|
+
|
|
223
|
+
// Agent def should be restored
|
|
224
|
+
const scoutContent = await Bun.file(
|
|
225
|
+
join(tempDir, ".agentplate", "agent-defs", "scout.md"),
|
|
226
|
+
).text();
|
|
227
|
+
const sourceScout = await Bun.file(join(SOURCE_AGENTS_DIR, "scout.md")).text();
|
|
228
|
+
expect(scoutContent).toBe(sourceScout);
|
|
229
|
+
|
|
230
|
+
// Manifest should NOT be restored (--agents only)
|
|
231
|
+
const manifestContent = await Bun.file(
|
|
232
|
+
join(tempDir, ".agentplate", "agent-manifest.json"),
|
|
233
|
+
).text();
|
|
234
|
+
expect(manifestContent).toBe("{}");
|
|
235
|
+
|
|
236
|
+
// Hooks should NOT be restored (--agents only)
|
|
237
|
+
const hooksContent = await Bun.file(join(tempDir, ".agentplate", "hooks.json")).text();
|
|
238
|
+
expect(hooksContent).toBe("{}");
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("--manifest only refreshes agent-manifest.json", async () => {
|
|
242
|
+
await Bun.write(join(tempDir, ".agentplate", "agent-manifest.json"), "{}");
|
|
243
|
+
await Bun.write(join(tempDir, ".agentplate", "agent-defs", "scout.md"), "# tampered\n");
|
|
244
|
+
|
|
245
|
+
await executeUpdate({ manifest: true });
|
|
246
|
+
|
|
247
|
+
// Manifest should be restored
|
|
248
|
+
const manifestContent = await Bun.file(
|
|
249
|
+
join(tempDir, ".agentplate", "agent-manifest.json"),
|
|
250
|
+
).text();
|
|
251
|
+
const expectedManifest = `${JSON.stringify(buildAgentManifest(), null, "\t")}\n`;
|
|
252
|
+
expect(manifestContent).toBe(expectedManifest);
|
|
253
|
+
|
|
254
|
+
// Agent def should NOT be restored
|
|
255
|
+
const scoutContent = await Bun.file(
|
|
256
|
+
join(tempDir, ".agentplate", "agent-defs", "scout.md"),
|
|
257
|
+
).text();
|
|
258
|
+
expect(scoutContent).toBe("# tampered\n");
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("--hooks only refreshes hooks.json", async () => {
|
|
262
|
+
await Bun.write(join(tempDir, ".agentplate", "hooks.json"), "{}");
|
|
263
|
+
await Bun.write(join(tempDir, ".agentplate", "agent-manifest.json"), "{}");
|
|
264
|
+
|
|
265
|
+
await executeUpdate({ hooks: true });
|
|
266
|
+
|
|
267
|
+
// Hooks should be restored
|
|
268
|
+
const hooksContent = await Bun.file(join(tempDir, ".agentplate", "hooks.json")).text();
|
|
269
|
+
expect(hooksContent).toBe(buildHooksJson());
|
|
270
|
+
|
|
271
|
+
// Manifest should NOT be restored
|
|
272
|
+
const manifestContent = await Bun.file(
|
|
273
|
+
join(tempDir, ".agentplate", "agent-manifest.json"),
|
|
274
|
+
).text();
|
|
275
|
+
expect(manifestContent).toBe("{}");
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
test("granular flags do not refresh gitignore or readme", async () => {
|
|
279
|
+
await Bun.write(join(tempDir, ".agentplate", ".gitignore"), "# old\n");
|
|
280
|
+
await Bun.write(join(tempDir, ".agentplate", "README.md"), "# old\n");
|
|
281
|
+
|
|
282
|
+
await executeUpdate({ agents: true });
|
|
283
|
+
|
|
284
|
+
const gitignoreContent = await Bun.file(join(tempDir, ".agentplate", ".gitignore")).text();
|
|
285
|
+
expect(gitignoreContent).toBe("# old\n");
|
|
286
|
+
|
|
287
|
+
const readmeContent = await Bun.file(join(tempDir, ".agentplate", "README.md")).text();
|
|
288
|
+
expect(readmeContent).toBe("# old\n");
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
describe("executeUpdate: --dry-run", () => {
|
|
293
|
+
let tempDir: string;
|
|
294
|
+
let originalCwd: string;
|
|
295
|
+
let originalWrite: typeof process.stdout.write;
|
|
296
|
+
|
|
297
|
+
beforeEach(async () => {
|
|
298
|
+
tempDir = await createTempGitRepo();
|
|
299
|
+
originalCwd = process.cwd();
|
|
300
|
+
process.chdir(tempDir);
|
|
301
|
+
|
|
302
|
+
originalWrite = process.stdout.write;
|
|
303
|
+
process.stdout.write = (() => true) as typeof process.stdout.write;
|
|
304
|
+
|
|
305
|
+
await initCommand({ _spawner: noopSpawner });
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
afterEach(async () => {
|
|
309
|
+
process.chdir(originalCwd);
|
|
310
|
+
process.stdout.write = originalWrite;
|
|
311
|
+
await cleanupTempDir(tempDir);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
test("reports changes without writing files", async () => {
|
|
315
|
+
// Tamper with files
|
|
316
|
+
await Bun.write(join(tempDir, ".agentplate", "agent-defs", "scout.md"), "# tampered\n");
|
|
317
|
+
await Bun.write(join(tempDir, ".agentplate", "agent-manifest.json"), "{}");
|
|
318
|
+
|
|
319
|
+
let captured = "";
|
|
320
|
+
const restoreWrite = process.stdout.write;
|
|
321
|
+
process.stdout.write = ((chunk: unknown) => {
|
|
322
|
+
captured += String(chunk);
|
|
323
|
+
return true;
|
|
324
|
+
}) as typeof process.stdout.write;
|
|
325
|
+
|
|
326
|
+
await executeUpdate({ dryRun: true, json: true });
|
|
327
|
+
|
|
328
|
+
process.stdout.write = restoreWrite;
|
|
329
|
+
|
|
330
|
+
const parsed = JSON.parse(captured.trim()) as Record<string, unknown>;
|
|
331
|
+
expect(parsed.success).toBe(true);
|
|
332
|
+
expect(parsed.dryRun).toBe(true);
|
|
333
|
+
|
|
334
|
+
const agentDefs = parsed.agentDefs as { updated: string[]; unchanged: string[] };
|
|
335
|
+
expect(agentDefs.updated).toContain("scout.md");
|
|
336
|
+
|
|
337
|
+
expect(parsed.manifest).toEqual({ updated: true });
|
|
338
|
+
|
|
339
|
+
// Verify files were NOT actually modified
|
|
340
|
+
const scoutContent = await Bun.file(
|
|
341
|
+
join(tempDir, ".agentplate", "agent-defs", "scout.md"),
|
|
342
|
+
).text();
|
|
343
|
+
expect(scoutContent).toBe("# tampered\n");
|
|
344
|
+
|
|
345
|
+
const manifestContent = await Bun.file(
|
|
346
|
+
join(tempDir, ".agentplate", "agent-manifest.json"),
|
|
347
|
+
).text();
|
|
348
|
+
expect(manifestContent).toBe("{}");
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
describe("executeUpdate: --json output", () => {
|
|
353
|
+
let tempDir: string;
|
|
354
|
+
let originalCwd: string;
|
|
355
|
+
let originalWrite: typeof process.stdout.write;
|
|
356
|
+
|
|
357
|
+
beforeEach(async () => {
|
|
358
|
+
tempDir = await createTempGitRepo();
|
|
359
|
+
originalCwd = process.cwd();
|
|
360
|
+
process.chdir(tempDir);
|
|
361
|
+
|
|
362
|
+
originalWrite = process.stdout.write;
|
|
363
|
+
process.stdout.write = (() => true) as typeof process.stdout.write;
|
|
364
|
+
|
|
365
|
+
await initCommand({ _spawner: noopSpawner });
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
afterEach(async () => {
|
|
369
|
+
process.chdir(originalCwd);
|
|
370
|
+
process.stdout.write = originalWrite;
|
|
371
|
+
await cleanupTempDir(tempDir);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
test("outputs correct JSON envelope", async () => {
|
|
375
|
+
let captured = "";
|
|
376
|
+
const restoreWrite = process.stdout.write;
|
|
377
|
+
process.stdout.write = ((chunk: unknown) => {
|
|
378
|
+
captured += String(chunk);
|
|
379
|
+
return true;
|
|
380
|
+
}) as typeof process.stdout.write;
|
|
381
|
+
|
|
382
|
+
await executeUpdate({ json: true });
|
|
383
|
+
|
|
384
|
+
process.stdout.write = restoreWrite;
|
|
385
|
+
|
|
386
|
+
const parsed = JSON.parse(captured.trim()) as Record<string, unknown>;
|
|
387
|
+
expect(parsed.success).toBe(true);
|
|
388
|
+
expect(parsed.command).toBe("update");
|
|
389
|
+
expect(parsed.dryRun).toBe(false);
|
|
390
|
+
expect(parsed.agentDefs).toBeDefined();
|
|
391
|
+
expect(parsed.manifest).toBeDefined();
|
|
392
|
+
expect(parsed.hooks).toBeDefined();
|
|
393
|
+
expect(parsed.gitignore).toBeDefined();
|
|
394
|
+
expect(parsed.readme).toBeDefined();
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
test("JSON envelope includes updated file lists", async () => {
|
|
398
|
+
// Tamper with scout
|
|
399
|
+
await Bun.write(join(tempDir, ".agentplate", "agent-defs", "scout.md"), "# tampered\n");
|
|
400
|
+
|
|
401
|
+
let captured = "";
|
|
402
|
+
const restoreWrite = process.stdout.write;
|
|
403
|
+
process.stdout.write = ((chunk: unknown) => {
|
|
404
|
+
captured += String(chunk);
|
|
405
|
+
return true;
|
|
406
|
+
}) as typeof process.stdout.write;
|
|
407
|
+
|
|
408
|
+
await executeUpdate({ json: true });
|
|
409
|
+
|
|
410
|
+
process.stdout.write = restoreWrite;
|
|
411
|
+
|
|
412
|
+
const parsed = JSON.parse(captured.trim()) as Record<string, unknown>;
|
|
413
|
+
const agentDefs = parsed.agentDefs as { updated: string[]; unchanged: string[] };
|
|
414
|
+
expect(agentDefs.updated).toContain("scout.md");
|
|
415
|
+
expect(agentDefs.unchanged.length).toBeGreaterThan(0);
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
describe("executeUpdate: agent def exclusions", () => {
|
|
420
|
+
let tempDir: string;
|
|
421
|
+
let originalCwd: string;
|
|
422
|
+
let originalWrite: typeof process.stdout.write;
|
|
423
|
+
|
|
424
|
+
beforeEach(async () => {
|
|
425
|
+
tempDir = await createTempGitRepo();
|
|
426
|
+
originalCwd = process.cwd();
|
|
427
|
+
process.chdir(tempDir);
|
|
428
|
+
|
|
429
|
+
originalWrite = process.stdout.write;
|
|
430
|
+
process.stdout.write = (() => true) as typeof process.stdout.write;
|
|
431
|
+
|
|
432
|
+
await initCommand({ _spawner: noopSpawner });
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
afterEach(async () => {
|
|
436
|
+
process.chdir(originalCwd);
|
|
437
|
+
process.stdout.write = originalWrite;
|
|
438
|
+
await cleanupTempDir(tempDir);
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
test("does not deploy supervisor.md (deprecated)", async () => {
|
|
442
|
+
await executeUpdate({ agents: true });
|
|
443
|
+
|
|
444
|
+
const agentDefsDir = join(tempDir, ".agentplate", "agent-defs");
|
|
445
|
+
const files = await readdir(agentDefsDir);
|
|
446
|
+
expect(files).not.toContain("supervisor.md");
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
test("deploys all non-deprecated agent defs", async () => {
|
|
450
|
+
// Delete all agent defs first
|
|
451
|
+
for (const f of AGENT_DEF_FILES) {
|
|
452
|
+
try {
|
|
453
|
+
const { unlink } = await import("node:fs/promises");
|
|
454
|
+
await unlink(join(tempDir, ".agentplate", "agent-defs", f));
|
|
455
|
+
} catch {
|
|
456
|
+
// May not exist
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
await executeUpdate({ agents: true });
|
|
461
|
+
|
|
462
|
+
const agentDefsDir = join(tempDir, ".agentplate", "agent-defs");
|
|
463
|
+
const files = (await readdir(agentDefsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
464
|
+
expect(files).toEqual(AGENT_DEF_FILES);
|
|
465
|
+
});
|
|
466
|
+
});
|