@jungjaehoon/mama-core 1.4.2 → 1.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 (181) hide show
  1. package/README.md +48 -10
  2. package/db/migrations/026-create-canonical-entity-tables.sql +99 -0
  3. package/db/migrations/027-create-entity-review-support.sql +44 -0
  4. package/db/migrations/028-create-entity-audit-tables.sql +45 -0
  5. package/db/migrations/029-extend-entity-observations-observation-type.sql +60 -0
  6. package/db/migrations/030-case-first-memory-substrate.sql +901 -0
  7. package/db/migrations/031-wiki-page-index-provenance-columns.sql +2 -0
  8. package/db/migrations/032-add-memory-provenance-columns.sql +21 -0
  9. package/db/migrations/033-create-model-runs-and-tool-traces.sql +53 -0
  10. package/db/migrations/034-add-connector-event-scope-columns.sql +14 -0
  11. package/db/migrations/035-create-twin-edges.sql +63 -0
  12. package/db/migrations/036-create-agent-situation-packets.sql +61 -0
  13. package/dist/agent-graph/alias-write.d.ts +3 -0
  14. package/dist/agent-graph/alias-write.js +231 -0
  15. package/dist/agent-graph/entity-resolve.d.ts +3 -0
  16. package/dist/agent-graph/entity-resolve.js +275 -0
  17. package/dist/agent-graph/errors.d.ts +4 -0
  18. package/dist/agent-graph/errors.js +11 -0
  19. package/dist/agent-graph/graph-query.d.ts +5 -0
  20. package/dist/agent-graph/graph-query.js +359 -0
  21. package/dist/agent-graph/index.d.ts +6 -0
  22. package/dist/agent-graph/index.js +22 -0
  23. package/dist/agent-graph/types.d.ts +162 -0
  24. package/dist/agent-graph/types.js +3 -0
  25. package/dist/agent-situation/builder.d.ts +8 -0
  26. package/dist/agent-situation/builder.js +239 -0
  27. package/dist/agent-situation/cache-key.d.ts +4 -0
  28. package/dist/agent-situation/cache-key.js +64 -0
  29. package/dist/agent-situation/index.d.ts +7 -0
  30. package/dist/agent-situation/index.js +28 -0
  31. package/dist/agent-situation/packet-store.d.ts +27 -0
  32. package/dist/agent-situation/packet-store.js +228 -0
  33. package/dist/agent-situation/ranking-policy.d.ts +18 -0
  34. package/dist/agent-situation/ranking-policy.js +75 -0
  35. package/dist/agent-situation/source-readers.d.ts +52 -0
  36. package/dist/agent-situation/source-readers.js +300 -0
  37. package/dist/agent-situation/types.d.ts +195 -0
  38. package/dist/agent-situation/types.js +3 -0
  39. package/dist/canonicalize.d.ts +38 -0
  40. package/dist/canonicalize.js +106 -0
  41. package/dist/cases/case-links.d.ts +116 -0
  42. package/dist/cases/case-links.js +794 -0
  43. package/dist/cases/composition-overrides.d.ts +90 -0
  44. package/dist/cases/composition-overrides.js +724 -0
  45. package/dist/cases/corrections.d.ts +156 -0
  46. package/dist/cases/corrections.js +1045 -0
  47. package/dist/cases/freshness.d.ts +57 -0
  48. package/dist/cases/freshness.js +283 -0
  49. package/dist/cases/live-state.d.ts +48 -0
  50. package/dist/cases/live-state.js +256 -0
  51. package/dist/cases/membership-explain.d.ts +56 -0
  52. package/dist/cases/membership-explain.js +140 -0
  53. package/dist/cases/membership-matcher.d.ts +23 -0
  54. package/dist/cases/membership-matcher.js +193 -0
  55. package/dist/cases/merge-split.d.ts +61 -0
  56. package/dist/cases/merge-split.js +368 -0
  57. package/dist/cases/role-inference.d.ts +10 -0
  58. package/dist/cases/role-inference.js +85 -0
  59. package/dist/cases/search-rollup.d.ts +27 -0
  60. package/dist/cases/search-rollup.js +309 -0
  61. package/dist/cases/sqlite-transaction.d.ts +10 -0
  62. package/dist/cases/sqlite-transaction.js +62 -0
  63. package/dist/cases/store.d.ts +74 -0
  64. package/dist/cases/store.js +816 -0
  65. package/dist/cases/target-ref.d.ts +25 -0
  66. package/dist/cases/target-ref.js +22 -0
  67. package/dist/cases/timeline-range.d.ts +6 -0
  68. package/dist/cases/timeline-range.js +322 -0
  69. package/dist/cases/tombstone-sweeper.d.ts +13 -0
  70. package/dist/cases/tombstone-sweeper.js +128 -0
  71. package/dist/cases/types.d.ts +244 -0
  72. package/dist/cases/types.js +47 -0
  73. package/dist/cases/wiki-page-index.d.ts +50 -0
  74. package/dist/cases/wiki-page-index.js +350 -0
  75. package/dist/connectors/event-index.d.ts +45 -0
  76. package/dist/connectors/event-index.js +381 -0
  77. package/dist/connectors/raw-query.d.ts +18 -0
  78. package/dist/connectors/raw-query.js +305 -0
  79. package/dist/connectors/types.d.ts +109 -0
  80. package/dist/connectors/types.js +3 -0
  81. package/dist/db-adapter/node-sqlite-adapter.d.ts +6 -0
  82. package/dist/db-adapter/node-sqlite-adapter.js +131 -0
  83. package/dist/db-manager.d.ts +12 -1
  84. package/dist/db-manager.js +60 -5
  85. package/dist/decision-formatter.d.ts +2 -0
  86. package/dist/decision-formatter.js +11 -8
  87. package/dist/edges/ref-validation.d.ts +8 -0
  88. package/dist/edges/ref-validation.js +262 -0
  89. package/dist/edges/store.d.ts +10 -0
  90. package/dist/edges/store.js +343 -0
  91. package/dist/edges/types.d.ts +86 -0
  92. package/dist/edges/types.js +18 -0
  93. package/dist/embedding-server/mobile/daemon.d.ts +1 -0
  94. package/dist/embedding-server/mobile/daemon.js +11 -1
  95. package/dist/embeddings.js +13 -0
  96. package/dist/entities/audit-metrics.d.ts +73 -0
  97. package/dist/entities/audit-metrics.js +128 -0
  98. package/dist/entities/candidate-generator.d.ts +9 -0
  99. package/dist/entities/candidate-generator.js +436 -0
  100. package/dist/entities/entity-impact.d.ts +41 -0
  101. package/dist/entities/entity-impact.js +140 -0
  102. package/dist/entities/entity-linked-decision-counts.d.ts +2 -0
  103. package/dist/entities/entity-linked-decision-counts.js +29 -0
  104. package/dist/entities/entity-list.d.ts +23 -0
  105. package/dist/entities/entity-list.js +99 -0
  106. package/dist/entities/entity-orphan-list.d.ts +26 -0
  107. package/dist/entities/entity-orphan-list.js +91 -0
  108. package/dist/entities/entity-search.d.ts +21 -0
  109. package/dist/entities/entity-search.js +150 -0
  110. package/dist/entities/errors.d.ts +65 -0
  111. package/dist/entities/errors.js +124 -0
  112. package/dist/entities/exact-merge-backfill.d.ts +11 -0
  113. package/dist/entities/exact-merge-backfill.js +161 -0
  114. package/dist/entities/lineage-backfill.d.ts +12 -0
  115. package/dist/entities/lineage-backfill.js +101 -0
  116. package/dist/entities/lineage-store.d.ts +51 -0
  117. package/dist/entities/lineage-store.js +308 -0
  118. package/dist/entities/normalization.d.ts +14 -0
  119. package/dist/entities/normalization.js +63 -0
  120. package/dist/entities/policy-store.d.ts +17 -0
  121. package/dist/entities/policy-store.js +263 -0
  122. package/dist/entities/policy-types.d.ts +72 -0
  123. package/dist/entities/policy-types.js +59 -0
  124. package/dist/entities/projection.d.ts +8 -0
  125. package/dist/entities/projection.js +82 -0
  126. package/dist/entities/provenance-query.d.ts +33 -0
  127. package/dist/entities/provenance-query.js +167 -0
  128. package/dist/entities/read-identity.d.ts +31 -0
  129. package/dist/entities/read-identity.js +264 -0
  130. package/dist/entities/recall-bridge.d.ts +5 -0
  131. package/dist/entities/recall-bridge.js +171 -0
  132. package/dist/entities/resolution-engine.d.ts +15 -0
  133. package/dist/entities/resolution-engine.js +69 -0
  134. package/dist/entities/rollback-preview.d.ts +39 -0
  135. package/dist/entities/rollback-preview.js +235 -0
  136. package/dist/entities/source-locator.d.ts +3 -0
  137. package/dist/entities/source-locator.js +32 -0
  138. package/dist/entities/store.d.ts +75 -0
  139. package/dist/entities/store.js +465 -0
  140. package/dist/entities/types.d.ts +162 -0
  141. package/dist/entities/types.js +30 -0
  142. package/dist/index.d.ts +62 -3
  143. package/dist/index.js +116 -26
  144. package/dist/mama-api.d.ts +53 -35
  145. package/dist/mama-api.js +437 -78
  146. package/dist/memory/api.d.ts +26 -38
  147. package/dist/memory/api.js +772 -68
  148. package/dist/memory/event-store.d.ts +3 -0
  149. package/dist/memory/event-store.js +21 -2
  150. package/dist/memory/provenance-audit.d.ts +22 -0
  151. package/dist/memory/provenance-audit.js +112 -0
  152. package/dist/memory/provenance-query.d.ts +11 -0
  153. package/dist/memory/provenance-query.js +193 -0
  154. package/dist/memory/provenance.d.ts +29 -0
  155. package/dist/memory/provenance.js +136 -0
  156. package/dist/memory/scope-backfill.d.ts +17 -0
  157. package/dist/memory/scope-backfill.js +77 -0
  158. package/dist/memory/types.d.ts +97 -16
  159. package/dist/model-runs/store.d.ts +13 -0
  160. package/dist/model-runs/store.js +457 -0
  161. package/dist/model-runs/tool-trace-store.d.ts +4 -0
  162. package/dist/model-runs/tool-trace-store.js +114 -0
  163. package/dist/model-runs/types.d.ts +69 -0
  164. package/dist/model-runs/types.js +5 -0
  165. package/dist/runtime/trusted-provenance.d.ts +3 -0
  166. package/dist/runtime/trusted-provenance.js +6 -0
  167. package/dist/search/feedback-store.d.ts +59 -0
  168. package/dist/search/feedback-store.js +211 -0
  169. package/dist/search/question-type.d.ts +5 -0
  170. package/dist/search/question-type.js +41 -0
  171. package/dist/search/ranker-features.d.ts +23 -0
  172. package/dist/search/ranker-features.js +104 -0
  173. package/dist/search/ranker-rescore.d.ts +31 -0
  174. package/dist/search/ranker-rescore.js +226 -0
  175. package/dist/search/ranker-trainer.d.ts +94 -0
  176. package/dist/search/ranker-trainer.js +860 -0
  177. package/dist/search/search-quality.d.ts +36 -0
  178. package/dist/search/search-quality.js +29 -0
  179. package/dist/test-utils.d.ts +14 -0
  180. package/dist/test-utils.js +52 -0
  181. package/package.json +28 -3
