nlm-memory 0.20.1 → 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.
Files changed (168) hide show
  1. package/README.md +2 -0
  2. package/dist/cli/digest.js +39 -1
  3. package/dist/cli/digest.js.map +1 -1
  4. package/dist/cli/nlm.js +106 -6
  5. package/dist/cli/nlm.js.map +1 -1
  6. package/dist/cli/scope-backfill.d.ts +34 -0
  7. package/dist/cli/scope-backfill.js +237 -0
  8. package/dist/cli/scope-backfill.js.map +1 -0
  9. package/dist/cli/scope-coverage.d.ts +44 -0
  10. package/dist/cli/scope-coverage.js +205 -0
  11. package/dist/cli/scope-coverage.js.map +1 -0
  12. package/dist/core/adapters/claude-code.d.ts +14 -0
  13. package/dist/core/adapters/claude-code.js +30 -0
  14. package/dist/core/adapters/claude-code.js.map +1 -1
  15. package/dist/core/dataset/build-dataset.js +1 -0
  16. package/dist/core/dataset/build-dataset.js.map +1 -1
  17. package/dist/core/digest/compose.d.ts +3 -3
  18. package/dist/core/digest/compose.js +16 -17
  19. package/dist/core/digest/compose.js.map +1 -1
  20. package/dist/core/digest/hook-injection.d.ts +43 -0
  21. package/dist/core/digest/hook-injection.js +79 -0
  22. package/dist/core/digest/hook-injection.js.map +1 -0
  23. package/dist/core/exemplars/capture-from-session.d.ts +1 -0
  24. package/dist/core/exemplars/capture-from-session.js +1 -1
  25. package/dist/core/exemplars/capture-from-session.js.map +1 -1
  26. package/dist/core/exemplars/extract-exemplar.d.ts +2 -0
  27. package/dist/core/exemplars/extract-exemplar.js +7 -1
  28. package/dist/core/exemplars/extract-exemplar.js.map +1 -1
  29. package/dist/core/exemplars/ingest-exemplar.d.ts +1 -0
  30. package/dist/core/exemplars/ingest-exemplar.js +1 -0
  31. package/dist/core/exemplars/ingest-exemplar.js.map +1 -1
  32. package/dist/core/hook/claude-settings.d.ts +1 -1
  33. package/dist/core/hook/claude-settings.js +0 -1
  34. package/dist/core/hook/claude-settings.js.map +1 -1
  35. package/dist/core/ingest/backfill-derivables.d.ts +92 -0
  36. package/dist/core/ingest/backfill-derivables.js +175 -0
  37. package/dist/core/ingest/backfill-derivables.js.map +1 -0
  38. package/dist/core/ingest/ingest-session.js +20 -0
  39. package/dist/core/ingest/ingest-session.js.map +1 -1
  40. package/dist/core/ingest/reclassify-oversized.js +6 -0
  41. package/dist/core/ingest/reclassify-oversized.js.map +1 -1
  42. package/dist/core/ingest/reprocess.js +5 -0
  43. package/dist/core/ingest/reprocess.js.map +1 -1
  44. package/dist/core/ingest/transcript-derivables.d.ts +27 -0
  45. package/dist/core/ingest/transcript-derivables.js +138 -0
  46. package/dist/core/ingest/transcript-derivables.js.map +1 -0
  47. package/dist/core/outcome/coverage.d.ts +33 -0
  48. package/dist/core/outcome/coverage.js +46 -0
  49. package/dist/core/outcome/coverage.js.map +1 -0
  50. package/dist/core/outcome/rollup.d.ts +33 -0
  51. package/dist/core/outcome/rollup.js +113 -0
  52. package/dist/core/outcome/rollup.js.map +1 -0
  53. package/dist/core/recall/hook-recall-log.d.ts +2 -2
  54. package/dist/core/recall/hook-recall-log.js +2 -2
  55. package/dist/core/recall-facts/fact-recall-service.js +1 -0
  56. package/dist/core/recall-facts/fact-recall-service.js.map +1 -1
  57. package/dist/core/scheduler/scan-once.js +2 -0
  58. package/dist/core/scheduler/scan-once.js.map +1 -1
  59. package/dist/core/scheduler/scheduler.js +34 -3
  60. package/dist/core/scheduler/scheduler.js.map +1 -1
  61. package/dist/core/scope/alias-map.d.ts +10 -0
  62. package/dist/core/scope/alias-map.js +41 -0
  63. package/dist/core/scope/alias-map.js.map +1 -0
  64. package/dist/core/scope/derive-scope.d.ts +8 -0
  65. package/dist/core/scope/derive-scope.js +54 -0
  66. package/dist/core/scope/derive-scope.js.map +1 -0
  67. package/dist/core/scope/scope-clause.d.ts +16 -0
  68. package/dist/core/scope/scope-clause.js +21 -0
  69. package/dist/core/scope/scope-clause.js.map +1 -0
  70. package/dist/core/scope/stamp-flag.d.ts +1 -0
  71. package/dist/core/scope/stamp-flag.js +4 -0
  72. package/dist/core/scope/stamp-flag.js.map +1 -0
  73. package/dist/core/signals/code-signal.d.ts +1 -0
  74. package/dist/core/signals/code-signal.js +1 -0
  75. package/dist/core/signals/code-signal.js.map +1 -1
  76. package/dist/core/signals/ingest-signal.d.ts +1 -1
  77. package/dist/core/signals/ingest-signal.js +3 -1
  78. package/dist/core/signals/ingest-signal.js.map +1 -1
  79. package/dist/core/signals/stamp-scope.d.ts +18 -0
  80. package/dist/core/signals/stamp-scope.js +28 -0
  81. package/dist/core/signals/stamp-scope.js.map +1 -0
  82. package/dist/core/storage/pg-code-exemplar-store.js +6 -2
  83. package/dist/core/storage/pg-code-exemplar-store.js.map +1 -1
  84. package/dist/core/storage/pg-fact-ingest.d.ts +1 -1
  85. package/dist/core/storage/pg-fact-ingest.js +4 -4
  86. package/dist/core/storage/pg-fact-ingest.js.map +1 -1
  87. package/dist/core/storage/pg-session-store.d.ts +2 -2
  88. package/dist/core/storage/pg-session-store.js +31 -31
  89. package/dist/core/storage/pg-session-store.js.map +1 -1
  90. package/dist/core/storage/pg-signal-store.js +4 -3
  91. package/dist/core/storage/pg-signal-store.js.map +1 -1
  92. package/dist/core/storage/pg-workstream-store.d.ts +1 -0
  93. package/dist/core/storage/pg-workstream-store.js +2 -1
  94. package/dist/core/storage/pg-workstream-store.js.map +1 -1
  95. package/dist/core/storage/sqlite-code-exemplar-store.js +4 -2
  96. package/dist/core/storage/sqlite-code-exemplar-store.js.map +1 -1
  97. package/dist/core/storage/sqlite-fact-store.d.ts +1 -1
  98. package/dist/core/storage/sqlite-fact-store.js +8 -5
  99. package/dist/core/storage/sqlite-fact-store.js.map +1 -1
  100. package/dist/core/storage/sqlite-outcome-store.d.ts +89 -0
  101. package/dist/core/storage/sqlite-outcome-store.js +158 -0
  102. package/dist/core/storage/sqlite-outcome-store.js.map +1 -0
  103. package/dist/core/storage/sqlite-session-store.d.ts +22 -2
  104. package/dist/core/storage/sqlite-session-store.js +33 -35
  105. package/dist/core/storage/sqlite-session-store.js.map +1 -1
  106. package/dist/core/storage/sqlite-signal-store.js +4 -2
  107. package/dist/core/storage/sqlite-signal-store.js.map +1 -1
  108. package/dist/core/storage/sqlite-workstream-store.d.ts +1 -0
  109. package/dist/core/storage/sqlite-workstream-store.js +2 -1
  110. package/dist/core/storage/sqlite-workstream-store.js.map +1 -1
  111. package/dist/core/storage/supersedence-log.js +2 -0
  112. package/dist/core/storage/supersedence-log.js.map +1 -1
  113. package/dist/core/telemetry/probe-filter.d.ts +35 -0
  114. package/dist/core/telemetry/probe-filter.js +56 -0
  115. package/dist/core/telemetry/probe-filter.js.map +1 -0
  116. package/dist/core/update-check/check.d.ts +6 -0
  117. package/dist/core/update-check/check.js +35 -0
  118. package/dist/core/update-check/check.js.map +1 -1
  119. package/dist/core/workstream/bind.d.ts +2 -1
  120. package/dist/core/workstream/bind.js +28 -9
  121. package/dist/core/workstream/bind.js.map +1 -1
  122. package/dist/core/workstream/model.d.ts +1 -0
  123. package/dist/core/workstream/model.js.map +1 -1
  124. package/dist/hook/pre-compact-hook.js +2 -1
  125. package/dist/hook/pre-compact-hook.js.map +1 -1
  126. package/dist/hook/prompt-recall-hook.d.ts +3 -2
  127. package/dist/hook/prompt-recall-hook.js +8 -4
  128. package/dist/hook/prompt-recall-hook.js.map +1 -1
  129. package/dist/hook/recall-over-http.d.ts +2 -1
  130. package/dist/hook/recall-over-http.js +15 -2
  131. package/dist/hook/recall-over-http.js.map +1 -1
  132. package/dist/hook/session-start-hook.js +2 -1
  133. package/dist/hook/session-start-hook.js.map +1 -1
  134. package/dist/hook/stop-hook.js +2 -1
  135. package/dist/hook/stop-hook.js.map +1 -1
  136. package/dist/http/app.d.ts +6 -0
  137. package/dist/http/app.js +26 -38
  138. package/dist/http/app.js.map +1 -1
  139. package/dist/mcp/server.d.ts +22 -0
  140. package/dist/mcp/server.js +101 -1
  141. package/dist/mcp/server.js.map +1 -1
  142. package/dist/ports/outcome.d.ts +85 -0
  143. package/dist/ports/outcome.js +11 -0
  144. package/dist/ports/outcome.js.map +1 -0
  145. package/dist/ports/session-store.d.ts +0 -6
  146. package/dist/ports/workstream-store.d.ts +1 -0
  147. package/dist/shared/net.d.ts +3 -0
  148. package/dist/shared/net.js +4 -0
  149. package/dist/shared/net.js.map +1 -0
  150. package/dist/shared/types.d.ts +33 -0
  151. package/dist/shared/types.js +4 -1
  152. package/dist/shared/types.js.map +1 -1
  153. package/dist/ui/assets/{index-CMpQkbQy.js → index-CSaBtgXD.js} +1 -1
  154. package/dist/ui/index.html +1 -1
  155. package/migrations/029_project_scope.sql +21 -0
  156. package/migrations/032_session_derivables.sql +11 -0
  157. package/migrations/pg/030_project_scope.sql +23 -0
  158. package/migrations/pg/031_widen_session_edges_kind.sql +11 -0
  159. package/migrations/pg/032_session_derivables.sql +17 -0
  160. package/nlm/index.js +14 -6
  161. package/package.json +1 -1
  162. package/plugin/.codex-plugin/plugin.json +2 -2
  163. package/plugin/scripts/prompt-recall-hook.mjs +15 -6
  164. package/plugin/scripts/session-start-hook.mjs +11 -3
  165. package/plugin/scripts/stop-hook.mjs +4 -1
  166. package/dist/hook/subagent-start-hook.d.ts +0 -28
  167. package/dist/hook/subagent-start-hook.js +0 -81
  168. package/dist/hook/subagent-start-hook.js.map +0 -1
