akm-cli 0.9.0-rc.1 → 0.9.0-rc.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1190 -52
- package/README.md +62 -37
- package/SECURITY.md +46 -31
- package/dist/akm +162 -38
- package/dist/akm-migrate +44 -0
- package/dist/assets/backends/schtasks-template.xml +2 -1
- package/dist/assets/hints/cli-hints-full.md +268 -118
- package/dist/assets/hints/cli-hints-short.md +87 -24
- package/dist/assets/{profiles → improve-strategies}/catchup.json +3 -1
- package/dist/assets/{profiles → improve-strategies}/consolidate.json +3 -1
- package/dist/assets/{profiles → improve-strategies}/default.json +6 -7
- package/dist/assets/improve-strategies/frequent.json +15 -0
- package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +4 -2
- package/dist/assets/{profiles → improve-strategies}/memory-focus.json +4 -1
- package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +5 -5
- package/dist/assets/{profiles → improve-strategies}/quick.json +4 -2
- package/dist/assets/improve-strategies/reflect-distill.json +30 -0
- package/dist/assets/{profiles → improve-strategies}/thorough.json +1 -1
- package/dist/assets/prompts/consolidate-system.md +5 -5
- package/dist/assets/prompts/extract-session.md +2 -6
- package/dist/assets/prompts/memory-infer-user.md +2 -3
- package/dist/assets/prompts/reflect-llm-framed-contract.md +11 -0
- package/dist/assets/prompts/reflect-llm-schema-contract.md +3 -0
- package/dist/assets/prompts/reflect-output-repair.md +3 -0
- package/dist/assets/stash-skeleton/README.md +38 -10
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +14 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +13 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +9 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +11 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +9 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +9 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +100 -0
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +64 -0
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +136 -0
- package/dist/assets/tasks/core/extract.yml +3 -2
- package/dist/assets/tasks/core/improve.yml +2 -1
- package/dist/assets/tasks/core/index-refresh.yml +1 -0
- package/dist/assets/tasks/core/sync.yml +1 -0
- package/dist/assets/tasks/core/version-check.yml +2 -1
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
- package/dist/assets/templates/html/health.html +5 -4
- package/dist/assets/workflows/workflow-template.md +31 -15
- package/dist/cli/invocation.js +279 -0
- package/dist/cli/parse-args.js +5 -90
- package/dist/cli/retired-commands.js +78 -0
- package/dist/cli/shared.js +158 -48
- package/dist/cli-node.mjs +2 -1
- package/dist/cli.js +747 -293
- package/dist/commands/agent/agent-dispatch.js +19 -18
- package/dist/commands/agent/agent-support.js +0 -24
- package/dist/commands/agent/contribute-cli.js +43 -97
- package/dist/commands/completions.js +80 -23
- package/dist/commands/config-cli.js +44 -281
- package/dist/commands/env/env-binding.js +13 -9
- package/dist/commands/env/env-cli.js +76 -159
- package/dist/commands/env/env.js +12 -163
- package/dist/commands/env/marker-path.js +6 -0
- package/dist/commands/env/secret-cli.js +45 -61
- package/dist/commands/env/secret.js +32 -62
- package/dist/commands/feedback-cli.js +179 -85
- package/dist/commands/health/accept-rate.js +58 -0
- package/dist/commands/health/advisories.js +7 -8
- package/dist/commands/health/checks.js +279 -94
- package/dist/commands/health/html-report.js +197 -578
- package/dist/commands/health/improve-metrics.js +277 -246
- package/dist/commands/health/llm-usage.js +19 -19
- package/dist/commands/health/md-report.js +16 -7
- package/dist/commands/health/metrics.js +67 -32
- package/dist/commands/health/renderers.js +47 -0
- package/dist/commands/health/report-view-model.js +508 -0
- package/dist/commands/health/stash-exposure.js +1 -1
- package/dist/commands/health/surfaces.js +16 -56
- package/dist/commands/health/task-runs.js +3 -67
- package/dist/{migrate-storage-node.mjs → commands/health/types-checks.js} +1 -5
- package/dist/commands/health/types-improve.js +29 -0
- package/dist/{output/text/save.js → commands/health/types-metrics.js} +1 -2
- package/dist/commands/health/types-result.js +7 -0
- package/dist/commands/health/types-runs.js +4 -0
- package/dist/commands/health/types-session-log.js +4 -0
- package/dist/commands/health/types-windows.js +4 -0
- package/dist/commands/health/types.js +26 -21
- package/dist/commands/health/windows.js +2 -3
- package/dist/commands/health.js +296 -167
- package/dist/commands/improve/anti-collapse.js +5 -5
- package/dist/commands/improve/autonomy-gate.js +68 -0
- package/dist/commands/improve/collapse-detector.js +65 -52
- package/dist/commands/improve/consolidate/chunking.js +9 -7
- package/dist/commands/improve/consolidate/eligibility.js +1 -23
- package/dist/commands/improve/consolidate/merge.js +4 -0
- package/dist/commands/improve/consolidate.js +454 -1354
- package/dist/commands/improve/content-hash.js +39 -0
- package/dist/commands/improve/distill/content-repair.js +4 -10
- package/dist/commands/improve/distill/promote-memory.js +89 -64
- package/dist/commands/improve/distill/quality-gate.js +118 -42
- package/dist/commands/improve/distill-guards.js +1 -1
- package/dist/commands/improve/distill-promotion-policy.js +33 -888
- package/dist/commands/improve/distill.js +607 -363
- package/dist/commands/improve/eligibility.js +165 -79
- package/dist/commands/improve/extract-cli.js +35 -126
- package/dist/commands/improve/extract-prompt.js +6 -35
- package/dist/commands/improve/extract.js +640 -391
- package/dist/commands/improve/feedback-valence.js +2 -12
- package/dist/commands/improve/improve-cli.js +134 -135
- package/dist/commands/improve/improve-result-file.js +30 -50
- package/dist/commands/improve/improve-run-types.js +4 -0
- package/dist/commands/improve/improve-strategies.js +135 -0
- package/dist/commands/improve/improve.js +904 -701
- package/dist/commands/improve/locks.js +64 -111
- package/dist/commands/improve/loop-stages.js +1110 -923
- package/dist/commands/improve/memory/derived-ref.js +124 -0
- package/dist/commands/improve/memory/memory-belief.js +79 -7
- package/dist/commands/improve/memory/memory-contradiction-detect.js +49 -52
- package/dist/commands/improve/memory/memory-improve.js +25 -37
- package/dist/commands/improve/outcome-loop.js +25 -88
- package/dist/commands/improve/preparation.js +1034 -813
- package/dist/commands/improve/proactive-maintenance.js +34 -9
- package/dist/commands/improve/proposal-envelope.js +31 -0
- package/dist/commands/improve/reflect.js +983 -794
- package/dist/commands/improve/run-context.js +119 -0
- package/dist/commands/improve/salience.js +24 -127
- package/dist/commands/improve/session-asset.js +7 -3
- package/dist/commands/improve/shared.js +14 -34
- package/dist/commands/improve/source-identity.js +28 -0
- package/dist/commands/improve/triage.js +20 -17
- package/dist/commands/lint/base-linter.js +340 -313
- package/dist/commands/lint/env-key-rules.js +31 -47
- package/dist/commands/lint/index.js +185 -30
- package/dist/commands/{events.js → log.js} +28 -38
- package/dist/commands/migrate-cli.js +54 -0
- package/dist/commands/migration-tool.js +55 -0
- package/dist/commands/observability-cli.js +70 -208
- package/dist/commands/proposal/diff-format.js +50 -0
- package/dist/commands/proposal/drain-policies.js +0 -6
- package/dist/commands/proposal/drain.js +91 -40
- package/dist/commands/proposal/proposal-cli.js +134 -132
- package/dist/commands/proposal/proposal-types.js +56 -0
- package/dist/commands/proposal/proposal.js +83 -65
- package/dist/commands/proposal/propose-cli.js +88 -0
- package/dist/commands/proposal/propose.js +105 -88
- package/dist/commands/proposal/repository.js +1303 -278
- package/dist/commands/proposal/validators/proposal-quality-validators.js +16 -6
- package/dist/commands/proposal/validators/proposal-validators.js +61 -12
- package/dist/commands/proposal/validators/proposals.js +6 -8
- package/dist/commands/read/curate.js +78 -73
- package/dist/commands/read/knowledge.js +510 -13
- package/dist/commands/read/registry-search.js +2 -2
- package/dist/commands/read/remember-cli.js +84 -15
- package/dist/commands/read/search-cli.js +203 -96
- package/dist/commands/read/search.js +126 -94
- package/dist/commands/read/show.js +226 -250
- package/dist/commands/registry-cli.js +34 -60
- package/dist/commands/remember.js +18 -57
- package/dist/commands/sources/add-cli.js +104 -49
- package/dist/commands/sources/bundle-cli.js +166 -0
- package/dist/commands/sources/bundle-config-ops.js +63 -0
- package/dist/commands/sources/info.js +27 -15
- package/dist/commands/sources/init.js +30 -40
- package/dist/commands/sources/installed-stashes.js +469 -172
- package/dist/commands/sources/schema-repair.js +10 -9
- package/dist/commands/sources/self-update.js +182 -121
- package/dist/commands/sources/source-add.js +169 -178
- package/dist/commands/sources/source-clone.js +144 -41
- package/dist/commands/sources/source-manage.js +94 -59
- package/dist/commands/sources/sources-cli.js +64 -205
- package/dist/commands/sources/stash-cli.js +91 -54
- package/dist/commands/sources/stash-skeleton.js +1 -1
- package/dist/commands/tasks/tasks-cli.js +106 -104
- package/dist/commands/tasks/tasks.js +445 -262
- package/dist/commands/workflow-cli.js +75 -228
- package/dist/core/action-contributors.js +1 -1
- package/dist/core/activation-policy.js +49 -0
- package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
- package/dist/core/adapter/adapters/akm-adapter.js +528 -0
- package/dist/core/adapter/adapters/akm-lint.js +392 -0
- package/dist/core/adapter/adapters/akm-metadata.js +387 -0
- package/dist/core/adapter/adapters/akm-task-adapter.js +149 -0
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +180 -0
- package/dist/core/adapter/adapters/claude-adapter.js +61 -0
- package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
- package/dist/core/adapter/adapters/generic-files-adapter.js +119 -0
- package/dist/core/adapter/adapters/index.js +80 -0
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +419 -0
- package/dist/core/adapter/adapters/okf-adapter.js +391 -0
- package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
- package/dist/core/adapter/adapters/shared.js +286 -0
- package/dist/core/adapter/adapters/tool-dir-shared.js +217 -0
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +155 -0
- package/dist/core/adapter/bundle-adapter.js +4 -0
- package/dist/core/adapter/detect-adapter.js +17 -0
- package/dist/core/adapter/recognize-match.js +44 -0
- package/dist/core/adapter/registry.js +56 -0
- package/dist/core/adapter/types.js +4 -0
- package/dist/core/asset/akm-markdown.js +30 -0
- package/dist/core/asset/asset-placement.js +243 -0
- package/dist/core/asset/asset-ref.js +110 -79
- package/dist/core/asset/asset-serialize.js +20 -0
- package/dist/core/asset/frontmatter.js +28 -12
- package/dist/core/asset/markdown.js +40 -51
- package/dist/core/asset/resolve-ref.js +274 -0
- package/dist/core/asset/stash-meta.js +2 -2
- package/dist/core/bundle-id.js +51 -0
- package/dist/core/common.js +281 -86
- package/dist/core/config/config-io.js +42 -128
- package/dist/core/config/config-schema.js +233 -855
- package/dist/core/config/config-sources.js +162 -39
- package/dist/core/config/config-types.js +16 -11
- package/dist/core/config/config-version.js +29 -0
- package/dist/core/config/config-walker.js +126 -37
- package/dist/core/config/config.js +154 -331
- package/dist/core/config/deep-merge.js +41 -0
- package/dist/core/config/engine-semantics.js +28 -0
- package/dist/core/config/experimental.js +21 -0
- package/dist/core/config/schema/embedding.js +38 -0
- package/dist/core/config/schema/engines.js +116 -0
- package/dist/core/config/schema/experimental.js +47 -0
- package/dist/core/config/schema/feedback.js +31 -0
- package/dist/core/config/schema/improve-processes.js +389 -0
- package/dist/core/config/schema/improve.js +94 -0
- package/dist/core/config/schema/index-config.js +176 -0
- package/dist/core/config/schema/output.js +18 -0
- package/dist/core/config/schema/primitives.js +94 -0
- package/dist/core/config/schema/search.js +30 -0
- package/dist/core/config/schema/setup.js +18 -0
- package/dist/core/config/schema/sources-bundles.js +169 -0
- package/dist/core/config/schema/workflow.js +29 -0
- package/dist/core/env-secret-ref.js +155 -20
- package/dist/core/errors.js +17 -15
- package/dist/core/events-types.js +4 -0
- package/dist/core/events.js +46 -128
- package/dist/core/extra-params.js +62 -0
- package/dist/core/file-change.js +17 -0
- package/dist/core/file-lock.js +202 -57
- package/dist/core/fs-txn.js +392 -0
- package/dist/core/git-message.js +59 -0
- package/dist/core/improve-result.js +167 -0
- package/dist/core/lesson-lint.js +1 -17
- package/dist/core/logs-db.js +1 -1
- package/dist/core/maintenance-barrier.js +135 -0
- package/dist/core/migration-operation.js +44 -0
- package/dist/core/mutation-target.js +78 -0
- package/dist/core/paths.js +22 -25
- package/dist/core/platform.js +10 -0
- package/dist/core/recognition-util.js +128 -0
- package/dist/core/redaction.js +392 -0
- package/dist/core/standards/resolve-standards-context.js +36 -65
- package/dist/core/standards/resolve-stash-standards.js +2 -2
- package/dist/core/standards/resolve-type-conventions.js +5 -5
- package/dist/core/state/migrations.js +242 -11
- package/dist/core/state-db.js +98 -10
- package/dist/core/structured.js +1 -1
- package/dist/core/subprocess.js +303 -0
- package/dist/core/text-truncation.js +9 -5
- package/dist/core/time.js +20 -0
- package/dist/core/type-presentation.js +130 -0
- package/dist/core/warn.js +0 -3
- package/dist/core/write-source.js +834 -118
- package/dist/indexer/bundle-identity-guard.js +92 -0
- package/dist/indexer/db/graph-db.js +1 -25
- package/dist/indexer/db/llm-cache.js +1 -1
- package/dist/indexer/ensure-index.js +30 -9
- package/dist/indexer/graph/graph-boost.js +9 -30
- package/dist/indexer/graph/graph-extraction.js +41 -27
- package/dist/indexer/graph/graph-types.js +4 -0
- package/dist/indexer/index-writer-lock.js +93 -49
- package/dist/indexer/index-written-assets.js +100 -53
- package/dist/indexer/indexer.js +746 -329
- package/dist/indexer/init.js +18 -25
- package/dist/indexer/installations.js +142 -0
- package/dist/indexer/passes/dir-staleness.js +18 -10
- package/dist/indexer/passes/memory-inference.js +25 -15
- package/dist/indexer/passes/metadata.js +412 -243
- package/dist/indexer/scan/doc-to-entry.js +160 -0
- package/dist/indexer/scan/drain-dir.js +134 -0
- package/dist/indexer/search/db-search.js +292 -108
- package/dist/indexer/search/fts-query.js +64 -0
- package/dist/indexer/search/ranking-contributors.js +145 -25
- package/dist/indexer/search/ranking-types.js +4 -0
- package/dist/indexer/search/ranking.js +28 -71
- package/dist/indexer/search/search-attribution.js +67 -0
- package/dist/indexer/search/search-fields.js +18 -3
- package/dist/indexer/search/search-hit-enrichers.js +30 -40
- package/dist/indexer/search/search-source.js +157 -111
- package/dist/indexer/search/semantic-status.js +4 -1
- package/dist/indexer/usage/usage-events.js +10 -30
- package/dist/indexer/walk/file-context.js +3 -45
- package/dist/indexer/walk/matchers.js +42 -73
- package/dist/indexer/walk/path-resolver.js +11 -5
- package/dist/indexer/walk/walker.js +42 -14
- package/dist/integrations/agent/builder-shared.js +7 -0
- package/dist/integrations/agent/builders.js +5 -58
- package/dist/integrations/agent/config.js +3 -143
- package/dist/integrations/agent/detect.js +17 -2
- package/dist/integrations/agent/engine-resolution.js +231 -0
- package/dist/integrations/agent/index.js +1 -2
- package/dist/integrations/agent/model-aliases.js +8 -3
- package/dist/integrations/agent/profiles.js +6 -99
- package/dist/integrations/agent/prompts.js +46 -18
- package/dist/integrations/agent/runner-dispatch.js +78 -13
- package/dist/integrations/agent/runner.js +76 -208
- package/dist/integrations/agent/spawn.js +48 -279
- package/dist/integrations/harnesses/aider/agent-builder.js +9 -8
- package/dist/integrations/harnesses/aider/index.js +2 -12
- package/dist/integrations/harnesses/amazonq/agent-builder.js +10 -16
- package/dist/integrations/harnesses/amazonq/index.js +3 -17
- package/dist/integrations/harnesses/claude/agent-builder.js +2 -3
- package/dist/integrations/harnesses/claude/config-import.js +1 -3
- package/dist/integrations/harnesses/claude/index.js +1 -14
- package/dist/integrations/harnesses/claude/session-log.js +27 -75
- package/dist/integrations/harnesses/codex/agent-builder.js +8 -7
- package/dist/integrations/harnesses/codex/index.js +2 -13
- package/dist/integrations/harnesses/copilot/agent-builder.js +9 -9
- package/dist/integrations/harnesses/copilot/index.js +1 -13
- package/dist/integrations/harnesses/gemini/agent-builder.js +8 -9
- package/dist/integrations/harnesses/gemini/index.js +1 -13
- package/dist/integrations/harnesses/ids.js +24 -0
- package/dist/integrations/harnesses/index.js +31 -33
- package/dist/integrations/harnesses/opencode/agent-builder.js +23 -5
- package/dist/integrations/harnesses/opencode/config-import.js +1 -3
- package/dist/integrations/harnesses/opencode/index.js +1 -18
- package/dist/integrations/harnesses/opencode/session-log.js +67 -125
- package/dist/integrations/harnesses/opencode-sdk/harness.js +3 -17
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +274 -191
- package/dist/integrations/harnesses/openhands/agent-builder.js +12 -10
- package/dist/integrations/harnesses/openhands/index.js +2 -12
- package/dist/integrations/harnesses/pi/agent-builder.js +11 -18
- package/dist/integrations/harnesses/pi/index.js +3 -16
- package/dist/integrations/harnesses/shared.js +17 -0
- package/dist/integrations/harnesses/types.js +38 -34
- package/dist/integrations/lockfile.js +211 -24
- package/dist/integrations/session-logs/index.js +24 -40
- package/dist/integrations/session-logs/provider-base.js +113 -0
- package/dist/llm/client.js +182 -110
- package/dist/llm/embedders/deterministic.js +2 -2
- package/dist/llm/embedders/remote.js +21 -9
- package/dist/llm/feature-gate.js +17 -57
- package/dist/llm/graph-extract.js +12 -13
- package/dist/llm/index-passes.js +8 -42
- package/dist/llm/memory-infer.js +144 -1
- package/dist/llm/metadata-enhance.js +45 -30
- package/dist/llm/structured-call.js +16 -8
- package/dist/llm/usage-persist.js +30 -5
- package/dist/llm/usage-telemetry.js +59 -6
- package/dist/output/cli-hints.js +1 -2
- package/dist/output/command-registry.js +27 -0
- package/dist/output/context.js +22 -7
- package/dist/output/format-exempt.js +80 -0
- package/dist/output/generic-render.js +251 -0
- package/dist/output/html-render.js +11 -16
- package/dist/output/render-registry.js +57 -0
- package/dist/output/renderers.js +15 -281
- package/dist/output/shapes/curate.js +10 -1
- package/dist/output/shapes/events.js +12 -7
- package/dist/output/shapes/helpers.js +58 -84
- package/dist/output/shapes/passthrough.js +8 -40
- package/dist/output/shapes/proposal/producer.js +15 -7
- package/dist/output/shapes/registry.js +12 -6
- package/dist/output/shapes.js +0 -9
- package/dist/output/text/{init.js → bundle-create.js} +3 -1
- package/dist/output/text/bundle-show.js +7 -0
- package/dist/output/text/command-format.js +562 -0
- package/dist/output/text/env.js +1 -3
- package/dist/output/text/events.js +8 -7
- package/dist/output/text/helpers.js +15 -1375
- package/dist/output/text/proposal/producer.js +4 -2
- package/dist/output/text/proposal-format.js +202 -0
- package/dist/output/text/registry-commands.js +1 -2
- package/dist/output/text/registry.js +12 -6
- package/dist/output/text/show-directives.js +117 -0
- package/dist/output/text/show-format.js +103 -0
- package/dist/output/text/sync.js +5 -0
- package/dist/output/text/workflow-format.js +332 -0
- package/dist/output/text/workflow.js +1 -2
- package/dist/output/text.js +10 -19
- package/dist/registry/factory.js +4 -6
- package/dist/registry/origin-resolve.js +16 -27
- package/dist/registry/providers/skills-sh.js +3 -3
- package/dist/registry/providers/static-index.js +15 -25
- package/dist/registry/resolve.js +43 -94
- package/dist/registry/semver.js +43 -0
- package/dist/runtime.js +81 -12
- package/dist/scripts/akm-migrate.js +35529 -0
- package/dist/setup/detect.js +5 -7
- package/dist/setup/detected-engines.js +136 -0
- package/dist/setup/engine-config.js +100 -0
- package/dist/setup/registry-stash-loader.js +3 -3
- package/dist/setup/semantic-assets.js +12 -9
- package/dist/setup/setup.js +444 -208
- package/dist/setup/steps/connection-shared.js +120 -0
- package/dist/setup/steps/connection.js +108 -305
- package/dist/setup/steps/platforms.js +13 -12
- package/dist/setup/steps/semantic.js +15 -3
- package/dist/setup/steps/sources.js +21 -15
- package/dist/setup/steps/stashdir.js +6 -4
- package/dist/setup/steps/tasks.js +236 -119
- package/dist/setup/steps.js +3 -2
- package/dist/sources/freshness.js +39 -0
- package/dist/sources/provider-factory.js +11 -17
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +278 -34
- package/dist/sources/providers/git-provider.js +54 -56
- package/dist/sources/providers/git-stash.js +420 -91
- package/dist/sources/providers/git.js +2 -2
- package/dist/sources/providers/npm.js +16 -19
- package/dist/sources/providers/provider-utils.js +47 -22
- package/dist/sources/providers/sync-from-ref.js +3 -9
- package/dist/sources/providers/website.js +2 -2
- package/dist/sources/resolve.js +11 -10
- package/dist/sources/snapshot-fetchers/types.js +4 -0
- package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +110 -41
- package/dist/storage/database.js +60 -4
- package/dist/storage/engines/sqlite-migrations.js +156 -5
- package/dist/storage/locations.js +1 -2
- package/dist/storage/repositories/canaries-repository.js +1 -1
- package/dist/storage/repositories/events-repository.js +51 -11
- package/dist/storage/repositories/improve-runs-repository.js +6 -32
- package/dist/storage/repositories/index-connection.js +79 -0
- package/dist/storage/repositories/index-db.js +4 -3
- package/dist/storage/repositories/index-entries-repository.js +863 -0
- package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +19 -2
- package/dist/storage/repositories/index-entry-types.js +4 -0
- package/dist/storage/repositories/index-fts-repository.js +167 -0
- package/dist/storage/repositories/index-llm-cache-repository.js +108 -0
- package/dist/storage/repositories/index-meta-repository.js +49 -0
- package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +226 -100
- package/dist/storage/repositories/index-sql.js +12 -0
- package/dist/storage/repositories/index-utility-repository.js +356 -0
- package/dist/storage/repositories/index-vec-repository.js +250 -0
- package/dist/storage/repositories/outcome-repository.js +119 -0
- package/dist/storage/repositories/proposals-repository.js +317 -75
- package/dist/storage/repositories/registry-cache.js +1 -1
- package/dist/storage/repositories/salience-repository.js +172 -0
- package/dist/storage/repositories/task-history-repository.js +110 -3
- package/dist/storage/repositories/workflow-runs-repository.js +68 -35
- package/dist/tasks/backends/cron.js +169 -46
- package/dist/tasks/backends/exec-utils.js +76 -3
- package/dist/tasks/backends/index.js +6 -9
- package/dist/tasks/backends/launchd.js +292 -55
- package/dist/tasks/backends/schtasks.js +557 -70
- package/dist/tasks/backends/types.js +4 -0
- package/dist/tasks/command-executable.js +93 -0
- package/dist/tasks/embedded.js +56 -38
- package/dist/tasks/parser.js +156 -64
- package/dist/tasks/resolve-akm-bin.js +144 -51
- package/dist/tasks/runner.js +377 -209
- package/dist/tasks/schedule.js +108 -19
- package/dist/tasks/scheduler-invocation.js +296 -0
- package/dist/tasks/schema.js +1 -1
- package/dist/tasks/task-id.js +35 -0
- package/dist/tasks/validator.js +30 -16
- package/dist/workflows/authoring/authoring.js +96 -148
- package/dist/workflows/authoring/scope-key.js +1 -1
- package/dist/workflows/cli.js +0 -20
- package/dist/workflows/concurrency-policy.js +15 -0
- package/dist/workflows/exec/brief.js +25 -59
- package/dist/workflows/exec/frozen-judge.js +47 -0
- package/dist/workflows/exec/native-executor.js +157 -94
- package/dist/workflows/exec/report.js +365 -200
- package/dist/workflows/exec/run-workflow.js +46 -40
- package/dist/workflows/exec/scheduler.js +12 -41
- package/dist/workflows/exec/step-work.js +239 -205
- package/dist/workflows/exec/workflow-engine-gate.js +67 -0
- package/dist/workflows/ir/compile.js +141 -283
- package/dist/workflows/ir/freeze.js +233 -0
- package/dist/workflows/ir/plan-hash.js +40 -5
- package/dist/workflows/ir/schema.js +537 -1
- package/dist/workflows/parser.js +878 -306
- package/dist/workflows/program/expressions.js +20 -208
- package/dist/workflows/program/schema.js +7 -10
- package/dist/workflows/renderer.js +99 -121
- package/dist/workflows/resource-limits.js +22 -0
- package/dist/workflows/runtime/checkin.js +1 -1
- package/dist/workflows/runtime/plan-classifier.js +131 -0
- package/dist/workflows/runtime/runs.js +200 -113
- package/dist/workflows/runtime/unit-checkin.js +1 -1
- package/dist/workflows/runtime/unit-phases.js +20 -0
- package/dist/workflows/runtime/workflow-asset-loader.js +235 -97
- package/dist/workflows/schema.js +1 -11
- package/dist/workflows/validate-summary.js +4 -26
- package/dist/workflows/validator.js +52 -30
- package/docs/README.md +42 -78
- package/docs/migration/README.md +8 -0
- package/docs/migration/release-notes/0.6.0.md +1 -1
- package/docs/migration/release-notes/0.7.0.md +9 -8
- package/docs/migration/release-notes/0.9.0.md +158 -14
- package/docs/migration/v0.7-to-v0.8.md +46 -47
- package/docs/migration/v0.8-to-v0.9.md +844 -0
- package/docs/reference/README.md +12 -0
- package/docs/reference/data-and-telemetry.md +333 -0
- package/package.json +21 -17
- package/schemas/akm-asset-envelope.json +93 -0
- package/schemas/akm-config.json +4636 -0
- package/schemas/akm-task.json +87 -0
- package/{dist/schemas → schemas}/akm-workflow.json +127 -82
- package/dist/akm-migrate-storage +0 -38
- package/dist/assets/help/help-accept.md +0 -12
- package/dist/assets/help/help-improve.md +0 -84
- package/dist/assets/help/help-proposals.md +0 -17
- package/dist/assets/help/help-propose.md +0 -17
- package/dist/assets/help/help-reject.md +0 -11
- package/dist/assets/profiles/frequent.json +0 -13
- package/dist/assets/profiles/recombine-only.json +0 -21
- package/dist/assets/profiles/reflect-distill.json +0 -30
- package/dist/assets/profiles/synthesize.json +0 -15
- package/dist/assets/prompts/procedural-system.md +0 -44
- package/dist/assets/prompts/recombine-system.md +0 -40
- package/dist/assets/prompts/staleness-detect-system.md +0 -6
- package/dist/assets/tasks/core/backup.yml +0 -4
- package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
- package/dist/assets/templates/html/default.html +0 -78
- package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
- package/dist/assets/wiki/index-template.md +0 -12
- package/dist/assets/wiki/ingest-workflow-template.md +0 -83
- package/dist/assets/wiki/log-template.md +0 -8
- package/dist/assets/wiki/schema-template.md +0 -61
- package/dist/cli/config-migrate.js +0 -150
- package/dist/cli/config-validate.js +0 -39
- package/dist/commands/graph/graph-cli.js +0 -124
- package/dist/commands/graph/graph.js +0 -487
- package/dist/commands/improve/calibration.js +0 -161
- package/dist/commands/improve/dedup.js +0 -482
- package/dist/commands/improve/extract-watch.js +0 -140
- package/dist/commands/improve/hot-probation.js +0 -45
- package/dist/commands/improve/improve-auto-accept.js +0 -276
- package/dist/commands/improve/improve-profiles.js +0 -168
- package/dist/commands/improve/procedural.js +0 -398
- package/dist/commands/improve/recombine.js +0 -818
- package/dist/commands/improve/schema-similarity-gate.js +0 -168
- package/dist/commands/lint/agent-linter.js +0 -44
- package/dist/commands/lint/command-linter.js +0 -44
- package/dist/commands/lint/default-linter.js +0 -16
- package/dist/commands/lint/fact-linter.js +0 -39
- package/dist/commands/lint/knowledge-linter.js +0 -16
- package/dist/commands/lint/memory-linter.js +0 -61
- package/dist/commands/lint/registry.js +0 -41
- package/dist/commands/lint/skill-linter.js +0 -45
- package/dist/commands/lint/task-linter.js +0 -50
- package/dist/commands/lint/workflow-linter.js +0 -81
- package/dist/commands/proposal/legacy-import.js +0 -115
- package/dist/commands/sources/history.js +0 -196
- package/dist/commands/tasks/default-tasks.js +0 -186
- package/dist/commands/wiki-cli.js +0 -292
- package/dist/core/asset/asset-registry.js +0 -76
- package/dist/core/asset/asset-spec.js +0 -316
- package/dist/core/config/config-migration.js +0 -602
- package/dist/core/deep-merge.js +0 -38
- package/dist/core/eval/rank-metrics.js +0 -113
- package/dist/core/ripgrep/install.js +0 -163
- package/dist/core/ripgrep/resolve.js +0 -81
- package/dist/indexer/db/db.js +0 -1414
- package/dist/indexer/manifest.js +0 -170
- package/dist/indexer/passes/metadata-contributors.js +0 -31
- package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -94
- package/dist/integrations/harnesses/opencode-sdk/index.js +0 -25
- package/dist/llm/call-ai.js +0 -62
- package/dist/llm/memory-infer-impl.js +0 -138
- package/dist/output/shapes/distill.js +0 -14
- package/dist/output/shapes/history.js +0 -11
- package/dist/output/text/distill.js +0 -6
- package/dist/output/text/enable-disable.js +0 -8
- package/dist/output/text/history.js +0 -6
- package/dist/output/text/wiki.js +0 -16
- package/dist/registry/build-index.js +0 -386
- package/dist/schemas/akm-config.json +0 -14225
- package/dist/scripts/migrate-storage.js +0 -13169
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -10169
- package/dist/scripts/migrations/v16-to-v17.js +0 -141
- package/dist/setup/legacy-config.js +0 -106
- package/dist/storage/repositories/consolidation-repository.js +0 -38
- package/dist/storage/repositories/recombine-repository.js +0 -213
- package/dist/wiki/wiki-templates.js +0 -15
- package/dist/wiki/wiki.js +0 -1012
- package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
- package/dist/workflows/db.js +0 -350
- package/dist/workflows/exec/watch.js +0 -116
- package/dist/workflows/program/parser.js +0 -760
- package/dist/workflows/program/project.js +0 -105
- package/docs/data-and-telemetry.md +0 -227
- package/docs/migration/release-notes/0.9.0-beta.60.md +0 -19
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
|
@@ -56,27 +56,29 @@
|
|
|
56
56
|
* dropped rather than approximated — never silently widened.
|
|
57
57
|
* - **resume/session** — NOT expressible: per the matrix OpenHands resumes
|
|
58
58
|
* from *workspace state*, not a session-id flag, so there is no flag-shaped
|
|
59
|
-
*
|
|
59
|
+
* resume to describe. The extractor still captures a
|
|
60
60
|
* conversation/session id opportunistically when the stream reveals one;
|
|
61
61
|
* akm's `workflow_run_units` remains the durable source of truth either way
|
|
62
62
|
* (plan §"Session, MCP, and identity across harnesses").
|
|
63
63
|
* - **effort** — stays unconsumed (reserved; the shared request contract's
|
|
64
64
|
* "no builder consumes it yet" note stays true).
|
|
65
65
|
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* `
|
|
69
|
-
*
|
|
66
|
+
* Registered: `openhandsBuilder` is `OpenhandsHarness.agentBuilder`
|
|
67
|
+
* (`./index.ts`), one of the ten harnesses `HARNESS_REGISTRY` constructs
|
|
68
|
+
* (`harnesses/index.ts`); `agent/builders.ts` derives `BUILTIN_BUILDERS` from
|
|
69
|
+
* that registry, so this builder is reachable under the `"openhands"`
|
|
70
|
+
* platform name without any further wiring. The registry entry also declares
|
|
71
|
+
* `pattern: "local-runner"`, `structuredOutput: "native-json"` alongside it
|
|
72
|
+
* (`./index.ts`).
|
|
70
73
|
*/
|
|
71
|
-
import { assertNotFlag } from "../../agent/builder-shared.js";
|
|
72
|
-
import { resolveModel } from "../../agent/model-aliases.js";
|
|
74
|
+
import { assertNotFlag, resolveDispatchModel, } from "../../agent/builder-shared.js";
|
|
73
75
|
/** Canonical harness/platform id used for model-alias resolution. */
|
|
74
76
|
export const OPENHANDS_PLATFORM = "openhands";
|
|
75
77
|
/**
|
|
76
78
|
* Env var OpenHands reads its LLM model from — the platform's documented
|
|
77
79
|
* model-selection channel for headless runs (there is no headless model
|
|
78
|
-
* flag). Exported
|
|
79
|
-
* constant.
|
|
80
|
+
* flag). Exported (re-exported from `./index.ts`) so this harness's tests
|
|
81
|
+
* share the one constant.
|
|
80
82
|
*/
|
|
81
83
|
export const OPENHANDS_MODEL_ENV = "LLM_MODEL";
|
|
82
84
|
/**
|
|
@@ -117,7 +119,7 @@ export const openhandsBuilder = {
|
|
|
117
119
|
args.push(`--task=${buildTaskPayload(req)}`);
|
|
118
120
|
let env;
|
|
119
121
|
if (req.model) {
|
|
120
|
-
const resolved =
|
|
122
|
+
const resolved = resolveDispatchModel(req, profile, OPENHANDS_PLATFORM);
|
|
121
123
|
// Model travels via env, not argv — OpenHands' documented channel.
|
|
122
124
|
env = { [OPENHANDS_MODEL_ENV]: resolved };
|
|
123
125
|
}
|
|
@@ -12,22 +12,12 @@
|
|
|
12
12
|
* that `HARNESS_REGISTRY` registers. Dispatch-only: no native session-log
|
|
13
13
|
* reader or config importer yet.
|
|
14
14
|
*/
|
|
15
|
+
import { caps } from "../shared.js";
|
|
15
16
|
import { BaseHarness } from "../types.js";
|
|
16
17
|
import { openhandsBuilder } from "./agent-builder.js";
|
|
17
18
|
import { openhandsResultExtractor } from "./result-extractor.js";
|
|
18
19
|
export { OPENHANDS_MODEL_ENV, OPENHANDS_PLATFORM, openhandsBuilder } from "./agent-builder.js";
|
|
19
20
|
export { openhandsResultExtractor } from "./result-extractor.js";
|
|
20
|
-
function caps(c) {
|
|
21
|
-
return {
|
|
22
|
-
sessionLogs: false,
|
|
23
|
-
agentDispatch: false,
|
|
24
|
-
detection: false,
|
|
25
|
-
configImport: false,
|
|
26
|
-
runtimeIdentity: false,
|
|
27
|
-
v1Migration: false,
|
|
28
|
-
...c,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
21
|
/**
|
|
32
22
|
* OpenHands CLI.
|
|
33
23
|
*
|
|
@@ -45,7 +35,7 @@ export class OpenhandsHarness extends BaseHarness {
|
|
|
45
35
|
// `--json` emits a documented JSONL event stream akm parses, then validates
|
|
46
36
|
// against the node schema ⇒ native-json tier.
|
|
47
37
|
structuredOutput = "native-json";
|
|
48
|
-
// No
|
|
38
|
+
// No flag-shaped resume: per the matrix OpenHands resumes from workspace state, not a
|
|
49
39
|
// session-id flag. The extractor still captures a conversation id
|
|
50
40
|
// opportunistically; akm's `workflow_run_units` remains the durable source
|
|
51
41
|
// of truth.
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
* pi -p "<prompt>"
|
|
13
13
|
*
|
|
14
14
|
* with `--mode json` for structured (JSONL) output, `--model <m>` for model
|
|
15
|
-
* selection, and `-c`/`-r`/`--session <id>` for resume
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* selection, and `-c`/`-r`/`--session <id>` for resume — not built here
|
|
16
|
+
* because `AgentDispatchRequest` carries no session id (akm's
|
|
17
|
+
* `workflow_run_units` is the durable resume source of truth).
|
|
18
18
|
*
|
|
19
19
|
* Platform-specific mapping decisions (all localized here, per the adapter
|
|
20
20
|
* contract):
|
|
@@ -43,23 +43,16 @@
|
|
|
43
43
|
* - **effort** — stays unconsumed (reserved; the shared request contract's
|
|
44
44
|
* "no builder consumes it yet" note stays true).
|
|
45
45
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
46
|
+
* Registered: `piBuilder` is `PiHarness.agentBuilder` (`./index.ts`), one of
|
|
47
|
+
* the ten harnesses `HARNESS_REGISTRY` constructs (`harnesses/index.ts`);
|
|
48
|
+
* `agent/builders.ts` derives `BUILTIN_BUILDERS` from that registry, so this
|
|
49
|
+
* builder is reachable under the `"pi"` platform name without any further
|
|
50
|
+
* wiring. The `PI_SESSION_ID` identity-env marker is declared alongside it
|
|
51
|
+
* (`./index.ts`).
|
|
50
52
|
*/
|
|
51
|
-
import { assertNotFlag } from "../../agent/builder-shared.js";
|
|
52
|
-
import { resolveModel } from "../../agent/model-aliases.js";
|
|
53
|
+
import { assertNotFlag, resolveDispatchModel, } from "../../agent/builder-shared.js";
|
|
53
54
|
/** Canonical harness/platform id used for model-alias resolution. */
|
|
54
55
|
export const PI_PLATFORM = "pi";
|
|
55
|
-
/**
|
|
56
|
-
* Flag-shaped resume support per the capability matrix (`--session <id>`).
|
|
57
|
-
* Exported for the integration task's `AkmHarness.resume` registry entry; the
|
|
58
|
-
* harness-native session id comes from the unit row (stored opportunistically
|
|
59
|
-
* by the result extractor) — akm never depends on it (plan §"Session, MCP,
|
|
60
|
-
* and identity across harnesses").
|
|
61
|
-
*/
|
|
62
|
-
export const PI_RESUME_FLAG = "--session";
|
|
63
56
|
/**
|
|
64
57
|
* Assemble the positional prompt payload: the task prompt and — when a schema
|
|
65
58
|
* is requested — the same schema directive the workflow engine's prompt
|
|
@@ -87,7 +80,7 @@ export const piBuilder = {
|
|
|
87
80
|
args.push("--system-prompt", req.systemPrompt);
|
|
88
81
|
}
|
|
89
82
|
if (req.model) {
|
|
90
|
-
const resolved =
|
|
83
|
+
const resolved = resolveDispatchModel(req, profile, PI_PLATFORM);
|
|
91
84
|
args.push("--model", resolved);
|
|
92
85
|
}
|
|
93
86
|
if (req.schema) {
|
|
@@ -12,22 +12,12 @@
|
|
|
12
12
|
* `HARNESS_REGISTRY` registers. Dispatch-only: no native session-log reader or
|
|
13
13
|
* config importer yet.
|
|
14
14
|
*/
|
|
15
|
+
import { caps } from "../shared.js";
|
|
15
16
|
import { BaseHarness } from "../types.js";
|
|
16
|
-
import {
|
|
17
|
+
import { piBuilder } from "./agent-builder.js";
|
|
17
18
|
import { piResultExtractor } from "./result-extractor.js";
|
|
18
|
-
export { PI_PLATFORM,
|
|
19
|
+
export { PI_PLATFORM, piBuilder } from "./agent-builder.js";
|
|
19
20
|
export { piResultExtractor } from "./result-extractor.js";
|
|
20
|
-
function caps(c) {
|
|
21
|
-
return {
|
|
22
|
-
sessionLogs: false,
|
|
23
|
-
agentDispatch: false,
|
|
24
|
-
detection: false,
|
|
25
|
-
configImport: false,
|
|
26
|
-
runtimeIdentity: false,
|
|
27
|
-
v1Migration: false,
|
|
28
|
-
...c,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
21
|
/**
|
|
32
22
|
* Pi coding-agent CLI.
|
|
33
23
|
*
|
|
@@ -45,9 +35,6 @@ export class PiHarness extends BaseHarness {
|
|
|
45
35
|
// `--mode json` emits a documented JSONL event stream akm parses, then
|
|
46
36
|
// validates against the node schema ⇒ native-json tier.
|
|
47
37
|
structuredOutput = "native-json";
|
|
48
|
-
// `pi --session <id>` replays a previous session (the matrix's -c/-r/
|
|
49
|
-
// --session family; the id-taking long form is the registered flag).
|
|
50
|
-
resume = { flag: PI_RESUME_FLAG, takesSessionId: true };
|
|
51
38
|
// Session-id env marker only — the matrix's bare PI_* presence vars must
|
|
52
39
|
// not stamp identity onto manual runs (see `AkmHarness.identityEnv`).
|
|
53
40
|
identityEnv = ["PI_SESSION_ID"];
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
export function caps(c) {
|
|
5
|
+
return {
|
|
6
|
+
sessionLogs: false,
|
|
7
|
+
agentDispatch: false,
|
|
8
|
+
detection: false,
|
|
9
|
+
configImport: false,
|
|
10
|
+
runtimeIdentity: false,
|
|
11
|
+
...c,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** Home directory used for filesystem-only harness config detection. */
|
|
15
|
+
export function homeDir() {
|
|
16
|
+
return process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
17
|
+
}
|
|
@@ -1,14 +1,47 @@
|
|
|
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
|
+
/**
|
|
5
|
+
* Type-guard narrowing a harness to {@link SessionLogCapableHarness}.
|
|
6
|
+
*
|
|
7
|
+
* `Array.prototype.filter`'s type-predicate overload requires the predicate's
|
|
8
|
+
* inferred type to extend the array's element type — a plain
|
|
9
|
+
* `(h: AkmHarness) => h is SessionLogCapableHarness` predicate fails that
|
|
10
|
+
* constraint against `HARNESS_REGISTRY`'s element type (the union of the ten
|
|
11
|
+
* concrete harness classes, each with literal `id`s narrower than
|
|
12
|
+
* `SessionLogCapableHarness`'s `id: string`), so `.filter` would silently fall
|
|
13
|
+
* back to its non-narrowing overload. Generic over the input `H` and
|
|
14
|
+
* intersecting it into the predicate (`H & SessionLogCapableHarness`) keeps
|
|
15
|
+
* the result always a subtype of `H`, so the constraint holds regardless of
|
|
16
|
+
* what concrete harness type(s) `H` resolves to — this is what lets
|
|
17
|
+
* `HARNESS_REGISTRY.filter(isSessionLogHarness)` (in `./index.ts`) actually
|
|
18
|
+
* narrow to a type where `sessionLogProvider` is known-present, retiring the
|
|
19
|
+
* load-time throw that used to guard this in `session-logs/index.ts`.
|
|
20
|
+
*/
|
|
21
|
+
export function isSessionLogHarness(h) {
|
|
22
|
+
return h.capabilities.sessionLogs;
|
|
23
|
+
}
|
|
4
24
|
/**
|
|
5
25
|
* Shared base for harness descriptors (#566).
|
|
6
26
|
*
|
|
7
|
-
* Provides
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
27
|
+
* Provides shared optional descriptor fields for concrete harnesses.
|
|
28
|
+
*
|
|
29
|
+
* Deliberately implements {@link AkmHarnessCommon}, NOT the discriminated
|
|
30
|
+
* `AkmHarness` union (WI-9.7, H1): `AkmHarnessCommon` excludes `capabilities`
|
|
31
|
+
* and `sessionLogProvider`, the two fields whose pairing the union enforces.
|
|
32
|
+
* A base class shared by both branches cannot itself satisfy either specific
|
|
33
|
+
* union member — `capabilities` stays declared `abstract` at the (widened)
|
|
34
|
+
* `HarnessCapabilities` union type here, and each subclass narrows it to a
|
|
35
|
+
* literal `sessionLogs: true`/`false` variant via `caps({...})`.
|
|
36
|
+
* `sessionLogProvider` is intentionally NOT declared here at all (not even
|
|
37
|
+
* optional): the 8 non-session-log subclasses simply never declare it, which
|
|
38
|
+
* satisfies `NonSessionLogHarness`'s `sessionLogProvider?: undefined` (an
|
|
39
|
+
* absent optional property satisfies an `undefined`-typed optional); had this
|
|
40
|
+
* class declared it as `sessionLogProvider?: () => SessionLogHarness`
|
|
41
|
+
* instead, every non-session-log subclass would inherit that (function |
|
|
42
|
+
* undefined) type and fail to satisfy `NonSessionLogHarness` at the
|
|
43
|
+
* `HARNESS_REGISTRY` `satisfies` check. The two session-log subclasses
|
|
44
|
+
* (Claude, OpenCode) declare their own required `sessionLogProvider`.
|
|
12
45
|
*/
|
|
13
46
|
export class BaseHarness {
|
|
14
47
|
runtimeId;
|
|
@@ -16,36 +49,7 @@ export class BaseHarness {
|
|
|
16
49
|
agentBuilder;
|
|
17
50
|
pattern;
|
|
18
51
|
structuredOutput;
|
|
19
|
-
resume;
|
|
20
52
|
identityEnv;
|
|
21
53
|
presenceEnv;
|
|
22
54
|
resultExtractor;
|
|
23
|
-
sessionLogProvider;
|
|
24
|
-
/**
|
|
25
|
-
* Lowercase prefixes that a decorated v1 profile name may start with and
|
|
26
|
-
* still belong to this harness (e.g. `["opencode-sdk"]`). The canonical id
|
|
27
|
-
* and aliases are always matched in addition to these; an empty list means
|
|
28
|
-
* only exact id/alias matches.
|
|
29
|
-
*/
|
|
30
|
-
v1ProfilePrefixes = [];
|
|
31
|
-
matchesV1ProfileName(name) {
|
|
32
|
-
// Only harnesses with a v1→v2 mapping participate; others never claim a
|
|
33
|
-
// legacy profile name (so unknown names are dropped, not misclassified).
|
|
34
|
-
if (!this.capabilities.v1Migration)
|
|
35
|
-
return false;
|
|
36
|
-
const lower = name.trim().toLowerCase();
|
|
37
|
-
if (!lower)
|
|
38
|
-
return false;
|
|
39
|
-
if (lower === this.id.toLowerCase())
|
|
40
|
-
return true;
|
|
41
|
-
for (const alias of this.aliases) {
|
|
42
|
-
if (lower === alias.toLowerCase())
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
45
|
-
for (const prefix of this.v1ProfilePrefixes) {
|
|
46
|
-
if (lower.startsWith(prefix.toLowerCase()))
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
55
|
}
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { writeFileAtomic } from "../core/common.js";
|
|
7
|
-
import { rethrowIfTestIsolationError } from "../core/errors.js";
|
|
8
|
-
import { probeLock, releaseLock, tryAcquireLockSync } from "../core/file-lock.js";
|
|
7
|
+
import { ConfigError, rethrowIfTestIsolationError } from "../core/errors.js";
|
|
8
|
+
import { createLockPayload, probeLock, reclaimStaleLock, releaseLock, tryAcquireLockSync } from "../core/file-lock.js";
|
|
9
|
+
import { acquireMaintenanceBarrier } from "../core/maintenance-barrier.js";
|
|
9
10
|
import { getDataDir, getLockfileLockPath, getLockfilePath } from "../core/paths.js";
|
|
10
11
|
// ── Lock sentinel ────────────────────────────────────────────────────────────
|
|
11
12
|
const LOCK_MAX_RETRIES = 3;
|
|
@@ -15,23 +16,26 @@ async function acquireLockSentinel() {
|
|
|
15
16
|
// Ensure the directory exists before attempting to create the sentinel.
|
|
16
17
|
fs.mkdirSync(path.dirname(sentinelPath), { recursive: true });
|
|
17
18
|
for (let attempt = 0; attempt < LOCK_MAX_RETRIES; attempt++) {
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
const releaseBarrier = acquireMaintenanceBarrier();
|
|
20
|
+
try {
|
|
21
|
+
const ownership = tryAcquireLockSync(sentinelPath, createLockPayload());
|
|
22
|
+
if (ownership) {
|
|
23
|
+
return () => releaseLock(ownership);
|
|
24
|
+
}
|
|
25
|
+
const probe = probeLock(sentinelPath);
|
|
26
|
+
if (probe.state === "stale" && reclaimStaleLock(sentinelPath, probe)) {
|
|
27
|
+
continue; // Reclaimed — retry immediately.
|
|
28
|
+
}
|
|
20
29
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
continue; // Reclaimed — retry immediately.
|
|
30
|
+
finally {
|
|
31
|
+
releaseBarrier();
|
|
24
32
|
}
|
|
25
33
|
// Another process holds the lock — wait briefly before retrying.
|
|
26
34
|
if (attempt < LOCK_MAX_RETRIES - 1) {
|
|
27
35
|
await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_DELAY_MS));
|
|
28
36
|
}
|
|
29
37
|
}
|
|
30
|
-
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
function releaseLockSentinel() {
|
|
34
|
-
releaseLock(getLockfileLockPath());
|
|
38
|
+
throw new ConfigError(`Could not acquire lockfile sentinel at ${sentinelPath}; refusing to write without exclusive ownership.`, "INVALID_CONFIG_FILE");
|
|
35
39
|
}
|
|
36
40
|
// ── Read / Write ────────────────────────────────────────────────────────────
|
|
37
41
|
export function readLockfile() {
|
|
@@ -50,40 +54,223 @@ export function readLockfile() {
|
|
|
50
54
|
return [];
|
|
51
55
|
}
|
|
52
56
|
}
|
|
53
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Like {@link readLockfile}, but THROWS instead of silently degrading to `[]`
|
|
59
|
+
* when the on-disk lockfile exists yet is not parseable JSON or not a JSON
|
|
60
|
+
* array (R-012).
|
|
61
|
+
*
|
|
62
|
+
* `readLockfile`'s fail-open contract is intentional for READ paths — a
|
|
63
|
+
* corrupt lock degrades a managed bundle to "unmanaged" rather than erroring
|
|
64
|
+
* every read-only command (`list`, `installed-stashes`, …). But
|
|
65
|
+
* {@link upsertLockEntry} and {@link removeLockEntry} read the current
|
|
66
|
+
* entries and then WRITE `[...entries, change]` back out; if that read
|
|
67
|
+
* silently returned `[]` for a corrupt file, the write would silently
|
|
68
|
+
* replace the corrupt file with one containing only the single new/changed
|
|
69
|
+
* entry — permanently destroying every other surviving lock record. Write
|
|
70
|
+
* paths use this strict variant so a corrupt lockfile fails the operation
|
|
71
|
+
* loudly (matching the guard `mergeLockEntriesSync` already applies) instead
|
|
72
|
+
* of quietly deleting user state. A missing file is NOT corruption — there
|
|
73
|
+
* is nothing to preserve, so that case still returns `[]`. Entries that fail
|
|
74
|
+
* per-entry validation are still tolerated (filtered out), matching
|
|
75
|
+
* `readLockfile`'s existing shape-tolerant behavior.
|
|
76
|
+
*/
|
|
77
|
+
function readLockfileOrThrow() {
|
|
78
|
+
const lockfilePath = getLockfilePath();
|
|
79
|
+
let raw;
|
|
80
|
+
try {
|
|
81
|
+
raw = fs.readFileSync(lockfilePath, "utf8");
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
rethrowIfTestIsolationError(err);
|
|
85
|
+
return []; // File does not exist (or is otherwise unreadable) — nothing to preserve.
|
|
86
|
+
}
|
|
87
|
+
let parsed;
|
|
88
|
+
try {
|
|
89
|
+
parsed = JSON.parse(raw);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
throw new ConfigError(`Refusing to modify lockfile ${lockfilePath}: existing content is not valid JSON (${error instanceof Error ? error.message : String(error)}). Fix or remove the file by hand before retrying — every existing lock entry would otherwise be lost.`, "INVALID_CONFIG_FILE");
|
|
93
|
+
}
|
|
94
|
+
if (!Array.isArray(parsed)) {
|
|
95
|
+
throw new ConfigError(`Refusing to modify lockfile ${lockfilePath}: existing content is not a JSON array. Fix or remove the file by hand before retrying — every existing lock entry would otherwise be lost.`, "INVALID_CONFIG_FILE");
|
|
96
|
+
}
|
|
97
|
+
return parsed.filter(isValidLockfileEntry);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The materialized content root recorded in the lock for a managed (git/npm)
|
|
101
|
+
* bundle — spec §10.2 desired/resolved split, where the desired config carries
|
|
102
|
+
* only the source LOCATOR and the resolved `localRoot` lives here.
|
|
103
|
+
*
|
|
104
|
+
* This is the SINGLE lock-first resolution point shared by the indexer READ
|
|
105
|
+
* path (`resolveEntryContentDir` in indexer/search) and the command-layer WRITE
|
|
106
|
+
* path (`adaptConfiguredSource` in core/write-source): consulting it first makes
|
|
107
|
+
* a write land in exactly the directory a read walks. Returns `undefined` for a
|
|
108
|
+
* bundle with no lock `localRoot` (e.g. a config migrated from a `sources[]`
|
|
109
|
+
* url, whose provider re-derives the cache path) or a non-managed type, so both
|
|
110
|
+
* callers fall back to the identical provider-path derivation.
|
|
111
|
+
*/
|
|
112
|
+
export function lockContentRootFor(bundleId, type) {
|
|
113
|
+
if (!bundleId || (type !== "git" && type !== "npm"))
|
|
114
|
+
return undefined;
|
|
115
|
+
for (const lock of readLockfile()) {
|
|
116
|
+
if (lock.id === bundleId && typeof lock.localRoot === "string" && lock.localRoot.length > 0) {
|
|
117
|
+
return lock.localRoot;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
function writeLockfileUnlocked(entries) {
|
|
54
123
|
// Always write to $DATA — never to the legacy $CONFIG location.
|
|
55
124
|
const lockfilePath = getLockfilePath();
|
|
56
125
|
const dir = path.dirname(lockfilePath);
|
|
57
126
|
fs.mkdirSync(dir, { recursive: true });
|
|
58
127
|
writeFileAtomic(lockfilePath, `${JSON.stringify(entries, null, 2)}\n`);
|
|
59
128
|
}
|
|
129
|
+
export async function writeLockfile(entries) {
|
|
130
|
+
const release = await acquireLockSentinel();
|
|
131
|
+
try {
|
|
132
|
+
writeLockfileUnlocked(entries);
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
release();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/** Replace one exact parsed lock generation while the lockfile sentinel is held. */
|
|
139
|
+
export async function compareAndSwapLockfile(expected, desired) {
|
|
140
|
+
const release = await acquireLockSentinel();
|
|
141
|
+
try {
|
|
142
|
+
const current = readLockfileOrThrow();
|
|
143
|
+
if (JSON.stringify(current) !== JSON.stringify(expected))
|
|
144
|
+
return false;
|
|
145
|
+
writeLockfileUnlocked(desired);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
release();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
60
152
|
export async function upsertLockEntry(entry) {
|
|
61
|
-
const
|
|
153
|
+
const release = await acquireLockSentinel();
|
|
62
154
|
try {
|
|
63
|
-
|
|
155
|
+
// R-012: readLockfileOrThrow (not readLockfile) — a corrupt/malformed
|
|
156
|
+
// lockfile must abort the upsert loudly rather than read as `[]` and get
|
|
157
|
+
// silently overwritten with just this one entry.
|
|
158
|
+
const entries = readLockfileOrThrow();
|
|
64
159
|
const withoutExisting = entries.filter((e) => e.id !== entry.id);
|
|
65
|
-
|
|
160
|
+
writeLockfileUnlocked([...withoutExisting, entry]);
|
|
66
161
|
}
|
|
67
162
|
finally {
|
|
68
|
-
|
|
69
|
-
releaseLockSentinel();
|
|
163
|
+
release();
|
|
70
164
|
}
|
|
71
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Synchronously upsert lock entries (merge by id) WITHOUT acquiring the async
|
|
168
|
+
* sentinel — for a caller already holding an exclusive lifecycle lock (e.g.
|
|
169
|
+
* migrate-apply's config lock + maintenance barrier) whose synchronous body
|
|
170
|
+
* cannot await the sentinel's retry loop. No-op for an empty list.
|
|
171
|
+
*/
|
|
172
|
+
export function mergeLockEntriesSync(entries) {
|
|
173
|
+
if (entries.length === 0)
|
|
174
|
+
return;
|
|
175
|
+
let existing = [];
|
|
176
|
+
const lockfilePath = getLockfilePath();
|
|
177
|
+
if (fs.existsSync(lockfilePath)) {
|
|
178
|
+
let raw;
|
|
179
|
+
try {
|
|
180
|
+
raw = JSON.parse(fs.readFileSync(lockfilePath, "utf8"));
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
throw new ConfigError(`Cannot merge migration lock entries into unreadable lockfile ${lockfilePath}: ${error instanceof Error ? error.message : String(error)}.`, "INVALID_CONFIG_FILE");
|
|
184
|
+
}
|
|
185
|
+
if (!Array.isArray(raw) || !raw.every(isValidLockfileEntry)) {
|
|
186
|
+
throw new ConfigError(`Cannot merge migration lock entries into malformed lockfile ${lockfilePath}.`, "INVALID_CONFIG_FILE");
|
|
187
|
+
}
|
|
188
|
+
existing = raw;
|
|
189
|
+
}
|
|
190
|
+
// MERGE per id, never replace: the migrator's entries are sparse (id/source/
|
|
191
|
+
// ref/localRoot), while an existing row may carry `resolvedVersion`,
|
|
192
|
+
// `resolvedRevision`, `integrity`, `installedAt`, … from a real install.
|
|
193
|
+
// Replacing the whole row discarded the user's recorded resolution/pin and
|
|
194
|
+
// left later update reporting comparing against an unknown prior version.
|
|
195
|
+
// Incoming DEFINED fields win; existing fields absent from the incoming
|
|
196
|
+
// entry are preserved.
|
|
197
|
+
const byId = new Map(existing.map((e) => [e.id, e]));
|
|
198
|
+
const merged = entries.map((incoming) => {
|
|
199
|
+
const prior = byId.get(incoming.id);
|
|
200
|
+
return prior ? { ...prior, ...incoming } : incoming;
|
|
201
|
+
});
|
|
202
|
+
const incomingIds = new Set(entries.map((e) => e.id));
|
|
203
|
+
writeLockfileUnlocked([...existing.filter((e) => !incomingIds.has(e.id)), ...merged]);
|
|
204
|
+
}
|
|
205
|
+
/** Freeze exact old/desired lockfile bytes while the migration lifecycle lock is held. */
|
|
206
|
+
export function planLockMergeSync(entries) {
|
|
207
|
+
const lockfilePath = getLockfilePath();
|
|
208
|
+
let oldBytes = null;
|
|
209
|
+
let existing = [];
|
|
210
|
+
try {
|
|
211
|
+
oldBytes = fs.readFileSync(lockfilePath, "utf8");
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
if (error.code !== "ENOENT")
|
|
215
|
+
throw error;
|
|
216
|
+
}
|
|
217
|
+
if (oldBytes !== null) {
|
|
218
|
+
let parsed;
|
|
219
|
+
try {
|
|
220
|
+
parsed = JSON.parse(oldBytes);
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
throw new ConfigError(`Cannot plan migration lock entries from unreadable lockfile ${lockfilePath}: ${error instanceof Error ? error.message : String(error)}.`, "INVALID_CONFIG_FILE");
|
|
224
|
+
}
|
|
225
|
+
if (!Array.isArray(parsed) || !parsed.every(isValidLockfileEntry)) {
|
|
226
|
+
throw new ConfigError(`Cannot plan migration lock entries from malformed lockfile ${lockfilePath}.`, "INVALID_CONFIG_FILE");
|
|
227
|
+
}
|
|
228
|
+
existing = parsed;
|
|
229
|
+
}
|
|
230
|
+
if (entries.length === 0)
|
|
231
|
+
return { oldBytes, desiredBytes: oldBytes };
|
|
232
|
+
const byId = new Map(existing.map((entry) => [entry.id, entry]));
|
|
233
|
+
for (const entry of entries)
|
|
234
|
+
byId.set(entry.id, { ...byId.get(entry.id), ...entry });
|
|
235
|
+
return { oldBytes, desiredBytes: `${JSON.stringify([...byId.values()], null, 2)}\n` };
|
|
236
|
+
}
|
|
237
|
+
/** Publish a frozen migration lock generation, accepting only exact old or exact desired bytes. */
|
|
238
|
+
export function publishPlannedLockMergeSync(plan) {
|
|
239
|
+
const lockfilePath = getLockfilePath();
|
|
240
|
+
let current = null;
|
|
241
|
+
try {
|
|
242
|
+
current = fs.readFileSync(lockfilePath, "utf8");
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
if (error.code !== "ENOENT")
|
|
246
|
+
throw error;
|
|
247
|
+
}
|
|
248
|
+
if (current === plan.desiredBytes)
|
|
249
|
+
return;
|
|
250
|
+
if (current !== plan.oldBytes) {
|
|
251
|
+
throw new ConfigError(`Refusing migration lockfile publication because ${lockfilePath} is a third generation, neither the journaled old nor desired bytes.`, "INVALID_CONFIG_FILE");
|
|
252
|
+
}
|
|
253
|
+
if (plan.desiredBytes === null)
|
|
254
|
+
return;
|
|
255
|
+
fs.mkdirSync(path.dirname(lockfilePath), { recursive: true });
|
|
256
|
+
writeFileAtomic(lockfilePath, plan.desiredBytes, 0o600);
|
|
257
|
+
}
|
|
72
258
|
export async function removeLockEntry(id) {
|
|
73
259
|
if (!fs.existsSync(getDataDir()))
|
|
74
260
|
return;
|
|
75
|
-
const
|
|
261
|
+
const release = await acquireLockSentinel();
|
|
76
262
|
try {
|
|
77
|
-
|
|
78
|
-
|
|
263
|
+
// R-012: see upsertLockEntry — same destructive-overwrite risk on a
|
|
264
|
+
// corrupt lockfile, so the same strict reader is used here.
|
|
265
|
+
const entries = readLockfileOrThrow();
|
|
266
|
+
writeLockfileUnlocked(entries.filter((e) => e.id !== id));
|
|
79
267
|
}
|
|
80
268
|
finally {
|
|
81
|
-
|
|
82
|
-
releaseLockSentinel();
|
|
269
|
+
release();
|
|
83
270
|
}
|
|
84
271
|
}
|
|
85
272
|
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
86
|
-
function isValidLockfileEntry(value) {
|
|
273
|
+
export function isValidLockfileEntry(value) {
|
|
87
274
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
88
275
|
return false;
|
|
89
276
|
const obj = value;
|