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
|
@@ -3,20 +3,24 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import { defineJsonCommand, output, parseAllFlagValues } from "../cli/shared.js";
|
|
6
|
+
import { makeBundleRef, parseBundleRef } from "../core/asset/asset-ref.js";
|
|
6
7
|
import { assembleAsset } from "../core/asset/asset-serialize.js";
|
|
7
8
|
import { parseFrontmatter, parseFrontmatterBlock } from "../core/asset/frontmatter.js";
|
|
8
|
-
import { conceptIdFromTypeName,
|
|
9
|
-
import { writeFileAtomic } from "../core/common.js";
|
|
9
|
+
import { conceptIdFromTypeName, parseRefInput } from "../core/asset/resolve-ref.js";
|
|
10
|
+
import { isWithin, writeFileAtomic } from "../core/common.js";
|
|
10
11
|
import { FEEDBACK_FAILURE_MODES, loadConfig } from "../core/config/config.js";
|
|
11
|
-
import { UsageError } from "../core/errors.js";
|
|
12
|
+
import { NotFoundError, UsageError } from "../core/errors.js";
|
|
12
13
|
import { appendEvent } from "../core/events.js";
|
|
14
|
+
import { resolveMutationTarget } from "../core/mutation-target.js";
|
|
13
15
|
import { getDbPath } from "../core/paths.js";
|
|
14
16
|
import { withStateDb } from "../core/state-db.js";
|
|
15
17
|
import { warn } from "../core/warn.js";
|
|
18
|
+
import { withWriteTargetMutation } from "../core/write-source.js";
|
|
16
19
|
import { resolveSourceEntries } from "../indexer/search/search-source.js";
|
|
17
20
|
import { countFeedbackSignals, insertUsageEvent, resolveUsageEventSource } from "../indexer/usage/usage-events.js";
|
|
21
|
+
import { resolveSourcesForOrigin } from "../registry/origin-resolve.js";
|
|
18
22
|
import { closeDatabase, openExistingDatabase } from "../storage/repositories/index-connection.js";
|
|
19
|
-
import { findEntryIdByRef,
|
|
23
|
+
import { findEntryIdByRef, getEntryFilePathById, getItemRefById, } from "../storage/repositories/index-entries-repository.js";
|
|
20
24
|
import { applyFeedbackToUtilityScore } from "../storage/repositories/index-utility-repository.js";
|
|
21
25
|
// ── Tag validation ────────────────────────────────────────────────────────────
|
|
22
26
|
const TAG_KEY_RE = /^[a-z_][a-z0-9_]*$/;
|
|
@@ -56,34 +60,68 @@ function validateFeedbackTags(raw) {
|
|
|
56
60
|
* an existing asset — the same pattern memory-inference uses for
|
|
57
61
|
* `inferenceProcessed`.
|
|
58
62
|
*/
|
|
59
|
-
function appendLessonStrength(
|
|
60
|
-
// Canonical
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
const
|
|
63
|
+
function appendLessonStrength(refInput, feedbackRef) {
|
|
64
|
+
// Canonical conceptId (`lessons/<name>`, D-R3): `findEntryIdByRef` keys on
|
|
65
|
+
// the stored `item_ref`.
|
|
66
|
+
const conceptId = conceptIdFromTypeName(refInput.type, refInput.name);
|
|
67
|
+
const config = loadConfig();
|
|
64
68
|
let filePath;
|
|
69
|
+
let bundleId;
|
|
65
70
|
const db = openExistingDatabase();
|
|
66
71
|
try {
|
|
67
|
-
const entryId = findEntryIdByRef(db,
|
|
68
|
-
if (entryId
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
const entryId = findEntryIdByRef(db, makeBundleRef(refInput.origin, conceptId));
|
|
73
|
+
if (entryId !== undefined) {
|
|
74
|
+
const itemRef = getItemRefById(db, entryId);
|
|
75
|
+
const parsedItemRef = itemRef ? parseBundleRef(itemRef) : undefined;
|
|
76
|
+
filePath = getEntryFilePathById(db, entryId) ?? undefined;
|
|
77
|
+
bundleId = parsedItemRef?.bundle;
|
|
71
78
|
}
|
|
72
|
-
const resolvedPath = getEntryFilePathById(db, entryId);
|
|
73
|
-
if (!resolvedPath) {
|
|
74
|
-
warn(`[feedback] --applied-to: cannot resolve file path for ${ref}.`);
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
filePath = resolvedPath;
|
|
78
79
|
}
|
|
79
80
|
finally {
|
|
80
81
|
closeDatabase(db);
|
|
81
82
|
}
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
const requestedRef = makeBundleRef(refInput.origin, conceptId);
|
|
84
|
+
if (!filePath || !bundleId || !fs.existsSync(filePath)) {
|
|
85
|
+
warn(`[feedback] --applied-to: lesson ${requestedRef} is not in the index or is missing on disk.`);
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const resolved = resolveMutationTarget(config, { ...refInput, origin: bundleId });
|
|
89
|
+
if (!isWithin(filePath, resolved.target.source.path)) {
|
|
90
|
+
throw new UsageError(`Resolved lesson ${requestedRef} is outside bundle "${bundleId}".`);
|
|
91
|
+
}
|
|
92
|
+
fs.lstatSync(filePath);
|
|
93
|
+
const initialUpdate = buildLessonStrengthUpdate(fs.readFileSync(filePath), feedbackRef);
|
|
94
|
+
if (!initialUpdate.nextBytes) {
|
|
95
|
+
return { ref: makeBundleRef(bundleId, conceptId), strength: initialUpdate.strength };
|
|
96
|
+
}
|
|
97
|
+
let strength = initialUpdate.strength;
|
|
98
|
+
let mutationStarted = false;
|
|
99
|
+
try {
|
|
100
|
+
withWriteTargetMutation(resolved.target, [filePath], {
|
|
101
|
+
ignored: "reject",
|
|
102
|
+
purpose: "feedback-lesson-credit",
|
|
103
|
+
message: `Update ${makeBundleRef(bundleId, conceptId)}`,
|
|
104
|
+
}, () => {
|
|
105
|
+
const stat = fs.lstatSync(filePath);
|
|
106
|
+
const update = buildLessonStrengthUpdate(fs.readFileSync(filePath), feedbackRef);
|
|
107
|
+
strength = update.strength;
|
|
108
|
+
if (!update.nextBytes)
|
|
109
|
+
return;
|
|
110
|
+
mutationStarted = true;
|
|
111
|
+
// Preserve the existing file's permission bits (markdown assets are typically 0o644).
|
|
112
|
+
writeFileAtomic(filePath, update.nextBytes, stat.mode & 0o777);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
if (mutationStarted)
|
|
117
|
+
throw err;
|
|
118
|
+
warn(`[feedback] --applied-to: failed to write ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
84
119
|
return null;
|
|
85
120
|
}
|
|
86
|
-
|
|
121
|
+
return { ref: makeBundleRef(bundleId, conceptId), strength };
|
|
122
|
+
}
|
|
123
|
+
function buildLessonStrengthUpdate(rawBytes, feedbackRef) {
|
|
124
|
+
const raw = rawBytes.toString("utf8");
|
|
87
125
|
const parsed = parseFrontmatter(raw);
|
|
88
126
|
const data = { ...parsed.data };
|
|
89
127
|
const existing = data.lessonStrength;
|
|
@@ -93,7 +131,6 @@ function appendLessonStrength(type, name, feedbackRef) {
|
|
|
93
131
|
? [existing.trim()]
|
|
94
132
|
: [];
|
|
95
133
|
if (strengthList.includes(feedbackRef)) {
|
|
96
|
-
// Already credited — idempotent no-op.
|
|
97
134
|
return { strength: strengthList.length };
|
|
98
135
|
}
|
|
99
136
|
strengthList.push(feedbackRef);
|
|
@@ -101,29 +138,29 @@ function appendLessonStrength(type, name, feedbackRef) {
|
|
|
101
138
|
const block = parseFrontmatterBlock(raw);
|
|
102
139
|
const body = block?.content ?? raw;
|
|
103
140
|
const next = assembleAsset(data, body);
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// typically 0o644); writeFileAtomic defaults to 0o600 otherwise.
|
|
107
|
-
const mode = fs.statSync(filePath).mode & 0o777;
|
|
108
|
-
writeFileAtomic(filePath, next, mode);
|
|
109
|
-
}
|
|
110
|
-
catch (err) {
|
|
111
|
-
warn(`[feedback] --applied-to: failed to write ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
|
-
return { strength: strengthList.length };
|
|
141
|
+
const nextBytes = Buffer.from(next);
|
|
142
|
+
return rawBytes.equals(nextBytes) ? { strength: strengthList.length } : { strength: strengthList.length, nextBytes };
|
|
115
143
|
}
|
|
116
144
|
/**
|
|
117
145
|
* Persist the feedback usage-event (state.db) and immediately fold it into the
|
|
118
146
|
* entry's MemRL utility score (index.db). Chunk-8 WI-8.3: usage_events lives in
|
|
119
|
-
* state.db; entries + utility_scores stay in `indexDb`.
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
147
|
+
* state.db; entries + utility_scores stay in `indexDb`. BOTH positive and
|
|
148
|
+
* negative signals apply the EMA utility update unconditionally and
|
|
149
|
+
* immediately when the source is user-attributed — no `akm index` run is
|
|
150
|
+
* required for either signal to affect search ranking. Uses the bounded-step
|
|
151
|
+
* EMA policy (F-5 / #386, arXiv:2601.03192).
|
|
152
|
+
*
|
|
153
|
+
* The update is intentionally SKIPPED for non-`user` event sources (`improve`,
|
|
154
|
+
* `task`, `audit`, `unknown`) — an anti-self-reinforcement guard that stops an
|
|
155
|
+
* agent or automated pipeline from boosting its own picks. This is by design
|
|
156
|
+
* and must not be removed; R-034 only asks that the skip be surfaced to the
|
|
157
|
+
* caller rather than passing silently. Best-effort: a utility-update failure
|
|
158
|
+
* never fails the feedback record.
|
|
124
159
|
*/
|
|
125
160
|
function recordFeedbackUsage(indexDb, entryId, durableEntryRef, signal, metadataStr) {
|
|
126
161
|
let utilityResult;
|
|
162
|
+
let rankingUpdateApplied = false;
|
|
163
|
+
let rankingUpdateSkippedReason;
|
|
127
164
|
const eventSource = resolveUsageEventSource();
|
|
128
165
|
withStateDb((stateDb) => {
|
|
129
166
|
insertUsageEvent(stateDb, {
|
|
@@ -134,29 +171,33 @@ function recordFeedbackUsage(indexDb, entryId, durableEntryRef, signal, metadata
|
|
|
134
171
|
metadata: metadataStr,
|
|
135
172
|
source: eventSource,
|
|
136
173
|
});
|
|
137
|
-
if (eventSource !== "user")
|
|
174
|
+
if (eventSource !== "user") {
|
|
175
|
+
rankingUpdateSkippedReason =
|
|
176
|
+
`feedback source is "${eventSource}", not "user" — ranking updates only apply to user-attributed ` +
|
|
177
|
+
"feedback (anti-self-reinforcement guard; set AKM_EVENT_SOURCE=user to record as user demand).";
|
|
138
178
|
return;
|
|
179
|
+
}
|
|
139
180
|
try {
|
|
140
181
|
const { pos, neg } = countFeedbackSignals(stateDb, entryId);
|
|
141
182
|
utilityResult = applyFeedbackToUtilityScore(indexDb, entryId, pos, neg);
|
|
183
|
+
rankingUpdateApplied = true;
|
|
142
184
|
}
|
|
143
|
-
catch {
|
|
185
|
+
catch (err) {
|
|
144
186
|
// best-effort — feedback recording succeeds even if utility update fails
|
|
187
|
+
rankingUpdateSkippedReason = `utility update failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
145
188
|
}
|
|
146
189
|
});
|
|
147
|
-
return utilityResult;
|
|
190
|
+
return { utilityResult, rankingUpdateApplied, rankingUpdateSkippedReason };
|
|
148
191
|
}
|
|
149
192
|
// ── Command definition ────────────────────────────────────────────────────────
|
|
150
193
|
export const feedbackCommand = defineJsonCommand({
|
|
151
194
|
meta: {
|
|
152
195
|
name: "feedback",
|
|
153
|
-
description: "Record positive or negative feedback for any indexed
|
|
154
|
-
"
|
|
155
|
-
"
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
"updated the next time `akm index` runs (incremental or full). Run `akm index`\n" +
|
|
159
|
-
"after recording negative feedback to have it reflected in search results.",
|
|
196
|
+
description: "Record positive or negative feedback for any indexed bundle asset.\n\n" +
|
|
197
|
+
"Both signals adjust the asset's usefulness score right away, in the same\n" +
|
|
198
|
+
"process: positive feedback raises it, negative lowers it, and recent\n" +
|
|
199
|
+
"feedback counts for more than old feedback. No reindex is needed — the new\n" +
|
|
200
|
+
"score affects ranking starting with the very next `akm search`.",
|
|
160
201
|
},
|
|
161
202
|
args: {
|
|
162
203
|
// Optional in citty so run() is invoked even when omitted; we re-validate
|
|
@@ -166,8 +207,7 @@ export const feedbackCommand = defineJsonCommand({
|
|
|
166
207
|
positive: { type: "boolean", description: "Record positive feedback (boosts ranking immediately)", default: false },
|
|
167
208
|
negative: {
|
|
168
209
|
type: "boolean",
|
|
169
|
-
description: "Record negative feedback (
|
|
170
|
-
"Reindexing is required for the signal to affect search results.",
|
|
210
|
+
description: "Record negative feedback (lowers ranking immediately, no reindex needed).",
|
|
171
211
|
default: false,
|
|
172
212
|
},
|
|
173
213
|
reason: {
|
|
@@ -176,7 +216,7 @@ export const feedbackCommand = defineJsonCommand({
|
|
|
176
216
|
},
|
|
177
217
|
"failure-mode": {
|
|
178
218
|
type: "string",
|
|
179
|
-
description:
|
|
219
|
+
description: "Structured failure-mode taxonomy for negative feedback. " +
|
|
180
220
|
`Accepted values: ${FEEDBACK_FAILURE_MODES.join(", ")}. ` +
|
|
181
221
|
"Stored alongside --reason in event metadata for aggregation by the distill pipeline.",
|
|
182
222
|
},
|
|
@@ -188,7 +228,8 @@ export const feedbackCommand = defineJsonCommand({
|
|
|
188
228
|
type: "string",
|
|
189
229
|
description: "Credit a lesson that helped resolve this task. Accepts a `lessons/<name>` ref. " +
|
|
190
230
|
"When combined with --positive, appends this feedback ref to the target lesson's " +
|
|
191
|
-
"`lessonStrength[]` frontmatter array (dedup, idempotent).
|
|
231
|
+
"`lessonStrength[]` frontmatter array (dedup, idempotent). A non-lesson target or a " +
|
|
232
|
+
"missing --positive produces a warning rather than silently doing nothing.",
|
|
192
233
|
},
|
|
193
234
|
},
|
|
194
235
|
async run({ args }) {
|
|
@@ -196,7 +237,7 @@ export const feedbackCommand = defineJsonCommand({
|
|
|
196
237
|
if (!ref) {
|
|
197
238
|
throw new UsageError("Asset ref is required. Usage: akm feedback <ref> --positive|--negative", "MISSING_REQUIRED_ARGUMENT", "Pass a ref like `skills/deploy` and either --positive or --negative.");
|
|
198
239
|
}
|
|
199
|
-
const parsedRef =
|
|
240
|
+
const parsedRef = parseBundleRef(ref);
|
|
200
241
|
if (args.positive && args.negative) {
|
|
201
242
|
throw new UsageError("Specify either --positive or --negative, not both.");
|
|
202
243
|
}
|
|
@@ -256,40 +297,42 @@ export const feedbackCommand = defineJsonCommand({
|
|
|
256
297
|
// background reindex it spawned — now that ensureIndex is removed, holding
|
|
257
298
|
// the lock only causes feedback to block for the full improve run duration.
|
|
258
299
|
let utilityResult;
|
|
300
|
+
let rankingUpdateApplied = false;
|
|
301
|
+
let rankingUpdateSkippedReason;
|
|
259
302
|
let durableRef = ref;
|
|
260
303
|
const db = openExistingDatabase();
|
|
261
304
|
try {
|
|
262
305
|
const config = loadConfig();
|
|
263
306
|
const sources = resolveSourceEntries(undefined, config);
|
|
264
|
-
const requestedSource = parsedRef.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
: undefined;
|
|
268
|
-
if (parsedRef.origin && !requestedSource) {
|
|
269
|
-
throw new UsageError(`Source "${parsedRef.origin}" is not configured.`, "INVALID_FLAG_VALUE");
|
|
307
|
+
const requestedSource = parsedRef.bundle ? resolveSourcesForOrigin(parsedRef.bundle, sources)[0] : undefined;
|
|
308
|
+
if (parsedRef.bundle && !requestedSource) {
|
|
309
|
+
throw new UsageError(`Source "${parsedRef.bundle}" is not configured.`, "INVALID_FLAG_VALUE");
|
|
270
310
|
}
|
|
271
|
-
const
|
|
311
|
+
const lookupRef = makeBundleRef(parsedRef.bundle, parsedRef.conceptId);
|
|
312
|
+
const entryId = findEntryIdByRef(db, lookupRef, requestedSource?.path);
|
|
272
313
|
if (entryId === undefined) {
|
|
273
|
-
|
|
274
|
-
|
|
314
|
+
// NotFoundError (exit 1), not UsageError (exit 2): the flags parsed
|
|
315
|
+
// fine, the asset just isn't there. The documented exit-code table
|
|
316
|
+
// reserves 1 for "requested resource missing", and scripts branch on it.
|
|
317
|
+
throw new NotFoundError(`Ref "${ref}" is not in the index. ` +
|
|
318
|
+
"Run 'akm search' to verify the asset exists, then 'akm index' if it was recently added.", "ASSET_NOT_FOUND");
|
|
275
319
|
}
|
|
276
|
-
// Persist the feedback signal into usage_events.
|
|
277
|
-
// the EMA utility
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
// in search results until after reindexing.
|
|
281
|
-
const indexedEntry = getEntryById(db, entryId);
|
|
282
|
-
const source = sources.find((candidate) => candidate.path === indexedEntry?.stashDir);
|
|
283
|
-
const durableOrigin = parsedRef.origin ?? source?.registryId ?? "stash";
|
|
320
|
+
// Persist the feedback signal into usage_events. Both positive and
|
|
321
|
+
// negative signals apply the EMA utility update immediately — no
|
|
322
|
+
// `akm index` run is required for either signal to affect ranking in
|
|
323
|
+
// search results (see recordFeedbackUsage / applyFeedbackToUtilityScore).
|
|
284
324
|
// WI-8.5b: the `feedback` / `improve_review_needed` events key on the
|
|
285
325
|
// resolved entry's fully-qualified item_ref — the SAME durable key the
|
|
286
326
|
// usage_events row carries and the SAME spelling the signal-delta
|
|
287
327
|
// correlation reads (buildLatestFeedbackTsMap, collapsed to [item_ref]).
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
durableRef = itemRef
|
|
292
|
-
|
|
328
|
+
const itemRef = getItemRefById(db, entryId);
|
|
329
|
+
if (!itemRef)
|
|
330
|
+
throw new UsageError(`Indexed ref "${ref}" has no durable item ref.`, "INVALID_PROPOSAL");
|
|
331
|
+
durableRef = itemRef;
|
|
332
|
+
const recordResult = recordFeedbackUsage(db, entryId, itemRef, signal, metadataStr);
|
|
333
|
+
utilityResult = recordResult.utilityResult;
|
|
334
|
+
rankingUpdateApplied = recordResult.rankingUpdateApplied;
|
|
335
|
+
rankingUpdateSkippedReason = recordResult.rankingUpdateSkippedReason;
|
|
293
336
|
}
|
|
294
337
|
finally {
|
|
295
338
|
closeDatabase(db);
|
|
@@ -305,8 +348,8 @@ export const feedbackCommand = defineJsonCommand({
|
|
|
305
348
|
// the improve loop. Best-effort — failure is logged but does not fail the
|
|
306
349
|
// feedback command.
|
|
307
350
|
// Emit a structured event rather than a proposal so the review-needed
|
|
308
|
-
// signal
|
|
309
|
-
//
|
|
351
|
+
// signal doesn't risk an accidental asset overwrite if the proposal is
|
|
352
|
+
// accepted.
|
|
310
353
|
if (utilityResult?.crossedReviewThreshold) {
|
|
311
354
|
try {
|
|
312
355
|
appendEvent({
|
|
@@ -327,23 +370,31 @@ export const feedbackCommand = defineJsonCommand({
|
|
|
327
370
|
// Phase 7A / Advantage D4b: --applied-to credits a lesson. When the
|
|
328
371
|
// target is a `lessons/<name>` ref and the signal is positive, append
|
|
329
372
|
// the feedback ref to the target lesson's `lessonStrength[]`
|
|
330
|
-
// frontmatter array (dedup, idempotent). Non-lesson targets are
|
|
331
|
-
//
|
|
332
|
-
//
|
|
373
|
+
// frontmatter array (dedup, idempotent). Non-lesson targets are REJECTED
|
|
374
|
+
// with a loud warning (R-033b) rather than silently doing nothing.
|
|
375
|
+
// Failures here are warnings — feedback recording is the primary
|
|
376
|
+
// contract and must not regress on lesson-write errors.
|
|
333
377
|
const appliedToRaw = args["applied-to"]?.trim();
|
|
334
378
|
let appliedToResult = null;
|
|
335
379
|
if (appliedToRaw && signal === "positive") {
|
|
380
|
+
let parsedApplied;
|
|
336
381
|
try {
|
|
337
|
-
|
|
382
|
+
parsedApplied = parseRefInput(appliedToRaw);
|
|
383
|
+
}
|
|
384
|
+
catch (err) {
|
|
385
|
+
warn(`[feedback] --applied-to failed for ${appliedToRaw}: ${err instanceof Error ? err.message : String(err)}`);
|
|
386
|
+
}
|
|
387
|
+
if (parsedApplied) {
|
|
338
388
|
if (parsedApplied.type === "lesson") {
|
|
339
|
-
const updated = appendLessonStrength(parsedApplied
|
|
389
|
+
const updated = appendLessonStrength(parsedApplied, durableRef);
|
|
340
390
|
if (updated) {
|
|
341
|
-
appliedToResult = { lessonRef:
|
|
391
|
+
appliedToResult = { lessonRef: updated.ref, strength: updated.strength };
|
|
342
392
|
}
|
|
343
393
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
394
|
+
else {
|
|
395
|
+
warn(`[feedback] --applied-to ${appliedToRaw} was ignored: it resolves to a "${parsedApplied.type}" asset, ` +
|
|
396
|
+
"not a lesson. Only `lessons/<name>` refs can be credited via --applied-to.");
|
|
397
|
+
}
|
|
347
398
|
}
|
|
348
399
|
}
|
|
349
400
|
else if (appliedToRaw && signal !== "positive") {
|
|
@@ -356,6 +407,9 @@ export const feedbackCommand = defineJsonCommand({
|
|
|
356
407
|
reason: reason?.trim() ?? null,
|
|
357
408
|
failureMode: failureMode ?? null,
|
|
358
409
|
tags: validatedTags,
|
|
410
|
+
rankingUpdate: rankingUpdateApplied
|
|
411
|
+
? { applied: true }
|
|
412
|
+
: { applied: false, reason: rankingUpdateSkippedReason ?? "unknown" },
|
|
359
413
|
...(appliedToResult
|
|
360
414
|
? { appliedTo: { ref: appliedToResult.lessonRef, lessonStrength: appliedToResult.strength } }
|
|
361
415
|
: {}),
|
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
/**
|
|
5
|
+
* Per-proposal-source accept-rate metrics, folded into `akm health --report`
|
|
6
|
+
* (0.9.0 CLI overhaul, S3).
|
|
7
|
+
*
|
|
8
|
+
* Provides the core self-measurement metric for recursive self-improvement:
|
|
9
|
+
* if reflect proposals are accepted at 20% and distill proposals at 60%,
|
|
10
|
+
* that guides resource allocation to higher-ROI generators.
|
|
11
|
+
*
|
|
12
|
+
* Previously exposed as the removed `akm history --accept-rate-by-source`
|
|
13
|
+
* flag (src/commands/sources/history.ts, F-4 / #385); `health` already reads
|
|
14
|
+
* the pending proposal queue for its own `--report` dataset, so this is the
|
|
15
|
+
* same read extended to the accepted/rejected archive.
|
|
16
|
+
*/
|
|
17
|
+
import { resolveStashDir } from "../../core/common.js";
|
|
18
|
+
import { listProposals } from "../proposal/repository.js";
|
|
19
|
+
/**
|
|
20
|
+
* Compute accept-rate-per-source metrics from the proposal store. Defaults to
|
|
21
|
+
* the configured default stash when `stashDir` is omitted (same resolution
|
|
22
|
+
* `akm health` already uses for the rest of its report).
|
|
23
|
+
*/
|
|
24
|
+
export function computeAcceptRateBySource(stashDir) {
|
|
25
|
+
const stash = stashDir ?? resolveStashDir();
|
|
26
|
+
const bySource = new Map();
|
|
27
|
+
const countProposals = (statuses, includeArchive) => {
|
|
28
|
+
for (const status of statuses) {
|
|
29
|
+
const proposals = listProposals(stash, { status, includeArchive });
|
|
30
|
+
for (const p of proposals) {
|
|
31
|
+
const src = p.source || "(unknown)";
|
|
32
|
+
const entry = bySource.get(src) ?? { accepted: 0, rejected: 0, pending: 0 };
|
|
33
|
+
if (status === "accepted")
|
|
34
|
+
entry.accepted++;
|
|
35
|
+
else if (status === "rejected")
|
|
36
|
+
entry.rejected++;
|
|
37
|
+
else
|
|
38
|
+
entry.pending++;
|
|
39
|
+
bySource.set(src, entry);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
countProposals(["pending"], false);
|
|
44
|
+
countProposals(["accepted", "rejected"], true);
|
|
45
|
+
return Array.from(bySource.entries())
|
|
46
|
+
.map(([source, counts]) => {
|
|
47
|
+
const decided = counts.accepted + counts.rejected;
|
|
48
|
+
return {
|
|
49
|
+
source,
|
|
50
|
+
total: decided + counts.pending,
|
|
51
|
+
accepted: counts.accepted,
|
|
52
|
+
rejected: counts.rejected,
|
|
53
|
+
pending: counts.pending,
|
|
54
|
+
acceptRate: decided > 0 ? counts.accepted / decided : null,
|
|
55
|
+
};
|
|
56
|
+
})
|
|
57
|
+
.sort((a, b) => b.total - a.total); // Most active source first
|
|
58
|
+
}
|
|
@@ -106,8 +106,7 @@ export function collectImproveAdvisories(db, stateDbPath, since, improveSummary)
|
|
|
106
106
|
const latestCycle = getLatestCycleMetrics(db);
|
|
107
107
|
const cycleSummary = latestCycle
|
|
108
108
|
? `Latest cycle (${latestCycle.ts}, ${latestCycle.pass}): mean canary recall ${latestCycle.mean_recall.toFixed(3)}, ` +
|
|
109
|
-
`distinct-content ratio ${latestCycle.distinct_content_ratio.toFixed(3)}
|
|
110
|
-
`${latestCycle.accepted_actions} accepted action(s).`
|
|
109
|
+
`distinct-content ratio ${latestCycle.distinct_content_ratio.toFixed(3)}.`
|
|
111
110
|
: "";
|
|
112
111
|
if (collapseAlertEvents.length > 0) {
|
|
113
112
|
const kinds = [...new Set(collapseAlertEvents.map((e) => String(e.metadata?.kind ?? "unknown")))];
|
|
@@ -116,8 +115,8 @@ export function collectImproveAdvisories(db, stateDbPath, since, improveSummary)
|
|
|
116
115
|
name: "collapse-churn-detector",
|
|
117
116
|
status: "warn",
|
|
118
117
|
kind: "deterministic",
|
|
119
|
-
// Collapse kinds are measured, not inferred;
|
|
120
|
-
// volume
|
|
118
|
+
// Collapse kinds are measured, not inferred; the merge-floor
|
|
119
|
+
// volume threshold is still being tuned (design doc §7).
|
|
121
120
|
confidence: collapseKinds.length > 0 ? "high" : "medium",
|
|
122
121
|
message: `R5 detector fired ${collapseAlertEvents.length} alert(s) in window (kinds: ${kinds.join(", ")}). ` +
|
|
123
122
|
`${cycleSummary} See docs/architecture/specs/improve-collapse-churn-detector-design.md §6.3 runbook queries.`,
|
|
@@ -2,13 +2,12 @@
|
|
|
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
|
import { spawnSync } from "node:child_process";
|
|
5
|
-
import { createRequire } from "node:module";
|
|
6
5
|
import { loadConfig } from "../../core/config/config.js";
|
|
6
|
+
import { withEngineFallback } from "../../integrations/agent/engine-fallback.js";
|
|
7
7
|
import { resolveEngine } from "../../integrations/agent/engine-resolution.js";
|
|
8
8
|
import { resolveModel } from "../../integrations/agent/model-aliases.js";
|
|
9
9
|
import { resolveImprovePlan } from "../improve/improve-strategies.js";
|
|
10
|
-
import { TASK_FAIL_RATE_WARN, } from "./types.js";
|
|
11
|
-
const ACTIVE_RUN_WARN_MS = 15 * 60 * 1000;
|
|
10
|
+
import { ACTIVE_RUN_WARN_MS, TASK_FAIL_RATE_WARN, } from "./types.js";
|
|
12
11
|
function credentialAvailable(credential, env) {
|
|
13
12
|
return !credential?.required || credential.names.some((name) => Boolean(env[name]?.trim()));
|
|
14
13
|
}
|
|
@@ -29,7 +28,7 @@ function runConfiguredEngineProbe(checkName, engineName, config, deps) {
|
|
|
29
28
|
if (configuredEngine?.kind === "agent" && configuredEngine.platform === "opencode-sdk") {
|
|
30
29
|
let packageAvailable = false;
|
|
31
30
|
try {
|
|
32
|
-
const resolvePackage = deps.resolvePackage ?? ((name) =>
|
|
31
|
+
const resolvePackage = deps.resolvePackage ?? ((name) => import.meta.resolve(name));
|
|
33
32
|
resolvePackage("@opencode-ai/sdk");
|
|
34
33
|
packageAvailable = true;
|
|
35
34
|
}
|
|
@@ -171,7 +170,10 @@ function runConfiguredEngineProbe(checkName, engineName, config, deps) {
|
|
|
171
170
|
}
|
|
172
171
|
}
|
|
173
172
|
export function runDefaultEngineProbe(deps = {}) {
|
|
174
|
-
|
|
173
|
+
// Probe the effective view: an install with no `defaults.engine` but a usable
|
|
174
|
+
// opencode binary DOES have a working default, and reporting otherwise would
|
|
175
|
+
// contradict what `workflow run` / `task run` actually do.
|
|
176
|
+
const { config } = withEngineFallback(deps.loadConfig?.() ?? loadConfig(), deps.which);
|
|
175
177
|
return runConfiguredEngineProbe("default-engine", config.defaults?.engine, config, deps);
|
|
176
178
|
}
|
|
177
179
|
export function runDefaultLlmEngineProbe(deps = {}) {
|
|
@@ -289,16 +291,23 @@ export const HEALTH_CHECKS = [
|
|
|
289
291
|
{
|
|
290
292
|
name: "active-runs",
|
|
291
293
|
channel: "hard",
|
|
292
|
-
run: (ctx) =>
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
:
|
|
300
|
-
|
|
301
|
-
|
|
294
|
+
run: (ctx) => {
|
|
295
|
+
// Name the stuck task_ids (deduped, oldest first) so an operator knows
|
|
296
|
+
// WHICH tasks to investigate, not just how many rows are stale. No
|
|
297
|
+
// pid/liveness detection — that's out of scope here.
|
|
298
|
+
const named = [...ctx.stuckActiveTasks].sort((a, b) => b.ageMs - a.ageMs);
|
|
299
|
+
const detail = named.map((t) => `${t.taskId} (${Math.round(t.ageMs / 60000)}m)`).join(", ");
|
|
300
|
+
return {
|
|
301
|
+
name: "active-runs",
|
|
302
|
+
kind: "deterministic",
|
|
303
|
+
status: ctx.stuckActiveRuns === 0 ? "pass" : "warn",
|
|
304
|
+
confidence: "high",
|
|
305
|
+
message: ctx.stuckActiveRuns === 0
|
|
306
|
+
? "No active task runs exceeded the stale threshold."
|
|
307
|
+
: `${ctx.stuckActiveRuns} active task run(s) are older than ${Math.round(ACTIVE_RUN_WARN_MS / 60000)} minutes: ${detail}.`,
|
|
308
|
+
evidence: { stuckActiveRuns: ctx.stuckActiveRuns, stuckActiveTasks: ctx.stuckActiveTasks },
|
|
309
|
+
};
|
|
310
|
+
},
|
|
302
311
|
},
|
|
303
312
|
{
|
|
304
313
|
name: "default-engine",
|
|
@@ -320,23 +329,51 @@ export const HEALTH_CHECKS = [
|
|
|
320
329
|
// in the HTML report but never surfaced as an advisory, so a sustained
|
|
321
330
|
// 15–16% fail rate stayed invisible on `akm health`. Warn at/above the SAME
|
|
322
331
|
// 5% threshold the html-report badge uses (see TASK_FAIL_RATE_WARN).
|
|
332
|
+
//
|
|
333
|
+
// Item 6: the aggregate can hide a single consistently-failing task inside
|
|
334
|
+
// a large, mostly-healthy population (e.g. 1 flaky task at 100 rows total
|
|
335
|
+
// reads as <5% aggregate). Also warn when the single worst task_id (with
|
|
336
|
+
// enough rows to be a real signal — see MIN_ROWS_FOR_WORST_TASK_FAIL_RATE)
|
|
337
|
+
// crosses the same threshold, naming it explicitly.
|
|
323
338
|
name: "task-fail-rate",
|
|
324
339
|
channel: "advisory",
|
|
325
340
|
run: (ctx) => {
|
|
326
341
|
const pctStr = `${(ctx.taskFailRate * 100).toFixed(1)}%`;
|
|
327
342
|
const thresholdPct = `${(TASK_FAIL_RATE_WARN * 100).toFixed(0)}%`;
|
|
328
|
-
const
|
|
343
|
+
const aggregateWarn = ctx.taskFailRate >= TASK_FAIL_RATE_WARN;
|
|
344
|
+
const worst = ctx.worstTaskFailRate;
|
|
345
|
+
const worstWarn = worst !== null && worst.rate >= TASK_FAIL_RATE_WARN;
|
|
346
|
+
const warn = aggregateWarn || worstWarn;
|
|
347
|
+
let message;
|
|
348
|
+
if (ctx.taskRowCount === 0) {
|
|
349
|
+
message = `No cron tasks ran since ${ctx.since} — no task-fail-rate signal.`;
|
|
350
|
+
}
|
|
351
|
+
else if (warn) {
|
|
352
|
+
const parts = [];
|
|
353
|
+
if (aggregateWarn) {
|
|
354
|
+
parts.push(`aggregate ${pctStr} across ${ctx.taskRowCount} task(s) since ${ctx.since} ≥ ${thresholdPct}`);
|
|
355
|
+
}
|
|
356
|
+
if (worstWarn && worst) {
|
|
357
|
+
const worstPctStr = `${(worst.rate * 100).toFixed(1)}%`;
|
|
358
|
+
parts.push(`task "${worst.taskId}" fails ${worstPctStr} of its ${worst.rows} run(s) ≥ ${thresholdPct}`);
|
|
359
|
+
}
|
|
360
|
+
message = `Cron task fail rate warning: ${parts.join("; ")} — inspect failed runs (ok=false) for early-exit/harness errors.`;
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
message = `Cron task fail rate ${pctStr} across ${ctx.taskRowCount} task(s) since ${ctx.since} (below ${thresholdPct} threshold).`;
|
|
364
|
+
}
|
|
329
365
|
return {
|
|
330
366
|
name: "task-fail-rate",
|
|
331
367
|
kind: "deterministic",
|
|
332
368
|
status: warn ? "warn" : "pass",
|
|
333
369
|
confidence: "high",
|
|
334
|
-
message
|
|
335
|
-
|
|
336
|
-
:
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
370
|
+
message,
|
|
371
|
+
evidence: {
|
|
372
|
+
taskFailRate: ctx.taskFailRate,
|
|
373
|
+
taskRowCount: ctx.taskRowCount,
|
|
374
|
+
threshold: TASK_FAIL_RATE_WARN,
|
|
375
|
+
worstTaskFailRate: worst,
|
|
376
|
+
},
|
|
340
377
|
};
|
|
341
378
|
},
|
|
342
379
|
},
|
|
@@ -354,7 +391,7 @@ export const HEALTH_CHECKS = [
|
|
|
354
391
|
const endpointAdvisory = blocked && remoteReason && ctx.embeddingEndpoint
|
|
355
392
|
? `Configured embedding endpoint ${ctx.embeddingEndpoint} is failing ` +
|
|
356
393
|
`(${ctx.semanticStatus?.reason}${ctx.semanticStatus?.message ? `: ${ctx.semanticStatus.message}` : ""}) ` +
|
|
357
|
-
`while semanticSearchMode is "${ctx.semanticSearchMode ?? "
|
|
394
|
+
`while semanticSearchMode is "${ctx.semanticSearchMode ?? "off"}". Searches fall back to keyword-only. ` +
|
|
358
395
|
`Restore the endpoint, or set semanticSearchMode to "off" (or remove embedding.endpoint to use the local model).`
|
|
359
396
|
: undefined;
|
|
360
397
|
return {
|
|
@@ -489,4 +526,29 @@ export const HEALTH_CHECKS = [
|
|
|
489
526
|
};
|
|
490
527
|
},
|
|
491
528
|
},
|
|
529
|
+
{
|
|
530
|
+
// Item 4: stale durable-transaction journals under $DATA/txn (stranded
|
|
531
|
+
// recovery state seen twice in a real 0.9 migration) had zero health
|
|
532
|
+
// visibility. `count`/`unreadable` already exclude journals younger than
|
|
533
|
+
// the sweeper's grace period (a currently-running operation), so any
|
|
534
|
+
// nonzero count here is a real leftover.
|
|
535
|
+
name: "stale-txn-journals",
|
|
536
|
+
channel: "advisory",
|
|
537
|
+
run: (ctx) => {
|
|
538
|
+
const s = ctx.staleTxnJournals;
|
|
539
|
+
const warn = s.count > 0;
|
|
540
|
+
const unreadablePart = s.unreadable > 0 ? `, ${s.unreadable} unreadable` : "";
|
|
541
|
+
const agePart = s.oldestAgeMs !== null ? `, oldest ${Math.round(s.oldestAgeMs / 60000)}m old` : "";
|
|
542
|
+
return {
|
|
543
|
+
name: "stale-txn-journals",
|
|
544
|
+
kind: "deterministic",
|
|
545
|
+
status: warn ? "warn" : "pass",
|
|
546
|
+
confidence: "high",
|
|
547
|
+
message: warn
|
|
548
|
+
? `${s.count} stale transaction journal(s) found under ${s.dir}${unreadablePart}${agePart} — see docs/migration/v0.9.0-troubleshooting.md for journal reconciliation steps.`
|
|
549
|
+
: "No stale transaction journals found.",
|
|
550
|
+
evidence: { dir: s.dir, count: s.count, unreadable: s.unreadable, oldestAgeMs: s.oldestAgeMs },
|
|
551
|
+
};
|
|
552
|
+
},
|
|
553
|
+
},
|
|
492
554
|
];
|