package/README.md CHANGED
@@ -339,6 +339,8 @@ recall: prompt / query
339
339
  | `NLM_PORT` | `3940` | Daemon bind port (loopback only) |
340
340
  | `NLM_DB_PATH` | `~/.nlm/canonical.sqlite` | SQLite canonical store location |
341
341
  | `NLM_HOOK_MODE` | `live` | `live` injects pointer block; `shadow` logs without injecting |
342
+ | `NLM_HOOK_RECALL_TIMEOUT_MS` | `4000` | Hook-side budget for the daemon recall call. Must stay below `NLM_HOOK_DEADLINE_MS` and above the daemon's embed deadline or the pointer block silently empties (#396). |
343
+ | `NLM_HOOK_DEADLINE_MS` | `6000` | Outer wall-clock deadline for the recall + gate stages of a hook fire. Fail-open on expiry. |
342
344
  | `NLM_HOOK_PROMPT_RECALL` | `(unset = off)` | Per-prompt ambient recall. Off by default (pull-first); set `on` to inject a pointer block on every prompt. `off` disables explicitly. |
343
345
  | `NLM_HOOK_LOG` | `~/.nlm/hook-log.jsonl` | Hook fire log; powers digest's liveness alert |
344
346
  | `NLM_USEFUL_HIT_LOG` | `~/.nlm/useful-hit-log.jsonl` | Citation/useful-hit ledger |
