@jungjaehoon/mama-core 1.8.1 → 2.0.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 (136) hide show
  1. package/dist/agent-graph/alias-write.js +3 -0
  2. package/dist/agent-graph/entity-resolve.js +3 -7
  3. package/dist/agent-graph/graph-query.js +5 -4
  4. package/dist/agent-graph/types.d.ts +30 -0
  5. package/dist/cases/store.d.ts +0 -4
  6. package/dist/cases/store.js +0 -66
  7. package/dist/cases/wiki-page-index.d.ts +0 -13
  8. package/dist/cases/wiki-page-index.js +0 -153
  9. package/dist/connectors/event-index.d.ts +1 -22
  10. package/dist/connectors/event-index.js +0 -157
  11. package/dist/context-compile/channel-grant.d.ts +46 -0
  12. package/dist/context-compile/channel-grant.js +66 -0
  13. package/dist/context-compile/compiler.js +5 -2
  14. package/dist/context-compile/index.d.ts +1 -0
  15. package/dist/context-compile/index.js +1 -0
  16. package/dist/context-compile/packet-store.d.ts +0 -1
  17. package/dist/context-compile/packet-store.js +0 -16
  18. package/dist/context-compile/source-readers.d.ts +1 -0
  19. package/dist/context-compile/source-readers.js +156 -23
  20. package/dist/context-compile/types.d.ts +17 -0
  21. package/dist/context-compile/visibility.js +28 -4
  22. package/dist/db-adapter/node-sqlite-adapter.js +4 -0
  23. package/dist/db-manager.d.ts +0 -13
  24. package/dist/db-manager.js +0 -66
  25. package/dist/decision-formatter.d.ts +0 -11
  26. package/dist/decision-formatter.js +0 -122
  27. package/dist/decision-tracker.d.ts +0 -12
  28. package/dist/decision-tracker.js +0 -50
  29. package/dist/edges/ref-validation.d.ts +1 -2
  30. package/dist/edges/ref-validation.js +33 -13
  31. package/dist/edges/store.d.ts +1 -3
  32. package/dist/edges/store.js +0 -214
  33. package/dist/edges/types.d.ts +10 -0
  34. package/dist/embedding-client.d.ts +0 -17
  35. package/dist/embedding-client.js +0 -80
  36. package/dist/embedding-server/mobile/auth.d.ts +1 -10
  37. package/dist/embedding-server/mobile/auth.js +0 -15
  38. package/dist/embeddings.d.ts +0 -12
  39. package/dist/embeddings.js +0 -68
  40. package/dist/entities/audit-metrics.d.ts +0 -5
  41. package/dist/entities/audit-metrics.js +0 -4
  42. package/dist/entities/candidate-generator.d.ts +1 -2
  43. package/dist/entities/candidate-generator.js +0 -412
  44. package/dist/entities/entity-list.d.ts +0 -1
  45. package/dist/entities/entity-list.js +0 -96
  46. package/dist/entities/entity-orphan-list.d.ts +0 -9
  47. package/dist/entities/entity-orphan-list.js +0 -88
  48. package/dist/entities/entity-search.d.ts +0 -1
  49. package/dist/entities/entity-search.js +0 -147
  50. package/dist/entities/errors.d.ts +0 -10
  51. package/dist/entities/errors.js +1 -25
  52. package/dist/entities/lineage-store.d.ts +0 -23
  53. package/dist/entities/lineage-store.js +0 -104
  54. package/dist/entities/policy-store.d.ts +0 -9
  55. package/dist/entities/policy-store.js +0 -188
  56. package/dist/entities/provenance-query.d.ts +0 -1
  57. package/dist/entities/provenance-query.js +0 -164
  58. package/dist/entities/resolution-engine.d.ts +1 -8
  59. package/dist/entities/resolution-engine.js +0 -66
  60. package/dist/entities/rollback-preview.d.ts +0 -4
  61. package/dist/entities/rollback-preview.js +0 -232
  62. package/dist/entities/store.d.ts +1 -10
  63. package/dist/entities/store.js +0 -49
  64. package/dist/index.d.ts +15 -31
  65. package/dist/index.js +4 -46
  66. package/dist/mama-api.d.ts +19 -1
  67. package/dist/mama-api.js +97 -2
  68. package/dist/memory/api.d.ts +9 -0
  69. package/dist/memory/api.js +68 -4
  70. package/dist/memory/event-store.d.ts +0 -1
  71. package/dist/memory/event-store.js +0 -15
  72. package/dist/memory/finding-store.d.ts +0 -1
  73. package/dist/memory/finding-store.js +0 -12
  74. package/dist/memory/scope-backfill.d.ts +0 -3
  75. package/dist/memory/scope-backfill.js +0 -74
  76. package/dist/memory/scope-store.d.ts +0 -1
  77. package/dist/memory/scope-store.js +0 -4
  78. package/dist/memory/truth-store.d.ts +0 -3
  79. package/dist/memory/truth-store.js +0 -22
  80. package/dist/memory/types.d.ts +0 -1
  81. package/dist/memory/types.js +0 -13
  82. package/dist/memory-store.d.ts +0 -16
  83. package/dist/memory-store.js +0 -51
  84. package/dist/ollama-client.d.ts +0 -9
  85. package/dist/ollama-client.js +0 -125
  86. package/dist/outcome-tracker.d.ts +0 -14
  87. package/dist/outcome-tracker.js +0 -44
  88. package/dist/progress-indicator.d.ts +0 -4
  89. package/dist/progress-indicator.js +0 -7
  90. package/dist/provenance/source-ref.d.ts +0 -9
  91. package/dist/provenance/source-ref.js +0 -145
  92. package/dist/query-intent.d.ts +0 -4
  93. package/dist/query-intent.js +0 -30
  94. package/dist/relevance-scorer.d.ts +0 -9
  95. package/dist/relevance-scorer.js +0 -81
  96. package/dist/search/feedback-store.d.ts +0 -1
  97. package/dist/search/feedback-store.js +0 -4
  98. package/dist/search/ranker-rescore.d.ts +0 -3
  99. package/dist/search/ranker-rescore.js +0 -27
  100. package/dist/search/ranker-trainer.d.ts +0 -8
  101. package/dist/search/ranker-trainer.js +0 -376
  102. package/dist/tier-validator.d.ts +0 -12
  103. package/dist/tier-validator.js +0 -56
  104. package/package.json +1 -10
  105. package/dist/cases/case-links.d.ts +0 -116
  106. package/dist/cases/case-links.js +0 -794
  107. package/dist/cases/composition-overrides.d.ts +0 -90
  108. package/dist/cases/composition-overrides.js +0 -724
  109. package/dist/cases/corrections.d.ts +0 -156
  110. package/dist/cases/corrections.js +0 -1045
  111. package/dist/cases/freshness.d.ts +0 -57
  112. package/dist/cases/freshness.js +0 -283
  113. package/dist/cases/live-state.d.ts +0 -48
  114. package/dist/cases/live-state.js +0 -256
  115. package/dist/cases/membership-explain.d.ts +0 -56
  116. package/dist/cases/membership-explain.js +0 -140
  117. package/dist/cases/membership-matcher.d.ts +0 -23
  118. package/dist/cases/membership-matcher.js +0 -193
  119. package/dist/cases/merge-split.d.ts +0 -61
  120. package/dist/cases/merge-split.js +0 -368
  121. package/dist/cases/role-inference.d.ts +0 -10
  122. package/dist/cases/role-inference.js +0 -85
  123. package/dist/cases/sqlite-transaction.d.ts +0 -10
  124. package/dist/cases/sqlite-transaction.js +0 -62
  125. package/dist/cases/target-ref.d.ts +0 -25
  126. package/dist/cases/target-ref.js +0 -22
  127. package/dist/cases/tombstone-sweeper.d.ts +0 -13
  128. package/dist/cases/tombstone-sweeper.js +0 -128
  129. package/dist/entities/entity-impact.d.ts +0 -41
  130. package/dist/entities/entity-impact.js +0 -140
  131. package/dist/entities/exact-merge-backfill.d.ts +0 -11
  132. package/dist/entities/exact-merge-backfill.js +0 -161
  133. package/dist/entities/lineage-backfill.d.ts +0 -12
  134. package/dist/entities/lineage-backfill.js +0 -101
  135. package/dist/memory-inject.d.ts +0 -24
  136. package/dist/memory-inject.js +0 -116
