akm-cli 0.9.0-rc.8 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1063 -44
- package/README.md +51 -25
- package/SECURITY.md +14 -1
- package/STABILITY.md +497 -0
- package/dist/akm +148 -35
- package/dist/{akm-migrate-storage → akm-migrate} +6 -9
- package/dist/assets/hints/cli-hints-full.md +223 -95
- package/dist/assets/hints/cli-hints-short.md +85 -22
- package/dist/assets/improve-strategies/default.json +1 -1
- package/dist/assets/improve-strategies/reflect-distill.json +1 -1
- package/dist/assets/prompts/memory-infer-user.md +2 -3
- package/dist/assets/stash-skeleton/README.md +6 -5
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +20 -9
- package/dist/assets/tasks/core/extract.yml +1 -1
- package/dist/assets/tasks/core/version-check.yml +1 -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 +1 -3
- package/dist/assets/workflows/workflow-template.md +32 -15
- package/dist/cli/invocation.js +40 -15
- package/dist/cli/parse-args.js +0 -22
- package/dist/cli/retired-commands.js +121 -0
- package/dist/cli/shared.js +154 -22
- package/dist/cli/unknown-flags.js +236 -0
- package/dist/cli-node.mjs +2 -1
- package/dist/cli.js +696 -258
- package/dist/commands/agent/agent-dispatch.js +14 -3
- package/dist/commands/agent/contribute-cli.js +73 -88
- package/dist/commands/completions.js +79 -22
- package/dist/commands/config-cli.js +17 -150
- package/dist/commands/env/env-cli.js +59 -143
- package/dist/commands/env/env.js +12 -163
- package/dist/commands/env/marker-path.js +6 -0
- package/dist/commands/env/secret-cli.js +36 -66
- package/dist/commands/env/secret.js +24 -57
- package/dist/commands/feedback-cli.js +141 -87
- package/dist/commands/health/accept-rate.js +58 -0
- package/dist/commands/health/advisories.js +3 -4
- package/dist/commands/health/checks.js +85 -23
- package/dist/commands/health/html-report.js +7 -10
- package/dist/commands/health/improve-metrics.js +25 -83
- package/dist/commands/health/md-report.js +5 -9
- package/dist/commands/health/metrics.js +62 -20
- package/dist/commands/health/renderers.js +47 -0
- package/dist/commands/health/report-view-model.js +4 -5
- package/dist/commands/health/stash-exposure.js +1 -1
- package/dist/commands/health/surfaces.js +3 -48
- package/dist/commands/health/task-runs.js +3 -67
- package/dist/commands/health/types-improve.js +7 -0
- package/dist/commands/health.js +99 -28
- package/dist/commands/improve/anti-collapse.js +2 -2
- package/dist/commands/improve/autonomy-gate.js +68 -0
- package/dist/commands/improve/collapse-detector.js +41 -40
- package/dist/commands/improve/consolidate/eligibility.js +1 -23
- package/dist/commands/improve/consolidate/merge.js +4 -0
- package/dist/commands/improve/consolidate.js +140 -1000
- package/dist/commands/improve/distill/promote-memory.js +12 -12
- package/dist/commands/improve/distill/quality-gate.js +6 -6
- package/dist/commands/improve/distill.js +58 -69
- package/dist/commands/improve/eligibility.js +105 -57
- package/dist/commands/improve/extract-cli.js +14 -133
- package/dist/commands/improve/improve-cli.js +98 -114
- package/dist/commands/improve/improve-result-file.js +1 -28
- package/dist/commands/improve/improve-strategies.js +8 -5
- package/dist/commands/improve/improve.js +128 -91
- package/dist/commands/improve/loop-stages.js +182 -20
- package/dist/commands/improve/memory/derived-ref.js +45 -43
- package/dist/commands/improve/memory/memory-belief.js +1 -1
- package/dist/commands/improve/memory/memory-contradiction-detect.js +4 -12
- package/dist/commands/improve/memory/memory-improve.js +6 -5
- package/dist/commands/improve/outcome-loop.js +22 -65
- package/dist/commands/improve/preparation.js +114 -123
- package/dist/commands/improve/proactive-maintenance.js +2 -5
- package/dist/commands/improve/reflect.js +56 -160
- package/dist/commands/improve/salience.js +11 -122
- package/dist/commands/improve/source-identity.js +10 -38
- package/dist/commands/lint/base-linter.js +20 -124
- package/dist/commands/lint/env-key-rules.js +31 -47
- package/dist/commands/lint/index.js +249 -43
- package/dist/commands/{events.js → log.js} +33 -38
- package/dist/commands/migrate-cli.js +92 -12
- package/dist/commands/migration-tool.js +46 -0
- package/dist/commands/observability-cli.js +70 -209
- package/dist/commands/proposal/drain.js +101 -29
- package/dist/commands/proposal/proposal-cli.js +76 -48
- package/dist/commands/proposal/proposal.js +54 -18
- package/dist/commands/proposal/propose-cli.js +88 -0
- package/dist/commands/proposal/propose.js +23 -15
- package/dist/commands/proposal/repository.js +701 -278
- package/dist/commands/proposal/validators/proposal-quality-validators.js +2 -8
- package/dist/commands/proposal/validators/proposal-validators.js +55 -7
- package/dist/commands/proposal/validators/proposals.js +4 -7
- package/dist/commands/read/curate.js +34 -53
- package/dist/commands/read/knowledge.js +150 -95
- package/dist/commands/read/registry-search.js +2 -2
- package/dist/commands/read/remember-cli.js +42 -15
- package/dist/commands/read/search-cli.js +180 -78
- package/dist/commands/read/search.js +58 -43
- package/dist/commands/read/show.js +197 -141
- package/dist/commands/registry-cli.js +12 -51
- package/dist/commands/remember.js +14 -57
- package/dist/commands/sources/add-cli.js +100 -31
- package/dist/commands/sources/bundle-cli.js +166 -0
- package/dist/commands/sources/bundle-config-ops.js +7 -2
- package/dist/commands/sources/info.js +18 -5
- package/dist/commands/sources/init.js +12 -12
- package/dist/commands/sources/installed-stashes.js +382 -98
- package/dist/commands/sources/schema-repair.js +3 -2
- package/dist/commands/sources/self-update.js +131 -38
- package/dist/commands/sources/source-add.js +72 -17
- package/dist/commands/sources/source-clone.js +129 -45
- package/dist/commands/sources/source-manage.js +43 -23
- package/dist/commands/sources/sources-cli.js +57 -208
- package/dist/commands/sources/stash-cli.js +46 -53
- package/dist/commands/tasks/tasks-cli.js +91 -97
- package/dist/commands/tasks/tasks.js +276 -421
- package/dist/commands/workflow-cli.js +175 -450
- package/dist/core/adapter/adapters/akm-adapter.js +47 -28
- package/dist/core/adapter/adapters/akm-lint.js +42 -27
- package/dist/core/adapter/adapters/akm-metadata.js +15 -44
- package/dist/core/adapter/adapters/akm-task-adapter.js +15 -13
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +55 -71
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +2 -0
- package/dist/core/adapter/adapters/index.js +6 -6
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +14 -8
- package/dist/core/adapter/adapters/okf-adapter.js +187 -19
- package/dist/core/adapter/adapters/shared.js +3 -19
- package/dist/core/adapter/adapters/tool-dir-shared.js +8 -3
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -0
- package/dist/core/adapter/detect-adapter.js +17 -0
- package/dist/core/adapter/recognize-match.js +6 -4
- package/dist/core/adapter/validate-context.js +214 -0
- package/dist/core/asset/akm-markdown.js +63 -0
- package/dist/core/asset/asset-placement.js +20 -6
- package/dist/core/asset/asset-ref.js +11 -9
- package/dist/core/asset/frontmatter-lint.js +30 -0
- package/dist/core/asset/frontmatter.js +37 -9
- package/dist/core/asset/markdown.js +40 -51
- package/dist/core/asset/resolve-ref.js +89 -18
- package/dist/core/asset/stash-meta.js +1 -1
- package/dist/core/bundle-id.js +51 -0
- package/dist/core/common.js +152 -38
- package/dist/core/config/config-io.js +12 -1
- package/dist/core/config/config-schema.js +35 -8
- package/dist/core/config/config-sources.js +55 -11
- package/dist/core/config/config-walker.js +25 -9
- package/dist/core/config/config.js +9 -48
- package/dist/core/config/experimental.js +21 -0
- package/dist/core/config/schema/embedding.js +5 -1
- package/dist/core/config/schema/experimental.js +30 -0
- package/dist/core/config/schema/improve-processes.js +0 -6
- package/dist/core/config/schema/improve.js +21 -3
- package/dist/core/config/schema/index-config.js +8 -15
- package/dist/core/config/schema/output.js +4 -1
- package/dist/core/config/schema/setup.js +9 -18
- package/dist/core/config/schema/sources-bundles.js +49 -33
- package/dist/core/config/schema/workflow.js +3 -3
- package/dist/core/env-secret-ref.js +76 -46
- package/dist/core/errors.js +18 -12
- package/dist/core/events.js +46 -128
- package/dist/core/file-change.js +6 -5
- package/dist/core/fs-txn.js +83 -7
- package/dist/core/git-message.js +2 -2
- package/dist/core/improve-result.js +1 -100
- package/dist/core/lesson-lint.js +1 -17
- package/dist/core/logs-db.js +2 -1
- package/dist/core/migration-operation.js +16 -0
- package/dist/core/mutation-target.js +78 -0
- package/dist/core/parse.js +4 -1
- package/dist/core/paths.js +17 -20
- package/dist/core/recognition-util.js +12 -14
- package/dist/core/redaction.js +34 -0
- package/dist/core/standards/resolve-standards-context.js +2 -14
- package/dist/core/standards/resolve-stash-standards.js +2 -2
- package/dist/core/standards/resolve-type-conventions.js +2 -2
- package/dist/core/state/migrations.js +41 -18
- package/dist/core/state-db.js +5 -14
- package/dist/core/structured.js +1 -1
- package/dist/core/subprocess.js +6 -4
- package/dist/core/text-truncation.js +9 -5
- package/dist/core/type-presentation.js +3 -3
- package/dist/core/warn.js +0 -3
- package/dist/core/write-source.js +771 -95
- package/dist/indexer/bundle-identity-guard.js +3 -2
- package/dist/indexer/db/graph-db.js +0 -24
- package/dist/indexer/ensure-index.js +1 -0
- package/dist/indexer/graph/graph-boost.js +9 -34
- package/dist/indexer/graph/graph-extraction.js +8 -5
- package/dist/indexer/index-writer-lock.js +53 -17
- package/dist/indexer/index-written-assets.js +16 -22
- package/dist/indexer/indexer.js +497 -239
- package/dist/indexer/installations.js +14 -96
- package/dist/indexer/passes/dir-staleness.js +16 -9
- package/dist/indexer/passes/memory-inference.js +11 -9
- package/dist/indexer/passes/metadata.js +113 -47
- package/dist/indexer/scan/doc-to-entry.js +38 -1
- package/dist/indexer/scan/drain-dir.js +13 -23
- package/dist/indexer/search/db-search.js +99 -54
- package/dist/indexer/search/fts-query.js +47 -24
- package/dist/indexer/search/ranking-contributors.js +42 -20
- package/dist/indexer/search/ranking.js +18 -99
- package/dist/indexer/search/search-fields.js +7 -2
- package/dist/indexer/search/search-source.js +82 -93
- package/dist/indexer/usage/usage-events.js +0 -89
- package/dist/indexer/walk/file-context.js +2 -1
- package/dist/indexer/walk/matchers.js +30 -43
- package/dist/indexer/walk/path-resolver.js +7 -2
- package/dist/indexer/walk/walker.js +38 -12
- package/dist/integrations/agent/builders.js +0 -6
- package/dist/integrations/agent/config.js +2 -2
- package/dist/integrations/agent/detect.js +49 -19
- package/dist/integrations/agent/engine-fallback.js +76 -0
- package/dist/integrations/agent/profiles.js +14 -0
- package/dist/integrations/agent/prompts.js +12 -8
- package/dist/integrations/agent/runner-dispatch.js +4 -2
- package/dist/integrations/agent/runner.js +0 -1
- package/dist/integrations/agent/spawn.js +5 -6
- package/dist/integrations/github.js +1 -1
- package/dist/integrations/harnesses/aider/agent-builder.js +6 -4
- package/dist/integrations/harnesses/amazonq/agent-builder.js +7 -4
- package/dist/integrations/harnesses/claude/session-log.js +0 -10
- package/dist/integrations/harnesses/codex/agent-builder.js +5 -2
- package/dist/integrations/harnesses/copilot/agent-builder.js +5 -3
- package/dist/integrations/harnesses/gemini/agent-builder.js +5 -3
- package/dist/integrations/harnesses/index.js +3 -7
- package/dist/integrations/harnesses/opencode/agent-builder.js +21 -2
- package/dist/integrations/harnesses/opencode/session-log.js +0 -15
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +13 -4
- package/dist/integrations/harnesses/openhands/agent-builder.js +9 -6
- package/dist/integrations/harnesses/pi/agent-builder.js +6 -4
- package/dist/integrations/lockfile.js +101 -6
- package/dist/integrations/session-logs/index.js +3 -28
- package/dist/llm/client.js +136 -100
- package/dist/llm/embedders/remote.js +13 -5
- package/dist/llm/feature-gate.js +4 -12
- package/dist/llm/graph-extract.js +5 -11
- package/dist/llm/memory-infer.js +144 -1
- package/dist/llm/metadata-enhance.js +5 -7
- package/dist/llm/structured-call.js +1 -1
- package/dist/llm/usage-persist.js +26 -5
- package/dist/llm/usage-telemetry.js +25 -2
- package/dist/output/cli-hints.js +1 -2
- package/dist/output/context.js +22 -7
- package/dist/output/format-exempt.js +80 -0
- package/dist/output/generic-render.js +259 -0
- package/dist/output/render-registry.js +57 -0
- package/dist/output/renderers.js +14 -36
- package/dist/output/shapes/curate.js +10 -1
- package/dist/output/shapes/events.js +12 -7
- package/dist/output/shapes/helpers.js +56 -83
- package/dist/output/shapes/migrate.js +8 -0
- package/dist/output/shapes/passthrough.js +7 -41
- package/dist/output/shapes/proposal/producer.js +15 -7
- package/dist/output/shapes.js +2 -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 +164 -96
- package/dist/output/text/env.js +1 -3
- package/dist/output/text/events.js +8 -7
- package/dist/output/text/health-format.js +103 -0
- package/dist/output/text/health.js +7 -0
- package/dist/output/text/helpers.js +10 -8
- package/dist/output/text/lint-format.js +43 -0
- package/dist/output/text/{save.js → lint.js} +2 -2
- package/dist/output/text/migrate.js +88 -0
- package/dist/output/text/proposal/producer.js +4 -2
- package/dist/output/text/proposal-format.js +44 -72
- package/dist/output/text/registry-commands.js +1 -2
- package/dist/output/text/show-directives.js +15 -7
- package/dist/output/text/status-list.js +32 -0
- package/dist/output/text/sync.js +5 -0
- package/dist/output/text/workflow-format.js +24 -203
- package/dist/output/text/workflow.js +1 -7
- package/dist/output/text.js +16 -17
- 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 +13 -23
- package/dist/registry/resolve.js +42 -7
- package/dist/registry/semver.js +34 -84
- package/dist/runtime.js +2 -23
- package/dist/scripts/akm-migrate-node.js +60290 -0
- package/dist/scripts/akm-migrate.js +59628 -0
- package/dist/setup/detect.js +42 -15
- package/dist/setup/registry-stash-loader.js +2 -2
- package/dist/setup/setup.js +236 -136
- package/dist/setup/steps/connection.js +7 -9
- package/dist/setup/steps/platforms.js +9 -9
- package/dist/setup/steps/semantic.js +15 -3
- package/dist/setup/steps/sources.js +12 -13
- package/dist/setup/steps/stashdir.js +2 -3
- package/dist/setup/steps/tasks.js +237 -120
- package/dist/sources/freshness.js +1 -1
- 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 +25 -23
- package/dist/sources/providers/git-stash.js +395 -106
- package/dist/sources/providers/git.js +2 -2
- package/dist/sources/providers/npm.js +16 -19
- package/dist/sources/providers/provider-utils.js +7 -4
- package/dist/sources/providers/sync-from-ref.js +3 -9
- package/dist/sources/providers/website.js +6 -1
- package/dist/sources/resolve.js +6 -5
- package/dist/sources/snapshot-fetchers/bluesky.js +146 -0
- package/dist/sources/snapshot-fetchers/content-extract.js +566 -0
- package/dist/sources/snapshot-fetchers/fetcher-util.js +41 -0
- package/dist/sources/snapshot-fetchers/github.js +100 -0
- package/dist/sources/snapshot-fetchers/host-guard.js +291 -0
- package/dist/sources/snapshot-fetchers/registry.js +17 -1
- package/dist/sources/snapshot-fetchers/robots.js +348 -0
- package/dist/sources/snapshot-fetchers/rss.js +282 -0
- package/dist/sources/snapshot-fetchers/secret-seam.js +42 -0
- package/dist/sources/snapshot-fetchers/website-ingest.js +566 -268
- package/dist/sources/snapshot-fetchers/x.js +910 -0
- package/dist/storage/database.js +7 -0
- package/dist/storage/engines/sqlite-migrations.js +23 -111
- package/dist/storage/managed-db.js +2 -2
- package/dist/storage/repositories/canaries-repository.js +1 -1
- package/dist/storage/repositories/events-repository.js +27 -11
- package/dist/storage/repositories/improve-runs-repository.js +6 -12
- package/dist/storage/repositories/index-connection.js +17 -6
- package/dist/storage/repositories/index-entries-repository.js +151 -240
- package/dist/storage/repositories/index-entry-mapper.js +15 -11
- package/dist/storage/repositories/index-fts-repository.js +5 -2
- package/dist/storage/repositories/index-llm-cache-repository.js +0 -1
- package/dist/storage/repositories/index-meta-repository.js +2 -3
- package/dist/storage/repositories/index-schema.js +10 -25
- package/dist/storage/repositories/index-utility-repository.js +15 -28
- package/dist/storage/repositories/index-vec-repository.js +6 -1
- package/dist/storage/repositories/outcome-repository.js +119 -0
- package/dist/storage/repositories/proposals-repository.js +296 -59
- package/dist/storage/repositories/registry-cache.js +19 -0
- package/dist/storage/repositories/salience-repository.js +172 -0
- package/dist/storage/repositories/task-history-repository.js +15 -13
- package/dist/storage/repositories/workflow-runs-repository.js +52 -40
- package/dist/tasks/backends/cron.js +105 -15
- package/dist/tasks/backends/index.js +1 -1
- package/dist/tasks/backends/launchd.js +85 -38
- package/dist/tasks/backends/schtasks.js +135 -15
- package/dist/tasks/embedded.js +56 -40
- package/dist/tasks/parser.js +7 -157
- package/dist/tasks/resolve-akm-bin.js +137 -59
- package/dist/tasks/runner.js +79 -42
- package/dist/tasks/scheduler-invocation.js +220 -10
- package/dist/tasks/schema.js +24 -1
- package/dist/tasks/task-id.js +1 -3
- package/dist/tasks/validator.js +20 -6
- package/dist/workflows/authoring/authoring.js +94 -143
- package/dist/workflows/authoring/scope-key.js +1 -1
- package/dist/workflows/exec/frozen-judge.js +28 -2
- package/dist/workflows/exec/native-executor.js +77 -57
- package/dist/workflows/exec/param-secrets.js +9 -9
- package/dist/workflows/exec/run-workflow.js +133 -79
- package/dist/workflows/exec/step-work.js +219 -346
- package/dist/{migrate-storage-node.mjs → workflows/exec/unit-dispatch.js} +1 -5
- package/dist/workflows/ir/compile.js +141 -270
- package/dist/workflows/ir/freeze.js +40 -30
- package/dist/workflows/ir/params.js +135 -11
- package/dist/workflows/ir/plan-hash.js +1 -1
- package/dist/workflows/ir/schema.js +25 -26
- package/dist/workflows/parser.js +872 -307
- package/dist/workflows/program/expressions.js +20 -208
- package/dist/workflows/program/schema.js +7 -10
- package/dist/workflows/renderer.js +95 -68
- package/dist/workflows/resource-limits.js +2 -0
- package/dist/workflows/runtime/checkin.js +3 -3
- package/dist/workflows/runtime/plan-classifier.js +16 -75
- package/dist/workflows/runtime/runs.js +186 -127
- package/dist/workflows/runtime/unit-checkin.js +1 -1
- package/dist/workflows/runtime/unit-phases.js +2 -2
- package/dist/workflows/runtime/workflow-asset-loader.js +232 -83
- package/dist/workflows/schema.js +1 -11
- package/dist/workflows/validate-summary.js +30 -36
- package/dist/workflows/validator.js +21 -62
- package/docs/README.md +68 -0
- package/docs/migration/README.md +8 -0
- package/docs/migration/release-notes/0.7.0.md +11 -11
- package/docs/migration/release-notes/0.9.0.md +208 -27
- package/docs/migration/v0.7-to-v0.8.md +46 -47
- package/docs/migration/v0.8-to-v0.9.md +564 -208
- package/docs/migration/v0.9.0-troubleshooting.md +561 -0
- package/docs/reference/README.md +12 -0
- package/docs/reference/cli.md +2253 -0
- package/docs/reference/configuration.md +358 -0
- package/docs/reference/data-and-telemetry.md +105 -42
- package/docs/reference/workflows.md +647 -0
- package/package.json +22 -11
- package/schemas/akm-asset-envelope.json +93 -0
- package/schemas/akm-config.json +81 -128
- package/schemas/akm-workflow.json +74 -73
- package/dist/assets/tasks/core/backup.yml +0 -5
- package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
- package/dist/cli/config-migrate.js +0 -1806
- package/dist/cli/config-validate.js +0 -41
- package/dist/commands/backup-cli.js +0 -56
- package/dist/commands/bundle/bundle-cli.js +0 -68
- package/dist/commands/bundle/bundle.js +0 -219
- package/dist/commands/graph/graph-cli.js +0 -124
- package/dist/commands/graph/graph.js +0 -489
- package/dist/commands/improve/extract-watch.js +0 -140
- package/dist/commands/mv-cli.js +0 -1221
- package/dist/commands/sources/history.js +0 -201
- package/dist/commands/tasks/default-tasks.js +0 -186
- package/dist/core/migration-backup.js +0 -1234
- package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -95
- package/dist/llm/memory-infer-impl.js +0 -138
- package/dist/migrate/legacy/config-source-migration.js +0 -223
- package/dist/migrate/legacy/content-migration.js +0 -305
- package/dist/migrate/legacy/legacy-layout.js +0 -779
- package/dist/migrate/legacy/legacy-paths.js +0 -25
- package/dist/migrate/legacy/legacy-stash-json.js +0 -72
- package/dist/migrate/legacy/proposal-fs-import.js +0 -168
- package/dist/migrate/legacy/task-target-ref-migration.js +0 -272
- package/dist/migrate/legacy/three-db-cutover.js +0 -841
- package/dist/migrate/legacy/workflow-migrations-bodies.js +0 -52
- package/dist/migrate/legacy/workflow-migrations-frozen.js +0 -21
- package/dist/migrate/legacy-ref-grammar.js +0 -214
- 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/registry/build-index.js +0 -382
- package/dist/schemas/akm-config.json +0 -4704
- package/dist/schemas/akm-task.json +0 -87
- package/dist/schemas/akm-workflow.json +0 -372
- package/dist/scripts/migrate-storage.js +0 -3816
- package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
- package/dist/workflows/cli.js +0 -53
- package/dist/workflows/exec/brief.js +0 -481
- package/dist/workflows/exec/report.js +0 -1460
- package/dist/workflows/exec/watch.js +0 -116
- package/dist/workflows/program/parser.js +0 -813
- package/dist/workflows/program/project.js +0 -104
package/dist/setup/setup.js
CHANGED
|
@@ -20,8 +20,10 @@ import path from "node:path";
|
|
|
20
20
|
import { isDeepStrictEqual } from "node:util";
|
|
21
21
|
import * as p from "../cli/clack.js";
|
|
22
22
|
import { akmInit } from "../commands/sources/init.js";
|
|
23
|
-
import {
|
|
23
|
+
import { deriveBundleIds } from "../core/bundle-id.js";
|
|
24
|
+
import { bundleEntryToSourceEntry, DEFAULT_CONFIG, loadUserConfig, mutateConfigWithPrecommit, parseAndValidateConfigText, primaryBundlePath, validateCompleteConfig, } from "../core/config/config.js";
|
|
24
25
|
import { readConfigText } from "../core/config/config-io.js";
|
|
26
|
+
import { listTopLevelConfigKeys } from "../core/config/config-schema.js";
|
|
25
27
|
import { deepMergeConfig } from "../core/config/deep-merge.js";
|
|
26
28
|
import { ConfigError, UsageError } from "../core/errors.js";
|
|
27
29
|
import { getConfigPath, getDefaultStashDir, isTransientStashPath } from "../core/paths.js";
|
|
@@ -32,7 +34,6 @@ import { detectAgentCliProfiles, pickDefaultAgentProfile } from "../integrations
|
|
|
32
34
|
import { defaultProfileName } from "../integrations/harnesses/index.js";
|
|
33
35
|
import { readLockfile } from "../integrations/lockfile.js";
|
|
34
36
|
import { probeLlmCapabilities } from "../llm/client.js";
|
|
35
|
-
import { migrateConfigSourcesToBundles } from "../migrate/legacy/config-source-migration.js";
|
|
36
37
|
import { detectEnvironment, detectLMStudio, renderDetectionSummary, } from "./detect.js";
|
|
37
38
|
import { upsertDetectedAgentEngine, upsertDetectedLlmEngine, verifyOpenAiCompatibleEndpoint } from "./detected-engines.js";
|
|
38
39
|
import { readCurrentLlmEngine, writeAgentEngines, writeLlmEngine } from "./engine-config.js";
|
|
@@ -47,13 +48,13 @@ import { printCapabilitySummary, stepAgentCliDetection, stepAgentPlatforms, step
|
|
|
47
48
|
import { stepSemanticSearch } from "./steps/semantic.js";
|
|
48
49
|
import { stepAdditionalSources, stepAddSources, stepRegistries } from "./steps/sources.js";
|
|
49
50
|
import { stepStashDir } from "./steps/stashdir.js";
|
|
50
|
-
import {
|
|
51
|
+
import { stepScheduledTasks } from "./steps/tasks.js";
|
|
51
52
|
// ── Setup sandbox guard ─────────────────────────────────────────────────────
|
|
52
53
|
/**
|
|
53
|
-
* Refuse to persist an explicit `--dir /tmp/...`
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
54
|
+
* Refuse to persist an explicit `--dir /tmp/...` as the default bundle path.
|
|
55
|
+
* The OS may reap the directory at any time, leaving the next run with a
|
|
56
|
+
* default bundle that points at a deleted path. Mirrors the
|
|
57
|
+
* `assertInitSandbox` check in commands/init.ts, but
|
|
57
58
|
* fires under all runtimes (not just `bun test`) because `akm setup --dir
|
|
58
59
|
* /tmp/X` is a documented isolation pattern that has been observed to
|
|
59
60
|
* silently clobber the host config (the 2026-05-23 setup-clobbers-user-config
|
|
@@ -61,7 +62,7 @@ import { stepDefaultImproveTasks, stepScheduledTasks } from "./steps/tasks.js";
|
|
|
61
62
|
*
|
|
62
63
|
* Escape hatch: set `AKM_FORCE_SETUP_TMP_STASH=1` to override. When the
|
|
63
64
|
* escape hatch is on, `applyStashIsolationToEnv` below also pre-sets
|
|
64
|
-
* `
|
|
65
|
+
* `AKM_BUNDLE_DIR` so that the `getConfigDir` / `getCacheDir` isolation
|
|
65
66
|
* rules fire and config + cache writes route into `$stashDir/.akm/`
|
|
66
67
|
* instead of the user's host `~/.config/akm`.
|
|
67
68
|
*/
|
|
@@ -73,7 +74,7 @@ function assertSetupSandbox(stashDir, dirExplicitlyProvided) {
|
|
|
73
74
|
if (!isTransientStashPath(stashDir))
|
|
74
75
|
return;
|
|
75
76
|
throw new ConfigError(`refusing to run \`akm setup --dir ${stashDir}\`: the path is in a transient/sandbox directory family the OS may reap. ` +
|
|
76
|
-
"Persisting it as the
|
|
77
|
+
"Persisting it as the default bundle would leave the next run pointing at a deleted path. " +
|
|
77
78
|
"Use a persistent directory, OR set AKM_FORCE_SETUP_TMP_STASH=1 if you intentionally want a sandbox setup " +
|
|
78
79
|
"(setup will also auto-isolate config + cache writes into $stashDir/.akm/ so the host config is preserved).", "SETUP_TMP_STASH_REFUSED");
|
|
79
80
|
}
|
|
@@ -81,11 +82,11 @@ function assertSetupSandbox(stashDir, dirExplicitlyProvided) {
|
|
|
81
82
|
* Propagate the explicit `--dir <stashDir>` choice to the env so that the
|
|
82
83
|
* `getConfigDir` / `getCacheDir` isolation rules in `src/core/paths.ts`
|
|
83
84
|
* actually fire for the duration of this setup run. Without this, a CLI
|
|
84
|
-
* caller who passes `--dir /tmp/X` but doesn't pre-export `
|
|
85
|
+
* caller who passes `--dir /tmp/X` but doesn't pre-export `AKM_BUNDLE_DIR`
|
|
85
86
|
* would still write config to the host `~/.config/akm/config.json`. We
|
|
86
87
|
* only set the env var when:
|
|
87
88
|
* - `--dir` was explicitly provided (we have an operator-stated stash), AND
|
|
88
|
-
* - `
|
|
89
|
+
* - `AKM_BUNDLE_DIR` is not already set (caller's explicit env wins).
|
|
89
90
|
* The set is process-wide; for the CLI that's the right scope (the process
|
|
90
91
|
* is about to do all its work against this stash). For tests, each test
|
|
91
92
|
* already isolates env via beforeEach/afterEach so there is no leak.
|
|
@@ -93,12 +94,37 @@ function assertSetupSandbox(stashDir, dirExplicitlyProvided) {
|
|
|
93
94
|
function applyStashIsolationToEnv(stashDir, dirExplicitlyProvided) {
|
|
94
95
|
if (!dirExplicitlyProvided)
|
|
95
96
|
return;
|
|
96
|
-
if (process.env.
|
|
97
|
+
if (process.env.AKM_BUNDLE_DIR?.trim())
|
|
97
98
|
return;
|
|
98
|
-
process.env.
|
|
99
|
+
process.env.AKM_BUNDLE_DIR = stashDir;
|
|
99
100
|
}
|
|
100
101
|
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
101
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* Raw preflight used before setup performs prompts, initialization, or writes.
|
|
104
|
+
*
|
|
105
|
+
* `setup` is allowlisted in `shouldBypassConfigStartup` (src/cli.ts) so it
|
|
106
|
+
* never dies on the CLI's own startup config load — but every entry point
|
|
107
|
+
* below (`runSetupWizard`, `runSetupWithDefaults`, `runSetupFromConfig`,
|
|
108
|
+
* `runResetRecommended`) still needs the CURRENT config as its merge base, so
|
|
109
|
+
* this is the first thing each one calls. When the on-disk config predates
|
|
110
|
+
* 0.9 (or is otherwise unparseable/invalid), `parseAndValidateConfigText`
|
|
111
|
+
* throws `ConfigError`; deliberately let that propagate rather than falling
|
|
112
|
+
* back to a fresh default config here.
|
|
113
|
+
*
|
|
114
|
+
* That fallback was considered and rejected: `mutateConfigWithPrecommit`
|
|
115
|
+
* (src/core/config/config.ts) re-reads and re-validates this SAME file
|
|
116
|
+
* inside its write lock before saving, so a wizard that "survived" this
|
|
117
|
+
* preflight by substituting `DEFAULT_CONFIG` would still crash with the
|
|
118
|
+
* identical error at the final save — after prompting the user through the
|
|
119
|
+
* entire wizard. Worse, making the save path itself tolerate an old config
|
|
120
|
+
* would mean writing a freshly-generated 0.9 config over the live 0.8 file
|
|
121
|
+
* `akm migrate apply` needs to read as ITS OWN input — replacing the user's
|
|
122
|
+
* real engine/source settings with the wizard's placeholder ones, silently,
|
|
123
|
+
* on the one path (`akm migrate ...`) the upgrade docs tell users to run
|
|
124
|
+
* first. Refusing here — before any prompt, detection, or write — is strictly
|
|
125
|
+
* safer: the file is left byte-for-byte untouched and the error message
|
|
126
|
+
* below points straight at the real recovery command.
|
|
127
|
+
*/
|
|
102
128
|
export function assertSetupConfigPreflight() {
|
|
103
129
|
const configPath = getConfigPath();
|
|
104
130
|
let text;
|
|
@@ -108,8 +134,21 @@ export function assertSetupConfigPreflight() {
|
|
|
108
134
|
catch (error) {
|
|
109
135
|
throw new ConfigError(`Could not read config at ${configPath}: ${error instanceof Error ? error.message : String(error)}`, "INVALID_CONFIG_FILE");
|
|
110
136
|
}
|
|
111
|
-
if (text
|
|
137
|
+
if (text === undefined)
|
|
138
|
+
return;
|
|
139
|
+
try {
|
|
112
140
|
parseAndValidateConfigText(text, configPath);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
if (!(error instanceof ConfigError))
|
|
144
|
+
throw error;
|
|
145
|
+
if (error.code !== "UNSUPPORTED_CONFIG_VERSION" && error.code !== "INVALID_CONFIG_FILE")
|
|
146
|
+
throw error;
|
|
147
|
+
throw new ConfigError(`\`akm setup\` cannot run: the config at ${configPath} did not load (${error.message}). ` +
|
|
148
|
+
"It was left untouched — setup never writes over a config it cannot first read cleanly.", error.code, "Run `akm migrate status` to check what this config needs before continuing, or `akm help migrate 0.9.0` " +
|
|
149
|
+
"for the full upgrade checklist. To abandon it and start fresh instead, move it aside " +
|
|
150
|
+
`(e.g. \`mv ${configPath} ${configPath}.bak\`) and re-run \`akm setup\`.`);
|
|
151
|
+
}
|
|
113
152
|
}
|
|
114
153
|
function isPlainRecord(value) {
|
|
115
154
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
@@ -202,56 +241,104 @@ async function saveSetupConfig(original, desired, precommit) {
|
|
|
202
241
|
const result = await mutateConfigWithPrecommit((latest) => rebaseSetupChanges(original, desired, latest), precommit);
|
|
203
242
|
return { config: result.config, precommit: result.precommit };
|
|
204
243
|
}
|
|
205
|
-
/**
|
|
206
|
-
function
|
|
207
|
-
|
|
208
|
-
return {};
|
|
209
|
-
const lockIds = new Set(readLockfile().map((entry) => entry.id));
|
|
210
|
-
const out = {};
|
|
211
|
-
for (const [key, bundle] of Object.entries(bundles)) {
|
|
212
|
-
if (lockIds.has(key))
|
|
213
|
-
out[key] = bundle;
|
|
214
|
-
}
|
|
215
|
-
return out;
|
|
244
|
+
/** Registry-managed bundles are not editable through setup's source picker. */
|
|
245
|
+
function managedBundleIds() {
|
|
246
|
+
return new Set(readLockfile().map((entry) => entry.id));
|
|
216
247
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
248
|
+
function setupSourceDescriptor(source) {
|
|
249
|
+
switch (source.type) {
|
|
250
|
+
case "filesystem":
|
|
251
|
+
return source.path ? { path: source.path } : undefined;
|
|
252
|
+
case "git":
|
|
253
|
+
return source.url ? { git: source.url } : undefined;
|
|
254
|
+
case "website":
|
|
255
|
+
return source.url ? { website: { url: source.url, ...(source.options ?? {}) } } : undefined;
|
|
256
|
+
case "npm":
|
|
257
|
+
return source.path ? { npm: source.path } : undefined;
|
|
258
|
+
default:
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function selectsExistingBundle(source, id, bundle) {
|
|
263
|
+
const configured = bundleEntryToSourceEntry(id, bundle);
|
|
264
|
+
return (configured !== undefined &&
|
|
265
|
+
configured.type === source.type &&
|
|
266
|
+
configured.path === source.path &&
|
|
267
|
+
configured.url === source.url);
|
|
268
|
+
}
|
|
269
|
+
/** Convert only the wizard's private drafts, leaving current bundle entries intact. */
|
|
225
270
|
function finalizeSetupDraft(draft) {
|
|
226
|
-
const
|
|
227
|
-
const
|
|
228
|
-
if (
|
|
229
|
-
return
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
271
|
+
const { primaryPath, additionalSources, ...canonical } = draft;
|
|
272
|
+
const finalized = canonical;
|
|
273
|
+
if (primaryPath === undefined && additionalSources === undefined)
|
|
274
|
+
return finalized;
|
|
275
|
+
const bundles = { ...(draft.bundles ?? {}) };
|
|
276
|
+
const managedIds = managedBundleIds();
|
|
277
|
+
const newBundles = [];
|
|
278
|
+
if (additionalSources !== undefined) {
|
|
279
|
+
const selectedExistingIds = new Set();
|
|
280
|
+
for (const source of additionalSources) {
|
|
281
|
+
const existing = source.name ? bundles[source.name] : undefined;
|
|
282
|
+
if (source.name &&
|
|
283
|
+
source.name !== draft.defaultBundle &&
|
|
284
|
+
existing &&
|
|
285
|
+
selectsExistingBundle(source, source.name, existing)) {
|
|
286
|
+
selectedExistingIds.add(source.name);
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
const descriptor = setupSourceDescriptor(source);
|
|
290
|
+
if (!descriptor)
|
|
291
|
+
continue;
|
|
292
|
+
newBundles.push({
|
|
293
|
+
descriptor,
|
|
294
|
+
derivationPath: source.path ? path.resolve(source.path) : (source.url ?? ""),
|
|
295
|
+
preferredId: source.name,
|
|
296
|
+
primary: false,
|
|
297
|
+
writable: source.writable,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
for (const id of Object.keys(bundles)) {
|
|
301
|
+
if (id === draft.defaultBundle || managedIds.has(id) || selectedExistingIds.has(id))
|
|
302
|
+
continue;
|
|
303
|
+
delete bundles[id];
|
|
242
304
|
}
|
|
243
305
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
306
|
+
let defaultBundle = draft.defaultBundle;
|
|
307
|
+
const configuredPrimaryPath = primaryBundlePath(draft);
|
|
308
|
+
if (primaryPath !== undefined &&
|
|
309
|
+
(configuredPrimaryPath === undefined || path.resolve(configuredPrimaryPath) !== path.resolve(primaryPath))) {
|
|
310
|
+
if (defaultBundle && !managedIds.has(defaultBundle))
|
|
311
|
+
delete bundles[defaultBundle];
|
|
312
|
+
defaultBundle = undefined;
|
|
313
|
+
newBundles.unshift({
|
|
314
|
+
descriptor: { path: primaryPath },
|
|
315
|
+
derivationPath: path.resolve(primaryPath),
|
|
316
|
+
primary: true,
|
|
317
|
+
writable: true,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
const reserved = Object.keys(bundles).map((id) => ({ path: id, registryId: id }));
|
|
321
|
+
const ids = deriveBundleIds([
|
|
322
|
+
...reserved,
|
|
323
|
+
...newBundles.map((bundle) => ({ path: bundle.derivationPath, registryId: bundle.preferredId })),
|
|
324
|
+
]).slice(reserved.length);
|
|
325
|
+
for (const [index, bundle] of newBundles.entries()) {
|
|
326
|
+
const id = ids[index];
|
|
327
|
+
bundles[id] = {
|
|
328
|
+
...bundle.descriptor,
|
|
329
|
+
...(bundle.writable !== undefined ? { writable: bundle.writable } : {}),
|
|
330
|
+
};
|
|
331
|
+
if (bundle.primary)
|
|
332
|
+
defaultBundle = id;
|
|
333
|
+
}
|
|
251
334
|
if (Object.keys(bundles).length > 0)
|
|
252
335
|
finalized.bundles = bundles;
|
|
253
336
|
else
|
|
254
337
|
delete finalized.bundles;
|
|
338
|
+
if (defaultBundle !== undefined)
|
|
339
|
+
finalized.defaultBundle = defaultBundle;
|
|
340
|
+
else
|
|
341
|
+
delete finalized.defaultBundle;
|
|
255
342
|
return finalized;
|
|
256
343
|
}
|
|
257
344
|
/**
|
|
@@ -304,14 +391,14 @@ export function buildSetupSteps(options) {
|
|
|
304
391
|
const steps = [
|
|
305
392
|
{
|
|
306
393
|
id: "stash-dir",
|
|
307
|
-
label: "
|
|
394
|
+
label: "Bundle Directory",
|
|
308
395
|
nonInteractive: true,
|
|
309
396
|
async run(ctx) {
|
|
310
397
|
const stashDir = await stepStashDir(ctx.config, {
|
|
311
398
|
nonInteractive: ctx.nonInteractive,
|
|
312
399
|
preferredDir: options.preferredStashDir,
|
|
313
400
|
});
|
|
314
|
-
ctx.apply({ stashDir });
|
|
401
|
+
ctx.apply({ primaryPath: stashDir });
|
|
315
402
|
},
|
|
316
403
|
},
|
|
317
404
|
{
|
|
@@ -359,17 +446,17 @@ export function buildSetupSteps(options) {
|
|
|
359
446
|
},
|
|
360
447
|
{
|
|
361
448
|
id: "stash-sources",
|
|
362
|
-
label: "
|
|
449
|
+
label: "Bundle Sources",
|
|
363
450
|
async run(ctx) {
|
|
364
451
|
const stashes = await stepAddSources(ctx.config, { promptForAdditional: false });
|
|
365
|
-
const platforms = await stepAgentPlatforms({ ...ctx.config,
|
|
452
|
+
const platforms = await stepAgentPlatforms({ ...ctx.config, additionalSources: stashes });
|
|
366
453
|
const merged = [...stashes];
|
|
367
454
|
for (const ps of platforms) {
|
|
368
455
|
if (!merged.some((s) => s.path === ps.path))
|
|
369
456
|
merged.push(ps);
|
|
370
457
|
}
|
|
371
458
|
const withAdditional = await stepAdditionalSources(merged);
|
|
372
|
-
ctx.apply({
|
|
459
|
+
ctx.apply({ additionalSources: withAdditional });
|
|
373
460
|
},
|
|
374
461
|
},
|
|
375
462
|
{
|
|
@@ -431,7 +518,7 @@ export async function runSetupWizard(opts) {
|
|
|
431
518
|
// API key values.
|
|
432
519
|
const detection = await detectEnvironment({ existingStashDir: primaryBundlePath(current) });
|
|
433
520
|
p.note(renderDetectionSummary(detection), "Detected environment");
|
|
434
|
-
// Interactive entry point for
|
|
521
|
+
// Interactive entry point for `runResetRecommended`: offer to apply the
|
|
435
522
|
// opinionated, detection-derived defaults and skip the step-by-step wizard.
|
|
436
523
|
const useRecommended = await prompt(() => p.confirm({
|
|
437
524
|
message: "Apply recommended defaults from the detected environment (merged into your existing config)?",
|
|
@@ -469,26 +556,25 @@ export async function runSetupWizard(opts) {
|
|
|
469
556
|
// Step 2/2: Agent connection (for agentic features)
|
|
470
557
|
const agentConfig = await stepAgentConnection(ctx.config, smallModelResult);
|
|
471
558
|
ctx.apply(writeAgentEngines(ctx.config, agentConfig));
|
|
472
|
-
// Registry-managed (lock-backed) bundles are preserved by finalizeSetupDraft.
|
|
473
559
|
const newConfig = { ...ctx.config };
|
|
474
560
|
const semanticSearchMode = outcome.semantic;
|
|
475
|
-
const stashDir = newConfig.
|
|
561
|
+
const stashDir = newConfig.primaryPath ?? primaryBundlePath(current) ?? getDefaultStashDir();
|
|
476
562
|
const embedding = newConfig.embedding;
|
|
477
563
|
const llm = readCurrentLlmEngine(newConfig);
|
|
478
564
|
const registries = newConfig.registries;
|
|
479
|
-
const allStashes = newConfig.
|
|
565
|
+
const allStashes = newConfig.additionalSources ?? [];
|
|
480
566
|
// Feature capability summary
|
|
481
567
|
const agentConfigured = Boolean(agentConfig && !agentConfig.disabled);
|
|
482
568
|
printCapabilitySummary(smallModelResult.skipped, agentConfigured);
|
|
483
569
|
// Confirm before saving
|
|
484
570
|
const effectiveRegistries = registries ?? DEFAULT_CONFIG.registries ?? [];
|
|
485
571
|
p.note([
|
|
486
|
-
`
|
|
572
|
+
`Bundle directory: ${stashDir}`,
|
|
487
573
|
`Embedding: ${embedding ? `${embedding.provider ?? "remote"} / ${embedding.model}` : "built-in local"}`,
|
|
488
574
|
`LLM: ${llm ? `${llm.provider ?? "remote"} / ${llm.model}` : "disabled"}`,
|
|
489
575
|
`Semantic search: ${semanticSearchMode.mode}`,
|
|
490
576
|
`Registries: ${effectiveRegistries.filter((r) => r.enabled !== false).length} enabled`,
|
|
491
|
-
`
|
|
577
|
+
`Bundle sources: ${allStashes.length}`,
|
|
492
578
|
`Agent default: ${newConfig.defaults?.engine ?? "disabled"}`,
|
|
493
579
|
`Output: ${newConfig.output?.format ?? "json"} / ${newConfig.output?.detail ?? "brief"}`,
|
|
494
580
|
].join("\n"), "Configuration Summary");
|
|
@@ -502,19 +588,12 @@ export async function runSetupWizard(opts) {
|
|
|
502
588
|
validateCompleteConfig(finalConfig);
|
|
503
589
|
const { config: savedConfig } = await saveSetupConfig(current, finalConfig, async () => {
|
|
504
590
|
if (!opts?.noInit)
|
|
505
|
-
await akmInit({ dir:
|
|
591
|
+
await akmInit({ dir: stashDir, setDefault: true, persistConfig: false });
|
|
506
592
|
});
|
|
507
|
-
//
|
|
508
|
-
//
|
|
509
|
-
//
|
|
510
|
-
// nothing behind. The task-setup path re-reads config via `loadConfig()`,
|
|
511
|
-
// which now returns the just-saved config (the cache is invalidated on
|
|
512
|
-
// write) — so tasks register against the confirmed engine/connection rather
|
|
513
|
-
// than the stale pre-wizard config. This is interactive-only: `akm init` /
|
|
514
|
-
// `--yes` go through the non-interactive entry points, which never reach
|
|
515
|
-
// here (issue #512).
|
|
593
|
+
// After config persistence, the task step reviews the plan and asks one
|
|
594
|
+
// explicit confirmation before changing task files or scheduler state.
|
|
595
|
+
// Non-interactive setup paths never reach this interactive-only step.
|
|
516
596
|
p.log.step("Scheduled Tasks");
|
|
517
|
-
await stepDefaultImproveTasks();
|
|
518
597
|
await stepScheduledTasks();
|
|
519
598
|
if (semanticSearchMode.mode === "off") {
|
|
520
599
|
clearSemanticStatus();
|
|
@@ -595,7 +674,8 @@ export async function runSetupWizard(opts) {
|
|
|
595
674
|
p.log.info("Reminder: Set your LLM API key via the AKM_LLM_API_KEY environment variable.");
|
|
596
675
|
}
|
|
597
676
|
}
|
|
598
|
-
p.outro(`Configuration saved to ${configPath}`
|
|
677
|
+
p.outro(`Configuration saved to ${configPath}\n` +
|
|
678
|
+
'Next: `akm bundle add <source>`, `akm index`, `akm search "<query>"`, `akm help agents`');
|
|
599
679
|
}
|
|
600
680
|
// ── Non-interactive / scripting entry points ─────────────────────────────────
|
|
601
681
|
/**
|
|
@@ -605,14 +685,21 @@ export async function runSetupWizard(opts) {
|
|
|
605
685
|
export async function runSetupWithDefaults(opts) {
|
|
606
686
|
assertSetupConfigPreflight();
|
|
607
687
|
const explicitStashDir = opts.dir != null ? path.resolve(opts.dir) : undefined;
|
|
688
|
+
// R-066 #4: a second `assertSetupSandbox(stashDir, explicitStashDir != null)`
|
|
689
|
+
// + `applyStashIsolationToEnv(stashDir, explicitStashDir != null)` pair used
|
|
690
|
+
// to follow `stashDir`'s resolution below. It was strictly redundant: unlike
|
|
691
|
+
// `runSetupFromConfig` (which can also derive an explicit stash dir from an
|
|
692
|
+
// incoming config file's bundle path, a case the early block below can't
|
|
693
|
+
// see yet), `runSetupWithDefaults` has only one source of an explicit dir —
|
|
694
|
+
// `opts.dir` — so `stashDir` always equals `explicitStashDir` whenever the
|
|
695
|
+
// `if` below ran, and always fails `dirExplicitlyProvided` (an immediate
|
|
696
|
+
// no-op in both helpers) whenever it didn't. Removed rather than duplicated.
|
|
608
697
|
if (explicitStashDir) {
|
|
609
698
|
assertSetupSandbox(explicitStashDir, true);
|
|
610
699
|
applyStashIsolationToEnv(explicitStashDir, true);
|
|
611
700
|
}
|
|
612
701
|
const current = loadUserConfig();
|
|
613
702
|
const stashDir = explicitStashDir ?? primaryBundlePath(current) ?? getDefaultStashDir();
|
|
614
|
-
assertSetupSandbox(stashDir, explicitStashDir != null);
|
|
615
|
-
applyStashIsolationToEnv(stashDir, explicitStashDir != null);
|
|
616
703
|
// Run steps in non-interactive mode (applies defaults, skips prompts)
|
|
617
704
|
const ctx = createSetupContext(current, { nonInteractive: true });
|
|
618
705
|
const { steps } = buildSetupSteps({
|
|
@@ -621,11 +708,10 @@ export async function runSetupWithDefaults(opts) {
|
|
|
621
708
|
preferredStashDir: stashDir,
|
|
622
709
|
});
|
|
623
710
|
await runSetupSteps(steps, ctx);
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
ctx.apply({ stashDir });
|
|
711
|
+
if (!ctx.config.primaryPath)
|
|
712
|
+
ctx.apply({ primaryPath: stashDir });
|
|
627
713
|
// Aggregate environment detection — apply detected values directly.
|
|
628
|
-
const env = await detectEnvironment({ existingStashDir: ctx.config.
|
|
714
|
+
const env = await detectEnvironment({ existingStashDir: ctx.config.primaryPath });
|
|
629
715
|
// Apply a detected LLM (live local server) when the config has none yet.
|
|
630
716
|
if (!readCurrentLlmEngine(ctx.config) && opts.probe) {
|
|
631
717
|
const liveLocal = env.localServers.find((s) => s.available && s.defaultModel);
|
|
@@ -677,7 +763,7 @@ export async function runSetupWithDefaults(opts) {
|
|
|
677
763
|
});
|
|
678
764
|
return {
|
|
679
765
|
configPath: getConfigPath(),
|
|
680
|
-
stashDir,
|
|
766
|
+
bundleDir: stashDir,
|
|
681
767
|
stashCreated: initResult?.created ?? false,
|
|
682
768
|
written: true,
|
|
683
769
|
fields: Object.keys(finalConfig).filter((k) => finalConfig[k] !== undefined),
|
|
@@ -685,7 +771,7 @@ export async function runSetupWithDefaults(opts) {
|
|
|
685
771
|
}
|
|
686
772
|
/**
|
|
687
773
|
* Run ONLY environment detection and return the typed result. Performs no
|
|
688
|
-
* config writes and shows no prompts.
|
|
774
|
+
* config writes and shows no prompts.
|
|
689
775
|
*
|
|
690
776
|
* SAFETY: The returned object carries env var NAMES only — never any API key
|
|
691
777
|
* value.
|
|
@@ -699,9 +785,8 @@ export async function runDetectOnly() {
|
|
|
699
785
|
* - Best harness → agent default (when a profile maps to it).
|
|
700
786
|
* - Fastest live local model, else the first detected cloud key's provider.
|
|
701
787
|
* - `nomic-embed-text` embeddings when a local LLM is live.
|
|
702
|
-
* - improve task `0 2 * * *`, index task `0 4 * * *`.
|
|
703
788
|
*
|
|
704
|
-
* Returns a partial `AkmConfig`-shaped object plus
|
|
789
|
+
* Returns a partial `AkmConfig`-shaped object plus an LLM connection block, ready
|
|
705
790
|
* to merge. Never includes an API key value.
|
|
706
791
|
*/
|
|
707
792
|
export function deriveRecommendedConfig(env) {
|
|
@@ -736,14 +821,13 @@ export function deriveRecommendedConfig(env) {
|
|
|
736
821
|
}
|
|
737
822
|
}
|
|
738
823
|
}
|
|
739
|
-
result.taskSchedules = { improve: "0 2 * * *", index: "0 4 * * *" };
|
|
740
824
|
return result;
|
|
741
825
|
}
|
|
742
826
|
/**
|
|
743
|
-
*
|
|
744
|
-
*
|
|
745
|
-
* Uses the same merge path as
|
|
746
|
-
* (follows #511 semantics).
|
|
827
|
+
* Merge opinionated, detection-derived defaults into the existing config
|
|
828
|
+
* WITHOUT removing pre-existing custom keys. Backs the interactive wizard's
|
|
829
|
+
* "apply recommended defaults" prompt. Uses the same merge path as
|
|
830
|
+
* {@link runSetupFromConfig} so custom keys survive (follows #511 semantics).
|
|
747
831
|
*/
|
|
748
832
|
export async function runResetRecommended(opts) {
|
|
749
833
|
assertSetupConfigPreflight();
|
|
@@ -787,9 +871,6 @@ export async function runResetRecommended(opts) {
|
|
|
787
871
|
if (recommended.agentDefault) {
|
|
788
872
|
incoming = deepMergeConfig(incoming, writeAgentEngines(incoming, { default: recommended.agentDefault }));
|
|
789
873
|
}
|
|
790
|
-
if (recommended.taskSchedules) {
|
|
791
|
-
incoming.setup = { taskSchedules: recommended.taskSchedules };
|
|
792
|
-
}
|
|
793
874
|
return runSetupFromConfig({
|
|
794
875
|
configJson: JSON.stringify(incoming),
|
|
795
876
|
dir: opts.dir,
|
|
@@ -804,35 +885,36 @@ export async function runResetRecommended(opts) {
|
|
|
804
885
|
export async function runSetupFromConfig(opts) {
|
|
805
886
|
assertSetupConfigPreflight();
|
|
806
887
|
// Phase 1: Parse JSON
|
|
807
|
-
let
|
|
888
|
+
let parsed;
|
|
808
889
|
try {
|
|
809
|
-
|
|
890
|
+
parsed = JSON.parse(opts.configJson);
|
|
810
891
|
}
|
|
811
892
|
catch (e) {
|
|
812
|
-
throw new
|
|
893
|
+
throw new UsageError(`Invalid JSON in --config: ${e.message}`, "INVALID_FLAG_VALUE");
|
|
894
|
+
}
|
|
895
|
+
if (!isPlainRecord(parsed)) {
|
|
896
|
+
throw new ConfigError("Setup config must contain a top-level object.", "INVALID_CONFIG_FILE");
|
|
813
897
|
}
|
|
898
|
+
const incoming = parsed;
|
|
814
899
|
// Phase 2: Validate — only allow safe top-level keys
|
|
815
|
-
const
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
"defaults",
|
|
834
|
-
"setup",
|
|
835
|
-
]);
|
|
900
|
+
for (const key of ["stashDir", "sources", "installed"]) {
|
|
901
|
+
if (key in incoming) {
|
|
902
|
+
throw new ConfigError(`${key} is not supported by the current config schema; run the standalone akm-migrate tool first.`, "INVALID_CONFIG_FILE");
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
// Derived from AkmConfigShape (via `listTopLevelConfigKeys`) rather than a
|
|
906
|
+
// hand-copied set: a hand-copied allowlist silently fell out of sync as the
|
|
907
|
+
// schema grew (R-017 — `index`, `search`, `feedback`, `archiveRetentionDays`,
|
|
908
|
+
// `workflow`, and `experimental` were all valid schema keys that this list
|
|
909
|
+
// forgot, each dropped with only a warning while the command exited 0).
|
|
910
|
+
// Every key the schema recognizes is a legitimate thing to set via
|
|
911
|
+
// `--config`/`--from`; there is no key a user can set here that they
|
|
912
|
+
// couldn't set by hand-editing config.json and letting `akm config set`
|
|
913
|
+
// validate it. Keys that remain genuinely retired (`profiles`, `llm`,
|
|
914
|
+
// `agent`, `features`, `stashes`, `bindings`, `writable`) are not part of
|
|
915
|
+
// the schema shape, so they still fall into the warn-and-drop branch below;
|
|
916
|
+
// `stashDir`/`sources`/`installed` get the more specific migration error above.
|
|
917
|
+
const ALLOWED_KEYS = new Set(listTopLevelConfigKeys());
|
|
836
918
|
for (const key of Object.keys(incoming)) {
|
|
837
919
|
if (!ALLOWED_KEYS.has(key)) {
|
|
838
920
|
warn(`[akm setup] Ignoring unknown or restricted config key: "${key}"`);
|
|
@@ -847,21 +929,41 @@ export async function runSetupFromConfig(opts) {
|
|
|
847
929
|
throw new Error("embedding.model is required when embedding is provided");
|
|
848
930
|
}
|
|
849
931
|
// Phase 3: Merge with existing config
|
|
850
|
-
|
|
851
|
-
|
|
932
|
+
//
|
|
933
|
+
// R-066 #4 (verified, NOT reduced — unlike the `runSetupWithDefaults` pair
|
|
934
|
+
// above, this one is NOT strictly redundant): the `assertSetupSandbox` +
|
|
935
|
+
// `applyStashIsolationToEnv` pair below looks like a duplicate of the pair
|
|
936
|
+
// here, but each guards a case the other cannot:
|
|
937
|
+
// - THIS early pair must run before `loadUserConfig()` so an explicit
|
|
938
|
+
// `--dir` pointed at a force-escaped transient sandbox isolates the
|
|
939
|
+
// config READ too, not just the later write (the isolation env var has
|
|
940
|
+
// to be set before `loadUserConfig()` executes, or `current` below is
|
|
941
|
+
// read from the host config instead of the sandboxed one — the exact
|
|
942
|
+
// failure class the "2026-05-23 setup-clobbers-user-config incident"
|
|
943
|
+
// comment on `assertSetupSandbox` describes).
|
|
944
|
+
// - The LATER pair below additionally covers a case this one can't see
|
|
945
|
+
// yet: an incoming `--config`/`--file` JSON blob that names its own
|
|
946
|
+
// bundle path (`incomingPrimaryPath`) with no `--dir` at all — that
|
|
947
|
+
// path is only known after the merge, so it cannot be checked early.
|
|
948
|
+
// When `explicitStashDir` is set both pairs do end up asserting the same
|
|
949
|
+
// (stashDir, true), but removing either one changes behavior in the case
|
|
950
|
+
// it uniquely covers, so both stay.
|
|
951
|
+
const explicitStashDir = opts.dir != null ? path.resolve(opts.dir) : undefined;
|
|
852
952
|
if (explicitStashDir) {
|
|
853
953
|
assertSetupSandbox(explicitStashDir, true);
|
|
854
954
|
applyStashIsolationToEnv(explicitStashDir, true);
|
|
855
955
|
}
|
|
856
956
|
const current = loadUserConfig();
|
|
857
|
-
|
|
858
|
-
const
|
|
957
|
+
let merged = deepMergeConfig(current, incoming);
|
|
958
|
+
const incomingPrimaryPath = primaryBundlePath(incoming);
|
|
959
|
+
const configuredPrimaryPath = primaryBundlePath(merged);
|
|
960
|
+
const stashDir = explicitStashDir ?? configuredPrimaryPath ?? getDefaultStashDir();
|
|
961
|
+
const stashDirExplicit = explicitStashDir != null || incomingPrimaryPath !== undefined;
|
|
859
962
|
assertSetupSandbox(stashDir, stashDirExplicit);
|
|
860
963
|
applyStashIsolationToEnv(stashDir, stashDirExplicit);
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
});
|
|
964
|
+
if (explicitStashDir !== undefined || configuredPrimaryPath === undefined) {
|
|
965
|
+
merged = deepMergeConfig(merged, { primaryPath: stashDir });
|
|
966
|
+
}
|
|
865
967
|
// Deep-merge canonical keys: nested objects merge key-by-key so a
|
|
866
968
|
// partial `--file` only updates the keys it carries and never drops sibling
|
|
867
969
|
// subkeys (e.g. output.detail survives an output.format-only file). Arrays
|
|
@@ -878,8 +980,8 @@ export async function runSetupFromConfig(opts) {
|
|
|
878
980
|
preferredStashDir: stashDir,
|
|
879
981
|
});
|
|
880
982
|
await runSetupSteps(steps, ctx);
|
|
881
|
-
if (!ctx.config.
|
|
882
|
-
ctx.apply({ stashDir });
|
|
983
|
+
if (!ctx.config.primaryPath)
|
|
984
|
+
ctx.apply({ primaryPath: stashDir });
|
|
883
985
|
if (!ctx.config.defaults?.engine) {
|
|
884
986
|
const detected = detectAgentCliProfiles(undefined);
|
|
885
987
|
const defaultProfile = pickDefaultAgentProfile(detected, undefined);
|
|
@@ -889,9 +991,7 @@ export async function runSetupFromConfig(opts) {
|
|
|
889
991
|
}
|
|
890
992
|
merged = ctx.config;
|
|
891
993
|
}
|
|
892
|
-
//
|
|
893
|
-
// bundles shape (Decision E) so old-shape and new-shape input files both land
|
|
894
|
-
// as bundles; nothing half-migrated is ever validated or written.
|
|
994
|
+
// Convert the private setup draft to the persisted bundle shape.
|
|
895
995
|
let finalizedMerged = finalizeSetupDraft(merged);
|
|
896
996
|
// Reject an invalid merged engine graph before probing or touching the stash.
|
|
897
997
|
validateCompleteConfig(finalizedMerged);
|
|
@@ -922,7 +1022,7 @@ export async function runSetupFromConfig(opts) {
|
|
|
922
1022
|
});
|
|
923
1023
|
return {
|
|
924
1024
|
configPath: getConfigPath(),
|
|
925
|
-
stashDir,
|
|
1025
|
+
bundleDir: stashDir,
|
|
926
1026
|
stashCreated: initResult?.created ?? false,
|
|
927
1027
|
written: true,
|
|
928
1028
|
fields: Object.keys(incoming).filter((k) => incoming[k] !== undefined),
|