@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,399 @@
|
|
|
1
|
+
import { readdir, stat } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import type { AgentManifest } from "../types.ts";
|
|
4
|
+
import type { DoctorCheck, DoctorCheckFn } from "./types.ts";
|
|
5
|
+
|
|
6
|
+
const VALID_NAME_REGEX = /^[a-zA-Z0-9_-]+$/;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Check if a path exists.
|
|
10
|
+
*/
|
|
11
|
+
async function pathExists(path: string): Promise<boolean> {
|
|
12
|
+
try {
|
|
13
|
+
await stat(path);
|
|
14
|
+
return true;
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Parse and validate agent-manifest.json structure.
|
|
22
|
+
*/
|
|
23
|
+
async function loadAndValidateManifest(
|
|
24
|
+
agentplateDir: string,
|
|
25
|
+
): Promise<{ manifest: AgentManifest | null; errors: string[] }> {
|
|
26
|
+
const manifestPath = join(agentplateDir, "agent-manifest.json");
|
|
27
|
+
const errors: string[] = [];
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const content = await Bun.file(manifestPath).text();
|
|
31
|
+
const raw = JSON.parse(content) as {
|
|
32
|
+
version?: unknown;
|
|
33
|
+
agents?: unknown;
|
|
34
|
+
capabilityIndex?: unknown;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Validate top-level fields
|
|
38
|
+
if (typeof raw.version !== "string" || raw.version.length === 0) {
|
|
39
|
+
errors.push('Missing or empty "version" field');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (typeof raw.agents !== "object" || raw.agents === null) {
|
|
43
|
+
errors.push('"agents" must be an object');
|
|
44
|
+
return { manifest: null, errors };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (typeof raw.capabilityIndex !== "object" || raw.capabilityIndex === null) {
|
|
48
|
+
errors.push('"capabilityIndex" must be an object');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const agents = raw.agents as Record<string, unknown>;
|
|
52
|
+
|
|
53
|
+
// Validate each agent definition
|
|
54
|
+
for (const [name, def] of Object.entries(agents)) {
|
|
55
|
+
if (typeof def !== "object" || def === null) {
|
|
56
|
+
errors.push(`Agent "${name}": definition must be an object`);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const agentDef = def as Record<string, unknown>;
|
|
61
|
+
|
|
62
|
+
if (typeof agentDef.file !== "string" || agentDef.file.length === 0) {
|
|
63
|
+
errors.push(`Agent "${name}": "file" must be a non-empty string`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (typeof agentDef.model !== "string" || agentDef.model.length === 0) {
|
|
67
|
+
errors.push(`Agent "${name}": "model" must be a non-empty string`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!Array.isArray(agentDef.tools)) {
|
|
71
|
+
errors.push(`Agent "${name}": "tools" must be an array`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!Array.isArray(agentDef.capabilities)) {
|
|
75
|
+
errors.push(`Agent "${name}": "capabilities" must be an array`);
|
|
76
|
+
} else if (agentDef.capabilities.length === 0) {
|
|
77
|
+
errors.push(`Agent "${name}": must have at least one capability`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (typeof agentDef.canSpawn !== "boolean") {
|
|
81
|
+
errors.push(`Agent "${name}": "canSpawn" must be a boolean`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!Array.isArray(agentDef.constraints)) {
|
|
85
|
+
errors.push(`Agent "${name}": "constraints" must be an array`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Return manifest only if structure is valid
|
|
90
|
+
if (errors.length > 0) {
|
|
91
|
+
return { manifest: null, errors };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return { manifest: raw as AgentManifest, errors: [] };
|
|
95
|
+
} catch (error) {
|
|
96
|
+
if (error instanceof SyntaxError) {
|
|
97
|
+
errors.push("Invalid JSON syntax");
|
|
98
|
+
} else {
|
|
99
|
+
errors.push(error instanceof Error ? error.message : "Failed to read manifest");
|
|
100
|
+
}
|
|
101
|
+
return { manifest: null, errors };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Validate capability index bidirectional consistency.
|
|
107
|
+
*/
|
|
108
|
+
function validateCapabilityIndex(manifest: AgentManifest): string[] {
|
|
109
|
+
const errors: string[] = [];
|
|
110
|
+
|
|
111
|
+
// Build expected index from agent definitions
|
|
112
|
+
const expectedIndex: Record<string, string[]> = {};
|
|
113
|
+
for (const [name, def] of Object.entries(manifest.agents)) {
|
|
114
|
+
for (const cap of def.capabilities) {
|
|
115
|
+
const existing = expectedIndex[cap];
|
|
116
|
+
if (existing) {
|
|
117
|
+
existing.push(name);
|
|
118
|
+
} else {
|
|
119
|
+
expectedIndex[cap] = [name];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Check that declared index matches expected
|
|
125
|
+
for (const [cap, agentNames] of Object.entries(manifest.capabilityIndex)) {
|
|
126
|
+
const expected = expectedIndex[cap];
|
|
127
|
+
if (!expected) {
|
|
128
|
+
errors.push(`Capability "${cap}" in index but no agents declare it`);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const missing = expected.filter((name) => !agentNames.includes(name));
|
|
133
|
+
const extra = agentNames.filter((name) => !expected.includes(name));
|
|
134
|
+
|
|
135
|
+
if (missing.length > 0) {
|
|
136
|
+
errors.push(`Capability "${cap}": missing agents in index: ${missing.join(", ")}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (extra.length > 0) {
|
|
140
|
+
errors.push(`Capability "${cap}": extra agents in index: ${extra.join(", ")}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Check for missing capabilities in index
|
|
145
|
+
for (const [cap, agentNames] of Object.entries(expectedIndex)) {
|
|
146
|
+
if (!manifest.capabilityIndex[cap]) {
|
|
147
|
+
errors.push(
|
|
148
|
+
`Capability "${cap}" declared by ${agentNames.join(", ")} but missing from index`,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Check for capabilities with zero providers
|
|
154
|
+
for (const [cap, agentNames] of Object.entries(expectedIndex)) {
|
|
155
|
+
if (agentNames.length === 0) {
|
|
156
|
+
errors.push(`Capability "${cap}" has zero providers`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return errors;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Parse a simple YAML identity file.
|
|
165
|
+
*/
|
|
166
|
+
function parseIdentityYaml(text: string): {
|
|
167
|
+
name?: string;
|
|
168
|
+
capability?: string;
|
|
169
|
+
created?: string;
|
|
170
|
+
sessionsCompleted?: number;
|
|
171
|
+
} {
|
|
172
|
+
const lines = text.split("\n");
|
|
173
|
+
const identity: {
|
|
174
|
+
name?: string;
|
|
175
|
+
capability?: string;
|
|
176
|
+
created?: string;
|
|
177
|
+
sessionsCompleted?: number;
|
|
178
|
+
} = {};
|
|
179
|
+
|
|
180
|
+
for (const line of lines) {
|
|
181
|
+
const trimmed = line.trim();
|
|
182
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
183
|
+
|
|
184
|
+
const colonIndex = trimmed.indexOf(":");
|
|
185
|
+
if (colonIndex === -1) continue;
|
|
186
|
+
|
|
187
|
+
const key = trimmed.slice(0, colonIndex).trim();
|
|
188
|
+
let value = trimmed.slice(colonIndex + 1).trim();
|
|
189
|
+
|
|
190
|
+
// Remove quotes if present
|
|
191
|
+
if (
|
|
192
|
+
(value.startsWith('"') && value.endsWith('"')) ||
|
|
193
|
+
(value.startsWith("'") && value.endsWith("'"))
|
|
194
|
+
) {
|
|
195
|
+
value = value.slice(1, -1);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (key === "name") {
|
|
199
|
+
identity.name = value;
|
|
200
|
+
} else if (key === "capability") {
|
|
201
|
+
identity.capability = value;
|
|
202
|
+
} else if (key === "created") {
|
|
203
|
+
identity.created = value;
|
|
204
|
+
} else if (key === "sessionsCompleted") {
|
|
205
|
+
identity.sessionsCompleted = Number.parseInt(value, 10);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return identity;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Agent state checks.
|
|
214
|
+
* Validates agent definitions, tmux sessions, and agent identity files.
|
|
215
|
+
*/
|
|
216
|
+
export const checkAgents: DoctorCheckFn = async (
|
|
217
|
+
_config,
|
|
218
|
+
agentplateDir,
|
|
219
|
+
): Promise<DoctorCheck[]> => {
|
|
220
|
+
const checks: DoctorCheck[] = [];
|
|
221
|
+
|
|
222
|
+
// Check 1: Parse agent-manifest.json
|
|
223
|
+
const { manifest, errors: parseErrors } = await loadAndValidateManifest(agentplateDir);
|
|
224
|
+
|
|
225
|
+
if (parseErrors.length > 0) {
|
|
226
|
+
checks.push({
|
|
227
|
+
name: "Manifest parsing",
|
|
228
|
+
category: "agents",
|
|
229
|
+
status: "fail",
|
|
230
|
+
message: `Found ${parseErrors.length} error(s)`,
|
|
231
|
+
details: parseErrors,
|
|
232
|
+
fixable: false,
|
|
233
|
+
});
|
|
234
|
+
return checks; // Can't proceed without valid manifest
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
checks.push({
|
|
238
|
+
name: "Manifest parsing",
|
|
239
|
+
category: "agents",
|
|
240
|
+
status: "pass",
|
|
241
|
+
message: "JSON parses successfully",
|
|
242
|
+
fixable: false,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
if (!manifest) {
|
|
246
|
+
return checks;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Check 2: Validate referenced .md files exist
|
|
250
|
+
const agentDefsDir = join(agentplateDir, "agent-defs");
|
|
251
|
+
const missingFiles: string[] = [];
|
|
252
|
+
|
|
253
|
+
for (const [name, def] of Object.entries(manifest.agents)) {
|
|
254
|
+
const filePath = join(agentDefsDir, def.file);
|
|
255
|
+
const exists = await pathExists(filePath);
|
|
256
|
+
if (!exists) {
|
|
257
|
+
missingFiles.push(`${name}: ${def.file}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
checks.push({
|
|
262
|
+
name: "Agent definition files",
|
|
263
|
+
category: "agents",
|
|
264
|
+
status: missingFiles.length === 0 ? "pass" : "fail",
|
|
265
|
+
message:
|
|
266
|
+
missingFiles.length === 0 ? "All .md files found" : `Missing ${missingFiles.length} file(s)`,
|
|
267
|
+
details: missingFiles.length > 0 ? missingFiles : undefined,
|
|
268
|
+
fixable: missingFiles.length > 0,
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Check 3: Capability index consistency
|
|
272
|
+
const indexErrors = validateCapabilityIndex(manifest);
|
|
273
|
+
|
|
274
|
+
checks.push({
|
|
275
|
+
name: "Capability index",
|
|
276
|
+
category: "agents",
|
|
277
|
+
status: indexErrors.length === 0 ? "pass" : "warn",
|
|
278
|
+
message:
|
|
279
|
+
indexErrors.length === 0 ? "Index is consistent" : `Found ${indexErrors.length} issue(s)`,
|
|
280
|
+
details: indexErrors.length > 0 ? indexErrors : undefined,
|
|
281
|
+
fixable: indexErrors.length > 0,
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// Check 4: Validate identity files
|
|
285
|
+
const agentsDir = join(agentplateDir, "agents");
|
|
286
|
+
const agentsDirExists = await pathExists(agentsDir);
|
|
287
|
+
|
|
288
|
+
if (!agentsDirExists) {
|
|
289
|
+
checks.push({
|
|
290
|
+
name: "Agent identities",
|
|
291
|
+
category: "agents",
|
|
292
|
+
status: "pass",
|
|
293
|
+
message: "No agent identities yet (agents/ directory missing)",
|
|
294
|
+
fixable: false,
|
|
295
|
+
});
|
|
296
|
+
return checks;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
try {
|
|
300
|
+
const identityErrors: string[] = [];
|
|
301
|
+
const staleIdentities: string[] = [];
|
|
302
|
+
const agentDirs = await readdir(agentsDir, { withFileTypes: true });
|
|
303
|
+
let identityFileCount = 0;
|
|
304
|
+
|
|
305
|
+
for (const dir of agentDirs) {
|
|
306
|
+
if (!dir.isDirectory()) continue;
|
|
307
|
+
|
|
308
|
+
const agentName = dir.name;
|
|
309
|
+
const identityPath = join(agentsDir, agentName, "identity.yaml");
|
|
310
|
+
const identityExists = await pathExists(identityPath);
|
|
311
|
+
|
|
312
|
+
if (!identityExists) {
|
|
313
|
+
continue; // Skip if no identity file
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
identityFileCount++;
|
|
317
|
+
|
|
318
|
+
// Parse and validate identity
|
|
319
|
+
try {
|
|
320
|
+
const content = await Bun.file(identityPath).text();
|
|
321
|
+
const identity = parseIdentityYaml(content);
|
|
322
|
+
|
|
323
|
+
if (!identity.name) {
|
|
324
|
+
identityErrors.push(`${agentName}: missing "name" field`);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (!identity.capability) {
|
|
328
|
+
identityErrors.push(`${agentName}: missing "capability" field`);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (!identity.created) {
|
|
332
|
+
identityErrors.push(`${agentName}: missing "created" field`);
|
|
333
|
+
} else {
|
|
334
|
+
// Validate ISO timestamp format
|
|
335
|
+
const timestamp = new Date(identity.created);
|
|
336
|
+
if (Number.isNaN(timestamp.getTime())) {
|
|
337
|
+
identityErrors.push(`${agentName}: invalid "created" timestamp`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (typeof identity.sessionsCompleted !== "number" || identity.sessionsCompleted < 0) {
|
|
342
|
+
identityErrors.push(`${agentName}: "sessionsCompleted" must be a non-negative integer`);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Identity directories are keyed by runtime agent names (for example
|
|
346
|
+
// lead-foo-1234), not by manifest role names. Validate the recorded
|
|
347
|
+
// role/capability against the manifest instead of the directory name.
|
|
348
|
+
if (identity.capability && !manifest.agents[identity.capability]) {
|
|
349
|
+
staleIdentities.push(`${agentName} (capability: ${identity.capability})`);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Validate name is valid identifier
|
|
353
|
+
if (identity.name && !VALID_NAME_REGEX.test(identity.name)) {
|
|
354
|
+
identityErrors.push(
|
|
355
|
+
`${agentName}: name "${identity.name}" contains invalid characters (use alphanumeric, dash, underscore only)`,
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
} catch (error) {
|
|
359
|
+
identityErrors.push(
|
|
360
|
+
`${agentName}: ${error instanceof Error ? error.message : "failed to parse YAML"}`,
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (identityErrors.length > 0) {
|
|
366
|
+
checks.push({
|
|
367
|
+
name: "Identity validation",
|
|
368
|
+
category: "agents",
|
|
369
|
+
status: "warn",
|
|
370
|
+
message: `Found ${identityErrors.length} issue(s)`,
|
|
371
|
+
details: identityErrors,
|
|
372
|
+
fixable: false,
|
|
373
|
+
});
|
|
374
|
+
} else if (identityFileCount > 0) {
|
|
375
|
+
checks.push({
|
|
376
|
+
name: "Identity validation",
|
|
377
|
+
category: "agents",
|
|
378
|
+
status: "pass",
|
|
379
|
+
message: "All identity files are valid",
|
|
380
|
+
fixable: false,
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (staleIdentities.length > 0) {
|
|
385
|
+
checks.push({
|
|
386
|
+
name: "Stale identities",
|
|
387
|
+
category: "agents",
|
|
388
|
+
status: "warn",
|
|
389
|
+
message: `Found ${staleIdentities.length} stale identity file(s)`,
|
|
390
|
+
details: staleIdentities.map((name) => `${name} (role not present in manifest)`),
|
|
391
|
+
fixable: true,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
} catch {
|
|
395
|
+
// Ignore errors reading agents directory
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return checks;
|
|
399
|
+
};
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import type { AgentplateConfig } from "../types.ts";
|
|
6
|
+
import { checkConfig } from "./config-check.ts";
|
|
7
|
+
|
|
8
|
+
// Helper to create a temp agentplate dir with config.yaml
|
|
9
|
+
function createTempAgentplateDir(configYaml: string): string {
|
|
10
|
+
const tempDir = mkdtempSync(join(tmpdir(), "agentplate-test-"));
|
|
11
|
+
const agentplateDir = join(tempDir, ".agentplate");
|
|
12
|
+
mkdirSync(agentplateDir, { recursive: true });
|
|
13
|
+
writeFileSync(join(agentplateDir, "config.yaml"), configYaml);
|
|
14
|
+
return agentplateDir;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Valid minimal config
|
|
18
|
+
const validConfigYaml = `
|
|
19
|
+
projectName: test-project
|
|
20
|
+
project:
|
|
21
|
+
root: ${tmpdir()}
|
|
22
|
+
canonicalBranch: main
|
|
23
|
+
maxConcurrent: 5
|
|
24
|
+
maxDepth: 2
|
|
25
|
+
watchdog:
|
|
26
|
+
tier0Enabled: false
|
|
27
|
+
tier1Enabled: false
|
|
28
|
+
tier2Enabled: false
|
|
29
|
+
tier3Enabled: false
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
const mockConfig: AgentplateConfig = {
|
|
33
|
+
project: {
|
|
34
|
+
name: "test-project",
|
|
35
|
+
root: tmpdir(),
|
|
36
|
+
canonicalBranch: "main",
|
|
37
|
+
},
|
|
38
|
+
agents: {
|
|
39
|
+
manifestPath: `${tmpdir()}/.agentplate/agent-manifest.json`,
|
|
40
|
+
baseDir: `${tmpdir()}/.agentplate/agents`,
|
|
41
|
+
maxConcurrent: 5,
|
|
42
|
+
staggerDelayMs: 1000,
|
|
43
|
+
maxDepth: 2,
|
|
44
|
+
maxSessionsPerRun: 0,
|
|
45
|
+
maxAgentsPerLead: 5,
|
|
46
|
+
},
|
|
47
|
+
worktrees: {
|
|
48
|
+
baseDir: `${tmpdir()}/.agentplate/worktrees`,
|
|
49
|
+
},
|
|
50
|
+
taskTracker: {
|
|
51
|
+
backend: "auto",
|
|
52
|
+
enabled: false,
|
|
53
|
+
},
|
|
54
|
+
loam: {
|
|
55
|
+
enabled: false,
|
|
56
|
+
domains: [],
|
|
57
|
+
primeFormat: "markdown",
|
|
58
|
+
},
|
|
59
|
+
merge: {
|
|
60
|
+
aiResolveEnabled: false,
|
|
61
|
+
reimagineEnabled: false,
|
|
62
|
+
},
|
|
63
|
+
providers: {
|
|
64
|
+
anthropic: { type: "native" },
|
|
65
|
+
},
|
|
66
|
+
watchdog: {
|
|
67
|
+
tier0Enabled: false,
|
|
68
|
+
tier0IntervalMs: 30000,
|
|
69
|
+
tier1Enabled: false,
|
|
70
|
+
tier2Enabled: false,
|
|
71
|
+
staleThresholdMs: 300000,
|
|
72
|
+
zombieThresholdMs: 600000,
|
|
73
|
+
nudgeIntervalMs: 60000,
|
|
74
|
+
},
|
|
75
|
+
models: {},
|
|
76
|
+
logging: {
|
|
77
|
+
verbose: false,
|
|
78
|
+
redactSecrets: true,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
describe("checkConfig", () => {
|
|
83
|
+
test("returns checks with category config", async () => {
|
|
84
|
+
const agentplateDir = createTempAgentplateDir(validConfigYaml);
|
|
85
|
+
const checks = await checkConfig(mockConfig, agentplateDir);
|
|
86
|
+
|
|
87
|
+
expect(checks).toBeArray();
|
|
88
|
+
expect(checks.length).toBeGreaterThan(0);
|
|
89
|
+
|
|
90
|
+
for (const check of checks) {
|
|
91
|
+
expect(check.category).toBe("config");
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("includes all four config checks", async () => {
|
|
96
|
+
const agentplateDir = createTempAgentplateDir(validConfigYaml);
|
|
97
|
+
const checks = await checkConfig(mockConfig, agentplateDir);
|
|
98
|
+
|
|
99
|
+
const checkNames = checks.map((c) => c.name);
|
|
100
|
+
expect(checkNames).toContain("config-parseable");
|
|
101
|
+
expect(checkNames).toContain("config-valid");
|
|
102
|
+
expect(checkNames).toContain("project-root-exists");
|
|
103
|
+
expect(checkNames).toContain("canonical-branch-exists");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("config-parseable passes with valid config", async () => {
|
|
107
|
+
const agentplateDir = createTempAgentplateDir(validConfigYaml);
|
|
108
|
+
const checks = await checkConfig(mockConfig, agentplateDir);
|
|
109
|
+
|
|
110
|
+
const parseableCheck = checks.find((c) => c.name === "config-parseable");
|
|
111
|
+
expect(parseableCheck).toBeDefined();
|
|
112
|
+
expect(parseableCheck?.status).toBe("pass");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("config-valid passes with valid config", async () => {
|
|
116
|
+
const agentplateDir = createTempAgentplateDir(validConfigYaml);
|
|
117
|
+
const checks = await checkConfig(mockConfig, agentplateDir);
|
|
118
|
+
|
|
119
|
+
const validCheck = checks.find((c) => c.name === "config-valid");
|
|
120
|
+
expect(validCheck).toBeDefined();
|
|
121
|
+
expect(validCheck?.status).toBe("pass");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("project-root-exists passes when directory exists", async () => {
|
|
125
|
+
const agentplateDir = createTempAgentplateDir(validConfigYaml);
|
|
126
|
+
const checks = await checkConfig(mockConfig, agentplateDir);
|
|
127
|
+
|
|
128
|
+
const rootCheck = checks.find((c) => c.name === "project-root-exists");
|
|
129
|
+
expect(rootCheck).toBeDefined();
|
|
130
|
+
expect(rootCheck?.status).toBe("pass");
|
|
131
|
+
expect(rootCheck?.details).toBeDefined();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("project-root-exists fails when directory does not exist", async () => {
|
|
135
|
+
const agentplateDir = createTempAgentplateDir(validConfigYaml);
|
|
136
|
+
const configWithBadRoot = {
|
|
137
|
+
...mockConfig,
|
|
138
|
+
project: {
|
|
139
|
+
...mockConfig.project,
|
|
140
|
+
root: "/nonexistent/path/that/does/not/exist",
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
const checks = await checkConfig(configWithBadRoot, agentplateDir);
|
|
144
|
+
|
|
145
|
+
const rootCheck = checks.find((c) => c.name === "project-root-exists");
|
|
146
|
+
expect(rootCheck).toBeDefined();
|
|
147
|
+
expect(rootCheck?.status).toBe("fail");
|
|
148
|
+
expect(rootCheck?.fixable).toBe(true);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("canonical-branch-exists warns when branch does not exist", async () => {
|
|
152
|
+
const agentplateDir = createTempAgentplateDir(validConfigYaml);
|
|
153
|
+
const configWithBadBranch = {
|
|
154
|
+
...mockConfig,
|
|
155
|
+
project: {
|
|
156
|
+
...mockConfig.project,
|
|
157
|
+
canonicalBranch: "nonexistent-branch-xyz",
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
const checks = await checkConfig(configWithBadBranch, agentplateDir);
|
|
161
|
+
|
|
162
|
+
const branchCheck = checks.find((c) => c.name === "canonical-branch-exists");
|
|
163
|
+
expect(branchCheck).toBeDefined();
|
|
164
|
+
expect(branchCheck?.status).toBe("warn");
|
|
165
|
+
expect(branchCheck?.message).toContain("nonexistent-branch-xyz");
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test("all checks have required DoctorCheck fields", async () => {
|
|
169
|
+
const agentplateDir = createTempAgentplateDir(validConfigYaml);
|
|
170
|
+
const checks = await checkConfig(mockConfig, agentplateDir);
|
|
171
|
+
|
|
172
|
+
for (const check of checks) {
|
|
173
|
+
expect(check).toHaveProperty("name");
|
|
174
|
+
expect(check).toHaveProperty("category");
|
|
175
|
+
expect(check).toHaveProperty("status");
|
|
176
|
+
expect(check).toHaveProperty("message");
|
|
177
|
+
|
|
178
|
+
expect(typeof check.name).toBe("string");
|
|
179
|
+
expect(typeof check.message).toBe("string");
|
|
180
|
+
expect(["pass", "warn", "fail"]).toContain(check.status);
|
|
181
|
+
|
|
182
|
+
if (check.details !== undefined) {
|
|
183
|
+
expect(check.details).toBeArray();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (check.fixable !== undefined) {
|
|
187
|
+
expect(typeof check.fixable).toBe("boolean");
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
});
|