@@ -191,6 +191,9 @@ function attachEntityAliasWithEdge(adapter, input) {
191
191
  connectors: input.connectors,
192
192
  projectRefs: input.project_refs,
193
193
  tenantId: input.tenant_id,
194
+ // source_refs are caller-supplied, so this is the surface where naming a raw id from
195
+ // an ungranted channel would bind it to an entity the caller can read back.
196
+ ...(input.channels ? { channels: input.channels } : {}),
194
197
  };
195
198
  const sourceRefs = normalizeSourceRefs(input.source_refs);
196
199
  if (sourceRefs.length === 0) {
@@ -168,13 +168,8 @@ function contextBoost(adapter, entityId, contextRefs, visibility, asOfMs) {
168
168
  if (!contextRefs || contextRefs.length === 0) {
169
169
  return 0;
170
170
  }
171
- const edges = (0, ref_validation_js_1.listVisibleTwinEdgesForRefs)(adapter, contextRefs, {
172
- scopes: visibility.scopes,
173
- connectors: visibility.connectors,
174
- projectRefs: visibility.projectRefs,
175
- tenantId: visibility.tenantId,
176
- asOfMs,
177
- });
171
+ // Spread rather than re-list: see graph-query's listFilteredEdges.
172
+ const edges = (0, ref_validation_js_1.listVisibleTwinEdgesForRefs)(adapter, contextRefs, { ...visibility, asOfMs });
178
173
  return edges.some((edge) => (edge.subject_ref.kind === 'entity' && edge.subject_ref.id === entityId) ||
179
174
  (edge.object_ref.kind === 'entity' && edge.object_ref.id === entityId))
180
175
  ? 0.2
@@ -189,6 +184,7 @@ function resolveEntity(adapter, input) {
189
184
  projectRefs: input.project_refs,
190
185
  tenantId: input.tenant_id,
191
186
  asOfMs: input.as_of_ms,
187
+ ...(input.channels ? { channels: input.channels } : {}),
192
188
  };
193
189
  if (input.context_refs && input.context_refs.length > 0) {
194
190
  try {
@@ -80,11 +80,11 @@ function oppositeRef(edge, current) {
80
80
  return refs;
81
81
  }
82
82
  function listFilteredEdges(adapter, refs, input) {
83
+ // Spread, not a field-by-field re-listing. Re-listing is how the channel grant was
84
+ // silently dropped here while every other path enforced it: a new field on the
85
+ // visibility type simply never arrived, and nothing failed to say so.
83
86
  return (0, ref_validation_js_1.listVisibleTwinEdgesForRefs)(adapter, refs, {
84
- scopes: input.visibility.scopes,
85
- connectors: input.visibility.connectors,
86
- projectRefs: input.visibility.projectRefs,
87
- tenantId: input.visibility.tenantId,
87
+ ...input.visibility,
88
88
  edgeTypes: input.edge_filters?.edge_types,
89
89
  asOfMs: input.as_of_ms,
90
90
  limit: input.limit,
@@ -104,6 +104,7 @@ function graphVisibility(input) {
104
104
  connectors: input.connectors,
105
105
  projectRefs: input.project_refs,
106
106
  tenantId: input.tenant_id,
107
+ ...(input.channels ? { channels: input.channels } : {}),
107
108
  };
108
109
  }
109
110
  function numberMs(value, field, refId) {
@@ -10,6 +10,12 @@ export interface ResolveEntityInput {
10
10
  scopes?: TwinScopeRef[];
11
11
  connectors?: string[];
12
12
  project_refs?: TwinProjectRef[];
13
+ /**
14
+ * Which channels of each connector may be read. Carried on every graph input for the
15
+ * same reason it is carried on the reader's boundary: a raw ref reached through an edge
16
+ * must satisfy the same rule as a row the reader would have returned.
17
+ */
18
+ channels?: Record<string, readonly string[]>;
13
19
  tenant_id?: string | null;
14
20
  context_refs?: TwinRef[];
15
21
  limit?: number;
@@ -31,6 +37,12 @@ export interface GraphNeighborhoodInput {
31
37
  scopes?: TwinScopeRef[];
32
38
  connectors?: string[];
33
39
  project_refs?: TwinProjectRef[];
40
+ /**
41
+ * Which channels of each connector may be read. Carried on every graph input for the
42
+ * same reason it is carried on the reader's boundary: a raw ref reached through an edge
43
+ * must satisfy the same rule as a row the reader would have returned.
44
+ */
45
+ channels?: Record<string, readonly string[]>;
34
46
  tenant_id?: string | null;
35
47
  edge_filters?: AgentGraphEdgeFilters;
36
48
  as_of_ms?: number | null;
@@ -47,6 +59,12 @@ export interface GraphPathsInput {
47
59
  scopes?: TwinScopeRef[];
48
60
  connectors?: string[];
49
61
  project_refs?: TwinProjectRef[];
62
+ /**
63
+ * Which channels of each connector may be read. Carried on every graph input for the
64
+ * same reason it is carried on the reader's boundary: a raw ref reached through an edge
65
+ * must satisfy the same rule as a row the reader would have returned.
66
+ */
67
+ channels?: Record<string, readonly string[]>;
50
68
  tenant_id?: string | null;
51
69
  edge_filters?: AgentGraphEdgeFilters;
52
70
  as_of_ms?: number | null;
@@ -64,6 +82,12 @@ export interface GraphTimelineInput {
64
82
  scopes?: TwinScopeRef[];
65
83
  connectors?: string[];
66
84
  project_refs?: TwinProjectRef[];
85
+ /**
86
+ * Which channels of each connector may be read. Carried on every graph input for the
87
+ * same reason it is carried on the reader's boundary: a raw ref reached through an edge
88
+ * must satisfy the same rule as a row the reader would have returned.
89
+ */
90
+ channels?: Record<string, readonly string[]>;
67
91
  tenant_id?: string | null;
68
92
  edge_filters?: AgentGraphEdgeFilters;
69
93
  from_ms?: number;
@@ -153,6 +177,12 @@ export interface AttachEntityAliasWithEdgeInput {
153
177
  scopes?: TwinScopeRef[];
154
178
  connectors?: string[];
155
179
  project_refs?: TwinProjectRef[];
180
+ /**
181
+ * Which channels of each connector may be read. Carried on every graph input for the
182
+ * same reason it is carried on the reader's boundary: a raw ref reached through an edge
183
+ * must satisfy the same rule as a row the reader would have returned.
184
+ */
185
+ channels?: Record<string, readonly string[]>;
156
186
  tenant_id?: string | null;
157
187
  }
158
188
  export interface AttachEntityAliasWithEdgeResult {
@@ -63,10 +63,6 @@ export interface ListActiveCorrectionsForCaseResult {
63
63
  */
64
64
  export declare function listActiveCorrectionsForCase(adapter: CaseStoreAdapter, caseId: string): ListActiveCorrectionsForCaseResult;
65
65
  export declare function listActiveCorrectionsForCaseChain(adapter: CaseStoreAdapter, caseIds: string[]): CaseCorrectionRecord[];
66
- export declare function enqueueCaseProposal(adapter: CaseStoreAdapter, input: EnqueueCaseProposalInput): {
67
- proposal_id: string;
68
- inserted: boolean;
69
- };
70
66
  export declare function listUnresolvedCaseProposals(adapter: CaseStoreAdapter, project: string): CaseProposalQueueRecord[];
71
67
  export declare function assembleCase(caseId: string, options?: AssembleCaseOptions): CaseAssembly;
72
68
  export declare function assembleCase(adapter: CaseStoreAdapter, caseId: string, options?: AssembleCaseOptions): CaseAssembly;
@@ -7,11 +7,8 @@ exports.upsertExplicitCaseMemberships = upsertExplicitCaseMemberships;
7
7
  exports.listActiveMembershipsForCaseChain = listActiveMembershipsForCaseChain;
8
8
  exports.listActiveCorrectionsForCase = listActiveCorrectionsForCase;
9
9
  exports.listActiveCorrectionsForCaseChain = listActiveCorrectionsForCaseChain;
10
- exports.enqueueCaseProposal = enqueueCaseProposal;
11
10
  exports.listUnresolvedCaseProposals = listUnresolvedCaseProposals;
12
11
  exports.assembleCase = assembleCase;
13
- const node_crypto_1 = require("node:crypto");
14
- const canonicalize_js_1 = require("../canonicalize.js");
15
12
  const db_manager_js_1 = require("../db-manager.js");
16
13
  const errors_js_1 = require("../entities/errors.js");
17
14
  function isAdapter(value) {
@@ -447,69 +444,6 @@ function listActiveCorrectionsForCaseChain(adapter, caseIds) {
447
444
  .all(...caseIds);
448
445
  return rows.map(mapCaseCorrectionRow);
449
446
  }
450
- function isUniqueConstraintError(error) {
451
- if (!(error instanceof Error)) {
452
- return false;
453
- }
454
- return /UNIQUE constraint|SQLITE_CONSTRAINT_UNIQUE/i.test(error.message);
455
- }
456
- function findExistingProposalId(adapter, input, payloadFingerprint) {
457
- const row = adapter
458
- .prepare(`
459
- SELECT proposal_id
460
- FROM case_proposal_queue
461
- WHERE project = ?
462
- AND proposal_kind = ?
463
- AND COALESCE(conflicting_case_id, '') = ?
464
- AND payload_fingerprint = ?
465
- AND resolved_at IS NULL
466
- LIMIT 1
467
- `)
468
- .get(input.project, input.proposal_kind, input.conflicting_case_id ?? '', payloadFingerprint);
469
- return row?.proposal_id ?? null;
470
- }
471
- function enqueueCaseProposal(adapter, input) {
472
- const canonicalFingerprintInput = (0, canonicalize_js_1.canonicalizeJSON)(input.stable_fingerprint_input);
473
- const payloadFingerprint = (0, canonicalize_js_1.targetRefHashCanonicalJSON)(canonicalFingerprintInput);
474
- const proposalId = (0, node_crypto_1.randomUUID)();
475
- const detectedAt = nowIso();
476
- return adapter.transaction(() => {
477
- try {
478
- adapter
479
- .prepare(`
480
- INSERT INTO case_proposal_queue (
481
- proposal_id, project, proposal_kind, proposed_payload, payload_fingerprint,
482
- conflicting_case_id, detected_at, resolved_at, resolution, resolution_note
483
- )
484
- VALUES (?, ?, ?, ?, ?, ?, ?, NULL, NULL, NULL)
485
- `)
486
- .run(proposalId, input.project, input.proposal_kind, input.proposed_payload, payloadFingerprint, input.conflicting_case_id ?? null, detectedAt);
487
- return { proposal_id: proposalId, inserted: true };
488
- }
489
- catch (error) {
490
- if (!isUniqueConstraintError(error)) {
491
- throw error;
492
- }
493
- const existingId = findExistingProposalId(adapter, input, payloadFingerprint);
494
- if (!existingId) {
495
- throw error;
496
- }
497
- // Spec §5.7 L355: re-detection updates detected_at without duplicating.
498
- // Keeps listUnresolvedCaseProposals ordering (ASC detected_at) honest —
499
- // recently re-detected rows move to the tail instead of sitting at
500
- // stale timestamps.
501
- adapter
502
- .prepare(`
503
- UPDATE case_proposal_queue
504
- SET detected_at = ?
505
- WHERE proposal_id = ?
506
- AND resolved_at IS NULL
507
- `)
508
- .run(detectedAt, existingId);
509
- return { proposal_id: existingId, inserted: false };
510
- }
511
- });
512
- }
513
447
  function listUnresolvedCaseProposals(adapter, project) {
514
448
  const rows = adapter
515
449
  .prepare(`
@@ -32,19 +32,6 @@ export interface UpsertWikiPageIndexInput {
32
32
  embedding?: Float32Array | null;
33
33
  embedding_model?: string;
34
34
  }
35
- export declare function upsertWikiPageIndexEntry(adapter: AdapterLike, input: UpsertWikiPageIndexInput): {
36
- id: number;
37
- created: boolean;
38
- };
39
- export declare function deleteWikiPageIndexEntry(adapter: AdapterLike, source_locator: string): {
40
- deleted: boolean;
41
- };
42
35
  export declare function ftsSearchWikiPages(adapter: AdapterLike, query: string, limit: number): WikiPageSearchHit[];
43
36
  export declare function vectorSearchWikiPages(adapter: AdapterLike, queryEmbedding: Float32Array, limit: number): WikiPageSearchHit[];
44
- export declare function searchWikiPages(input: {
45
- adapter: AdapterLike;
46
- query: string;
47
- queryEmbedding?: Float32Array | null;
48
- limit: number;
49
- }): WikiPageSearchHit[];
50
37
  //# sourceMappingURL=wiki-page-index.d.ts.map
@@ -1,14 +1,7 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.upsertWikiPageIndexEntry = upsertWikiPageIndexEntry;
7
- exports.deleteWikiPageIndexEntry = deleteWikiPageIndexEntry;
8
3
  exports.ftsSearchWikiPages = ftsSearchWikiPages;
9
4
  exports.vectorSearchWikiPages = vectorSearchWikiPages;
10
- exports.searchWikiPages = searchWikiPages;
11
- const node_crypto_1 = __importDefault(require("node:crypto"));
12
5
  const embeddings_js_1 = require("../embeddings.js");
13
6
  function tableColumns(adapter, tableName) {
14
7
  const rows = adapter.prepare(`PRAGMA table_info(${tableName})`).all();
@@ -34,19 +27,12 @@ function readSchema(adapter) {
34
27
  embeddingHasCreatedAt: embeddingColumns.has('created_at'),
35
28
  };
36
29
  }
37
- function nowIso() {
38
- return new Date().toISOString();
39
- }
40
30
  function normalizeLimit(limit) {
41
31
  if (!Number.isFinite(limit)) {
42
32
  return 10;
43
33
  }
44
34
  return Math.max(0, Math.floor(limit));
45
35
  }
46
- function pageIdForSourceLocator(sourceLocator) {
47
- const digest = node_crypto_1.default.createHash('sha256').update(sourceLocator).digest('hex').slice(0, 24);
48
- return `wiki_page_${digest}`;
49
- }
50
36
  function parseJsonArray(value) {
51
37
  if (value === null || value === undefined || value === '') {
52
38
  return [];
@@ -89,13 +75,6 @@ function rowToRecord(row) {
89
75
  updated_at: String(row.updated_at ?? row.created_at ?? row.compiled_at ?? ''),
90
76
  };
91
77
  }
92
- function selectByLocator(adapter, schema, sourceLocator) {
93
- const sql = schema.hasIdColumn
94
- ? 'SELECT * FROM wiki_page_index WHERE source_locator = ?'
95
- : 'SELECT rowid AS id, * FROM wiki_page_index WHERE source_locator = ?';
96
- const row = adapter.prepare(sql).get(sourceLocator);
97
- return row ? rowToRecord(row) : null;
98
- }
99
78
  function selectByFtsPageId(adapter, schema, pageId) {
100
79
  const sql = schema.hasIdColumn
101
80
  ? 'SELECT * FROM wiki_page_index WHERE id = ?'
@@ -104,9 +83,6 @@ function selectByFtsPageId(adapter, schema, pageId) {
104
83
  const row = adapter.prepare(sql).get(lookup);
105
84
  return row ? rowToRecord(row) : null;
106
85
  }
107
- function vectorToBuffer(embedding) {
108
- return Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
109
- }
110
86
  function blobToVector(value) {
111
87
  if (!(value instanceof Uint8Array)) {
112
88
  return null;
@@ -118,35 +94,6 @@ function blobToVector(value) {
118
94
  const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
119
95
  return new Float32Array(arrayBuffer);
120
96
  }
121
- function upsertEmbedding(adapter, schema, record, input) {
122
- if (!input.embedding) {
123
- return;
124
- }
125
- const vector = vectorToBuffer(input.embedding);
126
- const model = input.embedding_model ?? embeddings_js_1.MODEL_NAME;
127
- const dim = input.embedding.length;
128
- if (schema.embeddingUsesWikiPageId && schema.embeddingUsesVector) {
129
- adapter
130
- .prepare(`
131
- INSERT INTO wiki_page_embeddings(wiki_page_id, vector, model, dim, created_at)
132
- VALUES (?, ?, ?, ?, ?)
133
- ON CONFLICT(wiki_page_id) DO UPDATE SET
134
- vector = excluded.vector,
135
- model = excluded.model,
136
- dim = excluded.dim
137
- `)
138
- .run(record.id, vector, model, dim, nowIso());
139
- return;
140
- }
141
- adapter
142
- .prepare(`
143
- INSERT INTO wiki_page_embeddings(page_id, embedding)
144
- VALUES (?, ?)
145
- ON CONFLICT(page_id) DO UPDATE SET
146
- embedding = excluded.embedding
147
- `)
148
- .run(pageIdForSourceLocator(record.source_locator), vector);
149
- }
150
97
  function buildFtsQuery(query) {
151
98
  const tokens = query
152
99
  .toLowerCase()
@@ -173,89 +120,6 @@ function searchTableExists(adapter, tableName) {
173
120
  .get(tableName);
174
121
  return row !== undefined;
175
122
  }
176
- function upsertWikiPageIndexEntry(adapter, input) {
177
- const schema = readSchema(adapter);
178
- const existing = selectByLocator(adapter, schema, input.source_locator);
179
- const updatedAt = nowIso();
180
- return adapter.transaction(() => {
181
- if (schema.hasIdColumn) {
182
- adapter
183
- .prepare(`
184
- INSERT INTO wiki_page_index (
185
- source_locator, page_type, title, content, case_id, source_ids,
186
- confidence, entity_refs, compiled_at, created_at, updated_at
187
- )
188
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
189
- ON CONFLICT(source_locator) DO UPDATE SET
190
- page_type = excluded.page_type,
191
- title = excluded.title,
192
- content = excluded.content,
193
- case_id = excluded.case_id,
194
- source_ids = excluded.source_ids,
195
- confidence = excluded.confidence,
196
- entity_refs = excluded.entity_refs,
197
- compiled_at = excluded.compiled_at,
198
- updated_at = excluded.updated_at
199
- `)
200
- .run(input.source_locator, input.page_type, input.title, input.content, input.case_id ?? null, JSON.stringify(input.source_ids), input.confidence, JSON.stringify(input.entity_refs), input.compiled_at, updatedAt, updatedAt);
201
- }
202
- else if (schema.hasSourceIdsColumn && schema.hasEntityRefsColumn) {
203
- adapter
204
- .prepare(`
205
- INSERT INTO wiki_page_index (
206
- page_id, source_type, source_locator, case_id, title, page_type,
207
- content, confidence, source_ids, entity_refs, compiled_at, updated_at
208
- )
209
- VALUES (?, 'wiki_page', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
210
- ON CONFLICT(source_type, source_locator) DO UPDATE SET
211
- case_id = excluded.case_id,
212
- title = excluded.title,
213
- page_type = excluded.page_type,
214
- content = excluded.content,
215
- confidence = excluded.confidence,
216
- source_ids = excluded.source_ids,
217
- entity_refs = excluded.entity_refs,
218
- compiled_at = excluded.compiled_at,
219
- updated_at = excluded.updated_at
220
- `)
221
- .run(pageIdForSourceLocator(input.source_locator), input.source_locator, input.case_id ?? null, input.title, input.page_type, input.content, input.confidence, JSON.stringify(input.source_ids), JSON.stringify(input.entity_refs), input.compiled_at, updatedAt);
222
- }
223
- else {
224
- adapter
225
- .prepare(`
226
- INSERT INTO wiki_page_index (
227
- page_id, source_type, source_locator, case_id, title, page_type,
228
- content, confidence, compiled_at, updated_at
229
- )
230
- VALUES (?, 'wiki_page', ?, ?, ?, ?, ?, ?, ?, ?)
231
- ON CONFLICT(source_type, source_locator) DO UPDATE SET
232
- case_id = excluded.case_id,
233
- title = excluded.title,
234
- page_type = excluded.page_type,
235
- content = excluded.content,
236
- confidence = excluded.confidence,
237
- compiled_at = excluded.compiled_at,
238
- updated_at = excluded.updated_at
239
- `)
240
- .run(pageIdForSourceLocator(input.source_locator), input.source_locator, input.case_id ?? null, input.title, input.page_type, input.content, input.confidence, input.compiled_at, updatedAt);
241
- }
242
- const saved = selectByLocator(adapter, schema, input.source_locator);
243
- if (!saved) {
244
- throw new Error(`Failed to load wiki_page_index row for ${input.source_locator}.`);
245
- }
246
- upsertEmbedding(adapter, schema, saved, input);
247
- return {
248
- id: saved.id,
249
- created: existing === null,
250
- };
251
- });
252
- }
253
- function deleteWikiPageIndexEntry(adapter, source_locator) {
254
- const result = adapter
255
- .prepare('DELETE FROM wiki_page_index WHERE source_locator = ?')
256
- .run(source_locator);
257
- return { deleted: result.changes > 0 };
258
- }
259
123
  function ftsSearchWikiPages(adapter, query, limit) {
260
124
  const boundedLimit = normalizeLimit(limit);
261
125
  if (boundedLimit === 0 || !query.trim()) {
@@ -334,21 +198,4 @@ function vectorSearchWikiPages(adapter, queryEmbedding, limit) {
334
198
  raw_score: entry.score,
335
199
  }));
336
200
  }
337
- function searchWikiPages(input) {
338
- const ftsHits = ftsSearchWikiPages(input.adapter, input.query, input.limit);
339
- const vectorHits = input.queryEmbedding
340
- ? vectorSearchWikiPages(input.adapter, input.queryEmbedding, input.limit)
341
- : [];
342
- const merged = new Map();
343
- for (const hit of [...ftsHits, ...vectorHits]) {
344
- const existing = merged.get(hit.record.id);
345
- if (!existing || hit.raw_score > existing.raw_score) {
346
- merged.set(hit.record.id, hit);
347
- }
348
- }
349
- return Array.from(merged.values())
350
- .sort((left, right) => right.raw_score - left.raw_score)
351
- .slice(0, normalizeLimit(input.limit))
352
- .map((hit, rank) => ({ ...hit, rank }));
353
- }
354
201
  //# sourceMappingURL=wiki-page-index.js.map
@@ -1,28 +1,11 @@
1
1
  import type { DatabaseAdapter } from '../db-manager.js';
2
- import type { ConnectorEventIndexCursorRecord, ConnectorEventIndexRecord, ConnectorEventSearchHit, ConnectorEventStalenessStatus, UpsertConnectorEventIndexCursorInput, UpsertConnectorEventIndexInput } from './types.js';
2
+ import type { ConnectorEventIndexCursorRecord, ConnectorEventIndexRecord, UpsertConnectorEventIndexInput } from './types.js';
3
3
  type ConnectorEventIndexAdapter = Pick<DatabaseAdapter, 'prepare' | 'transaction'>;
4
- interface ListConnectorEventsByDatetimeRangeInput {
5
- fromMs: number;
6
- toMs: number;
7
- limit?: number;
8
- connectors?: string[];
9
- order?: 'asc' | 'desc';
10
- }
11
- interface SearchConnectorEventsOptions {
12
- limit?: number;
13
- connectors?: string[];
14
- }
15
4
  interface DeleteExpiredConnectorEventsInput {
16
5
  nowMs: number;
17
6
  retentionMs: number;
18
7
  connectorName?: string;
19
8
  }
20
- interface StalenessOptions {
21
- nowMs: number;
22
- staleAfterMs?: number;
23
- stalenessWarnAfterMs?: number;
24
- unhealthyAfterMs?: number;
25
- }
26
9
  export declare function mapConnectorEventIndexRecord(row: Record<string, unknown>): ConnectorEventIndexRecord;
27
10
  export declare function connectorEventIndexId(sourceConnector: string, sourceId: string): string;
28
11
  export declare function connectorEventContentHash(input: {
@@ -33,13 +16,9 @@ export declare function connectorEventContentHash(input: {
33
16
  }): Buffer;
34
17
  export declare function upsertConnectorEventIndex(adapter: ConnectorEventIndexAdapter, input: UpsertConnectorEventIndexInput): ConnectorEventIndexRecord;
35
18
  export declare function getConnectorEventIndexRecord(adapter: ConnectorEventIndexAdapter, sourceConnector: string, sourceId: string): ConnectorEventIndexRecord | null;
36
- export declare function listConnectorEventsByDatetimeRange(adapter: ConnectorEventIndexAdapter, input: ListConnectorEventsByDatetimeRangeInput): ConnectorEventIndexRecord[];
37
- export declare function searchConnectorEventsByFTS(adapter: ConnectorEventIndexAdapter, query: string, options?: SearchConnectorEventsOptions): ConnectorEventSearchHit[];
38
19
  export declare function readConnectorCursor(adapter: ConnectorEventIndexAdapter, connectorName: string): ConnectorEventIndexCursorRecord | null;
39
- export declare function upsertConnectorCursor(adapter: ConnectorEventIndexAdapter, input: UpsertConnectorEventIndexCursorInput): ConnectorEventIndexCursorRecord;
40
20
  export declare function deleteExpiredConnectorEvents(adapter: ConnectorEventIndexAdapter, input: DeleteExpiredConnectorEventsInput): {
41
21
  rows_deleted: number;
42
22
  };
43
- export declare function computeStalenessStatus(cursor: ConnectorEventIndexCursorRecord | null, options: StalenessOptions): ConnectorEventStalenessStatus;
44
23
  export type { ConnectorEventIndexCursorRecord, ConnectorEventIndexRecord, ConnectorEventSearchHit, ConnectorEventStalenessStatus, UpsertConnectorEventIndexCursorInput, UpsertConnectorEventIndexInput, } from './types.js';
45
24
  //# sourceMappingURL=event-index.d.ts.map
@@ -5,32 +5,10 @@ exports.connectorEventIndexId = connectorEventIndexId;
5
5
  exports.connectorEventContentHash = connectorEventContentHash;
6
6
  exports.upsertConnectorEventIndex = upsertConnectorEventIndex;
7
7
  exports.getConnectorEventIndexRecord = getConnectorEventIndexRecord;
8
- exports.listConnectorEventsByDatetimeRange = listConnectorEventsByDatetimeRange;
9
- exports.searchConnectorEventsByFTS = searchConnectorEventsByFTS;
10
8
  exports.readConnectorCursor = readConnectorCursor;
11
- exports.upsertConnectorCursor = upsertConnectorCursor;
12
9
  exports.deleteExpiredConnectorEvents = deleteExpiredConnectorEvents;
13
- exports.computeStalenessStatus = computeStalenessStatus;
14
10
  const node_crypto_1 = require("node:crypto");
15
11
  const canonicalize_js_1 = require("../canonicalize.js");
16
- const DEFAULT_RANGE_LIMIT = 100;
17
- const DEFAULT_SEARCH_LIMIT = 25;
18
- const MAX_RANGE_LIMIT = 500;
19
- const FIVE_MINUTES_MS = 5 * 60 * 1000;
20
- const FIFTEEN_MINUTES_MS = 15 * 60 * 1000;
21
- const SIXTY_MINUTES_MS = 60 * 60 * 1000;
22
- function placeholders(values) {
23
- if (values.length === 0) {
24
- throw new Error('Cannot build SQL placeholders for an empty list.');
25
- }
26
- return values.map(() => '?').join(', ');
27
- }
28
- function positiveLimit(value, fallback, max = MAX_RANGE_LIMIT) {
29
- if (value === undefined) {
30
- return fallback;
31
- }
32
- return Math.min(max, Math.max(0, Math.floor(value)));
33
- }
34
12
  function nowIso() {
35
13
  return new Date().toISOString();
36
14
  }
@@ -119,16 +97,6 @@ function mapConnectorCursorRow(row) {
119
97
  indexed_count: Number(row.indexed_count),
120
98
  };
121
99
  }
122
- function connectorFilterSql(connectors, alias = '') {
123
- if (!connectors || connectors.length === 0) {
124
- return '';
125
- }
126
- const prefix = alias.length > 0 ? `${alias}.` : '';
127
- return ` AND ${prefix}source_connector IN (${placeholders(connectors)})`;
128
- }
129
- function hasOwn(input, key) {
130
- return Object.prototype.hasOwnProperty.call(input, key);
131
- }
132
100
  function connectorEventIndexId(sourceConnector, sourceId) {
133
101
  const digest = (0, node_crypto_1.createHash)('sha1').update(`${sourceConnector}\0${sourceId}`, 'utf8').digest('hex');
134
102
  return `evt_${digest.slice(0, 16)}`;
@@ -214,59 +182,6 @@ function getConnectorEventIndexRecord(adapter, sourceConnector, sourceId) {
214
182
  .get(sourceConnector, sourceId);
215
183
  return row ? mapConnectorEventIndexRow(row) : null;
216
184
  }
217
- function listConnectorEventsByDatetimeRange(adapter, input) {
218
- const limit = positiveLimit(input.limit, DEFAULT_RANGE_LIMIT);
219
- if (limit === 0) {
220
- return [];
221
- }
222
- const order = input.order === 'desc' ? 'DESC' : 'ASC';
223
- const connectors = input.connectors?.filter(Boolean) ?? [];
224
- const params = [input.fromMs, input.toMs, ...connectors, limit];
225
- const rows = adapter
226
- .prepare(`
227
- SELECT *
228
- FROM connector_event_index
229
- WHERE event_datetime >= ?
230
- AND event_datetime <= ?
231
- ${connectorFilterSql(connectors)}
232
- ORDER BY event_datetime ${order}, event_index_id ASC
233
- LIMIT ?
234
- `)
235
- .all(...params);
236
- return rows.map(mapConnectorEventIndexRow);
237
- }
238
- function searchConnectorEventsByFTS(adapter, query, options = {}) {
239
- const normalizedQuery = query.trim();
240
- if (normalizedQuery.length === 0) {
241
- return [];
242
- }
243
- const limit = positiveLimit(options.limit, DEFAULT_SEARCH_LIMIT, 100);
244
- if (limit === 0) {
245
- return [];
246
- }
247
- const connectors = options.connectors?.filter(Boolean) ?? [];
248
- const params = [normalizedQuery, ...connectors, limit];
249
- const rows = adapter
250
- .prepare(`
251
- SELECT e.*, bm25(connector_event_index_fts) AS rank
252
- FROM connector_event_index_fts
253
- JOIN connector_event_index e
254
- ON e.event_index_id = connector_event_index_fts.event_index_id
255
- WHERE connector_event_index_fts MATCH ?
256
- ${connectorFilterSql(connectors, 'e')}
257
- ORDER BY rank ASC, e.event_datetime DESC, e.event_index_id ASC
258
- LIMIT ?
259
- `)
260
- .all(...params);
261
- return rows.map((row) => {
262
- const rank = Number(row.rank);
263
- return {
264
- ...mapConnectorEventIndexRow(row),
265
- rank,
266
- score: Number.isFinite(rank) ? 1 / (1 + Math.exp(rank)) : 0,
267
- };
268
- });
269
- }
270
185
  function readConnectorCursor(adapter, connectorName) {
271
186
  const row = adapter
272
187
  .prepare(`
@@ -278,49 +193,6 @@ function readConnectorCursor(adapter, connectorName) {
278
193
  .get(connectorName);
279
194
  return row ? mapConnectorCursorRow(row) : null;
280
195
  }
281
- function upsertConnectorCursor(adapter, input) {
282
- const current = readConnectorCursor(adapter, input.connector_name);
283
- const merged = {
284
- connector_name: input.connector_name,
285
- last_seen_timestamp_ms: input.last_seen_timestamp_ms ?? current?.last_seen_timestamp_ms ?? 0,
286
- last_seen_source_id: input.last_seen_source_id ?? current?.last_seen_source_id ?? '',
287
- last_sweep_at: hasOwn(input, 'last_sweep_at')
288
- ? (input.last_sweep_at ?? null)
289
- : (current?.last_sweep_at ?? null),
290
- last_success_at: hasOwn(input, 'last_success_at')
291
- ? (input.last_success_at ?? null)
292
- : (current?.last_success_at ?? null),
293
- last_error: hasOwn(input, 'last_error')
294
- ? (input.last_error ?? null)
295
- : (current?.last_error ?? null),
296
- last_error_at: hasOwn(input, 'last_error_at')
297
- ? (input.last_error_at ?? null)
298
- : (current?.last_error_at ?? null),
299
- indexed_count: input.indexed_count ?? current?.indexed_count ?? 0,
300
- };
301
- adapter
302
- .prepare(`
303
- INSERT INTO connector_event_index_cursors (
304
- connector_name, last_seen_timestamp_ms, last_seen_source_id, last_sweep_at,
305
- last_success_at, last_error, last_error_at, indexed_count
306
- )
307
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
308
- ON CONFLICT(connector_name) DO UPDATE SET
309
- last_seen_timestamp_ms = excluded.last_seen_timestamp_ms,
310
- last_seen_source_id = excluded.last_seen_source_id,
311
- last_sweep_at = excluded.last_sweep_at,
312
- last_success_at = excluded.last_success_at,
313
- last_error = excluded.last_error,
314
- last_error_at = excluded.last_error_at,
315
- indexed_count = excluded.indexed_count
316
- `)
317
- .run(merged.connector_name, merged.last_seen_timestamp_ms, merged.last_seen_source_id, merged.last_sweep_at, merged.last_success_at, merged.last_error, merged.last_error_at, merged.indexed_count);
318
- const saved = readConnectorCursor(adapter, input.connector_name);
319
- if (!saved) {
320
- throw new Error(`Failed to read connector cursor after upsert: ${input.connector_name}`);
321
- }
322
- return saved;
323
- }
324
196
  function deleteExpiredConnectorEvents(adapter, input) {
325
197
  if (!Number.isFinite(input.nowMs)) {
326
198
  throw new Error('deleteExpiredConnectorEvents.nowMs must be a finite number.');
@@ -349,33 +221,4 @@ function deleteExpiredConnectorEvents(adapter, input) {
349
221
  .run(cutoffMs);
350
222
  return { rows_deleted: result.changes };
351
223
  }
352
- function computeStalenessStatus(cursor, options) {
353
- if (!cursor) {
354
- return 'never_swept';
355
- }
356
- if (cursor.last_error !== null) {
357
- return 'unhealthy';
358
- }
359
- if (cursor.last_success_at === null) {
360
- return 'never_swept';
361
- }
362
- const lastSuccessMs = Date.parse(cursor.last_success_at);
363
- if (!Number.isFinite(lastSuccessMs)) {
364
- return 'unhealthy';
365
- }
366
- const elapsedMs = options.nowMs - lastSuccessMs;
367
- const staleAfterMs = options.staleAfterMs ?? FIVE_MINUTES_MS;
368
- const warnAfterMs = options.stalenessWarnAfterMs ?? FIFTEEN_MINUTES_MS;
369
- const unhealthyAfterMs = options.unhealthyAfterMs ?? SIXTY_MINUTES_MS;
370
- if (elapsedMs > unhealthyAfterMs) {
371
- return 'unhealthy';
372
- }
373
- if (elapsedMs > warnAfterMs) {
374
- return 'warn';
375
- }
376
- if (elapsedMs > staleAfterMs) {
377
- return 'stale-but-warming';
378
- }
379
- return 'healthy';
380
- }
381
224
  //# sourceMappingURL=event-index.js.map