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
|
@@ -5,9 +5,16 @@ import fs from "node:fs";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { parse as parseYaml } from "yaml";
|
|
7
7
|
import { factDiagnostics, matchWorkflowPlaceholder, memoryOrphanStubApplies, nameOrTypeDiagnostics, ORPHANED_STUB_DETAIL, taskDiagnostics, workflowStructureDiagnostics, } from "../../core/adapter/adapters/akm-lint.js";
|
|
8
|
+
import { detectAdapterId } from "../../core/adapter/detect-adapter.js";
|
|
9
|
+
import { adapterForId } from "../../core/adapter/registry.js";
|
|
10
|
+
import { createValidateContext } from "../../core/adapter/validate-context.js";
|
|
11
|
+
import { stashDirFor } from "../../core/asset/asset-placement.js";
|
|
8
12
|
import { parseFrontmatter } from "../../core/asset/frontmatter.js";
|
|
13
|
+
import { conceptIdForStashFile, displayRefForConceptId } from "../../core/asset/resolve-ref.js";
|
|
14
|
+
import { deriveBundleIds } from "../../core/bundle-id.js";
|
|
9
15
|
import { resolveStashDir } from "../../core/common.js";
|
|
10
16
|
import { loadConfig, primaryBundlePath } from "../../core/config/config.js";
|
|
17
|
+
import { UsageError } from "../../core/errors.js";
|
|
11
18
|
import { resolveSourceEntries } from "../../indexer/search/search-source.js";
|
|
12
19
|
import { runBaseChecks } from "./base-linter.js";
|
|
13
20
|
import { checkEnvForDangerousKeys } from "./env-key-rules.js";
|
|
@@ -39,21 +46,164 @@ function collectYamlFiles(dir) {
|
|
|
39
46
|
}
|
|
40
47
|
return results;
|
|
41
48
|
}
|
|
42
|
-
function collectMarkdownFiles(dir) {
|
|
49
|
+
function collectMarkdownFiles(dir, caseInsensitive = false) {
|
|
43
50
|
if (!fs.existsSync(dir))
|
|
44
51
|
return [];
|
|
45
52
|
const results = [];
|
|
46
53
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
54
|
+
if (entry.name === ".git" || entry.isSymbolicLink())
|
|
55
|
+
continue;
|
|
47
56
|
const full = path.join(dir, entry.name);
|
|
48
57
|
if (entry.isDirectory()) {
|
|
49
|
-
results.push(...collectMarkdownFiles(full));
|
|
58
|
+
results.push(...collectMarkdownFiles(full, caseInsensitive));
|
|
50
59
|
}
|
|
51
|
-
else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
60
|
+
else if (entry.isFile() && (caseInsensitive ? entry.name.toLowerCase() : entry.name).endsWith(".md")) {
|
|
52
61
|
results.push(full);
|
|
53
62
|
}
|
|
54
63
|
}
|
|
55
64
|
return results;
|
|
56
65
|
}
|
|
66
|
+
// ── Non-akm adapter dispatch (real `adapter.validate()`, not a re-implementation) ──
|
|
67
|
+
//
|
|
68
|
+
// akm 0.9.0 lint/adapter-dispatch wiring: `akm lint` used to special-case
|
|
69
|
+
// exactly one non-akm adapter (`okf`, via a hand-rolled `missing-type`-only
|
|
70
|
+
// `lintOkfBundle` re-implementation this change deletes) and silently route
|
|
71
|
+
// every OTHER non-akm bundle (llm-wiki, dotenv, claude, opencode,
|
|
72
|
+
// agent-skills, website-snapshot, generic-files, akm-task, akm-workflow)
|
|
73
|
+
// through the AKM-shaped STASH_SUBDIRS sweep — the wrong linter for the wrong
|
|
74
|
+
// format, and the reason those adapters' own `validate()` checks (OKF's
|
|
75
|
+
// `missing-ref`; llm-wiki's `uncited-raw`/`missing-description`/`broken-xref`/
|
|
76
|
+
// `broken-source`) were unreachable dead code. Every bundle is now linted by
|
|
77
|
+
// its OWN configured/detected adapter's `validate()` — the single definition
|
|
78
|
+
// of that format's rules, shared with the (now also wired, advisory-only)
|
|
79
|
+
// change-transaction pre-commit gate in `commands/proposal/repository.ts`.
|
|
80
|
+
// This is intentionally the ONLY branch this module adds: the `akm` sweep
|
|
81
|
+
// below is completely untouched (pinned by the goldens/test suite —
|
|
82
|
+
// CRITICAL: akm findings/`--fix` must not move).
|
|
83
|
+
/**
|
|
84
|
+
* Case-insensitive SUFFIX match against an adapter's declared `extensions`
|
|
85
|
+
* hint. Deliberately NOT `path.extname()`: Node's `extname(".env")` is `""`
|
|
86
|
+
* (a leading-dot-only basename has no "extension" by that definition), which
|
|
87
|
+
* would silently skip every bare `env/.env` file — exactly the shape
|
|
88
|
+
* `dotenvAdapter`'s own `classify()` (and the akm adapter's env recognition)
|
|
89
|
+
* match by plain `endsWith`, not `path.extname`. A suffix match is also a
|
|
90
|
+
* strict superset of the `path.extname` behavior for a normal `name.ext`
|
|
91
|
+
* file, so nothing that matched before stops matching.
|
|
92
|
+
*/
|
|
93
|
+
function matchesAdapterExtension(fileName, extensions) {
|
|
94
|
+
const lower = fileName.toLowerCase();
|
|
95
|
+
return extensions.some((candidate) => lower.endsWith(candidate.toLowerCase()));
|
|
96
|
+
}
|
|
97
|
+
/** Walk the whole bundle tree, collecting every file whose extension the adapter recognizes (skip `.git`, symlinks, cache/registry copies). */
|
|
98
|
+
function collectAdapterFiles(root, extensions) {
|
|
99
|
+
if (!fs.existsSync(root))
|
|
100
|
+
return [];
|
|
101
|
+
const results = [];
|
|
102
|
+
const walk = (dir) => {
|
|
103
|
+
let entries;
|
|
104
|
+
try {
|
|
105
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
for (const entry of entries) {
|
|
111
|
+
if (entry.name === ".git" || entry.isSymbolicLink())
|
|
112
|
+
continue;
|
|
113
|
+
const full = path.join(dir, entry.name);
|
|
114
|
+
if (entry.isDirectory()) {
|
|
115
|
+
walk(full);
|
|
116
|
+
}
|
|
117
|
+
else if (entry.isFile() && matchesAdapterExtension(entry.name, extensions)) {
|
|
118
|
+
// Compare PATH SEGMENTS, not raw substrings: `path.join` yields `\` on
|
|
119
|
+
// Windows so a `"/.cache/"` substring test never matches there, and a
|
|
120
|
+
// substring test would also skip a legitimately-named `registry` file.
|
|
121
|
+
const segments = path.relative(root, full).split(/[\\/]/);
|
|
122
|
+
if (segments.includes(".cache") || segments.includes("registry"))
|
|
123
|
+
continue;
|
|
124
|
+
results.push(full);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
walk(root);
|
|
129
|
+
return results;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Every closed {@link LintIssueType} member a current adapter `validate()` can
|
|
133
|
+
* legitimately emit. Anything outside this set folds onto `"adapter-diagnostic"`
|
|
134
|
+
* (see `types.ts`'s doc comment on that member) rather than being dropped.
|
|
135
|
+
*/
|
|
136
|
+
const KNOWN_ADAPTER_ISSUE_TYPES = new Set([
|
|
137
|
+
"unquoted-colon",
|
|
138
|
+
"missing-updated",
|
|
139
|
+
"stale-path",
|
|
140
|
+
"missing-ref",
|
|
141
|
+
"missing-type",
|
|
142
|
+
"missing-name-or-type",
|
|
143
|
+
"missing-skill-md",
|
|
144
|
+
"dangerous-env-key",
|
|
145
|
+
"uncited-raw",
|
|
146
|
+
"missing-description",
|
|
147
|
+
"broken-xref",
|
|
148
|
+
"broken-source",
|
|
149
|
+
]);
|
|
150
|
+
/** Map one adapter {@link Diagnostic} onto a {@link LintIssue} — see `types.ts`'s `"adapter-diagnostic"` doc comment for the open→closed reconciliation. */
|
|
151
|
+
export function diagnosticToLintIssue(diag) {
|
|
152
|
+
if (KNOWN_ADAPTER_ISSUE_TYPES.has(diag.issue)) {
|
|
153
|
+
return { file: diag.file, issue: diag.issue, detail: diag.detail, fixed: diag.fixed };
|
|
154
|
+
}
|
|
155
|
+
return { file: diag.file, issue: "adapter-diagnostic", detail: `[${diag.issue}] ${diag.detail}`, fixed: diag.fixed };
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Lint a bundle through its OWN adapter's `validate()` (spec §12.1): the
|
|
159
|
+
* adapter never writes, so every finding lands in `flagged` — `fixed` is
|
|
160
|
+
* always `false`/`"failed"` for a non-akm bundle regardless of `--fix`
|
|
161
|
+
* (the CLI option is silently a no-op here, exactly as it already was for
|
|
162
|
+
* `okf` before this change).
|
|
163
|
+
*/
|
|
164
|
+
async function lintViaAdapter(adapterId, stashRoot, extraStashRoots, sources, cfg, options) {
|
|
165
|
+
const adapter = adapterForId(adapterId);
|
|
166
|
+
// Defensive fallback (shouldn't happen via `detectAdapterId`/a valid config
|
|
167
|
+
// — both only ever name a registered built-in): an unregistered adapter id
|
|
168
|
+
// falls back to the akm-shaped sweep, the same default `akm lint` has
|
|
169
|
+
// always applied to a bundle it can't otherwise place.
|
|
170
|
+
if (!adapter)
|
|
171
|
+
return lintAkmSweep(stashRoot, extraStashRoots, cfg, sources, options);
|
|
172
|
+
const files = collectAdapterFiles(stashRoot, adapter.extensions);
|
|
173
|
+
const changes = files.map((filePath) => ({
|
|
174
|
+
path: path.relative(stashRoot, filePath).replace(/\\/g, "/"),
|
|
175
|
+
op: "update",
|
|
176
|
+
}));
|
|
177
|
+
const ids = deriveBundleIds(sources);
|
|
178
|
+
const sourceIndex = sources.findIndex((s) => path.resolve(s.path) === path.resolve(stashRoot));
|
|
179
|
+
const componentId = sourceIndex >= 0 ? ids[sourceIndex] : stashRoot;
|
|
180
|
+
const ctx = createValidateContext({ root: stashRoot, extraRoots: extraStashRoots });
|
|
181
|
+
const diagnostics = await adapter.validate({ id: componentId, adapter: adapterId, root: stashRoot, writable: true }, changes, ctx);
|
|
182
|
+
const flagged = diagnostics.map(diagnosticToLintIssue);
|
|
183
|
+
// The cross-bundle env dangerous-key sweep (see `runEnvDangerousKeyPass`'s
|
|
184
|
+
// doc comment) ran for every non-akm adapter via the STASH_SUBDIRS
|
|
185
|
+
// fallthrough this dispatch replaces — EXCEPT `okf`, which the old code
|
|
186
|
+
// special-cased out before ever reaching that pass. Preserve both halves of
|
|
187
|
+
// that history exactly: skip only for `okf`. Some adapters (`dotenv`) ALSO
|
|
188
|
+
// find the same `dangerous-env-key` findings natively through their own
|
|
189
|
+
// `validate()` (reusing the same `dangerousEnvKeyDiagnostics` rule) — dedupe
|
|
190
|
+
// by `(file, issue, detail)` so a bundle covered both ways reports each
|
|
191
|
+
// finding once, not twice.
|
|
192
|
+
if (adapterId !== "okf") {
|
|
193
|
+
const seen = new Set(flagged.map(lintIssueDedupeKey));
|
|
194
|
+
for (const issue of runEnvDangerousKeyPass(stashRoot, extraStashRoots, sources, cfg)) {
|
|
195
|
+
const key = lintIssueDedupeKey(issue);
|
|
196
|
+
if (seen.has(key))
|
|
197
|
+
continue;
|
|
198
|
+
seen.add(key);
|
|
199
|
+
flagged.push(issue);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return { ok: true, fixed: [], flagged, summary: { fixed: 0, flagged: flagged.length } };
|
|
203
|
+
}
|
|
204
|
+
function lintIssueDedupeKey(issue) {
|
|
205
|
+
return `${issue.file} ${issue.issue} ${issue.detail}`;
|
|
206
|
+
}
|
|
57
207
|
function collectEnvFiles(dir) {
|
|
58
208
|
const results = [];
|
|
59
209
|
try {
|
|
@@ -70,6 +220,45 @@ function collectEnvFiles(dir) {
|
|
|
70
220
|
}
|
|
71
221
|
return results;
|
|
72
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Scan every `env/`/`secrets/` `.env` file across `[stashRoot, ...extraStashRoots]`
|
|
225
|
+
* for keys that are known to enable process-execution hijacking. This is a
|
|
226
|
+
* cross-bundle SECURITY sweep, not per-adapter validation — it has always run
|
|
227
|
+
* regardless of which format family a given root's OWN files are (verbatim
|
|
228
|
+
* extraction of the pass `lintAkmSweep` still runs inline; kept byte-identical
|
|
229
|
+
* there per the CRITICAL akm-path constraint, and reused here for the
|
|
230
|
+
* non-akm dispatch path so a non-akm PRIMARY bundle keeps the exact
|
|
231
|
+
* cross-bundle coverage it already had — the pass previously reached every
|
|
232
|
+
* non-akm adapter's bundle via the accidental STASH_SUBDIRS fallthrough this
|
|
233
|
+
* change replaces with real dispatch).
|
|
234
|
+
*/
|
|
235
|
+
function runEnvDangerousKeyPass(stashRoot, extraStashRoots, sources, cfg) {
|
|
236
|
+
const flagged = [];
|
|
237
|
+
const envRoots = [stashRoot, ...extraStashRoots];
|
|
238
|
+
const bundleIdByRoot = new Map(sources.map((source) => [path.resolve(source.path), source.registryId]));
|
|
239
|
+
for (const root of envRoots) {
|
|
240
|
+
const bundleId = bundleIdByRoot.get(path.resolve(root));
|
|
241
|
+
// `env` assets live under `env/`, whole-file `secret` assets under
|
|
242
|
+
// `secrets/`. `displayRefForConceptId` owns the short-default /
|
|
243
|
+
// qualified-secondary `Ref:` spelling `akm show` emits — the old
|
|
244
|
+
// hand-built `env:<base>` colon grammar is rejected by the 0.9.0 ref
|
|
245
|
+
// parser, which dead-ended a user copying the ref off a security finding.
|
|
246
|
+
for (const assetType of ["env", "secret"]) {
|
|
247
|
+
const dir = path.join(root, stashDirFor(assetType));
|
|
248
|
+
if (!fs.existsSync(dir))
|
|
249
|
+
continue;
|
|
250
|
+
for (const envPath of collectEnvFiles(dir)) {
|
|
251
|
+
const conceptId = conceptIdForStashFile(assetType, root, envPath);
|
|
252
|
+
const ref = displayRefForConceptId(conceptId, bundleId, cfg.defaultBundle);
|
|
253
|
+
const relPath = path.relative(root, envPath);
|
|
254
|
+
for (const issue of checkEnvForDangerousKeys(envPath, relPath, ref)) {
|
|
255
|
+
flagged.push(issue);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return flagged;
|
|
261
|
+
}
|
|
73
262
|
/** True when the issue represents a file deletion that was successfully applied. */
|
|
74
263
|
function isFileDeletion(issue) {
|
|
75
264
|
return issue.fixed === true && (issue.issue === "orphaned-stub" || issue.issue === "placeholder-stub");
|
|
@@ -99,7 +288,7 @@ export function lintSkillDirectory(subdirPath, stashRoot) {
|
|
|
99
288
|
function appendMemoryStubIssue(ctx, issues) {
|
|
100
289
|
if (!memoryOrphanStubApplies(ctx.data, ctx.body))
|
|
101
290
|
return;
|
|
102
|
-
const derivedPath = `${ctx.filePath.replace(/\.md
|
|
291
|
+
const derivedPath = `${ctx.filePath.replace(/\.md$/i, "")}.derived.md`;
|
|
103
292
|
if (fs.existsSync(derivedPath))
|
|
104
293
|
return;
|
|
105
294
|
if (ctx.fix) {
|
|
@@ -187,24 +376,26 @@ export function lintAssetFile(ctx, subdir) {
|
|
|
187
376
|
return issues;
|
|
188
377
|
}
|
|
189
378
|
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const fix = options.fix
|
|
379
|
+
/**
|
|
380
|
+
* The `akm`-adapter sweep: STASH_SUBDIRS walk + per-file `lintAssetFile` +
|
|
381
|
+
* the env dangerous-key pass. UNTOUCHED by the adapter-dispatch wiring above
|
|
382
|
+
* (CRITICAL CONSTRAINT — the overwhelming majority of real bundles use `akm`,
|
|
383
|
+
* and its findings / `--fix` behavior / exact `LintIssueType` codes are
|
|
384
|
+
* pinned by goldens + a large test suite). Only reached when the resolved
|
|
385
|
+
* adapter id is `"akm"` (or, defensively, an unregistered adapter id —
|
|
386
|
+
* see {@link lintViaAdapter}'s fallback).
|
|
387
|
+
*/
|
|
388
|
+
function lintAkmSweep(stashRoot, extraStashRoots, cfg, sources, options) {
|
|
389
|
+
const fix = options.fix === true;
|
|
201
390
|
const fixed = [];
|
|
202
391
|
const flagged = [];
|
|
203
392
|
const dirsToScan = options.typeFilter ? STASH_SUBDIRS.filter((d) => d === options.typeFilter) : STASH_SUBDIRS;
|
|
204
393
|
for (const subdir of dirsToScan) {
|
|
205
394
|
const dirPath = path.join(stashRoot, subdir);
|
|
206
|
-
// Tasks are .yml files; everything else
|
|
207
|
-
|
|
395
|
+
// Tasks are .yml files; everything else (including workflows, one
|
|
396
|
+
// markdown format now) is .md
|
|
397
|
+
const files = subdir === "tasks" ? collectYamlFiles(dirPath) : collectMarkdownFiles(dirPath, true);
|
|
398
|
+
const assetFiles = subdir === "workflows" ? files.filter((file) => path.basename(file).toLowerCase() !== "readme.md") : files;
|
|
208
399
|
// Directory-level check: skills require a SKILL.md entry point (was
|
|
209
400
|
// SkillLinter.lintDirectory). Run once per direct subdirectory before the
|
|
210
401
|
// per-file loop.
|
|
@@ -224,7 +415,7 @@ export function akmLint(options = {}) {
|
|
|
224
415
|
}
|
|
225
416
|
}
|
|
226
417
|
}
|
|
227
|
-
for (const filePath of
|
|
418
|
+
for (const filePath of assetFiles) {
|
|
228
419
|
// Skip registry-cached read-only files — --fix must not mutate them.
|
|
229
420
|
if (filePath.includes("/.cache/") || filePath.includes("/registry/"))
|
|
230
421
|
continue;
|
|
@@ -278,31 +469,7 @@ export function akmLint(options = {}) {
|
|
|
278
469
|
// Scan every `.env` file under <stashRoot>/env/ across all stash roots for
|
|
279
470
|
// keys that are known to enable process-execution hijacking. Warn-only —
|
|
280
471
|
// findings go into `flagged`, never `fixed`.
|
|
281
|
-
|
|
282
|
-
for (const root of envRoots) {
|
|
283
|
-
// The `env` assets live under `env/` (ref prefix `env:`); whole-file
|
|
284
|
-
// `secret` assets live under `secrets/` (canonical ref prefix `secret:`,
|
|
285
|
-
// singular). Map the scan directory to its canonical ref prefix so the
|
|
286
|
-
// finding's `Ref:` field matches what `akm show`/`akm secret` accept.
|
|
287
|
-
for (const { scanSubdir, refPrefix } of [
|
|
288
|
-
{ scanSubdir: "env", refPrefix: "env" },
|
|
289
|
-
{ scanSubdir: "secrets", refPrefix: "secret" },
|
|
290
|
-
]) {
|
|
291
|
-
const dir = path.join(root, scanSubdir);
|
|
292
|
-
if (!fs.existsSync(dir))
|
|
293
|
-
continue;
|
|
294
|
-
for (const envPath of collectEnvFiles(dir)) {
|
|
295
|
-
const baseName = path.basename(envPath, ".env");
|
|
296
|
-
// A dotfile literally named `.env` has an empty baseName — use the full
|
|
297
|
-
// basename so it doesn't collide with `default.env` → refPrefix:default.
|
|
298
|
-
const ref = baseName === "" ? `${refPrefix}:.env` : `${refPrefix}:${baseName}`;
|
|
299
|
-
const relPath = path.relative(root, envPath);
|
|
300
|
-
for (const issue of checkEnvForDangerousKeys(envPath, relPath, ref)) {
|
|
301
|
-
flagged.push(issue);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
472
|
+
flagged.push(...runEnvDangerousKeyPass(stashRoot, extraStashRoots, sources, cfg));
|
|
306
473
|
// `ok` reflects whether the lint run completed successfully — NOT whether
|
|
307
474
|
// it found anything. Findings are surfaced via `summary.flagged`; the CLI
|
|
308
475
|
// gates its exit code on `--fail-on-flagged`. Conflating "issues exist"
|
|
@@ -319,3 +486,42 @@ export function akmLint(options = {}) {
|
|
|
319
486
|
summary: { fixed: fixed.length, flagged: flagged.length },
|
|
320
487
|
};
|
|
321
488
|
}
|
|
489
|
+
/**
|
|
490
|
+
* Lint the resolved bundle at `options.dir` (default: the primary bundle).
|
|
491
|
+
* Dispatches to the bundle's OWN adapter: the `akm` sweep for `"akm"`
|
|
492
|
+
* (unchanged), or {@link lintViaAdapter} — a real `adapter.validate()` call —
|
|
493
|
+
* for every other configured/detected adapter id (OKF, llm-wiki, dotenv,
|
|
494
|
+
* claude, opencode, agent-skills, website-snapshot, generic-files, akm-task,
|
|
495
|
+
* akm-workflow). `async` because `BundleAdapter.validate()` is async by
|
|
496
|
+
* interface contract (`core/adapter/bundle-adapter.ts`); every existing
|
|
497
|
+
* caller already runs inside an async context (`commands/agent/contribute-cli.ts`,
|
|
498
|
+
* `commands/improve/preparation.ts`) or is a test that can `await` it.
|
|
499
|
+
*/
|
|
500
|
+
export async function akmLint(options = {}) {
|
|
501
|
+
// Fail closed on a mistyped invocation (§24.2 "Lint" release gate): a
|
|
502
|
+
// nonexistent --dir used to walk nothing and report a clean
|
|
503
|
+
// `ok:true, flagged:0`, silently passing scripted --fail-on-flagged gates.
|
|
504
|
+
if (options.dir !== undefined && !fs.statSync(options.dir, { throwIfNoEntry: false })?.isDirectory()) {
|
|
505
|
+
throw new UsageError(`lint: --dir "${options.dir}" is not a directory.`, "INVALID_FLAG_VALUE");
|
|
506
|
+
}
|
|
507
|
+
// Collect secondary stash roots from configured filesystem sources so that
|
|
508
|
+
// cross-stash refs (e.g. referencing assets in dimm-city/agent-stash) are
|
|
509
|
+
// not falsely flagged as missing-ref.
|
|
510
|
+
const cfg = options.config ?? loadConfig();
|
|
511
|
+
// 0.9.0 (spec §10.1): the primary stash is the defaultBundle's path.
|
|
512
|
+
const stashRoot = options.dir ?? primaryBundlePath(cfg) ?? resolveStashDir();
|
|
513
|
+
const sources = resolveSourceEntries(stashRoot, cfg);
|
|
514
|
+
const configuredAdapter = sources.find((source) => path.resolve(source.path) === path.resolve(stashRoot))?.adapterId;
|
|
515
|
+
const adapterId = configuredAdapter ?? detectAdapterId(stashRoot);
|
|
516
|
+
const extraStashRoots = sources.map((s) => s.path).filter((p) => p !== stashRoot && fs.existsSync(p));
|
|
517
|
+
if (adapterId !== "akm")
|
|
518
|
+
return lintViaAdapter(adapterId, stashRoot, extraStashRoots, sources, cfg, options);
|
|
519
|
+
// Same fail-closed rule for --type on the akm sweep: an unknown value used
|
|
520
|
+
// to filter the walk to ZERO directories — a false-clean result on the
|
|
521
|
+
// classic singular/plural typo ("workflow" for "workflows"). Non-akm
|
|
522
|
+
// adapters keep their own type vocabularies (see lintViaAdapter).
|
|
523
|
+
if (options.typeFilter && !STASH_SUBDIRS.includes(options.typeFilter)) {
|
|
524
|
+
throw new UsageError(`lint: unknown --type "${options.typeFilter}". Valid types: ${STASH_SUBDIRS.join(", ")}.`, "INVALID_FLAG_VALUE");
|
|
525
|
+
}
|
|
526
|
+
return lintAkmSweep(stashRoot, extraStashRoots, cfg, sources, options);
|
|
527
|
+
}
|
|
@@ -2,21 +2,27 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Programmatic event listing behind `akm log` (#204).
|
|
6
6
|
*
|
|
7
|
-
* Programmatic surface — the CLI dispatcher in `src/cli.ts` registers
|
|
8
|
-
*
|
|
7
|
+
* Programmatic surface — the CLI dispatcher in `src/cli.ts` registers the
|
|
8
|
+
* `log` leaf command that delegates here. Returns a JSON envelope shaped by
|
|
9
9
|
* `src/output/shapes.ts` so the output flows through the same shape and
|
|
10
10
|
* text-renderer pipeline as the rest of the CLI (no silent
|
|
11
11
|
* `JSON.stringify` fallback).
|
|
12
|
+
*
|
|
13
|
+
* 0.9.0 CLI overhaul (S3): `akmEventsTail` (and the `log tail` command it
|
|
14
|
+
* backed) was dropped — a foreground polling daemon in a one-shot CLI. The
|
|
15
|
+
* lower-level `tailEvents` poller it wrapped (src/core/events.ts) had no
|
|
16
|
+
* other caller and was removed with it.
|
|
12
17
|
*/
|
|
13
|
-
import {
|
|
18
|
+
import { makeBundleRef, parseBundleRef } from "../core/asset/asset-ref.js";
|
|
19
|
+
import { loadConfig } from "../core/config/config.js";
|
|
14
20
|
import { UsageError } from "../core/errors.js";
|
|
15
|
-
import { readEvents
|
|
21
|
+
import { readEvents } from "../core/events.js";
|
|
16
22
|
import { parseSinceToIso } from "../core/time.js";
|
|
17
23
|
/**
|
|
18
|
-
* Parse `--since` accepting either
|
|
19
|
-
* cross-process resumption, or a timestamp / epoch-ms
|
|
24
|
+
* Parse `--since` accepting either an opaque row cursor (`@offset:<int>`) for
|
|
25
|
+
* cross-process resumption, or a timestamp / epoch-ms.
|
|
20
26
|
* Returns one of `{ sinceOffset }` or `{ since }`.
|
|
21
27
|
*/
|
|
22
28
|
function parseSinceFlag(since) {
|
|
@@ -30,7 +36,7 @@ function parseSinceFlag(since) {
|
|
|
30
36
|
const raw = trimmed.slice("@offset:".length);
|
|
31
37
|
const value = Number.parseInt(raw, 10);
|
|
32
38
|
if (Number.isNaN(value) || value < 0) {
|
|
33
|
-
throw new UsageError(`Invalid --since
|
|
39
|
+
throw new UsageError(`Invalid --since offset: "${since}". Expected @offset:<non-negative integer>.`, "INVALID_FLAG_VALUE");
|
|
34
40
|
}
|
|
35
41
|
return { sinceOffset: value };
|
|
36
42
|
}
|
|
@@ -43,19 +49,35 @@ function validateRef(ref) {
|
|
|
43
49
|
if (!trimmed) {
|
|
44
50
|
throw new UsageError("--ref cannot be empty.", "INVALID_FLAG_VALUE");
|
|
45
51
|
}
|
|
46
|
-
|
|
52
|
+
const parsed = parseBundleRef(trimmed);
|
|
53
|
+
// Deliberately shallow qualification: a bare conceptId is assumed to mean
|
|
54
|
+
// the default bundle, without the full priority-walk `resolveRef` performs —
|
|
55
|
+
// event refs are recorded fully qualified, so the default is the only
|
|
56
|
+
// spelling a short --ref can usefully mean here.
|
|
57
|
+
return makeBundleRef(parsed.bundle ?? loadConfig().defaultBundle, parsed.conceptId);
|
|
58
|
+
}
|
|
59
|
+
function validateRunId(run) {
|
|
60
|
+
if (run === undefined)
|
|
61
|
+
return undefined;
|
|
62
|
+
const trimmed = run.trim();
|
|
63
|
+
if (!trimmed) {
|
|
64
|
+
throw new UsageError("--run cannot be empty.", "INVALID_FLAG_VALUE");
|
|
65
|
+
}
|
|
47
66
|
return trimmed;
|
|
48
67
|
}
|
|
49
68
|
export function akmEventsList(options = {}) {
|
|
50
69
|
const ref = validateRef(options.ref);
|
|
70
|
+
const run = validateRunId(options.run);
|
|
51
71
|
const parsed = parseSinceFlag(options.since);
|
|
52
72
|
const result = readEvents({
|
|
53
73
|
since: parsed.since,
|
|
54
74
|
sinceOffset: parsed.sinceOffset,
|
|
55
75
|
type: options.type,
|
|
56
76
|
ref,
|
|
77
|
+
runId: run,
|
|
57
78
|
excludeTags: options.excludeTags,
|
|
58
79
|
includeTags: options.includeTags,
|
|
80
|
+
limit: options.limit,
|
|
59
81
|
}, options.ctx);
|
|
60
82
|
return {
|
|
61
83
|
schemaVersion: 1,
|
|
@@ -64,36 +86,9 @@ export function akmEventsList(options = {}) {
|
|
|
64
86
|
...(options.type !== undefined ? { type: options.type } : {}),
|
|
65
87
|
...(parsed.since !== undefined ? { since: parsed.since } : {}),
|
|
66
88
|
...(parsed.sinceOffset !== undefined ? { sinceOffset: parsed.sinceOffset } : {}),
|
|
89
|
+
...(options.limit !== undefined ? { limit: options.limit } : {}),
|
|
90
|
+
...(run !== undefined ? { run } : {}),
|
|
67
91
|
nextOffset: result.nextOffset,
|
|
68
92
|
events: result.events,
|
|
69
93
|
};
|
|
70
94
|
}
|
|
71
|
-
export async function akmEventsTail(options = {}) {
|
|
72
|
-
const ref = validateRef(options.ref);
|
|
73
|
-
const parsed = parseSinceFlag(options.since);
|
|
74
|
-
const tailOptions = {
|
|
75
|
-
since: parsed.since,
|
|
76
|
-
sinceOffset: parsed.sinceOffset,
|
|
77
|
-
type: options.type,
|
|
78
|
-
ref,
|
|
79
|
-
intervalMs: options.intervalMs,
|
|
80
|
-
maxDurationMs: options.maxDurationMs,
|
|
81
|
-
maxEvents: options.maxEvents,
|
|
82
|
-
signal: options.signal,
|
|
83
|
-
onEvent: options.onEvent,
|
|
84
|
-
excludeTags: options.excludeTags,
|
|
85
|
-
includeTags: options.includeTags,
|
|
86
|
-
};
|
|
87
|
-
const result = await tailEvents(tailOptions, options.ctx);
|
|
88
|
-
return {
|
|
89
|
-
schemaVersion: 1,
|
|
90
|
-
totalCount: result.events.length,
|
|
91
|
-
...(ref !== undefined ? { ref } : {}),
|
|
92
|
-
...(options.type !== undefined ? { type: options.type } : {}),
|
|
93
|
-
...(parsed.since !== undefined ? { since: parsed.since } : {}),
|
|
94
|
-
...(parsed.sinceOffset !== undefined ? { sinceOffset: parsed.sinceOffset } : {}),
|
|
95
|
-
nextOffset: result.nextOffset,
|
|
96
|
-
events: result.events,
|
|
97
|
-
reason: result.reason,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
@@ -1,36 +1,116 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
import { defineGroupCommand, defineJsonCommand } from "../cli/shared.js";
|
|
5
|
-
import {
|
|
4
|
+
import { defineGroupCommand, defineJsonCommand, output } from "../cli/shared.js";
|
|
5
|
+
import { runMigrationTool } from "./migration-tool.js";
|
|
6
6
|
const configArg = {
|
|
7
7
|
type: "string",
|
|
8
8
|
description: "Complete operator-prepared current config; optional when the active config is current",
|
|
9
9
|
};
|
|
10
|
+
/**
|
|
11
|
+
* Split the standalone `akm-migrate` tool's captured stdout into its
|
|
12
|
+
* progress-event lines (if any — `apply` prints one JSON line per completed
|
|
13
|
+
* sub-step, e.g. content migration / proposal-ref repair) and its final
|
|
14
|
+
* result line. `status` and `apply --dry-run` never print progress, so
|
|
15
|
+
* `progress` is empty for them; `apply` may print zero or more.
|
|
16
|
+
*
|
|
17
|
+
* Each `console.log` call in the child produces exactly one `\n`-terminated
|
|
18
|
+
* line, so splitting on `\n` and dropping the trailing empty entry from the
|
|
19
|
+
* final newline recovers exactly the lines it printed, in order.
|
|
20
|
+
*/
|
|
21
|
+
function splitToolStdout(stdout) {
|
|
22
|
+
const lines = stdout.split("\n");
|
|
23
|
+
if (lines.length > 0 && lines.at(-1) === "")
|
|
24
|
+
lines.pop();
|
|
25
|
+
if (lines.length === 0)
|
|
26
|
+
return { progress: [] };
|
|
27
|
+
return { progress: lines.slice(0, -1), resultLine: lines.at(-1) };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Runs the standalone `akm-migrate` tool and renders its result through the
|
|
31
|
+
* normal `--format` pipeline (D7) instead of a fixed JSON passthrough.
|
|
32
|
+
*
|
|
33
|
+
* The child's progress-event lines (if any) are not part of the result
|
|
34
|
+
* envelope — they print as-is, in order, regardless of `--format`, the same
|
|
35
|
+
* way `apply` always printed them before this change. Only the final result
|
|
36
|
+
* line — always a well-formed `MigrationPlan` JSON object — is parsed and
|
|
37
|
+
* handed to `output()`, so `text`/`md`/`html`/`yaml` render a real
|
|
38
|
+
* (registered or generic) rendering of it instead of silently staying JSON.
|
|
39
|
+
* `--format json` (the default) is therefore the only format whose BYTES can
|
|
40
|
+
* change here (pretty-printed via `output()` instead of the child's compact
|
|
41
|
+
* `JSON.stringify`) — every value stays identical, which is what the
|
|
42
|
+
* migration-lifecycle integration tests assert via `JSON.parse`.
|
|
43
|
+
*/
|
|
44
|
+
async function runMigrateSubcommand(command, args) {
|
|
45
|
+
const result = await runMigrationTool(args);
|
|
46
|
+
if (result.stderr)
|
|
47
|
+
process.stderr.write(result.stderr);
|
|
48
|
+
const { progress, resultLine } = splitToolStdout(result.stdout);
|
|
49
|
+
for (const line of progress)
|
|
50
|
+
console.log(line);
|
|
51
|
+
if (resultLine !== undefined) {
|
|
52
|
+
try {
|
|
53
|
+
output(command, JSON.parse(resultLine));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// The child is expected to always print one well-formed JSON result
|
|
57
|
+
// line; if it somehow didn't, don't lose the line, just don't reshape it.
|
|
58
|
+
console.log(resultLine);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// R-067: `process.exitCode = …; return;` (not `process.exit()`) so the
|
|
62
|
+
// command's normal cleanup (`disposeDispatchResources()` in `runCommand`,
|
|
63
|
+
// src/cli.ts) still runs before the process exits with the child's status.
|
|
64
|
+
if (result.status !== 0) {
|
|
65
|
+
process.exitCode = result.status;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
10
69
|
export const migrateCommand = defineGroupCommand({
|
|
70
|
+
// S11 originally hid this from `--help`/completions as an internal,
|
|
71
|
+
// self-update-only surface. That made it undiscoverable even though the
|
|
72
|
+
// 0.9.0 upgrade instructions tell users to run it first (`akm migrate
|
|
73
|
+
// status`, `akm migrate apply`) — the one command those instructions
|
|
74
|
+
// depend on was invisible. Listed in the SYSTEM section of HELP_SECTIONS
|
|
75
|
+
// (src/cli.ts) and in shell completions now; `akm migrate status`/`apply`
|
|
76
|
+
// always executed regardless of `hidden`.
|
|
11
77
|
meta: { name: "migrate", description: "Inspect or apply config and durable database migrations" },
|
|
12
78
|
subCommands: {
|
|
13
79
|
status: defineJsonCommand({
|
|
14
80
|
meta: { name: "status", description: "Read-only cross-artifact migration eligibility check" },
|
|
15
81
|
args: { config: configArg },
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
await runMigrationStatus({ preparedConfigPath: args.config });
|
|
82
|
+
run({ args }) {
|
|
83
|
+
return runMigrateSubcommand("migrate-status", ["status", ...(args.config ? ["--config", args.config] : [])]);
|
|
19
84
|
},
|
|
20
85
|
}),
|
|
21
86
|
apply: defineJsonCommand({
|
|
22
87
|
meta: { name: "apply", description: "Create a verified backup and atomically apply pending migrations" },
|
|
23
88
|
args: {
|
|
24
89
|
config: configArg,
|
|
25
|
-
|
|
90
|
+
// R-062: canonical spelling is kebab-case, matching every other
|
|
91
|
+
// multi-word flag in the CLI. `--dryRun` (the pre-rename spelling)
|
|
92
|
+
// is kept as an explicit, documented alias — citty registers BOTH
|
|
93
|
+
// the camelCase and kebab-case spelling of any declared flag name
|
|
94
|
+
// automatically, so this is a rename, not a breaking change: both
|
|
95
|
+
// spellings already worked, and both keep working.
|
|
96
|
+
"dry-run": {
|
|
97
|
+
type: "boolean",
|
|
98
|
+
alias: "dryRun",
|
|
99
|
+
default: false,
|
|
100
|
+
description: "Run the same eligibility checks without mutation. Alias: --dryRun.",
|
|
101
|
+
},
|
|
26
102
|
},
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
103
|
+
run({ args }) {
|
|
104
|
+
return runMigrateSubcommand("migrate-apply", [
|
|
105
|
+
"apply",
|
|
106
|
+
...(args.config ? ["--config", args.config] : []),
|
|
107
|
+
...(args.dryRun ? ["--dry-run"] : []),
|
|
108
|
+
]);
|
|
30
109
|
},
|
|
31
110
|
}),
|
|
32
111
|
},
|
|
33
|
-
defaultRun()
|
|
34
|
-
|
|
35
|
-
|
|
112
|
+
// No `defaultRun`: bare `akm migrate` is a usage error (exit 2). This group
|
|
113
|
+
// already threw its own hand-rolled UsageError; it now shares the canonical
|
|
114
|
+
// one from `defineGroupCommand` so the message and hint match every other
|
|
115
|
+
// group — owner ruling 12.
|
|
36
116
|
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { NotFoundError } from "../core/errors.js";
|
|
8
|
+
function migrationEntryPoint() {
|
|
9
|
+
const candidates = [
|
|
10
|
+
fileURLToPath(new URL(process.versions.bun ? "../scripts/akm-migrate.js" : "../scripts/akm-migrate-node.js", import.meta.url)),
|
|
11
|
+
...(process.versions.bun ? [fileURLToPath(new URL("../../scripts/akm-migrate.ts", import.meta.url))] : []),
|
|
12
|
+
];
|
|
13
|
+
return candidates.find((candidate) => fs.existsSync(candidate));
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Spawns the standalone `akm-migrate` tool and returns its captured exit
|
|
17
|
+
* status plus stdout/stderr — never writes them itself. `migrate-cli.ts`'s
|
|
18
|
+
* `status`/`apply` commands use this to reshape the child's final JSON result
|
|
19
|
+
* line through the normal `--format` pipeline (D7) while any earlier
|
|
20
|
+
* progress-event lines the child printed still go through verbatim.
|
|
21
|
+
*/
|
|
22
|
+
export async function runMigrationTool(args) {
|
|
23
|
+
const entry = migrationEntryPoint();
|
|
24
|
+
if (!entry && process.env.AKM_MIGRATE_ENTRY === "1") {
|
|
25
|
+
// Re-exec loop guard: we ARE the marked child, yet no migrator entry
|
|
26
|
+
// resolved and the standalone wrapper did not intercept the marker — this
|
|
27
|
+
// binary was compiled without `scripts/akm-standalone.ts`.
|
|
28
|
+
throw new NotFoundError("This binary was built without the embedded akm-migrate tool.", "FILE_NOT_FOUND", "Rebuild from scripts/akm-standalone.ts, or run akm-migrate from a source/npm install.");
|
|
29
|
+
}
|
|
30
|
+
// Compiled standalone: no scripts/ tree exists on disk (`import.meta.url`
|
|
31
|
+
// resolves inside the binary's virtual filesystem), so the documented
|
|
32
|
+
// `./akm-<ver> migrate status/apply` path used to dead-end with
|
|
33
|
+
// FILE_NOT_FOUND. Release binaries are compiled from
|
|
34
|
+
// `scripts/akm-standalone.ts`, which embeds the migrator and dispatches to
|
|
35
|
+
// it when `AKM_MIGRATE_ENTRY=1` — so re-exec ourselves with the marker.
|
|
36
|
+
// (src must not import scripts/: the dist build's tsc has `rootDir: src`.)
|
|
37
|
+
const result = spawnSync(process.execPath, entry ? [entry, ...args] : [...args], {
|
|
38
|
+
encoding: "utf8",
|
|
39
|
+
env: entry ? process.env : { ...process.env, AKM_MIGRATE_ENTRY: "1" },
|
|
40
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
41
|
+
});
|
|
42
|
+
if (result.error) {
|
|
43
|
+
throw new NotFoundError(`Cannot start the standalone akm-migrate tool: ${result.error.message}`, "FILE_NOT_FOUND", "Reinstall akm-cli, or use a runtime-free standalone release binary.");
|
|
44
|
+
}
|
|
45
|
+
return { status: result.status ?? 1, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
46
|
+
}
|