@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,458 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for agentplate hooks install/uninstall/status command.
|
|
3
|
+
*
|
|
4
|
+
* Uses real temp directories and real filesystem (no mocks needed).
|
|
5
|
+
* Each test gets an isolated temp directory with minimal .agentplate/
|
|
6
|
+
* and .claude/ scaffolding.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
10
|
+
import { mkdir, realpath } from "node:fs/promises";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { ValidationError } from "../errors.ts";
|
|
13
|
+
import { cleanupTempDir, createTempGitRepo } from "../test-helpers.ts";
|
|
14
|
+
import { hooksCommand, mergeHooksByEventType } from "./hooks.ts";
|
|
15
|
+
|
|
16
|
+
let tempDir: string;
|
|
17
|
+
const originalCwd = process.cwd();
|
|
18
|
+
|
|
19
|
+
/** Orchestrator hooks content for .agentplate/hooks.json. */
|
|
20
|
+
const SAMPLE_HOOKS = {
|
|
21
|
+
hooks: {
|
|
22
|
+
SessionStart: [
|
|
23
|
+
{
|
|
24
|
+
matcher: "",
|
|
25
|
+
hooks: [{ type: "command", command: "ap prime --agent orchestrator" }],
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
Stop: [
|
|
29
|
+
{
|
|
30
|
+
matcher: "",
|
|
31
|
+
hooks: [{ type: "command", command: "ap log session-end --agent orchestrator" }],
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** Capture stdout.write output during a function call. */
|
|
38
|
+
async function captureStdout(fn: () => Promise<void>): Promise<string> {
|
|
39
|
+
const chunks: string[] = [];
|
|
40
|
+
const originalWrite = process.stdout.write;
|
|
41
|
+
process.stdout.write = ((chunk: string) => {
|
|
42
|
+
chunks.push(chunk);
|
|
43
|
+
return true;
|
|
44
|
+
}) as typeof process.stdout.write;
|
|
45
|
+
try {
|
|
46
|
+
await fn();
|
|
47
|
+
} finally {
|
|
48
|
+
process.stdout.write = originalWrite;
|
|
49
|
+
}
|
|
50
|
+
return chunks.join("");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
beforeEach(async () => {
|
|
54
|
+
process.chdir(originalCwd);
|
|
55
|
+
tempDir = await realpath(await createTempGitRepo());
|
|
56
|
+
|
|
57
|
+
// Create minimal .agentplate/ with config.yaml
|
|
58
|
+
const agentplateDir = join(tempDir, ".agentplate");
|
|
59
|
+
await mkdir(agentplateDir, { recursive: true });
|
|
60
|
+
await Bun.write(
|
|
61
|
+
join(agentplateDir, "config.yaml"),
|
|
62
|
+
["project:", " name: test-project", ` root: ${tempDir}`, " canonicalBranch: main"].join(
|
|
63
|
+
"\n",
|
|
64
|
+
),
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
process.chdir(tempDir);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
afterEach(async () => {
|
|
71
|
+
process.chdir(originalCwd);
|
|
72
|
+
await cleanupTempDir(tempDir);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("hooksCommand help", () => {
|
|
76
|
+
test("--help outputs help text", async () => {
|
|
77
|
+
const output = await captureStdout(() => hooksCommand(["--help"]));
|
|
78
|
+
expect(output).toContain("hooks");
|
|
79
|
+
expect(output).toContain("install");
|
|
80
|
+
expect(output).toContain("uninstall");
|
|
81
|
+
expect(output).toContain("status");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("empty args outputs help text", async () => {
|
|
85
|
+
const output = await captureStdout(() => hooksCommand([]));
|
|
86
|
+
expect(output).toContain("hooks");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("unknown subcommand throws ValidationError", async () => {
|
|
90
|
+
await expect(hooksCommand(["frobnicate"])).rejects.toThrow(ValidationError);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("hooks install", () => {
|
|
95
|
+
test("installs hooks from .agentplate/hooks.json to .claude/settings.local.json", async () => {
|
|
96
|
+
// Write source hooks
|
|
97
|
+
await Bun.write(
|
|
98
|
+
join(tempDir, ".agentplate", "hooks.json"),
|
|
99
|
+
`${JSON.stringify(SAMPLE_HOOKS, null, "\t")}\n`,
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
await captureStdout(() => hooksCommand(["install"]));
|
|
103
|
+
|
|
104
|
+
// Verify target file was created
|
|
105
|
+
const targetPath = join(tempDir, ".claude", "settings.local.json");
|
|
106
|
+
const content = await Bun.file(targetPath).text();
|
|
107
|
+
const parsed = JSON.parse(content) as Record<string, unknown>;
|
|
108
|
+
expect(parsed.hooks).toBeDefined();
|
|
109
|
+
expect(content).toContain("ap prime");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("preserves existing non-hooks keys in settings.local.json", async () => {
|
|
113
|
+
await Bun.write(
|
|
114
|
+
join(tempDir, ".agentplate", "hooks.json"),
|
|
115
|
+
`${JSON.stringify(SAMPLE_HOOKS, null, "\t")}\n`,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
// Write existing settings.local.json with non-hooks content
|
|
119
|
+
const claudeDir = join(tempDir, ".claude");
|
|
120
|
+
await mkdir(claudeDir, { recursive: true });
|
|
121
|
+
await Bun.write(
|
|
122
|
+
join(claudeDir, "settings.local.json"),
|
|
123
|
+
`${JSON.stringify({ env: { SOME_VAR: "1" } }, null, "\t")}\n`,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
await captureStdout(() => hooksCommand(["install"]));
|
|
127
|
+
|
|
128
|
+
const content = await Bun.file(join(claudeDir, "settings.local.json")).text();
|
|
129
|
+
const parsed = JSON.parse(content) as Record<string, unknown>;
|
|
130
|
+
expect(parsed.hooks).toBeDefined();
|
|
131
|
+
expect(parsed.env).toEqual({ SOME_VAR: "1" });
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("warns when hooks already exist without --force", async () => {
|
|
135
|
+
await Bun.write(
|
|
136
|
+
join(tempDir, ".agentplate", "hooks.json"),
|
|
137
|
+
`${JSON.stringify(SAMPLE_HOOKS, null, "\t")}\n`,
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const claudeDir = join(tempDir, ".claude");
|
|
141
|
+
await mkdir(claudeDir, { recursive: true });
|
|
142
|
+
await Bun.write(
|
|
143
|
+
join(claudeDir, "settings.local.json"),
|
|
144
|
+
`${JSON.stringify({ hooks: { old: "hooks" } }, null, "\t")}\n`,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const output = await captureStdout(() => hooksCommand(["install"]));
|
|
148
|
+
expect(output).toContain("already present");
|
|
149
|
+
expect(output).toContain("--force");
|
|
150
|
+
|
|
151
|
+
// Verify hooks were NOT overwritten
|
|
152
|
+
const content = await Bun.file(join(claudeDir, "settings.local.json")).text();
|
|
153
|
+
expect(content).toContain("old");
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("--force merges existing hooks (not overwrites)", async () => {
|
|
157
|
+
await Bun.write(
|
|
158
|
+
join(tempDir, ".agentplate", "hooks.json"),
|
|
159
|
+
`${JSON.stringify(SAMPLE_HOOKS, null, "\t")}\n`,
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
const claudeDir = join(tempDir, ".claude");
|
|
163
|
+
await mkdir(claudeDir, { recursive: true });
|
|
164
|
+
const existingSettings = {
|
|
165
|
+
hooks: {
|
|
166
|
+
UserInput: [
|
|
167
|
+
{
|
|
168
|
+
matcher: "",
|
|
169
|
+
hooks: [{ type: "command", command: "echo user-hook" }],
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
await Bun.write(
|
|
175
|
+
join(claudeDir, "settings.local.json"),
|
|
176
|
+
`${JSON.stringify(existingSettings, null, "\t")}\n`,
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
await captureStdout(() => hooksCommand(["install", "--force"]));
|
|
180
|
+
|
|
181
|
+
const content = await Bun.file(join(claudeDir, "settings.local.json")).text();
|
|
182
|
+
// Existing user hook is preserved
|
|
183
|
+
expect(content).toContain("user-hook");
|
|
184
|
+
// Agentplate hooks are added
|
|
185
|
+
expect(content).toContain("ap prime");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("throws when .agentplate/hooks.json does not exist", async () => {
|
|
189
|
+
await expect(hooksCommand(["install"])).rejects.toThrow(ValidationError);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test("writes JSON with trailing newline", async () => {
|
|
193
|
+
await Bun.write(
|
|
194
|
+
join(tempDir, ".agentplate", "hooks.json"),
|
|
195
|
+
`${JSON.stringify(SAMPLE_HOOKS, null, "\t")}\n`,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
await captureStdout(() => hooksCommand(["install"]));
|
|
199
|
+
|
|
200
|
+
const content = await Bun.file(join(tempDir, ".claude", "settings.local.json")).text();
|
|
201
|
+
expect(content.endsWith("\n")).toBe(true);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe("hooks uninstall", () => {
|
|
206
|
+
test("removes hooks-only settings.local.json file entirely", async () => {
|
|
207
|
+
const claudeDir = join(tempDir, ".claude");
|
|
208
|
+
await mkdir(claudeDir, { recursive: true });
|
|
209
|
+
await Bun.write(
|
|
210
|
+
join(claudeDir, "settings.local.json"),
|
|
211
|
+
`${JSON.stringify({ hooks: { some: "hooks" } }, null, "\t")}\n`,
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const output = await captureStdout(() => hooksCommand(["uninstall"]));
|
|
215
|
+
expect(output).toContain("Removed");
|
|
216
|
+
|
|
217
|
+
const exists = await Bun.file(join(claudeDir, "settings.local.json")).exists();
|
|
218
|
+
expect(exists).toBe(false);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test("preserves non-hooks keys when uninstalling", async () => {
|
|
222
|
+
const claudeDir = join(tempDir, ".claude");
|
|
223
|
+
await mkdir(claudeDir, { recursive: true });
|
|
224
|
+
await Bun.write(
|
|
225
|
+
join(claudeDir, "settings.local.json"),
|
|
226
|
+
`${JSON.stringify({ hooks: { some: "hooks" }, env: { KEY: "val" } }, null, "\t")}\n`,
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
const output = await captureStdout(() => hooksCommand(["uninstall"]));
|
|
230
|
+
expect(output).toContain("Removed");
|
|
231
|
+
|
|
232
|
+
const content = await Bun.file(join(claudeDir, "settings.local.json")).text();
|
|
233
|
+
const parsed = JSON.parse(content) as Record<string, unknown>;
|
|
234
|
+
expect(parsed.hooks).toBeUndefined();
|
|
235
|
+
expect(parsed.env).toEqual({ KEY: "val" });
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test("handles missing settings.local.json gracefully", async () => {
|
|
239
|
+
const output = await captureStdout(() => hooksCommand(["uninstall"]));
|
|
240
|
+
expect(output).toContain("nothing to uninstall");
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("handles settings.local.json with no hooks key", async () => {
|
|
244
|
+
const claudeDir = join(tempDir, ".claude");
|
|
245
|
+
await mkdir(claudeDir, { recursive: true });
|
|
246
|
+
await Bun.write(
|
|
247
|
+
join(claudeDir, "settings.local.json"),
|
|
248
|
+
`${JSON.stringify({ env: { KEY: "val" } }, null, "\t")}\n`,
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
const output = await captureStdout(() => hooksCommand(["uninstall"]));
|
|
252
|
+
expect(output).toContain("No hooks found");
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
describe("hooks install merge behavior", () => {
|
|
257
|
+
test("--force merges agentplate hooks into existing user hooks", async () => {
|
|
258
|
+
await Bun.write(
|
|
259
|
+
join(tempDir, ".agentplate", "hooks.json"),
|
|
260
|
+
`${JSON.stringify(SAMPLE_HOOKS, null, "\t")}\n`,
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
const claudeDir = join(tempDir, ".claude");
|
|
264
|
+
await mkdir(claudeDir, { recursive: true });
|
|
265
|
+
const existingSettings = {
|
|
266
|
+
hooks: {
|
|
267
|
+
PreToolUse: [
|
|
268
|
+
{
|
|
269
|
+
matcher: "Write",
|
|
270
|
+
hooks: [{ type: "command", command: "echo user-write-hook" }],
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
await Bun.write(
|
|
276
|
+
join(claudeDir, "settings.local.json"),
|
|
277
|
+
`${JSON.stringify(existingSettings, null, "\t")}\n`,
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
await captureStdout(() => hooksCommand(["install", "--force"]));
|
|
281
|
+
|
|
282
|
+
const content = await Bun.file(join(claudeDir, "settings.local.json")).text();
|
|
283
|
+
const parsed = JSON.parse(content) as { hooks: Record<string, unknown[]> };
|
|
284
|
+
// User's PreToolUse hook preserved
|
|
285
|
+
expect(content).toContain("user-write-hook");
|
|
286
|
+
// Agentplate's SessionStart hook added
|
|
287
|
+
expect(content).toContain("ap prime");
|
|
288
|
+
// Both event types present
|
|
289
|
+
expect(parsed.hooks.PreToolUse).toBeDefined();
|
|
290
|
+
expect(parsed.hooks.SessionStart).toBeDefined();
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
test("--force deduplicates identical entries", async () => {
|
|
294
|
+
await Bun.write(
|
|
295
|
+
join(tempDir, ".agentplate", "hooks.json"),
|
|
296
|
+
`${JSON.stringify(SAMPLE_HOOKS, null, "\t")}\n`,
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
const claudeDir = join(tempDir, ".claude");
|
|
300
|
+
await mkdir(claudeDir, { recursive: true });
|
|
301
|
+
|
|
302
|
+
// First install
|
|
303
|
+
await captureStdout(() => hooksCommand(["install"]));
|
|
304
|
+
|
|
305
|
+
// Second install with --force (same hooks again)
|
|
306
|
+
await captureStdout(() => hooksCommand(["install", "--force"]));
|
|
307
|
+
|
|
308
|
+
const content = await Bun.file(join(claudeDir, "settings.local.json")).text();
|
|
309
|
+
const parsed = JSON.parse(content) as { hooks: Record<string, unknown[]> };
|
|
310
|
+
|
|
311
|
+
// SessionStart should have exactly 1 entry (no duplicate)
|
|
312
|
+
expect(parsed.hooks.SessionStart?.length).toBe(1);
|
|
313
|
+
// Stop should have exactly 1 entry (no duplicate)
|
|
314
|
+
expect(parsed.hooks.Stop?.length).toBe(1);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test("--force preserves existing event types not in source", async () => {
|
|
318
|
+
await Bun.write(
|
|
319
|
+
join(tempDir, ".agentplate", "hooks.json"),
|
|
320
|
+
`${JSON.stringify(SAMPLE_HOOKS, null, "\t")}\n`,
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
const claudeDir = join(tempDir, ".claude");
|
|
324
|
+
await mkdir(claudeDir, { recursive: true });
|
|
325
|
+
const existingSettings = {
|
|
326
|
+
hooks: {
|
|
327
|
+
Notification: [
|
|
328
|
+
{
|
|
329
|
+
matcher: "",
|
|
330
|
+
hooks: [{ type: "command", command: "echo notification-hook" }],
|
|
331
|
+
},
|
|
332
|
+
],
|
|
333
|
+
},
|
|
334
|
+
};
|
|
335
|
+
await Bun.write(
|
|
336
|
+
join(claudeDir, "settings.local.json"),
|
|
337
|
+
`${JSON.stringify(existingSettings, null, "\t")}\n`,
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
await captureStdout(() => hooksCommand(["install", "--force"]));
|
|
341
|
+
|
|
342
|
+
const content = await Bun.file(join(claudeDir, "settings.local.json")).text();
|
|
343
|
+
const parsed = JSON.parse(content) as { hooks: Record<string, unknown[]> };
|
|
344
|
+
// Custom event type preserved
|
|
345
|
+
expect(parsed.hooks.Notification).toBeDefined();
|
|
346
|
+
expect(content).toContain("notification-hook");
|
|
347
|
+
// Agentplate hooks also present
|
|
348
|
+
expect(parsed.hooks.SessionStart).toBeDefined();
|
|
349
|
+
expect(parsed.hooks.Stop).toBeDefined();
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
test("first install without existing hooks works unchanged", async () => {
|
|
353
|
+
await Bun.write(
|
|
354
|
+
join(tempDir, ".agentplate", "hooks.json"),
|
|
355
|
+
`${JSON.stringify(SAMPLE_HOOKS, null, "\t")}\n`,
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
await captureStdout(() => hooksCommand(["install"]));
|
|
359
|
+
|
|
360
|
+
const content = await Bun.file(join(tempDir, ".claude", "settings.local.json")).text();
|
|
361
|
+
const parsed = JSON.parse(content) as { hooks: Record<string, unknown[]> };
|
|
362
|
+
expect(parsed.hooks.SessionStart).toBeDefined();
|
|
363
|
+
expect(parsed.hooks.Stop).toBeDefined();
|
|
364
|
+
expect(content).toContain("ap prime");
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
describe("mergeHooksByEventType unit tests", () => {
|
|
368
|
+
test("copies existing event types not in incoming", () => {
|
|
369
|
+
const existing = {
|
|
370
|
+
UserInput: [{ matcher: "", hooks: [{ type: "command", command: "echo a" }] }],
|
|
371
|
+
};
|
|
372
|
+
const incoming = {
|
|
373
|
+
SessionStart: [{ matcher: "", hooks: [{ type: "command", command: "echo b" }] }],
|
|
374
|
+
};
|
|
375
|
+
const result = mergeHooksByEventType(existing, incoming);
|
|
376
|
+
expect(result.UserInput).toBeDefined();
|
|
377
|
+
expect(result.SessionStart).toBeDefined();
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
test("appends non-duplicate incoming entries to existing event type", () => {
|
|
381
|
+
const existing = {
|
|
382
|
+
PreToolUse: [{ matcher: "Read", hooks: [{ type: "command", command: "echo read" }] }],
|
|
383
|
+
};
|
|
384
|
+
const incoming = {
|
|
385
|
+
PreToolUse: [{ matcher: "Write", hooks: [{ type: "command", command: "echo write" }] }],
|
|
386
|
+
};
|
|
387
|
+
const result = mergeHooksByEventType(existing, incoming);
|
|
388
|
+
expect(result.PreToolUse?.length).toBe(2);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
test("does not add duplicate entries (same matcher + same commands)", () => {
|
|
392
|
+
const entry = { matcher: "", hooks: [{ type: "command", command: "echo dupe" }] };
|
|
393
|
+
const existing = { PreToolUse: [entry] };
|
|
394
|
+
const incoming = { PreToolUse: [entry] };
|
|
395
|
+
const result = mergeHooksByEventType(existing, incoming);
|
|
396
|
+
expect(result.PreToolUse?.length).toBe(1);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
test("adds entry with same matcher but different commands", () => {
|
|
400
|
+
const existing = {
|
|
401
|
+
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: "echo a" }] }],
|
|
402
|
+
};
|
|
403
|
+
const incoming = {
|
|
404
|
+
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: "echo b" }] }],
|
|
405
|
+
};
|
|
406
|
+
const result = mergeHooksByEventType(existing, incoming);
|
|
407
|
+
expect(result.PreToolUse?.length).toBe(2);
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
describe("hooks status", () => {
|
|
413
|
+
test("reports source missing when .agentplate/hooks.json does not exist", async () => {
|
|
414
|
+
const output = await captureStdout(() => hooksCommand(["status"]));
|
|
415
|
+
expect(output).toContain("missing");
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
test("reports installed:false when no hooks in .claude/", async () => {
|
|
419
|
+
await Bun.write(
|
|
420
|
+
join(tempDir, ".agentplate", "hooks.json"),
|
|
421
|
+
`${JSON.stringify(SAMPLE_HOOKS, null, "\t")}\n`,
|
|
422
|
+
);
|
|
423
|
+
|
|
424
|
+
const output = await captureStdout(() => hooksCommand(["status"]));
|
|
425
|
+
expect(output).toContain("present");
|
|
426
|
+
expect(output).toContain("no");
|
|
427
|
+
expect(output).toContain("ap hooks install");
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
test("reports installed:true when hooks present in .claude/", async () => {
|
|
431
|
+
await Bun.write(
|
|
432
|
+
join(tempDir, ".agentplate", "hooks.json"),
|
|
433
|
+
`${JSON.stringify(SAMPLE_HOOKS, null, "\t")}\n`,
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
const claudeDir = join(tempDir, ".claude");
|
|
437
|
+
await mkdir(claudeDir, { recursive: true });
|
|
438
|
+
await Bun.write(
|
|
439
|
+
join(claudeDir, "settings.local.json"),
|
|
440
|
+
`${JSON.stringify({ hooks: {} }, null, "\t")}\n`,
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
const output = await captureStdout(() => hooksCommand(["status"]));
|
|
444
|
+
expect(output).toContain("yes");
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
test("--json outputs correct fields", async () => {
|
|
448
|
+
await Bun.write(
|
|
449
|
+
join(tempDir, ".agentplate", "hooks.json"),
|
|
450
|
+
`${JSON.stringify(SAMPLE_HOOKS, null, "\t")}\n`,
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
const output = await captureStdout(() => hooksCommand(["status", "--json"]));
|
|
454
|
+
const parsed = JSON.parse(output) as Record<string, unknown>;
|
|
455
|
+
expect(parsed.sourceExists).toBe(true);
|
|
456
|
+
expect(parsed.installed).toBe(false);
|
|
457
|
+
});
|
|
458
|
+
});
|