@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,278 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { Command, Option } from "commander";
|
|
5
|
+
import { registerAddCommand } from "./commands/add.ts";
|
|
6
|
+
import { registerArchiveCommand } from "./commands/archive.ts";
|
|
7
|
+
import { registerAuditCommand } from "./commands/audit.ts";
|
|
8
|
+
import { registerCompactCommand } from "./commands/compact.ts";
|
|
9
|
+
import { registerCompletionsCommand } from "./commands/completions.ts";
|
|
10
|
+
import { registerConfigCommand } from "./commands/config.ts";
|
|
11
|
+
import { registerDeleteCommand } from "./commands/delete.ts";
|
|
12
|
+
import { registerDeleteDomainCommand } from "./commands/delete-domain.ts";
|
|
13
|
+
import { registerDiffCommand } from "./commands/diff.ts";
|
|
14
|
+
import { registerDoctorCommand } from "./commands/doctor.ts";
|
|
15
|
+
import { registerEditCommand } from "./commands/edit.ts";
|
|
16
|
+
import { registerInitCommand } from "./commands/init.ts";
|
|
17
|
+
import { registerLearnCommand } from "./commands/learn.ts";
|
|
18
|
+
import { registerMoveCommand } from "./commands/move.ts";
|
|
19
|
+
import { registerOnboardCommand } from "./commands/onboard.ts";
|
|
20
|
+
import { registerOutcomeCommand } from "./commands/outcome.ts";
|
|
21
|
+
import { registerPrimeCommand } from "./commands/prime.ts";
|
|
22
|
+
import { registerPruneCommand } from "./commands/prune.ts";
|
|
23
|
+
import { registerQueryCommand } from "./commands/query.ts";
|
|
24
|
+
import { registerRankCommand } from "./commands/rank.ts";
|
|
25
|
+
import { registerReadyCommand } from "./commands/ready.ts";
|
|
26
|
+
import { registerRecordCommand } from "./commands/record.ts";
|
|
27
|
+
import { registerRestoreCommand } from "./commands/restore.ts";
|
|
28
|
+
import { registerSearchCommand } from "./commands/search.ts";
|
|
29
|
+
import { registerSetupCommand } from "./commands/setup.ts";
|
|
30
|
+
import { registerStatusCommand } from "./commands/status.ts";
|
|
31
|
+
import { registerSyncCommand } from "./commands/sync.ts";
|
|
32
|
+
import { registerUpdateCommand } from "./commands/update.ts";
|
|
33
|
+
import { registerUpgradeCommand } from "./commands/upgrade.ts";
|
|
34
|
+
import { registerValidateCommand } from "./commands/validate.ts";
|
|
35
|
+
import { log } from "./log.ts";
|
|
36
|
+
import { initRegistryFromConfig } from "./registry/init.ts";
|
|
37
|
+
import { outputJsonError } from "./utils/json-output.ts";
|
|
38
|
+
import { brand, muted, setQuiet } from "./utils/palette.ts";
|
|
39
|
+
import { setAllowDomainMismatch, setAllowUnknownTypes } from "./utils/runtime-flags.ts";
|
|
40
|
+
|
|
41
|
+
// Initialize the type registry from config so any custom_types declared in
|
|
42
|
+
// loam.config.yaml are first-class. Falls back to built-ins-only when no
|
|
43
|
+
// .loam/ directory exists yet (e.g., before `lm init`). Wrap any thrown
|
|
44
|
+
// registry-init errors (bad custom_types config, disabled_types referencing
|
|
45
|
+
// unknown types, etc.) so users see a formatted message instead of a Bun stack
|
|
46
|
+
// trace from a top-level await failure.
|
|
47
|
+
try {
|
|
48
|
+
await initRegistryFromConfig();
|
|
49
|
+
} catch (err) {
|
|
50
|
+
const wantsJson = process.argv.includes("--json");
|
|
51
|
+
const message = (err as Error).message;
|
|
52
|
+
if (wantsJson) {
|
|
53
|
+
// In --json mode stderr must carry ONLY the machine-readable error
|
|
54
|
+
// object; a diagnostic log line would corrupt the parse. So skip the
|
|
55
|
+
// structured log here and let the JSON error stand alone.
|
|
56
|
+
outputJsonError("init", `Config error: ${message}`);
|
|
57
|
+
} else {
|
|
58
|
+
// Structured diagnostic for operators, gated behind LOAM_DEBUG so it
|
|
59
|
+
// never clutters the formatted human error below during normal use.
|
|
60
|
+
log.debug({ err: message }, "registry init from config failed");
|
|
61
|
+
process.stderr.write(`${chalk.red("Config error:")} ${message}\n`);
|
|
62
|
+
process.stderr.write(
|
|
63
|
+
chalk.dim("Edit .loam/loam.config.yaml to resolve, or run `loam doctor` for details.\n"),
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { VERSION } from "../../version.ts";
|
|
70
|
+
|
|
71
|
+
import { VERSION } from "../../version.ts";
|
|
72
|
+
|
|
73
|
+
const rawArgs = process.argv.slice(2);
|
|
74
|
+
|
|
75
|
+
// Handle --version --json before Commander processes the flag
|
|
76
|
+
if ((rawArgs.includes("-v") || rawArgs.includes("--version")) && rawArgs.includes("--json")) {
|
|
77
|
+
const platform = `${process.platform}-${process.arch}`;
|
|
78
|
+
console.log(
|
|
79
|
+
JSON.stringify({
|
|
80
|
+
name: "@ag-eco/loam-cli",
|
|
81
|
+
version: VERSION,
|
|
82
|
+
runtime: "bun",
|
|
83
|
+
platform,
|
|
84
|
+
}),
|
|
85
|
+
);
|
|
86
|
+
process.exit();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Apply quiet mode early so it affects all output during command execution
|
|
90
|
+
if (rawArgs.includes("--quiet") || rawArgs.includes("-q")) {
|
|
91
|
+
setQuiet(true);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Apply --allow-unknown-types early so readers (which run before Commander
|
|
95
|
+
// finishes parsing in some commands) consult the right runtime flag.
|
|
96
|
+
if (rawArgs.includes("--allow-unknown-types")) {
|
|
97
|
+
setAllowUnknownTypes(true);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (rawArgs.includes("--allow-domain-mismatch")) {
|
|
101
|
+
setAllowDomainMismatch(true);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Detect --timing early (before Commander) so we can measure from startup
|
|
105
|
+
const hasTiming = rawArgs.includes("--timing");
|
|
106
|
+
const startTime = Date.now();
|
|
107
|
+
|
|
108
|
+
const program = new Command();
|
|
109
|
+
|
|
110
|
+
const COL_WIDTH = 20;
|
|
111
|
+
|
|
112
|
+
program
|
|
113
|
+
.name("loam")
|
|
114
|
+
.description("Structured expertise management")
|
|
115
|
+
.showSuggestionAfterError(false)
|
|
116
|
+
.version(VERSION, "-v, --version", "Print version")
|
|
117
|
+
.option("--json", "Output as structured JSON")
|
|
118
|
+
.option("-q, --quiet", "Suppress non-error output")
|
|
119
|
+
.option("--verbose", "Show full details in output")
|
|
120
|
+
.option("--timing", "Print execution time to stderr")
|
|
121
|
+
.option(
|
|
122
|
+
"--allow-unknown-types",
|
|
123
|
+
"tolerate on-disk records of unregistered types (worktree/CI lag escape hatch)",
|
|
124
|
+
)
|
|
125
|
+
.option(
|
|
126
|
+
"--allow-domain-mismatch",
|
|
127
|
+
"tolerate records that violate per-domain allowed_types/required_fields (escape hatch for record/validate; ignored by sync)",
|
|
128
|
+
)
|
|
129
|
+
.addOption(
|
|
130
|
+
new Option(
|
|
131
|
+
"--format <format>",
|
|
132
|
+
"output format for record-rendering commands (prime, query, search)",
|
|
133
|
+
).choices(["markdown", "compact", "xml", "plain"]),
|
|
134
|
+
)
|
|
135
|
+
.configureHelp({
|
|
136
|
+
formatHelp(cmd, helper): string {
|
|
137
|
+
const lines: string[] = [];
|
|
138
|
+
|
|
139
|
+
// Header: "loam v0.6.2 — Structured expertise management"
|
|
140
|
+
lines.push(
|
|
141
|
+
`${brand.bold(cmd.name())} ${muted(`v${VERSION}`)} — Structured expertise management`,
|
|
142
|
+
);
|
|
143
|
+
lines.push("");
|
|
144
|
+
|
|
145
|
+
// Usage
|
|
146
|
+
lines.push(`Usage: ${chalk.dim(cmd.name())} <command> [options]`);
|
|
147
|
+
lines.push("");
|
|
148
|
+
|
|
149
|
+
// Commands
|
|
150
|
+
const visibleCmds = helper.visibleCommands(cmd);
|
|
151
|
+
if (visibleCmds.length > 0) {
|
|
152
|
+
lines.push("Commands:");
|
|
153
|
+
for (const sub of visibleCmds) {
|
|
154
|
+
const term = helper.subcommandTerm(sub);
|
|
155
|
+
const firstSpace = term.indexOf(" ");
|
|
156
|
+
const name = firstSpace >= 0 ? term.slice(0, firstSpace) : term;
|
|
157
|
+
const args = firstSpace >= 0 ? ` ${term.slice(firstSpace + 1)}` : "";
|
|
158
|
+
const coloredTerm = `${chalk.green(name)}${args ? chalk.dim(args) : ""}`;
|
|
159
|
+
const rawLen = term.length;
|
|
160
|
+
const padding = " ".repeat(Math.max(2, COL_WIDTH - rawLen));
|
|
161
|
+
lines.push(` ${coloredTerm}${padding}${helper.subcommandDescription(sub)}`);
|
|
162
|
+
}
|
|
163
|
+
lines.push("");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Options
|
|
167
|
+
const visibleOpts = helper.visibleOptions(cmd);
|
|
168
|
+
if (visibleOpts.length > 0) {
|
|
169
|
+
lines.push("Options:");
|
|
170
|
+
for (const opt of visibleOpts) {
|
|
171
|
+
const flags = helper.optionTerm(opt);
|
|
172
|
+
const padding = " ".repeat(Math.max(2, COL_WIDTH - flags.length));
|
|
173
|
+
lines.push(` ${chalk.dim(flags)}${padding}${helper.optionDescription(opt)}`);
|
|
174
|
+
}
|
|
175
|
+
lines.push("");
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Footer
|
|
179
|
+
lines.push(`Run '${chalk.dim(cmd.name())} <command> --help' for command-specific help.`);
|
|
180
|
+
|
|
181
|
+
return `${lines.join("\n")}\n`;
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Suppress the default description header (we handle it in formatHelp)
|
|
186
|
+
program.addHelpCommand(false);
|
|
187
|
+
|
|
188
|
+
registerInitCommand(program);
|
|
189
|
+
registerAddCommand(program);
|
|
190
|
+
registerRecordCommand(program);
|
|
191
|
+
registerEditCommand(program);
|
|
192
|
+
registerQueryCommand(program);
|
|
193
|
+
registerSetupCommand(program);
|
|
194
|
+
registerPrimeCommand(program);
|
|
195
|
+
registerOnboardCommand(program);
|
|
196
|
+
registerStatusCommand(program);
|
|
197
|
+
registerValidateCommand(program);
|
|
198
|
+
registerPruneCommand(program);
|
|
199
|
+
registerArchiveCommand(program);
|
|
200
|
+
registerRestoreCommand(program);
|
|
201
|
+
registerSearchCommand(program);
|
|
202
|
+
registerRankCommand(program);
|
|
203
|
+
registerOutcomeCommand(program);
|
|
204
|
+
registerDoctorCommand(program);
|
|
205
|
+
registerReadyCommand(program);
|
|
206
|
+
registerSyncCommand(program);
|
|
207
|
+
registerDeleteCommand(program);
|
|
208
|
+
registerDeleteDomainCommand(program);
|
|
209
|
+
registerMoveCommand(program);
|
|
210
|
+
registerLearnCommand(program);
|
|
211
|
+
registerCompactCommand(program);
|
|
212
|
+
registerConfigCommand(program);
|
|
213
|
+
registerDiffCommand(program);
|
|
214
|
+
registerUpdateCommand(program);
|
|
215
|
+
registerUpgradeCommand(program);
|
|
216
|
+
registerCompletionsCommand(program);
|
|
217
|
+
registerAuditCommand(program);
|
|
218
|
+
|
|
219
|
+
// --- Typo suggestions via Levenshtein distance ---
|
|
220
|
+
|
|
221
|
+
function editDistance(a: string, b: string): number {
|
|
222
|
+
const m = a.length;
|
|
223
|
+
const n = b.length;
|
|
224
|
+
const dp = new Array<number>((m + 1) * (n + 1)).fill(0);
|
|
225
|
+
const idx = (i: number, j: number) => i * (n + 1) + j;
|
|
226
|
+
for (let i = 0; i <= m; i++) dp[idx(i, 0)] = i;
|
|
227
|
+
for (let j = 0; j <= n; j++) dp[idx(0, j)] = j;
|
|
228
|
+
for (let i = 1; i <= m; i++) {
|
|
229
|
+
for (let j = 1; j <= n; j++) {
|
|
230
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
231
|
+
const del = (dp[idx(i - 1, j)] ?? 0) + 1;
|
|
232
|
+
const ins = (dp[idx(i, j - 1)] ?? 0) + 1;
|
|
233
|
+
const sub = (dp[idx(i - 1, j - 1)] ?? 0) + cost;
|
|
234
|
+
dp[idx(i, j)] = Math.min(del, ins, sub);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return dp[idx(m, n)] ?? 0;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function suggestCommand(input: string): string | undefined {
|
|
241
|
+
const commands = program.commands.map((c) => c.name());
|
|
242
|
+
let bestMatch: string | undefined;
|
|
243
|
+
let bestDist = 3; // Only suggest if distance <= 2
|
|
244
|
+
for (const cmd of commands) {
|
|
245
|
+
const dist = editDistance(input, cmd);
|
|
246
|
+
if (dist < bestDist) {
|
|
247
|
+
bestDist = dist;
|
|
248
|
+
bestMatch = cmd;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return bestMatch;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
program.on("command:*", (operands: string[]) => {
|
|
255
|
+
const unknown = operands[0] ?? "";
|
|
256
|
+
const json = rawArgs.includes("--json");
|
|
257
|
+
const suggestion = suggestCommand(unknown);
|
|
258
|
+
if (json) {
|
|
259
|
+
outputJsonError(
|
|
260
|
+
unknown,
|
|
261
|
+
`Unknown command: ${unknown}${suggestion ? `. Did you mean '${suggestion}'?` : ""}`,
|
|
262
|
+
);
|
|
263
|
+
} else {
|
|
264
|
+
process.stderr.write(`Unknown command: ${unknown}\n`);
|
|
265
|
+
if (suggestion) {
|
|
266
|
+
process.stderr.write(`Did you mean '${suggestion}'?\n`);
|
|
267
|
+
}
|
|
268
|
+
process.stderr.write("Run 'loam --help' for usage.\n");
|
|
269
|
+
}
|
|
270
|
+
process.exitCode = 1;
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
await program.parseAsync();
|
|
274
|
+
|
|
275
|
+
if (hasTiming) {
|
|
276
|
+
const elapsed = Date.now() - startTime;
|
|
277
|
+
console.error(muted(`Done in ${elapsed}ms`));
|
|
278
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import type { Command } from "commander";
|
|
4
|
+
import { getExpertisePath, getLoamDir, readConfig, writeConfig } from "../utils/config.ts";
|
|
5
|
+
import { createExpertiseFile } from "../utils/expertise.ts";
|
|
6
|
+
import { outputJson, outputJsonError } from "../utils/json-output.ts";
|
|
7
|
+
import { isQuiet } from "../utils/palette.ts";
|
|
8
|
+
|
|
9
|
+
export function registerAddCommand(program: Command): void {
|
|
10
|
+
program
|
|
11
|
+
.command("add")
|
|
12
|
+
.argument("<domain>", "expertise domain to add")
|
|
13
|
+
.description("Add a new expertise domain")
|
|
14
|
+
.action(async (domain: string) => {
|
|
15
|
+
const jsonMode = program.opts().json === true;
|
|
16
|
+
const loamDir = getLoamDir();
|
|
17
|
+
|
|
18
|
+
if (!existsSync(loamDir)) {
|
|
19
|
+
if (jsonMode) {
|
|
20
|
+
outputJsonError("add", "No .loam/ directory found. Run `loam init` first.");
|
|
21
|
+
} else {
|
|
22
|
+
console.error(chalk.red("No .loam/ directory found. Run `loam init` first."));
|
|
23
|
+
}
|
|
24
|
+
process.exitCode = 1;
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const config = await readConfig();
|
|
29
|
+
|
|
30
|
+
if (domain in config.domains) {
|
|
31
|
+
if (jsonMode) {
|
|
32
|
+
outputJsonError("add", `Domain "${domain}" already exists.`);
|
|
33
|
+
} else {
|
|
34
|
+
console.error(chalk.red(`Domain "${domain}" already exists.`));
|
|
35
|
+
}
|
|
36
|
+
process.exitCode = 1;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const expertisePath = getExpertisePath(domain);
|
|
41
|
+
await createExpertiseFile(expertisePath);
|
|
42
|
+
|
|
43
|
+
config.domains[domain] = {};
|
|
44
|
+
await writeConfig(config);
|
|
45
|
+
|
|
46
|
+
if (jsonMode) {
|
|
47
|
+
outputJson({ success: true, command: "add", domain });
|
|
48
|
+
} else if (!isQuiet()) {
|
|
49
|
+
console.log(chalk.green(`Added domain "${domain}".`));
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import type { Command } from "commander";
|
|
3
|
+
import type { ExpertiseRecord } from "../schemas/record.ts";
|
|
4
|
+
import { archiveRecords } from "../utils/archive.ts";
|
|
5
|
+
import { getExpertisePath, readConfig } from "../utils/config.ts";
|
|
6
|
+
import { readExpertiseFile, resolveRecordId, writeExpertiseFile } from "../utils/expertise.ts";
|
|
7
|
+
import { getRecordSummary } from "../utils/format.ts";
|
|
8
|
+
import { outputJson, outputJsonError } from "../utils/json-output.ts";
|
|
9
|
+
import { withFileLock } from "../utils/lock.ts";
|
|
10
|
+
import { accent, brand, isQuiet } from "../utils/palette.ts";
|
|
11
|
+
|
|
12
|
+
interface ArchivedRecordInfo {
|
|
13
|
+
id: string | null;
|
|
14
|
+
type: string;
|
|
15
|
+
summary: string;
|
|
16
|
+
reason: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function buildArchivedInfo(record: ExpertiseRecord, reason: string): ArchivedRecordInfo {
|
|
20
|
+
return {
|
|
21
|
+
id: record.id ?? null,
|
|
22
|
+
type: record.type,
|
|
23
|
+
summary: getRecordSummary(record),
|
|
24
|
+
reason,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function printArchivedRecord(
|
|
29
|
+
record: ExpertiseRecord,
|
|
30
|
+
domain: string,
|
|
31
|
+
reason: string,
|
|
32
|
+
dryRun: boolean,
|
|
33
|
+
): void {
|
|
34
|
+
const prefix = dryRun ? `${chalk.yellow("[DRY RUN]")} ` : "";
|
|
35
|
+
const verb = dryRun ? "Would archive" : "Archived";
|
|
36
|
+
const rid = record.id ? ` ${accent(record.id)}` : "";
|
|
37
|
+
console.log(
|
|
38
|
+
`${prefix}${brand(`${verb} ${record.type}`)}${rid} ${brand(`from ${domain}`)} (${reason}): ${getRecordSummary(record)}`,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function registerArchiveCommand(program: Command): void {
|
|
43
|
+
program
|
|
44
|
+
.command("archive")
|
|
45
|
+
.argument("<domain>", "expertise domain")
|
|
46
|
+
.argument("[id]", "record ID (e.g. mx-abc123, abc123, or abc)")
|
|
47
|
+
.description(
|
|
48
|
+
"Soft-archive one or more live records (symmetric to `lm restore`; pairs with `lm prune` for bulk decay)",
|
|
49
|
+
)
|
|
50
|
+
.option("--records <ids>", "comma-separated list of record IDs to archive")
|
|
51
|
+
.requiredOption("--reason <text>", "why this record is being archived (required, free-text)")
|
|
52
|
+
.option("--dry-run", "preview what would be archived without making changes", false)
|
|
53
|
+
.action(
|
|
54
|
+
async (
|
|
55
|
+
domain: string,
|
|
56
|
+
id: string | undefined,
|
|
57
|
+
options: { records?: string; reason: string; dryRun: boolean },
|
|
58
|
+
) => {
|
|
59
|
+
const jsonMode = program.opts().json === true;
|
|
60
|
+
try {
|
|
61
|
+
const config = await readConfig();
|
|
62
|
+
|
|
63
|
+
if (!(domain in config.domains)) {
|
|
64
|
+
const available = Object.keys(config.domains).join(", ") || "(none)";
|
|
65
|
+
if (jsonMode) {
|
|
66
|
+
outputJsonError(
|
|
67
|
+
"archive",
|
|
68
|
+
`Domain "${domain}" not found in config. Available domains: ${available}`,
|
|
69
|
+
);
|
|
70
|
+
} else {
|
|
71
|
+
console.error(chalk.red(`Error: domain "${domain}" not found in config.`));
|
|
72
|
+
console.error(chalk.red(`Available domains: ${available}`));
|
|
73
|
+
}
|
|
74
|
+
process.exitCode = 1;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const reasonText = options.reason.trim();
|
|
79
|
+
if (reasonText.length === 0) {
|
|
80
|
+
if (jsonMode) {
|
|
81
|
+
outputJsonError("archive", "--reason must not be empty.");
|
|
82
|
+
} else {
|
|
83
|
+
console.error(chalk.red("Error: --reason must not be empty."));
|
|
84
|
+
}
|
|
85
|
+
process.exitCode = 1;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const hasId = id !== undefined;
|
|
90
|
+
const hasRecords = options.records !== undefined;
|
|
91
|
+
const modeCount = [hasId, hasRecords].filter(Boolean).length;
|
|
92
|
+
|
|
93
|
+
if (modeCount === 0) {
|
|
94
|
+
if (jsonMode) {
|
|
95
|
+
outputJsonError("archive", "Must provide a record ID or --records.");
|
|
96
|
+
} else {
|
|
97
|
+
console.error(chalk.red("Error: must provide a record ID or --records."));
|
|
98
|
+
}
|
|
99
|
+
process.exitCode = 1;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (modeCount > 1) {
|
|
104
|
+
if (jsonMode) {
|
|
105
|
+
outputJsonError(
|
|
106
|
+
"archive",
|
|
107
|
+
"Cannot combine a record ID with --records. Use only one mode.",
|
|
108
|
+
);
|
|
109
|
+
} else {
|
|
110
|
+
console.error(
|
|
111
|
+
chalk.red("Error: cannot combine a record ID with --records. Use only one mode."),
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
process.exitCode = 1;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const rawIds: string[] = hasRecords
|
|
119
|
+
? (options.records as string)
|
|
120
|
+
.split(",")
|
|
121
|
+
.map((s) => s.trim())
|
|
122
|
+
.filter(Boolean)
|
|
123
|
+
: [id as string];
|
|
124
|
+
|
|
125
|
+
if (rawIds.length === 0) {
|
|
126
|
+
if (jsonMode) {
|
|
127
|
+
outputJsonError("archive", "--records requires at least one ID.");
|
|
128
|
+
} else {
|
|
129
|
+
console.error(chalk.red("Error: --records requires at least one ID."));
|
|
130
|
+
}
|
|
131
|
+
process.exitCode = 1;
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const stampedReason = `manual: ${reasonText}`;
|
|
136
|
+
const filePath = getExpertisePath(domain);
|
|
137
|
+
|
|
138
|
+
// Resolve + remove from live under the live-file lock so concurrent
|
|
139
|
+
// writers don't lose data between read and write. Archive write
|
|
140
|
+
// happens after the live write (mirrors `lm prune` phase 3).
|
|
141
|
+
const lockResult = await withFileLock(filePath, async () => {
|
|
142
|
+
const records = await readExpertiseFile(filePath);
|
|
143
|
+
const toArchiveIndices = new Set<number>();
|
|
144
|
+
|
|
145
|
+
for (const rawId of rawIds) {
|
|
146
|
+
const resolved = resolveRecordId(records, rawId);
|
|
147
|
+
if (!resolved.ok) {
|
|
148
|
+
return { ok: false as const, error: resolved.error };
|
|
149
|
+
}
|
|
150
|
+
toArchiveIndices.add(resolved.index);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const archived = records.filter((_, i) => toArchiveIndices.has(i));
|
|
154
|
+
const kept = records.filter((_, i) => !toArchiveIndices.has(i));
|
|
155
|
+
|
|
156
|
+
if (!options.dryRun) {
|
|
157
|
+
await writeExpertiseFile(filePath, kept);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return { ok: true as const, archived, kept };
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
if (!lockResult.ok) {
|
|
164
|
+
if (jsonMode) {
|
|
165
|
+
outputJsonError("archive", lockResult.error);
|
|
166
|
+
} else {
|
|
167
|
+
console.error(chalk.red(`Error: ${lockResult.error}`));
|
|
168
|
+
}
|
|
169
|
+
process.exitCode = 1;
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const { archived, kept } = lockResult;
|
|
174
|
+
|
|
175
|
+
if (!options.dryRun && archived.length > 0) {
|
|
176
|
+
await archiveRecords(domain, archived, new Date(), stampedReason);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (jsonMode) {
|
|
180
|
+
outputJson({
|
|
181
|
+
success: true,
|
|
182
|
+
command: "archive",
|
|
183
|
+
domain,
|
|
184
|
+
dryRun: options.dryRun,
|
|
185
|
+
archived: archived.map((r) => buildArchivedInfo(r, stampedReason)),
|
|
186
|
+
kept: kept.length,
|
|
187
|
+
});
|
|
188
|
+
} else if (!isQuiet()) {
|
|
189
|
+
for (const r of archived) {
|
|
190
|
+
printArchivedRecord(r, domain, stampedReason, options.dryRun);
|
|
191
|
+
}
|
|
192
|
+
if (!options.dryRun && archived.length > 1) {
|
|
193
|
+
console.log(brand(`✓ Archived ${archived.length} records from ${domain}`));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
} catch (err) {
|
|
197
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
|
|
198
|
+
if (jsonMode) {
|
|
199
|
+
outputJsonError("archive", "No .loam/ directory found. Run `loam init` first.");
|
|
200
|
+
} else {
|
|
201
|
+
console.error(chalk.red("Error: No .loam/ directory found. Run `loam init` first."));
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
if (jsonMode) {
|
|
205
|
+
outputJsonError("archive", (err as Error).message);
|
|
206
|
+
} else {
|
|
207
|
+
console.error(chalk.red(`Error: ${(err as Error).message}`));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
process.exitCode = 1;
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
);
|
|
214
|
+
}
|