@graphorin/cli 0.5.0 → 0.6.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 (76) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +8 -8
  3. package/dist/bin/graphorin.js +15 -7
  4. package/dist/bin/graphorin.js.map +1 -1
  5. package/dist/commands/audit.d.ts +2 -2
  6. package/dist/commands/audit.js +6 -6
  7. package/dist/commands/audit.js.map +1 -1
  8. package/dist/commands/auth.d.ts +1 -1
  9. package/dist/commands/auth.js +3 -3
  10. package/dist/commands/auth.js.map +1 -1
  11. package/dist/commands/consolidator.js +2 -2
  12. package/dist/commands/consolidator.js.map +1 -1
  13. package/dist/commands/doctor.d.ts +1 -1
  14. package/dist/commands/doctor.js +5 -5
  15. package/dist/commands/doctor.js.map +1 -1
  16. package/dist/commands/guard.js +3 -3
  17. package/dist/commands/guard.js.map +1 -1
  18. package/dist/commands/index.d.ts +2 -2
  19. package/dist/commands/index.js +2 -2
  20. package/dist/commands/init.d.ts +2 -2
  21. package/dist/commands/init.js +3 -3
  22. package/dist/commands/init.js.map +1 -1
  23. package/dist/commands/memory.d.ts +5 -5
  24. package/dist/commands/memory.d.ts.map +1 -1
  25. package/dist/commands/memory.js +11 -11
  26. package/dist/commands/memory.js.map +1 -1
  27. package/dist/commands/migrate-config.js +2 -2
  28. package/dist/commands/migrate-config.js.map +1 -1
  29. package/dist/commands/migrate-export.d.ts +1 -1
  30. package/dist/commands/migrate-export.js +2 -2
  31. package/dist/commands/migrate-export.js.map +1 -1
  32. package/dist/commands/migrate.d.ts +1 -1
  33. package/dist/commands/migrate.js +1 -1
  34. package/dist/commands/migrate.js.map +1 -1
  35. package/dist/commands/pricing.d.ts +1 -1
  36. package/dist/commands/pricing.js +6 -6
  37. package/dist/commands/pricing.js.map +1 -1
  38. package/dist/commands/secrets.d.ts +1 -1
  39. package/dist/commands/secrets.js +5 -5
  40. package/dist/commands/secrets.js.map +1 -1
  41. package/dist/commands/skills.js +5 -5
  42. package/dist/commands/skills.js.map +1 -1
  43. package/dist/commands/start.d.ts +1 -1
  44. package/dist/commands/start.js +1 -1
  45. package/dist/commands/start.js.map +1 -1
  46. package/dist/commands/storage.d.ts +26 -2
  47. package/dist/commands/storage.d.ts.map +1 -1
  48. package/dist/commands/storage.js +51 -11
  49. package/dist/commands/storage.js.map +1 -1
  50. package/dist/commands/telemetry.js +6 -6
  51. package/dist/commands/telemetry.js.map +1 -1
  52. package/dist/commands/token.d.ts +2 -2
  53. package/dist/commands/token.js +4 -4
  54. package/dist/commands/token.js.map +1 -1
  55. package/dist/commands/tools-lint.d.ts +1 -1
  56. package/dist/commands/tools-lint.js +6 -6
  57. package/dist/commands/tools-lint.js.map +1 -1
  58. package/dist/commands/traces.js +5 -5
  59. package/dist/commands/traces.js.map +1 -1
  60. package/dist/commands/triggers.d.ts +1 -1
  61. package/dist/commands/triggers.js +1 -1
  62. package/dist/commands/triggers.js.map +1 -1
  63. package/dist/index.d.ts +4 -4
  64. package/dist/index.js +4 -4
  65. package/dist/index.js.map +1 -1
  66. package/dist/internal/exit.js.map +1 -1
  67. package/dist/internal/load-config.js +5 -5
  68. package/dist/internal/load-config.js.map +1 -1
  69. package/dist/internal/offline.d.ts +1 -1
  70. package/dist/internal/offline.js +2 -2
  71. package/dist/internal/offline.js.map +1 -1
  72. package/dist/internal/output.d.ts +6 -6
  73. package/dist/internal/output.js +6 -6
  74. package/dist/internal/output.js.map +1 -1
  75. package/dist/internal/store-context.js.map +1 -1
  76. package/package.json +12 -12
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","names":[],"sources":["../../src/commands/memory.ts"],"sourcesContent":[],"mappings":";;;;;AAyPgC,UAxNf,mBAAA,SAA4B,mBAwNb,CAAA;EAAd,SAAA,MAAA,CAAA,EAAA,MAAA;;;AAEkB,UArNnB,oBAAA,CAqNmB;EAAd,SAAA,EAAA,EAAA,MAAA;EACmB,SAAA,KAAA,EAAA,MAAA;EAAd,SAAA,GAAA,EAAA,MAAA;EAEc,SAAA,cAAA,EAAA,MAAA;EAAd,SAAA,OAAA,EAAA,OAAA;EAAa,SAAA,SAAA,EAAA,MAAA;EAIvB,SAAA,SAAA,CAAA,EAAA,MAAqB;AAatC;;AAEW,UAhOM,kBAAA,CAgON;EAAR,SAAA,WAAA,EAAA,MAAA;EAAO,SAAA,SAAA,EA9NY,aA8NZ,CA9N0B,oBA8N1B,CAAA;EAwJO,SAAA,MAAA,EAAA;IASA,SAAA,KAAA,EAAA,MAAsB;IAStB,SAAA,QAAA,EAAoB,MAAA;IAMG,SAAA,eAAA,EAAA,MAAA;IAAd,SAAA,UAAA,EAAA,MAAA;EACgB,CAAA;;;AAIzB,iBAzYK,eAAA,CAyYyB,OAAmB,CAAnB,EAxYpC,mBAwYuD,CAAA,EAvY/D,OAuY+D,CAvYvD,kBAuYuD,CAAA;AAclE;AACW,UAtWM,oBAAA,SAA6B,mBAsWnC,CAAA;EACA,SAAA,IAAA,EAAA,MAAA;EAAR,SAAA,EAAA,EAAA,MAAA;EAAO,SAAA,QAAA,EAAA,eAAA,GAAA,cAAA,GAAA,cAAA;EAiGO;;;;;AAajB;AAKA;EAqBsB,SAAA,eAAY,CAAA,EAAA,MAAA;;;;;AAyElC;AAOA;;;;AAIqB,iBA7iBC,gBAAA,CA6iBD,OAAA,EA7iB2B,oBA6iB3B,CAAA,EA7iBkD,OA6iBlD,CAAA,KAAA,CAAA;;AACA,UAnfJ,iBAAA,CAmfI;EACgB,SAAA,EAAA,EAAA,MAAA;EAAd,SAAA,IAAA,EAAA,MAAA;EAAa,SAAA,MAAA,EAAA,MAAA;EAInB,SAAA,UAAA,EAAA,MAAoB,GAAA,IAAQ;EA2BvB;EACX,SAAA,UAAA,EAAA,MAAA,GAAA,IAAA;EACA,SAAA,SAAA,EAAA,MAAA,GAAA,IAAA;EAAR,SAAA,OAAA,EAAA,MAAA,GAAA,IAAA;EAAO,SAAA,UAAA,EAAA,MAAA,GAAA,IAAA;;;;;;;;;;UAjgBO,mBAAA;;;;;;;;UASA,kBAAA;;;;;;UAOA,mBAAA;;;;;;;;;UAUA,mBAAA;;;;;;;UAQA,mBAAA;;iBAEA;kBACC,cAAc;oBACZ,cAAc;sBACZ,cAAc;2BACT,cAAc;;2BAEd,cAAc;;;UAIxB,oBAAA,SAA6B;;;;;;;;;;;;iBAaxB,gBAAA,UACX,uBACR,QAAQ;;UAwJM,mBAAA;;;;;;;;UASA,sBAAA;;;;;;;;UASA,oBAAA;;;;;;0BAMS,cAAc;4BACZ,cAAc;;;UAIzB,qBAAA,SAA8B;;;;;;;;;;;;;iBAczB,iBAAA,WACX,wBACR,QAAQ;;UAiGM,eAAA;;;;oBAIG;;;;sBAIE,SAAS;;;;UAKd,eAAA;oBACG,cAAc;;;UAIjB,gBAAA,SAAyB;;;;;;;;;;;;;;iBAqBpB,YAAA,UAAsB,mBAAmB,QAAQ;;UAyEtD,gBAAA;;;;;;UAOA,kBAAA;;;;;;kBAGC,cAAc;qBACX,cAAc;qBACd,cAAc;uBACZ,cAAc;;;UAIpB,mBAAA,SAA4B;;;;;;;;;;;;;;;;;;;iBA2BvB,eAAA,WACX,sBACR,QAAQ"}
1
+ {"version":3,"file":"memory.d.ts","names":[],"sources":["../../src/commands/memory.ts"],"sourcesContent":[],"mappings":";;;;;AAyPgC,UAxNf,mBAAA,SAA4B,mBAwNb,CAAA;EAAd,SAAA,MAAA,CAAA,EAAA,MAAA;;;AAEkB,UArNnB,oBAAA,CAqNmB;EAAd,SAAA,EAAA,EAAA,MAAA;EACmB,SAAA,KAAA,EAAA,MAAA;EAAd,SAAA,GAAA,EAAA,MAAA;EAEc,SAAA,cAAA,EAAA,MAAA;EAAd,SAAA,OAAA,EAAA,OAAA;EAAa,SAAA,SAAA,EAAA,MAAA;EAIvB,SAAA,SAAA,CAAA,EAAA,MAAqB;AAatC;;AAEW,UAhOM,kBAAA,CAgON;EAAR,SAAA,WAAA,EAAA,MAAA;EAAO,SAAA,SAAA,EA9NY,aA8NZ,CA9N0B,oBA8N1B,CAAA;EAwJO,SAAA,MAAA,EAAA;IASA,SAAA,KAAA,EAAA,MAAsB;IAStB,SAAA,QAAA,EAAoB,MAAA;IAMG,SAAA,eAAA,EAAA,MAAA;IAAd,SAAA,UAAA,EAAA,MAAA;EACgB,CAAA;;;AAIzB,iBAzYK,eAAA,CAyYiB,OAA2B,CAAnB,EAxYpC,mBAwYuD,CAAA,EAvY/D,OAuY+D,CAvYvD,kBAuYuD,CAAA;AAclE;AACW,UAtWM,oBAAA,SAA6B,mBAsWnC,CAAA;EACA,SAAA,IAAA,EAAA,MAAA;EAAR,SAAA,EAAA,EAAA,MAAA;EAAO,SAAA,QAAA,EAAA,eAAA,GAAA,cAAA,GAAA,cAAA;EAiGO;;;;;AAajB;AAKA;EAqBsB,SAAA,eAAY,CAAA,EAAA,MAAA;;;;;AAyElC;AAOA;;;;AAIqB,iBA7iBC,gBAAA,CA6iBD,OAAA,EA7iB2B,oBA6iB3B,CAAA,EA7iBkD,OA6iBlD,CAAA,KAAA,CAAA;;AACA,UAnfJ,iBAAA,CAmfI;EACgB,SAAA,EAAA,EAAA,MAAA;EAAd,SAAA,IAAA,EAAA,MAAA;EAAa,SAAA,MAAA,EAAA,MAAA;EAInB,SAAA,UAAA,EAAA,MAAoB,GAAA,IAAA;EA2Bf;EACX,SAAA,UAAA,EAAA,MAAA,GAAA,IAAA;EACA,SAAA,SAAA,EAAA,MAAA,GAAA,IAAA;EAAR,SAAA,OAAA,EAAA,MAAA,GAAA,IAAA;EAAO,SAAA,UAAA,EAAA,MAAA,GAAA,IAAA;;;;;;;;;;UAjgBO,mBAAA;;;;;;;;UASA,kBAAA;;;;;;UAOA,mBAAA;;;;;;;;;UAUA,mBAAA;;;;;;;UAQA,mBAAA;;iBAEA;kBACC,cAAc;oBACZ,cAAc;sBACZ,cAAc;2BACT,cAAc;;2BAEd,cAAc;;;UAIxB,oBAAA,SAA6B;;;;;;;;;;;;iBAaxB,gBAAA,UACX,uBACR,QAAQ;;UAwJM,mBAAA;;;;;;;;UASA,sBAAA;;;;;;;;UASA,oBAAA;;;;;;0BAMS,cAAc;4BACZ,cAAc;;;UAIzB,qBAAA,SAA8B;;;;;;;;;;;;;iBAczB,iBAAA,WACX,wBACR,QAAQ;;UAiGM,eAAA;;;;oBAIG;;;;sBAIE,SAAS;;;;UAKd,eAAA;oBACG,cAAc;;;UAIjB,gBAAA,SAAyB;;;;;;;;;;;;;;iBAqBpB,YAAA,UAAsB,mBAAmB,QAAQ;;UAyEtD,gBAAA;;;;;;UAOA,kBAAA;;;;;;kBAGC,cAAc;qBACX,cAAc;qBACd,cAAc;uBACZ,cAAc;;;UAIpB,mBAAA,SAA4B;;;;;;;;;;;;;;;;;;;iBA2BvB,eAAA,WACX,sBACR,QAAQ"}
@@ -6,14 +6,14 @@ import { createMemory } from "@graphorin/memory";
6
6
 
7
7
  //#region src/commands/memory.ts
