akm-cli 0.9.0-rc.0 → 0.9.0-rc.13
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/CHANGELOG.md +1283 -22
- package/README.md +62 -37
- package/SECURITY.md +46 -31
- package/dist/akm +162 -38
- package/dist/akm-migrate +44 -0
- package/dist/assets/backends/schtasks-template.xml +2 -1
- package/dist/assets/hints/cli-hints-full.md +268 -118
- package/dist/assets/hints/cli-hints-short.md +87 -24
- package/dist/assets/{profiles → improve-strategies}/catchup.json +3 -1
- package/dist/assets/{profiles → improve-strategies}/consolidate.json +3 -1
- package/dist/assets/{profiles → improve-strategies}/default.json +6 -7
- package/dist/assets/improve-strategies/frequent.json +15 -0
- package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +4 -2
- package/dist/assets/{profiles → improve-strategies}/memory-focus.json +4 -1
- package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +5 -5
- package/dist/assets/{profiles → improve-strategies}/quick.json +4 -2
- package/dist/assets/improve-strategies/reflect-distill.json +30 -0
- package/dist/assets/{profiles → improve-strategies}/thorough.json +1 -1
- package/dist/assets/prompts/consolidate-system.md +5 -5
- package/dist/assets/prompts/extract-session.md +2 -6
- package/dist/assets/prompts/memory-infer-user.md +2 -3
- package/dist/assets/prompts/reflect-llm-framed-contract.md +11 -0
- package/dist/assets/prompts/reflect-llm-schema-contract.md +3 -0
- package/dist/assets/prompts/reflect-output-repair.md +3 -0
- package/dist/assets/prompts/workflow-unit-preamble.md +26 -0
- package/dist/assets/stash-skeleton/README.md +38 -10
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +14 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +13 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +9 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +11 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +9 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +9 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +100 -0
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +64 -0
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +136 -0
- package/dist/assets/tasks/core/extract.yml +3 -2
- package/dist/assets/tasks/core/improve.yml +2 -1
- package/dist/assets/tasks/core/index-refresh.yml +1 -0
- package/dist/assets/tasks/core/sync.yml +1 -0
- package/dist/assets/tasks/core/version-check.yml +2 -1
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
- package/dist/assets/templates/html/health.html +5 -4
- package/dist/assets/workflows/workflow-template.md +31 -15
- package/dist/cli/invocation.js +279 -0
- package/dist/cli/parse-args.js +5 -90
- package/dist/cli/retired-commands.js +78 -0
- package/dist/cli/shared.js +158 -48
- package/dist/cli-node.mjs +2 -1
- package/dist/cli.js +747 -293
- package/dist/commands/agent/agent-dispatch.js +19 -18
- package/dist/commands/agent/agent-support.js +0 -24
- package/dist/commands/agent/contribute-cli.js +43 -97
- package/dist/commands/completions.js +80 -23
- package/dist/commands/config-cli.js +44 -281
- package/dist/commands/env/env-binding.js +99 -0
- package/dist/commands/env/env-cli.js +84 -224
- package/dist/commands/env/env.js +12 -163
- package/dist/commands/env/marker-path.js +6 -0
- package/dist/commands/env/secret-cli.js +45 -61
- package/dist/commands/env/secret.js +32 -62
- package/dist/commands/feedback-cli.js +179 -85
- package/dist/commands/health/accept-rate.js +58 -0
- package/dist/commands/health/advisories.js +7 -8
- package/dist/commands/health/checks.js +279 -94
- package/dist/commands/health/html-report.js +197 -578
- package/dist/commands/health/improve-metrics.js +277 -246
- package/dist/commands/health/llm-usage.js +19 -19
- package/dist/commands/health/md-report.js +16 -7
- package/dist/commands/health/metrics.js +67 -32
- package/dist/commands/health/renderers.js +47 -0
- package/dist/commands/health/report-view-model.js +508 -0
- package/dist/commands/health/stash-exposure.js +1 -1
- package/dist/commands/health/surfaces.js +16 -56
- package/dist/commands/health/task-runs.js +3 -67
- package/dist/{migrate-storage-node.mjs → commands/health/types-checks.js} +1 -5
- package/dist/commands/health/types-improve.js +29 -0
- package/dist/{output/text/save.js → commands/health/types-metrics.js} +1 -2
- package/dist/commands/health/types-result.js +7 -0
- package/dist/commands/health/types-runs.js +4 -0
- package/dist/commands/health/types-session-log.js +4 -0
- package/dist/commands/health/types-windows.js +4 -0
- package/dist/commands/health/types.js +26 -21
- package/dist/commands/health/windows.js +2 -3
- package/dist/commands/health.js +296 -167
- package/dist/commands/improve/anti-collapse.js +5 -5
- package/dist/commands/improve/autonomy-gate.js +68 -0
- package/dist/commands/improve/collapse-detector.js +65 -52
- package/dist/commands/improve/consolidate/chunking.js +9 -7
- package/dist/commands/improve/consolidate/eligibility.js +1 -23
- package/dist/commands/improve/consolidate/merge.js +4 -0
- package/dist/commands/improve/consolidate.js +454 -1354
- package/dist/commands/improve/content-hash.js +39 -0
- package/dist/commands/improve/distill/content-repair.js +4 -10
- package/dist/commands/improve/distill/promote-memory.js +89 -64
- package/dist/commands/improve/distill/quality-gate.js +118 -42
- package/dist/commands/improve/distill-guards.js +1 -1
- package/dist/commands/improve/distill-promotion-policy.js +33 -888
- package/dist/commands/improve/distill.js +607 -363
- package/dist/commands/improve/eligibility.js +165 -79
- package/dist/commands/improve/extract-cli.js +35 -126
- package/dist/commands/improve/extract-prompt.js +6 -35
- package/dist/commands/improve/extract.js +640 -391
- package/dist/commands/improve/feedback-valence.js +2 -12
- package/dist/commands/improve/improve-cli.js +134 -135
- package/dist/commands/improve/improve-result-file.js +30 -50
- package/dist/commands/improve/improve-run-types.js +4 -0
- package/dist/commands/improve/improve-strategies.js +135 -0
- package/dist/commands/improve/improve.js +904 -701
- package/dist/commands/improve/locks.js +64 -111
- package/dist/commands/improve/loop-stages.js +1110 -923
- package/dist/commands/improve/memory/derived-ref.js +124 -0
- package/dist/commands/improve/memory/memory-belief.js +79 -7
- package/dist/commands/improve/memory/memory-contradiction-detect.js +49 -52
- package/dist/commands/improve/memory/memory-improve.js +25 -37
- package/dist/commands/improve/outcome-loop.js +25 -88
- package/dist/commands/improve/preparation.js +1034 -813
- package/dist/commands/improve/proactive-maintenance.js +34 -9
- package/dist/commands/improve/proposal-envelope.js +31 -0
- package/dist/commands/improve/reflect.js +983 -794
- package/dist/commands/improve/run-context.js +119 -0
- package/dist/commands/improve/salience.js +24 -127
- package/dist/commands/improve/session-asset.js +7 -3
- package/dist/commands/improve/shared.js +14 -34
- package/dist/commands/improve/source-identity.js +28 -0
- package/dist/commands/improve/triage.js +20 -17
- package/dist/commands/lint/base-linter.js +340 -313
- package/dist/commands/lint/env-key-rules.js +31 -47
- package/dist/commands/lint/index.js +185 -30
- package/dist/commands/{events.js → log.js} +28 -38
- package/dist/commands/migrate-cli.js +54 -0
- package/dist/commands/migration-tool.js +55 -0
- package/dist/commands/observability-cli.js +70 -208
- package/dist/commands/proposal/diff-format.js +50 -0
- package/dist/commands/proposal/drain-policies.js +0 -6
- package/dist/commands/proposal/drain.js +91 -40
- package/dist/commands/proposal/proposal-cli.js +134 -132
- package/dist/commands/proposal/proposal-types.js +56 -0
- package/dist/commands/proposal/proposal.js +83 -65
- package/dist/commands/proposal/propose-cli.js +88 -0
- package/dist/commands/proposal/propose.js +105 -88
- package/dist/commands/proposal/repository.js +1303 -278
- package/dist/commands/proposal/validators/proposal-quality-validators.js +16 -6
- package/dist/commands/proposal/validators/proposal-validators.js +61 -12
- package/dist/commands/proposal/validators/proposals.js +6 -8
- package/dist/commands/read/curate.js +78 -73
- package/dist/commands/read/knowledge.js +510 -13
- package/dist/commands/read/registry-search.js +2 -2
- package/dist/commands/read/remember-cli.js +84 -15
- package/dist/commands/read/search-cli.js +203 -96
- package/dist/commands/read/search.js +126 -94
- package/dist/commands/read/show.js +226 -250
- package/dist/commands/registry-cli.js +34 -60
- package/dist/commands/remember.js +18 -57
- package/dist/commands/sources/add-cli.js +104 -49
- package/dist/commands/sources/bundle-cli.js +166 -0
- package/dist/commands/sources/bundle-config-ops.js +63 -0
- package/dist/commands/sources/info.js +27 -15
- package/dist/commands/sources/init.js +30 -40
- package/dist/commands/sources/installed-stashes.js +469 -172
- package/dist/commands/sources/migration-help.js +7 -4
- package/dist/commands/sources/schema-repair.js +10 -9
- package/dist/commands/sources/self-update.js +182 -121
- package/dist/commands/sources/source-add.js +169 -178
- package/dist/commands/sources/source-clone.js +144 -41
- package/dist/commands/sources/source-manage.js +94 -59
- package/dist/commands/sources/sources-cli.js +64 -205
- package/dist/commands/sources/stash-cli.js +91 -54
- package/dist/commands/sources/stash-skeleton.js +1 -1
- package/dist/commands/tasks/tasks-cli.js +106 -104
- package/dist/commands/tasks/tasks.js +445 -262
- package/dist/commands/workflow-cli.js +232 -121
- package/dist/core/action-contributors.js +1 -1
- package/dist/core/activation-policy.js +49 -0
- package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
- package/dist/core/adapter/adapters/akm-adapter.js +528 -0
- package/dist/core/adapter/adapters/akm-lint.js +392 -0
- package/dist/core/adapter/adapters/akm-metadata.js +387 -0
- package/dist/core/adapter/adapters/akm-task-adapter.js +149 -0
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +180 -0
- package/dist/core/adapter/adapters/claude-adapter.js +61 -0
- package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
- package/dist/core/adapter/adapters/generic-files-adapter.js +119 -0
- package/dist/core/adapter/adapters/index.js +80 -0
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +419 -0
- package/dist/core/adapter/adapters/okf-adapter.js +391 -0
- package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
- package/dist/core/adapter/adapters/shared.js +286 -0
- package/dist/core/adapter/adapters/tool-dir-shared.js +217 -0
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +155 -0
- package/dist/core/adapter/bundle-adapter.js +4 -0
- package/dist/core/adapter/detect-adapter.js +17 -0
- package/dist/core/adapter/recognize-match.js +44 -0
- package/dist/core/adapter/registry.js +56 -0
- package/dist/core/adapter/types.js +4 -0
- package/dist/core/asset/akm-markdown.js +30 -0
- package/dist/core/asset/asset-placement.js +243 -0
- package/dist/core/asset/asset-ref.js +110 -79
- package/dist/core/asset/asset-serialize.js +20 -0
- package/dist/core/asset/frontmatter.js +28 -12
- package/dist/core/asset/markdown.js +40 -51
- package/dist/core/asset/resolve-ref.js +274 -0
- package/dist/core/asset/stash-meta.js +2 -2
- package/dist/core/bundle-id.js +51 -0
- package/dist/core/common.js +281 -86
- package/dist/core/config/config-io.js +42 -128
- package/dist/core/config/config-schema.js +233 -834
- package/dist/core/config/config-sources.js +162 -39
- package/dist/core/config/config-types.js +16 -11
- package/dist/core/config/config-version.js +29 -0
- package/dist/core/config/config-walker.js +126 -37
- package/dist/core/config/config.js +154 -331
- package/dist/core/config/deep-merge.js +41 -0
- package/dist/core/config/engine-semantics.js +28 -0
- package/dist/core/config/experimental.js +21 -0
- package/dist/core/config/schema/embedding.js +38 -0
- package/dist/core/config/schema/engines.js +116 -0
- package/dist/core/config/schema/experimental.js +47 -0
- package/dist/core/config/schema/feedback.js +31 -0
- package/dist/core/config/schema/improve-processes.js +389 -0
- package/dist/core/config/schema/improve.js +94 -0
- package/dist/core/config/schema/index-config.js +176 -0
- package/dist/core/config/schema/output.js +18 -0
- package/dist/core/config/schema/primitives.js +94 -0
- package/dist/core/config/schema/search.js +30 -0
- package/dist/core/config/schema/setup.js +18 -0
- package/dist/core/config/schema/sources-bundles.js +169 -0
- package/dist/core/config/schema/workflow.js +29 -0
- package/dist/core/env-secret-ref.js +155 -20
- package/dist/core/errors.js +17 -15
- package/dist/core/events-types.js +4 -0
- package/dist/core/events.js +46 -128
- package/dist/core/extra-params.js +62 -0
- package/dist/core/file-change.js +17 -0
- package/dist/core/file-lock.js +202 -57
- package/dist/core/fs-txn.js +392 -0
- package/dist/core/git-message.js +59 -0
- package/dist/core/improve-result.js +167 -0
- package/dist/core/json-schema.js +142 -0
- package/dist/core/lesson-lint.js +1 -17
- package/dist/core/logs-db.js +1 -1
- package/dist/core/maintenance-barrier.js +135 -0
- package/dist/core/migration-operation.js +44 -0
- package/dist/core/mutation-target.js +78 -0
- package/dist/core/paths.js +22 -25
- package/dist/core/platform.js +10 -0
- package/dist/core/recognition-util.js +128 -0
- package/dist/core/redaction.js +392 -0
- package/dist/core/standards/resolve-standards-context.js +36 -65
- package/dist/core/standards/resolve-stash-standards.js +2 -2
- package/dist/core/standards/resolve-type-conventions.js +5 -5
- package/dist/core/state/migrations.js +242 -11
- package/dist/core/state-db.js +98 -10
- package/dist/core/structured.js +1 -1
- package/dist/core/subprocess.js +303 -0
- package/dist/core/text-truncation.js +9 -5
- package/dist/core/time.js +20 -0
- package/dist/core/type-presentation.js +130 -0
- package/dist/core/warn.js +0 -3
- package/dist/core/write-source.js +834 -118
- package/dist/indexer/bundle-identity-guard.js +92 -0
- package/dist/indexer/db/graph-db.js +1 -25
- package/dist/indexer/db/llm-cache.js +1 -1
- package/dist/indexer/ensure-index.js +30 -9
- package/dist/indexer/graph/graph-boost.js +9 -30
- package/dist/indexer/graph/graph-extraction.js +41 -27
- package/dist/indexer/graph/graph-types.js +4 -0
- package/dist/indexer/index-writer-lock.js +93 -49
- package/dist/indexer/index-written-assets.js +100 -53
- package/dist/indexer/indexer.js +746 -329
- package/dist/indexer/init.js +18 -25
- package/dist/indexer/installations.js +142 -0
- package/dist/indexer/passes/dir-staleness.js +18 -10
- package/dist/indexer/passes/memory-inference.js +25 -15
- package/dist/indexer/passes/metadata.js +412 -243
- package/dist/indexer/scan/doc-to-entry.js +160 -0
- package/dist/indexer/scan/drain-dir.js +134 -0
- package/dist/indexer/search/db-search.js +292 -108
- package/dist/indexer/search/fts-query.js +64 -0
- package/dist/indexer/search/ranking-contributors.js +145 -25
- package/dist/indexer/search/ranking-types.js +4 -0
- package/dist/indexer/search/ranking.js +28 -71
- package/dist/indexer/search/search-attribution.js +67 -0
- package/dist/indexer/search/search-fields.js +18 -3
- package/dist/indexer/search/search-hit-enrichers.js +30 -40
- package/dist/indexer/search/search-source.js +157 -111
- package/dist/indexer/search/semantic-status.js +4 -1
- package/dist/indexer/usage/usage-events.js +10 -30
- package/dist/indexer/walk/file-context.js +3 -45
- package/dist/indexer/walk/matchers.js +42 -34
- package/dist/indexer/walk/path-resolver.js +11 -5
- package/dist/indexer/walk/walker.js +42 -14
- package/dist/integrations/agent/builder-shared.js +7 -0
- package/dist/integrations/agent/builders.js +5 -56
- package/dist/integrations/agent/config.js +3 -143
- package/dist/integrations/agent/detect.js +17 -2
- package/dist/integrations/agent/engine-resolution.js +231 -0
- package/dist/integrations/agent/index.js +1 -2
- package/dist/integrations/agent/model-aliases.js +16 -2
- package/dist/integrations/agent/profiles.js +36 -62
- package/dist/integrations/agent/prompts.js +46 -18
- package/dist/integrations/agent/runner-dispatch.js +93 -4
- package/dist/integrations/agent/runner.js +76 -208
- package/dist/integrations/agent/spawn.js +88 -196
- package/dist/integrations/harnesses/aider/agent-builder.js +114 -0
- package/dist/integrations/harnesses/aider/index.js +48 -0
- package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
- package/dist/integrations/harnesses/amazonq/agent-builder.js +147 -0
- package/dist/integrations/harnesses/amazonq/index.js +45 -0
- package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
- package/dist/integrations/harnesses/claude/agent-builder.js +46 -8
- package/dist/integrations/harnesses/claude/config-import.js +1 -3
- package/dist/integrations/harnesses/claude/index.js +24 -35
- package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
- package/dist/integrations/harnesses/claude/session-log.js +27 -75
- package/dist/integrations/harnesses/codex/agent-builder.js +138 -0
- package/dist/integrations/harnesses/codex/index.js +52 -0
- package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
- package/dist/integrations/harnesses/copilot/agent-builder.js +122 -0
- package/dist/integrations/harnesses/copilot/index.js +48 -0
- package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
- package/dist/integrations/harnesses/gemini/agent-builder.js +120 -0
- package/dist/integrations/harnesses/gemini/index.js +48 -0
- package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
- package/dist/integrations/harnesses/ids.js +24 -0
- package/dist/integrations/harnesses/index.js +54 -34
- package/dist/integrations/harnesses/opencode/agent-builder.js +23 -5
- package/dist/integrations/harnesses/opencode/config-import.js +1 -3
- package/dist/integrations/harnesses/opencode/index.js +14 -32
- package/dist/integrations/harnesses/opencode/session-log.js +67 -125
- package/dist/integrations/harnesses/opencode-sdk/harness.js +51 -0
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +681 -108
- package/dist/integrations/harnesses/openhands/agent-builder.js +128 -0
- package/dist/integrations/harnesses/openhands/index.js +48 -0
- package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
- package/dist/integrations/harnesses/pi/agent-builder.js +97 -0
- package/dist/integrations/harnesses/pi/index.js +45 -0
- package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
- package/dist/integrations/harnesses/shared.js +17 -0
- package/dist/integrations/harnesses/types.js +43 -32
- package/dist/integrations/lockfile.js +211 -24
- package/dist/integrations/session-logs/index.js +36 -39
- package/dist/integrations/session-logs/provider-base.js +113 -0
- package/dist/llm/client.js +182 -110
- package/dist/llm/embedders/deterministic.js +2 -2
- package/dist/llm/embedders/remote.js +21 -9
- package/dist/llm/feature-gate.js +17 -57
- package/dist/llm/graph-extract.js +12 -13
- package/dist/llm/index-passes.js +8 -42
- package/dist/llm/memory-infer.js +144 -1
- package/dist/llm/metadata-enhance.js +45 -30
- package/dist/llm/structured-call.js +16 -8
- package/dist/llm/usage-persist.js +30 -5
- package/dist/llm/usage-telemetry.js +59 -6
- package/dist/output/cli-hints.js +1 -2
- package/dist/output/command-registry.js +27 -0
- package/dist/output/context.js +22 -7
- package/dist/output/format-exempt.js +80 -0
- package/dist/output/generic-render.js +251 -0
- package/dist/output/html-render.js +11 -16
- package/dist/output/render-registry.js +57 -0
- package/dist/output/renderers.js +14 -279
- package/dist/output/shapes/curate.js +10 -1
- package/dist/output/shapes/events.js +12 -7
- package/dist/output/shapes/helpers.js +58 -84
- package/dist/output/shapes/passthrough.js +11 -39
- package/dist/output/shapes/proposal/producer.js +15 -7
- package/dist/output/shapes/registry.js +12 -6
- package/dist/output/shapes.js +0 -9
- package/dist/output/text/{init.js → bundle-create.js} +3 -1
- package/dist/output/text/bundle-show.js +7 -0
- package/dist/output/text/command-format.js +562 -0
- package/dist/output/text/env.js +1 -3
- package/dist/output/text/events.js +8 -7
- package/dist/output/text/helpers.js +15 -1164
- package/dist/output/text/proposal/producer.js +4 -2
- package/dist/output/text/proposal-format.js +202 -0
- package/dist/output/text/registry-commands.js +1 -2
- package/dist/output/text/registry.js +12 -6
- package/dist/output/text/show-directives.js +117 -0
- package/dist/output/text/show-format.js +103 -0
- package/dist/output/text/sync.js +5 -0
- package/dist/output/text/workflow-format.js +332 -0
- package/dist/output/text/workflow.js +3 -2
- package/dist/output/text.js +10 -19
- package/dist/registry/factory.js +4 -6
- package/dist/registry/origin-resolve.js +16 -27
- package/dist/registry/providers/skills-sh.js +3 -3
- package/dist/registry/providers/static-index.js +15 -25
- package/dist/registry/resolve.js +43 -94
- package/dist/registry/semver.js +43 -0
- package/dist/runtime.js +81 -12
- package/dist/scripts/akm-migrate.js +35529 -0
- package/dist/setup/detect.js +5 -7
- package/dist/setup/detected-engines.js +136 -0
- package/dist/setup/engine-config.js +100 -0
- package/dist/setup/registry-stash-loader.js +3 -3
- package/dist/setup/semantic-assets.js +12 -9
- package/dist/setup/setup.js +444 -208
- package/dist/setup/steps/connection-shared.js +120 -0
- package/dist/setup/steps/connection.js +108 -305
- package/dist/setup/steps/platforms.js +13 -12
- package/dist/setup/steps/semantic.js +15 -3
- package/dist/setup/steps/sources.js +21 -15
- package/dist/setup/steps/stashdir.js +6 -4
- package/dist/setup/steps/tasks.js +236 -119
- package/dist/setup/steps.js +3 -2
- package/dist/sources/freshness.js +39 -0
- package/dist/sources/provider-factory.js +11 -17
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +278 -34
- package/dist/sources/providers/git-provider.js +54 -56
- package/dist/sources/providers/git-stash.js +420 -91
- package/dist/sources/providers/git.js +2 -2
- package/dist/sources/providers/npm.js +16 -19
- package/dist/sources/providers/provider-utils.js +47 -22
- package/dist/sources/providers/sync-from-ref.js +3 -9
- package/dist/sources/providers/website.js +2 -2
- package/dist/sources/resolve.js +11 -10
- package/dist/sources/snapshot-fetchers/types.js +4 -0
- package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +110 -41
- package/dist/storage/database.js +60 -4
- package/dist/storage/engines/sqlite-migrations.js +156 -5
- package/dist/storage/locations.js +1 -2
- package/dist/storage/repositories/canaries-repository.js +1 -1
- package/dist/storage/repositories/events-repository.js +51 -11
- package/dist/storage/repositories/improve-runs-repository.js +6 -32
- package/dist/storage/repositories/index-connection.js +79 -0
- package/dist/storage/repositories/index-db.js +4 -3
- package/dist/storage/repositories/index-entries-repository.js +863 -0
- package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +19 -2
- package/dist/storage/repositories/index-entry-types.js +4 -0
- package/dist/storage/repositories/index-fts-repository.js +167 -0
- package/dist/storage/repositories/index-llm-cache-repository.js +108 -0
- package/dist/storage/repositories/index-meta-repository.js +49 -0
- package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +226 -100
- package/dist/storage/repositories/index-sql.js +12 -0
- package/dist/storage/repositories/index-utility-repository.js +356 -0
- package/dist/storage/repositories/index-vec-repository.js +250 -0
- package/dist/storage/repositories/outcome-repository.js +119 -0
- package/dist/storage/repositories/proposals-repository.js +317 -75
- package/dist/storage/repositories/registry-cache.js +1 -1
- package/dist/storage/repositories/salience-repository.js +172 -0
- package/dist/storage/repositories/task-history-repository.js +110 -3
- package/dist/storage/repositories/workflow-runs-repository.js +240 -19
- package/dist/tasks/backends/cron.js +169 -46
- package/dist/tasks/backends/exec-utils.js +76 -3
- package/dist/tasks/backends/index.js +6 -9
- package/dist/tasks/backends/launchd.js +292 -55
- package/dist/tasks/backends/schtasks.js +557 -70
- package/dist/tasks/backends/types.js +4 -0
- package/dist/tasks/command-executable.js +93 -0
- package/dist/tasks/embedded.js +56 -38
- package/dist/tasks/parser.js +156 -64
- package/dist/tasks/resolve-akm-bin.js +144 -51
- package/dist/tasks/runner.js +377 -209
- package/dist/tasks/schedule.js +108 -19
- package/dist/tasks/scheduler-invocation.js +296 -0
- package/dist/tasks/schema.js +1 -1
- package/dist/tasks/task-id.js +35 -0
- package/dist/tasks/validator.js +30 -16
- package/dist/text-import-hook.mjs +1 -1
- package/dist/workflows/authoring/authoring.js +104 -43
- package/dist/workflows/authoring/scope-key.js +1 -1
- package/dist/workflows/cli.js +0 -16
- package/dist/workflows/concurrency-policy.js +15 -0
- package/dist/workflows/exec/brief.js +450 -0
- package/dist/workflows/exec/frozen-judge.js +47 -0
- package/dist/workflows/exec/native-executor.js +1038 -0
- package/dist/workflows/exec/param-secrets.js +115 -0
- package/dist/workflows/exec/report.js +1460 -0
- package/dist/workflows/exec/run-workflow.js +602 -0
- package/dist/workflows/exec/scheduler.js +71 -0
- package/dist/workflows/exec/step-work.js +1190 -0
- package/dist/workflows/exec/unit-writer.js +23 -0
- package/dist/workflows/exec/workflow-engine-gate.js +67 -0
- package/dist/workflows/exec/worktree.js +171 -0
- package/dist/workflows/ir/compile.js +246 -0
- package/dist/workflows/ir/freeze.js +233 -0
- package/dist/workflows/ir/params.js +54 -0
- package/dist/workflows/ir/plan-hash.js +68 -0
- package/dist/workflows/ir/schema.js +540 -0
- package/dist/workflows/parser.js +878 -304
- package/dist/workflows/program/expressions.js +181 -0
- package/dist/workflows/program/schema.js +51 -0
- package/dist/workflows/renderer.js +100 -45
- package/dist/workflows/resource-limits.js +22 -0
- package/dist/workflows/runtime/agent-identity.js +59 -14
- package/dist/workflows/runtime/checkin.js +1 -1
- package/dist/workflows/runtime/plan-classifier.js +131 -0
- package/dist/workflows/runtime/runs.js +376 -119
- package/dist/workflows/runtime/unit-checkin.js +45 -0
- package/dist/workflows/runtime/unit-phases.js +20 -0
- package/dist/workflows/runtime/workflow-asset-loader.js +241 -40
- package/dist/workflows/schema.js +1 -11
- package/dist/workflows/validate-summary.js +2 -3
- package/dist/workflows/validator.js +52 -30
- package/docs/README.md +42 -78
- package/docs/migration/README.md +8 -0
- package/docs/migration/release-notes/0.6.0.md +1 -1
- package/docs/migration/release-notes/0.7.0.md +9 -8
- package/docs/migration/release-notes/0.9.0.md +158 -14
- package/docs/migration/v0.7-to-v0.8.md +46 -47
- package/docs/migration/v0.8-to-v0.9.md +844 -0
- package/docs/reference/README.md +12 -0
- package/docs/reference/data-and-telemetry.md +333 -0
- package/package.json +21 -17
- package/schemas/akm-asset-envelope.json +93 -0
- package/schemas/akm-config.json +4636 -0
- package/schemas/akm-task.json +87 -0
- package/schemas/akm-workflow.json +373 -0
- package/dist/akm-migrate-storage +0 -38
- package/dist/assets/help/help-accept.md +0 -12
- package/dist/assets/help/help-improve.md +0 -84
- package/dist/assets/help/help-proposals.md +0 -17
- package/dist/assets/help/help-propose.md +0 -17
- package/dist/assets/help/help-reject.md +0 -11
- package/dist/assets/profiles/frequent.json +0 -13
- package/dist/assets/profiles/recombine-only.json +0 -21
- package/dist/assets/profiles/reflect-distill.json +0 -30
- package/dist/assets/profiles/synthesize.json +0 -15
- package/dist/assets/prompts/procedural-system.md +0 -44
- package/dist/assets/prompts/recombine-system.md +0 -40
- package/dist/assets/prompts/staleness-detect-system.md +0 -6
- package/dist/assets/tasks/core/backup.yml +0 -4
- package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
- package/dist/assets/templates/html/default.html +0 -78
- package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
- package/dist/assets/wiki/index-template.md +0 -12
- package/dist/assets/wiki/ingest-workflow-template.md +0 -83
- package/dist/assets/wiki/log-template.md +0 -8
- package/dist/assets/wiki/schema-template.md +0 -61
- package/dist/cli/config-migrate.js +0 -150
- package/dist/cli/config-validate.js +0 -39
- package/dist/commands/graph/graph-cli.js +0 -124
- package/dist/commands/graph/graph.js +0 -487
- package/dist/commands/improve/calibration.js +0 -161
- package/dist/commands/improve/dedup.js +0 -482
- package/dist/commands/improve/extract-watch.js +0 -140
- package/dist/commands/improve/hot-probation.js +0 -45
- package/dist/commands/improve/improve-auto-accept.js +0 -276
- package/dist/commands/improve/improve-profiles.js +0 -168
- package/dist/commands/improve/procedural.js +0 -398
- package/dist/commands/improve/recombine.js +0 -818
- package/dist/commands/improve/schema-similarity-gate.js +0 -168
- package/dist/commands/lint/agent-linter.js +0 -44
- package/dist/commands/lint/command-linter.js +0 -44
- package/dist/commands/lint/default-linter.js +0 -16
- package/dist/commands/lint/fact-linter.js +0 -39
- package/dist/commands/lint/knowledge-linter.js +0 -16
- package/dist/commands/lint/memory-linter.js +0 -61
- package/dist/commands/lint/registry.js +0 -41
- package/dist/commands/lint/skill-linter.js +0 -45
- package/dist/commands/lint/task-linter.js +0 -50
- package/dist/commands/lint/workflow-linter.js +0 -81
- package/dist/commands/proposal/legacy-import.js +0 -115
- package/dist/commands/sources/history.js +0 -196
- package/dist/commands/tasks/default-tasks.js +0 -186
- package/dist/commands/wiki-cli.js +0 -292
- package/dist/core/asset/asset-registry.js +0 -76
- package/dist/core/asset/asset-spec.js +0 -259
- package/dist/core/config/config-migration.js +0 -602
- package/dist/core/deep-merge.js +0 -38
- package/dist/core/eval/rank-metrics.js +0 -113
- package/dist/core/ripgrep/install.js +0 -163
- package/dist/core/ripgrep/resolve.js +0 -81
- package/dist/indexer/db/db.js +0 -1413
- package/dist/indexer/manifest.js +0 -170
- package/dist/indexer/passes/metadata-contributors.js +0 -31
- package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -94
- package/dist/integrations/harnesses/opencode-sdk/index.js +0 -49
- package/dist/llm/call-ai.js +0 -62
- package/dist/llm/memory-infer-impl.js +0 -138
- package/dist/output/shapes/distill.js +0 -14
- package/dist/output/shapes/history.js +0 -11
- package/dist/output/text/distill.js +0 -6
- package/dist/output/text/enable-disable.js +0 -8
- package/dist/output/text/history.js +0 -6
- package/dist/output/text/wiki.js +0 -16
- package/dist/registry/build-index.js +0 -386
- package/dist/scripts/migrate-storage.js +0 -19108
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -9411
- package/dist/scripts/migrations/v16-to-v17.js +0 -141
- package/dist/setup/legacy-config.js +0 -106
- package/dist/storage/repositories/consolidation-repository.js +0 -38
- package/dist/storage/repositories/recombine-repository.js +0 -213
- package/dist/wiki/wiki-templates.js +0 -15
- package/dist/wiki/wiki.js +0 -1012
- package/dist/workflows/db.js +0 -215
- package/docs/data-and-telemetry.md +0 -226
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
package/dist/cli.js
CHANGED
|
@@ -2,28 +2,26 @@
|
|
|
2
2
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
3
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
4
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
-
// Runtime guard: akm-cli
|
|
6
|
-
// #560)
|
|
7
|
-
//
|
|
5
|
+
// Runtime guard: the akm-cli npm package bootstraps with Node.js >= 22
|
|
6
|
+
// (#465, #560), then its launcher prefers a working Bun >= 1.0 when available.
|
|
7
|
+
// The runtime boundary (src/runtime.ts, src/storage/database.ts) supports both.
|
|
8
|
+
// Under Node the CLI must be launched via the
|
|
8
9
|
// `dist/cli-node.mjs` wrapper, which registers the text-import loader hook
|
|
9
10
|
// before this module graph loads; running `node dist/cli.js` directly still
|
|
10
11
|
// works for code paths that touch no embedded text asset, but the wrapper is
|
|
11
|
-
// the supported entry. The hard floor is Node 20
|
|
12
|
+
// the supported entry. The hard floor is Node 22 (Node 20 support dropped 2026-07; `@clack/core` imports
|
|
12
13
|
// `node:util`'s `styleText` (added in Node 20.12) — Node 18 (EOL) throws at import.
|
|
13
14
|
{
|
|
14
15
|
const isBun = typeof globalThis.Bun !== "undefined";
|
|
15
16
|
if (!isBun) {
|
|
16
|
-
const [major = 0
|
|
17
|
-
|
|
18
|
-
.map((part) => Number.parseInt(part, 10) || 0);
|
|
19
|
-
const nodeOk = major > 20 || (major === 20 && (minor > 12 || (minor === 12 && patch >= 0)));
|
|
17
|
+
const [major = 0] = (process.versions.node ?? "0").split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
18
|
+
const nodeOk = major >= 22;
|
|
20
19
|
if (!nodeOk) {
|
|
21
|
-
console.error("\n ERROR: akm-cli
|
|
20
|
+
console.error("\n ERROR: the akm-cli npm package requires Node.js >= 22.\n" +
|
|
22
21
|
` Detected Node.js ${process.versions.node ?? "unknown"}.\n` +
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
" 3. Binary: curl -fsSL https://github.com/itlackey/akm/releases/latest/download/install.sh | bash\n");
|
|
22
|
+
" Bun >= 1.0 is optional for execution; it does not replace the Node.js bootstrap.\n" +
|
|
23
|
+
" Upgrade Node.js (https://nodejs.org), or install the runtime-free standalone binary:\n" +
|
|
24
|
+
" curl -fsSL https://github.com/itlackey/akm/releases/latest/download/install.sh | bash\n");
|
|
27
25
|
process.exit(1);
|
|
28
26
|
}
|
|
29
27
|
}
|
|
@@ -44,7 +42,7 @@ process.on("unhandledRejection", (reason) => {
|
|
|
44
42
|
}, null, 2));
|
|
45
43
|
if (process.env.AKM_DEBUG === "1" && err.stack)
|
|
46
44
|
console.error(err.stack);
|
|
47
|
-
process.exit(
|
|
45
|
+
process.exit(EXIT_CODES.INTERNAL);
|
|
48
46
|
});
|
|
49
47
|
process.on("uncaughtException", (err) => {
|
|
50
48
|
console.error(JSON.stringify({
|
|
@@ -55,92 +53,61 @@ process.on("uncaughtException", (err) => {
|
|
|
55
53
|
}, null, 2));
|
|
56
54
|
if (process.env.AKM_DEBUG === "1" && err.stack)
|
|
57
55
|
console.error(err.stack);
|
|
58
|
-
process.exit(
|
|
56
|
+
process.exit(EXIT_CODES.INTERNAL);
|
|
59
57
|
});
|
|
60
58
|
import fs from "node:fs";
|
|
61
|
-
import
|
|
62
|
-
import {
|
|
63
|
-
import {
|
|
64
|
-
import { EXIT_CODES, emitJsonError,
|
|
65
|
-
import { agentCommand, lintCommand
|
|
59
|
+
import { defineCommand, parseArgs, renderUsage, runCommand, showUsage } from "citty";
|
|
60
|
+
import { findCittyTopLevelCommand, findCittyTopLevelCommandIndex, getParsedInvocation, parseAllFlagValues, resolveHelpMigrateVersionArg, setParsedInvocation, } from "./cli/invocation.js";
|
|
61
|
+
import { retiredCommandHint } from "./cli/retired-commands.js";
|
|
62
|
+
import { defineGroupCommand, EXIT_CODES, emitJsonError, GLOBAL_OUTPUT_ARGS, output, runWithJsonErrors, } from "./cli/shared.js";
|
|
63
|
+
import { agentCommand, lintCommand } from "./commands/agent/contribute-cli.js";
|
|
66
64
|
import { generateBashCompletions, installBashCompletions } from "./commands/completions.js";
|
|
67
65
|
import { configCommand } from "./commands/config-cli.js";
|
|
68
66
|
import { envCommand } from "./commands/env/env-cli.js";
|
|
69
67
|
import { secretCommand } from "./commands/env/secret-cli.js";
|
|
70
68
|
import { feedbackCommand } from "./commands/feedback-cli.js";
|
|
71
|
-
import { graphCommand } from "./commands/graph/graph-cli.js";
|
|
72
69
|
import { akmHealth } from "./commands/health.js";
|
|
73
|
-
import
|
|
70
|
+
import "./commands/health/renderers.js";
|
|
74
71
|
import { parseWindowSpec } from "./commands/health/windows.js";
|
|
75
|
-
import { extractCommand } from "./commands/improve/extract-cli.js";
|
|
76
72
|
import { improveCommand } from "./commands/improve/improve-cli.js";
|
|
77
|
-
import {
|
|
73
|
+
import { migrateCommand } from "./commands/migrate-cli.js";
|
|
74
|
+
import { logCommand } from "./commands/observability-cli.js";
|
|
78
75
|
import { proposalCommand } from "./commands/proposal/proposal-cli.js";
|
|
79
76
|
import { rememberCommand } from "./commands/read/remember-cli.js";
|
|
80
77
|
import { curateCommand, searchCommand, showCommand } from "./commands/read/search-cli.js";
|
|
81
|
-
import { normalizeShowArgv } from "./commands/read/show.js";
|
|
82
78
|
import { registryCommand } from "./commands/registry-cli.js";
|
|
83
|
-
import {
|
|
79
|
+
import { bundleCommand } from "./commands/sources/bundle-cli.js";
|
|
84
80
|
import { renderMigrationHelp } from "./commands/sources/migration-help.js";
|
|
85
|
-
import { cloneCommand,
|
|
86
|
-
import { importKnowledgeCommand, indexCommand, infoCommand
|
|
87
|
-
import {
|
|
88
|
-
import { wikiCommand } from "./commands/wiki-cli.js";
|
|
81
|
+
import { cloneCommand, syncCommand, upgradeCommand } from "./commands/sources/sources-cli.js";
|
|
82
|
+
import { importKnowledgeCommand, indexCommand, infoCommand } from "./commands/sources/stash-cli.js";
|
|
83
|
+
import { taskCommand } from "./commands/tasks/tasks-cli.js";
|
|
89
84
|
import { workflowCommand } from "./commands/workflow-cli.js";
|
|
90
|
-
import {
|
|
91
|
-
import { loadConfig } from "./core/config/config.js";
|
|
85
|
+
import { DEFAULT_CONFIG, loadConfig } from "./core/config/config.js";
|
|
92
86
|
import { UsageError } from "./core/errors.js";
|
|
93
|
-
import {
|
|
87
|
+
import { assertNoPendingMigrationOperation } from "./core/migration-operation.js";
|
|
88
|
+
import { getConfigPath } from "./core/paths.js";
|
|
89
|
+
import { DURATION_UNITS, parseDuration } from "./core/time.js";
|
|
94
90
|
import { plainize } from "./core/tty.js";
|
|
95
91
|
import { info, isQuiet, setQuiet, setVerbose, warn } from "./core/warn.js";
|
|
96
|
-
import {
|
|
97
|
-
import {
|
|
92
|
+
import { disposeDispatchResources } from "./integrations/agent/runner-dispatch.js";
|
|
93
|
+
import { EMBEDDED_HINTS, EMBEDDED_HINTS_FULL } from "./output/cli-hints.js";
|
|
94
|
+
import { getOutputMode, initOutputMode, parseDetailLevel } from "./output/context.js";
|
|
95
|
+
import { isFormatExemptCommand } from "./output/format-exempt.js";
|
|
96
|
+
import { consumeSchedulerContextArg } from "./tasks/scheduler-invocation.js";
|
|
98
97
|
import { pkgVersion } from "./version.js";
|
|
99
98
|
function applyEarlyStderrFlags(argv) {
|
|
100
|
-
|
|
99
|
+
const separator = argv.indexOf("--");
|
|
100
|
+
const ownArgv = separator === -1 ? argv : argv.slice(0, separator);
|
|
101
|
+
if (ownArgv.includes("--quiet") || ownArgv.includes("-q")) {
|
|
101
102
|
setQuiet(true);
|
|
102
103
|
}
|
|
103
|
-
if (
|
|
104
|
+
if (ownArgv.includes("--verbose")) {
|
|
104
105
|
setVerbose(true);
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const parsedFormat = parseFlagValue(process.argv, "--format");
|
|
111
|
-
if (parsedFormat !== undefined &&
|
|
112
|
-
version === parsedFormat &&
|
|
113
|
-
wasHelpMigrateFlagValueConsumedAsVersion(version, parsedFormat, "--format")) {
|
|
114
|
-
return undefined;
|
|
115
|
-
}
|
|
116
|
-
const parsedDetail = parseFlagValue(process.argv, "--detail");
|
|
117
|
-
if (parsedDetail !== undefined &&
|
|
118
|
-
version === parsedDetail &&
|
|
119
|
-
wasHelpMigrateFlagValueConsumedAsVersion(version, parsedDetail, "--detail")) {
|
|
120
|
-
return undefined;
|
|
121
|
-
}
|
|
122
|
-
return version;
|
|
123
|
-
}
|
|
124
|
-
function wasHelpMigrateFlagValueConsumedAsVersion(version, flagValue, flagName) {
|
|
125
|
-
const argv = process.argv.slice(2);
|
|
126
|
-
const helpIndex = argv.indexOf("help");
|
|
127
|
-
const tokens = helpIndex >= 0 ? argv.slice(helpIndex + 1) : argv;
|
|
128
|
-
const migrateIndex = tokens.indexOf("migrate");
|
|
129
|
-
const relevant = migrateIndex >= 0 ? tokens.slice(migrateIndex + 1) : tokens;
|
|
130
|
-
let flagIndex = -1;
|
|
131
|
-
for (let i = 0; i < relevant.length; i += 1) {
|
|
132
|
-
const token = relevant[i];
|
|
133
|
-
if (token === flagName || token === `${flagName}=${flagValue}`) {
|
|
134
|
-
flagIndex = i;
|
|
135
|
-
break;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (flagIndex === -1)
|
|
139
|
-
return false;
|
|
140
|
-
if (relevant.slice(0, flagIndex).includes(version))
|
|
141
|
-
return false;
|
|
142
|
-
return relevant[flagIndex] === flagName ? relevant[flagIndex + 1] === version : true;
|
|
143
|
-
}
|
|
108
|
+
// resolveHelpMigrateVersionArg moved to ./cli/invocation (chunk-9 WI-9.9
|
|
109
|
+
// argv-normalization fold — it re-scanned process.argv, same as
|
|
110
|
+
// findCittyTopLevelCommand and parseAllFlagValues below).
|
|
144
111
|
/**
|
|
145
112
|
* Stderr-only human-friendly hint after a non-interactive `setup` invocation.
|
|
146
113
|
* Default --format is `json`, so a CI or piped consumer sees only the JSON on
|
|
@@ -160,10 +127,10 @@ function printSetupTtyHint(result) {
|
|
|
160
127
|
return;
|
|
161
128
|
if (isQuiet())
|
|
162
129
|
return;
|
|
163
|
-
if (!result?.
|
|
130
|
+
if (!result?.bundleDir)
|
|
164
131
|
return;
|
|
165
|
-
console.error(plainize(`\n✓
|
|
166
|
-
|
|
132
|
+
console.error(plainize(`\n✓ Bundle created at ${result.bundleDir}\n` +
|
|
133
|
+
' Next: `akm bundle add <source>`, `akm index`, `akm search "<query>"`, `akm help agents`'));
|
|
167
134
|
}
|
|
168
135
|
/**
|
|
169
136
|
* Module Naming:
|
|
@@ -178,9 +145,14 @@ const setupCommand = defineCommand({
|
|
|
178
145
|
description: "Interactive configuration wizard. Configures embeddings/LLM connections (for indexing/enrichment), agent profiles (CLI agent, embedded SDK, or none), sources, and registries. Shows which features are enabled at the end. Use --config <json> or --yes for non-interactive/scripting mode.",
|
|
179
146
|
},
|
|
180
147
|
args: {
|
|
148
|
+
// R-051/S11: `setup` is a raw `defineCommand` (not `defineJsonCommand`),
|
|
149
|
+
// so it does not get `GLOBAL_OUTPUT_ARGS` for free — same gap `health`
|
|
150
|
+
// already had. Three of its four run branches call `output()`; spreading
|
|
151
|
+
// this in is a `--help` visibility fix, not a behavior change.
|
|
152
|
+
...GLOBAL_OUTPUT_ARGS,
|
|
181
153
|
config: {
|
|
182
154
|
type: "string",
|
|
183
|
-
description: 'Config JSON to apply non-interactively, e.g. \'{"
|
|
155
|
+
description: 'Config JSON to apply non-interactively, e.g. \'{"engines":{"local":{"kind":"llm","endpoint":"...","model":"..."}},"defaults":{"llmEngine":"local"}}\'',
|
|
184
156
|
},
|
|
185
157
|
from: {
|
|
186
158
|
type: "string",
|
|
@@ -193,43 +165,29 @@ const setupCommand = defineCommand({
|
|
|
193
165
|
},
|
|
194
166
|
dir: {
|
|
195
167
|
type: "string",
|
|
196
|
-
description: "
|
|
168
|
+
description: "Bundle directory path (overrides defaultBundle in config or --config JSON)",
|
|
197
169
|
},
|
|
198
|
-
|
|
170
|
+
// Declared as the POSITIVE name with `default: true` so citty's native
|
|
171
|
+
// `--no-<name>` negation (it strips a leading `--no-` from ANY token and
|
|
172
|
+
// negates the remainder BEFORE consulting the declared-args table) does
|
|
173
|
+
// the work, matching the `sync --push/--no-push` pattern. A flag
|
|
174
|
+
// DECLARED as `no-init` can never be negated: `--no-init` parses as
|
|
175
|
+
// "negate `init`", a name nothing declared, leaving the real key at its
|
|
176
|
+
// default forever — see `search --no-project-context`'s identical fix.
|
|
177
|
+
init: {
|
|
199
178
|
type: "boolean",
|
|
200
|
-
default:
|
|
201
|
-
description: "
|
|
179
|
+
default: true,
|
|
180
|
+
description: "Scaffold the bundle directory. Use --no-init to write configuration without scaffolding it.",
|
|
202
181
|
},
|
|
203
|
-
|
|
204
|
-
type: "boolean",
|
|
205
|
-
default: false,
|
|
206
|
-
description: "Run environment detection only and print the result (no prompts, no writes). Pair with --format json.",
|
|
207
|
-
},
|
|
208
|
-
"reset-recommended": {
|
|
182
|
+
probe: {
|
|
209
183
|
type: "boolean",
|
|
210
184
|
default: false,
|
|
211
|
-
description: "
|
|
185
|
+
description: "Probe LLM/embedding endpoints before writing config to verify connectivity",
|
|
212
186
|
},
|
|
213
187
|
},
|
|
214
188
|
async run({ args }) {
|
|
215
189
|
await runWithJsonErrors(async () => {
|
|
216
|
-
const noInit =
|
|
217
|
-
const detectOnly = args["detect-only"];
|
|
218
|
-
const resetRecommended = args["reset-recommended"];
|
|
219
|
-
if (detectOnly) {
|
|
220
|
-
// Detection only: no prompts, no writes.
|
|
221
|
-
const { runDetectOnly } = await import("./setup/setup.js");
|
|
222
|
-
const detection = await runDetectOnly();
|
|
223
|
-
output("setup", detection);
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
if (resetRecommended) {
|
|
227
|
-
const { runResetRecommended } = await import("./setup/setup.js");
|
|
228
|
-
const result = await runResetRecommended({ dir: args.dir, noInit, probe: args.probe });
|
|
229
|
-
output("setup", result);
|
|
230
|
-
printSetupTtyHint(result);
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
190
|
+
const noInit = !args.init;
|
|
233
191
|
if (args.from && args.config) {
|
|
234
192
|
throw new UsageError("Pass either --from <file> or --config <json>, not both.", "INVALID_FLAG_VALUE");
|
|
235
193
|
}
|
|
@@ -286,8 +244,17 @@ const setupCommand = defineCommand({
|
|
|
286
244
|
},
|
|
287
245
|
});
|
|
288
246
|
const healthCommand = defineCommand({
|
|
289
|
-
meta: {
|
|
247
|
+
meta: {
|
|
248
|
+
name: "health",
|
|
249
|
+
description: "Check akm runtime health, artifacts, and improve metrics",
|
|
250
|
+
},
|
|
290
251
|
args: {
|
|
252
|
+
// R-051: `health` is a raw `defineCommand` (not `defineJsonCommand`), so
|
|
253
|
+
// it does not get `GLOBAL_OUTPUT_ARGS` for free. `--format`/`--detail`/
|
|
254
|
+
// `--shape`/`--output` already parsed correctly here (this command has
|
|
255
|
+
// no positional for a stray value to fall into), so this is purely a
|
|
256
|
+
// `--help` visibility / consistency fix, not a behavior change.
|
|
257
|
+
...GLOBAL_OUTPUT_ARGS,
|
|
291
258
|
since: {
|
|
292
259
|
type: "string",
|
|
293
260
|
description: "Rolling window start (ISO timestamp, date, epoch ms, or shorthand like 24h / 7d)",
|
|
@@ -304,95 +271,228 @@ const healthCommand = defineCommand({
|
|
|
304
271
|
type: "string",
|
|
305
272
|
description: "Explicit comparison window 'name=...,since=ISO,until=ISO' (repeatable, up to 4; mutually exclusive with --window-compare)",
|
|
306
273
|
},
|
|
307
|
-
|
|
308
|
-
type: "
|
|
309
|
-
description: "
|
|
274
|
+
report: {
|
|
275
|
+
type: "boolean",
|
|
276
|
+
description: "Fetch the full report dataset: per-run rows, trend deltas vs the prior window, and the pending proposal queue. Renders as the rich report under --format md/html and as complete data under any other format.",
|
|
277
|
+
default: false,
|
|
310
278
|
},
|
|
311
279
|
},
|
|
312
280
|
async run({ args }) {
|
|
313
281
|
let resultStatus;
|
|
282
|
+
const exitCodeBeforeRun = process.exitCode;
|
|
314
283
|
await runWithJsonErrors(async () => {
|
|
315
284
|
// citty only surfaces the last value of a repeated flag, so read --windows
|
|
316
285
|
// directly from argv to support multi-window comparison.
|
|
317
286
|
const rawWindows = parseAllFlagValues("--windows");
|
|
318
287
|
const windows = rawWindows.length > 0 ? rawWindows.map((raw) => parseWindowSpec(raw)) : undefined;
|
|
319
288
|
const groupBy = args["group-by"];
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
//
|
|
325
|
-
//
|
|
326
|
-
//
|
|
327
|
-
//
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
deltas,
|
|
344
|
-
});
|
|
345
|
-
deliverRendered(renderHtml(resolveTemplatePath("health"), replacements), mode.outputPath);
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
const result = akmHealth({
|
|
289
|
+
const report = args.report === true;
|
|
290
|
+
// `--report` is a DATA flag: it selects the richer read (per-run rows +
|
|
291
|
+
// window-compare deltas + the proposal queue) and nothing about the read
|
|
292
|
+
// depends on --format. The registered md/html renderers are pure
|
|
293
|
+
// functions of the result — a report-shaped result renders as the rich
|
|
294
|
+
// report, any other shape falls through to the generic rendering.
|
|
295
|
+
//
|
|
296
|
+
// The compare window defaults to the report's own `--since` window so the
|
|
297
|
+
// deltas are like-for-like (e.g. last 7d vs the prior 7d). A fixed 24h
|
|
298
|
+
// default made a `--since 7d` report compare its 7-day totals against a
|
|
299
|
+
// 24-hour prior window, producing meaningless deltas.
|
|
300
|
+
// Comparison-window precedence. An explicit `--window-compare` always
|
|
301
|
+
// wins. Otherwise `--report` seeds a like-for-like comparison from
|
|
302
|
+
// `--since`, but only when `--since` is a DURATION: `resolveWindowCompare`
|
|
303
|
+
// parses durations only, so feeding it an absolute date, ISO timestamp, or
|
|
304
|
+
// epoch value throws. And explicit `--windows` gets no implicit value at
|
|
305
|
+
// all — the two are mutually exclusive, so synthesizing one turned a valid
|
|
306
|
+
// invocation into a usage error.
|
|
307
|
+
const explicitWindows = windows !== undefined && windows.length > 0;
|
|
308
|
+
const sinceIsDuration = args.since !== undefined && parseDuration(args.since, DURATION_UNITS) !== null;
|
|
309
|
+
const implicitCompare = explicitWindows ? undefined : ((sinceIsDuration ? args.since : undefined) ?? "24h");
|
|
310
|
+
const windowCompare = report ? (args["window-compare"] ?? implicitCompare) : args["window-compare"];
|
|
311
|
+
const base = akmHealth({
|
|
349
312
|
since: args.since,
|
|
350
|
-
groupBy: groupBy,
|
|
351
|
-
windowCompare
|
|
313
|
+
groupBy: report ? "run" : groupBy,
|
|
314
|
+
windowCompare,
|
|
352
315
|
windows,
|
|
353
316
|
});
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
317
|
+
const reportCompare = windowCompare ??
|
|
318
|
+
(explicitWindows
|
|
319
|
+
? [...(base.windows ?? [])]
|
|
320
|
+
.sort((a, b) => new Date(a.since).getTime() - new Date(b.since).getTime())
|
|
321
|
+
.map((window) => window.name)
|
|
322
|
+
.join(" → ")
|
|
323
|
+
: undefined) ??
|
|
324
|
+
"24h";
|
|
325
|
+
resultStatus = base.status;
|
|
326
|
+
if (report) {
|
|
327
|
+
const { listPendingProposals } = await import("./commands/proposal/proposal.js");
|
|
328
|
+
const { computeAcceptRateBySource } = await import("./commands/health/accept-rate.js");
|
|
329
|
+
output("health", {
|
|
330
|
+
...base,
|
|
331
|
+
report: {
|
|
332
|
+
window: args.since ?? "24h",
|
|
333
|
+
compare: reportCompare,
|
|
334
|
+
comparisonMode: explicitWindows ? "custom" : "duration",
|
|
335
|
+
pendingProposals: listPendingProposals().map(({ ref, source, createdAt }) => ({ ref, source, createdAt })),
|
|
336
|
+
acceptRateBySource: computeAcceptRateBySource(),
|
|
337
|
+
},
|
|
338
|
+
});
|
|
339
|
+
return;
|
|
371
340
|
}
|
|
341
|
+
output("health", base);
|
|
372
342
|
});
|
|
343
|
+
// R-067: `emitJsonError` (src/cli/shared.ts) no longer force-exits on the
|
|
344
|
+
// error path — it sets `process.exitCode` and returns, so a `--report`
|
|
345
|
+
// failure thrown AFTER `resultStatus` was already assigned (e.g. the
|
|
346
|
+
// proposal-queue read above) would otherwise leave `resultStatus`
|
|
347
|
+
// populated here too. Skip the status-derived exit entirely once
|
|
348
|
+
// `runWithJsonErrors` has already recorded a classified failure, so it is
|
|
349
|
+
// never clobbered by a mismatched health status.
|
|
350
|
+
if (process.exitCode !== exitCodeBeforeRun)
|
|
351
|
+
return;
|
|
373
352
|
if (resultStatus === "fail") {
|
|
374
|
-
process.
|
|
353
|
+
process.exitCode = EXIT_GENERAL;
|
|
375
354
|
}
|
|
376
355
|
if (resultStatus === "warn") {
|
|
377
|
-
process.
|
|
356
|
+
process.exitCode = EXIT_HEALTH_WARN;
|
|
378
357
|
}
|
|
379
358
|
},
|
|
380
359
|
});
|
|
381
|
-
|
|
360
|
+
function loadAgentHints(full) {
|
|
361
|
+
return full ? EMBEDDED_HINTS_FULL : EMBEDDED_HINTS;
|
|
362
|
+
}
|
|
363
|
+
const hintsCommand = defineCommand({
|
|
364
|
+
meta: {
|
|
365
|
+
name: "hints",
|
|
366
|
+
description: "Print agent instructions on how to use akm — the complete guide by default; pass --detail brief for the short one",
|
|
367
|
+
},
|
|
368
|
+
args: {
|
|
369
|
+
detail: {
|
|
370
|
+
type: "string",
|
|
371
|
+
description: "Hints detail level (brief|normal|full). `brief` prints the short guide; `normal`/`full` print the complete guide.",
|
|
372
|
+
default: "normal",
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
run({ args }) {
|
|
376
|
+
return runWithJsonErrors(() => {
|
|
377
|
+
const detail = parseDetailLevel(args.detail) ?? "normal";
|
|
378
|
+
process.stdout.write(loadAgentHints(detail !== "brief"));
|
|
379
|
+
});
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
const completionsCommand = defineCommand({
|
|
383
|
+
meta: {
|
|
384
|
+
name: "completions",
|
|
385
|
+
description: "Generate or install shell completion script",
|
|
386
|
+
},
|
|
387
|
+
args: {
|
|
388
|
+
install: {
|
|
389
|
+
type: "boolean",
|
|
390
|
+
description: "Install completions to the appropriate directory",
|
|
391
|
+
default: false,
|
|
392
|
+
},
|
|
393
|
+
shell: {
|
|
394
|
+
type: "string",
|
|
395
|
+
description: "Shell type (bash)",
|
|
396
|
+
default: "bash",
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
run({ args }) {
|
|
400
|
+
// R-052(b): this was a bare `run()` throwing directly, so an unsupported
|
|
401
|
+
// `--shell` value escaped straight to citty's top-level error handling
|
|
402
|
+
// instead of the standard JSON envelope — exit 1 with a raw stack trace
|
|
403
|
+
// instead of the classified exit-2 usage error every other command
|
|
404
|
+
// produces (`completions` is format-exempt, so it stays a raw
|
|
405
|
+
// `defineCommand` rather than `defineJsonCommand`, but still needs the
|
|
406
|
+
// same error-classification wrapper other bare `defineCommand`s in this
|
|
407
|
+
// file use, e.g. `help migrate` below).
|
|
408
|
+
return runWithJsonErrors(() => {
|
|
409
|
+
if (args.shell !== "bash") {
|
|
410
|
+
throw new UsageError(`Unsupported shell: ${args.shell}. Only bash is supported.`);
|
|
411
|
+
}
|
|
412
|
+
const script = generateBashCompletions(main);
|
|
413
|
+
if (args.install) {
|
|
414
|
+
const dest = installBashCompletions(script);
|
|
415
|
+
info(`Completions installed to ${dest}`);
|
|
416
|
+
info(`Restart your shell or run: source ${dest}`);
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
process.stdout.write(script);
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
},
|
|
423
|
+
});
|
|
424
|
+
const commands = {
|
|
425
|
+
setup: setupCommand,
|
|
426
|
+
index: indexCommand,
|
|
427
|
+
health: healthCommand,
|
|
428
|
+
info: infoCommand,
|
|
429
|
+
bundle: bundleCommand,
|
|
430
|
+
upgrade: upgradeCommand,
|
|
431
|
+
search: searchCommand,
|
|
432
|
+
curate: curateCommand,
|
|
433
|
+
show: showCommand,
|
|
434
|
+
workflow: workflowCommand,
|
|
435
|
+
remember: rememberCommand,
|
|
436
|
+
import: importKnowledgeCommand,
|
|
437
|
+
sync: syncCommand,
|
|
438
|
+
clone: cloneCommand,
|
|
439
|
+
registry: registryCommand,
|
|
440
|
+
migrate: migrateCommand,
|
|
441
|
+
config: configCommand,
|
|
442
|
+
feedback: feedbackCommand,
|
|
443
|
+
log: logCommand,
|
|
444
|
+
agent: agentCommand,
|
|
445
|
+
lint: lintCommand,
|
|
446
|
+
improve: improveCommand,
|
|
447
|
+
proposal: proposalCommand,
|
|
448
|
+
completions: completionsCommand,
|
|
449
|
+
env: envCommand,
|
|
450
|
+
secret: secretCommand,
|
|
451
|
+
task: taskCommand,
|
|
452
|
+
hints: hintsCommand,
|
|
453
|
+
};
|
|
454
|
+
function commandHelpTopic(name, command) {
|
|
455
|
+
return defineCommand({
|
|
456
|
+
meta: { name, description: `Print help for akm ${name}` },
|
|
457
|
+
async run() {
|
|
458
|
+
await showUsage(command, buildUsageParentForPath([name]));
|
|
459
|
+
},
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
const commandHelpTopics = Object.fromEntries(Object.entries(commands)
|
|
463
|
+
.filter(([name]) => name !== "migrate")
|
|
464
|
+
.map(([name, command]) => [name, commandHelpTopic(name, command)]));
|
|
465
|
+
const helpCommand = defineGroupCommand({
|
|
382
466
|
meta: {
|
|
383
467
|
name: "help",
|
|
384
|
-
description: "Print
|
|
468
|
+
description: "Print the command overview, detailed help for a command, agent instructions, or a release's migration guidance",
|
|
385
469
|
},
|
|
386
470
|
subCommands: {
|
|
471
|
+
...commandHelpTopics,
|
|
472
|
+
agents: defineCommand({
|
|
473
|
+
meta: {
|
|
474
|
+
name: "agents",
|
|
475
|
+
description: "Print agent instructions on how to use akm — the short guide by default; pass --full for the complete guide",
|
|
476
|
+
},
|
|
477
|
+
args: {
|
|
478
|
+
full: {
|
|
479
|
+
type: "boolean",
|
|
480
|
+
default: false,
|
|
481
|
+
description: "Print the complete guide instead of the short one.",
|
|
482
|
+
},
|
|
483
|
+
},
|
|
484
|
+
run({ args }) {
|
|
485
|
+
return runWithJsonErrors(() => {
|
|
486
|
+
process.stdout.write(loadAgentHints(args.full === true));
|
|
487
|
+
});
|
|
488
|
+
},
|
|
489
|
+
}),
|
|
387
490
|
migrate: defineCommand({
|
|
388
491
|
meta: {
|
|
389
492
|
name: "migrate",
|
|
390
493
|
description: "Print release notes and migration guidance for a version. Bundled notes live in docs/migration/release-notes/<version>.md; an unknown version lists what's available.",
|
|
391
494
|
},
|
|
392
495
|
args: {
|
|
393
|
-
// Optional in citty so run() is invoked even when omitted; we
|
|
394
|
-
// re-validate below to surface a structured UsageError (exit 2)
|
|
395
|
-
// instead of citty's default help-banner exit-0.
|
|
396
496
|
version: {
|
|
397
497
|
type: "positional",
|
|
398
498
|
description: "Version to review (for example 0.6.0, v0.6.0, 0.6.0-rc1, or latest)",
|
|
@@ -410,123 +510,76 @@ const helpCommand = defineCommand({
|
|
|
410
510
|
},
|
|
411
511
|
}),
|
|
412
512
|
},
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
meta: {
|
|
416
|
-
name: "completions",
|
|
417
|
-
description: "Generate or install shell completion script",
|
|
418
|
-
},
|
|
419
|
-
args: {
|
|
420
|
-
install: {
|
|
421
|
-
type: "boolean",
|
|
422
|
-
description: "Install completions to the appropriate directory",
|
|
423
|
-
default: false,
|
|
424
|
-
},
|
|
425
|
-
shell: {
|
|
426
|
-
type: "string",
|
|
427
|
-
description: "Shell type (bash)",
|
|
428
|
-
default: "bash",
|
|
429
|
-
},
|
|
430
|
-
},
|
|
431
|
-
run({ args }) {
|
|
432
|
-
if (args.shell !== "bash") {
|
|
433
|
-
throw new UsageError(`Unsupported shell: ${args.shell}. Only bash is supported.`);
|
|
434
|
-
}
|
|
435
|
-
const script = generateBashCompletions(main);
|
|
436
|
-
if (args.install) {
|
|
437
|
-
const dest = installBashCompletions(script);
|
|
438
|
-
info(`Completions installed to ${dest}`);
|
|
439
|
-
info(`Restart your shell or run: source ${dest}`);
|
|
440
|
-
}
|
|
441
|
-
else {
|
|
442
|
-
process.stdout.write(script);
|
|
443
|
-
}
|
|
513
|
+
async defaultRun() {
|
|
514
|
+
process.stdout.write(`${await renderSectionedRootHelp()}\n`);
|
|
444
515
|
},
|
|
445
516
|
});
|
|
446
517
|
export const main = defineCommand({
|
|
447
518
|
meta: {
|
|
448
519
|
name: "akm",
|
|
449
520
|
version: pkgVersion,
|
|
450
|
-
description: "Agent Knowledge
|
|
521
|
+
description: "Agent Knowledge Manager — search, show, and manage assets from your bundle.\n\n" +
|
|
451
522
|
"Exit codes:\n" +
|
|
452
523
|
" 0 success\n" +
|
|
453
|
-
" 1
|
|
524
|
+
" 1 not found / command-reported failure\n" +
|
|
454
525
|
" 2 usage error\n" +
|
|
455
526
|
" 4 health warn (akm health only)\n" +
|
|
527
|
+
" 70 internal / unclassified error\n" +
|
|
456
528
|
" 78 config error",
|
|
457
529
|
},
|
|
458
530
|
args: {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
},
|
|
464
|
-
detail: {
|
|
465
|
-
type: "string",
|
|
466
|
-
description: "Detail level (verbosity): brief|normal|full. Default: brief.",
|
|
467
|
-
default: "brief",
|
|
468
|
-
},
|
|
469
|
-
shape: {
|
|
470
|
-
type: "string",
|
|
471
|
-
description: "Output projection: human|agent|summary. 'agent' trims to agent-essential fields; " +
|
|
472
|
-
"'summary' is only valid on 'akm show'. Default: human.",
|
|
473
|
-
},
|
|
474
|
-
quiet: {
|
|
475
|
-
type: "boolean",
|
|
476
|
-
alias: "q",
|
|
477
|
-
description: "Suppress non-essential stderr output (banners, spinners, progress info). " +
|
|
478
|
-
"Safety-critical output is never suppressed: errors, destructive-action confirmation prompts, " +
|
|
479
|
-
"and auto-migration banners always appear regardless of --quiet.",
|
|
480
|
-
default: false,
|
|
481
|
-
},
|
|
482
|
-
verbose: {
|
|
483
|
-
type: "boolean",
|
|
484
|
-
description: "Print per-spec diagnostics to stderr (also honours AKM_VERBOSE env var)",
|
|
485
|
-
default: false,
|
|
486
|
-
},
|
|
531
|
+
// Single-sourced from GLOBAL_OUTPUT_ARGS (src/cli/shared.ts) so root help
|
|
532
|
+
// and leaf help state identical text. format/detail get their `default`
|
|
533
|
+
// added here only — the description text itself is never redeclared.
|
|
534
|
+
...GLOBAL_OUTPUT_ARGS,
|
|
535
|
+
format: { ...GLOBAL_OUTPUT_ARGS.format, default: "json" },
|
|
536
|
+
detail: { ...GLOBAL_OUTPUT_ARGS.detail, default: "brief" },
|
|
487
537
|
},
|
|
488
538
|
subCommands: {
|
|
489
|
-
|
|
490
|
-
init: initCommand,
|
|
491
|
-
index: indexCommand,
|
|
492
|
-
health: healthCommand,
|
|
493
|
-
info: infoCommand,
|
|
494
|
-
graph: graphCommand,
|
|
495
|
-
add: addCommand,
|
|
496
|
-
list: listCommand,
|
|
497
|
-
remove: removeCommand,
|
|
498
|
-
update: updateCommand,
|
|
499
|
-
upgrade: upgradeCommand,
|
|
500
|
-
search: searchCommand,
|
|
501
|
-
curate: curateCommand,
|
|
502
|
-
show: showCommand,
|
|
503
|
-
workflow: workflowCommand,
|
|
504
|
-
remember: rememberCommand,
|
|
505
|
-
import: importKnowledgeCommand,
|
|
506
|
-
sync: syncCommand,
|
|
507
|
-
clone: cloneCommand,
|
|
508
|
-
registry: registryCommand,
|
|
509
|
-
config: configCommand,
|
|
510
|
-
feedback: feedbackCommand,
|
|
511
|
-
history: historyCommand,
|
|
512
|
-
log: logCommand,
|
|
513
|
-
lessons: lessonsCommand,
|
|
514
|
-
agent: agentCommand,
|
|
515
|
-
lint: lintCommand,
|
|
516
|
-
improve: improveCommand,
|
|
517
|
-
extract: extractCommand,
|
|
518
|
-
propose: proposeCommand,
|
|
519
|
-
proposal: proposalCommand,
|
|
539
|
+
...commands,
|
|
520
540
|
help: helpCommand,
|
|
521
|
-
hints: hintsCommand,
|
|
522
|
-
completions: completionsCommand,
|
|
523
|
-
env: envCommand,
|
|
524
|
-
secret: secretCommand,
|
|
525
|
-
wiki: wikiCommand,
|
|
526
|
-
tasks: tasksCommand,
|
|
527
541
|
},
|
|
528
542
|
});
|
|
529
543
|
const MAIN_TOP_LEVEL_ARGS = main.args;
|
|
544
|
+
function isTaskRunWithId(argv) {
|
|
545
|
+
const args = argv.slice(2);
|
|
546
|
+
const commandIndex = findCittyTopLevelCommandIndex(args, MAIN_TOP_LEVEL_ARGS);
|
|
547
|
+
const command = commandIndex >= 0 ? args[commandIndex] : undefined;
|
|
548
|
+
if (command !== "task")
|
|
549
|
+
return false;
|
|
550
|
+
const taskArgs = args.slice(commandIndex + 1);
|
|
551
|
+
if (taskArgs[0] !== "run")
|
|
552
|
+
return false;
|
|
553
|
+
const runCommand = taskCommand.subCommands?.run;
|
|
554
|
+
if (!runCommand?.args)
|
|
555
|
+
return false;
|
|
556
|
+
try {
|
|
557
|
+
const parsed = parseArgs(taskArgs.slice(1), runCommand.args);
|
|
558
|
+
return typeof parsed.id === "string" && parsed.id.length > 0;
|
|
559
|
+
}
|
|
560
|
+
catch {
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
/** Recovery/setup surfaces must remain reachable when config.json is invalid. */
|
|
565
|
+
export function shouldBypassConfigStartup(argv) {
|
|
566
|
+
const userArgs = argv.slice(2);
|
|
567
|
+
const separator = userArgs.indexOf("--");
|
|
568
|
+
const args = separator === -1 ? userArgs : userArgs.slice(0, separator);
|
|
569
|
+
if (args.includes("--help") || args.includes("-h") || args.includes("--version") || args.includes("-v"))
|
|
570
|
+
return true;
|
|
571
|
+
const commandIndex = findCittyTopLevelCommandIndex(args, MAIN_TOP_LEVEL_ARGS);
|
|
572
|
+
const command = commandIndex >= 0 ? args[commandIndex] : undefined;
|
|
573
|
+
if (command === "setup" || command === "migrate")
|
|
574
|
+
return true;
|
|
575
|
+
if (isTaskRunWithId(argv))
|
|
576
|
+
return true;
|
|
577
|
+
if (command !== "config")
|
|
578
|
+
return false;
|
|
579
|
+
const configIndex = args.indexOf("config");
|
|
580
|
+
const subcommand = args.slice(configIndex + 1).find((arg) => !arg.startsWith("-"));
|
|
581
|
+
return subcommand === "path";
|
|
582
|
+
}
|
|
530
583
|
// ── Exit codes ──────────────────────────────────────────────────────────────
|
|
531
584
|
// Canonical table lives in `src/cli/shared.ts` (EXIT_CODES). These aliases keep
|
|
532
585
|
// the local call sites terse. EXIT_HEALTH_WARN (4) is the `akm health` "warn"
|
|
@@ -534,21 +587,339 @@ const MAIN_TOP_LEVEL_ARGS = main.args;
|
|
|
534
587
|
// GENERAL (1) and USAGE (2). CI monitors can map: 0=pass, 4=warn, 1=fail.
|
|
535
588
|
const EXIT_GENERAL = EXIT_CODES.GENERAL;
|
|
536
589
|
const EXIT_HEALTH_WARN = EXIT_CODES.HEALTH_WARN;
|
|
537
|
-
//
|
|
538
|
-
// imported (e.g. by the in-process test harness in tests/_helpers/cli.ts),
|
|
539
|
-
// `import.meta.main` is false and we skip all startup side effects (argv
|
|
540
|
-
// mutation, output-mode init, index cleanup, banner, runMain) so importers
|
|
541
|
-
// can drive the `main` command themselves without the process exiting.
|
|
590
|
+
// ── Top-level driver (replaces citty's `runMain`) ───────────────────────────
|
|
542
591
|
//
|
|
543
|
-
//
|
|
544
|
-
//
|
|
545
|
-
//
|
|
546
|
-
//
|
|
547
|
-
//
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
592
|
+
// R-032: citty's own `runMain` catches EVERY error escaping `runCommand` —
|
|
593
|
+
// including its unexported `CLIError`, thrown for "Unknown command …", "No
|
|
594
|
+
// command specified.", "Missing required argument/positional …", and invalid
|
|
595
|
+
// enum values — and unconditionally calls `process.exit(1)`, regardless of
|
|
596
|
+
// error kind (node_modules/citty/dist/index.mjs). That collapsed usage
|
|
597
|
+
// mistakes (`akm totally-bogus`, `akm wiki list`, bare `akm log`) onto exit
|
|
598
|
+
// code 1 instead of the documented usage-error code 2 (STABILITY.md's
|
|
599
|
+
// exit-code table), and there is no way to override it from outside
|
|
600
|
+
// `runMain`'s own call frame: once it calls `process.exit`, nothing run
|
|
601
|
+
// afterward — including a `finally` further up the stack — gets a chance to
|
|
602
|
+
// execute. So the CLI drives citty's exported `runCommand` directly instead
|
|
603
|
+
// of `runMain`, replicating `runMain`'s `--help` / `--version`
|
|
604
|
+
// short-circuits and its CLIError → usage-banner rendering, but classifying
|
|
605
|
+
// a CLIError as USAGE (2) instead of GENERAL (1). Every other error escaping
|
|
606
|
+
// this boundary keeps the previous GENERAL (1) mapping — this only
|
|
607
|
+
// reclassifies the one error family citty itself throws before any of our
|
|
608
|
+
// own command bodies (and their `runWithJsonErrors` / `emitJsonError`
|
|
609
|
+
// classification) ever run.
|
|
610
|
+
const HELP_FLAGS = ["--help", "-h"];
|
|
611
|
+
const VERSION_FLAGS = ["--version", "-v"];
|
|
612
|
+
/**
|
|
613
|
+
* Duck-types citty's internal, unexported `CLIError`
|
|
614
|
+
* (node_modules/citty/dist/index.mjs) — the class `runCommand` throws for
|
|
615
|
+
* "Unknown command …", "No command specified.", "Missing required
|
|
616
|
+
* argument/positional …", and invalid enum values. citty does not export
|
|
617
|
+
* this class, so `instanceof` isn't available; `name` is set in its
|
|
618
|
+
* constructor (`this.name = "CLIError"`) and is stable across the pinned
|
|
619
|
+
* `citty@^0.2.2` dependency.
|
|
620
|
+
*/
|
|
621
|
+
function isCittyCliError(error) {
|
|
622
|
+
return error instanceof Error && error.name === "CLIError";
|
|
623
|
+
}
|
|
624
|
+
function findCittySubCommandByName(subCommands, name) {
|
|
625
|
+
if (name in subCommands)
|
|
626
|
+
return subCommands[name];
|
|
627
|
+
for (const sub of Object.values(subCommands)) {
|
|
628
|
+
const alias = sub.meta?.alias;
|
|
629
|
+
const aliases = Array.isArray(alias) ? alias : alias ? [alias] : [];
|
|
630
|
+
if (aliases.includes(name))
|
|
631
|
+
return sub;
|
|
632
|
+
}
|
|
633
|
+
return undefined;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Re-implementation of citty's own (unexported) `resolveSubCommand`: walks
|
|
637
|
+
* `rawArgs` down the subcommand tree the same way its private
|
|
638
|
+
* `findSubCommandIndex` / `_findSubCommand` do, so an explicit `--help`
|
|
639
|
+
* renders the deepest command the user was actually invoking, matching what
|
|
640
|
+
* citty's own `runMain` would have shown.
|
|
641
|
+
*/
|
|
642
|
+
function resolveDeepestCittyCommand(cmd, rawArgs) {
|
|
643
|
+
const subCommands = cmd.subCommands;
|
|
644
|
+
if (subCommands && Object.keys(subCommands).length > 0) {
|
|
645
|
+
const idx = findCittyTopLevelCommandIndex(rawArgs, (cmd.args ?? {}));
|
|
646
|
+
const name = idx >= 0 ? rawArgs[idx] : undefined;
|
|
647
|
+
if (name !== undefined) {
|
|
648
|
+
const sub = findCittySubCommandByName(subCommands, name);
|
|
649
|
+
if (sub)
|
|
650
|
+
return resolveDeepestCittyCommand(sub, rawArgs.slice(idx + 1));
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
return cmd;
|
|
654
|
+
}
|
|
655
|
+
function resolveCittyCommandPath(cmd, rawArgs, path = []) {
|
|
656
|
+
const subCommands = cmd.subCommands;
|
|
657
|
+
if (!subCommands || Object.keys(subCommands).length === 0)
|
|
658
|
+
return [...path];
|
|
659
|
+
const index = findCittyTopLevelCommandIndex(rawArgs, (cmd.args ?? {}));
|
|
660
|
+
const token = index >= 0 ? rawArgs[index] : undefined;
|
|
661
|
+
if (token === undefined)
|
|
662
|
+
return [...path];
|
|
663
|
+
const sub = findCittySubCommandByName(subCommands, token);
|
|
664
|
+
if (!sub)
|
|
665
|
+
return [...path];
|
|
666
|
+
const name = Object.entries(subCommands).find(([, candidate]) => candidate === sub)?.[0] ?? token;
|
|
667
|
+
return resolveCittyCommandPath(sub, rawArgs.slice(index + 1), [...path, name]);
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* `showUsage`/`renderUsage` (citty) render a subcommand's own USAGE line as
|
|
671
|
+
* `${parentMeta.name} ${cmdMeta.name}` using only the DIRECT parent — for a
|
|
672
|
+
* two-deep command (`akm task run`) that renders `task run`, silently
|
|
673
|
+
* dropping the `akm ` root prefix every top-level command's `--help` already
|
|
674
|
+
* shows. Building a synthetic parent whose `meta.name` is the full prefix
|
|
675
|
+
* (`akm task`) fixes it for any depth without patching the vendored
|
|
676
|
+
* dependency (S11 item 4).
|
|
677
|
+
*/
|
|
678
|
+
function buildUsageParentForPath(path) {
|
|
679
|
+
// `version` carries through too — citty's renderUsage falls back to
|
|
680
|
+
// `parentMeta.version` when the resolved command itself declares none
|
|
681
|
+
// (true of every subcommand here), and the real parent it substitutes for
|
|
682
|
+
// always resolves to `main`, which does declare one.
|
|
683
|
+
return {
|
|
684
|
+
meta: {
|
|
685
|
+
name: ["akm", ...path.slice(0, -1)].join(" "),
|
|
686
|
+
version: pkgVersion,
|
|
687
|
+
},
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
// ── Sectioned root help (S11) ────────────────────────────────────────────────
|
|
691
|
+
//
|
|
692
|
+
// citty's own generated COMMANDS list is a flat, unordered dump of every
|
|
693
|
+
// top-level command — fine for a handful of commands, not for the ~28 this
|
|
694
|
+
// CLI has grown to. Groups them instead under fixed sections mirroring
|
|
695
|
+
// how they're actually used, reusing citty's own `renderUsage` for the
|
|
696
|
+
// banner/USAGE/OPTIONS portion (so it stays byte-identical to every
|
|
697
|
+
// subcommand's own `--help`) and replacing only the COMMANDS section.
|
|
698
|
+
const HELP_SECTIONS = [
|
|
699
|
+
{
|
|
700
|
+
title: "AGENT LOOP",
|
|
701
|
+
commands: ["curate", "search", "show", "feedback", "remember"],
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
title: "ASSETS",
|
|
705
|
+
commands: ["import", "clone", "bundle", "env", "secret", "sync", "proposal"],
|
|
706
|
+
},
|
|
707
|
+
{ title: "AUTOMATION", commands: ["improve", "agent", "workflow", "task"] },
|
|
708
|
+
{
|
|
709
|
+
title: "SYSTEM",
|
|
710
|
+
commands: [
|
|
711
|
+
"setup",
|
|
712
|
+
"index",
|
|
713
|
+
"lint",
|
|
714
|
+
"health",
|
|
715
|
+
"config",
|
|
716
|
+
"registry",
|
|
717
|
+
"info",
|
|
718
|
+
"log",
|
|
719
|
+
"help",
|
|
720
|
+
"hints",
|
|
721
|
+
"upgrade",
|
|
722
|
+
"completions",
|
|
723
|
+
],
|
|
724
|
+
},
|
|
725
|
+
];
|
|
726
|
+
/** Abbreviations whose trailing period does not end a sentence. */
|
|
727
|
+
const NON_TERMINAL_ABBREVIATIONS = ["e.g.", "i.e.", "etc.", "vs."];
|
|
728
|
+
/**
|
|
729
|
+
* First sentence of a description, for the root command list.
|
|
730
|
+
*
|
|
731
|
+
* Several commands carry multi-paragraph descriptions that are correct on
|
|
732
|
+
* `akm <cmd> --help` but turn the root listing back into the undifferentiated
|
|
733
|
+
* wall this section replaced (a single command's description ran past 1k
|
|
734
|
+
* characters on one row).
|
|
735
|
+
*/
|
|
736
|
+
function firstSentence(text) {
|
|
737
|
+
const line = text.split("\n", 1)[0]?.trim() ?? "";
|
|
738
|
+
for (let i = 0; i < line.length; i++) {
|
|
739
|
+
if (line[i] !== "." && line[i] !== "!" && line[i] !== "?")
|
|
740
|
+
continue;
|
|
741
|
+
const candidate = line.slice(0, i + 1);
|
|
742
|
+
const next = line[i + 1];
|
|
743
|
+
if (next !== undefined && next !== " ")
|
|
744
|
+
continue;
|
|
745
|
+
if (NON_TERMINAL_ABBREVIATIONS.some((abbr) => candidate.toLowerCase().endsWith(abbr)))
|
|
746
|
+
continue;
|
|
747
|
+
return candidate;
|
|
748
|
+
}
|
|
749
|
+
return line;
|
|
750
|
+
}
|
|
751
|
+
function topLevelCommandDescription(name) {
|
|
752
|
+
const sub = main.subCommands?.[name];
|
|
753
|
+
return firstSentence(sub?.meta?.description ?? "");
|
|
754
|
+
}
|
|
755
|
+
function formatCommandRows(names) {
|
|
756
|
+
const width = Math.max(...names.map((name) => name.length));
|
|
757
|
+
return names.map((name) => ` ${name.padEnd(width)} ${topLevelCommandDescription(name)}`).join("\n");
|
|
758
|
+
}
|
|
759
|
+
function renderCommandSections() {
|
|
760
|
+
return HELP_SECTIONS.map(({ title, commands }) => `${title}\n${formatCommandRows(commands)}`).join("\n\n");
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Sectioned replacement for citty's root COMMANDS list (S11 item 1). Reuses
|
|
764
|
+
* `renderUsage(main)` for the banner + exit-code table (kept verbatim) +
|
|
765
|
+
* USAGE line + global OPTIONS, then cuts the string before citty's own
|
|
766
|
+
* "COMMANDS" heading (present because `main` has `subCommands`) and appends
|
|
767
|
+
* the grouped sections plus a one-line bundle/ref-grammar tagline and the
|
|
768
|
+
* `akm help agents` pointer.
|
|
769
|
+
*/
|
|
770
|
+
async function renderSectionedRootHelp() {
|
|
771
|
+
const base = await renderUsage(main, undefined);
|
|
772
|
+
const commandsHeadingIndex = base.indexOf("COMMANDS");
|
|
773
|
+
// Cut at the START of the heading's own line, not the word itself — the
|
|
774
|
+
// word is preceded by citty's own ANSI bold/underline escape codes, and
|
|
775
|
+
// slicing mid-line would leave a dangling open escape sequence.
|
|
776
|
+
const cutIndex = commandsHeadingIndex === -1 ? -1 : base.lastIndexOf("\n", commandsHeadingIndex);
|
|
777
|
+
const head = (cutIndex === -1 ? base : base.slice(0, cutIndex)).replace(/\n+$/, "");
|
|
778
|
+
const epilogue = [
|
|
779
|
+
'A "bundle" is your managed directory of assets (skills, agents, memories, workflows, ...). Refs use the ' +
|
|
780
|
+
"grammar [bundle//]conceptId[#fragment], where the concept id is the bundle's own path for the asset — " +
|
|
781
|
+
"e.g. `akm show skills/deploy`, or `akm show work//skills/deploy` for a named bundle. Copy ids from " +
|
|
782
|
+
"`akm search` output rather than synthesizing them.",
|
|
783
|
+
"",
|
|
784
|
+
"Run `akm help <command>` or `akm <command> --help` for details on any command.",
|
|
785
|
+
"Agents: run `akm hints` for the complete guide or `akm help agents` for the short guide.",
|
|
786
|
+
].join("\n");
|
|
787
|
+
return [head, "", renderCommandSections(), "", epilogue].join("\n");
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Walk down the subcommand tree the same way {@link resolveDeepestCittyCommand}
|
|
791
|
+
* does, but stop and report the first token that fails to resolve instead of
|
|
792
|
+
* silently giving up — the attempted spelling plus its sibling candidate set,
|
|
793
|
+
* for the did-you-mean suggestion below. Returns undefined when every token
|
|
794
|
+
* resolved (e.g. "no command specified", or a missing positional/flag on an
|
|
795
|
+
* otherwise-valid command) — there is no unknown NAME to suggest a fix for.
|
|
796
|
+
*/
|
|
797
|
+
function findUnknownCommandAttempt(rawArgs) {
|
|
798
|
+
let cmd = main;
|
|
799
|
+
let args = rawArgs;
|
|
800
|
+
const parentPath = [];
|
|
801
|
+
for (;;) {
|
|
802
|
+
const subCommands = cmd.subCommands;
|
|
803
|
+
if (!subCommands || Object.keys(subCommands).length === 0)
|
|
804
|
+
return undefined;
|
|
805
|
+
const idx = findCittyTopLevelCommandIndex(args, (cmd.args ?? {}));
|
|
806
|
+
const token = idx >= 0 ? args[idx] : undefined;
|
|
807
|
+
if (token === undefined)
|
|
808
|
+
return undefined;
|
|
809
|
+
const sub = findCittySubCommandByName(subCommands, token);
|
|
810
|
+
if (!sub)
|
|
811
|
+
return {
|
|
812
|
+
attempted: token,
|
|
813
|
+
candidates: Object.keys(subCommands),
|
|
814
|
+
parentPath,
|
|
815
|
+
};
|
|
816
|
+
parentPath.push(token);
|
|
817
|
+
cmd = sub;
|
|
818
|
+
args = args.slice(idx + 1);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* Standard edit-distance DP, single-row-at-a-time (sizes here are always
|
|
823
|
+
* short command-name strings). Builds each row left-to-right, appending as
|
|
824
|
+
* it goes, so every index read below is already-populated — the `?? 0`
|
|
825
|
+
* fallbacks only satisfy `noUncheckedIndexedAccess`, they never fire.
|
|
826
|
+
*/
|
|
827
|
+
function levenshteinDistance(a, b) {
|
|
828
|
+
let previousRow = Array.from({ length: b.length + 1 }, (_, j) => j);
|
|
829
|
+
for (let i = 1; i <= a.length; i++) {
|
|
830
|
+
const currentRow = [i];
|
|
831
|
+
for (let j = 1; j <= b.length; j++) {
|
|
832
|
+
const substitutionCost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
833
|
+
const deletion = (previousRow[j] ?? 0) + 1;
|
|
834
|
+
const insertion = (currentRow[j - 1] ?? 0) + 1;
|
|
835
|
+
const substitution = (previousRow[j - 1] ?? 0) + substitutionCost;
|
|
836
|
+
currentRow.push(Math.min(deletion, insertion, substitution));
|
|
837
|
+
}
|
|
838
|
+
previousRow = currentRow;
|
|
839
|
+
}
|
|
840
|
+
return previousRow[b.length] ?? 0;
|
|
841
|
+
}
|
|
842
|
+
/** Closest candidate within a length-scaled distance threshold, or undefined when nothing is close enough to be worth suggesting. */
|
|
843
|
+
function closestCommandMatch(attempted, candidates) {
|
|
844
|
+
let best;
|
|
845
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
846
|
+
for (const candidate of candidates) {
|
|
847
|
+
const distance = levenshteinDistance(attempted, candidate);
|
|
848
|
+
if (distance < bestDistance) {
|
|
849
|
+
bestDistance = distance;
|
|
850
|
+
best = candidate;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
const threshold = Math.max(2, Math.ceil(attempted.length / 2));
|
|
854
|
+
return best !== undefined && bestDistance <= threshold ? best : undefined;
|
|
855
|
+
}
|
|
856
|
+
const CLI_HELP_POINTER = "Run `akm --help` for usage.";
|
|
857
|
+
/**
|
|
858
|
+
* citty's `CLIError` carries its own stable `.code` (not exported in its
|
|
859
|
+
* types, but present on every instance — see {@link isCittyCliError}'s doc
|
|
860
|
+
* comment): `E_UNKNOWN_COMMAND` for an unrecognized command/subcommand name,
|
|
861
|
+
* `EARG`/`E_NO_COMMAND` for a missing required argument/positional or a bare
|
|
862
|
+
* group with no `run`. Maps that to one of this CLI's own stable
|
|
863
|
+
* `UsageErrorCode`s so the reclassified error (below) carries a real code
|
|
864
|
+
* instead of the generic fallback.
|
|
865
|
+
*/
|
|
866
|
+
function cittyCliErrorUsageCode(error) {
|
|
867
|
+
switch (error.code) {
|
|
868
|
+
case "E_UNKNOWN_COMMAND":
|
|
869
|
+
return "UNKNOWN_COMMAND";
|
|
870
|
+
case "EARG":
|
|
871
|
+
case "E_NO_COMMAND":
|
|
872
|
+
return "MISSING_REQUIRED_ARGUMENT";
|
|
873
|
+
default:
|
|
874
|
+
return "INVALID_FLAG_VALUE";
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Route a citty `CLIError` through the standard JSON envelope instead of
|
|
879
|
+
* citty's own usage-banner + raw `console.error(message)` (S11 item 3): the
|
|
880
|
+
* one-line diagnosis is the error's own message (e.g. "Unknown command
|
|
881
|
+
* foo"), and the hint is a short pointer — with a did-you-mean suggestion
|
|
882
|
+
* prepended when the unresolved token is close to a real sibling command —
|
|
883
|
+
* rather than the full ~46KB usage dump citty would otherwise print.
|
|
884
|
+
*/
|
|
885
|
+
function toUsageErrorFromCliError(error, rawArgs) {
|
|
886
|
+
const code = cittyCliErrorUsageCode(error);
|
|
887
|
+
const attempt = code === "UNKNOWN_COMMAND" ? findUnknownCommandAttempt(rawArgs) : undefined;
|
|
888
|
+
// Retired spellings from the 0.9 hard break get their replacement, not a
|
|
889
|
+
// did-you-mean: edit distance suggests the WRONG command for most of them
|
|
890
|
+
// (`init`→`info`, `update`→`upgrade`), and agents follow suggestions.
|
|
891
|
+
const retired = attempt ? retiredCommandHint(attempt.parentPath, attempt.attempted) : undefined;
|
|
892
|
+
const suggestion = retired === undefined && attempt ? closestCommandMatch(attempt.attempted, attempt.candidates) : undefined;
|
|
893
|
+
const hint = retired ?? (suggestion ? `Did you mean \`${suggestion}\`? ${CLI_HELP_POINTER}` : CLI_HELP_POINTER);
|
|
894
|
+
// citty colorizes error.message with ANSI escapes even when stdout/stderr
|
|
895
|
+
// is not a TTY. Strip them so the JSON envelope's `error` field is plain
|
|
896
|
+
// text instead of embedding raw escape sequences.
|
|
897
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: intentional — strip ANSI escape codes
|
|
898
|
+
const message = error.message.replace(/\x1b\[[0-9;]*m/g, "");
|
|
899
|
+
return new UsageError(message, code, hint);
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* The CLI's real startup sequence, extracted into a function so error paths
|
|
903
|
+
* can `return` early — top-level `return` is a syntax error in an ES module,
|
|
904
|
+
* and this used to rely on `emitJsonError`'s `never` return type (a
|
|
905
|
+
* synchronous `process.exit`) to stop execution instead. Now that
|
|
906
|
+
* `emitJsonError` (src/cli/shared.ts, R-067) only records `process.exitCode`
|
|
907
|
+
* and returns, every direct call site here needs its own explicit `return;`
|
|
908
|
+
* to stop the rest of startup from running after a fatal early error.
|
|
909
|
+
*/
|
|
910
|
+
async function runCli() {
|
|
911
|
+
try {
|
|
912
|
+
process.argv = consumeSchedulerContextArg(process.argv);
|
|
913
|
+
}
|
|
914
|
+
catch (error) {
|
|
915
|
+
emitJsonError(error);
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
// Mint the ParsedInvocation singleton from the (normalized) argv — the ONE
|
|
919
|
+
// place argv is parsed for the whole process (plan §10.7 / chunk-9 WI-9.9).
|
|
920
|
+
// Every out-of-cli.ts command module reads argv state through
|
|
921
|
+
// `getParsedInvocation()` from here on instead of re-scanning process.argv.
|
|
922
|
+
setParsedInvocation(process.argv);
|
|
552
923
|
// Resolve output mode once at startup from the (normalized) argv and persisted
|
|
553
924
|
// config. All subsequent output() calls read from this in-memory singleton.
|
|
554
925
|
// `initOutputMode` can throw a UsageError when --format/--detail values are
|
|
@@ -556,10 +927,14 @@ if (import.meta.main || process.env.AKM_NODE_ENTRY === "1") {
|
|
|
556
927
|
// rather than letting the raw exception escape with a stack trace.
|
|
557
928
|
try {
|
|
558
929
|
applyEarlyStderrFlags(process.argv);
|
|
559
|
-
|
|
930
|
+
if (isTaskRunWithId(process.argv))
|
|
931
|
+
assertNoPendingMigrationOperation();
|
|
932
|
+
const bypassConfig = shouldBypassConfigStartup(process.argv);
|
|
933
|
+
initOutputMode(process.argv, bypassConfig ? (DEFAULT_CONFIG.output ?? {}) : (loadConfig().output ?? {}));
|
|
560
934
|
}
|
|
561
935
|
catch (error) {
|
|
562
936
|
emitJsonError(error);
|
|
937
|
+
return;
|
|
563
938
|
}
|
|
564
939
|
// `--shape summary` is only meaningful on `akm show`. Reject it up front for
|
|
565
940
|
// every other command so a write command (e.g. `akm proposal accept …`)
|
|
@@ -567,23 +942,23 @@ if (import.meta.main || process.env.AKM_NODE_ENTRY === "1") {
|
|
|
567
942
|
// output-shaping time after the side effect has already happened. The
|
|
568
943
|
// shape-registry gate in shapeForCommand() remains as defense-in-depth (and
|
|
569
944
|
// covers the in-process test harness, which skips this startup block).
|
|
570
|
-
const
|
|
945
|
+
const commandPath = resolveCittyCommandPath(main, process.argv.slice(2));
|
|
946
|
+
const topLevelCommand = commandPath[0] ?? findCittyTopLevelCommand(process.argv.slice(2), MAIN_TOP_LEVEL_ARGS);
|
|
571
947
|
if (getOutputMode().shape === "summary" && topLevelCommand !== "show") {
|
|
572
948
|
emitJsonError(new UsageError("'--shape summary' is only valid on 'akm show'.", "INVALID_SHAPE_VALUE"));
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
// D7 — every command that renders through output() honours all six --format
|
|
952
|
+
// values. The declared exempt set (src/output/format-exempt.ts) does not
|
|
953
|
+
// render an envelope at all, so warn rather than pretend: silently ignoring
|
|
954
|
+
// the flag is what made the old md/html behaviour so hard to discover. A
|
|
955
|
+
// warning, not an error, because the flag is harmless here and scripts that
|
|
956
|
+
// pass --format globally to a mixed batch of commands should still work.
|
|
957
|
+
const invocation = getParsedInvocation();
|
|
958
|
+
if ((invocation.hasFlag("--format") || invocation.getFlagValue("--format") !== undefined) &&
|
|
959
|
+
isFormatExemptCommand(commandPath)) {
|
|
960
|
+
warn(`[output] '--format' has no effect on 'akm ${commandPath.join(" ")}' — its output is not a result envelope.`);
|
|
573
961
|
}
|
|
574
|
-
// One-time cleanup of stale 0.7.x index file at the old cache location.
|
|
575
|
-
// 0.8.0 moved the index to $XDG_DATA_HOME/akm/index.db (getDataDir()).
|
|
576
|
-
// If the old file exists at $XDG_CACHE_HOME/akm/index.db, remove it so the
|
|
577
|
-
// user isn't confused by a phantom DB. Best-effort; never fatal.
|
|
578
|
-
bestEffort(() => {
|
|
579
|
-
const oldIndexPath = path.join(getCacheDir(), "index.db");
|
|
580
|
-
if (fs.existsSync(oldIndexPath)) {
|
|
581
|
-
fs.rmSync(oldIndexPath, { force: true });
|
|
582
|
-
fs.rmSync(`${oldIndexPath}-shm`, { force: true });
|
|
583
|
-
fs.rmSync(`${oldIndexPath}-wal`, { force: true });
|
|
584
|
-
warn(`Cleaned up stale 0.7.x index from ${oldIndexPath}. Canonical path is now ${getDbPath()}.`);
|
|
585
|
-
}
|
|
586
|
-
}, "stale 0.7.x index cleanup is non-fatal");
|
|
587
962
|
// First-time-user breadcrumb: when run with no subcommand AND no config
|
|
588
963
|
// exists yet AND stderr is a TTY, print a friendly pointer to `akm setup`
|
|
589
964
|
// above citty's auto-generated usage block. Triggers only when stdin/stderr
|
|
@@ -608,5 +983,84 @@ if (import.meta.main || process.env.AKM_NODE_ENTRY === "1") {
|
|
|
608
983
|
}
|
|
609
984
|
console.error(plainize("👋 First time with akm? Run `akm setup` to get started.\n Docs: https://github.com/itlackey/akm#readme\n"));
|
|
610
985
|
})();
|
|
611
|
-
|
|
986
|
+
const rawArgs = process.argv.slice(2);
|
|
987
|
+
try {
|
|
988
|
+
if (rawArgs.length === 0) {
|
|
989
|
+
process.stdout.write(`${await renderSectionedRootHelp()}\n`);
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
// Mirrors citty's own builtin-flag short-circuit in `runMain` (main's own
|
|
993
|
+
// args never declare `help`/`h`/`version`/`v`, so both stay the fixed
|
|
994
|
+
// defaults citty would have computed too).
|
|
995
|
+
//
|
|
996
|
+
// Scan only akm's OWN arguments: everything after a literal `--` belongs to
|
|
997
|
+
// the child process (`akm env run <ref> -- tool --help`, `akm secret run
|
|
998
|
+
// <ref> -- tool -h`). Scanning the tail printed akm's usage and returned
|
|
999
|
+
// without ever launching the requested command.
|
|
1000
|
+
const passthroughAt = rawArgs.indexOf("--");
|
|
1001
|
+
const ownArgs = passthroughAt === -1 ? rawArgs : rawArgs.slice(0, passthroughAt);
|
|
1002
|
+
if (HELP_FLAGS.some((flag) => ownArgs.includes(flag))) {
|
|
1003
|
+
const resolved = resolveDeepestCittyCommand(main, rawArgs);
|
|
1004
|
+
if (resolved === main) {
|
|
1005
|
+
// Root `--help` (S11 item 1): the sectioned overview, not citty's
|
|
1006
|
+
// flat COMMANDS dump.
|
|
1007
|
+
process.stdout.write(`${await renderSectionedRootHelp()}\n`);
|
|
1008
|
+
}
|
|
1009
|
+
else {
|
|
1010
|
+
const path = resolveCittyCommandPath(main, rawArgs);
|
|
1011
|
+
await showUsage(resolved, buildUsageParentForPath(path));
|
|
1012
|
+
}
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
if (rawArgs.length === 1 && VERSION_FLAGS.includes(rawArgs[0])) {
|
|
1016
|
+
console.log(pkgVersion);
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
await runCommand(main, { rawArgs });
|
|
1020
|
+
}
|
|
1021
|
+
catch (error) {
|
|
1022
|
+
if (isCittyCliError(error)) {
|
|
1023
|
+
// R-032/S11: reclassify citty's own "unknown command" / "no command
|
|
1024
|
+
// specified" / "missing required argument" family as USAGE (2) and
|
|
1025
|
+
// route it through the SAME JSON envelope every other command's
|
|
1026
|
+
// failure uses (`emitJsonError`), rather than citty's own usage-banner
|
|
1027
|
+
// + raw `console.error(message)` — a one-line diagnosis plus a short
|
|
1028
|
+
// hint (with a did-you-mean suggestion when applicable), not a ~46KB
|
|
1029
|
+
// usage dump.
|
|
1030
|
+
emitJsonError(toUsageErrorFromCliError(error, rawArgs));
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
// Anything else escaping here is a genuinely unexpected failure outside
|
|
1034
|
+
// any command's own error handling — every command wraps its body in
|
|
1035
|
+
// `runWithJsonErrors`, `defineJsonCommand`, or `defineGroupCommand`, all
|
|
1036
|
+
// three of which route thrown errors through `emitJsonError` before they
|
|
1037
|
+
// could ever reach this boundary. Route it the same way rather than
|
|
1038
|
+
// hard-coding GENERAL(1): the CLI contract reserves 1 for general/not-found
|
|
1039
|
+
// and requires a non-`AkmError` throw to render the JSON failure envelope
|
|
1040
|
+
// with INTERNAL(70) (AGENTS.md "CLI Contract"), which is what lets
|
|
1041
|
+
// automation tell an internal defect apart from an ordinary failure.
|
|
1042
|
+
// `emitJsonError` classifies and sets `process.exitCode` itself.
|
|
1043
|
+
emitJsonError(error);
|
|
1044
|
+
}
|
|
1045
|
+
finally {
|
|
1046
|
+
await disposeDispatchResources();
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
// Only run the CLI when this module is the direct entry point. When it is
|
|
1050
|
+
// imported (e.g. by the in-process test harness in tests/_helpers/cli.ts),
|
|
1051
|
+
// `import.meta.main` is false and we skip all startup side effects (argv
|
|
1052
|
+
// mutation, output-mode init, index cleanup, banner, command dispatch) so
|
|
1053
|
+
// importers can drive the `main` command themselves without the process
|
|
1054
|
+
// exiting.
|
|
1055
|
+
//
|
|
1056
|
+
// Node path: this module carries a `#!/usr/bin/env bun` shebang and is launched
|
|
1057
|
+
// under Node via the `dist/cli-node.mjs` wrapper, which `import()`s this file
|
|
1058
|
+
// (so `import.meta.main` is false here even though the CLI is the real entry).
|
|
1059
|
+
// The wrapper sets `AKM_NODE_ENTRY=1` to opt into the startup block. Compiled
|
|
1060
|
+
// standalone binaries are the same shape: their entry is
|
|
1061
|
+
// `scripts/akm-standalone.ts` (which also embeds the akm-migrate tool), and it
|
|
1062
|
+
// sets `AKM_STANDALONE_ENTRY=1` before importing this file. The test harness
|
|
1063
|
+
// sets neither, so importing cli.ts under Bun stays inert as before.
|
|
1064
|
+
if (import.meta.main || process.env.AKM_NODE_ENTRY === "1" || process.env.AKM_STANDALONE_ENTRY === "1") {
|
|
1065
|
+
await runCli();
|
|
612
1066
|
}
|