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
|
@@ -1,482 +0,0 @@
|
|
|
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
|
-
// ── Deterministic near-duplicate MEMORY dedup (#617) ─────────────────────────
|
|
5
|
-
//
|
|
6
|
-
// A CHEAP, DETERMINISTIC fast path that collapses the obvious duplicates with
|
|
7
|
-
// NO LLM call, run in front of the embedding-clustered LLM consolidation pass
|
|
8
|
-
// (see consolidate.ts). The working stash accumulates near-duplicates faster
|
|
9
|
-
// than the capped/rotating LLM consolidate pass can merge them; this pre-pass
|
|
10
|
-
// clears the unambiguous twins so the (expensive) LLM only ever sees genuinely
|
|
11
|
-
// distinct-but-related memories.
|
|
12
|
-
//
|
|
13
|
-
// Two collapse classes, both safe and reversible (archive + backup at the call
|
|
14
|
-
// site in consolidate.ts; this module only computes the plan and applies the
|
|
15
|
-
// file writes/deletes):
|
|
16
|
-
//
|
|
17
|
-
// 1. `.derived` ↔ origin pairs — a memory-inference `<parent>.derived` child
|
|
18
|
-
// whose normalized body is identical to (or, with embeddings, ≥ the strict
|
|
19
|
-
// cosine threshold of) its origin. Keep the canonical (non-derived) origin;
|
|
20
|
-
// drop the derived variant; preserve the variant's provenance on the
|
|
21
|
-
// canonical (`dedupedFrom`).
|
|
22
|
-
//
|
|
23
|
-
// 2. Content twins — two non-derived memories with identical normalized body
|
|
24
|
-
// hash, or ≥ the strict cosine threshold. Keep the deterministic canonical
|
|
25
|
-
// (lexicographically smallest name); merge the other into it, preserving
|
|
26
|
-
// provenance.
|
|
27
|
-
//
|
|
28
|
-
// Determinism: the plan is a pure function of the on-disk memory set + config.
|
|
29
|
-
// Nothing here reads Date.now()/Math.random(); ordering is by memory name so the
|
|
30
|
-
// canonical choice and op order are stable across runs.
|
|
31
|
-
//
|
|
32
|
-
// Gating: DEFAULT OFF. The pre-pass only runs when `dedup.enabled === true`. The
|
|
33
|
-
// cosine path additionally requires an embedding config; absent embeddings the
|
|
34
|
-
// pass still collapses exact normalized-hash twins. `cosineThreshold` defaults
|
|
35
|
-
// to 0.97 — a strict floor chosen so distinct-but-related memories fall through
|
|
36
|
-
// untouched to the LLM consolidation.
|
|
37
|
-
import { createHash } from "node:crypto";
|
|
38
|
-
import fs from "node:fs";
|
|
39
|
-
import path from "node:path";
|
|
40
|
-
import { parseAssetRef } from "../../core/asset/asset-ref.js";
|
|
41
|
-
import { assembleAssetFromString, serializeFrontmatter } from "../../core/asset/asset-serialize.js";
|
|
42
|
-
import { parseFrontmatter } from "../../core/asset/frontmatter.js";
|
|
43
|
-
import { warn } from "../../core/warn.js";
|
|
44
|
-
import { cosineSimilarity, embedBatch, resolveEmbeddingModelId } from "../../llm/embedder.js";
|
|
45
|
-
import { getBodyEmbeddings, upsertBodyEmbeddings } from "../../storage/repositories/embeddings-repository.js";
|
|
46
|
-
/** Default strict cosine floor — high enough to skip distinct-but-related memories. */
|
|
47
|
-
export const DEFAULT_DEDUP_COSINE_THRESHOLD = 0.97;
|
|
48
|
-
/**
|
|
49
|
-
* Strip frontmatter from raw memory content, returning the body text trimmed.
|
|
50
|
-
* Case and whitespace are preserved — this is the shared primitive used by
|
|
51
|
-
* both hash wrappers below. Falls back to `raw.trim()` on unparseable
|
|
52
|
-
* frontmatter (consistent with the pre-existing load-time hot guard).
|
|
53
|
-
*/
|
|
54
|
-
export function stripFrontmatterBody(raw) {
|
|
55
|
-
try {
|
|
56
|
-
return parseFrontmatter(raw).content.trim();
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
return raw.trim();
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Normalize a memory body for content-twin equality. Strips frontmatter,
|
|
64
|
-
* lowercases, trims, and collapses all runs of whitespace to a single space so
|
|
65
|
-
* trivial reformatting (extra blank lines, trailing spaces, case) does not
|
|
66
|
-
* defeat the hash. Deterministic and pure.
|
|
67
|
-
*
|
|
68
|
-
* Use this for the DEDUP path only (exact-twin detection). For the change-
|
|
69
|
-
* detection / embedding-cache path use `cacheHash` instead.
|
|
70
|
-
*/
|
|
71
|
-
export function normalizeMemoryBody(raw) {
|
|
72
|
-
return stripFrontmatterBody(raw).toLowerCase().replace(/\s+/g, " ");
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Hash used for content-twin detection: lowercase + whitespace-collapsed body.
|
|
76
|
-
* Two memories that differ only in case or whitespace produce the same hash
|
|
77
|
-
* and are considered identical twins. Use this key for the dedup buckets.
|
|
78
|
-
*/
|
|
79
|
-
export function dedupHash(raw) {
|
|
80
|
-
return createHash("sha256").update(normalizeMemoryBody(raw), "utf8").digest("hex");
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Hash used for change-detection and the body-embedding cache: case-/whitespace-
|
|
84
|
-
* preserving stripped body. Two memories with the same wording but different
|
|
85
|
-
* casing produce DIFFERENT hashes here, which is intentional — we embed the
|
|
86
|
-
* exact text and cache by its precise content.
|
|
87
|
-
*
|
|
88
|
-
* This is the `content_hash` stored in `body_embeddings` and
|
|
89
|
-
* `consolidation_judged`. Do NOT reuse the `dedupHash` for those tables.
|
|
90
|
-
*/
|
|
91
|
-
export function cacheHash(raw) {
|
|
92
|
-
return createHash("sha256").update(stripFrontmatterBody(raw), "utf8").digest("hex");
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Load every memory `.md` file (including `.derived` children) from the stash
|
|
96
|
-
* memories directory. Unlike the consolidate loader, this DOES include derived
|
|
97
|
-
* children — the whole point of class 1 is to collapse a derived child into its
|
|
98
|
-
* origin, so both must be visible here.
|
|
99
|
-
*/
|
|
100
|
-
export function loadDedupMemories(stashDir) {
|
|
101
|
-
const memoriesDir = path.join(stashDir, "memories");
|
|
102
|
-
if (!fs.existsSync(memoriesDir))
|
|
103
|
-
return [];
|
|
104
|
-
const out = [];
|
|
105
|
-
for (const fname of fs.readdirSync(memoriesDir).sort()) {
|
|
106
|
-
if (!fname.endsWith(".md"))
|
|
107
|
-
continue;
|
|
108
|
-
const name = fname.replace(/\.md$/, "");
|
|
109
|
-
const filePath = path.join(memoriesDir, fname);
|
|
110
|
-
let raw;
|
|
111
|
-
try {
|
|
112
|
-
raw = fs.readFileSync(filePath, "utf8");
|
|
113
|
-
}
|
|
114
|
-
catch {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
let fm = {};
|
|
118
|
-
try {
|
|
119
|
-
fm = parseFrontmatter(raw).data ?? {};
|
|
120
|
-
}
|
|
121
|
-
catch {
|
|
122
|
-
fm = {};
|
|
123
|
-
}
|
|
124
|
-
const normalizedBody = normalizeMemoryBody(raw);
|
|
125
|
-
out.push({
|
|
126
|
-
name,
|
|
127
|
-
filePath,
|
|
128
|
-
derived: name.endsWith(".derived"),
|
|
129
|
-
derivedFrom: typeof fm.derivedFrom === "string" ? fm.derivedFrom : undefined,
|
|
130
|
-
raw,
|
|
131
|
-
normalizedBody,
|
|
132
|
-
bodyHash: dedupHash(raw),
|
|
133
|
-
hot: fm.captureMode === "hot",
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
return out;
|
|
137
|
-
}
|
|
138
|
-
/** Default cap on the O(n²) cosine-compare pool size. */
|
|
139
|
-
export const DEFAULT_COSINE_CANDIDATE_LIMIT = 500;
|
|
140
|
-
/**
|
|
141
|
-
* Build the deterministic collapse plan. Pure over (memories, similarities,
|
|
142
|
-
* threshold) — `embeddings` is optional; when absent only exact normalized-hash
|
|
143
|
-
* twins are matched.
|
|
144
|
-
*
|
|
145
|
-
* Pass invariants:
|
|
146
|
-
* - A memory is consumed (collapsed) at most once.
|
|
147
|
-
* - Hot (captureMode: hot) memories are never collapsed, as canonical OR
|
|
148
|
-
* variant — user-explicit, only the user retires them.
|
|
149
|
-
* - Class 1 (`.derived` ↔ origin) is matched first so a derived child is
|
|
150
|
-
* always folded into its origin (never the reverse, never twin-matched).
|
|
151
|
-
*/
|
|
152
|
-
export function planDedup(memories, opts) {
|
|
153
|
-
const collapses = [];
|
|
154
|
-
const warnings = [];
|
|
155
|
-
const consumed = new Set();
|
|
156
|
-
const threshold = opts.cosineThreshold;
|
|
157
|
-
const byName = new Map();
|
|
158
|
-
for (const m of memories)
|
|
159
|
-
byName.set(m.name, m);
|
|
160
|
-
const sim = (a, b) => {
|
|
161
|
-
if (!opts.embeddings)
|
|
162
|
-
return undefined;
|
|
163
|
-
const ea = opts.embeddings.get(a.name);
|
|
164
|
-
const eb = opts.embeddings.get(b.name);
|
|
165
|
-
if (!ea || !eb)
|
|
166
|
-
return undefined;
|
|
167
|
-
return cosineSimilarity(ea, eb);
|
|
168
|
-
};
|
|
169
|
-
// ── Class 1: `.derived` children ↔ their origin ────────────────────────────
|
|
170
|
-
// Iterate derived children in sorted order (loadDedupMemories sorts), folding
|
|
171
|
-
// each into its origin when near-identical.
|
|
172
|
-
const derived = memories.filter((m) => m.derived).sort((a, b) => a.name.localeCompare(b.name));
|
|
173
|
-
for (const child of derived) {
|
|
174
|
-
if (consumed.has(child.name))
|
|
175
|
-
continue;
|
|
176
|
-
if (child.hot)
|
|
177
|
-
continue;
|
|
178
|
-
const originName = child.derivedFrom ?? child.name.replace(/\.derived$/, "");
|
|
179
|
-
const origin = byName.get(originName);
|
|
180
|
-
if (!origin || consumed.has(origin.name) || origin.derived || origin.hot)
|
|
181
|
-
continue;
|
|
182
|
-
let via;
|
|
183
|
-
let similarity;
|
|
184
|
-
if (child.bodyHash === origin.bodyHash) {
|
|
185
|
-
via = "derived-hash";
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
const s = sim(child, origin);
|
|
189
|
-
if (s !== undefined && s >= threshold) {
|
|
190
|
-
via = "derived-cosine";
|
|
191
|
-
similarity = s;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
if (!via)
|
|
195
|
-
continue;
|
|
196
|
-
collapses.push({ canonical: origin.name, variant: child.name, via, similarity });
|
|
197
|
-
consumed.add(child.name);
|
|
198
|
-
}
|
|
199
|
-
// ── Class 2: content twins among non-derived memories ──────────────────────
|
|
200
|
-
// Bucket by exact normalized-hash first (cheap, transitive, deterministic).
|
|
201
|
-
const remaining = memories
|
|
202
|
-
.filter((m) => !m.derived && !m.hot && !consumed.has(m.name))
|
|
203
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
204
|
-
const hashBuckets = new Map();
|
|
205
|
-
for (const m of remaining) {
|
|
206
|
-
const list = hashBuckets.get(m.bodyHash);
|
|
207
|
-
if (list)
|
|
208
|
-
list.push(m);
|
|
209
|
-
else
|
|
210
|
-
hashBuckets.set(m.bodyHash, [m]);
|
|
211
|
-
}
|
|
212
|
-
for (const bucket of hashBuckets.values()) {
|
|
213
|
-
if (bucket.length < 2)
|
|
214
|
-
continue;
|
|
215
|
-
// Canonical = lexicographically smallest name (already sorted).
|
|
216
|
-
const canonical = bucket[0];
|
|
217
|
-
for (let i = 1; i < bucket.length; i++) {
|
|
218
|
-
const variant = bucket[i];
|
|
219
|
-
if (consumed.has(variant.name))
|
|
220
|
-
continue;
|
|
221
|
-
collapses.push({ canonical: canonical.name, variant: variant.name, via: "twin-hash" });
|
|
222
|
-
consumed.add(variant.name);
|
|
223
|
-
}
|
|
224
|
-
consumed.add(canonical.name); // canonical kept but no longer a twin candidate
|
|
225
|
-
}
|
|
226
|
-
// Cosine twins (only when embeddings are available). O(n²) over the still-
|
|
227
|
-
// unconsumed non-derived pool; deterministic greedy: for each canonical in
|
|
228
|
-
// sorted order, claim every unconsumed later memory whose similarity ≥ floor.
|
|
229
|
-
// The pool is capped at `cosineCandidateLimit` (default 500) to bound the
|
|
230
|
-
// O(n²) cost (~0.1 s at 500; ~3 s at 2.6 k; ~85 s at 13 k). Exact-hash
|
|
231
|
-
// matches above always run over the full pool and are unaffected.
|
|
232
|
-
if (opts.embeddings) {
|
|
233
|
-
const limit = opts.cosineCandidateLimit ?? DEFAULT_COSINE_CANDIDATE_LIMIT;
|
|
234
|
-
const fullPool = remaining.filter((m) => !consumed.has(m.name));
|
|
235
|
-
const pool = fullPool.length > limit ? fullPool.slice(0, limit) : fullPool;
|
|
236
|
-
if (fullPool.length > limit) {
|
|
237
|
-
warnings.push(`dedup: cosine compare pool (${fullPool.length}) exceeds cosineCandidateLimit (${limit}); capping to first ${limit} memories (exact-hash matches unaffected).`);
|
|
238
|
-
}
|
|
239
|
-
for (let i = 0; i < pool.length; i++) {
|
|
240
|
-
const canonical = pool[i];
|
|
241
|
-
if (consumed.has(canonical.name))
|
|
242
|
-
continue;
|
|
243
|
-
for (let j = i + 1; j < pool.length; j++) {
|
|
244
|
-
const variant = pool[j];
|
|
245
|
-
if (consumed.has(variant.name))
|
|
246
|
-
continue;
|
|
247
|
-
const s = sim(canonical, variant);
|
|
248
|
-
if (s !== undefined && s >= threshold) {
|
|
249
|
-
collapses.push({ canonical: canonical.name, variant: variant.name, via: "twin-cosine", similarity: s });
|
|
250
|
-
consumed.add(variant.name);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
consumed.add(canonical.name);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
return { collapses, warnings };
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Fold a dropped variant's provenance into the canonical's frontmatter. Appends
|
|
260
|
-
* the variant ref to a `dedupedFrom` list (deduplicated, sorted) and carries
|
|
261
|
-
* any `source`/`sources` references the variant held that the canonical lacks.
|
|
262
|
-
* Pure string→string; never invents timestamps.
|
|
263
|
-
*/
|
|
264
|
-
export function applyProvenance(canonicalRaw, variant) {
|
|
265
|
-
let parsed;
|
|
266
|
-
try {
|
|
267
|
-
parsed = parseFrontmatter(canonicalRaw);
|
|
268
|
-
}
|
|
269
|
-
catch {
|
|
270
|
-
// Canonical frontmatter unparseable — leave content untouched (the file is
|
|
271
|
-
// never collapsed AS a canonical when hot/unparseable is the variant, but
|
|
272
|
-
// the canonical itself can still be odd; preserve bytes).
|
|
273
|
-
return canonicalRaw;
|
|
274
|
-
}
|
|
275
|
-
const fm = { ...parsed.data };
|
|
276
|
-
const variantRef = `memory:${variant.name}`;
|
|
277
|
-
const existing = Array.isArray(fm.dedupedFrom)
|
|
278
|
-
? fm.dedupedFrom.filter((v) => typeof v === "string")
|
|
279
|
-
: typeof fm.dedupedFrom === "string"
|
|
280
|
-
? [fm.dedupedFrom]
|
|
281
|
-
: [];
|
|
282
|
-
const next = Array.from(new Set([...existing, variantRef])).sort();
|
|
283
|
-
fm.dedupedFrom = next;
|
|
284
|
-
return assembleAssetFromString(serializeFrontmatter(fm), parsed.content);
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Apply a collapse plan to disk: rewrite each canonical with merged provenance,
|
|
288
|
-
* delete each variant. Returns counts + consumed refs so the consolidate pass
|
|
289
|
-
* can prune them from the LLM pool. NO LLM call.
|
|
290
|
-
*
|
|
291
|
-
* `onArchive` (optional) is invoked with the variant file path before deletion
|
|
292
|
-
* so the caller can archive/back up exactly as it does for LLM merges.
|
|
293
|
-
*/
|
|
294
|
-
export function applyDedupPlan(plan, memories, onArchive) {
|
|
295
|
-
const byName = new Map();
|
|
296
|
-
for (const m of memories)
|
|
297
|
-
byName.set(m.name, m);
|
|
298
|
-
const warnings = [...plan.warnings];
|
|
299
|
-
const consumedRefs = [];
|
|
300
|
-
let collapsed = 0;
|
|
301
|
-
// Accumulate provenance per canonical so multiple variants folding into the
|
|
302
|
-
// same canonical produce a single rewrite.
|
|
303
|
-
const provByCanonical = new Map();
|
|
304
|
-
for (const c of plan.collapses) {
|
|
305
|
-
const list = provByCanonical.get(c.canonical);
|
|
306
|
-
if (list)
|
|
307
|
-
list.push(byName.get(c.variant));
|
|
308
|
-
else
|
|
309
|
-
provByCanonical.set(c.canonical, [byName.get(c.variant)]);
|
|
310
|
-
}
|
|
311
|
-
// 1. Rewrite canonicals with merged provenance.
|
|
312
|
-
for (const [canonicalName, variants] of provByCanonical) {
|
|
313
|
-
const canonical = byName.get(canonicalName);
|
|
314
|
-
if (!canonical)
|
|
315
|
-
continue;
|
|
316
|
-
let content = canonical.raw;
|
|
317
|
-
for (const v of variants.filter((x) => x).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
318
|
-
content = applyProvenance(content, v);
|
|
319
|
-
}
|
|
320
|
-
try {
|
|
321
|
-
fs.writeFileSync(canonical.filePath, content.endsWith("\n") ? content : `${content}\n`, "utf8");
|
|
322
|
-
}
|
|
323
|
-
catch (e) {
|
|
324
|
-
warnings.push(`dedup: failed to rewrite canonical ${canonicalName}: ${String(e)}`);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
// 2. Delete variants (archive first if requested).
|
|
328
|
-
for (const c of plan.collapses) {
|
|
329
|
-
const variant = byName.get(c.variant);
|
|
330
|
-
if (!variant)
|
|
331
|
-
continue;
|
|
332
|
-
if (!fs.existsSync(variant.filePath)) {
|
|
333
|
-
warnings.push(`dedup: variant ${c.variant} already absent — skipping delete.`);
|
|
334
|
-
continue;
|
|
335
|
-
}
|
|
336
|
-
if (onArchive) {
|
|
337
|
-
try {
|
|
338
|
-
onArchive(variant);
|
|
339
|
-
}
|
|
340
|
-
catch {
|
|
341
|
-
// best-effort archival; deletion proceeds
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
try {
|
|
345
|
-
fs.unlinkSync(variant.filePath);
|
|
346
|
-
collapsed++;
|
|
347
|
-
consumedRefs.push(`memory:${variant.name}`);
|
|
348
|
-
}
|
|
349
|
-
catch (e) {
|
|
350
|
-
warnings.push(`dedup: failed to delete variant ${c.variant}: ${String(e)}`);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
return { collapsed, consumedRefs, warnings };
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Top-level entry point for the consolidate pre-pass. Loads memories, optionally
|
|
357
|
-
* embeds them (only when a cosine path is reachable), plans, and applies the
|
|
358
|
-
* collapse. DEFAULT OFF — returns a no-op result when `config.enabled !== true`.
|
|
359
|
-
*
|
|
360
|
-
* `onArchive` lets the caller archive/back up each dropped variant before
|
|
361
|
-
* deletion (consolidate.ts wires this to its existing archive helper).
|
|
362
|
-
*
|
|
363
|
-
* `signal` (optional): an AbortSignal forwarded from the caller's budget
|
|
364
|
-
* controller. When aborted before the embedding call the function returns a
|
|
365
|
-
* no-op result immediately; the signal is also forwarded into `embedBatch`
|
|
366
|
-
* so a mid-embedding abort is handled cleanly.
|
|
367
|
-
*/
|
|
368
|
-
export async function runDeterministicDedup(stashDir, dedupConfig, akmConfig, onArchive, signal,
|
|
369
|
-
/** Optional open state.db handle for the body-embedding cache (WS-3a). */
|
|
370
|
-
stateDb) {
|
|
371
|
-
if (!dedupConfig?.enabled) {
|
|
372
|
-
return { collapsed: 0, consumedRefs: [], warnings: [] };
|
|
373
|
-
}
|
|
374
|
-
if (signal?.aborted) {
|
|
375
|
-
return { collapsed: 0, consumedRefs: [], warnings: ["dedup: aborted before start"] };
|
|
376
|
-
}
|
|
377
|
-
const threshold = dedupConfig.cosineThreshold ?? DEFAULT_DEDUP_COSINE_THRESHOLD;
|
|
378
|
-
const candidateLimit = dedupConfig.cosineCandidateLimit ?? DEFAULT_COSINE_CANDIDATE_LIMIT;
|
|
379
|
-
const memories = loadDedupMemories(stashDir);
|
|
380
|
-
if (memories.length === 0) {
|
|
381
|
-
return { collapsed: 0, consumedRefs: [], warnings: [] };
|
|
382
|
-
}
|
|
383
|
-
// Embed only when embeddings are configured — exact-hash collapse still works
|
|
384
|
-
// without them. Fail-open: any embedding error degrades to hash-only matching.
|
|
385
|
-
// NOTE: embedBatch embeds the case-preserving stripped body (cacheHash domain),
|
|
386
|
-
// not the lowercase dedupHash body, so dedup cosine and the body_embeddings
|
|
387
|
-
// cache share the same canonical embedding input.
|
|
388
|
-
let embeddings;
|
|
389
|
-
if (akmConfig.embedding) {
|
|
390
|
-
try {
|
|
391
|
-
const eligible = memories.filter((m) => !m.hot);
|
|
392
|
-
// Use the case-preserving stripped body for embeddings (matching cacheHash
|
|
393
|
-
// canonical input) so the embedding cache can be shared with consolidate.
|
|
394
|
-
const modelId = resolveEmbeddingModelId(akmConfig.embedding);
|
|
395
|
-
// WS-3a: body-embedding cache — look up all content_hashes in one query,
|
|
396
|
-
// embed only the misses, then upsert the new vectors in one transaction.
|
|
397
|
-
const contentHashes = eligible.map((m) => cacheHash(m.raw));
|
|
398
|
-
const hashToName = new Map();
|
|
399
|
-
for (let i = 0; i < eligible.length; i++) {
|
|
400
|
-
hashToName.set(contentHashes[i], eligible[i].name);
|
|
401
|
-
}
|
|
402
|
-
let cachedVecs = new Map();
|
|
403
|
-
if (stateDb) {
|
|
404
|
-
try {
|
|
405
|
-
cachedVecs = getBodyEmbeddings(stateDb, contentHashes, modelId);
|
|
406
|
-
}
|
|
407
|
-
catch {
|
|
408
|
-
// Fail open: cache read errors degrade to full embed.
|
|
409
|
-
cachedVecs = new Map();
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
const missIndices = [];
|
|
413
|
-
const missTexts = [];
|
|
414
|
-
for (let i = 0; i < eligible.length; i++) {
|
|
415
|
-
const hash = contentHashes[i];
|
|
416
|
-
if (!cachedVecs.has(hash)) {
|
|
417
|
-
missIndices.push(i);
|
|
418
|
-
missTexts.push(stripFrontmatterBody(eligible[i].raw) || eligible[i].name);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
let missVecs = [];
|
|
422
|
-
if (missTexts.length > 0) {
|
|
423
|
-
missVecs = await embedBatch(missTexts, akmConfig.embedding, signal);
|
|
424
|
-
// Upsert new vectors into cache.
|
|
425
|
-
if (stateDb && missVecs.length === missTexts.length) {
|
|
426
|
-
try {
|
|
427
|
-
const toUpsert = missIndices.map((idx, pos) => ({
|
|
428
|
-
contentHash: contentHashes[idx],
|
|
429
|
-
embedding: missVecs[pos],
|
|
430
|
-
modelId,
|
|
431
|
-
}));
|
|
432
|
-
upsertBodyEmbeddings(stateDb, toUpsert);
|
|
433
|
-
}
|
|
434
|
-
catch {
|
|
435
|
-
// Fail open: cache write errors are non-fatal.
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
// Assemble the full embeddings map (cache hits + freshly embedded misses).
|
|
440
|
-
if (missVecs.length === missTexts.length || cachedVecs.size > 0) {
|
|
441
|
-
embeddings = new Map();
|
|
442
|
-
// Add cache hits.
|
|
443
|
-
for (let i = 0; i < eligible.length; i++) {
|
|
444
|
-
const hash = contentHashes[i];
|
|
445
|
-
const cached = cachedVecs.get(hash);
|
|
446
|
-
if (cached)
|
|
447
|
-
embeddings.set(eligible[i].name, cached);
|
|
448
|
-
}
|
|
449
|
-
// Add freshly embedded misses.
|
|
450
|
-
for (let pos = 0; pos < missIndices.length; pos++) {
|
|
451
|
-
const idx = missIndices[pos];
|
|
452
|
-
const vec = missVecs[pos];
|
|
453
|
-
if (vec)
|
|
454
|
-
embeddings.set(eligible[idx].name, vec);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
catch {
|
|
459
|
-
embeddings = undefined;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
const plan = planDedup(memories, { cosineThreshold: threshold, embeddings, cosineCandidateLimit: candidateLimit });
|
|
463
|
-
if (plan.collapses.length === 0) {
|
|
464
|
-
return { collapsed: 0, consumedRefs: [], warnings: plan.warnings };
|
|
465
|
-
}
|
|
466
|
-
// Sanity: every variant ref must be a parseable memory ref before we touch
|
|
467
|
-
// disk (defends against a malformed name slipping through).
|
|
468
|
-
for (const c of plan.collapses) {
|
|
469
|
-
try {
|
|
470
|
-
parseAssetRef(`memory:${c.variant}`);
|
|
471
|
-
parseAssetRef(`memory:${c.canonical}`);
|
|
472
|
-
}
|
|
473
|
-
catch {
|
|
474
|
-
plan.warnings.push(`dedup: unparseable ref in collapse ${c.canonical} ← ${c.variant} — dropping op.`);
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
const result = applyDedupPlan(plan, memories, (v) => onArchive?.(v.filePath, v.name));
|
|
478
|
-
if (result.collapsed > 0) {
|
|
479
|
-
warn(`[consolidate] deterministic dedup collapsed ${result.collapsed} near-duplicate memor${result.collapsed === 1 ? "y" : "ies"} (no LLM).`);
|
|
480
|
-
}
|
|
481
|
-
return result;
|
|
482
|
-
}
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
-
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
-
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
import { akmExtract } from "./extract.js";
|
|
5
|
-
const DEFAULT_DEBOUNCE_MS = 2000;
|
|
6
|
-
/** Small look-back window for the default trigger's `akmExtract` call. */
|
|
7
|
-
const DEFAULT_TRIGGER_SINCE = "10m";
|
|
8
|
-
/**
|
|
9
|
-
* Does `filePath` look like a real session file under one of the configured
|
|
10
|
-
* roots? True only when the path is under a root AND matches that harness's
|
|
11
|
-
* on-disk session-file shape:
|
|
12
|
-
* - claude-code: `<root>/<project>/<id>.jsonl`
|
|
13
|
-
* - opencode: `<root>/<project>/<id>.json`
|
|
14
|
-
* Anything out-of-root, or in-root with the wrong extension, returns false.
|
|
15
|
-
*/
|
|
16
|
-
export function isSessionFile(filePath, roots) {
|
|
17
|
-
return matchHarness(filePath, roots) !== undefined;
|
|
18
|
-
}
|
|
19
|
-
/** Normalize a path for prefix comparison (ensure a trailing separator). */
|
|
20
|
-
function withSep(dir) {
|
|
21
|
-
return dir.endsWith("/") ? dir : `${dir}/`;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Resolve which harness a path belongs to by longest-prefix match against the
|
|
25
|
-
* configured roots, then validate the file shape for that harness. Returns the
|
|
26
|
-
* harness name, or `undefined` when the path is out-of-root or not a session
|
|
27
|
-
* file. Longest-prefix match guards against the (in practice impossible) case
|
|
28
|
-
* of nested roots.
|
|
29
|
-
*/
|
|
30
|
-
export function matchHarness(filePath, roots) {
|
|
31
|
-
let best;
|
|
32
|
-
let bestLen = -1;
|
|
33
|
-
for (const target of roots) {
|
|
34
|
-
for (const root of target.roots) {
|
|
35
|
-
const prefix = withSep(root);
|
|
36
|
-
if (filePath.startsWith(prefix) && prefix.length > bestLen) {
|
|
37
|
-
best = { harnessName: target.harnessName };
|
|
38
|
-
bestLen = prefix.length;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
if (!best)
|
|
43
|
-
return undefined;
|
|
44
|
-
// Validate the file shape for the resolved harness.
|
|
45
|
-
if (best.harnessName === "claude-code") {
|
|
46
|
-
return filePath.endsWith(".jsonl") ? best.harnessName : undefined;
|
|
47
|
-
}
|
|
48
|
-
if (best.harnessName === "opencode") {
|
|
49
|
-
return filePath.endsWith(".json") ? best.harnessName : undefined;
|
|
50
|
-
}
|
|
51
|
-
// Unknown harness: accept any file under its root.
|
|
52
|
-
return best.harnessName;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Start the watch-mode core. Returns a handle whose `stop()` tears everything
|
|
56
|
-
* down. The event source is injected, so this never touches the real
|
|
57
|
-
* filesystem itself.
|
|
58
|
-
*/
|
|
59
|
-
export function akmExtractWatch(options) {
|
|
60
|
-
const { roots, eventSource, debounceMs = DEFAULT_DEBOUNCE_MS, setTimeoutFn = setTimeout, clearTimeoutFn = clearTimeout, isSessionFile: isSessionFileFn = isSessionFile, } = options;
|
|
61
|
-
const onTrigger = options.onTrigger ??
|
|
62
|
-
(async (harnessName) => {
|
|
63
|
-
await akmExtract({ type: harnessName, since: DEFAULT_TRIGGER_SINCE, force: false });
|
|
64
|
-
});
|
|
65
|
-
let stopped = false;
|
|
66
|
-
// Pending debounce timers, keyed by harness name.
|
|
67
|
-
const pendingTimers = new Map();
|
|
68
|
-
// Harnesses with an in-flight trigger, and whether a re-run is queued.
|
|
69
|
-
const inFlight = new Set();
|
|
70
|
-
const rerunPending = new Set();
|
|
71
|
-
function runTrigger(harnessName) {
|
|
72
|
-
if (stopped)
|
|
73
|
-
return;
|
|
74
|
-
if (inFlight.has(harnessName)) {
|
|
75
|
-
// A trigger is already running for this harness; coalesce into a single
|
|
76
|
-
// re-run after it resolves rather than launching a concurrent extract.
|
|
77
|
-
rerunPending.add(harnessName);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
inFlight.add(harnessName);
|
|
81
|
-
// Invoke synchronously so a synchronous `onTrigger` observes its effect
|
|
82
|
-
// before control returns (tests advance the clock then assert inline).
|
|
83
|
-
// Wrap the (possibly async) result in a promise to drive the in-flight
|
|
84
|
-
// guard's release without forcing the trigger itself into a microtask.
|
|
85
|
-
let result;
|
|
86
|
-
try {
|
|
87
|
-
result = onTrigger(harnessName);
|
|
88
|
-
}
|
|
89
|
-
catch (err) {
|
|
90
|
-
// One failed extract must never kill the watcher (mirrors the non-fatal
|
|
91
|
-
// handling in collectSessionEvents).
|
|
92
|
-
console.error(`[akm] extract --watch trigger for "${harnessName}" failed:`, err);
|
|
93
|
-
inFlight.delete(harnessName);
|
|
94
|
-
if (rerunPending.delete(harnessName) && !stopped)
|
|
95
|
-
runTrigger(harnessName);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
Promise.resolve(result)
|
|
99
|
-
.catch((err) => {
|
|
100
|
-
console.error(`[akm] extract --watch trigger for "${harnessName}" failed:`, err);
|
|
101
|
-
})
|
|
102
|
-
.finally(() => {
|
|
103
|
-
inFlight.delete(harnessName);
|
|
104
|
-
if (rerunPending.delete(harnessName) && !stopped) {
|
|
105
|
-
runTrigger(harnessName);
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
function onEvent(e) {
|
|
110
|
-
if (stopped)
|
|
111
|
-
return;
|
|
112
|
-
if (!isSessionFileFn(e.path, roots))
|
|
113
|
-
return;
|
|
114
|
-
const harnessName = matchHarness(e.path, roots);
|
|
115
|
-
if (!harnessName)
|
|
116
|
-
return;
|
|
117
|
-
const existing = pendingTimers.get(harnessName);
|
|
118
|
-
if (existing !== undefined)
|
|
119
|
-
clearTimeoutFn(existing);
|
|
120
|
-
const timer = setTimeoutFn(() => {
|
|
121
|
-
pendingTimers.delete(harnessName);
|
|
122
|
-
if (!stopped)
|
|
123
|
-
runTrigger(harnessName);
|
|
124
|
-
}, debounceMs);
|
|
125
|
-
pendingTimers.set(harnessName, timer);
|
|
126
|
-
}
|
|
127
|
-
const unsubscribe = eventSource.subscribe(onEvent);
|
|
128
|
-
return {
|
|
129
|
-
stop() {
|
|
130
|
-
if (stopped)
|
|
131
|
-
return;
|
|
132
|
-
stopped = true;
|
|
133
|
-
unsubscribe();
|
|
134
|
-
for (const timer of pendingTimers.values())
|
|
135
|
-
clearTimeoutFn(timer);
|
|
136
|
-
pendingTimers.clear();
|
|
137
|
-
rerunPending.clear();
|
|
138
|
-
},
|
|
139
|
-
};
|
|
140
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
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
|
-
* WS-3b Step 0c — Hot-probation intake buffer (#604).
|
|
6
|
-
*
|
|
7
|
-
* New system-generated extractions enter `captureMode: hot-probation` and spend
|
|
8
|
-
* ONE consolidation cycle in probation before promotion to the main stash;
|
|
9
|
-
* dedup + quality second-pass runs against them. Stops noisy extractions from
|
|
10
|
-
* polluting the stash at the source. Reuses shared dedupHash + body_embeddings.
|
|
11
|
-
* Default OFF.
|
|
12
|
-
*
|
|
13
|
-
* @module hot-probation
|
|
14
|
-
*/
|
|
15
|
-
/**
|
|
16
|
-
* captureMode value for system-generated extractions in probation.
|
|
17
|
-
* Automatic counterpart to the user-explicit `captureMode: hot`.
|
|
18
|
-
*/
|
|
19
|
-
export const CAPTURE_MODE_HOT_PROBATION = "hot-probation";
|
|
20
|
-
/**
|
|
21
|
-
* Returns true when an asset is in hot-probation (system-generated, not yet
|
|
22
|
-
* graduated from the intake dedup+quality pass).
|
|
23
|
-
*/
|
|
24
|
-
export function isHotProbation(captureModeValue) {
|
|
25
|
-
return captureModeValue === CAPTURE_MODE_HOT_PROBATION;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Returns true when an asset should be skipped by the consolidation LLM
|
|
29
|
-
* because it's still in hot-probation (hasn't completed the intake pass yet).
|
|
30
|
-
*
|
|
31
|
-
* Hot-probation assets are processed by the consolidation dedup pre-pass
|
|
32
|
-
* (runDeterministicDedup) but excluded from the LLM merge clustering, so
|
|
33
|
-
* noisy extractions can't pollute the LLM context.
|
|
34
|
-
*/
|
|
35
|
-
export function shouldSkipHotProbationInLlm(frontmatterData) {
|
|
36
|
-
return isHotProbation(frontmatterData.captureMode);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Build frontmatter fields to inject when creating a hot-probation proposal.
|
|
40
|
-
* The proposal will carry `captureMode: hot-probation` so downstream logic
|
|
41
|
-
* knows to run the intake dedup pass before graduating it.
|
|
42
|
-
*/
|
|
43
|
-
export function buildHotProbationFrontmatter() {
|
|
44
|
-
return { captureMode: CAPTURE_MODE_HOT_PROBATION };
|
|
45
|
-
}
|