8
8
  /**
9
- * `graphorin memory` long-term memory operator commands.
9
+ * `graphorin memory` - long-term memory operator commands.
10
10
  *
11
11
  * Surface (per Phase 15 § Memory):
12
12
  *
13
- * - `graphorin memory status` counts + active embedder + migration
13
+ * - `graphorin memory status` - counts + active embedder + migration
14
14
  * state. Pure read-only inspection of the SQLite store.
15
15
  * - `graphorin memory migrate --from <embedder> --to <embedder>
16
- * --strategy <lock-on-first|auto-migrate|multi-active>` embedder
16
+ * --strategy <lock-on-first|auto-migrate|multi-active>` - embedder
17
17
  * swap. The runner itself lives in `@graphorin/memory`
18
18
  * ({@link migrateEmbedder}); the CLI is a thin wrapper that loads
19
19
  * the operator's `embedders.ts` module if supplied through
@@ -45,7 +45,7 @@ async function runMemoryStatus(options = {}) {
45
45
  emitReport(options, out, () => {
46
46
  const print = options.print ?? defaultPrintSink;
47
47
  print(brand(`memory status (${out.storagePath})`));
48
- if (out.embedders.length === 0) print(brand(` no embedders registered yet run createMemory({ embedder }) once.`));
48
+ if (out.embedders.length === 0) print(brand(` no embedders registered yet - run createMemory({ embedder }) once.`));
49
49
  else {
50
50
  print(brand(` embedders (${out.embedders.length}):`));
51
51
  for (const e of out.embedders) print(` ${e.retired ? statusMarker("warn") : statusMarker("ok")} ${e.id} (model=${e.model}, dim=${e.dim}, retired=${e.retired})`);
@@ -58,7 +58,7 @@ async function runMemoryStatus(options = {}) {
58
58
  }
59
59
  }
60
60
  /**
61
- * `graphorin memory migrate` embedder swap. The migration logic lives
61
+ * `graphorin memory migrate` - embedder swap. The migration logic lives
62
62
  * in `@graphorin/memory`'s `migrateEmbedder(...)`; the CLI prints a
63
63
  * pointer when the operator did not supply the embedder factory module
64
64
  * (the framework cannot guess the operator's embedder configuration).
@@ -78,7 +78,7 @@ async function runMemoryMigrate(options) {
78
78
  }
79
79
  const FACT_INSPECT_COLUMNS = "id, text, status, provenance, importance, valid_from, valid_to, supersedes, superseded_by, created_at";
80
80
  /**
81
- * `graphorin memory inspect <factId>` surface everything the store
81
+ * `graphorin memory inspect <factId>` - surface everything the store
82
82
  * knows about one fact: its retrieval-trust status + provenance, the
83
83
  * full bi-temporal supersede chain it belongs to, the audit-log events
84
84
  * recorded against it, the conflict decisions that referenced it, and
@@ -143,7 +143,7 @@ async function runMemoryInspect(options) {
143
143
  const f = out.fact;
144
144
  print(` ${statusMarker(f.status === "quarantined" ? "warn" : "ok")} status=${f.status} provenance=${f.provenance ?? "user (first-party)"}`);
145
145
  print(` text: ${f.text}`);
146
- print(` importance: ${f.importance !== null ? f.importance.toFixed(2) : "(unset neutral salience)"}`);
146
+ print(` importance: ${f.importance !== null ? f.importance.toFixed(2) : "(unset - neutral salience)"}`);
147
147
  print(` valid: ${f.validFrom ?? "open"} .. ${f.validTo ?? "open"}`);
148
148
  if (out.linkedEntities.length > 0) {
149
149
  print(brand(` linked entities (${out.linkedEntities.length}):`));
@@ -172,7 +172,7 @@ async function runMemoryInspect(options) {
172
172
  }
173
173
  }
174
174
  /**
175
- * `graphorin memory activity` a store-wide view of what the
175
+ * `graphorin memory activity` - a store-wide view of what the
176
176
  * consolidator and reflection passes have been doing: how many facts /
177
177
  * episodes / insights currently sit in quarantine, the most recent
178
178
  * audit-log events (supersede / validate / quarantine / archive), and
@@ -225,7 +225,7 @@ async function runMemoryActivity(options = {}) {
225
225
  }
226
226
  }
227
227
  /**
228
- * `graphorin memory why` explain why facts were recalled, by decoding the
228
+ * `graphorin memory why` - explain why facts were recalled, by decoding the
229
229
  * `memory.search.semantic.explain` attribute off the persisted recall spans.
230
230
  * Pure read-only inspection; requires the SQLite span exporter to have recorded
231
231
  * spans (RP-17). Empty when nothing was recorded.
@@ -282,7 +282,7 @@ const EMPTY_REVIEW = Object.freeze({
282
282
  procedures: Object.freeze([])
283
283
  });
284
284
  /**
285
- * `graphorin memory review` list the facts / episodes / insights / induced
285
+ * `graphorin memory review` - list the facts / episodes / insights / induced
286
286
  * procedures the consolidator left in quarantine (read-only), or promote a
287
287
  * reviewed item out of quarantine with `--promote <id>`. The promote path runs
288
288
  * through the tier `validate(...)`, so an injection-flagged memory is refused
@@ -339,7 +339,7 @@ async function runMemoryReview(options = {}) {
339
339
  procedures: listQuarantined(conn, "rules", "text", limit)
340
340
  });
341
341
  emitReport(options, out, () => {
342
- print(brand("memory review quarantined"));
342
+ print(brand("memory review - quarantined"));
343
343
  printReviewItems(print, "facts", out.facts);
344
344
  printReviewItems(print, "episodes", out.episodes);
345
345
  printReviewItems(print, "insights", out.insights);
@@ -1 +1 @@
1
- {"version":3,"file":"memory.js","names":["out: MemoryStatusResult","out: MemoryInspectResult","out: MemoryActivityResult","results: MemoryWhyRecall['results']","parsed: unknown","out: MemoryWhyResult","EMPTY_REVIEW: MemoryReviewResult","out: MemoryReviewResult","out","queue: string[]","rows: FactInspectRow[]"],"sources":["../../src/commands/memory.ts"],"sourcesContent":["/**\n * `graphorin memory` — long-term memory operator commands.\n *\n * Surface (per Phase 15 § Memory):\n *\n * - `graphorin memory status` — counts + active embedder + migration\n * state. Pure read-only inspection of the SQLite store.\n * - `graphorin memory migrate --from <embedder> --to <embedder>\n * --strategy <lock-on-first|auto-migrate|multi-active>` — embedder\n * swap. The runner itself lives in `@graphorin/memory`\n * ({@link migrateEmbedder}); the CLI is a thin wrapper that loads\n * the operator's `embedders.ts` module if supplied through\n * `--embedders <path>`. Without that module the command emits a\n * pointer to the documentation rather than guessing which embedder\n * factory to instantiate.\n *\n * @packageDocumentation\n */\n\nimport process from 'node:process';\n\nimport { createMemory } from '@graphorin/memory';\nimport { EXIT_CODES } from '../internal/exit.js';\nimport {\n brand,\n type CommonOutputOptions,\n defaultPrintSink,\n emitReport,\n statusMarker,\n} from '../internal/output.js';\nimport { openStoreContext } from '../internal/store-context.js';\n\n/** @stable */\nexport interface MemoryCommonOptions extends CommonOutputOptions {\n readonly config?: string;\n}\n\n/** @stable */\nexport interface MemoryStatusEmbedder {\n readonly id: string;\n readonly model: string;\n readonly dim: number;\n readonly distanceMetric: string;\n readonly retired: boolean;\n readonly createdAt: string;\n readonly retiredAt?: string;\n}\n\n/** @stable */\nexport interface MemoryStatusResult {\n readonly storagePath: string;\n readonly embedders: ReadonlyArray<MemoryStatusEmbedder>;\n readonly counts: {\n readonly facts: number;\n readonly episodes: number;\n readonly sessionMessages: number;\n readonly procedures: number;\n };\n}\n\n/** @stable */\nexport async function runMemoryStatus(\n options: MemoryCommonOptions = {},\n): Promise<MemoryStatusResult> {\n const ctx = await openStoreContext({\n ...(options.config !== undefined ? { config: options.config } : {}),\n });\n try {\n const embedders = ctx.store.embeddings.listAll().map(\n (row): MemoryStatusEmbedder =>\n Object.freeze({\n id: row.id,\n model: row.model,\n dim: row.dim,\n distanceMetric: row.distanceMetric,\n retired: row.retiredAt !== null,\n createdAt: new Date(row.createdAt).toISOString(),\n ...(row.retiredAt !== null ? { retiredAt: new Date(row.retiredAt).toISOString() } : {}),\n }),\n );\n const counts = await readMemoryCounts(ctx.store);\n const out: MemoryStatusResult = Object.freeze({\n storagePath: ctx.config.storage.path,\n embedders: Object.freeze(embedders),\n counts: Object.freeze(counts),\n });\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand(`memory status (${out.storagePath})`));\n if (out.embedders.length === 0) {\n print(brand(` no embedders registered yet — run createMemory({ embedder }) once.`));\n } else {\n print(brand(` embedders (${out.embedders.length}):`));\n for (const e of out.embedders) {\n const status = e.retired ? statusMarker('warn') : statusMarker('ok');\n print(` ${status} ${e.id} (model=${e.model}, dim=${e.dim}, retired=${e.retired})`);\n }\n }\n print(\n brand(\n ` counts: facts=${out.counts.facts}, episodes=${out.counts.episodes}, sessionMessages=${out.counts.sessionMessages}, procedures=${out.counts.procedures}`,\n ),\n );\n });\n return out;\n } finally {\n await ctx.close();\n }\n}\n\n/** @stable */\nexport interface MemoryMigrateOptions extends MemoryCommonOptions {\n readonly from: string;\n readonly to: string;\n readonly strategy: 'lock-on-first' | 'auto-migrate' | 'multi-active';\n /**\n * Optional path to a JS / TS module exporting an\n * `embedders` object: `{ <id>: () => EmbedderProvider }`. The CLI\n * imports this module so it can construct the source / target\n * embedder instances the runner needs. Without the module the\n * command exits `2` with a pointer to the documentation.\n */\n readonly embeddersModule?: string;\n}\n\n/**\n * `graphorin memory migrate` — embedder swap. The migration logic lives\n * in `@graphorin/memory`'s `migrateEmbedder(...)`; the CLI prints a\n * pointer when the operator did not supply the embedder factory module\n * (the framework cannot guess the operator's embedder configuration).\n *\n * @stable\n */\nexport async function runMemoryMigrate(options: MemoryMigrateOptions): Promise<never> {\n const print = options.print ?? defaultPrintSink;\n if (options.embeddersModule === undefined) {\n print(\n brand(\n `'graphorin memory migrate' requires an --embedders module (a JS / TS file exporting { embedders: { '${options.from}': () => EmbedderProvider, '${options.to}': () => EmbedderProvider } }).`,\n ),\n );\n print(\n brand(\n 'The CLI cannot guess which embedder factory to instantiate; the framework intentionally avoids implicit network downloads (DEC-154).',\n ),\n );\n print(\n brand(\n `For programmatic migrations call migrateEmbedder({ source, target, embeddings, strategy: '${options.strategy}' }) from @graphorin/memory directly.`,\n ),\n );\n process.exit(EXIT_CODES.UNSUPPORTED);\n }\n // The full --embeddersModule wiring is out of scope for the v0.1\n // surface; the helpful message above plus the programmatic pointer\n // are the contract per the working plan acceptance criteria.\n print(\n brand(\n '--embeddersModule resolution is planned for v0.2; use migrateEmbedder() programmatically.',\n ),\n );\n process.exit(EXIT_CODES.UNSUPPORTED);\n}\n\n// ---------------------------------------------------------------------------\n// `graphorin memory inspect` / `graphorin memory activity` (X-3) — read-only\n// introspection over the SQLite store: a fact's supersede chain, quarantine /\n// provenance, the insights that cite it, the conflict decisions and audit\n// trail it appears in, plus a store-wide activity view (what the consolidator\n// / reflection formed, merged, and quarantined). All reads go through\n// `store.connection` exactly like `memory status`'s count queries — no embedder\n// or provider required, fully offline.\n// ---------------------------------------------------------------------------\n\nconst FACT_INSPECT_COLUMNS =\n 'id, text, status, provenance, importance, valid_from, valid_to, supersedes, superseded_by, created_at';\n\ninterface FactInspectRow {\n readonly id: string;\n readonly text: string;\n readonly status: string | null;\n readonly provenance: string | null;\n /** X-1 / migration 015: per-fact salience hint. */\n readonly importance: number | null;\n readonly valid_from: number | null;\n readonly valid_to: number | null;\n readonly supersedes: string | null;\n readonly superseded_by: string | null;\n readonly created_at: number;\n}\n\n/** @stable */\nexport interface MemoryInspectFact {\n readonly id: string;\n readonly text: string;\n readonly status: string;\n readonly provenance: string | null;\n /** X-1 / migration 015: per-fact importance (salience hint), if set. */\n readonly importance: number | null;\n readonly validFrom: string | null;\n readonly validTo: string | null;\n readonly supersedes: string | null;\n readonly supersededBy: string | null;\n readonly createdAt: string;\n}\n\n/**\n * A canonical entity a fact links to (P2-1 / migration 016). `name` follows\n * `merged_into` to the surviving entity, so a merged link shows its canonical.\n *\n * @stable\n */\nexport interface MemoryInspectEntity {\n readonly entityId: string;\n readonly name: string;\n readonly role: string;\n /** Set when the linked entity was merged into `entityId`/`name`. */\n readonly mergedFrom: string | null;\n}\n\n/** @stable */\nexport interface MemoryHistoryEntry {\n readonly event: string;\n readonly source: string;\n readonly createdAt: string;\n}\n\n/** @stable */\nexport interface MemoryConflictEntry {\n readonly candidateId: string;\n readonly existingId: string | null;\n readonly decision: string;\n readonly stage: string;\n readonly similarity: number | null;\n readonly detectedAt: string;\n}\n\n/** @stable */\nexport interface MemoryCitingInsight {\n readonly id: string;\n readonly text: string;\n readonly status: string;\n readonly salience: number;\n}\n\n/** @stable */\nexport interface MemoryInspectResult {\n readonly found: boolean;\n readonly fact: MemoryInspectFact | null;\n readonly chain: ReadonlyArray<MemoryInspectFact>;\n readonly history: ReadonlyArray<MemoryHistoryEntry>;\n readonly conflicts: ReadonlyArray<MemoryConflictEntry>;\n readonly citingInsights: ReadonlyArray<MemoryCitingInsight>;\n /** Canonical entities this fact links to (P2-1 / migration 016). */\n readonly linkedEntities: ReadonlyArray<MemoryInspectEntity>;\n}\n\n/** @stable */\nexport interface MemoryInspectOptions extends MemoryCommonOptions {\n readonly factId: string;\n}\n\n/**\n * `graphorin memory inspect <factId>` — surface everything the store\n * knows about one fact: its retrieval-trust status + provenance, the\n * full bi-temporal supersede chain it belongs to, the audit-log events\n * recorded against it, the conflict decisions that referenced it, and\n * the (quarantined) insights that cite it. Pure read-only inspection.\n *\n * @stable\n */\nexport async function runMemoryInspect(\n options: MemoryInspectOptions,\n): Promise<MemoryInspectResult> {\n const ctx = await openStoreContext({\n ...(options.config !== undefined ? { config: options.config } : {}),\n });\n try {\n const conn = ctx.store.connection;\n const factRow = conn.get<FactInspectRow>(\n `SELECT ${FACT_INSPECT_COLUMNS} FROM facts WHERE id = ?`,\n [options.factId],\n );\n const fact = factRow !== undefined ? toInspectFact(factRow) : null;\n const chain = factRow !== undefined ? readSupersedeChain(conn, options.factId) : [];\n const history = conn\n .all<{ event: string; source: string; created_at: number }>(\n 'SELECT event, source, created_at FROM memory_history WHERE memory_id = ? ORDER BY created_at ASC, id ASC',\n [options.factId],\n )\n .map(\n (r): MemoryHistoryEntry =>\n Object.freeze({\n event: r.event,\n source: r.source,\n createdAt: epochToIso(r.created_at) ?? '',\n }),\n );\n const conflicts = conn\n .all<{\n candidate_id: string;\n existing_id: string | null;\n decision: string;\n stage: string;\n similarity: number | null;\n detected_at: number;\n }>(\n 'SELECT candidate_id, existing_id, decision, stage, similarity, detected_at FROM fact_conflicts WHERE candidate_id = ? OR existing_id = ? ORDER BY id DESC',\n [options.factId, options.factId],\n )\n .map(\n (r): MemoryConflictEntry =>\n Object.freeze({\n candidateId: r.candidate_id,\n existingId: r.existing_id,\n decision: r.decision,\n stage: r.stage,\n similarity: r.similarity,\n detectedAt: epochToIso(r.detected_at) ?? '',\n }),\n );\n const citingInsights = conn\n .all<{ id: string; text: string; status: string; salience: number }>(\n 'SELECT id, text, status, salience FROM insights WHERE deleted_at IS NULL AND cites_json LIKE ? ORDER BY salience DESC, created_at DESC',\n [`%\"${options.factId}\"%`],\n )\n .map(\n (r): MemoryCitingInsight =>\n Object.freeze({ id: r.id, text: r.text, status: r.status, salience: r.salience }),\n );\n\n // IP-22: a fact's canonical-entity links (migration 016). Each link is\n // followed through `entities.merged_into` so a link to a merged entity\n // shows its surviving canonical.\n const linkedEntities =\n fact === null\n ? []\n : conn\n .all<{ entity_id: string; name: string; role: string; merged_from: string | null }>(\n `SELECT canon.id AS entity_id, canon.name AS name, fe.role AS role,\n CASE WHEN e.merged_into IS NULL THEN NULL ELSE e.id END AS merged_from\n FROM fact_entities fe\n JOIN entities e ON e.id = fe.entity_id\n JOIN entities canon ON canon.id = COALESCE(e.merged_into, e.id)\n WHERE fe.fact_id = ?\n ORDER BY fe.role, canon.name`,\n [options.factId],\n )\n .map(\n (r): MemoryInspectEntity =>\n Object.freeze({\n entityId: r.entity_id,\n name: r.name,\n role: r.role,\n mergedFrom: r.merged_from,\n }),\n );\n\n const out: MemoryInspectResult = Object.freeze({\n found: fact !== null,\n fact,\n chain: Object.freeze(chain),\n history: Object.freeze(history),\n conflicts: Object.freeze(conflicts),\n citingInsights: Object.freeze(citingInsights),\n linkedEntities: Object.freeze(linkedEntities),\n });\n\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand(`memory inspect ${options.factId}`));\n if (out.fact === null) {\n print(` ${statusMarker('fail')} fact not found`);\n return;\n }\n const f = out.fact;\n print(\n ` ${statusMarker(f.status === 'quarantined' ? 'warn' : 'ok')} status=${f.status} provenance=${f.provenance ?? 'user (first-party)'}`,\n );\n print(` text: ${f.text}`);\n print(\n ` importance: ${f.importance !== null ? f.importance.toFixed(2) : '(unset — neutral salience)'}`,\n );\n print(` valid: ${f.validFrom ?? 'open'} .. ${f.validTo ?? 'open'}`);\n if (out.linkedEntities.length > 0) {\n print(brand(` linked entities (${out.linkedEntities.length}):`));\n for (const e of out.linkedEntities) {\n const merged = e.mergedFrom !== null ? ` (merged from ${e.mergedFrom})` : '';\n print(` ${statusMarker('info')} ${e.role}: ${e.name} [${e.entityId}]${merged}`);\n }\n }\n if (out.chain.length > 1) {\n print(brand(` supersede chain (${out.chain.length}, oldest -> newest):`));\n for (const c of out.chain) {\n const mark = c.id === options.factId ? '*' : '-';\n print(\n ` ${mark} ${c.id} [${c.status}] ${c.validFrom ?? 'open'} .. ${c.validTo ?? 'open'}`,\n );\n }\n }\n print(brand(` audit history (${out.history.length}):`));\n for (const h of out.history) {\n print(` ${statusMarker('info')} ${h.event} by ${h.source} @ ${h.createdAt}`);\n }\n print(brand(` conflict decisions (${out.conflicts.length}):`));\n for (const c of out.conflicts) {\n const sim = c.similarity !== null ? ` sim=${c.similarity.toFixed(3)}` : '';\n print(\n ` ${c.decision}/${c.stage}${sim} ${c.candidateId} -> ${c.existingId ?? '-'} @ ${c.detectedAt}`,\n );\n }\n print(brand(` citing insights (${out.citingInsights.length}):`));\n for (const i of out.citingInsights) {\n print(\n ` ${statusMarker(i.status === 'quarantined' ? 'warn' : 'ok')} ${i.id} (salience=${i.salience}, ${i.status}) ${i.text}`,\n );\n }\n });\n return out;\n } finally {\n await ctx.close();\n }\n}\n\n/** @stable */\nexport interface MemoryActivityEvent {\n readonly memoryKind: string;\n readonly memoryId: string;\n readonly event: string;\n readonly source: string;\n readonly createdAt: string;\n}\n\n/** @stable */\nexport interface MemoryActivityConflict {\n readonly candidateId: string;\n readonly existingId: string | null;\n readonly decision: string;\n readonly stage: string;\n readonly detectedAt: string;\n}\n\n/** @stable */\nexport interface MemoryActivityResult {\n readonly quarantine: {\n readonly facts: number;\n readonly episodes: number;\n readonly insights: number;\n };\n readonly recentHistory: ReadonlyArray<MemoryActivityEvent>;\n readonly recentConflicts: ReadonlyArray<MemoryActivityConflict>;\n}\n\n/** @stable */\nexport interface MemoryActivityOptions extends MemoryCommonOptions {\n /** Cap on the recent-history / recent-conflict rows returned. Default 20. */\n readonly limit?: number;\n}\n\n/**\n * `graphorin memory activity` — a store-wide view of what the\n * consolidator and reflection passes have been doing: how many facts /\n * episodes / insights currently sit in quarantine, the most recent\n * audit-log events (supersede / validate / quarantine / archive), and\n * the most recent conflict decisions. Pure read-only inspection.\n *\n * @stable\n */\nexport async function runMemoryActivity(\n options: MemoryActivityOptions = {},\n): Promise<MemoryActivityResult> {\n const limit = Math.max(1, options.limit ?? 20);\n const ctx = await openStoreContext({\n ...(options.config !== undefined ? { config: options.config } : {}),\n });\n try {\n const conn = ctx.store.connection;\n const quarantine = Object.freeze({\n facts: countQuarantined(conn, 'facts'),\n episodes: countQuarantined(conn, 'episodes'),\n insights: countQuarantined(conn, 'insights'),\n });\n const recentHistory = conn\n .all<{\n memory_kind: string;\n memory_id: string;\n event: string;\n source: string;\n created_at: number;\n }>(\n 'SELECT memory_kind, memory_id, event, source, created_at FROM memory_history ORDER BY id DESC LIMIT ?',\n [limit],\n )\n .map(\n (r): MemoryActivityEvent =>\n Object.freeze({\n memoryKind: r.memory_kind,\n memoryId: r.memory_id,\n event: r.event,\n source: r.source,\n createdAt: epochToIso(r.created_at) ?? '',\n }),\n );\n const recentConflicts = conn\n .all<{\n candidate_id: string;\n existing_id: string | null;\n decision: string;\n stage: string;\n detected_at: number;\n }>(\n 'SELECT candidate_id, existing_id, decision, stage, detected_at FROM fact_conflicts ORDER BY id DESC LIMIT ?',\n [limit],\n )\n .map(\n (r): MemoryActivityConflict =>\n Object.freeze({\n candidateId: r.candidate_id,\n existingId: r.existing_id,\n decision: r.decision,\n stage: r.stage,\n detectedAt: epochToIso(r.detected_at) ?? '',\n }),\n );\n\n const out: MemoryActivityResult = Object.freeze({\n quarantine,\n recentHistory: Object.freeze(recentHistory),\n recentConflicts: Object.freeze(recentConflicts),\n });\n\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand('memory activity'));\n const q = out.quarantine;\n const qMarker =\n q.facts + q.episodes + q.insights > 0 ? statusMarker('warn') : statusMarker('ok');\n print(\n ` ${qMarker} quarantined: facts=${q.facts}, episodes=${q.episodes}, insights=${q.insights}`,\n );\n print(brand(` recent history (${out.recentHistory.length}):`));\n for (const h of out.recentHistory) {\n print(\n ` ${statusMarker('info')} ${h.event} ${h.memoryKind}:${h.memoryId} by ${h.source} @ ${h.createdAt}`,\n );\n }\n print(brand(` recent conflict decisions (${out.recentConflicts.length}):`));\n for (const c of out.recentConflicts) {\n print(\n ` ${c.decision}/${c.stage} ${c.candidateId} -> ${c.existingId ?? '-'} @ ${c.detectedAt}`,\n );\n }\n });\n return out;\n } finally {\n await ctx.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// `graphorin memory why` (RP-17 / X-3) — \"why was this recalled?\" Decodes the\n// `memory.search.semantic.explain` attribute the memory search records on each\n// `memory.search.semantic` span (now durable via the RP-17 `spans` table) into\n// the per-fact ranking signals (FTS bm25, vector similarity, fused RRF, decay).\n// ---------------------------------------------------------------------------\n\n/** A single decoded recall explanation surfaced by `graphorin memory why`. */\nexport interface MemoryWhyRecall {\n readonly spanId: string;\n /** Span start time (unix nanos) of the recall. */\n readonly at: number;\n readonly results: ReadonlyArray<{\n readonly id: string;\n readonly rank: number;\n readonly score: number;\n readonly signals: Readonly<Record<string, number>>;\n }>;\n}\n\n/** @stable */\nexport interface MemoryWhyResult {\n readonly recalls: ReadonlyArray<MemoryWhyRecall>;\n}\n\n/** @stable */\nexport interface MemoryWhyOptions extends MemoryCommonOptions {\n /** Restrict to one session's recall spans. */\n readonly sessionId?: string;\n /** Cap on the most-recent recall spans returned. Default 5. */\n readonly limit?: number;\n}\n\ninterface SpanExplainRow {\n readonly span_id: string;\n readonly start_unix_nano: number;\n readonly attributes_json: string;\n}\n\n/**\n * `graphorin memory why` — explain why facts were recalled, by decoding the\n * `memory.search.semantic.explain` attribute off the persisted recall spans.\n * Pure read-only inspection; requires the SQLite span exporter to have recorded\n * spans (RP-17). Empty when nothing was recorded.\n *\n * @stable\n */\nexport async function runMemoryWhy(options: MemoryWhyOptions): Promise<MemoryWhyResult> {\n const ctx = await openStoreContext({\n ...(options.config !== undefined ? { config: options.config } : {}),\n });\n try {\n const conn = ctx.store.connection;\n const limit = options.limit ?? 5;\n const rows =\n options.sessionId !== undefined\n ? conn.all<SpanExplainRow>(\n `SELECT span_id, start_unix_nano, attributes_json FROM spans\n WHERE type = 'memory.search.semantic' AND session_id = ?\n ORDER BY start_unix_nano DESC LIMIT ?`,\n [options.sessionId, limit],\n )\n : conn.all<SpanExplainRow>(\n `SELECT span_id, start_unix_nano, attributes_json FROM spans\n WHERE type = 'memory.search.semantic'\n ORDER BY start_unix_nano DESC LIMIT ?`,\n [limit],\n );\n const recalls = rows.map((r): MemoryWhyRecall => {\n let results: MemoryWhyRecall['results'] = [];\n try {\n const attrs = JSON.parse(r.attributes_json) as Record<string, unknown>;\n const raw = attrs['memory.search.semantic.explain'];\n const parsed: unknown = typeof raw === 'string' ? JSON.parse(raw) : raw;\n if (Array.isArray(parsed)) {\n results = Object.freeze(parsed) as MemoryWhyRecall['results'];\n }\n } catch {\n // Malformed attribute payload — surface an empty recall, not a throw.\n }\n return Object.freeze({ spanId: r.span_id, at: r.start_unix_nano, results });\n });\n const out: MemoryWhyResult = Object.freeze({ recalls: Object.freeze(recalls) });\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand('memory why'));\n if (recalls.length === 0) {\n print(\n ` ${statusMarker('info')} no recorded memory.search.semantic spans ` +\n `(wire createSqliteSpanExporter into the tracer to record recall explanations)`,\n );\n return;\n }\n for (const rc of recalls) {\n print(brand(` recall @ ${rc.at} (span ${rc.spanId}):`));\n for (const item of rc.results) {\n const signals = Object.entries(item.signals)\n .map(([k, v]) => `${k}=${v.toFixed(3)}`)\n .join(', ');\n print(\n ` ${statusMarker('info')} #${item.rank} ${item.id} ` +\n `score=${item.score.toFixed(3)} [${signals}]`,\n );\n }\n }\n });\n return out;\n } finally {\n await ctx.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// `graphorin memory review` (MCON-2) — list what the consolidator left in\n// quarantine across every tier, and promote a reviewed item out of it. The\n// promote path runs through the tier's `validate(...)`, so an injection-flagged\n// memory is refused unless the operator passes `--force` after review.\n// ---------------------------------------------------------------------------\n\n/** A single quarantined memory row surfaced by `graphorin memory review`. */\nexport interface MemoryReviewItem {\n readonly id: string;\n readonly text: string;\n readonly provenance: string | null;\n}\n\n/** @stable */\nexport interface MemoryReviewResult {\n /** Set when `--promote <id>` succeeded. */\n readonly promoted?: { readonly id: string; readonly type: string };\n readonly facts: ReadonlyArray<MemoryReviewItem>;\n readonly episodes: ReadonlyArray<MemoryReviewItem>;\n readonly insights: ReadonlyArray<MemoryReviewItem>;\n readonly procedures: ReadonlyArray<MemoryReviewItem>;\n}\n\n/** @stable */\nexport interface MemoryReviewOptions extends MemoryCommonOptions {\n /** Cap on the rows listed per type. Default 20. */\n readonly limit?: number;\n /** Promote this id out of quarantine instead of listing. */\n readonly promote?: string;\n /** Audit reason recorded with the promotion. */\n readonly reason?: string;\n /** Override the injection-refusal gate (operator action, after review). */\n readonly force?: boolean;\n}\n\nconst EMPTY_REVIEW: MemoryReviewResult = Object.freeze({\n facts: Object.freeze([]),\n episodes: Object.freeze([]),\n insights: Object.freeze([]),\n procedures: Object.freeze([]),\n});\n\n/**\n * `graphorin memory review` — list the facts / episodes / insights / induced\n * procedures the consolidator left in quarantine (read-only), or promote a\n * reviewed item out of quarantine with `--promote <id>`. The promote path runs\n * through the tier `validate(...)`, so an injection-flagged memory is refused\n * unless `--force` is supplied after review (MCON-2).\n *\n * @stable\n */\nexport async function runMemoryReview(\n options: MemoryReviewOptions = {},\n): Promise<MemoryReviewResult> {\n const limit = Math.max(1, options.limit ?? 20);\n const ctx = await openStoreContext({\n ...(options.config !== undefined ? { config: options.config } : {}),\n });\n try {\n const conn = ctx.store.connection;\n const print = options.print ?? defaultPrintSink;\n\n if (options.promote !== undefined) {\n const located = locateQuarantined(conn, options.promote);\n if (located === null) {\n print(`${statusMarker('warn')} '${options.promote}' is not a quarantined memory.`);\n process.exitCode = EXIT_CODES.RECOVERABLE_FAILURE;\n return EMPTY_REVIEW;\n }\n const memory = createMemory({ store: ctx.store.memory, embeddings: ctx.store.embeddings });\n const scope = { userId: located.userId };\n const validateOpts = options.force === true ? ({ force: true } as const) : undefined;\n try {\n await promoteByType(\n memory,\n located.type,\n scope,\n options.promote,\n options.reason,\n validateOpts,\n );\n } catch (err) {\n if (err instanceof Error && err.name === 'QuarantinePromotionRefusedError') {\n print(\n `${statusMarker('warn')} refused: '${options.promote}' trips the injection heuristics.`,\n );\n print(' Review it, then re-run with --force from a trusted operator context.');\n process.exitCode = EXIT_CODES.RECOVERABLE_FAILURE;\n return EMPTY_REVIEW;\n }\n throw err;\n }\n const out: MemoryReviewResult = Object.freeze({\n ...EMPTY_REVIEW,\n promoted: Object.freeze({ id: options.promote, type: located.type }),\n });\n emitReport(options, out, () => {\n print(\n `${statusMarker('ok')} promoted ${located.type} ${options.promote} out of quarantine.`,\n );\n });\n return out;\n }\n\n const out: MemoryReviewResult = Object.freeze({\n facts: listQuarantined(conn, 'facts', 'text', limit),\n episodes: listQuarantined(conn, 'episodes', 'summary', limit),\n insights: listQuarantined(conn, 'insights', 'text', limit),\n procedures: listQuarantined(conn, 'rules', 'text', limit),\n });\n emitReport(options, out, () => {\n print(brand('memory review — quarantined'));\n printReviewItems(print, 'facts', out.facts);\n printReviewItems(print, 'episodes', out.episodes);\n printReviewItems(print, 'insights', out.insights);\n printReviewItems(print, 'procedures', out.procedures);\n const total =\n out.facts.length + out.episodes.length + out.insights.length + out.procedures.length;\n if (total === 0) {\n print(` ${statusMarker('ok')} nothing in quarantine.`);\n } else {\n print(' promote with: graphorin memory review --promote <id> [--reason <text>] [--force]');\n }\n });\n return out;\n } finally {\n await ctx.close();\n }\n}\n\nfunction printReviewItems(\n print: (line: string) => void,\n label: string,\n items: ReadonlyArray<MemoryReviewItem>,\n): void {\n print(brand(` ${label} (${items.length}):`));\n for (const item of items) {\n const snippet = item.text.length > 80 ? `${item.text.slice(0, 77)}...` : item.text;\n const prov = item.provenance !== null ? ` [${item.provenance}]` : '';\n print(` ${statusMarker('warn')} ${item.id}${prov} ${snippet}`);\n }\n}\n\nfunction listQuarantined(\n conn: { all<T>(q: string, p?: ReadonlyArray<unknown>): T[] },\n table: 'facts' | 'episodes' | 'insights' | 'rules',\n textColumn: 'text' | 'summary',\n limit: number,\n): ReadonlyArray<MemoryReviewItem> {\n const rows = conn.all<{ id: string; text: string; provenance: string | null }>(\n `SELECT id, ${textColumn} AS text, provenance FROM ${table} WHERE status = 'quarantined' AND deleted_at IS NULL ORDER BY created_at DESC LIMIT ?`,\n [limit],\n );\n return Object.freeze(\n rows.map((r) => Object.freeze({ id: r.id, text: r.text, provenance: r.provenance ?? null })),\n );\n}\n\ntype QuarantineType = 'fact' | 'episode' | 'insight' | 'rule';\n\nfunction locateQuarantined(\n conn: { get<T>(q: string, p?: ReadonlyArray<unknown>): T | undefined },\n id: string,\n): { type: QuarantineType; userId: string } | null {\n const tables: ReadonlyArray<{ table: string; type: QuarantineType }> = [\n { table: 'facts', type: 'fact' },\n { table: 'episodes', type: 'episode' },\n { table: 'insights', type: 'insight' },\n { table: 'rules', type: 'rule' },\n ];\n for (const { table, type } of tables) {\n const row = conn.get<{ uid: string }>(\n `SELECT scope_user_id AS uid FROM ${table} WHERE id = ? AND status = 'quarantined' AND deleted_at IS NULL`,\n [id],\n );\n if (row !== undefined) return { type, userId: row.uid };\n }\n return null;\n}\n\nasync function promoteByType(\n memory: ReturnType<typeof createMemory>,\n type: QuarantineType,\n scope: { userId: string },\n id: string,\n reason: string | undefined,\n opts: { readonly force: true } | undefined,\n): Promise<void> {\n switch (type) {\n case 'fact':\n return memory.semantic.validate(scope, id, reason, opts);\n case 'episode':\n return memory.episodic.validate(scope, id, reason, opts);\n case 'insight':\n return memory.insights.validate(scope, id, reason, opts);\n case 'rule':\n return memory.procedural.validate(scope, id, reason, opts);\n }\n}\n\n/** Walk the bi-temporal supersede chain `factId` belongs to, oldest -> newest. */\nfunction readSupersedeChain(\n conn: {\n get<T>(q: string, p?: ReadonlyArray<unknown>): T | undefined;\n all<T>(q: string, p?: ReadonlyArray<unknown>): T[];\n },\n factId: string,\n): MemoryInspectFact[] {\n const seen = new Set<string>();\n const queue: string[] = [factId];\n const rows: FactInspectRow[] = [];\n while (queue.length > 0) {\n const id = queue.shift();\n if (id === undefined || seen.has(id)) continue;\n seen.add(id);\n const row = conn.get<FactInspectRow>(`SELECT ${FACT_INSPECT_COLUMNS} FROM facts WHERE id = ?`, [\n id,\n ]);\n if (row === undefined) continue;\n rows.push(row);\n if (row.supersedes !== null) queue.push(row.supersedes);\n if (row.superseded_by !== null) queue.push(row.superseded_by);\n for (const linked of conn.all<{ id: string }>(\n 'SELECT id FROM facts WHERE supersedes = ? OR superseded_by = ?',\n [id, id],\n )) {\n queue.push(linked.id);\n }\n }\n rows.sort((a, b) => (a.valid_from ?? a.created_at) - (b.valid_from ?? b.created_at));\n return rows.map(toInspectFact);\n}\n\nfunction toInspectFact(row: FactInspectRow): MemoryInspectFact {\n return Object.freeze({\n id: row.id,\n text: row.text,\n status: row.status ?? 'active',\n provenance: row.provenance,\n importance: row.importance,\n validFrom: epochToIso(row.valid_from),\n validTo: epochToIso(row.valid_to),\n supersedes: row.supersedes,\n supersededBy: row.superseded_by,\n createdAt: epochToIso(row.created_at) ?? new Date(0).toISOString(),\n });\n}\n\nfunction countQuarantined(\n conn: { get<T>(q: string, p?: ReadonlyArray<unknown>): T | undefined },\n table: string,\n): number {\n try {\n const row = conn.get<{ n: number }>(\n `SELECT COUNT(*) AS n FROM ${table} WHERE status = 'quarantined' AND deleted_at IS NULL`,\n );\n return typeof row?.n === 'number' ? row.n : 0;\n } catch {\n return 0;\n }\n}\n\nfunction epochToIso(epoch: number | null | undefined): string | null {\n if (epoch === null || epoch === undefined) return null;\n return new Date(epoch).toISOString();\n}\n\nasync function readMemoryCounts(\n store: Awaited<ReturnType<typeof openStoreContext>>['store'],\n): Promise<MemoryStatusResult['counts']> {\n const conn = store.connection;\n return Object.freeze({\n facts: countTable(conn, 'facts'),\n episodes: countTable(conn, 'episodes'),\n sessionMessages: countTable(conn, 'session_messages'),\n procedures: countTable(conn, 'rules'),\n });\n}\n\nfunction countTable(\n conn: { readonly get: <T = unknown>(query: string) => T | undefined },\n table: string,\n): number {\n try {\n const row = conn.get<{ n: number }>(`SELECT COUNT(*) AS n FROM ${table}`);\n return typeof row?.n === 'number' ? row.n : 0;\n } catch {\n return 0;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"memory.js","names":["out: MemoryStatusResult","out: MemoryInspectResult","out: MemoryActivityResult","results: MemoryWhyRecall['results']","parsed: unknown","out: MemoryWhyResult","EMPTY_REVIEW: MemoryReviewResult","out: MemoryReviewResult","out","queue: string[]","rows: FactInspectRow[]"],"sources":["../../src/commands/memory.ts"],"sourcesContent":["/**\n * `graphorin memory` - long-term memory operator commands.\n *\n * Surface (per Phase 15 § Memory):\n *\n * - `graphorin memory status` - counts + active embedder + migration\n * state. Pure read-only inspection of the SQLite store.\n * - `graphorin memory migrate --from <embedder> --to <embedder>\n * --strategy <lock-on-first|auto-migrate|multi-active>` - embedder\n * swap. The runner itself lives in `@graphorin/memory`\n * ({@link migrateEmbedder}); the CLI is a thin wrapper that loads\n * the operator's `embedders.ts` module if supplied through\n * `--embedders <path>`. Without that module the command emits a\n * pointer to the documentation rather than guessing which embedder\n * factory to instantiate.\n *\n * @packageDocumentation\n */\n\nimport process from 'node:process';\n\nimport { createMemory } from '@graphorin/memory';\nimport { EXIT_CODES } from '../internal/exit.js';\nimport {\n brand,\n type CommonOutputOptions,\n defaultPrintSink,\n emitReport,\n statusMarker,\n} from '../internal/output.js';\nimport { openStoreContext } from '../internal/store-context.js';\n\n/** @stable */\nexport interface MemoryCommonOptions extends CommonOutputOptions {\n readonly config?: string;\n}\n\n/** @stable */\nexport interface MemoryStatusEmbedder {\n readonly id: string;\n readonly model: string;\n readonly dim: number;\n readonly distanceMetric: string;\n readonly retired: boolean;\n readonly createdAt: string;\n readonly retiredAt?: string;\n}\n\n/** @stable */\nexport interface MemoryStatusResult {\n readonly storagePath: string;\n readonly embedders: ReadonlyArray<MemoryStatusEmbedder>;\n readonly counts: {\n readonly facts: number;\n readonly episodes: number;\n readonly sessionMessages: number;\n readonly procedures: number;\n };\n}\n\n/** @stable */\nexport async function runMemoryStatus(\n options: MemoryCommonOptions = {},\n): Promise<MemoryStatusResult> {\n const ctx = await openStoreContext({\n ...(options.config !== undefined ? { config: options.config } : {}),\n });\n try {\n const embedders = ctx.store.embeddings.listAll().map(\n (row): MemoryStatusEmbedder =>\n Object.freeze({\n id: row.id,\n model: row.model,\n dim: row.dim,\n distanceMetric: row.distanceMetric,\n retired: row.retiredAt !== null,\n createdAt: new Date(row.createdAt).toISOString(),\n ...(row.retiredAt !== null ? { retiredAt: new Date(row.retiredAt).toISOString() } : {}),\n }),\n );\n const counts = await readMemoryCounts(ctx.store);\n const out: MemoryStatusResult = Object.freeze({\n storagePath: ctx.config.storage.path,\n embedders: Object.freeze(embedders),\n counts: Object.freeze(counts),\n });\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand(`memory status (${out.storagePath})`));\n if (out.embedders.length === 0) {\n print(brand(` no embedders registered yet - run createMemory({ embedder }) once.`));\n } else {\n print(brand(` embedders (${out.embedders.length}):`));\n for (const e of out.embedders) {\n const status = e.retired ? statusMarker('warn') : statusMarker('ok');\n print(` ${status} ${e.id} (model=${e.model}, dim=${e.dim}, retired=${e.retired})`);\n }\n }\n print(\n brand(\n ` counts: facts=${out.counts.facts}, episodes=${out.counts.episodes}, sessionMessages=${out.counts.sessionMessages}, procedures=${out.counts.procedures}`,\n ),\n );\n });\n return out;\n } finally {\n await ctx.close();\n }\n}\n\n/** @stable */\nexport interface MemoryMigrateOptions extends MemoryCommonOptions {\n readonly from: string;\n readonly to: string;\n readonly strategy: 'lock-on-first' | 'auto-migrate' | 'multi-active';\n /**\n * Optional path to a JS / TS module exporting an\n * `embedders` object: `{ <id>: () => EmbedderProvider }`. The CLI\n * imports this module so it can construct the source / target\n * embedder instances the runner needs. Without the module the\n * command exits `2` with a pointer to the documentation.\n */\n readonly embeddersModule?: string;\n}\n\n/**\n * `graphorin memory migrate` - embedder swap. The migration logic lives\n * in `@graphorin/memory`'s `migrateEmbedder(...)`; the CLI prints a\n * pointer when the operator did not supply the embedder factory module\n * (the framework cannot guess the operator's embedder configuration).\n *\n * @stable\n */\nexport async function runMemoryMigrate(options: MemoryMigrateOptions): Promise<never> {\n const print = options.print ?? defaultPrintSink;\n if (options.embeddersModule === undefined) {\n print(\n brand(\n `'graphorin memory migrate' requires an --embedders module (a JS / TS file exporting { embedders: { '${options.from}': () => EmbedderProvider, '${options.to}': () => EmbedderProvider } }).`,\n ),\n );\n print(\n brand(\n 'The CLI cannot guess which embedder factory to instantiate; the framework intentionally avoids implicit network downloads (DEC-154).',\n ),\n );\n print(\n brand(\n `For programmatic migrations call migrateEmbedder({ source, target, embeddings, strategy: '${options.strategy}' }) from @graphorin/memory directly.`,\n ),\n );\n process.exit(EXIT_CODES.UNSUPPORTED);\n }\n // The full --embeddersModule wiring is out of scope for the v0.1\n // surface; the helpful message above plus the programmatic pointer\n // are the contract per the working plan acceptance criteria.\n print(\n brand(\n '--embeddersModule resolution is planned for v0.2; use migrateEmbedder() programmatically.',\n ),\n );\n process.exit(EXIT_CODES.UNSUPPORTED);\n}\n\n// ---------------------------------------------------------------------------\n// `graphorin memory inspect` / `graphorin memory activity` (X-3) - read-only\n// introspection over the SQLite store: a fact's supersede chain, quarantine /\n// provenance, the insights that cite it, the conflict decisions and audit\n// trail it appears in, plus a store-wide activity view (what the consolidator\n// / reflection formed, merged, and quarantined). All reads go through\n// `store.connection` exactly like `memory status`'s count queries - no embedder\n// or provider required, fully offline.\n// ---------------------------------------------------------------------------\n\nconst FACT_INSPECT_COLUMNS =\n 'id, text, status, provenance, importance, valid_from, valid_to, supersedes, superseded_by, created_at';\n\ninterface FactInspectRow {\n readonly id: string;\n readonly text: string;\n readonly status: string | null;\n readonly provenance: string | null;\n /** X-1 / migration 015: per-fact salience hint. */\n readonly importance: number | null;\n readonly valid_from: number | null;\n readonly valid_to: number | null;\n readonly supersedes: string | null;\n readonly superseded_by: string | null;\n readonly created_at: number;\n}\n\n/** @stable */\nexport interface MemoryInspectFact {\n readonly id: string;\n readonly text: string;\n readonly status: string;\n readonly provenance: string | null;\n /** X-1 / migration 015: per-fact importance (salience hint), if set. */\n readonly importance: number | null;\n readonly validFrom: string | null;\n readonly validTo: string | null;\n readonly supersedes: string | null;\n readonly supersededBy: string | null;\n readonly createdAt: string;\n}\n\n/**\n * A canonical entity a fact links to (P2-1 / migration 016). `name` follows\n * `merged_into` to the surviving entity, so a merged link shows its canonical.\n *\n * @stable\n */\nexport interface MemoryInspectEntity {\n readonly entityId: string;\n readonly name: string;\n readonly role: string;\n /** Set when the linked entity was merged into `entityId`/`name`. */\n readonly mergedFrom: string | null;\n}\n\n/** @stable */\nexport interface MemoryHistoryEntry {\n readonly event: string;\n readonly source: string;\n readonly createdAt: string;\n}\n\n/** @stable */\nexport interface MemoryConflictEntry {\n readonly candidateId: string;\n readonly existingId: string | null;\n readonly decision: string;\n readonly stage: string;\n readonly similarity: number | null;\n readonly detectedAt: string;\n}\n\n/** @stable */\nexport interface MemoryCitingInsight {\n readonly id: string;\n readonly text: string;\n readonly status: string;\n readonly salience: number;\n}\n\n/** @stable */\nexport interface MemoryInspectResult {\n readonly found: boolean;\n readonly fact: MemoryInspectFact | null;\n readonly chain: ReadonlyArray<MemoryInspectFact>;\n readonly history: ReadonlyArray<MemoryHistoryEntry>;\n readonly conflicts: ReadonlyArray<MemoryConflictEntry>;\n readonly citingInsights: ReadonlyArray<MemoryCitingInsight>;\n /** Canonical entities this fact links to (P2-1 / migration 016). */\n readonly linkedEntities: ReadonlyArray<MemoryInspectEntity>;\n}\n\n/** @stable */\nexport interface MemoryInspectOptions extends MemoryCommonOptions {\n readonly factId: string;\n}\n\n/**\n * `graphorin memory inspect <factId>` - surface everything the store\n * knows about one fact: its retrieval-trust status + provenance, the\n * full bi-temporal supersede chain it belongs to, the audit-log events\n * recorded against it, the conflict decisions that referenced it, and\n * the (quarantined) insights that cite it. Pure read-only inspection.\n *\n * @stable\n */\nexport async function runMemoryInspect(\n options: MemoryInspectOptions,\n): Promise<MemoryInspectResult> {\n const ctx = await openStoreContext({\n ...(options.config !== undefined ? { config: options.config } : {}),\n });\n try {\n const conn = ctx.store.connection;\n const factRow = conn.get<FactInspectRow>(\n `SELECT ${FACT_INSPECT_COLUMNS} FROM facts WHERE id = ?`,\n [options.factId],\n );\n const fact = factRow !== undefined ? toInspectFact(factRow) : null;\n const chain = factRow !== undefined ? readSupersedeChain(conn, options.factId) : [];\n const history = conn\n .all<{ event: string; source: string; created_at: number }>(\n 'SELECT event, source, created_at FROM memory_history WHERE memory_id = ? ORDER BY created_at ASC, id ASC',\n [options.factId],\n )\n .map(\n (r): MemoryHistoryEntry =>\n Object.freeze({\n event: r.event,\n source: r.source,\n createdAt: epochToIso(r.created_at) ?? '',\n }),\n );\n const conflicts = conn\n .all<{\n candidate_id: string;\n existing_id: string | null;\n decision: string;\n stage: string;\n similarity: number | null;\n detected_at: number;\n }>(\n 'SELECT candidate_id, existing_id, decision, stage, similarity, detected_at FROM fact_conflicts WHERE candidate_id = ? OR existing_id = ? ORDER BY id DESC',\n [options.factId, options.factId],\n )\n .map(\n (r): MemoryConflictEntry =>\n Object.freeze({\n candidateId: r.candidate_id,\n existingId: r.existing_id,\n decision: r.decision,\n stage: r.stage,\n similarity: r.similarity,\n detectedAt: epochToIso(r.detected_at) ?? '',\n }),\n );\n const citingInsights = conn\n .all<{ id: string; text: string; status: string; salience: number }>(\n 'SELECT id, text, status, salience FROM insights WHERE deleted_at IS NULL AND cites_json LIKE ? ORDER BY salience DESC, created_at DESC',\n [`%\"${options.factId}\"%`],\n )\n .map(\n (r): MemoryCitingInsight =>\n Object.freeze({ id: r.id, text: r.text, status: r.status, salience: r.salience }),\n );\n\n // IP-22: a fact's canonical-entity links (migration 016). Each link is\n // followed through `entities.merged_into` so a link to a merged entity\n // shows its surviving canonical.\n const linkedEntities =\n fact === null\n ? []\n : conn\n .all<{ entity_id: string; name: string; role: string; merged_from: string | null }>(\n `SELECT canon.id AS entity_id, canon.name AS name, fe.role AS role,\n CASE WHEN e.merged_into IS NULL THEN NULL ELSE e.id END AS merged_from\n FROM fact_entities fe\n JOIN entities e ON e.id = fe.entity_id\n JOIN entities canon ON canon.id = COALESCE(e.merged_into, e.id)\n WHERE fe.fact_id = ?\n ORDER BY fe.role, canon.name`,\n [options.factId],\n )\n .map(\n (r): MemoryInspectEntity =>\n Object.freeze({\n entityId: r.entity_id,\n name: r.name,\n role: r.role,\n mergedFrom: r.merged_from,\n }),\n );\n\n const out: MemoryInspectResult = Object.freeze({\n found: fact !== null,\n fact,\n chain: Object.freeze(chain),\n history: Object.freeze(history),\n conflicts: Object.freeze(conflicts),\n citingInsights: Object.freeze(citingInsights),\n linkedEntities: Object.freeze(linkedEntities),\n });\n\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand(`memory inspect ${options.factId}`));\n if (out.fact === null) {\n print(` ${statusMarker('fail')} fact not found`);\n return;\n }\n const f = out.fact;\n print(\n ` ${statusMarker(f.status === 'quarantined' ? 'warn' : 'ok')} status=${f.status} provenance=${f.provenance ?? 'user (first-party)'}`,\n );\n print(` text: ${f.text}`);\n print(\n ` importance: ${f.importance !== null ? f.importance.toFixed(2) : '(unset - neutral salience)'}`,\n );\n print(` valid: ${f.validFrom ?? 'open'} .. ${f.validTo ?? 'open'}`);\n if (out.linkedEntities.length > 0) {\n print(brand(` linked entities (${out.linkedEntities.length}):`));\n for (const e of out.linkedEntities) {\n const merged = e.mergedFrom !== null ? ` (merged from ${e.mergedFrom})` : '';\n print(` ${statusMarker('info')} ${e.role}: ${e.name} [${e.entityId}]${merged}`);\n }\n }\n if (out.chain.length > 1) {\n print(brand(` supersede chain (${out.chain.length}, oldest -> newest):`));\n for (const c of out.chain) {\n const mark = c.id === options.factId ? '*' : '-';\n print(\n ` ${mark} ${c.id} [${c.status}] ${c.validFrom ?? 'open'} .. ${c.validTo ?? 'open'}`,\n );\n }\n }\n print(brand(` audit history (${out.history.length}):`));\n for (const h of out.history) {\n print(` ${statusMarker('info')} ${h.event} by ${h.source} @ ${h.createdAt}`);\n }\n print(brand(` conflict decisions (${out.conflicts.length}):`));\n for (const c of out.conflicts) {\n const sim = c.similarity !== null ? ` sim=${c.similarity.toFixed(3)}` : '';\n print(\n ` ${c.decision}/${c.stage}${sim} ${c.candidateId} -> ${c.existingId ?? '-'} @ ${c.detectedAt}`,\n );\n }\n print(brand(` citing insights (${out.citingInsights.length}):`));\n for (const i of out.citingInsights) {\n print(\n ` ${statusMarker(i.status === 'quarantined' ? 'warn' : 'ok')} ${i.id} (salience=${i.salience}, ${i.status}) ${i.text}`,\n );\n }\n });\n return out;\n } finally {\n await ctx.close();\n }\n}\n\n/** @stable */\nexport interface MemoryActivityEvent {\n readonly memoryKind: string;\n readonly memoryId: string;\n readonly event: string;\n readonly source: string;\n readonly createdAt: string;\n}\n\n/** @stable */\nexport interface MemoryActivityConflict {\n readonly candidateId: string;\n readonly existingId: string | null;\n readonly decision: string;\n readonly stage: string;\n readonly detectedAt: string;\n}\n\n/** @stable */\nexport interface MemoryActivityResult {\n readonly quarantine: {\n readonly facts: number;\n readonly episodes: number;\n readonly insights: number;\n };\n readonly recentHistory: ReadonlyArray<MemoryActivityEvent>;\n readonly recentConflicts: ReadonlyArray<MemoryActivityConflict>;\n}\n\n/** @stable */\nexport interface MemoryActivityOptions extends MemoryCommonOptions {\n /** Cap on the recent-history / recent-conflict rows returned. Default 20. */\n readonly limit?: number;\n}\n\n/**\n * `graphorin memory activity` - a store-wide view of what the\n * consolidator and reflection passes have been doing: how many facts /\n * episodes / insights currently sit in quarantine, the most recent\n * audit-log events (supersede / validate / quarantine / archive), and\n * the most recent conflict decisions. Pure read-only inspection.\n *\n * @stable\n */\nexport async function runMemoryActivity(\n options: MemoryActivityOptions = {},\n): Promise<MemoryActivityResult> {\n const limit = Math.max(1, options.limit ?? 20);\n const ctx = await openStoreContext({\n ...(options.config !== undefined ? { config: options.config } : {}),\n });\n try {\n const conn = ctx.store.connection;\n const quarantine = Object.freeze({\n facts: countQuarantined(conn, 'facts'),\n episodes: countQuarantined(conn, 'episodes'),\n insights: countQuarantined(conn, 'insights'),\n });\n const recentHistory = conn\n .all<{\n memory_kind: string;\n memory_id: string;\n event: string;\n source: string;\n created_at: number;\n }>(\n 'SELECT memory_kind, memory_id, event, source, created_at FROM memory_history ORDER BY id DESC LIMIT ?',\n [limit],\n )\n .map(\n (r): MemoryActivityEvent =>\n Object.freeze({\n memoryKind: r.memory_kind,\n memoryId: r.memory_id,\n event: r.event,\n source: r.source,\n createdAt: epochToIso(r.created_at) ?? '',\n }),\n );\n const recentConflicts = conn\n .all<{\n candidate_id: string;\n existing_id: string | null;\n decision: string;\n stage: string;\n detected_at: number;\n }>(\n 'SELECT candidate_id, existing_id, decision, stage, detected_at FROM fact_conflicts ORDER BY id DESC LIMIT ?',\n [limit],\n )\n .map(\n (r): MemoryActivityConflict =>\n Object.freeze({\n candidateId: r.candidate_id,\n existingId: r.existing_id,\n decision: r.decision,\n stage: r.stage,\n detectedAt: epochToIso(r.detected_at) ?? '',\n }),\n );\n\n const out: MemoryActivityResult = Object.freeze({\n quarantine,\n recentHistory: Object.freeze(recentHistory),\n recentConflicts: Object.freeze(recentConflicts),\n });\n\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand('memory activity'));\n const q = out.quarantine;\n const qMarker =\n q.facts + q.episodes + q.insights > 0 ? statusMarker('warn') : statusMarker('ok');\n print(\n ` ${qMarker} quarantined: facts=${q.facts}, episodes=${q.episodes}, insights=${q.insights}`,\n );\n print(brand(` recent history (${out.recentHistory.length}):`));\n for (const h of out.recentHistory) {\n print(\n ` ${statusMarker('info')} ${h.event} ${h.memoryKind}:${h.memoryId} by ${h.source} @ ${h.createdAt}`,\n );\n }\n print(brand(` recent conflict decisions (${out.recentConflicts.length}):`));\n for (const c of out.recentConflicts) {\n print(\n ` ${c.decision}/${c.stage} ${c.candidateId} -> ${c.existingId ?? '-'} @ ${c.detectedAt}`,\n );\n }\n });\n return out;\n } finally {\n await ctx.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// `graphorin memory why` (RP-17 / X-3) - \"why was this recalled?\" Decodes the\n// `memory.search.semantic.explain` attribute the memory search records on each\n// `memory.search.semantic` span (now durable via the RP-17 `spans` table) into\n// the per-fact ranking signals (FTS bm25, vector similarity, fused RRF, decay).\n// ---------------------------------------------------------------------------\n\n/** A single decoded recall explanation surfaced by `graphorin memory why`. */\nexport interface MemoryWhyRecall {\n readonly spanId: string;\n /** Span start time (unix nanos) of the recall. */\n readonly at: number;\n readonly results: ReadonlyArray<{\n readonly id: string;\n readonly rank: number;\n readonly score: number;\n readonly signals: Readonly<Record<string, number>>;\n }>;\n}\n\n/** @stable */\nexport interface MemoryWhyResult {\n readonly recalls: ReadonlyArray<MemoryWhyRecall>;\n}\n\n/** @stable */\nexport interface MemoryWhyOptions extends MemoryCommonOptions {\n /** Restrict to one session's recall spans. */\n readonly sessionId?: string;\n /** Cap on the most-recent recall spans returned. Default 5. */\n readonly limit?: number;\n}\n\ninterface SpanExplainRow {\n readonly span_id: string;\n readonly start_unix_nano: number;\n readonly attributes_json: string;\n}\n\n/**\n * `graphorin memory why` - explain why facts were recalled, by decoding the\n * `memory.search.semantic.explain` attribute off the persisted recall spans.\n * Pure read-only inspection; requires the SQLite span exporter to have recorded\n * spans (RP-17). Empty when nothing was recorded.\n *\n * @stable\n */\nexport async function runMemoryWhy(options: MemoryWhyOptions): Promise<MemoryWhyResult> {\n const ctx = await openStoreContext({\n ...(options.config !== undefined ? { config: options.config } : {}),\n });\n try {\n const conn = ctx.store.connection;\n const limit = options.limit ?? 5;\n const rows =\n options.sessionId !== undefined\n ? conn.all<SpanExplainRow>(\n `SELECT span_id, start_unix_nano, attributes_json FROM spans\n WHERE type = 'memory.search.semantic' AND session_id = ?\n ORDER BY start_unix_nano DESC LIMIT ?`,\n [options.sessionId, limit],\n )\n : conn.all<SpanExplainRow>(\n `SELECT span_id, start_unix_nano, attributes_json FROM spans\n WHERE type = 'memory.search.semantic'\n ORDER BY start_unix_nano DESC LIMIT ?`,\n [limit],\n );\n const recalls = rows.map((r): MemoryWhyRecall => {\n let results: MemoryWhyRecall['results'] = [];\n try {\n const attrs = JSON.parse(r.attributes_json) as Record<string, unknown>;\n const raw = attrs['memory.search.semantic.explain'];\n const parsed: unknown = typeof raw === 'string' ? JSON.parse(raw) : raw;\n if (Array.isArray(parsed)) {\n results = Object.freeze(parsed) as MemoryWhyRecall['results'];\n }\n } catch {\n // Malformed attribute payload - surface an empty recall, not a throw.\n }\n return Object.freeze({ spanId: r.span_id, at: r.start_unix_nano, results });\n });\n const out: MemoryWhyResult = Object.freeze({ recalls: Object.freeze(recalls) });\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand('memory why'));\n if (recalls.length === 0) {\n print(\n ` ${statusMarker('info')} no recorded memory.search.semantic spans ` +\n `(wire createSqliteSpanExporter into the tracer to record recall explanations)`,\n );\n return;\n }\n for (const rc of recalls) {\n print(brand(` recall @ ${rc.at} (span ${rc.spanId}):`));\n for (const item of rc.results) {\n const signals = Object.entries(item.signals)\n .map(([k, v]) => `${k}=${v.toFixed(3)}`)\n .join(', ');\n print(\n ` ${statusMarker('info')} #${item.rank} ${item.id} ` +\n `score=${item.score.toFixed(3)} [${signals}]`,\n );\n }\n }\n });\n return out;\n } finally {\n await ctx.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// `graphorin memory review` (MCON-2) - list what the consolidator left in\n// quarantine across every tier, and promote a reviewed item out of it. The\n// promote path runs through the tier's `validate(...)`, so an injection-flagged\n// memory is refused unless the operator passes `--force` after review.\n// ---------------------------------------------------------------------------\n\n/** A single quarantined memory row surfaced by `graphorin memory review`. */\nexport interface MemoryReviewItem {\n readonly id: string;\n readonly text: string;\n readonly provenance: string | null;\n}\n\n/** @stable */\nexport interface MemoryReviewResult {\n /** Set when `--promote <id>` succeeded. */\n readonly promoted?: { readonly id: string; readonly type: string };\n readonly facts: ReadonlyArray<MemoryReviewItem>;\n readonly episodes: ReadonlyArray<MemoryReviewItem>;\n readonly insights: ReadonlyArray<MemoryReviewItem>;\n readonly procedures: ReadonlyArray<MemoryReviewItem>;\n}\n\n/** @stable */\nexport interface MemoryReviewOptions extends MemoryCommonOptions {\n /** Cap on the rows listed per type. Default 20. */\n readonly limit?: number;\n /** Promote this id out of quarantine instead of listing. */\n readonly promote?: string;\n /** Audit reason recorded with the promotion. */\n readonly reason?: string;\n /** Override the injection-refusal gate (operator action, after review). */\n readonly force?: boolean;\n}\n\nconst EMPTY_REVIEW: MemoryReviewResult = Object.freeze({\n facts: Object.freeze([]),\n episodes: Object.freeze([]),\n insights: Object.freeze([]),\n procedures: Object.freeze([]),\n});\n\n/**\n * `graphorin memory review` - list the facts / episodes / insights / induced\n * procedures the consolidator left in quarantine (read-only), or promote a\n * reviewed item out of quarantine with `--promote <id>`. The promote path runs\n * through the tier `validate(...)`, so an injection-flagged memory is refused\n * unless `--force` is supplied after review (MCON-2).\n *\n * @stable\n */\nexport async function runMemoryReview(\n options: MemoryReviewOptions = {},\n): Promise<MemoryReviewResult> {\n const limit = Math.max(1, options.limit ?? 20);\n const ctx = await openStoreContext({\n ...(options.config !== undefined ? { config: options.config } : {}),\n });\n try {\n const conn = ctx.store.connection;\n const print = options.print ?? defaultPrintSink;\n\n if (options.promote !== undefined) {\n const located = locateQuarantined(conn, options.promote);\n if (located === null) {\n print(`${statusMarker('warn')} '${options.promote}' is not a quarantined memory.`);\n process.exitCode = EXIT_CODES.RECOVERABLE_FAILURE;\n return EMPTY_REVIEW;\n }\n const memory = createMemory({ store: ctx.store.memory, embeddings: ctx.store.embeddings });\n const scope = { userId: located.userId };\n const validateOpts = options.force === true ? ({ force: true } as const) : undefined;\n try {\n await promoteByType(\n memory,\n located.type,\n scope,\n options.promote,\n options.reason,\n validateOpts,\n );\n } catch (err) {\n if (err instanceof Error && err.name === 'QuarantinePromotionRefusedError') {\n print(\n `${statusMarker('warn')} refused: '${options.promote}' trips the injection heuristics.`,\n );\n print(' Review it, then re-run with --force from a trusted operator context.');\n process.exitCode = EXIT_CODES.RECOVERABLE_FAILURE;\n return EMPTY_REVIEW;\n }\n throw err;\n }\n const out: MemoryReviewResult = Object.freeze({\n ...EMPTY_REVIEW,\n promoted: Object.freeze({ id: options.promote, type: located.type }),\n });\n emitReport(options, out, () => {\n print(\n `${statusMarker('ok')} promoted ${located.type} ${options.promote} out of quarantine.`,\n );\n });\n return out;\n }\n\n const out: MemoryReviewResult = Object.freeze({\n facts: listQuarantined(conn, 'facts', 'text', limit),\n episodes: listQuarantined(conn, 'episodes', 'summary', limit),\n insights: listQuarantined(conn, 'insights', 'text', limit),\n procedures: listQuarantined(conn, 'rules', 'text', limit),\n });\n emitReport(options, out, () => {\n print(brand('memory review - quarantined'));\n printReviewItems(print, 'facts', out.facts);\n printReviewItems(print, 'episodes', out.episodes);\n printReviewItems(print, 'insights', out.insights);\n printReviewItems(print, 'procedures', out.procedures);\n const total =\n out.facts.length + out.episodes.length + out.insights.length + out.procedures.length;\n if (total === 0) {\n print(` ${statusMarker('ok')} nothing in quarantine.`);\n } else {\n print(' promote with: graphorin memory review --promote <id> [--reason <text>] [--force]');\n }\n });\n return out;\n } finally {\n await ctx.close();\n }\n}\n\nfunction printReviewItems(\n print: (line: string) => void,\n label: string,\n items: ReadonlyArray<MemoryReviewItem>,\n): void {\n print(brand(` ${label} (${items.length}):`));\n for (const item of items) {\n const snippet = item.text.length > 80 ? `${item.text.slice(0, 77)}...` : item.text;\n const prov = item.provenance !== null ? ` [${item.provenance}]` : '';\n print(` ${statusMarker('warn')} ${item.id}${prov} ${snippet}`);\n }\n}\n\nfunction listQuarantined(\n conn: { all<T>(q: string, p?: ReadonlyArray<unknown>): T[] },\n table: 'facts' | 'episodes' | 'insights' | 'rules',\n textColumn: 'text' | 'summary',\n limit: number,\n): ReadonlyArray<MemoryReviewItem> {\n const rows = conn.all<{ id: string; text: string; provenance: string | null }>(\n `SELECT id, ${textColumn} AS text, provenance FROM ${table} WHERE status = 'quarantined' AND deleted_at IS NULL ORDER BY created_at DESC LIMIT ?`,\n [limit],\n );\n return Object.freeze(\n rows.map((r) => Object.freeze({ id: r.id, text: r.text, provenance: r.provenance ?? null })),\n );\n}\n\ntype QuarantineType = 'fact' | 'episode' | 'insight' | 'rule';\n\nfunction locateQuarantined(\n conn: { get<T>(q: string, p?: ReadonlyArray<unknown>): T | undefined },\n id: string,\n): { type: QuarantineType; userId: string } | null {\n const tables: ReadonlyArray<{ table: string; type: QuarantineType }> = [\n { table: 'facts', type: 'fact' },\n { table: 'episodes', type: 'episode' },\n { table: 'insights', type: 'insight' },\n { table: 'rules', type: 'rule' },\n ];\n for (const { table, type } of tables) {\n const row = conn.get<{ uid: string }>(\n `SELECT scope_user_id AS uid FROM ${table} WHERE id = ? AND status = 'quarantined' AND deleted_at IS NULL`,\n [id],\n );\n if (row !== undefined) return { type, userId: row.uid };\n }\n return null;\n}\n\nasync function promoteByType(\n memory: ReturnType<typeof createMemory>,\n type: QuarantineType,\n scope: { userId: string },\n id: string,\n reason: string | undefined,\n opts: { readonly force: true } | undefined,\n): Promise<void> {\n switch (type) {\n case 'fact':\n return memory.semantic.validate(scope, id, reason, opts);\n case 'episode':\n return memory.episodic.validate(scope, id, reason, opts);\n case 'insight':\n return memory.insights.validate(scope, id, reason, opts);\n case 'rule':\n return memory.procedural.validate(scope, id, reason, opts);\n }\n}\n\n/** Walk the bi-temporal supersede chain `factId` belongs to, oldest -> newest. */\nfunction readSupersedeChain(\n conn: {\n get<T>(q: string, p?: ReadonlyArray<unknown>): T | undefined;\n all<T>(q: string, p?: ReadonlyArray<unknown>): T[];\n },\n factId: string,\n): MemoryInspectFact[] {\n const seen = new Set<string>();\n const queue: string[] = [factId];\n const rows: FactInspectRow[] = [];\n while (queue.length > 0) {\n const id = queue.shift();\n if (id === undefined || seen.has(id)) continue;\n seen.add(id);\n const row = conn.get<FactInspectRow>(`SELECT ${FACT_INSPECT_COLUMNS} FROM facts WHERE id = ?`, [\n id,\n ]);\n if (row === undefined) continue;\n rows.push(row);\n if (row.supersedes !== null) queue.push(row.supersedes);\n if (row.superseded_by !== null) queue.push(row.superseded_by);\n for (const linked of conn.all<{ id: string }>(\n 'SELECT id FROM facts WHERE supersedes = ? OR superseded_by = ?',\n [id, id],\n )) {\n queue.push(linked.id);\n }\n }\n rows.sort((a, b) => (a.valid_from ?? a.created_at) - (b.valid_from ?? b.created_at));\n return rows.map(toInspectFact);\n}\n\nfunction toInspectFact(row: FactInspectRow): MemoryInspectFact {\n return Object.freeze({\n id: row.id,\n text: row.text,\n status: row.status ?? 'active',\n provenance: row.provenance,\n importance: row.importance,\n validFrom: epochToIso(row.valid_from),\n validTo: epochToIso(row.valid_to),\n supersedes: row.supersedes,\n supersededBy: row.superseded_by,\n createdAt: epochToIso(row.created_at) ?? new Date(0).toISOString(),\n });\n}\n\nfunction countQuarantined(\n conn: { get<T>(q: string, p?: ReadonlyArray<unknown>): T | undefined },\n table: string,\n): number {\n try {\n const row = conn.get<{ n: number }>(\n `SELECT COUNT(*) AS n FROM ${table} WHERE status = 'quarantined' AND deleted_at IS NULL`,\n );\n return typeof row?.n === 'number' ? row.n : 0;\n } catch {\n return 0;\n }\n}\n\nfunction epochToIso(epoch: number | null | undefined): string | null {\n if (epoch === null || epoch === undefined) return null;\n return new Date(epoch).toISOString();\n}\n\nasync function readMemoryCounts(\n store: Awaited<ReturnType<typeof openStoreContext>>['store'],\n): Promise<MemoryStatusResult['counts']> {\n const conn = store.connection;\n return Object.freeze({\n facts: countTable(conn, 'facts'),\n episodes: countTable(conn, 'episodes'),\n sessionMessages: countTable(conn, 'session_messages'),\n procedures: countTable(conn, 'rules'),\n });\n}\n\nfunction countTable(\n conn: { readonly get: <T = unknown>(query: string) => T | undefined },\n table: string,\n): number {\n try {\n const row = conn.get<{ n: number }>(`SELECT COUNT(*) AS n FROM ${table}`);\n return typeof row?.n === 'number' ? row.n : 0;\n } catch {\n return 0;\n }\n}\n"],"mappings":"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"}
@@ -7,7 +7,7 @@ import { parseServerConfig } from "@graphorin/server";
7
7
 
8
8
  //#region src/commands/migrate-config.ts
9
9
  /**
10
- * `graphorin migrate-config <input>` config-schema migration helper.
10
+ * `graphorin migrate-config <input>` - config-schema migration helper.
11
11
  *
12
12
  * v0.1 ships exactly one config schema; the migrator is therefore a
13
13
  * compatibility shell that round-trips the operator's config through
@@ -15,7 +15,7 @@ import { parseServerConfig } from "@graphorin/server";
15
15
  * disk. Future MAJOR bumps replace this body with the rewriter that
16
16
  * upgrades old field shapes; the CLI surface stays the same.
17
17
  *
18
- * The output path is always derived from the input `migrate-config`
18
+ * The output path is always derived from the input - `migrate-config`
19
19
  * writes `<input>.migrated` next to the source unless `--out` is
20
20
  * supplied. The original is never modified.
21
21
  *
@@ -1 +1 @@
1
- {"version":3,"file":"migrate-config.js","names":["out: MigrateConfigResult"],"sources":["../../src/commands/migrate-config.ts"],"sourcesContent":["/**\n * `graphorin migrate-config <input>` config-schema migration helper.\n *\n * v0.1 ships exactly one config schema; the migrator is therefore a\n * compatibility shell that round-trips the operator's config through\n * `parseServerConfig(...)` and writes the canonical-shape JSON back to\n * disk. Future MAJOR bumps replace this body with the rewriter that\n * upgrades old field shapes; the CLI surface stays the same.\n *\n * The output path is always derived from the input `migrate-config`\n * writes `<input>.migrated` next to the source unless `--out` is\n * supplied. The original is never modified.\n *\n * @packageDocumentation\n */\n\nimport { writeFile } from 'node:fs/promises';\nimport { isAbsolute, resolve } from 'node:path';\nimport process from 'node:process';\n\nimport { parseServerConfig } from '@graphorin/server';\n\nimport { loadConfig } from '../internal/load-config.js';\nimport {\n brand,\n type CommonOutputOptions,\n defaultPrintSink,\n emitReport,\n statusMarker,\n} from '../internal/output.js';\n\n/** @stable */\nexport interface MigrateConfigOptions extends CommonOutputOptions {\n readonly input: string;\n readonly out?: string;\n}\n\n/** @stable */\nexport interface MigrateConfigResult {\n readonly input: string;\n readonly output: string;\n readonly schemaVersion: '0.1';\n}\n\n/** @stable */\nexport async function runMigrateConfig(\n options: MigrateConfigOptions,\n): Promise<MigrateConfigResult> {\n const cwd = process.cwd();\n const inputPath = isAbsolute(options.input) ? options.input : resolve(cwd, options.input);\n const outputPath =\n options.out !== undefined\n ? isAbsolute(options.out)\n ? options.out\n : resolve(cwd, options.out)\n : `${inputPath}.migrated.json`;\n if (inputPath === outputPath) {\n throw new Error(\n `[graphorin/cli] migrate-config refuses to overwrite the input file '${inputPath}'.`,\n );\n }\n const loaded = await loadConfig(inputPath);\n const parsed = parseServerConfig(loaded.config);\n await writeFile(outputPath, `${JSON.stringify(parsed, null, 2)}\\n`, { mode: 0o600 });\n const out: MigrateConfigResult = Object.freeze({\n input: inputPath,\n output: outputPath,\n schemaVersion: '0.1',\n });\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand(`${statusMarker('ok')} migrated config v${out.schemaVersion}`));\n print(` input: ${out.input}`);\n print(` output: ${out.output}`);\n });\n return out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA6CA,eAAsB,iBACpB,SAC8B;CAC9B,MAAM,MAAM,QAAQ,KAAK;CACzB,MAAM,YAAY,WAAW,QAAQ,MAAM,GAAG,QAAQ,QAAQ,QAAQ,KAAK,QAAQ,MAAM;CACzF,MAAM,aACJ,QAAQ,QAAQ,SACZ,WAAW,QAAQ,IAAI,GACrB,QAAQ,MACR,QAAQ,KAAK,QAAQ,IAAI,GAC3B,GAAG,UAAU;AACnB,KAAI,cAAc,WAChB,OAAM,IAAI,MACR,uEAAuE,UAAU,IAClF;CAGH,MAAM,SAAS,mBADA,MAAM,WAAW,UAAU,EACF,OAAO;AAC/C,OAAM,UAAU,YAAY,GAAG,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAO,CAAC;CACpF,MAAMA,MAA2B,OAAO,OAAO;EAC7C,OAAO;EACP,QAAQ;EACR,eAAe;EAChB,CAAC;AACF,YAAW,SAAS,WAAW;EAC7B,MAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,MAAM,GAAG,aAAa,KAAK,CAAC,oBAAoB,IAAI,gBAAgB,CAAC;AAC3E,QAAM,aAAa,IAAI,QAAQ;AAC/B,QAAM,aAAa,IAAI,SAAS;GAChC;AACF,QAAO"}
1
+ {"version":3,"file":"migrate-config.js","names":["out: MigrateConfigResult"],"sources":["../../src/commands/migrate-config.ts"],"sourcesContent":["/**\n * `graphorin migrate-config <input>` - config-schema migration helper.\n *\n * v0.1 ships exactly one config schema; the migrator is therefore a\n * compatibility shell that round-trips the operator's config through\n * `parseServerConfig(...)` and writes the canonical-shape JSON back to\n * disk. Future MAJOR bumps replace this body with the rewriter that\n * upgrades old field shapes; the CLI surface stays the same.\n *\n * The output path is always derived from the input - `migrate-config`\n * writes `<input>.migrated` next to the source unless `--out` is\n * supplied. The original is never modified.\n *\n * @packageDocumentation\n */\n\nimport { writeFile } from 'node:fs/promises';\nimport { isAbsolute, resolve } from 'node:path';\nimport process from 'node:process';\n\nimport { parseServerConfig } from '@graphorin/server';\n\nimport { loadConfig } from '../internal/load-config.js';\nimport {\n brand,\n type CommonOutputOptions,\n defaultPrintSink,\n emitReport,\n statusMarker,\n} from '../internal/output.js';\n\n/** @stable */\nexport interface MigrateConfigOptions extends CommonOutputOptions {\n readonly input: string;\n readonly out?: string;\n}\n\n/** @stable */\nexport interface MigrateConfigResult {\n readonly input: string;\n readonly output: string;\n readonly schemaVersion: '0.1';\n}\n\n/** @stable */\nexport async function runMigrateConfig(\n options: MigrateConfigOptions,\n): Promise<MigrateConfigResult> {\n const cwd = process.cwd();\n const inputPath = isAbsolute(options.input) ? options.input : resolve(cwd, options.input);\n const outputPath =\n options.out !== undefined\n ? isAbsolute(options.out)\n ? options.out\n : resolve(cwd, options.out)\n : `${inputPath}.migrated.json`;\n if (inputPath === outputPath) {\n throw new Error(\n `[graphorin/cli] migrate-config refuses to overwrite the input file '${inputPath}'.`,\n );\n }\n const loaded = await loadConfig(inputPath);\n const parsed = parseServerConfig(loaded.config);\n await writeFile(outputPath, `${JSON.stringify(parsed, null, 2)}\\n`, { mode: 0o600 });\n const out: MigrateConfigResult = Object.freeze({\n input: inputPath,\n output: outputPath,\n schemaVersion: '0.1',\n });\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand(`${statusMarker('ok')} migrated config v${out.schemaVersion}`));\n print(` input: ${out.input}`);\n print(` output: ${out.output}`);\n });\n return out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA6CA,eAAsB,iBACpB,SAC8B;CAC9B,MAAM,MAAM,QAAQ,KAAK;CACzB,MAAM,YAAY,WAAW,QAAQ,MAAM,GAAG,QAAQ,QAAQ,QAAQ,KAAK,QAAQ,MAAM;CACzF,MAAM,aACJ,QAAQ,QAAQ,SACZ,WAAW,QAAQ,IAAI,GACrB,QAAQ,MACR,QAAQ,KAAK,QAAQ,IAAI,GAC3B,GAAG,UAAU;AACnB,KAAI,cAAc,WAChB,OAAM,IAAI,MACR,uEAAuE,UAAU,IAClF;CAGH,MAAM,SAAS,mBADA,MAAM,WAAW,UAAU,EACF,OAAO;AAC/C,OAAM,UAAU,YAAY,GAAG,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAO,CAAC;CACpF,MAAMA,MAA2B,OAAO,OAAO;EAC7C,OAAO;EACP,QAAQ;EACR,eAAe;EAChB,CAAC;AACF,YAAW,SAAS,WAAW;EAC7B,MAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,MAAM,GAAG,aAAa,KAAK,CAAC,oBAAoB,IAAI,gBAAgB,CAAC;AAC3E,QAAM,aAAa,IAAI,QAAQ;AAC/B,QAAM,aAAa,IAAI,SAAS;GAChC;AACF,QAAO"}
@@ -8,7 +8,7 @@ interface MigrateExportOptions extends CommonOutputOptions {
8
8
  readonly to: string;
9
9
  /** Defaults to the writer's current schema (e.g. `'1.0'`). */
10
10
  readonly toSchema?: string;
11
- /** Surfaced on the meta header. Defaults to `'graphorin-cli@0.5.0'`. */
11
+ /** Surfaced on the meta header. Defaults to `'graphorin-cli@0.6.0'`. */
12
12
  readonly writer?: string;
13
13
  }
14
14
  /** @stable */
@@ -7,7 +7,7 @@ import { SESSION_EXPORT_SCHEMA_CURRENT, createBufferSink, createSessionExportWri
7
7
 
8
8
  //#region src/commands/migrate-export.ts
9
9
  /**
10
- * `graphorin migrate-export <input> --to-schema <X.Y>` schema-version
10
+ * `graphorin migrate-export <input> --to-schema <X.Y>` - schema-version
11
11
  * migration for `graphorin-session-export/N.N` JSONL files (DEC-155 /
12
12
  * ADR-042).
13
13
  *
@@ -37,7 +37,7 @@ async function runMigrateExport(options) {
37
37
  const parsed = readSessionExport(await readFile(inputPath, "utf8"));
38
38
  const buffer = createBufferSink();
39
39
  const writer = createSessionExportWriter(buffer.sink, {
40
- writer: options.writer ?? "graphorin-cli@0.5.0",
40
+ writer: options.writer ?? "graphorin-cli@0.6.0",
41
41
  ...parsed.meta.embedderIds !== void 0 ? { embedderIds: parsed.meta.embedderIds } : {}
42
42
  });
43
43
  for (const record of parsed.records) {
@@ -1 +1 @@
1
- {"version":3,"file":"migrate-export.js","names":["out: MigrateExportResult"],"sources":["../../src/commands/migrate-export.ts"],"sourcesContent":["/**\n * `graphorin migrate-export <input> --to-schema <X.Y>` schema-version\n * migration for `graphorin-session-export/N.N` JSONL files (DEC-155 /\n * ADR-042).\n *\n * The exporter ships schema 1.0 in v0.1; the migrator's main job today\n * is to validate that the supplied input file is a well-formed session\n * export with a schema in the framework's N-2 backwards-compat band\n * and to round-trip the records through the writer with the desired\n * target schema. When the runtime reaches MAJOR 2.x / 3.x the\n * migrator extends the per-record transforms in place.\n *\n * The output path is required (`--to <file>`); the helper never\n * overwrites the input.\n *\n * @packageDocumentation\n */\n\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { isAbsolute, resolve } from 'node:path';\nimport process from 'node:process';\n\nimport {\n createBufferSink,\n createSessionExportWriter,\n readSessionExport,\n SESSION_EXPORT_SCHEMA_CURRENT,\n type SessionExportRecord,\n} from '@graphorin/sessions';\n\nimport { EXIT_CODES } from '../internal/exit.js';\nimport {\n brand,\n type CommonOutputOptions,\n defaultPrintSink,\n emitReport,\n statusMarker,\n} from '../internal/output.js';\n\n/** @stable */\nexport interface MigrateExportOptions extends CommonOutputOptions {\n readonly input: string;\n readonly to: string;\n /** Defaults to the writer's current schema (e.g. `'1.0'`). */\n readonly toSchema?: string;\n /** Surfaced on the meta header. Defaults to `'graphorin-cli@0.5.0'`. */\n readonly writer?: string;\n}\n\n/** @stable */\nexport interface MigrateExportResult {\n readonly input: string;\n readonly output: string;\n readonly schemaIn: string;\n readonly schemaOut: string;\n readonly records: number;\n}\n\n/** @stable */\nexport async function runMigrateExport(\n options: MigrateExportOptions,\n): Promise<MigrateExportResult> {\n const cwd = process.cwd();\n const inputPath = isAbsolute(options.input) ? options.input : resolve(cwd, options.input);\n const outputPath = isAbsolute(options.to) ? options.to : resolve(cwd, options.to);\n const targetSchema = options.toSchema ?? SESSION_EXPORT_SCHEMA_CURRENT;\n\n if (inputPath === outputPath) {\n throw new Error(\n `[graphorin/cli] migrate-export refuses to overwrite the input file '${inputPath}'.`,\n );\n }\n if (targetSchema !== SESSION_EXPORT_SCHEMA_CURRENT) {\n const print = options.print ?? defaultPrintSink;\n print(\n brand(\n `requested target schema '${targetSchema}' is not the writer's current schema (${SESSION_EXPORT_SCHEMA_CURRENT}); v0.1 supports the current schema only.`,\n ),\n );\n process.exit(EXIT_CODES.UNSUPPORTED);\n }\n\n const raw = await readFile(inputPath, 'utf8');\n const parsed = readSessionExport(raw);\n\n const buffer = createBufferSink();\n const writer = createSessionExportWriter(buffer.sink, {\n writer: options.writer ?? 'graphorin-cli@0.5.0',\n ...(parsed.meta.embedderIds !== undefined ? { embedderIds: parsed.meta.embedderIds } : {}),\n });\n for (const record of parsed.records) {\n if (record.kind === 'unknown') continue;\n await writer.writeRecord(record as SessionExportRecord);\n }\n await writer.close();\n await writeFile(outputPath, buffer.toString(), { mode: 0o600 });\n\n const out: MigrateExportResult = Object.freeze({\n input: inputPath,\n output: outputPath,\n schemaIn: parsed.meta.version,\n schemaOut: targetSchema,\n records: parsed.records.length,\n });\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(\n brand(\n `${statusMarker('ok')} migrated ${out.records} record(s) from schema ${out.schemaIn} -> ${out.schemaOut}`,\n ),\n );\n print(` input: ${out.input}`);\n print(` output: ${out.output}`);\n });\n return out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA2DA,eAAsB,iBACpB,SAC8B;CAC9B,MAAM,MAAM,QAAQ,KAAK;CACzB,MAAM,YAAY,WAAW,QAAQ,MAAM,GAAG,QAAQ,QAAQ,QAAQ,KAAK,QAAQ,MAAM;CACzF,MAAM,aAAa,WAAW,QAAQ,GAAG,GAAG,QAAQ,KAAK,QAAQ,KAAK,QAAQ,GAAG;CACjF,MAAM,eAAe,QAAQ,YAAY;AAEzC,KAAI,cAAc,WAChB,OAAM,IAAI,MACR,uEAAuE,UAAU,IAClF;AAEH,KAAI,iBAAiB,+BAA+B;AAElD,GADc,QAAQ,SAAS,kBAE7B,MACE,4BAA4B,aAAa,wCAAwC,8BAA8B,2CAChH,CACF;AACD,UAAQ,KAAK,WAAW,YAAY;;CAItC,MAAM,SAAS,kBADH,MAAM,SAAS,WAAW,OAAO,CACR;CAErC,MAAM,SAAS,kBAAkB;CACjC,MAAM,SAAS,0BAA0B,OAAO,MAAM;EACpD,QAAQ,QAAQ,UAAU;EAC1B,GAAI,OAAO,KAAK,gBAAgB,SAAY,EAAE,aAAa,OAAO,KAAK,aAAa,GAAG,EAAE;EAC1F,CAAC;AACF,MAAK,MAAM,UAAU,OAAO,SAAS;AACnC,MAAI,OAAO,SAAS,UAAW;AAC/B,QAAM,OAAO,YAAY,OAA8B;;AAEzD,OAAM,OAAO,OAAO;AACpB,OAAM,UAAU,YAAY,OAAO,UAAU,EAAE,EAAE,MAAM,KAAO,CAAC;CAE/D,MAAMA,MAA2B,OAAO,OAAO;EAC7C,OAAO;EACP,QAAQ;EACR,UAAU,OAAO,KAAK;EACtB,WAAW;EACX,SAAS,OAAO,QAAQ;EACzB,CAAC;AACF,YAAW,SAAS,WAAW;EAC7B,MAAM,QAAQ,QAAQ,SAAS;AAC/B,QACE,MACE,GAAG,aAAa,KAAK,CAAC,YAAY,IAAI,QAAQ,yBAAyB,IAAI,SAAS,MAAM,IAAI,YAC/F,CACF;AACD,QAAM,aAAa,IAAI,QAAQ;AAC/B,QAAM,aAAa,IAAI,SAAS;GAChC;AACF,QAAO"}
1
+ {"version":3,"file":"migrate-export.js","names":["out: MigrateExportResult"],"sources":["../../src/commands/migrate-export.ts"],"sourcesContent":["/**\n * `graphorin migrate-export <input> --to-schema <X.Y>` - schema-version\n * migration for `graphorin-session-export/N.N` JSONL files (DEC-155 /\n * ADR-042).\n *\n * The exporter ships schema 1.0 in v0.1; the migrator's main job today\n * is to validate that the supplied input file is a well-formed session\n * export with a schema in the framework's N-2 backwards-compat band\n * and to round-trip the records through the writer with the desired\n * target schema. When the runtime reaches MAJOR 2.x / 3.x the\n * migrator extends the per-record transforms in place.\n *\n * The output path is required (`--to <file>`); the helper never\n * overwrites the input.\n *\n * @packageDocumentation\n */\n\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { isAbsolute, resolve } from 'node:path';\nimport process from 'node:process';\n\nimport {\n createBufferSink,\n createSessionExportWriter,\n readSessionExport,\n SESSION_EXPORT_SCHEMA_CURRENT,\n type SessionExportRecord,\n} from '@graphorin/sessions';\n\nimport { EXIT_CODES } from '../internal/exit.js';\nimport {\n brand,\n type CommonOutputOptions,\n defaultPrintSink,\n emitReport,\n statusMarker,\n} from '../internal/output.js';\n\n/** @stable */\nexport interface MigrateExportOptions extends CommonOutputOptions {\n readonly input: string;\n readonly to: string;\n /** Defaults to the writer's current schema (e.g. `'1.0'`). */\n readonly toSchema?: string;\n /** Surfaced on the meta header. Defaults to `'graphorin-cli@0.6.0'`. */\n readonly writer?: string;\n}\n\n/** @stable */\nexport interface MigrateExportResult {\n readonly input: string;\n readonly output: string;\n readonly schemaIn: string;\n readonly schemaOut: string;\n readonly records: number;\n}\n\n/** @stable */\nexport async function runMigrateExport(\n options: MigrateExportOptions,\n): Promise<MigrateExportResult> {\n const cwd = process.cwd();\n const inputPath = isAbsolute(options.input) ? options.input : resolve(cwd, options.input);\n const outputPath = isAbsolute(options.to) ? options.to : resolve(cwd, options.to);\n const targetSchema = options.toSchema ?? SESSION_EXPORT_SCHEMA_CURRENT;\n\n if (inputPath === outputPath) {\n throw new Error(\n `[graphorin/cli] migrate-export refuses to overwrite the input file '${inputPath}'.`,\n );\n }\n if (targetSchema !== SESSION_EXPORT_SCHEMA_CURRENT) {\n const print = options.print ?? defaultPrintSink;\n print(\n brand(\n `requested target schema '${targetSchema}' is not the writer's current schema (${SESSION_EXPORT_SCHEMA_CURRENT}); v0.1 supports the current schema only.`,\n ),\n );\n process.exit(EXIT_CODES.UNSUPPORTED);\n }\n\n const raw = await readFile(inputPath, 'utf8');\n const parsed = readSessionExport(raw);\n\n const buffer = createBufferSink();\n const writer = createSessionExportWriter(buffer.sink, {\n writer: options.writer ?? 'graphorin-cli@0.6.0',\n ...(parsed.meta.embedderIds !== undefined ? { embedderIds: parsed.meta.embedderIds } : {}),\n });\n for (const record of parsed.records) {\n if (record.kind === 'unknown') continue;\n await writer.writeRecord(record as SessionExportRecord);\n }\n await writer.close();\n await writeFile(outputPath, buffer.toString(), { mode: 0o600 });\n\n const out: MigrateExportResult = Object.freeze({\n input: inputPath,\n output: outputPath,\n schemaIn: parsed.meta.version,\n schemaOut: targetSchema,\n records: parsed.records.length,\n });\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(\n brand(\n `${statusMarker('ok')} migrated ${out.records} record(s) from schema ${out.schemaIn} -> ${out.schemaOut}`,\n ),\n );\n print(` input: ${out.input}`);\n print(` output: ${out.output}`);\n });\n return out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA2DA,eAAsB,iBACpB,SAC8B;CAC9B,MAAM,MAAM,QAAQ,KAAK;CACzB,MAAM,YAAY,WAAW,QAAQ,MAAM,GAAG,QAAQ,QAAQ,QAAQ,KAAK,QAAQ,MAAM;CACzF,MAAM,aAAa,WAAW,QAAQ,GAAG,GAAG,QAAQ,KAAK,QAAQ,KAAK,QAAQ,GAAG;CACjF,MAAM,eAAe,QAAQ,YAAY;AAEzC,KAAI,cAAc,WAChB,OAAM,IAAI,MACR,uEAAuE,UAAU,IAClF;AAEH,KAAI,iBAAiB,+BAA+B;AAElD,GADc,QAAQ,SAAS,kBAE7B,MACE,4BAA4B,aAAa,wCAAwC,8BAA8B,2CAChH,CACF;AACD,UAAQ,KAAK,WAAW,YAAY;;CAItC,MAAM,SAAS,kBADH,MAAM,SAAS,WAAW,OAAO,CACR;CAErC,MAAM,SAAS,kBAAkB;CACjC,MAAM,SAAS,0BAA0B,OAAO,MAAM;EACpD,QAAQ,QAAQ,UAAU;EAC1B,GAAI,OAAO,KAAK,gBAAgB,SAAY,EAAE,aAAa,OAAO,KAAK,aAAa,GAAG,EAAE;EAC1F,CAAC;AACF,MAAK,MAAM,UAAU,OAAO,SAAS;AACnC,MAAI,OAAO,SAAS,UAAW;AAC/B,QAAM,OAAO,YAAY,OAA8B;;AAEzD,OAAM,OAAO,OAAO;AACpB,OAAM,UAAU,YAAY,OAAO,UAAU,EAAE,EAAE,MAAM,KAAO,CAAC;CAE/D,MAAMA,MAA2B,OAAO,OAAO;EAC7C,OAAO;EACP,QAAQ;EACR,UAAU,OAAO,KAAK;EACtB,WAAW;EACX,SAAS,OAAO,QAAQ;EACzB,CAAC;AACF,YAAW,SAAS,WAAW;EAC7B,MAAM,QAAQ,QAAQ,SAAS;AAC/B,QACE,MACE,GAAG,aAAa,KAAK,CAAC,YAAY,IAAI,QAAQ,yBAAyB,IAAI,SAAS,MAAM,IAAI,YAC/F,CACF;AACD,QAAM,aAAa,IAAI,QAAQ;AAC/B,QAAM,aAAa,IAAI,SAAS;GAChC;AACF,QAAO"}
@@ -1,6 +1,6 @@
1
1
  //#region src/commands/migrate.d.ts
2
2
  /**
3
- * `graphorin migrate` apply pending storage migrations.
3
+ * `graphorin migrate` - apply pending storage migrations.
4
4
  *
5
5
  * Idempotent: re-running the command after every migration has been
6
6
  * applied is a no-op + a successful exit. Failures bubble up with the
@@ -6,7 +6,7 @@ import { createSqliteStore } from "@graphorin/store-sqlite";
6
6
 
7
7
  //#region src/commands/migrate.ts
8
8
  /**
9
- * `graphorin migrate` apply pending storage migrations.
9
+ * `graphorin migrate` - apply pending storage migrations.
10
10
  *
11
11
  * Idempotent: re-running the command after every migration has been
12
12
  * applied is a no-op + a successful exit. Failures bubble up with the
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.js","names":["loaded: Awaited<ReturnType<typeof loadConfig>>","parsed: ReturnType<typeof parseServerConfig>"],"sources":["../../src/commands/migrate.ts"],"sourcesContent":["/**\n * `graphorin migrate` apply pending storage migrations.\n *\n * Idempotent: re-running the command after every migration has been\n * applied is a no-op + a successful exit. Failures bubble up with the\n * underlying SQLite error so operators can fix corrupted state.\n *\n * @packageDocumentation\n */\n\nimport process from 'node:process';\n\nimport { parseServerConfig } from '@graphorin/server';\nimport { createSqliteStore } from '@graphorin/store-sqlite';\nimport { loadConfig } from '../internal/load-config.js';\nimport { applyHardeningEarly } from './start.js';\n\n/**\n * @stable\n */\nexport interface MigrateCommandOptions {\n readonly config?: string;\n readonly target?: string;\n readonly print?: (line: string) => void;\n}\n\n/**\n * @stable\n */\nexport interface MigrateCommandResult {\n readonly applied: ReadonlyArray<string>;\n}\n\n/**\n * @stable\n */\nexport async function runMigrate(\n options: MigrateCommandOptions = {},\n): Promise<MigrateCommandResult> {\n applyHardeningEarly();\n const print = options.print ?? ((line: string) => process.stderr.write(`${line}\\n`));\n let loaded: Awaited<ReturnType<typeof loadConfig>>;\n try {\n loaded = await loadConfig(options.config);\n } catch (err) {\n print(`[graphorin/cli] ${(err as Error).message}`);\n process.exit(1);\n }\n print(`[graphorin/cli] resolved config: ${loaded.path}`);\n\n let parsed: ReturnType<typeof parseServerConfig>;\n try {\n parsed = parseServerConfig(loaded.config);\n } catch (err) {\n print(`[graphorin/cli] ${(err as Error).message}`);\n process.exit(1);\n }\n\n if (options.target !== undefined) {\n print(\n `[graphorin/cli] --target is reserved for the Phase 15 migration runner; the v0.1 store applies every pending migration in order.`,\n );\n }\n\n const store = await createSqliteStore({\n path: parsed.storage.path,\n mode: parsed.storage.mode,\n });\n try {\n await store.init();\n const ids = store.appliedMigrations.map((m) => `${m.version} (${m.name})`);\n print(`[graphorin/cli] applied ${ids.length} migration(s):`);\n for (const id of ids) {\n print(` - ${id}`);\n }\n return Object.freeze({ applied: Object.freeze(ids) });\n } catch (err) {\n print(`[graphorin/cli] migration failed: ${(err as Error).message}`);\n process.exit(1);\n } finally {\n await store.close();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoCA,eAAsB,WACpB,UAAiC,EAAE,EACJ;AAC/B,sBAAqB;CACrB,MAAM,QAAQ,QAAQ,WAAW,SAAiB,QAAQ,OAAO,MAAM,GAAG,KAAK,IAAI;CACnF,IAAIA;AACJ,KAAI;AACF,WAAS,MAAM,WAAW,QAAQ,OAAO;UAClC,KAAK;AACZ,QAAM,mBAAoB,IAAc,UAAU;AAClD,UAAQ,KAAK,EAAE;;AAEjB,OAAM,oCAAoC,OAAO,OAAO;CAExD,IAAIC;AACJ,KAAI;AACF,WAAS,kBAAkB,OAAO,OAAO;UAClC,KAAK;AACZ,QAAM,mBAAoB,IAAc,UAAU;AAClD,UAAQ,KAAK,EAAE;;AAGjB,KAAI,QAAQ,WAAW,OACrB,OACE,mIACD;CAGH,MAAM,QAAQ,MAAM,kBAAkB;EACpC,MAAM,OAAO,QAAQ;EACrB,MAAM,OAAO,QAAQ;EACtB,CAAC;AACF,KAAI;AACF,QAAM,MAAM,MAAM;EAClB,MAAM,MAAM,MAAM,kBAAkB,KAAK,MAAM,GAAG,EAAE,QAAQ,IAAI,EAAE,KAAK,GAAG;AAC1E,QAAM,2BAA2B,IAAI,OAAO,gBAAgB;AAC5D,OAAK,MAAM,MAAM,IACf,OAAM,OAAO,KAAK;AAEpB,SAAO,OAAO,OAAO,EAAE,SAAS,OAAO,OAAO,IAAI,EAAE,CAAC;UAC9C,KAAK;AACZ,QAAM,qCAAsC,IAAc,UAAU;AACpE,UAAQ,KAAK,EAAE;WACP;AACR,QAAM,MAAM,OAAO"}
1
+ {"version":3,"file":"migrate.js","names":["loaded: Awaited<ReturnType<typeof loadConfig>>","parsed: ReturnType<typeof parseServerConfig>"],"sources":["../../src/commands/migrate.ts"],"sourcesContent":["/**\n * `graphorin migrate` - apply pending storage migrations.\n *\n * Idempotent: re-running the command after every migration has been\n * applied is a no-op + a successful exit. Failures bubble up with the\n * underlying SQLite error so operators can fix corrupted state.\n *\n * @packageDocumentation\n */\n\nimport process from 'node:process';\n\nimport { parseServerConfig } from '@graphorin/server';\nimport { createSqliteStore } from '@graphorin/store-sqlite';\nimport { loadConfig } from '../internal/load-config.js';\nimport { applyHardeningEarly } from './start.js';\n\n/**\n * @stable\n */\nexport interface MigrateCommandOptions {\n readonly config?: string;\n readonly target?: string;\n readonly print?: (line: string) => void;\n}\n\n/**\n * @stable\n */\nexport interface MigrateCommandResult {\n readonly applied: ReadonlyArray<string>;\n}\n\n/**\n * @stable\n */\nexport async function runMigrate(\n options: MigrateCommandOptions = {},\n): Promise<MigrateCommandResult> {\n applyHardeningEarly();\n const print = options.print ?? ((line: string) => process.stderr.write(`${line}\\n`));\n let loaded: Awaited<ReturnType<typeof loadConfig>>;\n try {\n loaded = await loadConfig(options.config);\n } catch (err) {\n print(`[graphorin/cli] ${(err as Error).message}`);\n process.exit(1);\n }\n print(`[graphorin/cli] resolved config: ${loaded.path}`);\n\n let parsed: ReturnType<typeof parseServerConfig>;\n try {\n parsed = parseServerConfig(loaded.config);\n } catch (err) {\n print(`[graphorin/cli] ${(err as Error).message}`);\n process.exit(1);\n }\n\n if (options.target !== undefined) {\n print(\n `[graphorin/cli] --target is reserved for the Phase 15 migration runner; the v0.1 store applies every pending migration in order.`,\n );\n }\n\n const store = await createSqliteStore({\n path: parsed.storage.path,\n mode: parsed.storage.mode,\n });\n try {\n await store.init();\n const ids = store.appliedMigrations.map((m) => `${m.version} (${m.name})`);\n print(`[graphorin/cli] applied ${ids.length} migration(s):`);\n for (const id of ids) {\n print(` - ${id}`);\n }\n return Object.freeze({ applied: Object.freeze(ids) });\n } catch (err) {\n print(`[graphorin/cli] migration failed: ${(err as Error).message}`);\n process.exit(1);\n } finally {\n await store.close();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoCA,eAAsB,WACpB,UAAiC,EAAE,EACJ;AAC/B,sBAAqB;CACrB,MAAM,QAAQ,QAAQ,WAAW,SAAiB,QAAQ,OAAO,MAAM,GAAG,KAAK,IAAI;CACnF,IAAIA;AACJ,KAAI;AACF,WAAS,MAAM,WAAW,QAAQ,OAAO;UAClC,KAAK;AACZ,QAAM,mBAAoB,IAAc,UAAU;AAClD,UAAQ,KAAK,EAAE;;AAEjB,OAAM,oCAAoC,OAAO,OAAO;CAExD,IAAIC;AACJ,KAAI;AACF,WAAS,kBAAkB,OAAO,OAAO;UAClC,KAAK;AACZ,QAAM,mBAAoB,IAAc,UAAU;AAClD,UAAQ,KAAK,EAAE;;AAGjB,KAAI,QAAQ,WAAW,OACrB,OACE,mIACD;CAGH,MAAM,QAAQ,MAAM,kBAAkB;EACpC,MAAM,OAAO,QAAQ;EACrB,MAAM,OAAO,QAAQ;EACtB,CAAC;AACF,KAAI;AACF,QAAM,MAAM,MAAM;EAClB,MAAM,MAAM,MAAM,kBAAkB,KAAK,MAAM,GAAG,EAAE,QAAQ,IAAI,EAAE,KAAK,GAAG;AAC1E,QAAM,2BAA2B,IAAI,OAAO,gBAAgB;AAC5D,OAAK,MAAM,MAAM,IACf,OAAM,OAAO,KAAK;AAEpB,SAAO,OAAO,OAAO,EAAE,SAAS,OAAO,OAAO,IAAI,EAAE,CAAC;UAC9C,KAAK;AACZ,QAAM,qCAAsC,IAAc,UAAU;AACpE,UAAQ,KAAK,EAAE;WACP;AACR,QAAM,MAAM,OAAO"}
@@ -23,7 +23,7 @@ interface PricingRefreshOptions extends PricingCommonOptions {
23
23
  * CLI prints a status summary only; `--out` triggers a JSON write.
24
24
  */
25
25
  readonly out?: string;
26
- /** Test seam inject a fetch implementation. */
26
+ /** Test seam - inject a fetch implementation. */
27
27
  readonly fetchImpl?: typeof fetch;
28
28
  }
29
29
  /** @stable */
@@ -7,19 +7,19 @@ import { BUNDLED_SNAPSHOT, SNAPSHOT_DATE, computeEntriesDigest, diffPricing, lis
7
7
 
8
8
  //#region src/commands/pricing.ts
9
9
  /**
10
- * `graphorin pricing` operate on the bundled LLM pricing snapshot.
10
+ * `graphorin pricing` - operate on the bundled LLM pricing snapshot.
11
11
  *
12
12
  * Surface (per Phase 15 § Pricing):
13
13
  *
14
- * - `graphorin pricing status` bundled snapshot version + entry
14
+ * - `graphorin pricing status` - bundled snapshot version + entry
15
15
  * count + canonical digest.
16
- * - `graphorin pricing refresh --url <url>` opt-in network call
16
+ * - `graphorin pricing refresh --url <url>` - opt-in network call
17
17
  * that fetches a fresh snapshot. Honours `GRAPHORIN_OFFLINE=1`.
18
- * - `graphorin pricing diff` row-by-row delta vs the bundled
18
+ * - `graphorin pricing diff` - row-by-row delta vs the bundled
19
19
  * snapshot.
20
- * - `graphorin pricing lookup --provider <name> --model <id>` print
20
+ * - `graphorin pricing lookup --provider <name> --model <id>` - print
21
21
  * the per-token price for a single (provider, model) pair.
22
- * - `graphorin pricing missing` read trace spans from a JSON file
22
+ * - `graphorin pricing missing` - read trace spans from a JSON file
23
23
  * and report unknown (provider, model) pairs.
24
24
  *
25
25
  * @packageDocumentation
@@ -1 +1 @@
1
- {"version":3,"file":"pricing.js","names":["out: PricingStatusResult","result: { entries: number; version: string; out?: string }","parsed: unknown"],"sources":["../../src/commands/pricing.ts"],"sourcesContent":["/**\n * `graphorin pricing` — operate on the bundled LLM pricing snapshot.\n *\n * Surface (per Phase 15 § Pricing):\n *\n * - `graphorin pricing status` — bundled snapshot version + entry\n * count + canonical digest.\n * - `graphorin pricing refresh --url <url>` — opt-in network call\n * that fetches a fresh snapshot. Honours `GRAPHORIN_OFFLINE=1`.\n * - `graphorin pricing diff` — row-by-row delta vs the bundled\n * snapshot.\n * - `graphorin pricing lookup --provider <name> --model <id>` — print\n * the per-token price for a single (provider, model) pair.\n * - `graphorin pricing missing` — read trace spans from a JSON file\n * and report unknown (provider, model) pairs.\n *\n * @packageDocumentation\n */\n\nimport { readFile, writeFile } from 'node:fs/promises';\nimport process from 'node:process';\n\nimport {\n BUNDLED_SNAPSHOT,\n computeEntriesDigest,\n diffPricing,\n listMissingModels,\n lookupPrice,\n type PricingDiffEntry,\n type PricingSnapshot,\n refreshPricing,\n SNAPSHOT_DATE,\n} from '@graphorin/pricing';\n\nimport { EXIT_CODES } from '../internal/exit.js';\nimport { checkOfflineModeBlocked } from '../internal/offline.js';\nimport {\n brand,\n type CommonOutputOptions,\n defaultPrintSink,\n emitReport,\n statusMarker,\n} from '../internal/output.js';\n\n/** @stable */\nexport interface PricingCommonOptions extends CommonOutputOptions {}\n\n/** @stable */\nexport interface PricingStatusResult {\n readonly version: string;\n readonly snapshotDate: string;\n readonly entries: number;\n readonly digest: string;\n}\n\n/** @stable */\nexport function runPricingStatus(options: PricingCommonOptions = {}): PricingStatusResult {\n const out: PricingStatusResult = Object.freeze({\n version: BUNDLED_SNAPSHOT.version,\n snapshotDate: SNAPSHOT_DATE,\n entries: BUNDLED_SNAPSHOT.entries.length,\n digest: computeEntriesDigest(BUNDLED_SNAPSHOT.entries),\n });\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand(`pricing snapshot v${out.version} (${out.snapshotDate})`));\n print(` entries: ${out.entries}`);\n print(` digest: ${out.digest}`);\n });\n return out;\n}\n\n/** @stable */\nexport interface PricingRefreshOptions extends PricingCommonOptions {\n readonly url: string;\n /**\n * Optional path to write the refreshed snapshot to. When omitted the\n * CLI prints a status summary only; `--out` triggers a JSON write.\n */\n readonly out?: string;\n /** Test seam — inject a fetch implementation. */\n readonly fetchImpl?: typeof fetch;\n}\n\n/** @stable */\nexport async function runPricingRefresh(\n options: PricingRefreshOptions,\n): Promise<{ readonly entries: number; readonly version: string; readonly out?: string }> {\n if (\n !checkOfflineModeBlocked('pricing refresh', {\n ...(options.print !== undefined ? { print: options.print } : {}),\n })\n ) {\n process.exit(EXIT_CODES.RECOVERABLE_FAILURE);\n }\n const refreshed = await refreshPricing({\n url: options.url,\n ...(options.fetchImpl !== undefined ? { fetchImpl: options.fetchImpl } : {}),\n });\n if (options.out !== undefined) {\n await writeFile(options.out, JSON.stringify(refreshed, null, 2), { mode: 0o600 });\n }\n const result: { entries: number; version: string; out?: string } = {\n entries: refreshed.entries.length,\n version: refreshed.version,\n ...(options.out !== undefined ? { out: options.out } : {}),\n };\n emitReport(options, result, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand(`refreshed pricing snapshot v${result.version} (${result.entries} entries).`));\n if (result.out !== undefined) print(brand(`written to ${result.out} (mode 0600).`));\n });\n return result;\n}\n\n/** @stable */\nexport interface PricingDiffOptions extends PricingCommonOptions {\n /**\n * Path to a JSON file containing a `PricingSnapshot`. The CLI diffs\n * this against the bundled snapshot.\n */\n readonly snapshot: string;\n}\n\n/** @stable */\nexport async function runPricingDiff(\n options: PricingDiffOptions,\n): Promise<ReadonlyArray<PricingDiffEntry>> {\n const right = await readSnapshot(options.snapshot);\n const diff = diffPricing(BUNDLED_SNAPSHOT, right);\n emitReport(options, diff, () => {\n const print = options.print ?? defaultPrintSink;\n if (diff.length === 0) {\n print(brand('no diff between bundled snapshot and supplied snapshot.'));\n return;\n }\n print(brand(`${diff.length} pricing diff row(s):`));\n for (const row of diff) {\n print(` ${statusMarker('warn')} ${row.kind} ${row.provider}/${row.model}`);\n }\n });\n return diff;\n}\n\n/** @stable */\nexport interface PricingLookupOptions extends PricingCommonOptions {\n readonly provider: string;\n readonly model: string;\n readonly region?: string;\n}\n\n/** @stable */\nexport function runPricingLookup(options: PricingLookupOptions) {\n const result = lookupPrice({\n provider: options.provider,\n model: options.model,\n ...(options.region !== undefined ? { region: options.region } : {}),\n });\n emitReport(options, result, () => {\n const print = options.print ?? defaultPrintSink;\n if (result === null) {\n print(brand(`no pricing entry for ${options.provider}/${options.model}.`));\n process.exitCode = EXIT_CODES.RECOVERABLE_FAILURE;\n return;\n }\n print(\n brand(\n `${options.provider}/${options.model}: input=${result.inputUsdPerToken} / output=${result.outputUsdPerToken} USD per token (source=${result.source}, snapshot=${result.snapshotDate})`,\n ),\n );\n });\n return result;\n}\n\n/** @stable */\nexport interface PricingMissingOptions extends PricingCommonOptions {\n /**\n * Path to a JSON file containing an array of trace spans (each with\n * an `attributes` map). Output of `graphorin traces export` (Phase\n * 15) is the canonical source.\n */\n readonly spans: string;\n}\n\n/** @stable */\nexport async function runPricingMissing(options: PricingMissingOptions) {\n const raw = await readFile(options.spans, 'utf8');\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(\n `[graphorin/cli] '${options.spans}' is not valid JSON: ${(err as Error).message}`,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new Error(`[graphorin/cli] '${options.spans}' must contain an array of trace spans.`);\n }\n // The pricing helper trusts the shape; we cast through unknown.\n const missing = listMissingModels(\n parsed as ReadonlyArray<{ readonly attributes: Record<string, unknown> }>,\n );\n emitReport(options, missing, () => {\n const print = options.print ?? defaultPrintSink;\n if (missing.length === 0) {\n print(brand('every (provider, model) pair in the spans is present in the bundled snapshot.'));\n return;\n }\n print(brand(`${missing.length} unknown (provider, model) pair(s):`));\n for (const m of missing) {\n print(` ${statusMarker('warn')} ${m.provider}/${m.model} (${m.count} span(s))`);\n }\n });\n return missing;\n}\n\nasync function readSnapshot(path: string): Promise<PricingSnapshot> {\n const raw = await readFile(path, 'utf8');\n try {\n return JSON.parse(raw) as PricingSnapshot;\n } catch (err) {\n throw new Error(\n `[graphorin/cli] '${path}' is not a valid pricing snapshot JSON: ${(err as Error).message}`,\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pricing.js","names":["out: PricingStatusResult","result: { entries: number; version: string; out?: string }","parsed: unknown"],"sources":["../../src/commands/pricing.ts"],"sourcesContent":["/**\n * `graphorin pricing` - operate on the bundled LLM pricing snapshot.\n *\n * Surface (per Phase 15 § Pricing):\n *\n * - `graphorin pricing status` - bundled snapshot version + entry\n * count + canonical digest.\n * - `graphorin pricing refresh --url <url>` - opt-in network call\n * that fetches a fresh snapshot. Honours `GRAPHORIN_OFFLINE=1`.\n * - `graphorin pricing diff` - row-by-row delta vs the bundled\n * snapshot.\n * - `graphorin pricing lookup --provider <name> --model <id>` - print\n * the per-token price for a single (provider, model) pair.\n * - `graphorin pricing missing` - read trace spans from a JSON file\n * and report unknown (provider, model) pairs.\n *\n * @packageDocumentation\n */\n\nimport { readFile, writeFile } from 'node:fs/promises';\nimport process from 'node:process';\n\nimport {\n BUNDLED_SNAPSHOT,\n computeEntriesDigest,\n diffPricing,\n listMissingModels,\n lookupPrice,\n type PricingDiffEntry,\n type PricingSnapshot,\n refreshPricing,\n SNAPSHOT_DATE,\n} from '@graphorin/pricing';\n\nimport { EXIT_CODES } from '../internal/exit.js';\nimport { checkOfflineModeBlocked } from '../internal/offline.js';\nimport {\n brand,\n type CommonOutputOptions,\n defaultPrintSink,\n emitReport,\n statusMarker,\n} from '../internal/output.js';\n\n/** @stable */\nexport interface PricingCommonOptions extends CommonOutputOptions {}\n\n/** @stable */\nexport interface PricingStatusResult {\n readonly version: string;\n readonly snapshotDate: string;\n readonly entries: number;\n readonly digest: string;\n}\n\n/** @stable */\nexport function runPricingStatus(options: PricingCommonOptions = {}): PricingStatusResult {\n const out: PricingStatusResult = Object.freeze({\n version: BUNDLED_SNAPSHOT.version,\n snapshotDate: SNAPSHOT_DATE,\n entries: BUNDLED_SNAPSHOT.entries.length,\n digest: computeEntriesDigest(BUNDLED_SNAPSHOT.entries),\n });\n emitReport(options, out, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand(`pricing snapshot v${out.version} (${out.snapshotDate})`));\n print(` entries: ${out.entries}`);\n print(` digest: ${out.digest}`);\n });\n return out;\n}\n\n/** @stable */\nexport interface PricingRefreshOptions extends PricingCommonOptions {\n readonly url: string;\n /**\n * Optional path to write the refreshed snapshot to. When omitted the\n * CLI prints a status summary only; `--out` triggers a JSON write.\n */\n readonly out?: string;\n /** Test seam - inject a fetch implementation. */\n readonly fetchImpl?: typeof fetch;\n}\n\n/** @stable */\nexport async function runPricingRefresh(\n options: PricingRefreshOptions,\n): Promise<{ readonly entries: number; readonly version: string; readonly out?: string }> {\n if (\n !checkOfflineModeBlocked('pricing refresh', {\n ...(options.print !== undefined ? { print: options.print } : {}),\n })\n ) {\n process.exit(EXIT_CODES.RECOVERABLE_FAILURE);\n }\n const refreshed = await refreshPricing({\n url: options.url,\n ...(options.fetchImpl !== undefined ? { fetchImpl: options.fetchImpl } : {}),\n });\n if (options.out !== undefined) {\n await writeFile(options.out, JSON.stringify(refreshed, null, 2), { mode: 0o600 });\n }\n const result: { entries: number; version: string; out?: string } = {\n entries: refreshed.entries.length,\n version: refreshed.version,\n ...(options.out !== undefined ? { out: options.out } : {}),\n };\n emitReport(options, result, () => {\n const print = options.print ?? defaultPrintSink;\n print(brand(`refreshed pricing snapshot v${result.version} (${result.entries} entries).`));\n if (result.out !== undefined) print(brand(`written to ${result.out} (mode 0600).`));\n });\n return result;\n}\n\n/** @stable */\nexport interface PricingDiffOptions extends PricingCommonOptions {\n /**\n * Path to a JSON file containing a `PricingSnapshot`. The CLI diffs\n * this against the bundled snapshot.\n */\n readonly snapshot: string;\n}\n\n/** @stable */\nexport async function runPricingDiff(\n options: PricingDiffOptions,\n): Promise<ReadonlyArray<PricingDiffEntry>> {\n const right = await readSnapshot(options.snapshot);\n const diff = diffPricing(BUNDLED_SNAPSHOT, right);\n emitReport(options, diff, () => {\n const print = options.print ?? defaultPrintSink;\n if (diff.length === 0) {\n print(brand('no diff between bundled snapshot and supplied snapshot.'));\n return;\n }\n print(brand(`${diff.length} pricing diff row(s):`));\n for (const row of diff) {\n print(` ${statusMarker('warn')} ${row.kind} ${row.provider}/${row.model}`);\n }\n });\n return diff;\n}\n\n/** @stable */\nexport interface PricingLookupOptions extends PricingCommonOptions {\n readonly provider: string;\n readonly model: string;\n readonly region?: string;\n}\n\n/** @stable */\nexport function runPricingLookup(options: PricingLookupOptions) {\n const result = lookupPrice({\n provider: options.provider,\n model: options.model,\n ...(options.region !== undefined ? { region: options.region } : {}),\n });\n emitReport(options, result, () => {\n const print = options.print ?? defaultPrintSink;\n if (result === null) {\n print(brand(`no pricing entry for ${options.provider}/${options.model}.`));\n process.exitCode = EXIT_CODES.RECOVERABLE_FAILURE;\n return;\n }\n print(\n brand(\n `${options.provider}/${options.model}: input=${result.inputUsdPerToken} / output=${result.outputUsdPerToken} USD per token (source=${result.source}, snapshot=${result.snapshotDate})`,\n ),\n );\n });\n return result;\n}\n\n/** @stable */\nexport interface PricingMissingOptions extends PricingCommonOptions {\n /**\n * Path to a JSON file containing an array of trace spans (each with\n * an `attributes` map). Output of `graphorin traces export` (Phase\n * 15) is the canonical source.\n */\n readonly spans: string;\n}\n\n/** @stable */\nexport async function runPricingMissing(options: PricingMissingOptions) {\n const raw = await readFile(options.spans, 'utf8');\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(\n `[graphorin/cli] '${options.spans}' is not valid JSON: ${(err as Error).message}`,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new Error(`[graphorin/cli] '${options.spans}' must contain an array of trace spans.`);\n }\n // The pricing helper trusts the shape; we cast through unknown.\n const missing = listMissingModels(\n parsed as ReadonlyArray<{ readonly attributes: Record<string, unknown> }>,\n );\n emitReport(options, missing, () => {\n const print = options.print ?? defaultPrintSink;\n if (missing.length === 0) {\n print(brand('every (provider, model) pair in the spans is present in the bundled snapshot.'));\n return;\n }\n print(brand(`${missing.length} unknown (provider, model) pair(s):`));\n for (const m of missing) {\n print(` ${statusMarker('warn')} ${m.provider}/${m.model} (${m.count} span(s))`);\n }\n });\n return missing;\n}\n\nasync function readSnapshot(path: string): Promise<PricingSnapshot> {\n const raw = await readFile(path, 'utf8');\n try {\n return JSON.parse(raw) as PricingSnapshot;\n } catch (err) {\n throw new Error(\n `[graphorin/cli] '${path}' is not a valid pricing snapshot JSON: ${(err as Error).message}`,\n );\n }\n}\n"],"mappings":"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"}
@@ -81,7 +81,7 @@ interface SecretsRotateOptions extends SecretsCommonOptions {
81
81
  readonly fromStdin?: boolean;
82
82
  }
83
83
  /**
84
- * `graphorin secrets rotate <key>` overwrite the existing value
84
+ * `graphorin secrets rotate <key>` - overwrite the existing value
85
85
  * with a fresh one. Functionally identical to `set` but the CLI
86
86
  * surfaces the operation explicitly so audit logs can distinguish
87
87
  * a rotation from an initial write.
@@ -5,7 +5,7 @@ import { SecretValue, createSecretsStore, getActiveSecretsStore, parseSecretRef,
5
5
 
6
6
  //#region src/commands/secrets.ts
7
7
  /**
8
- * `graphorin secrets` manage the operator's secrets store.
8
+ * `graphorin secrets` - manage the operator's secrets store.
9
9
  *
10
10
  * Surface (per Phase 15 § Secrets):
11
11
  *
@@ -13,11 +13,11 @@ import { SecretValue, createSecretsStore, getActiveSecretsStore, parseSecretRef,
13
13
  * - `graphorin secrets get <key>`
14
14
  * - `graphorin secrets set <key> [--value <v>] [--from-stdin] [--scope <ref>]`
15
15
  * - `graphorin secrets delete <key>`
16
- * - `graphorin secrets ref <uri>` test resolution of a `SecretRef` URI.
16
+ * - `graphorin secrets ref <uri>` - test resolution of a `SecretRef` URI.
17
17
  * - `graphorin secrets rotate <key> --new-value <v>`
18
18
  *
19
19
  * Honours `--secrets-source <kind>` and `--strict-secrets` per
20
- * DEC-136 both flags are forwarded to `createSecretsStore(...)` so
20
+ * DEC-136 - both flags are forwarded to `createSecretsStore(...)` so
21
21
  * the CLI activates the same store the running server would.
22
22
  *
23
23
  * The CLI never logs raw secret bytes. `get` prints the value through
@@ -136,7 +136,7 @@ async function runSecretsRef(options) {
136
136
  }
137
137
  }
138
138
  /**
139
- * `graphorin secrets rotate <key>` overwrite the existing value
139
+ * `graphorin secrets rotate <key>` - overwrite the existing value
140
140
  * with a fresh one. Functionally identical to `set` but the CLI
141
141
  * surfaces the operation explicitly so audit logs can distinguish
142
142
  * a rotation from an initial write.
@@ -145,7 +145,7 @@ async function runSecretsRef(options) {
145
145
  */
146
146
  async function runSecretsRotate(options) {
147
147
  const store = await openStore(options);
148
- if (await store.get(options.key) === null) throw new Error(`[graphorin/cli] cannot rotate '${options.key}' secret does not exist (use 'graphorin secrets set' to create it).`);
148
+ if (await store.get(options.key) === null) throw new Error(`[graphorin/cli] cannot rotate '${options.key}' - secret does not exist (use 'graphorin secrets set' to create it).`);
149
149
  let raw = options.newValue;
150
150
  if (raw === void 0 && options.fromStdin === true) raw = await readStdin();
151
151
  if (raw === void 0) throw new Error("[graphorin/cli] secrets rotate requires either --new-value <v> or --from-stdin.");