akm-cli 0.8.7 → 0.8.14
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 +428 -0
- package/dist/assets/help/help-proposals.md +1 -2
- package/dist/assets/hints/cli-hints-full.md +34 -19
- package/dist/assets/hints/cli-hints-short.md +1 -1
- package/dist/assets/profiles/catchup.json +13 -0
- package/dist/assets/profiles/consolidate.json +13 -0
- package/dist/assets/profiles/frequent.json +13 -0
- package/dist/assets/tasks/core/backup.yml +4 -0
- package/dist/assets/tasks/core/extract.yml +4 -0
- package/dist/assets/tasks/core/improve.yml +4 -0
- package/dist/assets/tasks/core/index-refresh.yml +4 -0
- package/dist/assets/tasks/core/sync.yml +4 -0
- package/dist/assets/tasks/core/update-stashes.yml +4 -0
- package/dist/assets/tasks/core/version-check.yml +4 -0
- package/dist/assets/templates/html/default.html +78 -0
- package/dist/assets/templates/html/health.html +560 -0
- package/dist/assets/templates/html/vendor/echarts.min.js +45 -0
- package/dist/cli/config-migrate.js +6 -6
- package/dist/cli/config-validate.js +4 -4
- package/dist/cli/confirm.js +3 -3
- package/dist/cli/parse-args.js +1 -1
- package/dist/cli/shared.js +72 -19
- package/dist/cli-node.mjs +26 -0
- package/dist/cli.js +206 -3866
- package/dist/commands/{agent-dispatch.js → agent/agent-dispatch.js} +6 -6
- package/dist/commands/{agent-support.js → agent/agent-support.js} +2 -2
- package/dist/commands/agent/contribute-cli.js +200 -0
- package/dist/commands/completions.js +1 -1
- package/dist/commands/config-cli.js +230 -3
- package/dist/commands/db-cli.js +2 -2
- package/dist/commands/env/env-cli.js +529 -0
- package/dist/commands/env/env.js +410 -0
- package/dist/commands/env/secret-cli.js +259 -0
- package/dist/commands/{secret.js → env/secret.js} +6 -47
- package/dist/commands/events.js +4 -4
- package/dist/commands/feedback-cli.js +18 -34
- package/dist/commands/graph/graph-cli.js +132 -0
- package/dist/commands/{graph.js → graph/graph.js} +22 -16
- package/dist/commands/health/checks.js +279 -0
- package/dist/commands/health/html-report.js +448 -0
- package/dist/commands/health.js +189 -266
- package/dist/commands/{consolidate.js → improve/consolidate.js} +48 -36
- package/dist/commands/{distill-promotion-policy.js → improve/distill-promotion-policy.js} +3 -3
- package/dist/commands/{distill.js → improve/distill.js} +39 -18
- package/dist/commands/{eval-cases.js → improve/eval-cases.js} +1 -1
- package/dist/commands/{extract-cli.js → improve/extract-cli.js} +4 -4
- package/dist/commands/{extract-prompt.js → improve/extract-prompt.js} +2 -2
- package/dist/commands/{extract.js → improve/extract.js} +221 -26
- package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +30 -4
- package/dist/commands/{improve-cli.js → improve/improve-cli.js} +44 -22
- package/dist/commands/{improve-profiles.js → improve/improve-profiles.js} +13 -7
- package/dist/commands/{improve-result-file.js → improve/improve-result-file.js} +1 -1
- package/dist/commands/{improve.js → improve/improve.js} +672 -292
- package/dist/{core → commands/improve/memory}/memory-belief.js +2 -2
- package/dist/{core → commands/improve/memory}/memory-contradiction-detect.js +5 -5
- package/dist/{core → commands/improve/memory}/memory-improve.js +4 -4
- package/dist/commands/improve/reflect-noise.js +0 -0
- package/dist/commands/{reflect.js → improve/reflect.js} +58 -28
- package/dist/commands/improve/session-asset.js +248 -0
- package/dist/commands/lint/agent-linter.js +1 -1
- package/dist/commands/lint/base-linter.js +55 -37
- package/dist/commands/lint/command-linter.js +1 -1
- package/dist/commands/lint/default-linter.js +1 -1
- package/dist/commands/lint/env-key-rules.js +1 -1
- package/dist/commands/lint/index.js +19 -25
- package/dist/commands/lint/knowledge-linter.js +1 -1
- package/dist/commands/lint/memory-linter.js +1 -1
- package/dist/commands/lint/registry.js +8 -8
- package/dist/commands/lint/skill-linter.js +1 -1
- package/dist/commands/lint/task-linter.js +1 -1
- package/dist/commands/lint/workflow-linter.js +1 -1
- package/dist/commands/lint.js +1 -1
- package/dist/commands/observability-cli.js +244 -0
- package/dist/commands/proposal/drain-policies.js +3 -3
- package/dist/commands/proposal/drain.js +87 -15
- package/dist/commands/proposal/proposal-cli.js +490 -0
- package/dist/commands/{proposal.js → proposal/proposal.js} +17 -6
- package/dist/commands/{propose.js → proposal/propose.js} +11 -11
- package/dist/{core → commands/proposal/validators}/proposal-quality-validators.js +8 -3
- package/dist/{core → commands/proposal/validators}/proposal-validators.js +5 -5
- package/dist/{core → commands/proposal/validators}/proposals.js +374 -345
- package/dist/commands/{curate.js → read/curate.js} +7 -7
- package/dist/commands/{knowledge.js → read/knowledge.js} +22 -9
- package/dist/commands/{registry-search.js → read/registry-search.js} +5 -5
- package/dist/commands/{remember-cli.js → read/remember-cli.js} +15 -7
- package/dist/commands/read/search-cli.js +207 -0
- package/dist/commands/{search.js → read/search.js} +22 -27
- package/dist/commands/{show.js → read/show.js} +31 -45
- package/dist/commands/registry-cli.js +8 -8
- package/dist/commands/remember.js +14 -10
- package/dist/commands/sources/add-cli.js +293 -0
- package/dist/commands/{history.js → sources/history.js} +27 -25
- package/dist/commands/{info.js → sources/info.js} +6 -6
- package/dist/commands/{init.js → sources/init.js} +6 -6
- package/dist/commands/{installed-stashes.js → sources/installed-stashes.js} +12 -12
- package/dist/commands/{migration-help.js → sources/migration-help.js} +3 -2
- package/dist/commands/{schema-repair.js → sources/schema-repair.js} +8 -8
- package/dist/commands/{self-update.js → sources/self-update.js} +10 -9
- package/dist/commands/{source-add.js → sources/source-add.js} +10 -10
- package/dist/commands/{source-clone.js → sources/source-clone.js} +7 -7
- package/dist/commands/{source-manage.js → sources/source-manage.js} +4 -4
- package/dist/commands/sources/sources-cli.js +305 -0
- package/dist/commands/sources/stash-cli.js +219 -0
- package/dist/commands/{stash-skeleton.js → sources/stash-skeleton.js} +2 -1
- package/dist/commands/tasks/default-tasks.js +173 -0
- package/dist/commands/tasks/tasks-cli.js +210 -0
- package/dist/commands/{tasks.js → tasks/tasks.js} +14 -14
- package/dist/commands/wiki-cli.js +307 -0
- package/dist/commands/workflow-cli.js +329 -0
- package/dist/core/action-contributors.js +1 -1
- package/dist/core/assert.js +40 -0
- package/dist/core/asset/asset-create.js +54 -0
- package/dist/core/{asset-ref.js → asset/asset-ref.js} +21 -4
- package/dist/core/{asset-registry.js → asset/asset-registry.js} +3 -3
- package/dist/core/{asset-spec.js → asset/asset-spec.js} +17 -31
- package/dist/core/{markdown.js → asset/markdown.js} +1 -1
- package/dist/core/{stash-meta.js → asset/stash-meta.js} +1 -1
- package/dist/core/best-effort.js +64 -0
- package/dist/core/common.js +32 -18
- package/dist/core/{config-io.js → config/config-io.js} +29 -19
- package/dist/core/{config-migration.js → config/config-migration.js} +11 -9
- package/dist/core/{config-schema.js → config/config-schema.js} +50 -7
- package/dist/core/config/config-types.js +16 -0
- package/dist/core/{config-walker.js → config/config-walker.js} +2 -2
- package/dist/core/{config.js → config/config.js} +10 -8
- package/dist/core/env-secret-ref.js +90 -0
- package/dist/core/errors.js +13 -3
- package/dist/core/events.js +27 -4
- package/dist/core/file-lock.js +1 -1
- package/dist/core/improve-types.js +48 -0
- package/dist/core/lesson-lint.js +2 -2
- package/dist/core/logs-db.js +304 -0
- package/dist/core/paths.js +2 -2
- package/dist/core/ripgrep/install.js +2 -2
- package/dist/core/ripgrep/resolve.js +2 -2
- package/dist/core/state-db.js +195 -60
- package/dist/core/text-truncation.js +148 -0
- package/dist/core/time.js +1 -1
- package/dist/core/write-source.js +98 -85
- package/dist/indexer/{db-backup.js → db/db-backup.js} +9 -24
- package/dist/indexer/{db.js → db/db.js} +128 -118
- package/dist/indexer/{graph-db.js → db/graph-db.js} +9 -4
- package/dist/indexer/{llm-cache.js → db/llm-cache.js} +15 -12
- package/dist/indexer/ensure-index.js +4 -4
- package/dist/indexer/{graph-boost.js → graph/graph-boost.js} +1 -1
- package/dist/indexer/{graph-extraction.js → graph/graph-extraction.js} +55 -13
- package/dist/indexer/indexer.js +37 -30
- package/dist/indexer/init.js +54 -0
- package/dist/indexer/manifest.js +10 -10
- package/dist/indexer/{memory-inference.js → passes/memory-inference.js} +141 -33
- package/dist/indexer/{metadata-contributors.js → passes/metadata-contributors.js} +10 -8
- package/dist/indexer/{metadata.js → passes/metadata.js} +15 -19
- package/dist/indexer/{staleness-detect.js → passes/staleness-detect.js} +53 -12
- package/dist/indexer/{db-search.js → search/db-search.js} +28 -16
- package/dist/indexer/{ranking-contributors.js → search/ranking-contributors.js} +1 -1
- package/dist/indexer/{ranking.js → search/ranking.js} +2 -2
- package/dist/indexer/{search-hit-enrichers.js → search/search-hit-enrichers.js} +3 -3
- package/dist/indexer/{search-source.js → search/search-source.js} +8 -8
- package/dist/indexer/{semantic-status.js → search/semantic-status.js} +3 -3
- package/dist/indexer/usage/unmigrated-vaults-guard.js +94 -0
- package/dist/indexer/{usage-events.js → usage/usage-events.js} +32 -0
- package/dist/indexer/{file-context.js → walk/file-context.js} +10 -15
- package/dist/indexer/{matchers.js → walk/matchers.js} +13 -9
- package/dist/indexer/{path-resolver.js → walk/path-resolver.js} +6 -6
- package/dist/indexer/{project-context.js → walk/project-context.js} +1 -1
- package/dist/indexer/{walker.js → walk/walker.js} +4 -3
- package/dist/integrations/agent/builder-shared.js +39 -0
- package/dist/integrations/agent/builders.js +14 -81
- package/dist/integrations/agent/config.js +6 -4
- package/dist/integrations/agent/detect.js +1 -1
- package/dist/integrations/agent/index.js +23 -8
- package/dist/integrations/agent/prompts.js +2 -3
- package/dist/integrations/agent/runner.js +22 -3
- package/dist/integrations/agent/spawn.js +9 -10
- package/dist/integrations/harnesses/claude/agent-builder.js +48 -0
- package/dist/integrations/harnesses/claude/config-import.js +70 -0
- package/dist/integrations/harnesses/claude/index.js +64 -0
- package/dist/integrations/{session-logs/providers/claude-code.js → harnesses/claude/session-log.js} +32 -5
- package/dist/integrations/harnesses/index.js +144 -0
- package/dist/integrations/harnesses/opencode/agent-builder.js +43 -0
- package/dist/integrations/harnesses/opencode/config-import.js +82 -0
- package/dist/integrations/harnesses/opencode/index.js +59 -0
- package/dist/integrations/{session-logs/providers/opencode.js → harnesses/opencode/session-log.js} +1 -1
- package/dist/integrations/harnesses/opencode-sdk/index.js +49 -0
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +234 -0
- package/dist/integrations/harnesses/types.js +43 -0
- package/dist/integrations/lockfile.js +7 -16
- package/dist/integrations/session-logs/index.js +82 -9
- package/dist/llm/call-ai.js +4 -4
- package/dist/llm/client.js +146 -6
- package/dist/llm/embedder.js +6 -6
- package/dist/llm/embedders/local.js +9 -22
- package/dist/llm/embedders/remote.js +2 -2
- package/dist/llm/embedders/types.js +1 -1
- package/dist/llm/graph-extract.js +31 -12
- package/dist/llm/index-passes.js +1 -1
- package/dist/llm/memory-infer.js +12 -5
- package/dist/llm/metadata-enhance.js +2 -2
- package/dist/llm/usage-persist.js +77 -0
- package/dist/llm/usage-telemetry.js +103 -0
- package/dist/output/context.js +9 -46
- package/dist/output/html-render.js +73 -0
- package/dist/output/renderers.js +88 -58
- package/dist/output/shapes/curate.js +7 -3
- package/dist/output/shapes/distill.js +7 -3
- package/dist/output/shapes/env-list.js +18 -16
- package/dist/output/shapes/events.js +5 -4
- package/dist/output/shapes/helpers.js +19 -5
- package/dist/output/shapes/history.js +7 -3
- package/dist/output/shapes/passthrough.js +8 -11
- package/dist/output/shapes/{proposal-accept.js → proposal/accept.js} +7 -3
- package/dist/output/shapes/{proposal-diff.js → proposal/diff.js} +7 -3
- package/dist/output/shapes/{proposal-list.js → proposal/list.js} +7 -3
- package/dist/output/shapes/{proposal-producer.js → proposal/producer.js} +5 -4
- package/dist/output/shapes/{proposal-reject.js → proposal/reject.js} +7 -3
- package/dist/output/shapes/{proposal-show.js → proposal/show.js} +7 -3
- package/dist/output/shapes/registry-search.js +7 -3
- package/dist/output/shapes/registry.js +12 -0
- package/dist/output/shapes/search.js +7 -3
- package/dist/output/shapes/secret-list.js +18 -16
- package/dist/output/shapes/show.js +7 -3
- package/dist/output/shapes.js +55 -30
- package/dist/output/text/add.js +2 -3
- package/dist/output/text/clone.js +2 -3
- package/dist/output/text/config.js +2 -3
- package/dist/output/text/curate.js +4 -3
- package/dist/output/text/distill.js +2 -3
- package/dist/output/text/enable-disable.js +5 -4
- package/dist/output/text/env.js +13 -0
- package/dist/output/text/events.js +5 -4
- package/dist/output/text/feedback.js +4 -3
- package/dist/output/text/helpers.js +123 -40
- package/dist/output/text/history.js +2 -3
- package/dist/output/text/import.js +2 -3
- package/dist/output/text/index.js +2 -3
- package/dist/output/text/info.js +2 -3
- package/dist/output/text/init.js +2 -3
- package/dist/output/text/list.js +2 -3
- package/dist/output/text/proposal/producer.js +9 -0
- package/dist/output/text/proposal/proposal.js +13 -0
- package/dist/output/text/registry-commands.js +8 -7
- package/dist/output/text/registry.js +12 -0
- package/dist/output/text/remember.js +4 -3
- package/dist/output/text/remove.js +2 -3
- package/dist/output/text/save.js +2 -3
- package/dist/output/text/search.js +4 -3
- package/dist/output/text/show.js +4 -3
- package/dist/output/text/update.js +2 -3
- package/dist/output/text/upgrade.js +2 -3
- package/dist/output/text/wiki.js +12 -11
- package/dist/output/text/workflow.js +12 -10
- package/dist/output/text.js +66 -32
- package/dist/registry/build-index.js +11 -10
- package/dist/registry/factory.js +1 -1
- package/dist/registry/origin-resolve.js +1 -1
- package/dist/registry/providers/index.js +2 -2
- package/dist/registry/providers/skills-sh.js +91 -72
- package/dist/registry/providers/static-index.js +75 -52
- package/dist/registry/resolve.js +3 -3
- package/dist/runtime.js +242 -0
- package/dist/scripts/migrate-storage.js +1654 -683
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +254 -168
- package/dist/setup/detect.js +311 -9
- package/dist/setup/harness-config-import.js +6 -120
- package/dist/setup/setup.js +454 -43
- package/dist/sources/include.js +1 -1
- package/dist/sources/provider-factory.js +2 -2
- package/dist/sources/providers/filesystem.js +3 -3
- package/dist/sources/providers/git.js +9 -9
- package/dist/sources/providers/index.js +4 -4
- package/dist/sources/providers/npm.js +6 -6
- package/dist/sources/providers/provider-utils.js +13 -20
- package/dist/sources/providers/sync-from-ref.js +5 -5
- package/dist/sources/providers/tar-utils.js +2 -2
- package/dist/sources/providers/website.js +2 -2
- package/dist/sources/resolve.js +5 -5
- package/dist/sources/website-ingest.js +5 -5
- package/dist/storage/database.js +102 -0
- package/dist/storage/engines/sqlite-migrations.js +42 -0
- package/dist/storage/locations.js +25 -0
- package/dist/storage/repositories/index-db.js +43 -0
- package/dist/storage/repositories/workflow-runs-repository.js +141 -0
- package/dist/tasks/backends/cron.js +4 -4
- package/dist/tasks/backends/exec-utils.js +32 -0
- package/dist/tasks/backends/index.js +3 -3
- package/dist/tasks/backends/launchd.js +7 -14
- package/dist/tasks/backends/schtasks.js +7 -16
- package/dist/tasks/embedded.js +71 -0
- package/dist/tasks/parser.js +2 -2
- package/dist/tasks/resolveAkmBin.js +1 -1
- package/dist/tasks/runner.js +127 -31
- package/dist/tasks/schedule.js +1 -1
- package/dist/tasks/validator.js +7 -7
- package/dist/text-import-hook.mjs +51 -0
- package/dist/version.js +2 -1
- package/dist/wiki/wiki.js +7 -7
- package/dist/workflows/{authoring.js → authoring/authoring.js} +6 -6
- package/dist/workflows/{scope-key.js → authoring/scope-key.js} +1 -1
- package/dist/workflows/cli.js +1 -1
- package/dist/workflows/db.js +54 -32
- package/dist/workflows/parser.js +4 -4
- package/dist/workflows/renderer.js +5 -5
- package/dist/workflows/runtime/agent-identity.js +56 -0
- package/dist/workflows/runtime/checkin.js +57 -0
- package/dist/workflows/{runs.js → runtime/runs.js} +197 -101
- package/dist/workflows/validate-summary.js +82 -0
- package/docs/README.md +1 -1
- package/docs/data-and-telemetry.md +6 -6
- package/package.json +17 -8
- package/dist/commands/add-cli.js +0 -279
- package/dist/commands/env.js +0 -213
- package/dist/integrations/agent/sdk-runner.js +0 -126
- package/dist/output/shapes/vault-list.js +0 -19
- package/dist/output/text/proposal-producer.js +0 -8
- package/dist/output/text/proposal.js +0 -12
- package/dist/output/text/vault.js +0 -16
- /package/dist/core/{asset-serialize.js → asset/asset-serialize.js} +0 -0
- /package/dist/core/{frontmatter.js → asset/frontmatter.js} +0 -0
- /package/dist/core/{config-sources.js → config/config-sources.js} +0 -0
- /package/dist/indexer/{graph-dedup.js → graph/graph-dedup.js} +0 -0
- /package/dist/{core/config-types.js → indexer/passes/pass-context.js} +0 -0
- /package/dist/indexer/{search-fields.js → search/search-fields.js} +0 -0
- /package/dist/indexer/{index-context.js → walk/index-context.js} +0 -0
- /package/dist/workflows/{document-cache.js → runtime/document-cache.js} +0 -0
package/dist/indexer/indexer.js
CHANGED
|
@@ -3,20 +3,20 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import { SCRIPT_EXTENSIONS } from "../core/asset-spec";
|
|
7
|
-
import { isHttpUrl, resolveStashDir, toErrorMessage } from "../core/common";
|
|
8
|
-
import { concurrentMap } from "../core/concurrent";
|
|
9
|
-
import { getDbPath } from "../core/paths";
|
|
10
|
-
import { isVerbose, warn, warnVerbose } from "../core/warn";
|
|
11
|
-
import { resolveIndexPassLLM } from "../llm/index-passes";
|
|
12
|
-
import { takeWorkflowDocument } from "../workflows/document-cache";
|
|
13
|
-
import { clearStaleCacheEntries, closeDatabase, deleteEntriesByDir, deleteEntriesByIds, deleteEntriesByStashDir, deleteIndexDirStatesByStashDir, getAllEntriesForEmbedding, getEmbeddingCount, getEntriesByDir, getEntryCount, getIndexDirState, getMeta, isVecAvailable, openDatabase, openExistingDatabase, rebuildFts, relinkUsageEvents, setMeta, upsertEmbedding, upsertEntry, upsertIndexDirState, upsertUtilityScore, upsertWorkflowDocument, warnIfVecMissing, } from "./db";
|
|
14
|
-
import { deleteStoredGraph } from "./graph-db";
|
|
15
|
-
import { applyCuratedFrontmatter, applyWikiFrontmatter, generateMetadataFlat, isEnrichmentComplete, isWorkflowSkipWarning, loadStashFile, shouldIndexStashFile, } from "./metadata";
|
|
16
|
-
import { buildSearchText } from "./search-fields";
|
|
17
|
-
import { classifySemanticFailure, clearSemanticStatus, deriveSemanticProviderFingerprint, writeSemanticStatus, } from "./semantic-status";
|
|
18
|
-
import { ensureUsageEventsSchema, purgeOldUsageEvents } from "./usage-events";
|
|
19
|
-
import { walkStashFlat } from "./walker";
|
|
6
|
+
import { SCRIPT_EXTENSIONS } from "../core/asset/asset-spec.js";
|
|
7
|
+
import { isHttpUrl, resolveStashDir, toErrorMessage } from "../core/common.js";
|
|
8
|
+
import { concurrentMap } from "../core/concurrent.js";
|
|
9
|
+
import { getDbPath } from "../core/paths.js";
|
|
10
|
+
import { isVerbose, warn, warnVerbose } from "../core/warn.js";
|
|
11
|
+
import { resolveIndexPassLLM } from "../llm/index-passes.js";
|
|
12
|
+
import { takeWorkflowDocument } from "../workflows/runtime/document-cache.js";
|
|
13
|
+
import { clearStaleCacheEntries, closeDatabase, deleteEntriesByDir, deleteEntriesByIds, deleteEntriesByStashDir, deleteIndexDirStatesByStashDir, getAllEntriesForEmbedding, getEmbeddableEntryCount, getEmbeddingCount, getEntriesByDir, getEntryCount, getIndexDirState, getMeta, isVecAvailable, openDatabase, openExistingDatabase, rebuildFts, relinkUsageEvents, setMeta, upsertEmbedding, upsertEntry, upsertIndexDirState, upsertUtilityScore, upsertWorkflowDocument, warnIfVecMissing, } from "./db/db.js";
|
|
14
|
+
import { deleteStoredGraph } from "./db/graph-db.js";
|
|
15
|
+
import { applyCuratedFrontmatter, applyWikiFrontmatter, generateMetadataFlat, isEnrichmentComplete, isWorkflowSkipWarning, loadStashFile, shouldIndexStashFile, } from "./passes/metadata.js";
|
|
16
|
+
import { buildSearchText } from "./search/search-fields.js";
|
|
17
|
+
import { classifySemanticFailure, clearSemanticStatus, deriveSemanticProviderFingerprint, writeSemanticStatus, } from "./search/semantic-status.js";
|
|
18
|
+
import { ensureUsageEventsSchema, purgeOldUsageEvents } from "./usage/usage-events.js";
|
|
19
|
+
import { walkStashFlat } from "./walk/walker.js";
|
|
20
20
|
function throwIfAborted(signal) {
|
|
21
21
|
if (signal?.aborted) {
|
|
22
22
|
throw signal.reason instanceof Error ? signal.reason : new Error("index interrupted");
|
|
@@ -177,7 +177,8 @@ async function runFinalizePhase(ctx) {
|
|
|
177
177
|
setMeta(db, "hasEmbeddings", embeddingResult.success ? "1" : "0");
|
|
178
178
|
warnIfVecMissing(db);
|
|
179
179
|
const totalEntries = getEntryCount(db);
|
|
180
|
-
const
|
|
180
|
+
const semanticEntryCount = getEmbeddableEntryCount(db);
|
|
181
|
+
const verification = verifyIndexState(db, config, semanticEntryCount, embeddingResult);
|
|
181
182
|
if (config.semanticSearchMode === "off") {
|
|
182
183
|
clearSemanticStatus();
|
|
183
184
|
}
|
|
@@ -232,11 +233,17 @@ export async function akmIndex(options) {
|
|
|
232
233
|
const clean = options?.clean === true;
|
|
233
234
|
const dryRun = options?.dryRun === true;
|
|
234
235
|
// Load config and resolve all stash sources
|
|
235
|
-
const { loadConfig } = await import("../core/config.js");
|
|
236
|
+
const { loadConfig } = await import("../core/config/config.js");
|
|
236
237
|
const config = loadConfig();
|
|
238
|
+
// One-time, read-only guard: warn if the writable stash still holds an
|
|
239
|
+
// un-migrated `vaults/` directory. In 0.9.0 the indexer skips `vaults/`
|
|
240
|
+
// entirely, so an unmigrated vault's `.env` data would silently never be
|
|
241
|
+
// indexed. Non-destructive — only stats, never reads/writes/deletes.
|
|
242
|
+
const { warnOnUnmigratedVaults } = await import("./usage/unmigrated-vaults-guard.js");
|
|
243
|
+
warnOnUnmigratedVaults(stashDir);
|
|
237
244
|
// Ensure git stash caches are extracted before resolving stash dirs,
|
|
238
245
|
// so their content directories exist on disk for the walker to discover.
|
|
239
|
-
const { ensureSourceCaches, resolveSourceEntries } = await import("./search-source.js");
|
|
246
|
+
const { ensureSourceCaches, resolveSourceEntries } = await import("./search/search-source.js");
|
|
240
247
|
await ensureSourceCaches(config, { force: full });
|
|
241
248
|
const allSourceEntries = resolveSourceEntries(stashDir, config);
|
|
242
249
|
const allSourceDirs = allSourceEntries.map((s) => s.path);
|
|
@@ -995,11 +1002,11 @@ function getSemanticSearchLabel(semanticSearchMode, embeddingProvider, vecAvaila
|
|
|
995
1002
|
return "disabled";
|
|
996
1003
|
return `${embeddingProvider} embeddings, ${vecAvailable ? "sqlite-vec" : "JS fallback"}`;
|
|
997
1004
|
}
|
|
998
|
-
function verifyIndexState(db, config,
|
|
1005
|
+
function verifyIndexState(db, config, embeddableEntries, embeddingResult) {
|
|
999
1006
|
const embeddingCount = getEmbeddingCount(db);
|
|
1000
1007
|
const vecAvailable = isVecAvailable(db);
|
|
1001
1008
|
const embeddingProvider = getEmbeddingProvider(config.embedding);
|
|
1002
|
-
if (
|
|
1009
|
+
if (embeddableEntries === 0) {
|
|
1003
1010
|
return {
|
|
1004
1011
|
ok: true,
|
|
1005
1012
|
message: "Index ready. No assets were found yet.",
|
|
@@ -1007,7 +1014,7 @@ function verifyIndexState(db, config, totalEntries, embeddingResult) {
|
|
|
1007
1014
|
semanticSearchMode: config.semanticSearchMode,
|
|
1008
1015
|
semanticStatus: config.semanticSearchMode === "off" ? "disabled" : "pending",
|
|
1009
1016
|
embeddingProvider,
|
|
1010
|
-
entryCount:
|
|
1017
|
+
entryCount: embeddableEntries,
|
|
1011
1018
|
embeddingCount,
|
|
1012
1019
|
vecAvailable,
|
|
1013
1020
|
};
|
|
@@ -1020,20 +1027,20 @@ function verifyIndexState(db, config, totalEntries, embeddingResult) {
|
|
|
1020
1027
|
semanticSearchMode: config.semanticSearchMode,
|
|
1021
1028
|
semanticStatus: "disabled",
|
|
1022
1029
|
embeddingProvider,
|
|
1023
|
-
entryCount:
|
|
1030
|
+
entryCount: embeddableEntries,
|
|
1024
1031
|
embeddingCount,
|
|
1025
1032
|
vecAvailable,
|
|
1026
1033
|
};
|
|
1027
1034
|
}
|
|
1028
|
-
if (embeddingCount >=
|
|
1035
|
+
if (embeddingCount >= embeddableEntries) {
|
|
1029
1036
|
return {
|
|
1030
1037
|
ok: true,
|
|
1031
|
-
message: `Semantic search ready (${embeddingCount}/${
|
|
1038
|
+
message: `Semantic search ready (${embeddingCount}/${embeddableEntries} embeddings, ${vecAvailable ? "sqlite-vec active" : "JS fallback active"}).`,
|
|
1032
1039
|
semanticSearchEnabled: true,
|
|
1033
1040
|
semanticSearchMode: config.semanticSearchMode,
|
|
1034
1041
|
semanticStatus: vecAvailable ? "ready-vec" : "ready-js",
|
|
1035
1042
|
embeddingProvider,
|
|
1036
|
-
entryCount:
|
|
1043
|
+
entryCount: embeddableEntries,
|
|
1037
1044
|
embeddingCount,
|
|
1038
1045
|
vecAvailable,
|
|
1039
1046
|
};
|
|
@@ -1041,7 +1048,7 @@ function verifyIndexState(db, config, totalEntries, embeddingResult) {
|
|
|
1041
1048
|
return {
|
|
1042
1049
|
ok: false,
|
|
1043
1050
|
message: embeddingResult.message ??
|
|
1044
|
-
`Semantic search verification failed (${embeddingCount}/${
|
|
1051
|
+
`Semantic search verification failed (${embeddingCount}/${embeddableEntries} embeddings available).`,
|
|
1045
1052
|
guidance: embeddingProvider === "remote"
|
|
1046
1053
|
? "Check your embedding endpoint and credentials, then retry `akm index --full --verbose`."
|
|
1047
1054
|
: "Retry `akm index --full --verbose`. If it still fails, confirm local model downloads are permitted and see docs/configuration.md for local embedding dependency setup.",
|
|
@@ -1049,7 +1056,7 @@ function verifyIndexState(db, config, totalEntries, embeddingResult) {
|
|
|
1049
1056
|
semanticSearchMode: config.semanticSearchMode,
|
|
1050
1057
|
semanticStatus: "blocked",
|
|
1051
1058
|
embeddingProvider,
|
|
1052
|
-
entryCount:
|
|
1059
|
+
entryCount: embeddableEntries,
|
|
1053
1060
|
embeddingCount,
|
|
1054
1061
|
vecAvailable,
|
|
1055
1062
|
};
|
|
@@ -1075,8 +1082,8 @@ function resolveIndexedFiles(dirPath, files, stash) {
|
|
|
1075
1082
|
return resolved.size > 0 ? [...resolved] : files;
|
|
1076
1083
|
}
|
|
1077
1084
|
async function enhanceStashWithLlm(llmConfig, stash, files, summary, signal, db, entryKeys, reEnrich, akmConfig, onEntryDone) {
|
|
1078
|
-
const { enhanceMetadata } = await import("../llm/metadata-enhance");
|
|
1079
|
-
const { computeBodyHash, getLlmCacheEntry, upsertLlmCacheEntry } = await import("./db.js");
|
|
1085
|
+
const { enhanceMetadata } = await import("../llm/metadata-enhance.js");
|
|
1086
|
+
const { computeBodyHash, getLlmCacheEntry, upsertLlmCacheEntry } = await import("./db/db.js");
|
|
1080
1087
|
const results = await concurrentMap(stash.entries, async (entry, idx) => {
|
|
1081
1088
|
if (signal?.aborted)
|
|
1082
1089
|
return entry;
|
|
@@ -1233,8 +1240,8 @@ function mergeLegacyEntry(entry, legacyEntries) {
|
|
|
1233
1240
|
* `NotFoundError` with their own messaging.
|
|
1234
1241
|
*/
|
|
1235
1242
|
export async function lookup(ref) {
|
|
1236
|
-
const { loadConfig } = await import("../core/config.js");
|
|
1237
|
-
const { resolveSourceEntries } = await import("./search-source.js");
|
|
1243
|
+
const { loadConfig } = await import("../core/config/config.js");
|
|
1244
|
+
const { resolveSourceEntries } = await import("./search/search-source.js");
|
|
1238
1245
|
const config = loadConfig();
|
|
1239
1246
|
const sources = resolveSourceEntries(undefined, config);
|
|
1240
1247
|
if (sources.length === 0)
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
* Explicit composition root for the indexer's built-in registrations.
|
|
6
|
+
*
|
|
7
|
+
* Historically two independent lazy gates (`ensureBuiltinsRegistered` in
|
|
8
|
+
* `walk/file-context.ts` and `ensureBuiltinMetadataContributorsRegistered` in
|
|
9
|
+
* `passes/metadata-contributors.ts`) each registered a different built-in set
|
|
10
|
+
* on first use. That implicit, order-dependent wiring is the M1/M2 finding in
|
|
11
|
+
* `docs/technical/code-health-brittleness-audit.md`.
|
|
12
|
+
*
|
|
13
|
+
* `initIndexer()` folds both into a single deterministic, idempotent entry
|
|
14
|
+
* point. It registers, exactly once:
|
|
15
|
+
*
|
|
16
|
+
* 1. Built-in matchers — `registerBuiltinMatchers()` (`walk/matchers.ts`).
|
|
17
|
+
* 2. Built-in renderers — `registerBuiltinRenderers()` (`output/renderers.ts`).
|
|
18
|
+
* 3. Metadata contributors — top-level registration side-effects that run when
|
|
19
|
+
* `output/renderers.ts` and `workflows/renderer.ts` are imported.
|
|
20
|
+
*
|
|
21
|
+
* Importing `output/renderers.ts` satisfies both (2) and the renderer-owned
|
|
22
|
+
* metadata contributors; `workflows/renderer.ts` is imported explicitly for the
|
|
23
|
+
* workflow contributor (it is already transitively pulled in by renderers, but
|
|
24
|
+
* the explicit import preserves the original gate's import set and keeps the
|
|
25
|
+
* wiring self-documenting).
|
|
26
|
+
*
|
|
27
|
+
* Timing is preserved: this stays a *lazy* gate. It is awaited from the same
|
|
28
|
+
* accessor call sites the old gates were awaited from, so no startup work is
|
|
29
|
+
* forced eagerly. The shared promise makes concurrent and repeat calls safe —
|
|
30
|
+
* the registrations run at most once per process.
|
|
31
|
+
*/
|
|
32
|
+
let initPromise;
|
|
33
|
+
/**
|
|
34
|
+
* Idempotently register every built-in indexer contributor (matchers,
|
|
35
|
+
* renderers, and metadata contributors).
|
|
36
|
+
*
|
|
37
|
+
* Safe to call repeatedly and concurrently: the registration work runs at most
|
|
38
|
+
* once; subsequent calls await the same resolved promise.
|
|
39
|
+
*/
|
|
40
|
+
export function initIndexer() {
|
|
41
|
+
if (!initPromise) {
|
|
42
|
+
initPromise = (async () => {
|
|
43
|
+
const { registerBuiltinMatchers } = await import("./walk/matchers.js");
|
|
44
|
+
// Importing renderers registers the built-in metadata contributors as a
|
|
45
|
+
// load-time side-effect and exposes registerBuiltinRenderers().
|
|
46
|
+
const { registerBuiltinRenderers } = await import("../output/renderers.js");
|
|
47
|
+
// Imported for the workflow metadata contributor's load-time side-effect.
|
|
48
|
+
await import("../workflows/renderer.js");
|
|
49
|
+
registerBuiltinMatchers();
|
|
50
|
+
registerBuiltinRenderers();
|
|
51
|
+
})();
|
|
52
|
+
}
|
|
53
|
+
return initPromise;
|
|
54
|
+
}
|
package/dist/indexer/manifest.js
CHANGED
|
@@ -11,16 +11,16 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import fs from "node:fs";
|
|
13
13
|
import path from "node:path";
|
|
14
|
-
import { makeAssetRef } from "../core/asset-ref";
|
|
15
|
-
import { deriveCanonicalAssetNameFromStashRoot } from "../core/asset-spec";
|
|
16
|
-
import { resolveStashDir } from "../core/common";
|
|
17
|
-
import { loadConfig } from "../core/config";
|
|
18
|
-
import { getDbPath } from "../core/paths";
|
|
19
|
-
import { warn } from "../core/warn";
|
|
20
|
-
import { closeDatabase, getAllEntries, getEntryCount, getMeta, openExistingDatabase } from "./db";
|
|
21
|
-
import { generateMetadataFlat, loadStashFile } from "./metadata";
|
|
22
|
-
import { resolveSourceEntries } from "./search-source";
|
|
23
|
-
import { walkStashFlat } from "./walker";
|
|
14
|
+
import { makeAssetRef } from "../core/asset/asset-ref.js";
|
|
15
|
+
import { deriveCanonicalAssetNameFromStashRoot } from "../core/asset/asset-spec.js";
|
|
16
|
+
import { resolveStashDir } from "../core/common.js";
|
|
17
|
+
import { loadConfig } from "../core/config/config.js";
|
|
18
|
+
import { getDbPath } from "../core/paths.js";
|
|
19
|
+
import { warn } from "../core/warn.js";
|
|
20
|
+
import { closeDatabase, getAllEntries, getEntryCount, getMeta, openExistingDatabase } from "./db/db.js";
|
|
21
|
+
import { generateMetadataFlat, loadStashFile } from "./passes/metadata.js";
|
|
22
|
+
import { resolveSourceEntries } from "./search/search-source.js";
|
|
23
|
+
import { walkStashFlat } from "./walk/walker.js";
|
|
24
24
|
const MAX_DESCRIPTION_LENGTH = 80;
|
|
25
25
|
/**
|
|
26
26
|
* Truncate a description string to a maximum length, appending "..." if truncated.
|
|
@@ -1,19 +1,52 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
/**
|
|
5
|
+
* Memory inference pass for `akm index` (#201).
|
|
6
|
+
*
|
|
7
|
+
* Detects memories pending inference, asks the configured LLM to compress each
|
|
8
|
+
* into one higher-signal derived memory, and writes the result back as a new
|
|
9
|
+
* memory file with frontmatter `inferred: true` + a `source:` backref to the
|
|
10
|
+
* parent memory.
|
|
11
|
+
*
|
|
12
|
+
* Pending predicate (see {@link isPendingMemory}):
|
|
13
|
+
* - File lives under `<stashRoot>/memories/` and ends in `.md`.
|
|
14
|
+
* - Frontmatter does NOT have `inferenceProcessed: true` (parent already split).
|
|
15
|
+
* - Frontmatter does NOT have `inferred: true` (this is itself a child fact).
|
|
16
|
+
*
|
|
17
|
+
* Idempotency: after a successful split the parent's frontmatter is rewritten
|
|
18
|
+
* with `inferenceProcessed: true`. A subsequent `akm index` therefore skips
|
|
19
|
+
* the parent without re-running the LLM.
|
|
20
|
+
*
|
|
21
|
+
* Disabling — two orthogonal gates:
|
|
22
|
+
* 1. `profiles.improve.default.processes.memoryInference.enabled = false`
|
|
23
|
+
* blocks the pass at the feature-flag layer (no network call may ever
|
|
24
|
+
* issue). Historically the v1 spec §14 gate, superseded by the 0.8.0
|
|
25
|
+
* profile shape.
|
|
26
|
+
* 2. `index.memory.llm = false` (or no resolvable LLM profile) opts the
|
|
27
|
+
* pass out at the per-pass layer (#208).
|
|
28
|
+
* A pass runs iff both layers allow it. Existing inferred children are
|
|
29
|
+
* NEVER deleted — the user keeps what was already produced.
|
|
30
|
+
*
|
|
31
|
+
* Locked v1 contract:
|
|
32
|
+
* - LLM access is exclusively via `resolveIndexPassLLM("memory", config)`.
|
|
33
|
+
* - All child memory writes go through `writeAssetToSource` in
|
|
34
|
+
* `src/core/write-source.ts`. The parent's frontmatter rewrite is an
|
|
35
|
+
* explicit narrow exception — see {@link markParentProcessed}.
|
|
36
|
+
*/
|
|
4
37
|
import fs from "node:fs";
|
|
5
38
|
import path from "node:path";
|
|
6
|
-
import { parseAssetRef } from "
|
|
7
|
-
import { assembleAsset } from "
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { warn } from "
|
|
11
|
-
import { writeAssetToSource } from "
|
|
12
|
-
import { isProcessEnabled } from "
|
|
13
|
-
import { resolveIndexPassLLM } from "
|
|
14
|
-
import * as memoryInfer from "
|
|
15
|
-
import { withLlmCache } from "
|
|
16
|
-
import { walkMarkdownFiles } from "
|
|
39
|
+
import { parseAssetRef } from "../../core/asset/asset-ref.js";
|
|
40
|
+
import { assembleAsset } from "../../core/asset/asset-serialize.js";
|
|
41
|
+
import { parseFrontmatter, parseFrontmatterBlock } from "../../core/asset/frontmatter.js";
|
|
42
|
+
import { concurrentMap } from "../../core/concurrent.js";
|
|
43
|
+
import { warn } from "../../core/warn.js";
|
|
44
|
+
import { writeAssetToSource } from "../../core/write-source.js";
|
|
45
|
+
import { isProcessEnabled } from "../../llm/feature-gate.js";
|
|
46
|
+
import { resolveIndexPassLLM } from "../../llm/index-passes.js";
|
|
47
|
+
import * as memoryInfer from "../../llm/memory-infer.js";
|
|
48
|
+
import { withLlmCache } from "../db/llm-cache.js";
|
|
49
|
+
import { walkMarkdownFiles } from "../walk/walker.js";
|
|
17
50
|
/**
|
|
18
51
|
* Frontmatter keys this pass cares about. Constants so a future rename only
|
|
19
52
|
* needs to touch one site.
|
|
@@ -37,17 +70,24 @@ const FM_CAPTURE_MODE = "captureMode";
|
|
|
37
70
|
* Both must allow the call for the pass to run. Either set to `false`
|
|
38
71
|
* short-circuits to a no-op result.
|
|
39
72
|
*/
|
|
40
|
-
export async function runMemoryInferencePass(
|
|
73
|
+
export async function runMemoryInferencePass(ctx) {
|
|
74
|
+
const { config, sources, signal, db, reEnrich, onProgress, options = {} } = ctx;
|
|
41
75
|
const result = {
|
|
42
76
|
considered: 0,
|
|
43
77
|
cacheHits: 0,
|
|
78
|
+
retryAttempts: 0,
|
|
44
79
|
splitParents: 0,
|
|
45
80
|
writtenFacts: 0,
|
|
46
81
|
skippedNoFacts: 0,
|
|
47
82
|
skippedChildExists: 0,
|
|
48
83
|
skippedAborted: 0,
|
|
49
84
|
unaccounted: 0,
|
|
85
|
+
htmlErrorCount: 0,
|
|
50
86
|
};
|
|
87
|
+
// Mutable sink threaded into compressMemoryToDerivedMemory so the per-call
|
|
88
|
+
// HTML-error categorization (which is otherwise swallowed inside the feature
|
|
89
|
+
// gate) bubbles up into the pass result.
|
|
90
|
+
const inferTelemetry = {};
|
|
51
91
|
// Gate 1 — feature gate via isProcessEnabled, which reads the 0.8.0 path
|
|
52
92
|
// (profiles.improve.default.processes.memoryInference.enabled). Defaults to
|
|
53
93
|
// enabled when the key is absent.
|
|
@@ -79,6 +119,26 @@ export async function runMemoryInferencePass(config, sources, signal, db, reEnri
|
|
|
79
119
|
// 2026-05-26).
|
|
80
120
|
if (signal?.aborted)
|
|
81
121
|
return { aborted: true };
|
|
122
|
+
// Pre-check (#588): when `<parent>.derived.md` is already on disk the
|
|
123
|
+
// inference is by definition complete — the parent only looks pending
|
|
124
|
+
// because `markParentProcessed` never ran (process killed between the
|
|
125
|
+
// child write and the mark) or the child was created externally (e.g.
|
|
126
|
+
// consolidation). Skip the LLM/cache call entirely and mark the parent
|
|
127
|
+
// so it never re-pends. Before this check, production measurements
|
|
128
|
+
// showed ~55% of the pass's LLM budget re-deriving such parents only to
|
|
129
|
+
// discover the existing child after the fact.
|
|
130
|
+
if (fs.existsSync(derivedChildPath(record))) {
|
|
131
|
+
markParentProcessed(record);
|
|
132
|
+
return {
|
|
133
|
+
skipped: false,
|
|
134
|
+
splitParent: false,
|
|
135
|
+
written: 0,
|
|
136
|
+
fromCache: false,
|
|
137
|
+
retryAttempts: 0,
|
|
138
|
+
childExists: true,
|
|
139
|
+
precheck: true,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
82
142
|
// Incremental cache: skip LLM call when body hash is unchanged and
|
|
83
143
|
// --re-enrich was not requested. The cache ref is the absolute file path.
|
|
84
144
|
const validate = (raw) => {
|
|
@@ -103,31 +163,58 @@ export async function runMemoryInferencePass(config, sources, signal, db, reEnri
|
|
|
103
163
|
// the hit count separately so the operational yield rate
|
|
104
164
|
// (writtenFacts / freshAttempts) is interpretable as the cache warms.
|
|
105
165
|
let fromCache = false;
|
|
166
|
+
// Count single bounded retries for transient LLM failures on this
|
|
167
|
+
// candidate. Bumped via the `onRetryAttempt` callback threaded into
|
|
168
|
+
// `chatCompletion`; surfaced as `retryAttempts` telemetry, never as a
|
|
169
|
+
// failure for the same call.
|
|
170
|
+
let retryAttempts = 0;
|
|
171
|
+
const onRetryAttempt = () => {
|
|
172
|
+
retryAttempts += 1;
|
|
173
|
+
};
|
|
106
174
|
const derived = db
|
|
107
175
|
? await withLlmCache(db, record.filePath, record.body, reEnrich ?? false, () => memoryInfer.compressMemoryToDerivedMemory(llmConfig, record.body, signal, config, (evt) => {
|
|
108
176
|
warn(`[akm] LLM fallback for ${evt.feature}: ${evt.reason}`);
|
|
109
|
-
}), validate, undefined, "", {
|
|
177
|
+
}, inferTelemetry, onRetryAttempt), validate, undefined, "", {
|
|
110
178
|
onCacheHit: () => {
|
|
111
179
|
fromCache = true;
|
|
112
180
|
},
|
|
113
181
|
})
|
|
114
182
|
: await memoryInfer.compressMemoryToDerivedMemory(llmConfig, record.body, signal, config, (evt) => {
|
|
115
183
|
warn(`[akm] LLM fallback for ${evt.feature}: ${evt.reason}`);
|
|
116
|
-
});
|
|
184
|
+
}, inferTelemetry, onRetryAttempt);
|
|
117
185
|
if (!derived) {
|
|
118
|
-
return { skipped: true, fromCache };
|
|
186
|
+
return { skipped: true, fromCache, retryAttempts };
|
|
119
187
|
}
|
|
120
|
-
const
|
|
121
|
-
if (written > 0) {
|
|
188
|
+
const writeOutcome = await writeDerivedMemory(record, derived);
|
|
189
|
+
if (writeOutcome.written > 0) {
|
|
122
190
|
markParentProcessed(record);
|
|
123
|
-
return { skipped: false, splitParent: true, written, fromCache };
|
|
191
|
+
return { skipped: false, splitParent: true, written: writeOutcome.written, fromCache, retryAttempts };
|
|
124
192
|
}
|
|
125
193
|
// LLM produced a valid derived draft but no file was written — either
|
|
126
|
-
// because `<parent>.derived.md`
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
// into the freshAttempts
|
|
130
|
-
|
|
194
|
+
// because `<parent>.derived.md` appeared on disk after the pre-check
|
|
195
|
+
// above (a rare mid-flight race) or `writeAssetToSource` threw.
|
|
196
|
+
// Categorise as `childExists` so the consumed attempt is accounted for
|
|
197
|
+
// in health metrics rather than vanishing into the freshAttempts
|
|
198
|
+
// denominator.
|
|
199
|
+
//
|
|
200
|
+
// When the child exists the inference is, by definition, complete — so
|
|
201
|
+
// mark the parent processed here too (#550), otherwise
|
|
202
|
+
// `isPendingMemory()` re-queues the same parent every run. A genuine
|
|
203
|
+
// write *failure* (`writeAssetToSource` threw) must NOT mark the parent
|
|
204
|
+
// — it should be retried next run — so we key off the explicit
|
|
205
|
+
// `childExists` outcome rather than the conflated `written === 0`.
|
|
206
|
+
if (writeOutcome.childExists) {
|
|
207
|
+
markParentProcessed(record);
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
skipped: false,
|
|
211
|
+
splitParent: false,
|
|
212
|
+
written: 0,
|
|
213
|
+
fromCache,
|
|
214
|
+
retryAttempts,
|
|
215
|
+
childExists: true,
|
|
216
|
+
precheck: false,
|
|
217
|
+
};
|
|
131
218
|
},
|
|
132
219
|
// Default concurrency of 4 for cloud APIs. Set `llm.concurrency: 1`
|
|
133
220
|
// in config.json for local model servers (LM Studio, Ollama).
|
|
@@ -151,6 +238,9 @@ export async function runMemoryInferencePass(config, sources, signal, db, reEnri
|
|
|
151
238
|
if (res.fromCache) {
|
|
152
239
|
result.cacheHits += 1;
|
|
153
240
|
}
|
|
241
|
+
if ("retryAttempts" in res) {
|
|
242
|
+
result.retryAttempts += res.retryAttempts;
|
|
243
|
+
}
|
|
154
244
|
if (res.skipped) {
|
|
155
245
|
result.skippedNoFacts += 1;
|
|
156
246
|
// Intentionally NOT marked processed — a transient LLM failure should
|
|
@@ -161,11 +251,16 @@ export async function runMemoryInferencePass(config, sources, signal, db, reEnri
|
|
|
161
251
|
result.writtenFacts += res.written;
|
|
162
252
|
}
|
|
163
253
|
else if ("childExists" in res && res.childExists) {
|
|
164
|
-
//
|
|
165
|
-
//
|
|
166
|
-
//
|
|
254
|
+
// Derived child already on disk. Track separately so this category is
|
|
255
|
+
// observable in health output and stops bleeding into the
|
|
256
|
+
// freshAttempts denominator. Pre-check skips (#588) are the routine
|
|
257
|
+
// self-healing path — no LLM attempt was consumed and the parent has
|
|
258
|
+
// been marked processed — so only the rare post-LLM case (mid-flight
|
|
259
|
+
// race or write failure) warrants a per-ref warning.
|
|
167
260
|
result.skippedChildExists += 1;
|
|
168
|
-
|
|
261
|
+
if (!res.precheck) {
|
|
262
|
+
warn(`memory inference: derived child for ${pending[i]?.ref ?? "<unknown>"} already existed or write failed; counted as skippedChildExists`);
|
|
263
|
+
}
|
|
169
264
|
}
|
|
170
265
|
else {
|
|
171
266
|
// The per-record state machine should cover every outcome. A hit here
|
|
@@ -183,6 +278,7 @@ export async function runMemoryInferencePass(config, sources, signal, db, reEnri
|
|
|
183
278
|
currentRef: pending[i]?.ref,
|
|
184
279
|
});
|
|
185
280
|
}
|
|
281
|
+
result.htmlErrorCount = inferTelemetry.htmlErrorCount ?? 0;
|
|
186
282
|
return result;
|
|
187
283
|
}
|
|
188
284
|
// ── Pending detection ───────────────────────────────────────────────────────
|
|
@@ -260,7 +356,14 @@ function toMemoryName(memoriesDir, filePath) {
|
|
|
260
356
|
// user has organised under memories/.
|
|
261
357
|
return rel.replace(/\\/g, "/").replace(/\.md$/i, "");
|
|
262
358
|
}
|
|
263
|
-
|
|
359
|
+
/**
|
|
360
|
+
* Absolute path of the derived child for a parent memory. Single source of
|
|
361
|
+
* truth for the `<parent>.derived.md` naming convention — used both by the
|
|
362
|
+
* pre-LLM existence check (#588) and the write path.
|
|
363
|
+
*/
|
|
364
|
+
function derivedChildPath(parent) {
|
|
365
|
+
return path.join(parent.stashRoot, "memories", `${parent.name}.derived.md`);
|
|
366
|
+
}
|
|
264
367
|
async function writeDerivedMemory(parent, derived) {
|
|
265
368
|
const writeTarget = {
|
|
266
369
|
kind: "filesystem",
|
|
@@ -275,19 +378,24 @@ async function writeDerivedMemory(parent, derived) {
|
|
|
275
378
|
};
|
|
276
379
|
const childName = `${parent.name}.derived`;
|
|
277
380
|
const childRefStr = `memory:${childName}`;
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
381
|
+
if (fs.existsSync(derivedChildPath(parent))) {
|
|
382
|
+
// The derived child appeared on disk after the caller's pre-check (#588)
|
|
383
|
+
// — a rare mid-flight race. Report `childExists` so the caller marks the
|
|
384
|
+
// parent processed (#550) instead of re-queueing it forever.
|
|
385
|
+
return { written: 0, childExists: true };
|
|
281
386
|
}
|
|
282
387
|
try {
|
|
283
388
|
const content = renderDerivedMemory(parent, derived);
|
|
284
389
|
const childRef = parseAssetRef(childRefStr);
|
|
285
390
|
await writeAssetToSource(writeTarget, writeConfig, childRef, content);
|
|
286
|
-
return 1;
|
|
391
|
+
return { written: 1, childExists: false };
|
|
287
392
|
}
|
|
288
393
|
catch (err) {
|
|
289
394
|
warn(`memory inference: failed to write derived memory ${childName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
290
|
-
|
|
395
|
+
// A genuine write failure — the parent must remain pending so it is
|
|
396
|
+
// retried on the next run. `childExists: false` keeps it from being
|
|
397
|
+
// marked processed.
|
|
398
|
+
return { written: 0, childExists: false };
|
|
291
399
|
}
|
|
292
400
|
}
|
|
293
401
|
function renderDerivedMemory(parent, derived) {
|
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
const contributors = [];
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Ensure that all built-in indexer contributors are registered.
|
|
7
|
+
*
|
|
8
|
+
* Delegates to the single `initIndexer()` composition root (see
|
|
9
|
+
* `src/indexer/init.ts`). Imported dynamically to keep this a lazy gate and to
|
|
10
|
+
* avoid a static import cycle (init -> renderers -> metadata-contributors).
|
|
11
|
+
* Called on first use of getMetadataContributors; idempotent.
|
|
12
|
+
*/
|
|
6
13
|
async function ensureBuiltinMetadataContributorsRegistered() {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
await import("../output/renderers.js");
|
|
10
|
-
await import("../workflows/renderer.js");
|
|
11
|
-
})();
|
|
12
|
-
}
|
|
13
|
-
return builtinsPromise;
|
|
14
|
+
const { initIndexer } = await import("../init.js");
|
|
15
|
+
await initIndexer();
|
|
14
16
|
}
|
|
15
17
|
export function registerMetadataContributor(contributor) {
|
|
16
18
|
contributors.push(contributor);
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import { deriveCanonicalAssetName, deriveCanonicalAssetNameFromStashRoot, isRelevantAssetFile, } from "
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { isVerbose, warn } from "
|
|
10
|
-
import { buildFileContext, buildRenderContext, getRenderer, runMatchers } from "
|
|
11
|
-
import { applyMetadataContributors } from "./metadata-contributors";
|
|
6
|
+
import { deriveCanonicalAssetName, deriveCanonicalAssetNameFromStashRoot, isRelevantAssetFile, } from "../../core/asset/asset-spec.js";
|
|
7
|
+
import { parseFrontmatter } from "../../core/asset/frontmatter.js";
|
|
8
|
+
import { asNonEmptyString, isAssetType, writeFileAtomic } from "../../core/common.js";
|
|
9
|
+
import { isVerbose, warn } from "../../core/warn.js";
|
|
10
|
+
import { buildFileContext, buildRenderContext, getRenderer, runMatchers } from "../walk/file-context.js";
|
|
11
|
+
import { applyMetadataContributors } from "./metadata-contributors.js";
|
|
12
12
|
export const SCOPE_KEYS = ["user", "agent", "run", "channel"];
|
|
13
13
|
// ── Load / Write ────────────────────────────────────────────────────────────
|
|
14
14
|
const STASH_FILENAME = ".stash.json";
|
|
@@ -480,18 +480,15 @@ export function shouldIndexStashFile(stashRoot, file, options) {
|
|
|
480
480
|
const segments = relPath.split(/[\\/]+/).filter(Boolean);
|
|
481
481
|
if (segments.length === 0)
|
|
482
482
|
return true;
|
|
483
|
-
// Skip env
|
|
484
|
-
if (
|
|
485
|
-
(file.endsWith(".env") || path.basename(file) === ".env")) {
|
|
483
|
+
// Skip env .env files that have a sibling .sensitive marker file.
|
|
484
|
+
if (segments[0] === "env" && (file.endsWith(".env") || path.basename(file) === ".env")) {
|
|
486
485
|
const markerPath = file.replace(/\.env$/, ".sensitive");
|
|
487
486
|
if (fs.existsSync(markerPath))
|
|
488
487
|
return false;
|
|
489
488
|
}
|
|
490
|
-
//
|
|
491
|
-
//
|
|
492
|
-
|
|
493
|
-
// with no `env/` dir still index `vaults/` normally.)
|
|
494
|
-
if (segments[0] === "vaults" && fs.existsSync(path.join(stashRoot, "env"))) {
|
|
489
|
+
// The legacy `vaults/` directory (frozen copy left by the 0.8 migration) is
|
|
490
|
+
// never indexed — the `vault` asset type was removed in 0.9.0.
|
|
491
|
+
if (segments[0] === "vaults") {
|
|
495
492
|
return false;
|
|
496
493
|
}
|
|
497
494
|
// Skip secret files that are themselves a `.sensitive` marker, or that have a
|
|
@@ -853,11 +850,10 @@ async function buildEntryFromFile(file, assetType, canonicalName, dirPath, pkgMe
|
|
|
853
850
|
}
|
|
854
851
|
}
|
|
855
852
|
// Extract @param from script files.
|
|
856
|
-
// Env
|
|
857
|
-
//
|
|
858
|
-
//
|
|
859
|
-
|
|
860
|
-
if (ext !== ".md" && assetType !== "env" && assetType !== "vault" && assetType !== "secret") {
|
|
853
|
+
// Env files (.env) and secret files (whole-file secrets) are deliberately
|
|
854
|
+
// excluded — their contents are secrets and must never be parsed for @param
|
|
855
|
+
// or any other metadata that could embed a value into the entry.
|
|
856
|
+
if (ext !== ".md" && assetType !== "env" && assetType !== "secret") {
|
|
861
857
|
const content = ctx.content();
|
|
862
858
|
const scriptParams = extractScriptParameters(file, content);
|
|
863
859
|
if (scriptParams)
|