nlm-memory 0.20.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -10
- package/dist/cli/digest.js +60 -1
- package/dist/cli/digest.js.map +1 -1
- package/dist/cli/init.d.ts +12 -0
- package/dist/cli/init.js +49 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/nlm.d.ts +13 -1
- package/dist/cli/nlm.js +872 -61
- package/dist/cli/nlm.js.map +1 -1
- package/dist/cli/scope-backfill.d.ts +34 -0
- package/dist/cli/scope-backfill.js +237 -0
- package/dist/cli/scope-backfill.js.map +1 -0
- package/dist/cli/scope-coverage.d.ts +44 -0
- package/dist/cli/scope-coverage.js +205 -0
- package/dist/cli/scope-coverage.js.map +1 -0
- package/dist/core/actions/overlay.d.ts +20 -6
- package/dist/core/actions/overlay.js +32 -18
- package/dist/core/actions/overlay.js.map +1 -1
- package/dist/core/adapters/claude-code.d.ts +14 -0
- package/dist/core/adapters/claude-code.js +36 -0
- package/dist/core/adapters/claude-code.js.map +1 -1
- package/dist/core/classifier/prompt.js +3 -3
- package/dist/core/dataset/build-dataset.js +1 -0
- package/dist/core/dataset/build-dataset.js.map +1 -1
- package/dist/core/digest/compose.d.ts +13 -3
- package/dist/core/digest/compose.js +23 -18
- package/dist/core/digest/compose.js.map +1 -1
- package/dist/core/digest/hook-injection.d.ts +43 -0
- package/dist/core/digest/hook-injection.js +79 -0
- package/dist/core/digest/hook-injection.js.map +1 -0
- package/dist/core/embedding/embed-backfill.d.ts +13 -2
- package/dist/core/embedding/embed-backfill.js +181 -43
- package/dist/core/embedding/embed-backfill.js.map +1 -1
- package/dist/core/embedding/embedding-config.d.ts +17 -0
- package/dist/core/embedding/embedding-config.js +12 -0
- package/dist/core/embedding/embedding-config.js.map +1 -0
- package/dist/core/embedding/pg-embed-backfill.d.ts +31 -0
- package/dist/core/embedding/pg-embed-backfill.js +264 -0
- package/dist/core/embedding/pg-embed-backfill.js.map +1 -0
- package/dist/core/entities/dedup-suggest.d.ts +25 -0
- package/dist/core/entities/dedup-suggest.js +107 -0
- package/dist/core/entities/dedup-suggest.js.map +1 -0
- package/dist/core/eval/classifier-fixture-eval.d.ts +29 -0
- package/dist/core/eval/classifier-fixture-eval.js +217 -0
- package/dist/core/eval/classifier-fixture-eval.js.map +1 -0
- package/dist/core/eval/extraction-scoring.d.ts +63 -0
- package/dist/core/eval/extraction-scoring.js +79 -0
- package/dist/core/eval/extraction-scoring.js.map +1 -0
- package/dist/core/eval/run-eval.d.ts +40 -0
- package/dist/core/eval/run-eval.js +34 -0
- package/dist/core/eval/run-eval.js.map +1 -0
- package/dist/core/exemplars/capture-from-session.d.ts +2 -0
- package/dist/core/exemplars/capture-from-session.js +7 -3
- package/dist/core/exemplars/capture-from-session.js.map +1 -1
- package/dist/core/exemplars/diff-parse.d.ts +23 -0
- package/dist/core/exemplars/diff-parse.js +73 -0
- package/dist/core/exemplars/diff-parse.js.map +1 -0
- package/dist/core/exemplars/embed-backfill.d.ts +36 -0
- package/dist/core/exemplars/embed-backfill.js +85 -0
- package/dist/core/exemplars/embed-backfill.js.map +1 -0
- package/dist/core/exemplars/embed-text.d.ts +15 -0
- package/dist/core/exemplars/embed-text.js +18 -0
- package/dist/core/exemplars/embed-text.js.map +1 -0
- package/dist/core/exemplars/extract-exemplar.d.ts +2 -0
- package/dist/core/exemplars/extract-exemplar.js +9 -66
- package/dist/core/exemplars/extract-exemplar.js.map +1 -1
- package/dist/core/exemplars/ingest-exemplar.d.ts +1 -0
- package/dist/core/exemplars/ingest-exemplar.js +1 -0
- package/dist/core/exemplars/ingest-exemplar.js.map +1 -1
- package/dist/core/exemplars/recall-code.js +4 -0
- package/dist/core/exemplars/recall-code.js.map +1 -1
- package/dist/core/exemplars/warm-embedder.d.ts +14 -0
- package/dist/core/exemplars/warm-embedder.js +18 -0
- package/dist/core/exemplars/warm-embedder.js.map +1 -0
- package/dist/core/health/corpus-state.d.ts +8 -0
- package/dist/core/health/corpus-state.js +11 -0
- package/dist/core/health/corpus-state.js.map +1 -0
- package/dist/core/health/embed-inflight.d.ts +9 -0
- package/dist/core/health/embed-inflight.js +30 -0
- package/dist/core/health/embed-inflight.js.map +1 -0
- package/dist/core/health/embedding-lane-state.d.ts +6 -0
- package/dist/core/health/embedding-lane-state.js +18 -0
- package/dist/core/health/embedding-lane-state.js.map +1 -0
- package/dist/core/health/warmup-state.d.ts +12 -0
- package/dist/core/health/warmup-state.js +12 -0
- package/dist/core/health/warmup-state.js.map +1 -0
- package/dist/core/hook/claude-settings.d.ts +1 -1
- package/dist/core/hook/claude-settings.js +0 -1
- package/dist/core/hook/claude-settings.js.map +1 -1
- package/dist/core/hook/gate.d.ts +13 -6
- package/dist/core/hook/gate.js +47 -6
- package/dist/core/hook/gate.js.map +1 -1
- package/dist/core/hook/hook-log.d.ts +5 -0
- package/dist/core/hook/hook-log.js.map +1 -1
- package/dist/core/hook/memo.d.ts +12 -0
- package/dist/core/hook/memo.js +41 -1
- package/dist/core/hook/memo.js.map +1 -1
- package/dist/core/hook/pointer-block.d.ts +1 -0
- package/dist/core/hook/pointer-block.js +23 -2
- package/dist/core/hook/pointer-block.js.map +1 -1
- package/dist/core/hook/query-extract.d.ts +2 -1
- package/dist/core/hook/query-extract.js +10 -1
- package/dist/core/hook/query-extract.js.map +1 -1
- package/dist/core/hook/resolve-conversation-by-query.d.ts +28 -0
- package/dist/core/hook/resolve-conversation-by-query.js +98 -0
- package/dist/core/hook/resolve-conversation-by-query.js.map +1 -0
- package/dist/core/hook/select.d.ts +8 -0
- package/dist/core/hook/select.js +9 -2
- package/dist/core/hook/select.js.map +1 -1
- package/dist/core/hook/transcript.js +16 -2
- package/dist/core/hook/transcript.js.map +1 -1
- package/dist/core/ingest/backfill-derivables.d.ts +92 -0
- package/dist/core/ingest/backfill-derivables.js +175 -0
- package/dist/core/ingest/backfill-derivables.js.map +1 -0
- package/dist/core/ingest/ingest-session.d.ts +5 -0
- package/dist/core/ingest/ingest-session.js +23 -0
- package/dist/core/ingest/ingest-session.js.map +1 -1
- package/dist/core/ingest/reclassify-oversized.d.ts +5 -0
- package/dist/core/ingest/reclassify-oversized.js +9 -0
- package/dist/core/ingest/reclassify-oversized.js.map +1 -1
- package/dist/core/ingest/reprocess.d.ts +96 -0
- package/dist/core/ingest/reprocess.js +280 -0
- package/dist/core/ingest/reprocess.js.map +1 -0
- package/dist/core/ingest/transcript-derivables.d.ts +27 -0
- package/dist/core/ingest/transcript-derivables.js +138 -0
- package/dist/core/ingest/transcript-derivables.js.map +1 -0
- package/dist/core/integrity/check-invariants.d.ts +6 -1
- package/dist/core/integrity/check-invariants.js +209 -3
- package/dist/core/integrity/check-invariants.js.map +1 -1
- package/dist/core/metrics/corpus-stats.d.ts +49 -0
- package/dist/core/metrics/corpus-stats.js +111 -0
- package/dist/core/metrics/corpus-stats.js.map +1 -0
- package/dist/core/metrics/re-derivation.d.ts +48 -0
- package/dist/core/metrics/re-derivation.js +87 -0
- package/dist/core/metrics/re-derivation.js.map +1 -0
- package/dist/core/outcome/coverage.d.ts +33 -0
- package/dist/core/outcome/coverage.js +46 -0
- package/dist/core/outcome/coverage.js.map +1 -0
- package/dist/core/outcome/rollup.d.ts +33 -0
- package/dist/core/outcome/rollup.js +113 -0
- package/dist/core/outcome/rollup.js.map +1 -0
- package/dist/core/recall/citation-log.d.ts +8 -0
- package/dist/core/recall/citation-log.js +17 -0
- package/dist/core/recall/citation-log.js.map +1 -1
- package/dist/core/recall/hook-recall-log.d.ts +2 -2
- package/dist/core/recall/hook-recall-log.js +2 -2
- package/dist/core/recall/query-intent.d.ts +7 -0
- package/dist/core/recall/query-intent.js +25 -0
- package/dist/core/recall/query-intent.js.map +1 -0
- package/dist/core/recall/query-log.d.ts +4 -0
- package/dist/core/recall/query-log.js +4 -0
- package/dist/core/recall/query-log.js.map +1 -1
- package/dist/core/recall/recall-service.d.ts +37 -1
- package/dist/core/recall/recall-service.js +106 -63
- package/dist/core/recall/recall-service.js.map +1 -1
- package/dist/core/recall/related-exemplars.d.ts +1 -0
- package/dist/core/recall/related-exemplars.js +4 -1
- package/dist/core/recall/related-exemplars.js.map +1 -1
- package/dist/core/recall/related-facts.js +2 -2
- package/dist/core/recall/related-facts.js.map +1 -1
- package/dist/core/recall/reranker.d.ts +2 -1
- package/dist/core/recall/reranker.js +3 -3
- package/dist/core/recall/reranker.js.map +1 -1
- package/dist/core/recall-facts/fact-query-log.d.ts +7 -0
- package/dist/core/recall-facts/fact-query-log.js +2 -0
- package/dist/core/recall-facts/fact-query-log.js.map +1 -1
- package/dist/core/recall-facts/fact-recall-service.d.ts +9 -1
- package/dist/core/recall-facts/fact-recall-service.js +22 -8
- package/dist/core/recall-facts/fact-recall-service.js.map +1 -1
- package/dist/core/scheduler/scan-once.d.ts +6 -6
- package/dist/core/scheduler/scan-once.js +15 -49
- package/dist/core/scheduler/scan-once.js.map +1 -1
- package/dist/core/scheduler/scheduler.d.ts +10 -0
- package/dist/core/scheduler/scheduler.js +109 -13
- package/dist/core/scheduler/scheduler.js.map +1 -1
- package/dist/core/scope/alias-map.d.ts +10 -0
- package/dist/core/scope/alias-map.js +41 -0
- package/dist/core/scope/alias-map.js.map +1 -0
- package/dist/core/scope/derive-scope.d.ts +8 -0
- package/dist/core/scope/derive-scope.js +54 -0
- package/dist/core/scope/derive-scope.js.map +1 -0
- package/dist/core/scope/scope-clause.d.ts +16 -0
- package/dist/core/scope/scope-clause.js +21 -0
- package/dist/core/scope/scope-clause.js.map +1 -0
- package/dist/core/scope/stamp-flag.d.ts +1 -0
- package/dist/core/scope/stamp-flag.js +4 -0
- package/dist/core/scope/stamp-flag.js.map +1 -0
- package/dist/core/signals/code-signal.d.ts +50 -0
- package/dist/core/signals/code-signal.js +54 -0
- package/dist/core/signals/code-signal.js.map +1 -0
- package/dist/core/signals/ingest-signal.d.ts +1 -1
- package/dist/core/signals/ingest-signal.js +3 -1
- package/dist/core/signals/ingest-signal.js.map +1 -1
- package/dist/core/signals/stamp-scope.d.ts +18 -0
- package/dist/core/signals/stamp-scope.js +28 -0
- package/dist/core/signals/stamp-scope.js.map +1 -0
- package/dist/core/storage/db-restore.js +3 -1
- package/dist/core/storage/db-restore.js.map +1 -1
- package/dist/core/storage/fact-batch.d.ts +9 -0
- package/dist/core/storage/fact-batch.js +14 -0
- package/dist/core/storage/fact-batch.js.map +1 -0
- package/dist/core/storage/pg-code-exemplar-store.d.ts +1 -0
- package/dist/core/storage/pg-code-exemplar-store.js +13 -2
- package/dist/core/storage/pg-code-exemplar-store.js.map +1 -1
- package/dist/core/storage/pg-embedding-config.d.ts +29 -0
- package/dist/core/storage/pg-embedding-config.js +53 -0
- package/dist/core/storage/pg-embedding-config.js.map +1 -0
- package/dist/core/storage/pg-entity-store.d.ts +12 -0
- package/dist/core/storage/pg-entity-store.js +79 -0
- package/dist/core/storage/pg-entity-store.js.map +1 -0
- package/dist/core/storage/pg-fact-ingest.d.ts +15 -0
- package/dist/core/storage/pg-fact-ingest.js +34 -0
- package/dist/core/storage/pg-fact-ingest.js.map +1 -0
- package/dist/core/storage/pg-fact-store.d.ts +3 -0
- package/dist/core/storage/pg-fact-store.js +26 -30
- package/dist/core/storage/pg-fact-store.js.map +1 -1
- package/dist/core/storage/pg-migrate.d.ts +18 -0
- package/dist/core/storage/pg-migrate.js +73 -0
- package/dist/core/storage/pg-migrate.js.map +1 -0
- package/dist/core/storage/pg-session-store.d.ts +11 -2
- package/dist/core/storage/pg-session-store.js +224 -96
- package/dist/core/storage/pg-session-store.js.map +1 -1
- package/dist/core/storage/pg-signal-store.js +4 -3
- package/dist/core/storage/pg-signal-store.js.map +1 -1
- package/dist/core/storage/pg-storage.d.ts +9 -7
- package/dist/core/storage/pg-storage.js +20 -50
- package/dist/core/storage/pg-storage.js.map +1 -1
- package/dist/core/storage/pg-workstream-store.d.ts +25 -0
- package/dist/core/storage/pg-workstream-store.js +97 -0
- package/dist/core/storage/pg-workstream-store.js.map +1 -0
- package/dist/core/storage/sqlite-code-exemplar-store.d.ts +1 -0
- package/dist/core/storage/sqlite-code-exemplar-store.js +15 -2
- package/dist/core/storage/sqlite-code-exemplar-store.js.map +1 -1
- package/dist/core/storage/sqlite-embedding-config.d.ts +10 -0
- package/dist/core/storage/sqlite-embedding-config.js +27 -0
- package/dist/core/storage/sqlite-embedding-config.js.map +1 -0
- package/dist/core/storage/sqlite-entity-store.d.ts +13 -0
- package/dist/core/storage/sqlite-entity-store.js +96 -0
- package/dist/core/storage/sqlite-entity-store.js.map +1 -0
- package/dist/core/storage/sqlite-fact-store.d.ts +15 -7
- package/dist/core/storage/sqlite-fact-store.js +81 -27
- package/dist/core/storage/sqlite-fact-store.js.map +1 -1
- package/dist/core/storage/sqlite-outcome-store.d.ts +89 -0
- package/dist/core/storage/sqlite-outcome-store.js +158 -0
- package/dist/core/storage/sqlite-outcome-store.js.map +1 -0
- package/dist/core/storage/sqlite-session-store.d.ts +42 -7
- package/dist/core/storage/sqlite-session-store.js +208 -95
- package/dist/core/storage/sqlite-session-store.js.map +1 -1
- package/dist/core/storage/sqlite-signal-store.js +4 -2
- package/dist/core/storage/sqlite-signal-store.js.map +1 -1
- package/dist/core/storage/sqlite-storage.d.ts +8 -8
- package/dist/core/storage/sqlite-storage.js +21 -32
- package/dist/core/storage/sqlite-storage.js.map +1 -1
- package/dist/core/storage/sqlite-workstream-store.d.ts +25 -0
- package/dist/core/storage/sqlite-workstream-store.js +99 -0
- package/dist/core/storage/sqlite-workstream-store.js.map +1 -0
- package/dist/core/storage/supersedence-log.js +2 -0
- package/dist/core/storage/supersedence-log.js.map +1 -1
- package/dist/core/telemetry/probe-filter.d.ts +35 -0
- package/dist/core/telemetry/probe-filter.js +56 -0
- package/dist/core/telemetry/probe-filter.js.map +1 -0
- package/dist/core/update-check/check.d.ts +6 -0
- package/dist/core/update-check/check.js +35 -0
- package/dist/core/update-check/check.js.map +1 -1
- package/dist/core/work-digest/active-spans.d.ts +8 -0
- package/dist/core/work-digest/active-spans.js +29 -0
- package/dist/core/work-digest/active-spans.js.map +1 -0
- package/dist/core/work-digest/attribute.d.ts +15 -0
- package/dist/core/work-digest/attribute.js +76 -0
- package/dist/core/work-digest/attribute.js.map +1 -0
- package/dist/core/work-digest/build-work-digest.d.ts +12 -0
- package/dist/core/work-digest/build-work-digest.js +69 -0
- package/dist/core/work-digest/build-work-digest.js.map +1 -0
- package/dist/core/work-digest/compose-work-digest.d.ts +3 -0
- package/dist/core/work-digest/compose-work-digest.js +52 -0
- package/dist/core/work-digest/compose-work-digest.js.map +1 -0
- package/dist/core/work-digest/merge-active.d.ts +10 -0
- package/dist/core/work-digest/merge-active.js +22 -0
- package/dist/core/work-digest/merge-active.js.map +1 -0
- package/dist/core/work-digest/read-transcript-timestamps.d.ts +7 -0
- package/dist/core/work-digest/read-transcript-timestamps.js +40 -0
- package/dist/core/work-digest/read-transcript-timestamps.js.map +1 -0
- package/dist/core/work-digest/topics.d.ts +18 -0
- package/dist/core/work-digest/topics.js +26 -0
- package/dist/core/work-digest/topics.js.map +1 -0
- package/dist/core/work-digest/types.d.ts +45 -0
- package/dist/core/work-digest/types.js +2 -0
- package/dist/core/work-digest/types.js.map +1 -0
- package/dist/core/workstream/bind.d.ts +26 -0
- package/dist/core/workstream/bind.js +42 -0
- package/dist/core/workstream/bind.js.map +1 -0
- package/dist/core/workstream/compose-recall.d.ts +2 -0
- package/dist/core/workstream/compose-recall.js +39 -0
- package/dist/core/workstream/compose-recall.js.map +1 -0
- package/dist/core/workstream/merge-suggest.d.ts +19 -0
- package/dist/core/workstream/merge-suggest.js +61 -0
- package/dist/core/workstream/merge-suggest.js.map +1 -0
- package/dist/core/workstream/model.d.ts +21 -0
- package/dist/core/workstream/model.js +9 -0
- package/dist/core/workstream/model.js.map +1 -0
- package/dist/core/workstream/name-match.d.ts +8 -0
- package/dist/core/workstream/name-match.js +18 -0
- package/dist/core/workstream/name-match.js.map +1 -0
- package/dist/core/workstream/resolve.d.ts +10 -0
- package/dist/core/workstream/resolve.js +21 -0
- package/dist/core/workstream/resolve.js.map +1 -0
- package/dist/core/workstream/rollup.d.ts +12 -0
- package/dist/core/workstream/rollup.js +17 -0
- package/dist/core/workstream/rollup.js.map +1 -0
- package/dist/core/workstream/work-topics.d.ts +10 -0
- package/dist/core/workstream/work-topics.js +55 -0
- package/dist/core/workstream/work-topics.js.map +1 -0
- package/dist/hook/hook-helpers.d.ts +4 -0
- package/dist/hook/hook-helpers.js +36 -0
- package/dist/hook/hook-helpers.js.map +1 -0
- package/dist/hook/pre-compact-hook.d.ts +23 -0
- package/dist/hook/pre-compact-hook.js +67 -0
- package/dist/hook/pre-compact-hook.js.map +1 -0
- package/dist/hook/prompt-recall-hook.d.ts +38 -0
- package/dist/hook/prompt-recall-hook.js +124 -20
- package/dist/hook/prompt-recall-hook.js.map +1 -1
- package/dist/hook/recall-gate.d.ts +29 -0
- package/dist/hook/recall-gate.js +50 -0
- package/dist/hook/recall-gate.js.map +1 -0
- package/dist/hook/recall-over-http.d.ts +3 -2
- package/dist/hook/recall-over-http.js +26 -13
- package/dist/hook/recall-over-http.js.map +1 -1
- package/dist/hook/recent-context.d.ts +25 -0
- package/dist/hook/recent-context.js +104 -0
- package/dist/hook/recent-context.js.map +1 -0
- package/dist/hook/score-floor.d.ts +27 -0
- package/dist/hook/score-floor.js +42 -0
- package/dist/hook/score-floor.js.map +1 -0
- package/dist/hook/session-end-hook.js +8 -29
- package/dist/hook/session-end-hook.js.map +1 -1
- package/dist/hook/session-start-hook.js +26 -60
- package/dist/hook/session-start-hook.js.map +1 -1
- package/dist/hook/stop-hook.js +24 -60
- package/dist/hook/stop-hook.js.map +1 -1
- package/dist/http/app.d.ts +6 -0
- package/dist/http/app.js +52 -44
- package/dist/http/app.js.map +1 -1
- package/dist/install/setup.js +2 -0
- package/dist/install/setup.js.map +1 -1
- package/dist/llm/build-classifier.d.ts +22 -0
- package/dist/llm/build-classifier.js +42 -0
- package/dist/llm/build-classifier.js.map +1 -0
- package/dist/llm/build-embedder.d.ts +11 -0
- package/dist/llm/build-embedder.js +42 -0
- package/dist/llm/build-embedder.js.map +1 -0
- package/dist/llm/bundled-embedder-client.d.ts +37 -0
- package/dist/llm/bundled-embedder-client.js +90 -0
- package/dist/llm/bundled-embedder-client.js.map +1 -0
- package/dist/llm/classifier-box.d.ts +13 -5
- package/dist/llm/classifier-box.js +28 -6
- package/dist/llm/classifier-box.js.map +1 -1
- package/dist/llm/classifier-egress.d.ts +18 -0
- package/dist/llm/classifier-egress.js +59 -0
- package/dist/llm/classifier-egress.js.map +1 -0
- package/dist/llm/client-shared.d.ts +4 -0
- package/dist/llm/client-shared.js +39 -0
- package/dist/llm/client-shared.js.map +1 -0
- package/dist/llm/deepseek-client.d.ts +20 -0
- package/dist/llm/deepseek-client.js +59 -45
- package/dist/llm/deepseek-client.js.map +1 -1
- package/dist/llm/embedder-info.d.ts +15 -0
- package/dist/llm/embedder-info.js +27 -0
- package/dist/llm/embedder-info.js.map +1 -0
- package/dist/llm/model-quirks.d.ts +4 -0
- package/dist/llm/model-quirks.js +7 -0
- package/dist/llm/model-quirks.js.map +1 -0
- package/dist/llm/naming.d.ts +5 -0
- package/dist/llm/naming.js +20 -0
- package/dist/llm/naming.js.map +1 -0
- package/dist/llm/ollama-client.d.ts +7 -8
- package/dist/llm/ollama-client.js +59 -51
- package/dist/llm/ollama-client.js.map +1 -1
- package/dist/llm/ollama-code-embedder.d.ts +8 -3
- package/dist/llm/ollama-code-embedder.js +14 -24
- package/dist/llm/ollama-code-embedder.js.map +1 -1
- package/dist/llm/openai-code-embedder-client.d.ts +25 -0
- package/dist/llm/openai-code-embedder-client.js +52 -0
- package/dist/llm/openai-code-embedder-client.js.map +1 -0
- package/dist/llm/openai-embedder-client.d.ts +41 -0
- package/dist/llm/openai-embedder-client.js +83 -0
- package/dist/llm/openai-embedder-client.js.map +1 -0
- package/dist/mcp/server.d.ts +69 -2
- package/dist/mcp/server.js +404 -19
- package/dist/mcp/server.js.map +1 -1
- package/dist/ports/code-embedder.d.ts +6 -1
- package/dist/ports/code-exemplar-store.d.ts +5 -0
- package/dist/ports/entity-store.d.ts +35 -0
- package/dist/ports/entity-store.js +7 -0
- package/dist/ports/entity-store.js.map +1 -0
- package/dist/ports/fact-store.d.ts +0 -0
- package/dist/ports/fact-store.js.map +1 -1
- package/dist/ports/llm-client.d.ts +9 -1
- package/dist/ports/outcome.d.ts +85 -0
- package/dist/ports/outcome.js +11 -0
- package/dist/ports/outcome.js.map +1 -0
- package/dist/ports/session-store.d.ts +12 -6
- package/dist/ports/storage.d.ts +7 -30
- package/dist/ports/storage.js +3 -7
- package/dist/ports/storage.js.map +1 -1
- package/dist/ports/transcript-adapter.d.ts +2 -0
- package/dist/ports/workstream-store.d.ts +22 -0
- package/dist/ports/workstream-store.js +2 -0
- package/dist/ports/workstream-store.js.map +1 -0
- package/dist/shared/net.d.ts +3 -0
- package/dist/shared/net.js +4 -0
- package/dist/shared/net.js.map +1 -0
- package/dist/shared/types.d.ts +56 -2
- package/dist/shared/types.js +4 -1
- package/dist/shared/types.js.map +1 -1
- package/dist/ui/assets/{index-CMpQkbQy.js → index-CSaBtgXD.js} +1 -1
- package/dist/ui/index.html +1 -1
- package/fixtures/classifier-gold/README.md +94 -0
- package/fixtures/classifier-gold/reference.json +318 -0
- package/fixtures/classifier-gold/transcripts/01-bug-fix-null-pointer-api.txt +75 -0
- package/fixtures/classifier-gold/transcripts/02-bug-fix-race-condition-queue.txt +77 -0
- package/fixtures/classifier-gold/transcripts/03-bug-fix-jwt-clock-skew.txt +86 -0
- package/fixtures/classifier-gold/transcripts/04-feature-webhook-retry.txt +95 -0
- package/fixtures/classifier-gold/transcripts/05-feature-csv-export.txt +86 -0
- package/fixtures/classifier-gold/transcripts/06-feature-rate-limiting.txt +61 -0
- package/fixtures/classifier-gold/transcripts/07-refactor-db-abstraction.txt +72 -0
- package/fixtures/classifier-gold/transcripts/08-refactor-config-loading.txt +89 -0
- package/fixtures/classifier-gold/transcripts/09-ops-docker-staging.txt +94 -0
- package/fixtures/classifier-gold/transcripts/10-ops-nginx-ssl.txt +121 -0
- package/fixtures/classifier-gold/transcripts/11-ops-postgres-migration.txt +74 -0
- package/fixtures/classifier-gold/transcripts/12-ops-cron-debugging.txt +73 -0
- package/fixtures/classifier-gold/transcripts/13-research-vector-db-comparison.txt +59 -0
- package/fixtures/classifier-gold/transcripts/14-research-oauth-provider.txt +74 -0
- package/fixtures/classifier-gold/transcripts/15-writing-api-docs.txt +154 -0
- package/fixtures/classifier-gold/transcripts/16-meeting-sprint-planning.txt +69 -0
- package/fixtures/classifier-gold/transcripts/17-trivial-list-files.txt +14 -0
- package/fixtures/classifier-gold/transcripts/18-trivial-version-check.txt +21 -0
- package/fixtures/classifier-gold/transcripts/19-trivial-syntax-help.txt +29 -0
- package/fixtures/classifier-gold/transcripts/20-trivial-read-package-json.txt +41 -0
- package/migrations/000_initial_schema.sql +1 -1
- package/migrations/024_backfill_exemplar_repo_basename.sql +32 -0
- package/migrations/025_workstreams.sql +30 -0
- package/migrations/026_embedding_config.sql +12 -0
- package/migrations/027_drop_legacy_session_embeddings.sql +7 -0
- package/migrations/028_classifier_provenance.sql +5 -0
- package/migrations/029_project_scope.sql +21 -0
- package/migrations/032_session_derivables.sql +11 -0
- package/migrations/pg/001_initial.sql +34 -0
- package/migrations/pg/019_split_replaces.sql +16 -7
- package/migrations/pg/025_workstreams.sql +34 -0
- package/migrations/pg/026_embedding_config.sql +12 -0
- package/migrations/pg/028_classifier_provenance.sql +5 -0
- package/migrations/pg/029_entity_variants.sql +9 -0
- package/migrations/pg/030_project_scope.sql +23 -0
- package/migrations/pg/031_widen_session_edges_kind.sql +11 -0
- package/migrations/pg/032_session_derivables.sql +17 -0
- package/nlm/index.js +405 -39
- package/package.json +12 -2
- package/plugin/.codex-plugin/plugin.json +2 -2
- package/plugin/scripts/prompt-recall-hook.mjs +413 -43
- package/plugin/scripts/session-start-hook.mjs +295 -61
- package/plugin/scripts/stop-hook.mjs +89 -66
- package/plugin-hermes-agent/__init__.py +2 -1
- package/templates/agent-contract/README.md +24 -0
- package/templates/agent-contract/claude-code.md +40 -0
- package/templates/agent-contract/generic.md +38 -0
- package/dist/core/embedding/embed-normalize.d.ts +0 -28
- package/dist/core/embedding/embed-normalize.js +0 -98
- package/dist/core/embedding/embed-normalize.js.map +0 -1
- package/dist/core/storage/pg-tx-context.d.ts +0 -52
- package/dist/core/storage/pg-tx-context.js +0 -149
- package/dist/core/storage/pg-tx-context.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"corpus-state.js","sourceRoot":"","sources":["../../../src/core/health/corpus-state.ts"],"names":[],"mappings":"AAOA,IAAI,QAAQ,GAA0B,IAAI,CAAC;AAE3C,MAAM,UAAU,iBAAiB,CAAC,CAAiB;IACjD,QAAQ,GAAG,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,QAAQ,GAAG,IAAI,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function tryAcquire(): boolean;
|
|
2
|
+
export declare function release(): void;
|
|
3
|
+
export interface EmbedInflightSnapshot {
|
|
4
|
+
readonly current: number;
|
|
5
|
+
readonly cap: number;
|
|
6
|
+
readonly shedTotal: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function inflightSnapshot(): EmbedInflightSnapshot;
|
|
9
|
+
export declare function resetForTests(): void;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const DEFAULT_CAP = 4;
|
|
2
|
+
function parseCap(raw) {
|
|
3
|
+
if (raw === undefined)
|
|
4
|
+
return DEFAULT_CAP;
|
|
5
|
+
const n = parseInt(raw, 10);
|
|
6
|
+
return Number.isFinite(n) && n > 0 ? n : DEFAULT_CAP;
|
|
7
|
+
}
|
|
8
|
+
const cap = parseCap(process.env["NLM_RECALL_MAX_INFLIGHT_EMBEDS"]);
|
|
9
|
+
let current = 0;
|
|
10
|
+
let shedTotal = 0;
|
|
11
|
+
export function tryAcquire() {
|
|
12
|
+
if (current >= cap) {
|
|
13
|
+
shedTotal++;
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
current++;
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
export function release() {
|
|
20
|
+
if (current > 0)
|
|
21
|
+
current--;
|
|
22
|
+
}
|
|
23
|
+
export function inflightSnapshot() {
|
|
24
|
+
return { current, cap, shedTotal };
|
|
25
|
+
}
|
|
26
|
+
export function resetForTests() {
|
|
27
|
+
current = 0;
|
|
28
|
+
shedTotal = 0;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=embed-inflight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embed-inflight.js","sourceRoot":"","sources":["../../../src/core/health/embed-inflight.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG,CAAC,CAAC;AAEtB,SAAS,QAAQ,CAAC,GAAuB;IACvC,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC;IAC1C,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC5B,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;AACvD,CAAC;AAED,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC,CAAC;AAEpE,IAAI,OAAO,GAAG,CAAC,CAAC;AAChB,IAAI,SAAS,GAAG,CAAC,CAAC;AAElB,MAAM,UAAU,UAAU;IACxB,IAAI,OAAO,IAAI,GAAG,EAAE,CAAC;QACnB,SAAS,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,EAAE,CAAC;IACV,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,IAAI,OAAO,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;AAC7B,CAAC;AAQD,MAAM,UAAU,gBAAgB;IAC9B,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,GAAG,CAAC,CAAC;IACZ,SAAS,GAAG,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { EmbeddingLane } from "../embedding/embedding-config.js";
|
|
2
|
+
export type EmbeddingLaneHealth = "unknown" | "ok" | "stale";
|
|
3
|
+
export declare function setLaneHealth(lane: EmbeddingLane, health: EmbeddingLaneHealth): void;
|
|
4
|
+
export declare function laneHealth(lane: EmbeddingLane): EmbeddingLaneHealth;
|
|
5
|
+
export declare function laneHealthSnapshot(): Readonly<Record<EmbeddingLane, EmbeddingLaneHealth>>;
|
|
6
|
+
export declare function resetLaneHealthForTests(): void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const state = {
|
|
2
|
+
prose: "unknown",
|
|
3
|
+
code: "unknown",
|
|
4
|
+
};
|
|
5
|
+
export function setLaneHealth(lane, health) {
|
|
6
|
+
state[lane] = health;
|
|
7
|
+
}
|
|
8
|
+
export function laneHealth(lane) {
|
|
9
|
+
return state[lane];
|
|
10
|
+
}
|
|
11
|
+
export function laneHealthSnapshot() {
|
|
12
|
+
return Object.freeze({ ...state });
|
|
13
|
+
}
|
|
14
|
+
export function resetLaneHealthForTests() {
|
|
15
|
+
state.prose = "unknown";
|
|
16
|
+
state.code = "unknown";
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=embedding-lane-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding-lane-state.js","sourceRoot":"","sources":["../../../src/core/health/embedding-lane-state.ts"],"names":[],"mappings":"AAIA,MAAM,KAAK,GAA+C;IACxD,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,SAAS;CAChB,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,IAAmB,EAAE,MAA2B;IAC5E,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAmB;IAC5C,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC;IACxB,KAAK,CAAC,IAAI,GAAG,SAAS,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface WarmupState {
|
|
2
|
+
fts5: boolean;
|
|
3
|
+
textEmbedder: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare function markWarm(stage: keyof WarmupState): void;
|
|
6
|
+
export declare function warmupSnapshot(): {
|
|
7
|
+
fts5: boolean;
|
|
8
|
+
textEmbedder: boolean;
|
|
9
|
+
ready: boolean;
|
|
10
|
+
};
|
|
11
|
+
export declare function resetWarmupState(): void;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const state = { fts5: false, textEmbedder: false };
|
|
2
|
+
export function markWarm(stage) {
|
|
3
|
+
state[stage] = true;
|
|
4
|
+
}
|
|
5
|
+
export function warmupSnapshot() {
|
|
6
|
+
return { fts5: state.fts5, textEmbedder: state.textEmbedder, ready: state.fts5 && state.textEmbedder };
|
|
7
|
+
}
|
|
8
|
+
export function resetWarmupState() {
|
|
9
|
+
state.fts5 = false;
|
|
10
|
+
state.textEmbedder = false;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=warmup-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warmup-state.js","sourceRoot":"","sources":["../../../src/core/health/warmup-state.ts"],"names":[],"mappings":"AAKA,MAAM,KAAK,GAAgB,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AAEhE,MAAM,UAAU,QAAQ,CAAC,KAAwB;IAC/C,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;AACzG,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC;IACnB,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC;AAC7B,CAAC"}
|
|
@@ -19,7 +19,7 @@ export declare function shellQuote(arg: string): string;
|
|
|
19
19
|
*/
|
|
20
20
|
export declare function cmdQuote(arg: string): string;
|
|
21
21
|
export declare function buildHookCommand(execPath: string, hookJs: string, mode: "shadow" | "live", targetPlatform?: NodeJS.Platform): string;
|
|
22
|
-
export type ClaudeHookEvent = "UserPromptSubmit" | "SessionStart" | "SessionEnd" | "Stop" | "PreCompact" | "
|
|
22
|
+
export type ClaudeHookEvent = "UserPromptSubmit" | "SessionStart" | "SessionEnd" | "Stop" | "PreCompact" | "PostToolUse" | "PreToolUse";
|
|
23
23
|
export declare function addHook(settingsPath: string, command: string, event?: ClaudeHookEvent): void;
|
|
24
24
|
/**
|
|
25
25
|
* Remove the NLM-tagged hook entry from one event (default UserPromptSubmit)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-settings.js","sourceRoot":"","sources":["../../../src/core/hook/claude-settings.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,qEAAqE;AACrE,uEAAuE;AACvE,gCAAgC;AAChC,MAAM,mBAAmB,GAAG;IAC1B,uBAAuB;IACvB,qBAAqB;IACrB,cAAc;IACd,uBAAuB;IACvB,qBAAqB;
|
|
1
|
+
{"version":3,"file":"claude-settings.js","sourceRoot":"","sources":["../../../src/core/hook/claude-settings.ts"],"names":[],"mappings":"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"}
|
package/dist/core/hook/gate.d.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Prompt gate for the recall hook. Pure — no I/O.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* Two excluders, both conservative (a wrong exclusion skips useful recall — the
|
|
5
|
+
* failure this feature exists to prevent — so both sets are deliberately tight):
|
|
6
|
+
*
|
|
7
|
+
* - "skip": no user query to serve. Harness-injected events (IDE selections,
|
|
8
|
+
* task notifications, system reminders), bare acknowledgements ("ok", "do
|
|
9
|
+
* it"), and empty/punctuation prompts. Measured: ~41% of historical hook
|
|
10
|
+
* injections fired on these — pure context flooding that can never be cited.
|
|
11
|
+
* SAFE by construction: any prompt that still carries real user content after
|
|
12
|
+
* stripping harness boilerplate falls through and still fires.
|
|
13
|
+
* - "generative": high-precision generative openers ("write", "draft", …).
|
|
14
|
+
*
|
|
15
|
+
* Everything else defaults to "evaluate" (run recall).
|
|
9
16
|
*/
|
|
10
|
-
export type PromptClass = "generative" | "evaluate";
|
|
17
|
+
export type PromptClass = "generative" | "evaluate" | "skip";
|
|
11
18
|
export declare function classifyPrompt(prompt: string): PromptClass;
|
package/dist/core/hook/gate.js
CHANGED
|
@@ -1,19 +1,60 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Prompt gate for the recall hook. Pure — no I/O.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* Two excluders, both conservative (a wrong exclusion skips useful recall — the
|
|
5
|
+
* failure this feature exists to prevent — so both sets are deliberately tight):
|
|
6
|
+
*
|
|
7
|
+
* - "skip": no user query to serve. Harness-injected events (IDE selections,
|
|
8
|
+
* task notifications, system reminders), bare acknowledgements ("ok", "do
|
|
9
|
+
* it"), and empty/punctuation prompts. Measured: ~41% of historical hook
|
|
10
|
+
* injections fired on these — pure context flooding that can never be cited.
|
|
11
|
+
* SAFE by construction: any prompt that still carries real user content after
|
|
12
|
+
* stripping harness boilerplate falls through and still fires.
|
|
13
|
+
* - "generative": high-precision generative openers ("write", "draft", …).
|
|
14
|
+
*
|
|
15
|
+
* Everything else defaults to "evaluate" (run recall).
|
|
9
16
|
*/
|
|
10
17
|
const LEADING_FILLER = /^(please|can you|could you|would you|will you|i need you to|i'd like you to|i want you to|i would like you to|help me|let's|lets|hey|ok|okay)\b[\s,]*/i;
|
|
11
18
|
const GENERATIVE_OPENER = /^(write|draft|create|compose|generate|brainstorm|design|outline|sketch|invent|rename|come up with)\b/i;
|
|
19
|
+
// Harness-injected tags. These are emitted by the agent runtime, not typed by
|
|
20
|
+
// the user, so they carry no query intent on their own. We strip the whole
|
|
21
|
+
// block (well-formed `<tag>…</tag>`, or to end-of-string if unclosed) — a real
|
|
22
|
+
// user query appended after the block survives and still triggers recall.
|
|
23
|
+
const HARNESS_TAGS = [
|
|
24
|
+
"ide_selection",
|
|
25
|
+
"ide_opened_file",
|
|
26
|
+
"ide_closed_file",
|
|
27
|
+
"ide_diagnostics",
|
|
28
|
+
"ide_recently_modified_file",
|
|
29
|
+
"task-notification",
|
|
30
|
+
"system-reminder",
|
|
31
|
+
"command-name",
|
|
32
|
+
"command-message",
|
|
33
|
+
"command-args",
|
|
34
|
+
"local-command-stdout",
|
|
35
|
+
"local-command-stderr",
|
|
36
|
+
];
|
|
37
|
+
const HARNESS_BLOCK = new RegExp(`<(${HARNESS_TAGS.join("|")})\\b[^>]*>[\\s\\S]*?(?:</\\1>|$)`, "gi");
|
|
38
|
+
// Whole-prompt acknowledgements — matched against the entire residual, so a
|
|
39
|
+
// real query that merely opens with an ack word ("ok so why does X…") is NOT
|
|
40
|
+
// caught. A bare ack has no recall value.
|
|
41
|
+
const ACK_ONLY = /^(yes|yep|yeah|sure|ok|okay|k|thanks|thank you|ty|done|nice|cool|great|perfect|continue|next|go|go ahead|do it|yes please|sounds good|good|got it|right|correct)\W*$/i;
|
|
42
|
+
function contentWordCount(s) {
|
|
43
|
+
const m = s.match(/[A-Za-z0-9]{2,}/g);
|
|
44
|
+
return m ? m.length : 0;
|
|
45
|
+
}
|
|
12
46
|
export function classifyPrompt(prompt) {
|
|
13
|
-
let p = prompt.trim();
|
|
47
|
+
let p = prompt.replace(HARNESS_BLOCK, " ").replace(/\s+/g, " ").trim();
|
|
48
|
+
if (contentWordCount(p) === 0)
|
|
49
|
+
return "skip"; // harness-only / empty / punctuation
|
|
50
|
+
if (ACK_ONLY.test(p))
|
|
51
|
+
return "skip"; // bare acknowledgement
|
|
14
52
|
for (let i = 0; i < 3 && LEADING_FILLER.test(p); i++) {
|
|
15
53
|
p = p.replace(LEADING_FILLER, "");
|
|
16
54
|
}
|
|
55
|
+
p = p.trim();
|
|
56
|
+
if (contentWordCount(p) === 0)
|
|
57
|
+
return "skip"; // was pure leading filler ("ok", "lets")
|
|
17
58
|
return GENERATIVE_OPENER.test(p) ? "generative" : "evaluate";
|
|
18
59
|
}
|
|
19
60
|
//# sourceMappingURL=gate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../../src/core/hook/gate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../../src/core/hook/gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,MAAM,cAAc,GAClB,wJAAwJ,CAAC;AAE3J,MAAM,iBAAiB,GACrB,uGAAuG,CAAC;AAE1G,8EAA8E;AAC9E,2EAA2E;AAC3E,+EAA+E;AAC/E,0EAA0E;AAC1E,MAAM,YAAY,GAAG;IACnB,eAAe;IACf,iBAAiB;IACjB,iBAAiB;IACjB,iBAAiB;IACjB,4BAA4B;IAC5B,mBAAmB;IACnB,iBAAiB;IACjB,cAAc;IACd,iBAAiB;IACjB,cAAc;IACd,sBAAsB;IACtB,sBAAsB;CACvB,CAAC;AACF,MAAM,aAAa,GAAG,IAAI,MAAM,CAC9B,KAAK,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,kCAAkC,EAC7D,IAAI,CACL,CAAC;AAEF,4EAA4E;AAC5E,6EAA6E;AAC7E,0CAA0C;AAC1C,MAAM,QAAQ,GACZ,uKAAuK,CAAC;AAE1K,SAAS,gBAAgB,CAAC,CAAS;IACjC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACtC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,IAAI,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACvE,IAAI,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,CAAC,qCAAqC;IACnF,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC,CAAC,uBAAuB;IAE5D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACrD,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACpC,CAAC;IACD,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACb,IAAI,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,CAAC,yCAAyC;IAEvF,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC;AAC/D,CAAC"}
|
|
@@ -21,5 +21,10 @@ export interface HookLogEntry {
|
|
|
21
21
|
readonly wouldInject: ReadonlyArray<string>;
|
|
22
22
|
readonly estTokens: number;
|
|
23
23
|
readonly mode: "shadow" | "live";
|
|
24
|
+
/** Per-candidate relevance-gate decisions, when the recall gate ran. */
|
|
25
|
+
readonly gateDecisions?: ReadonlyArray<{
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly gate: "relevant" | "irrelevant";
|
|
28
|
+
}>;
|
|
24
29
|
}
|
|
25
30
|
export declare function appendHookLog(entry: HookLogEntry): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-log.js","sourceRoot":"","sources":["../../../src/core/hook/hook-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"hook-log.js","sourceRoot":"","sources":["../../../src/core/hook/hook-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAgB1C,SAAS,OAAO;IACd,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAmB;IAC/C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;QACvB,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,+EAA+E;QAC/E,cAAc,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,+CAA+C;IACjD,CAAC;AACH,CAAC"}
|
package/dist/core/hook/memo.d.ts
CHANGED
|
@@ -12,6 +12,18 @@
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function loadSurfaced(conversationId: string): Set<string>;
|
|
14
14
|
export declare function recordSurfaced(conversationId: string, ids: ReadonlyArray<string>): void;
|
|
15
|
+
/**
|
|
16
|
+
* Reverse lookup: which conversation most recently surfaced `sessionId`?
|
|
17
|
+
*
|
|
18
|
+
* cite_session callers rarely pass conversation_id, so the citation would be
|
|
19
|
+
* logged as the unjoinable "mcp_tool" placeholder (NLM #345). The hook already
|
|
20
|
+
* recorded a per-conversation memo of what it surfaced; scan those (few, since
|
|
21
|
+
* they're cleared on SessionEnd) for the session and return the most-recently-
|
|
22
|
+
* written conversation. Returns null when no live conversation surfaced it.
|
|
23
|
+
*
|
|
24
|
+
* Defensive: any I/O error yields null so cite_session never breaks.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveConversationForSession(sessionId: string): string | null;
|
|
15
27
|
/**
|
|
16
28
|
* Delete the memo file for a closed conversation. Called by the SessionEnd
|
|
17
29
|
* hook so memo files don't accumulate forever. Returns true if a file was
|
package/dist/core/hook/memo.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* memo, and a write failure is swallowed. The hook must never break on memo
|
|
11
11
|
* I/O.
|
|
12
12
|
*/
|
|
13
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
14
14
|
import { homedir } from "node:os";
|
|
15
15
|
import { join } from "node:path";
|
|
16
16
|
function stateDir() {
|
|
@@ -46,6 +46,46 @@ export function recordSurfaced(conversationId, ids) {
|
|
|
46
46
|
// Memo write failure must never break the hook.
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Reverse lookup: which conversation most recently surfaced `sessionId`?
|
|
51
|
+
*
|
|
52
|
+
* cite_session callers rarely pass conversation_id, so the citation would be
|
|
53
|
+
* logged as the unjoinable "mcp_tool" placeholder (NLM #345). The hook already
|
|
54
|
+
* recorded a per-conversation memo of what it surfaced; scan those (few, since
|
|
55
|
+
* they're cleared on SessionEnd) for the session and return the most-recently-
|
|
56
|
+
* written conversation. Returns null when no live conversation surfaced it.
|
|
57
|
+
*
|
|
58
|
+
* Defensive: any I/O error yields null so cite_session never breaks.
|
|
59
|
+
*/
|
|
60
|
+
export function resolveConversationForSession(sessionId) {
|
|
61
|
+
try {
|
|
62
|
+
const dir = stateDir();
|
|
63
|
+
if (!existsSync(dir))
|
|
64
|
+
return null;
|
|
65
|
+
let best = null;
|
|
66
|
+
for (const file of readdirSync(dir)) {
|
|
67
|
+
if (!file.endsWith(".json"))
|
|
68
|
+
continue;
|
|
69
|
+
const path = join(dir, file);
|
|
70
|
+
try {
|
|
71
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
72
|
+
if (!Array.isArray(parsed) || !parsed.includes(sessionId))
|
|
73
|
+
continue;
|
|
74
|
+
const mtimeMs = statSync(path).mtimeMs;
|
|
75
|
+
if (best === null || mtimeMs > best.mtimeMs) {
|
|
76
|
+
best = { conversationId: file.slice(0, -".json".length), mtimeMs };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Skip a corrupt or vanished memo file.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return best?.conversationId ?? null;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
49
89
|
/**
|
|
50
90
|
* Delete the memo file for a closed conversation. Called by the SessionEnd
|
|
51
91
|
* hook so memo files don't accumulate forever. Returns true if a file was
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memo.js","sourceRoot":"","sources":["../../../src/core/hook/memo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"memo.js","sourceRoot":"","sources":["../../../src/core/hook/memo.ts"],"names":[],"mappings":"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"}
|
|
@@ -29,4 +29,5 @@ export interface PointerExemplar {
|
|
|
29
29
|
readonly repo: string;
|
|
30
30
|
readonly taskContext: string;
|
|
31
31
|
}
|
|
32
|
+
export declare function truncateSummary(s: string, max?: number): string;
|
|
32
33
|
export declare function formatPointerBlock(hits: ReadonlyArray<PointerHit>, facts?: ReadonlyArray<PointerFact>, exemplars?: ReadonlyArray<PointerExemplar>): string;
|
|
@@ -11,6 +11,27 @@
|
|
|
11
11
|
* `<subject> <predicate>: <value> [N sessions]` so the agent has structured
|
|
12
12
|
* context alongside the session pointers.
|
|
13
13
|
*/
|
|
14
|
+
export function truncateSummary(s, max = 200) {
|
|
15
|
+
if (s.length <= max)
|
|
16
|
+
return s;
|
|
17
|
+
const window = s.slice(0, max);
|
|
18
|
+
const last = window[window.length - 1];
|
|
19
|
+
if ((last === "." || last === "!" || last === "?") && window.length - 1 >= 60) {
|
|
20
|
+
return window;
|
|
21
|
+
}
|
|
22
|
+
for (let i = window.length - 2; i >= 60; i--) {
|
|
23
|
+
const c = window[i];
|
|
24
|
+
if ((c === "." || c === "!" || c === "?") && window[i + 1] === " ") {
|
|
25
|
+
return s.slice(0, i + 1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
for (let i = window.length - 1; i >= 60; i--) {
|
|
29
|
+
if (window[i] === " ") {
|
|
30
|
+
return s.slice(0, i) + " ...";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return window + " ...";
|
|
34
|
+
}
|
|
14
35
|
export function formatPointerBlock(hits, facts = [], exemplars = []) {
|
|
15
36
|
if (hits.length === 0 && facts.length === 0 && exemplars.length === 0)
|
|
16
37
|
return "";
|
|
@@ -20,7 +41,7 @@ export function formatPointerBlock(hits, facts = [], exemplars = []) {
|
|
|
20
41
|
for (const h of hits) {
|
|
21
42
|
const datePart = h.startedAt.slice(0, 10);
|
|
22
43
|
if (h.summary) {
|
|
23
|
-
out.push(`- ${h.id} · ${h.label} (${datePart}) — ${h.summary
|
|
44
|
+
out.push(`- ${h.id} · ${h.label} (${datePart}) — ${truncateSummary(h.summary)}`);
|
|
24
45
|
}
|
|
25
46
|
else {
|
|
26
47
|
out.push(`- ${h.id} · ${h.label} (${datePart})`);
|
|
@@ -42,7 +63,7 @@ export function formatPointerBlock(hits, facts = [], exemplars = []) {
|
|
|
42
63
|
out.push("## Related code exemplars (nlm-memory)");
|
|
43
64
|
for (const e of exemplars) {
|
|
44
65
|
const langPart = e.lang ? `${e.lang} · ` : "";
|
|
45
|
-
out.push(`- [${e.outcome}] ${langPart}${e.repo} - ${e.taskContext
|
|
66
|
+
out.push(`- [${e.outcome}] ${langPart}${e.repo} - ${truncateSummary(e.taskContext)}`);
|
|
46
67
|
}
|
|
47
68
|
}
|
|
48
69
|
const tools = exemplars.length > 0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pointer-block.js","sourceRoot":"","sources":["../../../src/core/hook/pointer-block.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAuBH,MAAM,UAAU,kBAAkB,CAChC,IAA+B,EAC/B,QAAoC,EAAE,EACtC,YAA4C,EAAE;IAE9C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACjF,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,GAAG,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;QAC7D,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,QAAQ,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1C,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;gBACd,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,KAAK,QAAQ,OAAO,
|
|
1
|
+
{"version":3,"file":"pointer-block.js","sourceRoot":"","sources":["../../../src/core/hook/pointer-block.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Returns null when the message is too conversational to produce a useful
|
|
3
|
-
* query — the caller should skip
|
|
3
|
+
* query, or is a harness-injected system message — the caller should skip
|
|
4
|
+
* recall entirely in that case.
|
|
4
5
|
*/
|
|
5
6
|
export declare function extractRecallQuery(prompt: string): string | null;
|
|
@@ -18,11 +18,20 @@ const STOPWORDS = new Set([
|
|
|
18
18
|
]);
|
|
19
19
|
const MIN_CONTENT_WORDS = 2;
|
|
20
20
|
const MIN_WORD_LEN = 3;
|
|
21
|
+
// Harness-injected turns (task-completion notifications, slash-command wrappers,
|
|
22
|
+
// local-command output, background context) arrive on the prompt surface but are
|
|
23
|
+
// never user queries. Recalling against them floods context with irrelevant
|
|
24
|
+
// sessions (measured: 7.2% of historical fires). Skip any message that opens
|
|
25
|
+
// with one of these tags.
|
|
26
|
+
const SYSTEM_MESSAGE_PREFIX = /^<(task-notification|command-name|command-message|command-args|local-command-stdout|local-command-caveat|output-file|system-reminder)\b/;
|
|
21
27
|
/**
|
|
22
28
|
* Returns null when the message is too conversational to produce a useful
|
|
23
|
-
* query — the caller should skip
|
|
29
|
+
* query, or is a harness-injected system message — the caller should skip
|
|
30
|
+
* recall entirely in that case.
|
|
24
31
|
*/
|
|
25
32
|
export function extractRecallQuery(prompt) {
|
|
33
|
+
if (SYSTEM_MESSAGE_PREFIX.test(prompt.trim()))
|
|
34
|
+
return null;
|
|
26
35
|
const tokens = prompt
|
|
27
36
|
.trim()
|
|
28
37
|
.split(/\s+/)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-extract.js","sourceRoot":"","sources":["../../../src/core/hook/query-extract.ts"],"names":[],"mappings":"AAAA,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;IACxB,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO;IACnE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACnE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO;IACzD,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM;IAC7D,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK;IAC9D,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI;IAChE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;IAClE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IAChE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS;IAC/D,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK;IAC9D,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM;IACrE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK;IAC1D,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM;IAC9D,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IACjC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS;IAC7D,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM;CACrD,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAC5B,MAAM,YAAY,GAAG,CAAC,CAAC;AAEvB
|
|
1
|
+
{"version":3,"file":"query-extract.js","sourceRoot":"","sources":["../../../src/core/hook/query-extract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve which Claude Code conversation triggered a recall pull, by scanning
|
|
3
|
+
* the N most-recently-modified transcript JSONL files under ~/.claude/projects
|
|
4
|
+
* for the exact query string.
|
|
5
|
+
*
|
|
6
|
+
* When an agent calls a recall tool, the runtime has already written the
|
|
7
|
+
* tool_use block (containing the query string) to its transcript before the
|
|
8
|
+
* MCP handler runs. Scanning the tail of the newest transcripts gives a
|
|
9
|
+
* deterministic, cheap join between a pull log entry and its source
|
|
10
|
+
* conversation, without requiring the agent to pass conversation_id explicitly.
|
|
11
|
+
*
|
|
12
|
+
* Non-Claude-Code runtimes do not write to ~/.claude/projects, so they
|
|
13
|
+
* resolve to null and remain unattributed.
|
|
14
|
+
*
|
|
15
|
+
* Fail-open: any I/O error returns null so the recall path never breaks.
|
|
16
|
+
*/
|
|
17
|
+
export interface ResolveByQueryOpts {
|
|
18
|
+
readonly rootDir?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Scan the N most-recently-modified JSONL transcripts under rootDir for the
|
|
22
|
+
* exact query string. Returns the conversation id (filename stem without
|
|
23
|
+
* .jsonl) of the first match, or null if none found.
|
|
24
|
+
*
|
|
25
|
+
* Short queries (< MIN_QUERY_LEN chars) are always skipped: they are too
|
|
26
|
+
* ambiguous to produce a reliable match.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveConversationByQuery(query: string, opts?: ResolveByQueryOpts): string | null;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve which Claude Code conversation triggered a recall pull, by scanning
|
|
3
|
+
* the N most-recently-modified transcript JSONL files under ~/.claude/projects
|
|
4
|
+
* for the exact query string.
|
|
5
|
+
*
|
|
6
|
+
* When an agent calls a recall tool, the runtime has already written the
|
|
7
|
+
* tool_use block (containing the query string) to its transcript before the
|
|
8
|
+
* MCP handler runs. Scanning the tail of the newest transcripts gives a
|
|
9
|
+
* deterministic, cheap join between a pull log entry and its source
|
|
10
|
+
* conversation, without requiring the agent to pass conversation_id explicitly.
|
|
11
|
+
*
|
|
12
|
+
* Non-Claude-Code runtimes do not write to ~/.claude/projects, so they
|
|
13
|
+
* resolve to null and remain unattributed.
|
|
14
|
+
*
|
|
15
|
+
* Fail-open: any I/O error returns null so the recall path never breaks.
|
|
16
|
+
*/
|
|
17
|
+
import { closeSync, fstatSync, openSync, readdirSync, readSync, statSync } from "node:fs";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
import { homedir } from "node:os";
|
|
20
|
+
const MIN_QUERY_LEN = 12;
|
|
21
|
+
const TAIL_BYTES = 64 * 1024;
|
|
22
|
+
const MAX_CANDIDATES = 5;
|
|
23
|
+
function defaultRootDir() {
|
|
24
|
+
return process.env["NLM_CLAUDE_PROJECTS_ROOT"] ?? join(homedir(), ".claude", "projects");
|
|
25
|
+
}
|
|
26
|
+
function tailRead(path, maxBytes) {
|
|
27
|
+
const fd = openSync(path, "r");
|
|
28
|
+
try {
|
|
29
|
+
const size = fstatSync(fd).size;
|
|
30
|
+
const start = size > maxBytes ? size - maxBytes : 0;
|
|
31
|
+
const len = size - start;
|
|
32
|
+
if (len <= 0)
|
|
33
|
+
return "";
|
|
34
|
+
const buf = Buffer.alloc(len);
|
|
35
|
+
readSync(fd, buf, 0, len, start);
|
|
36
|
+
return buf.toString("utf8");
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
closeSync(fd);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function collectJsonlFiles(dir) {
|
|
43
|
+
const results = [];
|
|
44
|
+
try {
|
|
45
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
46
|
+
const full = join(dir, entry.name);
|
|
47
|
+
if (entry.isDirectory()) {
|
|
48
|
+
results.push(...collectJsonlFiles(full));
|
|
49
|
+
}
|
|
50
|
+
else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
51
|
+
try {
|
|
52
|
+
const st = statSync(full);
|
|
53
|
+
results.push({ path: full, stem: entry.name.slice(0, -".jsonl".length), mtimeMs: st.mtimeMs });
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// skip files that vanish or are unreadable
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// skip unreadable directories
|
|
63
|
+
}
|
|
64
|
+
return results;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Scan the N most-recently-modified JSONL transcripts under rootDir for the
|
|
68
|
+
* exact query string. Returns the conversation id (filename stem without
|
|
69
|
+
* .jsonl) of the first match, or null if none found.
|
|
70
|
+
*
|
|
71
|
+
* Short queries (< MIN_QUERY_LEN chars) are always skipped: they are too
|
|
72
|
+
* ambiguous to produce a reliable match.
|
|
73
|
+
*/
|
|
74
|
+
export function resolveConversationByQuery(query, opts) {
|
|
75
|
+
try {
|
|
76
|
+
if (query.length < MIN_QUERY_LEN)
|
|
77
|
+
return null;
|
|
78
|
+
const rootDir = opts?.rootDir ?? defaultRootDir();
|
|
79
|
+
const files = collectJsonlFiles(rootDir)
|
|
80
|
+
.sort((a, b) => b.mtimeMs - a.mtimeMs)
|
|
81
|
+
.slice(0, MAX_CANDIDATES);
|
|
82
|
+
for (const { path, stem } of files) {
|
|
83
|
+
try {
|
|
84
|
+
const tail = tailRead(path, TAIL_BYTES);
|
|
85
|
+
if (tail.includes(query))
|
|
86
|
+
return stem;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// skip unreadable or vanished files
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=resolve-conversation-by-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-conversation-by-query.js","sourceRoot":"","sources":["../../../src/core/hook/resolve-conversation-by-query.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,5 +18,13 @@ export interface SelectParams {
|
|
|
18
18
|
readonly scoreThreshold: number;
|
|
19
19
|
readonly perFireCap: number;
|
|
20
20
|
readonly perConversationCap: number;
|
|
21
|
+
/**
|
|
22
|
+
* Drop tail hits scoring below this fraction of the fire's median score (0 =
|
|
23
|
+
* off). Scale-invariant — a ratio — so it works on raw BM25 or normalized
|
|
24
|
+
* scores and ports across installs unchanged. The top hit (>= median) always
|
|
25
|
+
* survives, so this trims weak tail hits; it does not suppress an off-topic
|
|
26
|
+
* fire. Calibrated via scripts/eval/floor-calibration.ts (#284).
|
|
27
|
+
*/
|
|
28
|
+
readonly relativeFloor?: number;
|
|
21
29
|
}
|
|
22
30
|
export declare function selectHits(params: SelectParams): ReadonlyArray<RecallHitInput>;
|