@@ -0,0 +1,45 @@
1
+ import type { DatabaseAdapter } from '../db-manager.js';
2
+ import type { ConnectorEventIndexCursorRecord, ConnectorEventIndexRecord, ConnectorEventSearchHit, ConnectorEventStalenessStatus, UpsertConnectorEventIndexCursorInput, UpsertConnectorEventIndexInput } from './types.js';
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
+ interface DeleteExpiredConnectorEventsInput {
16
+ nowMs: number;
17
+ retentionMs: number;
18
+ connectorName?: string;
19
+ }
20
+ interface StalenessOptions {
21
+ nowMs: number;
22
+ staleAfterMs?: number;
23
+ stalenessWarnAfterMs?: number;
24
+ unhealthyAfterMs?: number;
25
+ }
26
+ export declare function mapConnectorEventIndexRecord(row: Record<string, unknown>): ConnectorEventIndexRecord;
27
+ export declare function connectorEventIndexId(sourceConnector: string, sourceId: string): string;
28
+ export declare function connectorEventContentHash(input: {
29
+ source_connector: string;
30
+ source_id: string;
31
+ content: string;
32
+ event_datetime?: number | null;
33
+ }): Buffer;
34
+ export declare function upsertConnectorEventIndex(adapter: ConnectorEventIndexAdapter, input: UpsertConnectorEventIndexInput): ConnectorEventIndexRecord;
35
+ 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
+ export declare function readConnectorCursor(adapter: ConnectorEventIndexAdapter, connectorName: string): ConnectorEventIndexCursorRecord | null;
39
+ export declare function upsertConnectorCursor(adapter: ConnectorEventIndexAdapter, input: UpsertConnectorEventIndexCursorInput): ConnectorEventIndexCursorRecord;
40
+ export declare function deleteExpiredConnectorEvents(adapter: ConnectorEventIndexAdapter, input: DeleteExpiredConnectorEventsInput): {
41
+ rows_deleted: number;
42
+ };
43
+ export declare function computeStalenessStatus(cursor: ConnectorEventIndexCursorRecord | null, options: StalenessOptions): ConnectorEventStalenessStatus;
44
+ export type { ConnectorEventIndexCursorRecord, ConnectorEventIndexRecord, ConnectorEventSearchHit, ConnectorEventStalenessStatus, UpsertConnectorEventIndexCursorInput, UpsertConnectorEventIndexInput, } from './types.js';
45
+ //# sourceMappingURL=event-index.d.ts.map
@@ -0,0 +1,381 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mapConnectorEventIndexRecord = mapConnectorEventIndexRecord;
4
+ exports.connectorEventIndexId = connectorEventIndexId;
5
+ exports.connectorEventContentHash = connectorEventContentHash;
6
+ exports.upsertConnectorEventIndex = upsertConnectorEventIndex;
7
+ exports.getConnectorEventIndexRecord = getConnectorEventIndexRecord;
8
+ exports.listConnectorEventsByDatetimeRange = listConnectorEventsByDatetimeRange;
9
+ exports.searchConnectorEventsByFTS = searchConnectorEventsByFTS;
10
+ exports.readConnectorCursor = readConnectorCursor;
11
+ exports.upsertConnectorCursor = upsertConnectorCursor;
12
+ exports.deleteExpiredConnectorEvents = deleteExpiredConnectorEvents;
13
+ exports.computeStalenessStatus = computeStalenessStatus;
14
+ const node_crypto_1 = require("node:crypto");
15
+ 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
+ function nowIso() {
35
+ return new Date().toISOString();
36
+ }
37
+ function eventDateFromMs(ms) {
38
+ if (ms === null || !Number.isFinite(ms)) {
39
+ return null;
40
+ }
41
+ return new Date(ms).toISOString().slice(0, 10);
42
+ }
43
+ function normalizeTimestampMs(input) {
44
+ const timestamp = input.source_timestamp_ms ?? input.event_datetime;
45
+ if (typeof timestamp !== 'number' || !Number.isFinite(timestamp)) {
46
+ throw new Error('connector_event_index.source_timestamp_ms must be a finite number.');
47
+ }
48
+ return Math.floor(timestamp);
49
+ }
50
+ function normalizeEventDatetime(input) {
51
+ if (input.event_datetime === null || input.event_datetime === undefined) {
52
+ return normalizeTimestampMs(input);
53
+ }
54
+ if (!Number.isFinite(input.event_datetime)) {
55
+ throw new Error('connector_event_index.event_datetime must be a finite number when provided.');
56
+ }
57
+ return Math.floor(input.event_datetime);
58
+ }
59
+ function normalizeMetadataJson(input) {
60
+ if (input.metadata_json !== undefined) {
61
+ return input.metadata_json;
62
+ }
63
+ if (input.metadata === undefined || input.metadata === null) {
64
+ return null;
65
+ }
66
+ return (0, canonicalize_js_1.canonicalizeJSON)(input.metadata);
67
+ }
68
+ function toBuffer(value) {
69
+ if (Buffer.isBuffer(value)) {
70
+ return value;
71
+ }
72
+ if (value instanceof Uint8Array) {
73
+ return Buffer.from(value);
74
+ }
75
+ throw new Error('connector_event_index.content_hash must be a 32-byte Buffer.');
76
+ }
77
+ function mapConnectorEventIndexRow(row) {
78
+ return {
79
+ event_index_id: String(row.event_index_id),
80
+ source_connector: String(row.source_connector),
81
+ source_type: String(row.source_type),
82
+ source_id: String(row.source_id),
83
+ source_locator: row.source_locator === null ? null : String(row.source_locator),
84
+ channel: row.channel === null ? null : String(row.channel),
85
+ author: row.author === null ? null : String(row.author),
86
+ title: row.title === null ? null : String(row.title),
87
+ content: String(row.content),
88
+ event_datetime: typeof row.event_datetime === 'number' && Number.isFinite(row.event_datetime)
89
+ ? row.event_datetime
90
+ : null,
91
+ event_date: row.event_date === null ? null : String(row.event_date),
92
+ source_timestamp_ms: Number(row.source_timestamp_ms),
93
+ source_cursor: row.source_cursor === null ? null : String(row.source_cursor),
94
+ tenant_id: row.tenant_id === null ? null : String(row.tenant_id),
95
+ project_id: row.project_id === null ? null : String(row.project_id),
96
+ memory_scope_kind: row.memory_scope_kind === null ? null : String(row.memory_scope_kind),
97
+ memory_scope_id: row.memory_scope_id === null ? null : String(row.memory_scope_id),
98
+ metadata_json: row.metadata_json === null ? null : String(row.metadata_json),
99
+ artifact_locator: row.artifact_locator === null ? null : String(row.artifact_locator),
100
+ artifact_title: row.artifact_title === null ? null : String(row.artifact_title),
101
+ content_hash: toBuffer(row.content_hash),
102
+ indexed_at: String(row.indexed_at),
103
+ updated_at: String(row.updated_at),
104
+ expires_at: row.expires_at === null ? null : String(row.expires_at),
105
+ };
106
+ }
107
+ function mapConnectorEventIndexRecord(row) {
108
+ return mapConnectorEventIndexRow(row);
109
+ }
110
+ function mapConnectorCursorRow(row) {
111
+ return {
112
+ connector_name: String(row.connector_name),
113
+ last_seen_timestamp_ms: Number(row.last_seen_timestamp_ms),
114
+ last_seen_source_id: String(row.last_seen_source_id),
115
+ last_sweep_at: row.last_sweep_at === null ? null : String(row.last_sweep_at),
116
+ last_success_at: row.last_success_at === null ? null : String(row.last_success_at),
117
+ last_error: row.last_error === null ? null : String(row.last_error),
118
+ last_error_at: row.last_error_at === null ? null : String(row.last_error_at),
119
+ indexed_count: Number(row.indexed_count),
120
+ };
121
+ }
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
+ function connectorEventIndexId(sourceConnector, sourceId) {
133
+ const digest = (0, node_crypto_1.createHash)('sha1').update(`${sourceConnector}\0${sourceId}`, 'utf8').digest('hex');
134
+ return `evt_${digest.slice(0, 16)}`;
135
+ }
136
+ function connectorEventContentHash(input) {
137
+ return (0, node_crypto_1.createHash)('sha256')
138
+ .update((0, canonicalize_js_1.canonicalizeJSON)({
139
+ source_connector: input.source_connector,
140
+ source_id: input.source_id,
141
+ content: input.content,
142
+ event_datetime: input.event_datetime ?? null,
143
+ }), 'utf8')
144
+ .digest();
145
+ }
146
+ function upsertConnectorEventIndex(adapter, input) {
147
+ const sourceTimestampMs = normalizeTimestampMs(input);
148
+ const eventDatetime = normalizeEventDatetime(input);
149
+ const eventDate = input.event_date ?? eventDateFromMs(eventDatetime);
150
+ const timestamp = input.updated_at ?? nowIso();
151
+ const eventIndexId = connectorEventIndexId(input.source_connector, input.source_id);
152
+ const contentHash = input.content_hash
153
+ ? Buffer.from(input.content_hash)
154
+ : connectorEventContentHash({
155
+ source_connector: input.source_connector,
156
+ source_id: input.source_id,
157
+ content: input.content,
158
+ event_datetime: eventDatetime,
159
+ });
160
+ if (contentHash.byteLength !== 32) {
161
+ throw new Error('connector_event_index.content_hash must be exactly 32 bytes.');
162
+ }
163
+ const metadataJson = normalizeMetadataJson(input);
164
+ return adapter.transaction(() => {
165
+ adapter
166
+ .prepare(`
167
+ INSERT INTO connector_event_index (
168
+ event_index_id, source_connector, source_type, source_id, source_locator,
169
+ channel, author, title, content, event_datetime, event_date, source_timestamp_ms,
170
+ source_cursor, tenant_id, project_id, memory_scope_kind, memory_scope_id,
171
+ metadata_json, artifact_locator, artifact_title, content_hash, indexed_at, updated_at,
172
+ expires_at
173
+ )
174
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
175
+ ON CONFLICT(source_connector, source_id) DO UPDATE SET
176
+ source_type = excluded.source_type,
177
+ source_locator = excluded.source_locator,
178
+ channel = excluded.channel,
179
+ author = excluded.author,
180
+ title = excluded.title,
181
+ content = excluded.content,
182
+ event_datetime = excluded.event_datetime,
183
+ event_date = excluded.event_date,
184
+ source_timestamp_ms = excluded.source_timestamp_ms,
185
+ source_cursor = excluded.source_cursor,
186
+ tenant_id = excluded.tenant_id,
187
+ project_id = excluded.project_id,
188
+ memory_scope_kind = excluded.memory_scope_kind,
189
+ memory_scope_id = excluded.memory_scope_id,
190
+ metadata_json = excluded.metadata_json,
191
+ artifact_locator = excluded.artifact_locator,
192
+ artifact_title = excluded.artifact_title,
193
+ content_hash = excluded.content_hash,
194
+ updated_at = excluded.updated_at,
195
+ expires_at = excluded.expires_at
196
+ `)
197
+ .run(eventIndexId, input.source_connector, input.source_type, input.source_id, input.source_locator ?? null, input.channel ?? null, input.author ?? null, input.title ?? null, input.content, eventDatetime, eventDate, sourceTimestampMs, input.source_cursor ?? null, input.tenant_id ?? null, input.project_id ?? null, input.memory_scope_kind ?? null, input.memory_scope_id ?? null, metadataJson, input.artifact_locator ?? null, input.artifact_title ?? null, contentHash, input.indexed_at ?? timestamp, timestamp, input.expires_at ?? null);
198
+ const saved = getConnectorEventIndexRecord(adapter, input.source_connector, input.source_id);
199
+ if (!saved) {
200
+ throw new Error(`Failed to read connector_event_index row after upsert: ${input.source_connector}/${input.source_id}`);
201
+ }
202
+ return saved;
203
+ });
204
+ }
205
+ function getConnectorEventIndexRecord(adapter, sourceConnector, sourceId) {
206
+ const row = adapter
207
+ .prepare(`
208
+ SELECT *
209
+ FROM connector_event_index
210
+ WHERE source_connector = ?
211
+ AND source_id = ?
212
+ LIMIT 1
213
+ `)
214
+ .get(sourceConnector, sourceId);
215
+ return row ? mapConnectorEventIndexRow(row) : null;
216
+ }
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
+ function readConnectorCursor(adapter, connectorName) {
271
+ const row = adapter
272
+ .prepare(`
273
+ SELECT *
274
+ FROM connector_event_index_cursors
275
+ WHERE connector_name = ?
276
+ LIMIT 1
277
+ `)
278
+ .get(connectorName);
279
+ return row ? mapConnectorCursorRow(row) : null;
280
+ }
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
+ function deleteExpiredConnectorEvents(adapter, input) {
325
+ if (!Number.isFinite(input.nowMs)) {
326
+ throw new Error('deleteExpiredConnectorEvents.nowMs must be a finite number.');
327
+ }
328
+ if (!Number.isFinite(input.retentionMs) || input.retentionMs < 0) {
329
+ throw new Error('deleteExpiredConnectorEvents.retentionMs must be a non-negative finite number.');
330
+ }
331
+ const cutoffMs = input.nowMs - input.retentionMs;
332
+ const result = input.connectorName
333
+ ? adapter
334
+ .prepare(`
335
+ DELETE FROM connector_event_index
336
+ WHERE source_connector = ?
337
+ AND event_datetime IS NOT NULL
338
+ AND event_datetime < ?
339
+ AND artifact_locator IS NULL
340
+ `)
341
+ .run(input.connectorName, cutoffMs)
342
+ : adapter
343
+ .prepare(`
344
+ DELETE FROM connector_event_index
345
+ WHERE event_datetime IS NOT NULL
346
+ AND event_datetime < ?
347
+ AND artifact_locator IS NULL
348
+ `)
349
+ .run(cutoffMs);
350
+ return { rows_deleted: result.changes };
351
+ }
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
+ //# sourceMappingURL=event-index.js.map
@@ -0,0 +1,18 @@
1
+ import type { DatabaseAdapter } from '../db-manager.js';
2
+ import type { RawSearchHit, RawSearchInput, RawSearchResult, RawSearchScopeFilter } from './types.js';
3
+ type RawQueryAdapter = Pick<DatabaseAdapter, 'prepare'>;
4
+ interface RawWindowInput {
5
+ connectors?: string[];
6
+ scopes?: RawSearchScopeFilter[];
7
+ before?: number;
8
+ after?: number;
9
+ }
10
+ export declare function searchRaw(adapter: RawQueryAdapter, input: RawSearchInput): RawSearchResult;
11
+ export declare function searchAllRaw(adapter: RawQueryAdapter, input: RawSearchInput): RawSearchResult;
12
+ export declare function getRawById(adapter: RawQueryAdapter, rawId: string, visibility: Pick<RawSearchInput, 'connectors' | 'scopes'>): RawSearchHit | null;
13
+ export declare function getRawWindow(adapter: RawQueryAdapter, rawId: string, input: RawWindowInput): {
14
+ target: RawSearchHit;
15
+ items: RawSearchHit[];
16
+ } | null;
17
+ export type { RawSearchHit, RawSearchInput, RawSearchResult, RawSearchScopeFilter, } from './types.js';
18
+ //# sourceMappingURL=raw-query.d.ts.map