@@ -10,12 +10,40 @@
10
10
  import { existsSync, readFileSync } from "node:fs";
11
11
  import { homedir } from "node:os";
12
12
  import { join } from "node:path";
13
+ import Database from "better-sqlite3";
13
14
  import { composeDigest, } from "../core/digest/compose.js";
14
15
  import { computePrecision } from "../core/recall/precision.js";
15
16
  import { readHookRecallLog } from "../core/recall/hook-recall-log.js";
16
17
  import { readCitationLog } from "../core/recall/citation-log.js";
17
18
  import { checkHookLiveness } from "../core/digest/hook-liveness.js";
19
+ import { checkHookInjection } from "../core/digest/hook-injection.js";
18
20
  import { hookAuthHeaders } from "../hook/hook-auth.js";
21
+ import { computeOutcomeCoverage } from "../core/outcome/coverage.js";
22
+ import { loadOutcomeCoverageInput } from "../core/storage/sqlite-outcome-store.js";
23
+ /** Sessions ended in the last N days count toward the Tier-B coverage block. */
24
+ const OUTCOME_COVERAGE_WINDOW_DAYS = 30;
25
+ function defaultDbPath() {
26
+ return process.env["NLM_DB_PATH"] ?? join(homedir(), ".nlm", "canonical.sqlite");
27
+ }
28
+ /**
29
+ * Best-effort, read-only: opens its own SQLite connection directly rather
30
+ * than round-tripping the daemon (same pattern as the hook-log/citation-log
31
+ * reads below). A failure here must not break the rest of the digest.
32
+ */
33
+ async function loadOutcomeCoverage() {
34
+ const dbPath = defaultDbPath();
35
+ if (!existsSync(dbPath))
36
+ return null;
37
+ const db = new Database(dbPath, { readonly: true });
38
+ try {
39
+ const sinceIso = new Date(Date.now() - OUTCOME_COVERAGE_WINDOW_DAYS * 24 * 60 * 60 * 1000).toISOString();
40
+ const input = await loadOutcomeCoverageInput(db, { sinceIso });
41
+ return await computeOutcomeCoverage(input);
42
+ }
43
+ finally {
44
+ db.close();
45
+ }
46
+ }
19
47
  export async function runDigest(opts) {
20
48
  const base = `http://localhost:${opts.port}`;
21
49
  const timeoutMs = opts.timeoutMs ?? 8000;
@@ -49,12 +77,14 @@ export async function runDigest(opts) {
49
77
  const hookLogPath = process.env["NLM_HOOK_LOG"] ?? join(homedir(), ".nlm", "hook-log.jsonl");
50
78
  const hookLogExists = existsSync(hookLogPath);
51
79
  const hookLog = hookLogExists ? readHookLog(hookLogPath) : [];
52
- const hookAlert = checkHookLiveness({
80
+ const livenessAlert = checkHookLiveness({
53
81
  sessions,
54
82
  hookLog,
55
83
  hookLogPath,
56
84
  hookLogExists,
57
85
  });
86
+ const injectionResult = checkHookInjection(hookLog);
87
+ const hookAlert = [livenessAlert, injectionResult.message].filter(Boolean).join("\n") || null;
58
88
  // True cited-precision over the 7-day window (the honest "was recall useful"
59
89
  // metric). Best-effort: a log-read failure must not break the digest.
60
90
  let precision = null;
@@ -72,12 +102,20 @@ export async function runDigest(opts) {
72
102
  catch {
73
103
  precision = null;
74
104
  }
105
+ let outcomeCoverage = null;
106
+ try {
107
+ outcomeCoverage = await loadOutcomeCoverage();
108
+ }
109
+ catch {
110
+ outcomeCoverage = null;
111
+ }
75
112
  const text = composeDigest({
76
113
  stats,
77
114
  recent,
78
115
  port: opts.port,
79
116
  hookAlert,
80
117
  precision,
118
+ outcomeCoverage,
81
119
  });
82
120
  if (opts.telegram) {
83
121
  await postTelegram(text);
@@ -1 +1 @@
1
- {"version":3,"file":"digest.js","sourceRoot":"","sources":["../../src/cli/digest.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"digest.js","sourceRoot":"","sources":["../../src/cli/digest.ts"],"names":[],"mappings":"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"}
package/dist/cli/nlm.js CHANGED
@@ -60,6 +60,9 @@ import { connectCursor, disconnectCursor } from "../install/cursor.js";
60
60
  import { describeRemove, describeUpsert, installCursorRules, installOpencodeRules, installWindsurfRules, uninstallCursorRules, uninstallOpencodeRules, uninstallWindsurfRules, } from "../install/rules-install.js";
61
61
  import { runSupersedeCommand } from "./supersede.js";
62
62
  import { runInitCommand } from "./init.js";
63
+ import { runScopeBackfill, formatBackfillResult } from "./scope-backfill.js";
64
+ import { runScopeCoverage, formatCoverageResult } from "./scope-coverage.js";
65
+ import { loadAliasMap } from "../core/scope/alias-map.js";
63
66
  import { getUpdateStatus } from "../core/update-check/check.js";
64
67
  import { connectHermes, disconnectHermes, hermesConfigPath } from "../install/hermes.js";
65
68
  import { connectHermesAgent, disconnectHermesAgent, hermesAgentPluginDir } from "../install/hermes-agent.js";
@@ -94,6 +97,7 @@ import { runChecksOnSqlite, runChecksOnPg, applyFixOnSqlite, applyFixOnPg } from
94
97
  import { normalizeLabel } from "../core/workstream/model.js";
95
98
  import { resolveWorkstreamId } from "../core/workstream/resolve.js";
96
99
  import { suggestMerges } from "../core/entities/dedup-suggest.js";
100
+ import { DEFAULT_NLM_PORT } from "../shared/net.js";
97
101
  const __filename = fileURLToPath(import.meta.url);
98
102
  const __dirname = dirname(__filename);
99
103
  const MIGRATIONS_DIR = resolve(__dirname, "../../migrations");
@@ -101,7 +105,7 @@ const CLASSIFIER_FIXTURES_DIR = resolve(__dirname, "../../fixtures/classifier-go
101
105
  const PG_MIGRATIONS_DIR = join(fileURLToPath(new URL(".", import.meta.url)), "../../migrations/pg");
102
106
  const UI_DIST = resolve(__dirname, "../../dist/ui");
103
107
  const DEFAULT_DB_PATH = resolve(homedir(), ".nlm/canonical.sqlite");
104
- const DEFAULT_PORT = 3940;
108
+ const DEFAULT_PORT = Number.parseInt(DEFAULT_NLM_PORT, 10);
105
109
  function dbPath() {
106
110
  return process.env["NLM_DB_PATH"] ?? DEFAULT_DB_PATH;
107
111
  }
@@ -384,6 +388,9 @@ program
384
388
  },
385
389
  signalStore: signals,
386
390
  installScope: scope,
391
+ // Signal scope inheritance (NLM_SCOPE_STAMP): a signal with only a
392
+ // session_id inherits that session's stamped scope at ingest.
393
+ sessionScopeReader: store,
387
394
  // Code-exemplar lane. The store + code embedder are always wired; the
388
395
  // NLM_CODE_EXEMPLARS_ENABLED flag gates capture (POST /api/signal) and
389
396
  // the /api/exemplar + /api/recall-code routes at request time.
@@ -406,6 +413,8 @@ program
406
413
  exemplarStore: storage.exemplars,
407
414
  codeEmbedder: codeEmb,
408
415
  installScope: scope,
416
+ signalStore: signals,
417
+ sessionScopeReader: store,
409
418
  workDigest: { store, topicProvider: loadTopicProvider(), workstreams: storage.workstreams, ...workDigestEnv() },
410
419
  workstreams: { store: storage.workstreams, sessions: store, facts: facts, exemplars: storage.exemplars },
411
420
  },
@@ -1205,11 +1214,39 @@ program
1205
1214
  await stack.storage.close();
1206
1215
  }
1207
1216
  });
1217
+ program
1218
+ .command("backfill-derivables")
1219
+ .description("Retroactive: stamp agent_persona + parent_session_id (#352 phase 2) onto sessions ingested\n" +
1220
+ "before the scheduler started stamping them at classify time. Idempotent (WHERE agent_persona IS NULL).")
1221
+ .option("--dry-run", "report counts without writing")
1222
+ .option("--with-transcript-scan", "also scan each candidate's transcript for primary_model/total_tokens/skill (slower)")
1223
+ .action(async (opts) => {
1224
+ const { backfillDerivables } = await import("../core/ingest/backfill-derivables.js");
1225
+ const stack = await buildStack();
1226
+ try {
1227
+ if (!(stack.storage instanceof SqliteStorage)) {
1228
+ console.error("backfill-derivables: only supported with SQLite storage (NLM_PG_URL must not be set)");
1229
+ await stack.storage.close();
1230
+ process.exit(1);
1231
+ }
1232
+ const report = await backfillDerivables(stack.storage.rawDb(), {
1233
+ dryRun: Boolean(opts.dryRun),
1234
+ withTranscriptScan: Boolean(opts.withTranscriptScan),
1235
+ });
1236
+ console.log(`backfill-derivables${opts.dryRun ? " (dry-run)" : ""}: ` +
1237
+ `updated=${report.updated} skipped(already-stamped)=${report.skippedAlreadyStamped} ` +
1238
+ `skipped(no-op)=${report.skippedNoop} subagent-candidates=${report.subagentCandidates} ` +
1239
+ `unknown-parent=${report.unknownParent} transcript-scanned=${report.transcriptScanned} total=${report.total}`);
1240
+ }
1241
+ finally {
1242
+ await stack.storage.close();
1243
+ }
1244
+ });
1208
1245
  program
1209
1246
  .command("mcp")
1210
1247
  .description("Run as an MCP stdio server (for ~/.mcp.json)")
1211
1248
  .action(async () => {
1212
- const { recall, store, facts, factRecall, storage, scope } = await buildStack();
1249
+ const { recall, store, facts, factRecall, storage, scope, signals } = await buildStack();
1213
1250
  const server = createMcpServer({
1214
1251
  recall,
1215
1252
  store,
@@ -1218,8 +1255,13 @@ program
1218
1255
  exemplarStore: storage.exemplars,
1219
1256
  codeEmbedder: buildCodeEmbedder(),
1220
1257
  installScope: scope,
1258
+ signalStore: signals,
1259
+ sessionScopeReader: store,
1221
1260
  workDigest: { store, topicProvider: loadTopicProvider(), workstreams: storage.workstreams, ...workDigestEnv() },
1222
1261
  workstreams: { store: storage.workstreams, sessions: store, facts: facts, exemplars: storage.exemplars },
1262
+ // Tier-B outcome rollup (#352 phase 2) only has a SQLite adapter today;
1263
+ // PgStorage deployments skip get_session's `outcome` field until parity lands.
1264
+ ...(storage instanceof SqliteStorage ? { outcomeDb: storage.rawDb() } : {}),
1223
1265
  });
1224
1266
  const transport = new StdioServerTransport();
1225
1267
  await server.connect(transport);
@@ -1607,14 +1649,12 @@ const SESSION_START_HOOK_JS = resolve(__dirname, "../hook/session-start-hook.js"
1607
1649
  const SESSION_END_HOOK_JS = resolve(__dirname, "../hook/session-end-hook.js");
1608
1650
  const STOP_HOOK_JS = resolve(__dirname, "../hook/stop-hook.js");
1609
1651
  const PRE_COMPACT_HOOK_JS = resolve(__dirname, "../hook/pre-compact-hook.js");
1610
- const SUBAGENT_START_HOOK_JS = resolve(__dirname, "../hook/subagent-start-hook.js");
1611
1652
  const ALL_HOOKS = [
1612
1653
  { event: "UserPromptSubmit", script: HOOK_JS, label: "recall" },
1613
1654
  { event: "SessionStart", script: SESSION_START_HOOK_JS, label: "session-start" },
1614
1655
  { event: "SessionEnd", script: SESSION_END_HOOK_JS, label: "session-end" },
1615
1656
  { event: "Stop", script: STOP_HOOK_JS, label: "stop" },
1616
1657
  { event: "PreCompact", script: PRE_COMPACT_HOOK_JS, label: "pre-compact" },
1617
- { event: "SubagentStart", script: SUBAGENT_START_HOOK_JS, label: "subagent-start" },
1618
1658
  ];
1619
1659
  function claudeSettingsPath() {
1620
1660
  return process.env["NLM_CLAUDE_SETTINGS"] ?? join(homedir(), ".claude", "settings.json");
@@ -1624,7 +1664,7 @@ const hook = program
1624
1664
  .description("Manage the Claude Code NLM hooks");
1625
1665
  hook
1626
1666
  .command("install")
1627
- .description("Add the NLM hooks (recall + session-end + stop) to ~/.claude/settings.json (live mode)")
1667
+ .description("Add the NLM hooks (recall + session-start + session-end + stop + pre-compact) to ~/.claude/settings.json (live mode)")
1628
1668
  .action(() => {
1629
1669
  const path = claudeSettingsPath();
1630
1670
  const installed = [];
@@ -2130,7 +2170,7 @@ program
2130
2170
  program
2131
2171
  .command("digest")
2132
2172
  .description("Compose a daily-activity digest from the running daemon (optionally post to Telegram)")
2133
- .option("-p, --port <n>", "daemon port", (v) => Number.parseInt(v, 10), Number.parseInt(process.env["NLM_PORT"] ?? "3940", 10))
2173
+ .option("-p, --port <n>", "daemon port", (v) => Number.parseInt(v, 10), Number.parseInt(process.env["NLM_PORT"] ?? DEFAULT_NLM_PORT, 10))
2134
2174
  .option("--telegram", "post to Telegram instead of printing to stdout (requires TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID)")
2135
2175
  .action(async (opts) => {
2136
2176
  autoloadEnv();
@@ -2566,6 +2606,66 @@ entitiesCmd
2566
2606
  if (failed > 0)
2567
2607
  process.exit(1);
2568
2608
  });
2609
+ const scopeCmd = program
2610
+ .command("scope")
2611
+ .description("Scope management commands");
2612
+ scopeCmd
2613
+ .command("backfill")
2614
+ .description("Derive and stamp scope on legacy sessions/facts/exemplars/signals/workstreams from stored transcript evidence")
2615
+ .option("--apply", "write changes (default: dry run, no writes)")
2616
+ .option("--db <path>", "SQLite DB file to backfill (default: canonical NLM DB)")
2617
+ .option("--json", "emit machine-readable JSON summary instead of human-readable output")
2618
+ .action(async (opts) => {
2619
+ const targetPath = opts.db ?? dbPath();
2620
+ const storage = SqliteStorage.create({ dbPath: targetPath, migrationsDir: MIGRATIONS_DIR });
2621
+ const aliasMap = loadAliasMap();
2622
+ try {
2623
+ const result = await runScopeBackfill({
2624
+ db: storage.rawDb(),
2625
+ apply: Boolean(opts.apply),
2626
+ aliasMap,
2627
+ });
2628
+ if (opts.json) {
2629
+ const out = {
2630
+ dryRun: result.dryRun,
2631
+ sessions: { total: result.sessions.total, byScope: result.sessions.byScope },
2632
+ facts: { total: result.facts.total, byScope: result.facts.byScope },
2633
+ exemplars: { total: result.exemplars.total, byScope: result.exemplars.byScope },
2634
+ signals: { total: result.signals.total, byScope: result.signals.byScope },
2635
+ workstreams: { total: result.workstreams.total, byScope: result.workstreams.byScope },
2636
+ skipped: result.skipped,
2637
+ };
2638
+ process.stdout.write(JSON.stringify(out, null, 2) + "\n");
2639
+ }
2640
+ else {
2641
+ formatBackfillResult(result, (s) => process.stdout.write(s));
2642
+ }
2643
+ }
2644
+ finally {
2645
+ await storage.close();
2646
+ }
2647
+ });
2648
+ scopeCmd
2649
+ .command("coverage")
2650
+ .description("Report per-table and recall-weighted scope coverage fractions")
2651
+ .option("--db <path>", "SQLite DB file (default: canonical NLM DB)")
2652
+ .option("--query-log <path>", "query log path for recall-weighted coverage")
2653
+ .option("--window <n>", "last N log entries for recall-weighted coverage (default 200)", (v) => Number.parseInt(v, 10), 200)
2654
+ .option("--json", "emit machine-readable JSON instead of human-readable output")
2655
+ .action(async (opts) => {
2656
+ const targetPath = opts.db ?? dbPath();
2657
+ const result = await runScopeCoverage({
2658
+ dbPath: targetPath,
2659
+ ...(opts.queryLog ? { queryLogPath: opts.queryLog } : {}),
2660
+ window: opts.window,
2661
+ });
2662
+ if (opts.json) {
2663
+ process.stdout.write(JSON.stringify(result, null, 2) + "\n");
2664
+ }
2665
+ else {
2666
+ formatCoverageResult(result, (s) => process.stdout.write(s));
2667
+ }
2668
+ });
2569
2669
  // Entrypoint guard: only parse argv when this file IS the executed script.
2570
2670
  // realpathSync resolves the npm bin symlink so the global `nlm` shim still
2571
2671
  // matches; without the guard, importing any helper from this module inside