akm-cli 0.9.1 → 0.9.2-alpha.2
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 +103 -28
- package/README.md +3 -1
- package/SECURITY.md +1 -1
- package/STABILITY.md +1 -1
- package/dist/akm +2 -2
- package/dist/akm-migrate +2 -2
- package/dist/assets/hints/cli-hints-full.md +14 -9
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -1
- package/dist/assets/improve-strategies/reflect-distill.json +1 -1
- package/dist/assets/models.json +35 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +3 -4
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +1 -3
- package/dist/assets/tasks/core/extract.yml +6 -5
- package/dist/assets/tasks/core/improve.yml +6 -5
- package/dist/assets/tasks/core/index-refresh.yml +6 -5
- package/dist/assets/tasks/core/sync.yml +6 -5
- package/dist/assets/tasks/core/version-check.yml +6 -5
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +6 -5
- package/dist/cli/confirm.js +2 -2
- package/dist/cli/parse-args.js +3 -24
- package/dist/cli/retired-commands.js +1 -1
- package/dist/cli/shared.js +2 -2
- package/dist/cli.js +11 -9
- package/dist/commands/agent/agent-dispatch.js +55 -89
- package/dist/commands/agent/contribute-cli.js +12 -45
- package/dist/commands/command/builtin-action.js +32 -0
- package/dist/commands/command/command-cli.js +99 -0
- package/dist/commands/command/command-execution.js +308 -0
- package/dist/commands/command/execution-source-loader.js +176 -0
- package/dist/commands/command/portable-template.js +60 -0
- package/dist/commands/config-cli.js +10 -4
- package/dist/commands/env/env.js +4 -2
- package/dist/commands/feedback-cli.js +1 -1
- package/dist/commands/health/checks.js +241 -29
- package/dist/commands/health/html-report.js +0 -14
- package/dist/commands/health/report-view-model.js +0 -1
- package/dist/commands/health/surfaces.js +6 -7
- package/dist/commands/health/types.js +0 -2
- package/dist/commands/health.js +63 -18
- package/dist/commands/improve/collapse-detector.js +5 -6
- package/dist/commands/improve/consolidate.js +251 -214
- package/dist/commands/improve/distill/promote-memory.js +71 -34
- package/dist/commands/improve/distill/quality-gate.js +17 -5
- package/dist/commands/improve/distill.js +232 -155
- package/dist/commands/improve/eligibility.js +112 -79
- package/dist/commands/improve/execution.js +57 -0
- package/dist/commands/improve/extract-cli.js +5 -5
- package/dist/commands/improve/extract-prompt.js +64 -22
- package/dist/commands/improve/extract.js +608 -360
- package/dist/commands/improve/improve-strategies.js +43 -14
- package/dist/commands/improve/improve.js +249 -29
- package/dist/commands/improve/loop-stages.js +11 -17
- package/dist/commands/improve/memory/memory-contradiction-detect.js +90 -66
- package/dist/commands/improve/outcome-loop.js +22 -38
- package/dist/commands/improve/planner.js +134 -0
- package/dist/commands/improve/preparation.js +730 -409
- package/dist/commands/improve/reflect.js +386 -223
- package/dist/commands/improve/run-context.js +3 -4
- package/dist/commands/improve/salience.js +6 -58
- package/dist/commands/improve/session-asset.js +12 -12
- package/dist/commands/lint/index.js +101 -29
- package/dist/commands/migrate-cli.js +11 -69
- package/dist/commands/migration-tool.js +6 -9
- package/dist/commands/models-cli.js +27 -0
- package/dist/commands/proposal/drain.js +258 -186
- package/dist/commands/proposal/proposal-cli.js +32 -10
- package/dist/commands/proposal/proposal.js +2 -5
- package/dist/commands/proposal/propose.js +192 -172
- package/dist/commands/proposal/repository.js +54 -91
- package/dist/commands/proposal/validators/proposal-validators.js +9 -7
- package/dist/commands/read/curate.js +53 -22
- package/dist/commands/read/registry-search.js +25 -9
- package/dist/commands/read/remember-cli.js +14 -2
- package/dist/commands/read/search.js +10 -4
- package/dist/commands/read/show.js +139 -153
- package/dist/commands/registry-cli.js +16 -7
- package/dist/commands/remember.js +33 -18
- package/dist/commands/sources/add-cli.js +19 -178
- package/dist/commands/sources/bundle-cli.js +15 -3
- package/dist/commands/sources/dangerous-env-audit.js +135 -0
- package/dist/commands/sources/info.js +2 -1
- package/dist/commands/sources/installed-stashes.js +901 -177
- package/dist/commands/sources/schema-repair.js +174 -95
- package/dist/commands/sources/self-update.js +30 -74
- package/dist/commands/sources/source-add.js +3 -5
- package/dist/commands/sources/sources-cli.js +2 -15
- package/dist/commands/sources/update-transaction.js +220 -0
- package/dist/commands/tasks/tasks-cli.js +3 -3
- package/dist/commands/tasks/tasks.js +736 -317
- package/dist/commands/workflow-cli.js +2 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +3 -0
- package/dist/core/adapter/adapters/akm-adapter.js +85 -35
- package/dist/core/adapter/adapters/akm-lint.js +54 -39
- package/dist/core/adapter/adapters/akm-metadata.js +45 -45
- package/dist/core/adapter/adapters/akm-task-adapter.js +32 -49
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +38 -23
- package/dist/core/adapter/adapters/dotenv-adapter.js +30 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +11 -0
- package/dist/core/adapter/adapters/index.js +0 -9
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +4 -0
- package/dist/core/adapter/adapters/okf-adapter.js +4 -0
- package/dist/core/adapter/adapters/opencode-adapter.js +5 -8
- package/dist/core/adapter/adapters/tool-dir-shared.js +63 -6
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -0
- package/dist/core/adapter/execution-source.js +308 -0
- package/dist/core/adapter/recognize-match.js +36 -13
- package/dist/core/adapter/registry.js +0 -9
- package/dist/core/asset/stash-meta.js +94 -4
- package/dist/core/common.js +6 -11
- package/dist/core/config/config-io.js +3 -3
- package/dist/core/config/config-schema.js +18 -40
- package/dist/core/config/config-sources.js +11 -21
- package/dist/core/config/config-walker.js +31 -13
- package/dist/core/config/config.js +23 -26
- package/dist/core/config/schema/engines.js +8 -7
- package/dist/core/config/schema/improve-processes.js +29 -5
- package/dist/core/config/schema/index-config.js +0 -27
- package/dist/core/config/schema/primitives.js +1 -23
- package/dist/core/config/schema/sources-bundles.js +13 -16
- package/dist/core/errors.js +2 -0
- package/dist/core/events.js +68 -32
- package/dist/core/extra-params.js +1 -0
- package/dist/core/improve-result.js +315 -0
- package/dist/core/lesson-lint.js +0 -6
- package/dist/core/maintenance-barrier.js +4 -4
- package/dist/core/network-policy.js +152 -0
- package/dist/core/paths.js +1 -1
- package/dist/core/recognition-util.js +4 -4
- package/dist/core/registry-url.js +456 -0
- package/dist/core/state/migrations.js +161 -47
- package/dist/core/state-db.js +453 -80
- package/dist/core/system-error.js +32 -0
- package/dist/core/time.js +2 -12
- package/dist/core/write-source.js +0 -18
- package/dist/execution/directory-identity.js +52 -0
- package/dist/execution/executable-identity.js +107 -0
- package/dist/execution/guarded-source.js +398 -0
- package/dist/execution/json.js +95 -0
- package/dist/{commands/health/types-session-log.js → execution/limits.js} +2 -1
- package/dist/execution/record.js +55 -0
- package/dist/execution/resolved-request.js +730 -0
- package/dist/execution/source.js +320 -0
- package/dist/indexer/bundle-identity-guard.js +5 -4
- package/dist/indexer/db/graph-db.js +33 -0
- package/dist/indexer/graph/graph-boost.js +3 -4
- package/dist/indexer/graph/graph-extraction.js +562 -373
- package/dist/indexer/index-written-assets.js +78 -39
- package/dist/indexer/indexer.js +471 -432
- package/dist/indexer/installations.js +6 -0
- package/dist/indexer/lookup/adapter-concept-owner.js +283 -0
- package/dist/indexer/materialize-embeddings.js +155 -0
- package/dist/indexer/passes/memory-inference.js +227 -174
- package/dist/indexer/passes/metadata.js +263 -118
- package/dist/indexer/scan/doc-to-entry.js +7 -10
- package/dist/indexer/scan/drain-dir.js +51 -23
- package/dist/indexer/search/db-search.js +156 -50
- package/dist/indexer/search/fts-query.js +40 -40
- package/dist/indexer/search/ranking.js +36 -1
- package/dist/indexer/search/search-attribution.js +3 -1
- package/dist/indexer/search/search-fields.js +23 -14
- package/dist/indexer/search/search-hit-enrichers.js +1 -1
- package/dist/indexer/search/search-source.js +7 -16
- package/dist/indexer/search/semantic-status.js +10 -1
- package/dist/indexer/usage/show-usage.js +105 -0
- package/dist/indexer/usage/usage-events.js +7 -2
- package/dist/indexer/walk/matchers.js +40 -10
- package/dist/indexer/walk/path-resolver.js +5 -2
- package/dist/indexer/walk/walker.js +20 -2
- package/dist/integrations/agent/builder-shared.js +3 -6
- package/dist/integrations/agent/conversation-fallback.js +16 -0
- package/dist/integrations/agent/engine-resolution.js +87 -87
- package/dist/integrations/agent/execution-cascade.js +566 -0
- package/dist/integrations/agent/execution-definitions.js +211 -0
- package/dist/integrations/agent/execution-lowering.js +811 -0
- package/dist/integrations/agent/execution-preparation.js +67 -0
- package/dist/integrations/agent/index.js +0 -2
- package/dist/integrations/agent/inline-execution.js +74 -0
- package/dist/integrations/agent/model-map.js +515 -0
- package/dist/integrations/agent/persona-fallback.js +30 -0
- package/dist/integrations/agent/request-lowering.js +186 -0
- package/dist/integrations/agent/runner-dispatch.js +230 -37
- package/dist/integrations/agent/runner.js +12 -83
- package/dist/integrations/harnesses/aider/agent-builder.js +8 -0
- package/dist/integrations/harnesses/aider/index.js +0 -1
- package/dist/integrations/harnesses/amazonq/agent-builder.js +8 -0
- package/dist/integrations/harnesses/amazonq/index.js +0 -1
- package/dist/integrations/harnesses/claude/agent-builder.js +14 -1
- package/dist/integrations/harnesses/claude/index.js +1 -5
- package/dist/integrations/harnesses/claude/session-log.js +3 -33
- package/dist/integrations/harnesses/codex/agent-builder.js +8 -0
- package/dist/integrations/harnesses/codex/index.js +0 -1
- package/dist/integrations/harnesses/copilot/agent-builder.js +8 -0
- package/dist/integrations/harnesses/copilot/index.js +0 -1
- package/dist/integrations/harnesses/gemini/agent-builder.js +8 -0
- package/dist/integrations/harnesses/gemini/index.js +0 -1
- package/dist/integrations/harnesses/index.js +4 -44
- package/dist/integrations/harnesses/opencode/agent-builder.js +16 -9
- package/dist/integrations/harnesses/opencode/index.js +0 -2
- package/dist/integrations/harnesses/opencode/session-log.js +14 -204
- package/dist/integrations/harnesses/opencode-sdk/harness.js +12 -1
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +40 -42
- package/dist/integrations/harnesses/openhands/agent-builder.js +8 -0
- package/dist/integrations/harnesses/openhands/index.js +0 -1
- package/dist/integrations/harnesses/pi/agent-builder.js +8 -0
- package/dist/integrations/harnesses/pi/index.js +0 -1
- package/dist/integrations/harnesses/shared.js +0 -1
- package/dist/integrations/harnesses/types.js +1 -3
- package/dist/integrations/lockfile.js +82 -79
- package/dist/integrations/session-logs/index.js +6 -17
- package/dist/integrations/session-logs/provider-base.js +1 -29
- package/dist/llm/client.js +10 -5
- package/dist/llm/embedder.js +6 -7
- package/dist/llm/embedders/local.js +37 -88
- package/dist/llm/embedders/types.js +1 -1
- package/dist/llm/graph-extract.js +75 -50
- package/dist/llm/index-passes.js +43 -5
- package/dist/llm/memory-infer.js +8 -6
- package/dist/llm/metadata-enhance.js +5 -3
- package/dist/llm/structured-call.js +122 -25
- package/dist/output/format-exempt.js +1 -1
- package/dist/output/render-registry.js +0 -16
- package/dist/output/renderers.js +12 -7
- package/dist/output/shapes/curate.js +1 -0
- package/dist/output/shapes/helpers.js +10 -2
- package/dist/output/shapes/passthrough.js +2 -0
- package/dist/output/text/command-format.js +31 -33
- package/dist/output/text/health-format.js +1 -29
- package/dist/output/text/migrate.js +6 -56
- package/dist/output/text/proposal-format.js +16 -1
- package/dist/output/text/workflow-format.js +16 -0
- package/dist/registry/network.js +279 -0
- package/dist/registry/pinned-request-helper.js +247 -0
- package/dist/registry/pinned-transport.js +717 -0
- package/dist/registry/providers/skills-sh.js +18 -6
- package/dist/registry/providers/static-index.js +20 -7
- package/dist/registry/resolve.js +53 -28
- package/dist/scripts/akm-migrate-node.js +19334 -52269
- package/dist/scripts/akm-migrate.js +19270 -51612
- package/dist/setup/registry-stash-loader.js +64 -20
- package/dist/setup/semantic-assets.js +9 -34
- package/dist/setup/setup.js +12 -30
- package/dist/setup/source-identity.js +17 -0
- package/dist/setup/steps/sources.js +36 -15
- package/dist/setup/steps/tasks.js +39 -11
- package/dist/sources/providers/git-provider.js +3 -3
- package/dist/sources/providers/npm.js +2 -2
- package/dist/sources/providers/provider-utils.js +4 -3
- package/dist/sources/providers/website.js +11 -7
- package/dist/sources/snapshot-fetchers/host-guard.js +9 -136
- package/dist/sources/snapshot-fetchers/website-ingest.js +25 -109
- package/dist/sources/website-url.js +73 -0
- package/dist/storage/engines/sqlite-migrations.js +81 -26
- package/dist/storage/managed-db.js +27 -24
- package/dist/storage/repositories/events-repository.js +3 -0
- package/dist/storage/repositories/index-connection.js +42 -10
- package/dist/storage/repositories/index-entries-repository.js +203 -229
- package/dist/storage/repositories/index-entry-mapper.js +8 -12
- package/dist/storage/repositories/index-entry-schema.js +255 -0
- package/dist/storage/repositories/index-fts-repository.js +64 -71
- package/dist/storage/repositories/index-llm-cache-repository.js +8 -13
- package/dist/storage/repositories/index-meta-repository.js +0 -11
- package/dist/storage/repositories/index-schema.js +74 -350
- package/dist/storage/repositories/index-utility-repository.js +12 -17
- package/dist/storage/repositories/index-vec-repository.js +56 -7
- package/dist/storage/repositories/proposals-repository.js +4 -127
- package/dist/storage/repositories/registry-cache.js +2 -1
- package/dist/storage/repositories/task-history-repository.js +20 -40
- package/dist/storage/repositories/workflow-runs-repository.js +228 -129
- package/dist/storage/sqlite-read-snapshot.js +148 -0
- package/dist/tasks/backends/cron.js +170 -42
- package/dist/tasks/backends/index.js +1 -1
- package/dist/tasks/backends/launchd.js +787 -202
- package/dist/tasks/backends/schtasks.js +282 -83
- package/dist/tasks/embedded.js +7 -7
- package/dist/tasks/frozen-script.js +50 -0
- package/dist/tasks/resolve-akm-bin.js +5 -1
- package/dist/tasks/runner.js +239 -251
- package/dist/tasks/runtime-v3.js +281 -0
- package/dist/tasks/scheduler-binding.js +272 -0
- package/dist/tasks/scheduler-invocation.js +57 -43
- package/dist/tasks/scheduler-sync.js +654 -0
- package/dist/tasks/source-v3.js +752 -0
- package/dist/tasks/standalone-script-entry.js +5 -0
- package/dist/tasks/task-id.js +29 -0
- package/dist/workflows/authoring/authoring.js +15 -32
- package/dist/workflows/exec/dispatch-redaction.js +14 -8
- package/dist/workflows/exec/exec-unit.js +7 -28
- package/dist/workflows/exec/frozen-judge.js +57 -89
- package/dist/workflows/exec/lowering-notices.js +23 -0
- package/dist/workflows/exec/native-executor.js +301 -458
- package/dist/workflows/exec/param-secrets.js +4 -3
- package/dist/workflows/exec/run-workflow.js +26 -32
- package/dist/workflows/exec/step-work.js +105 -109
- package/dist/workflows/exec/unit-dispatch.js +103 -27
- package/dist/workflows/exec/unit-writer.js +3 -3
- package/dist/workflows/exec/worktree.js +2 -2
- package/dist/workflows/ir/compile.js +86 -72
- package/dist/workflows/ir/environment-v4.js +328 -0
- package/dist/workflows/ir/freeze-v4.js +122 -0
- package/dist/workflows/ir/plan-hash.js +13 -7
- package/dist/workflows/ir/schema-v4.js +525 -0
- package/dist/workflows/ir/schema.js +25 -284
- package/dist/workflows/ir/source-freeze-v4.js +506 -0
- package/dist/workflows/parser.js +27 -24
- package/dist/workflows/program/schema.js +1 -2
- package/dist/workflows/renderer.js +42 -29
- package/dist/workflows/resource-limits.js +4 -5
- package/dist/workflows/runtime/agent-identity.js +11 -13
- package/dist/workflows/runtime/plan-classifier.js +8 -8
- package/dist/workflows/runtime/runs.js +27 -43
- package/dist/workflows/runtime/workflow-asset-loader.js +45 -205
- package/dist/workflows/source-files.js +373 -0
- package/dist/workflows/source-ir/compile.js +196 -0
- package/dist/workflows/source-ir/github-yaml.js +577 -0
- package/dist/workflows/source-ir/ordering.js +38 -0
- package/dist/workflows/source-ir/program.js +50 -0
- package/dist/workflows/source-ir/result.js +26 -0
- package/dist/workflows/source-ir/schema.js +772 -0
- package/dist/workflows/source-ir/semantics.js +242 -0
- package/dist/workflows/source-ir/uses.js +14 -0
- package/docs/README.md +2 -0
- package/docs/migration/README.md +3 -1
- package/docs/migration/release-notes/0.9.2.md +55 -0
- package/docs/migration/release-notes/README.md +5 -0
- package/docs/migration/v0.8-to-v0.9.md +76 -1077
- package/docs/migration/v0.9.0-troubleshooting.md +104 -516
- package/docs/migration/v0.9.1-to-v0.9.2.md +150 -0
- package/docs/reference/README.md +1 -0
- package/docs/reference/cli.md +230 -98
- package/docs/reference/configuration.md +159 -36
- package/docs/reference/data-and-telemetry.md +19 -1
- package/docs/reference/supported-formats.md +23 -3
- package/docs/reference/tasks.md +182 -0
- package/docs/reference/workflow-schema.md +91 -40
- package/docs/reference/workflows.md +33 -6
- package/package.json +10 -6
- package/schemas/akm-config.json +372 -224
- package/schemas/akm-task.json +324 -80
- package/schemas/akm-workflow.json +6 -9
- package/dist/core/migration-operation.js +0 -75
- package/dist/integrations/agent/model-aliases.js +0 -74
- package/dist/tasks/parser.js +0 -380
- package/dist/tasks/schema.js +0 -123
- package/dist/tasks/validator.js +0 -80
- package/dist/workflows/ir/freeze.js +0 -320
- package/dist/workflows/runtime/document-cache.js +0 -13
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
* NEVER deleted — the user keeps what was already produced.
|
|
30
30
|
*
|
|
31
31
|
* Locked v1 contract:
|
|
32
|
-
* - LLM access is exclusively via
|
|
32
|
+
* - LLM access is exclusively via the frozen runner returned by
|
|
33
|
+
* `resolveIndexPassExecution("memory", config)`.
|
|
33
34
|
* - All child memory writes go through `writeAssetToSource` in
|
|
34
35
|
* `src/core/write-source.ts`. The parent's frontmatter rewrite is an
|
|
35
36
|
* explicit narrow exception — see {@link markParentProcessed}.
|
|
@@ -40,14 +41,19 @@ import { detectAdapterId } from "../../core/adapter/detect-adapter.js";
|
|
|
40
41
|
import { assembleAsset } from "../../core/asset/asset-serialize.js";
|
|
41
42
|
import { parseFrontmatter, parseFrontmatterBlock } from "../../core/asset/frontmatter.js";
|
|
42
43
|
import { conceptIdFromTypeName, parseRefInput } from "../../core/asset/resolve-ref.js";
|
|
44
|
+
import { bestEffort } from "../../core/best-effort.js";
|
|
43
45
|
import { todayIso } from "../../core/common.js";
|
|
44
46
|
import { concurrentMap } from "../../core/concurrent.js";
|
|
47
|
+
import { ConfigError } from "../../core/errors.js";
|
|
45
48
|
import { warn } from "../../core/warn.js";
|
|
46
49
|
import { recordWrittenPath } from "../../core/write-provenance.js";
|
|
47
50
|
import { writeAssetToSource } from "../../core/write-source.js";
|
|
51
|
+
import { disposeLoweredExecutionDispatchLease, } from "../../integrations/agent/execution-lowering.js";
|
|
48
52
|
import { isProcessEnabled } from "../../llm/feature-gate.js";
|
|
49
|
-
import {
|
|
53
|
+
import { resolveIndexPassExecution } from "../../llm/index-passes.js";
|
|
50
54
|
import * as memoryInfer from "../../llm/memory-infer.js";
|
|
55
|
+
import { preflightStructuredLlmRunner } from "../../llm/structured-call.js";
|
|
56
|
+
import { computeBodyHash, getLlmCacheEntry } from "../../storage/repositories/index-llm-cache-repository.js";
|
|
51
57
|
import { withLlmCache } from "../db/llm-cache.js";
|
|
52
58
|
import { walkMarkdownFiles } from "../walk/walker.js";
|
|
53
59
|
/**
|
|
@@ -58,6 +64,114 @@ const FM_INFERRED = "inferred";
|
|
|
58
64
|
const FM_INFERENCE_PROCESSED = "inferenceProcessed";
|
|
59
65
|
const FM_SOURCE = "source";
|
|
60
66
|
const FM_CAPTURE_MODE = "captureMode";
|
|
67
|
+
function validateDerivedMemoryDraft(raw) {
|
|
68
|
+
if (!raw || typeof raw !== "object")
|
|
69
|
+
return undefined;
|
|
70
|
+
const parsed = raw;
|
|
71
|
+
const title = typeof parsed.title === "string" ? parsed.title : "";
|
|
72
|
+
const description = typeof parsed.description === "string" ? parsed.description : "";
|
|
73
|
+
const content = typeof parsed.content === "string" ? parsed.content : "";
|
|
74
|
+
const tags = Array.isArray(parsed.tags) ? parsed.tags.filter((tag) => typeof tag === "string") : [];
|
|
75
|
+
const searchHints = Array.isArray(parsed.searchHints)
|
|
76
|
+
? parsed.searchHints.filter((hint) => typeof hint === "string")
|
|
77
|
+
: [];
|
|
78
|
+
return title && description && content && tags.length > 0 && searchHints.length > 0
|
|
79
|
+
? { title, description, tags, searchHints, content }
|
|
80
|
+
: undefined;
|
|
81
|
+
}
|
|
82
|
+
function planPendingMemoryRecord(record, ctx) {
|
|
83
|
+
if (ctx.signal?.aborted)
|
|
84
|
+
return { kind: "aborted", record };
|
|
85
|
+
if (fs.existsSync(derivedChildPath(record)))
|
|
86
|
+
return { kind: "existing-child", record };
|
|
87
|
+
if (ctx.db && !ctx.reEnrich) {
|
|
88
|
+
const cached = bestEffort(() => {
|
|
89
|
+
const entry = getLlmCacheEntry(ctx.db, record.filePath, computeBodyHash(record.body), "memory-inference-v2");
|
|
90
|
+
return entry ? validateDerivedMemoryDraft(JSON.parse(entry.resultJson)) : undefined;
|
|
91
|
+
}, "memory inference cache read corrupt — fall through to recompute");
|
|
92
|
+
if (cached)
|
|
93
|
+
return { kind: "cache-hit", record, derived: cached };
|
|
94
|
+
}
|
|
95
|
+
return { kind: "model", record };
|
|
96
|
+
}
|
|
97
|
+
function memoryExecutionForContext(ctx, config) {
|
|
98
|
+
if (Object.hasOwn(ctx, "llmRunner")) {
|
|
99
|
+
return Object.freeze({ runner: ctx.llmRunner ?? undefined, notices: Object.freeze([]) });
|
|
100
|
+
}
|
|
101
|
+
return resolveIndexPassExecution("memory", config);
|
|
102
|
+
}
|
|
103
|
+
async function inferPendingMemoryRecord(plan, ctx) {
|
|
104
|
+
const { record } = plan;
|
|
105
|
+
const { config, featureConfig, signal, db, reEnrich, llmRunner, lease, inferTelemetry, compressMemoryToDerivedMemory, onNotices, onConfigFailure, } = ctx;
|
|
106
|
+
if (signal?.aborted || plan.kind === "aborted")
|
|
107
|
+
return { aborted: true };
|
|
108
|
+
// Existing children are complete, but the parent may be unmarked after a
|
|
109
|
+
// crash between the child write and parent update (or an external write).
|
|
110
|
+
if (fs.existsSync(derivedChildPath(record))) {
|
|
111
|
+
markParentProcessed(record);
|
|
112
|
+
return {
|
|
113
|
+
skipped: false,
|
|
114
|
+
splitParent: false,
|
|
115
|
+
written: 0,
|
|
116
|
+
fromCache: false,
|
|
117
|
+
retryAttempts: 0,
|
|
118
|
+
childExists: true,
|
|
119
|
+
precheck: true,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
// The child can disappear after the read-only classification pass (for
|
|
123
|
+
// example, an external cleanup racing this index run). The plan is not proof
|
|
124
|
+
// that the child still exists at the mutation boundary: leave the parent
|
|
125
|
+
// pending so a later run can classify and preflight the now-real model work.
|
|
126
|
+
if (plan.kind === "existing-child") {
|
|
127
|
+
return { skipped: true, fromCache: false, retryAttempts: 0 };
|
|
128
|
+
}
|
|
129
|
+
let fromCache = plan.kind === "cache-hit";
|
|
130
|
+
let retryAttempts = 0;
|
|
131
|
+
const onRetryAttempt = () => {
|
|
132
|
+
retryAttempts += 1;
|
|
133
|
+
};
|
|
134
|
+
const infer = () => compressMemoryToDerivedMemory(llmRunner, record.body, signal, featureConfig, (event) => warn(`[akm] LLM fallback for ${event.feature}: ${event.reason}`), inferTelemetry, onRetryAttempt, onNotices, lease);
|
|
135
|
+
let derived = plan.kind === "cache-hit" ? plan.derived : undefined;
|
|
136
|
+
try {
|
|
137
|
+
if (plan.kind === "model") {
|
|
138
|
+
derived = db
|
|
139
|
+
? await withLlmCache(db, record.filePath, record.body, reEnrich ?? false, infer, validateDerivedMemoryDraft, undefined, "memory-inference-v2", {
|
|
140
|
+
onCacheHit: () => {
|
|
141
|
+
fromCache = true;
|
|
142
|
+
},
|
|
143
|
+
})
|
|
144
|
+
: await compressMemoryToDerivedMemory(llmRunner, record.body, signal, config, (event) => warn(`[akm] LLM fallback for ${event.feature}: ${event.reason}`), inferTelemetry, onRetryAttempt, onNotices, lease);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
if (error instanceof ConfigError) {
|
|
149
|
+
onConfigFailure(error);
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
if (!derived)
|
|
155
|
+
return { skipped: true, fromCache, retryAttempts };
|
|
156
|
+
const writeOutcome = await writeDerivedMemory(record, derived);
|
|
157
|
+
if (writeOutcome.written > 0) {
|
|
158
|
+
markParentProcessed(record);
|
|
159
|
+
return { skipped: false, splitParent: true, written: writeOutcome.written, fromCache, retryAttempts };
|
|
160
|
+
}
|
|
161
|
+
// A child that appeared mid-flight is complete and can safely mark its
|
|
162
|
+
// parent. A genuine write failure remains unmarked for a later retry.
|
|
163
|
+
if (writeOutcome.childExists)
|
|
164
|
+
markParentProcessed(record);
|
|
165
|
+
return {
|
|
166
|
+
skipped: false,
|
|
167
|
+
splitParent: false,
|
|
168
|
+
written: 0,
|
|
169
|
+
fromCache,
|
|
170
|
+
retryAttempts,
|
|
171
|
+
childExists: true,
|
|
172
|
+
precheck: false,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
61
175
|
/**
|
|
62
176
|
* Top-level entry point. Returns a no-op result when the pass is disabled.
|
|
63
177
|
*
|
|
@@ -66,8 +180,8 @@ const FM_CAPTURE_MODE = "captureMode";
|
|
|
66
180
|
* 1. **Feature gate** — the selected strategy's `processes.memoryInference.enabled`
|
|
67
181
|
* (defaults to `true`). When `false`, no network call may issue regardless
|
|
68
182
|
* of per-pass settings.
|
|
69
|
-
* 2. **Per-pass gate** — `
|
|
70
|
-
*
|
|
183
|
+
* 2. **Per-pass gate** — `resolveIndexPassExecution("memory", config)` reads
|
|
184
|
+
* the index pass selection. Without a runner, the indexer simply skips
|
|
71
185
|
* this pass for the current run.
|
|
72
186
|
*
|
|
73
187
|
* Both must allow the call for the pass to run. Either set to `false`
|
|
@@ -75,7 +189,7 @@ const FM_CAPTURE_MODE = "captureMode";
|
|
|
75
189
|
*/
|
|
76
190
|
export async function runMemoryInferencePass(ctx) {
|
|
77
191
|
const { config, sources, signal, db, reEnrich, onProgress, options = {} } = ctx;
|
|
78
|
-
const
|
|
192
|
+
const invocationOwnsRunner = Object.hasOwn(ctx, "llmRunner");
|
|
79
193
|
const compressMemoryToDerivedMemory = options.compressMemoryToDerivedMemory ?? memoryInfer.compressMemoryToDerivedMemory;
|
|
80
194
|
const result = {
|
|
81
195
|
considered: 0,
|
|
@@ -93,17 +207,29 @@ export async function runMemoryInferencePass(ctx) {
|
|
|
93
207
|
// HTML-error categorization (which is otherwise swallowed inside the feature
|
|
94
208
|
// gate) bubbles up into the pass result.
|
|
95
209
|
const inferTelemetry = {};
|
|
210
|
+
const noticesByKey = new Map();
|
|
211
|
+
const onNotices = (notices) => {
|
|
212
|
+
for (const notice of notices)
|
|
213
|
+
noticesByKey.set(JSON.stringify(notice), notice);
|
|
214
|
+
};
|
|
215
|
+
const completeResult = () => {
|
|
216
|
+
if (noticesByKey.size > 0)
|
|
217
|
+
result.notices = Object.freeze([...noticesByKey.values()]);
|
|
218
|
+
return result;
|
|
219
|
+
};
|
|
96
220
|
// Gate 1 — feature gate via isProcessEnabled, which reads the 0.8.0 path
|
|
97
221
|
// (selected strategy's processes.memoryInference.enabled). Defaults to
|
|
98
222
|
// enabled when the key is absent.
|
|
99
|
-
if (!
|
|
100
|
-
return
|
|
223
|
+
if (!invocationOwnsRunner && !isProcessEnabled("index", "memory_inference", config))
|
|
224
|
+
return completeResult();
|
|
101
225
|
// Gate 2 — per-pass opt-out (#208). Returns the resolved llm config or
|
|
102
226
|
// `undefined` when the pass should not run.
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
227
|
+
const execution = memoryExecutionForContext(ctx, config);
|
|
228
|
+
onNotices(execution.notices);
|
|
229
|
+
const llmRunner = execution.runner;
|
|
230
|
+
if (!llmRunner)
|
|
231
|
+
return completeResult();
|
|
232
|
+
const featureConfig = invocationOwnsRunner
|
|
107
233
|
? { ...config, index: { ...config.index, memory: { ...config.index?.memory, enabled: true } } }
|
|
108
234
|
: config;
|
|
109
235
|
// The pass only writes to the primary (working) stash. Read-only caches
|
|
@@ -111,128 +237,94 @@ export async function runMemoryInferencePass(ctx) {
|
|
|
111
237
|
// children there would be clobbered by the next sync().
|
|
112
238
|
const primary = sources[0];
|
|
113
239
|
if (!primary || (primary.adapterId ?? detectAdapterId(primary.path)) !== "akm")
|
|
114
|
-
return
|
|
240
|
+
return completeResult();
|
|
115
241
|
const pending = collectPendingMemories(primary.path).filter((record) => !options.candidateRefs || options.candidateRefs.has(record.ref));
|
|
116
242
|
result.considered = pending.length;
|
|
117
243
|
if (pending.length === 0)
|
|
118
|
-
return
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
244
|
+
return completeResult();
|
|
245
|
+
// Classify the whole batch without mutation. Required credentials are
|
|
246
|
+
// materialized only when at least one record will actually dispatch; this
|
|
247
|
+
// keeps aborted, existing-child, and validated-cache-only batches available
|
|
248
|
+
// offline while preserving all-or-nothing preflight for mixed batches.
|
|
249
|
+
const plans = pending.map((record) => planPendingMemoryRecord(record, { signal, db, reEnrich }));
|
|
250
|
+
const dispatchLease = plans.some((plan) => plan.kind === "model")
|
|
251
|
+
? await preflightStructuredLlmRunner(llmRunner)
|
|
252
|
+
: undefined;
|
|
253
|
+
try {
|
|
254
|
+
let processed = 0;
|
|
255
|
+
const total = pending.length;
|
|
256
|
+
onProgress?.({ processed, total, writtenFacts: 0, skippedNoFacts: 0 });
|
|
257
|
+
let configFailure;
|
|
258
|
+
const perRecordResults = await concurrentMap(plans, (plan) => inferPendingMemoryRecord(plan, {
|
|
259
|
+
config,
|
|
260
|
+
featureConfig,
|
|
261
|
+
signal,
|
|
262
|
+
db,
|
|
263
|
+
reEnrich,
|
|
264
|
+
llmRunner,
|
|
265
|
+
lease: dispatchLease,
|
|
266
|
+
inferTelemetry,
|
|
267
|
+
compressMemoryToDerivedMemory,
|
|
268
|
+
onNotices,
|
|
269
|
+
onConfigFailure: (error) => {
|
|
270
|
+
configFailure ??= error;
|
|
271
|
+
},
|
|
272
|
+
}),
|
|
273
|
+
// Caller-set connection concurrency or 1: `resolveLlmEngineUse` does
|
|
274
|
+
// not forward `engines.<name>.concurrency`, so config cannot raise this.
|
|
275
|
+
llmRunner.connection.concurrency ?? 1);
|
|
276
|
+
if (configFailure)
|
|
277
|
+
throw configFailure;
|
|
278
|
+
for (let i = 0; i < perRecordResults.length; i++) {
|
|
279
|
+
const res = perRecordResults[i];
|
|
280
|
+
if (!res)
|
|
281
|
+
continue;
|
|
282
|
+
if ("aborted" in res && res.aborted) {
|
|
283
|
+
result.skippedAborted += 1;
|
|
284
|
+
processed++;
|
|
285
|
+
onProgress?.({
|
|
286
|
+
processed,
|
|
287
|
+
total,
|
|
288
|
+
writtenFacts: result.writtenFacts,
|
|
289
|
+
skippedNoFacts: result.skippedNoFacts,
|
|
290
|
+
currentRef: pending[i]?.ref,
|
|
291
|
+
});
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (res.fromCache) {
|
|
295
|
+
result.cacheHits += 1;
|
|
296
|
+
}
|
|
297
|
+
if ("retryAttempts" in res) {
|
|
298
|
+
result.retryAttempts += res.retryAttempts;
|
|
299
|
+
}
|
|
300
|
+
if (res.skipped) {
|
|
301
|
+
result.skippedNoFacts += 1;
|
|
302
|
+
// Intentionally NOT marked processed — a transient LLM failure should
|
|
303
|
+
// be retried on the next index run.
|
|
304
|
+
}
|
|
305
|
+
else if (res.splitParent) {
|
|
306
|
+
result.splitParents += 1;
|
|
307
|
+
result.writtenFacts += res.written;
|
|
308
|
+
}
|
|
309
|
+
else if ("childExists" in res && res.childExists) {
|
|
310
|
+
// Derived child already on disk. Track separately so this category is
|
|
311
|
+
// observable in health output and stops bleeding into the
|
|
312
|
+
// freshAttempts denominator. Pre-check skips (#588) are the routine
|
|
313
|
+
// self-healing path — no LLM attempt was consumed and the parent has
|
|
314
|
+
// been marked processed — so only the rare post-LLM case (mid-flight
|
|
315
|
+
// race or write failure) warrants a per-ref warning.
|
|
316
|
+
result.skippedChildExists += 1;
|
|
317
|
+
if (!res.precheck) {
|
|
318
|
+
warn(`memory inference: derived child for ${pending[i]?.ref ?? "<unknown>"} already existed or write failed; counted as skippedChildExists`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
// The per-record state machine should cover every outcome. A hit here
|
|
323
|
+
// means a new code path slipped past the categorisation — surface it
|
|
324
|
+
// loudly so health metrics stay honest and we get a signal to fix.
|
|
325
|
+
result.unaccounted += 1;
|
|
326
|
+
warn(`memory inference: unaccounted per-record outcome for ${pending[i]?.ref ?? "<unknown>"}`);
|
|
165
327
|
}
|
|
166
|
-
return undefined;
|
|
167
|
-
};
|
|
168
|
-
// Track whether THIS candidate's result came from the body-hash
|
|
169
|
-
// cache vs. a fresh LLM call. The cache short-circuits when the
|
|
170
|
-
// parent body has not changed since a prior derived write — surfacing
|
|
171
|
-
// the hit count separately so the operational yield rate
|
|
172
|
-
// (writtenFacts / freshAttempts) is interpretable as the cache warms.
|
|
173
|
-
let fromCache = false;
|
|
174
|
-
// Count single bounded retries for transient LLM failures on this
|
|
175
|
-
// candidate. Bumped via the `onRetryAttempt` callback threaded into
|
|
176
|
-
// `chatCompletion`; surfaced as `retryAttempts` telemetry, never as a
|
|
177
|
-
// failure for the same call.
|
|
178
|
-
let retryAttempts = 0;
|
|
179
|
-
const onRetryAttempt = () => {
|
|
180
|
-
retryAttempts += 1;
|
|
181
|
-
};
|
|
182
|
-
const derived = db
|
|
183
|
-
? await withLlmCache(db, record.filePath, record.body, reEnrich ?? false, () => compressMemoryToDerivedMemory(llmConfig, record.body, signal, featureConfig, (evt) => {
|
|
184
|
-
warn(`[akm] LLM fallback for ${evt.feature}: ${evt.reason}`);
|
|
185
|
-
}, inferTelemetry, onRetryAttempt), validate, undefined, "memory-inference-v2", {
|
|
186
|
-
onCacheHit: () => {
|
|
187
|
-
fromCache = true;
|
|
188
|
-
},
|
|
189
|
-
})
|
|
190
|
-
: await compressMemoryToDerivedMemory(llmConfig, record.body, signal, config, (evt) => {
|
|
191
|
-
warn(`[akm] LLM fallback for ${evt.feature}: ${evt.reason}`);
|
|
192
|
-
}, inferTelemetry, onRetryAttempt);
|
|
193
|
-
if (!derived) {
|
|
194
|
-
return { skipped: true, fromCache, retryAttempts };
|
|
195
|
-
}
|
|
196
|
-
const writeOutcome = await writeDerivedMemory(record, derived);
|
|
197
|
-
if (writeOutcome.written > 0) {
|
|
198
|
-
markParentProcessed(record);
|
|
199
|
-
return { skipped: false, splitParent: true, written: writeOutcome.written, fromCache, retryAttempts };
|
|
200
|
-
}
|
|
201
|
-
// LLM produced a valid derived draft but no file was written — either
|
|
202
|
-
// because `<parent>.derived.md` appeared on disk after the pre-check
|
|
203
|
-
// above (a rare mid-flight race) or `writeAssetToSource` threw.
|
|
204
|
-
// Categorise as `childExists` so the consumed attempt is accounted for
|
|
205
|
-
// in health metrics rather than vanishing into the freshAttempts
|
|
206
|
-
// denominator.
|
|
207
|
-
//
|
|
208
|
-
// When the child exists the inference is, by definition, complete — so
|
|
209
|
-
// mark the parent processed here too (#550), otherwise
|
|
210
|
-
// `isPendingMemory()` re-queues the same parent every run. A genuine
|
|
211
|
-
// write *failure* (`writeAssetToSource` threw) must NOT mark the parent
|
|
212
|
-
// — it should be retried next run — so we key off the explicit
|
|
213
|
-
// `childExists` outcome rather than the conflated `written === 0`.
|
|
214
|
-
if (writeOutcome.childExists) {
|
|
215
|
-
markParentProcessed(record);
|
|
216
|
-
}
|
|
217
|
-
return {
|
|
218
|
-
skipped: false,
|
|
219
|
-
splitParent: false,
|
|
220
|
-
written: 0,
|
|
221
|
-
fromCache,
|
|
222
|
-
retryAttempts,
|
|
223
|
-
childExists: true,
|
|
224
|
-
precheck: false,
|
|
225
|
-
};
|
|
226
|
-
},
|
|
227
|
-
// Caller-set connection concurrency or 1: `resolveLlmEngineUse` does
|
|
228
|
-
// not forward `engines.<name>.concurrency`, so config cannot raise this.
|
|
229
|
-
llmConfig.concurrency ?? 1);
|
|
230
|
-
for (let i = 0; i < perRecordResults.length; i++) {
|
|
231
|
-
const res = perRecordResults[i];
|
|
232
|
-
if (!res)
|
|
233
|
-
continue;
|
|
234
|
-
if ("aborted" in res && res.aborted) {
|
|
235
|
-
result.skippedAborted += 1;
|
|
236
328
|
processed++;
|
|
237
329
|
onProgress?.({
|
|
238
330
|
processed,
|
|
@@ -241,53 +333,14 @@ export async function runMemoryInferencePass(ctx) {
|
|
|
241
333
|
skippedNoFacts: result.skippedNoFacts,
|
|
242
334
|
currentRef: pending[i]?.ref,
|
|
243
335
|
});
|
|
244
|
-
continue;
|
|
245
|
-
}
|
|
246
|
-
if (res.fromCache) {
|
|
247
|
-
result.cacheHits += 1;
|
|
248
|
-
}
|
|
249
|
-
if ("retryAttempts" in res) {
|
|
250
|
-
result.retryAttempts += res.retryAttempts;
|
|
251
336
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
result.splitParents += 1;
|
|
259
|
-
result.writtenFacts += res.written;
|
|
260
|
-
}
|
|
261
|
-
else if ("childExists" in res && res.childExists) {
|
|
262
|
-
// Derived child already on disk. Track separately so this category is
|
|
263
|
-
// observable in health output and stops bleeding into the
|
|
264
|
-
// freshAttempts denominator. Pre-check skips (#588) are the routine
|
|
265
|
-
// self-healing path — no LLM attempt was consumed and the parent has
|
|
266
|
-
// been marked processed — so only the rare post-LLM case (mid-flight
|
|
267
|
-
// race or write failure) warrants a per-ref warning.
|
|
268
|
-
result.skippedChildExists += 1;
|
|
269
|
-
if (!res.precheck) {
|
|
270
|
-
warn(`memory inference: derived child for ${pending[i]?.ref ?? "<unknown>"} already existed or write failed; counted as skippedChildExists`);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
else {
|
|
274
|
-
// The per-record state machine should cover every outcome. A hit here
|
|
275
|
-
// means a new code path slipped past the categorisation — surface it
|
|
276
|
-
// loudly so health metrics stay honest and we get a signal to fix.
|
|
277
|
-
result.unaccounted += 1;
|
|
278
|
-
warn(`memory inference: unaccounted per-record outcome for ${pending[i]?.ref ?? "<unknown>"}`);
|
|
279
|
-
}
|
|
280
|
-
processed++;
|
|
281
|
-
onProgress?.({
|
|
282
|
-
processed,
|
|
283
|
-
total,
|
|
284
|
-
writtenFacts: result.writtenFacts,
|
|
285
|
-
skippedNoFacts: result.skippedNoFacts,
|
|
286
|
-
currentRef: pending[i]?.ref,
|
|
287
|
-
});
|
|
337
|
+
result.htmlErrorCount = inferTelemetry.htmlErrorCount ?? 0;
|
|
338
|
+
return completeResult();
|
|
339
|
+
}
|
|
340
|
+
finally {
|
|
341
|
+
if (dispatchLease)
|
|
342
|
+
disposeLoweredExecutionDispatchLease(dispatchLease);
|
|
288
343
|
}
|
|
289
|
-
result.htmlErrorCount = inferTelemetry.htmlErrorCount ?? 0;
|
|
290
|
-
return result;
|
|
291
344
|
}
|
|
292
345
|
// ── Pending detection ───────────────────────────────────────────────────────
|
|
293
346
|
/**
|