@h-rig/runtime 0.0.6-alpha.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 (176) hide show
  1. package/README.md +27 -0
  2. package/dist/bin/rig-agent-dispatch.js +9615 -0
  3. package/dist/bin/rig-agent.js +9512 -0
  4. package/dist/bin/rig-browser-tool.js +269 -0
  5. package/dist/src/agent-mode.js +48 -0
  6. package/dist/src/baked-secrets.js +121 -0
  7. package/dist/src/binary-build-worker.js +312 -0
  8. package/dist/src/binary-run.js +540 -0
  9. package/dist/src/boundaries.js +1 -0
  10. package/dist/src/build-time-config.js +25 -0
  11. package/dist/src/control-plane/agent-roles.js +27 -0
  12. package/dist/src/control-plane/agent-wrapper.js +9621 -0
  13. package/dist/src/control-plane/authority-files.js +582 -0
  14. package/dist/src/control-plane/browser-contract.js +135 -0
  15. package/dist/src/control-plane/controlled-bash.js +1111 -0
  16. package/dist/src/control-plane/errors.js +13 -0
  17. package/dist/src/control-plane/harness-main.js +10828 -0
  18. package/dist/src/control-plane/hook-materializer.js +75 -0
  19. package/dist/src/control-plane/hooks/audit-trail.js +353 -0
  20. package/dist/src/control-plane/hooks/completion-verification.js +7552 -0
  21. package/dist/src/control-plane/hooks/import-guard.js +890 -0
  22. package/dist/src/control-plane/hooks/inject-context.js +4189 -0
  23. package/dist/src/control-plane/hooks/post-edit-lint.js +43 -0
  24. package/dist/src/control-plane/hooks/safety-guard.js +910 -0
  25. package/dist/src/control-plane/hooks/scope-guard.js +907 -0
  26. package/dist/src/control-plane/hooks/shared.js +44 -0
  27. package/dist/src/control-plane/hooks/submodule-branch.js +7797 -0
  28. package/dist/src/control-plane/hooks/task-runtime-start.js +7799 -0
  29. package/dist/src/control-plane/hooks/test-integrity-guard.js +891 -0
  30. package/dist/src/control-plane/materialize-task-config.js +453 -0
  31. package/dist/src/control-plane/memory-sync/cli.js +2019 -0
  32. package/dist/src/control-plane/memory-sync/db.js +753 -0
  33. package/dist/src/control-plane/memory-sync/embed.js +281 -0
  34. package/dist/src/control-plane/memory-sync/index.js +2049 -0
  35. package/dist/src/control-plane/memory-sync/query.js +294 -0
  36. package/dist/src/control-plane/memory-sync/read.js +784 -0
  37. package/dist/src/control-plane/memory-sync/types.js +6 -0
  38. package/dist/src/control-plane/memory-sync/write.js +1547 -0
  39. package/dist/src/control-plane/native/git-native.js +490 -0
  40. package/dist/src/control-plane/native/git-ops.js +2860 -0
  41. package/dist/src/control-plane/native/harness-cli.js +9721 -0
  42. package/dist/src/control-plane/native/pr-automation.js +373 -0
  43. package/dist/src/control-plane/native/profile-ops.js +481 -0
  44. package/dist/src/control-plane/native/repo-ops.js +2342 -0
  45. package/dist/src/control-plane/native/root-resolver.js +66 -0
  46. package/dist/src/control-plane/native/run-ops.js +3281 -0
  47. package/dist/src/control-plane/native/runtime-native-sidecar.js +299 -0
  48. package/dist/src/control-plane/native/runtime-native.js +392 -0
  49. package/dist/src/control-plane/native/scope-rules.js +17 -0
  50. package/dist/src/control-plane/native/task-ops.js +6320 -0
  51. package/dist/src/control-plane/native/task-state.js +1512 -0
  52. package/dist/src/control-plane/native/utils.js +535 -0
  53. package/dist/src/control-plane/native/validator-binaries.js +889 -0
  54. package/dist/src/control-plane/native/validator.js +2197 -0
  55. package/dist/src/control-plane/native/verifier.js +3249 -0
  56. package/dist/src/control-plane/native/workspace-ops.js +1635 -0
  57. package/dist/src/control-plane/plugin-host-context.js +334 -0
  58. package/dist/src/control-plane/project-main-pre-run-sync.js +630 -0
  59. package/dist/src/control-plane/provider/claude-stream-records.js +158 -0
  60. package/dist/src/control-plane/provider/codex-app-server.js +885 -0
  61. package/dist/src/control-plane/provider/codex-exec-records.js +203 -0
  62. package/dist/src/control-plane/provider/rig-task-run-skill.js +39 -0
  63. package/dist/src/control-plane/provider/runtime-instructions.js +96 -0
  64. package/dist/src/control-plane/remote.js +854 -0
  65. package/dist/src/control-plane/repos/index.js +473 -0
  66. package/dist/src/control-plane/repos/layout.js +124 -0
  67. package/dist/src/control-plane/repos/mirror/bootstrap.js +268 -0
  68. package/dist/src/control-plane/repos/mirror/refresh.js +398 -0
  69. package/dist/src/control-plane/repos/mirror/state.js +167 -0
  70. package/dist/src/control-plane/repos/registry.js +77 -0
  71. package/dist/src/control-plane/repos/types.js +1 -0
  72. package/dist/src/control-plane/runtime/agent-mode.js +48 -0
  73. package/dist/src/control-plane/runtime/baked-secrets.js +120 -0
  74. package/dist/src/control-plane/runtime/claude-tool-router-binary.js +343 -0
  75. package/dist/src/control-plane/runtime/claude-tool-router.js +520 -0
  76. package/dist/src/control-plane/runtime/context.js +216 -0
  77. package/dist/src/control-plane/runtime/events.js +218 -0
  78. package/dist/src/control-plane/runtime/guard-types.js +6 -0
  79. package/dist/src/control-plane/runtime/guard.js +880 -0
  80. package/dist/src/control-plane/runtime/image/fingerprint-sidecar.js +1194 -0
  81. package/dist/src/control-plane/runtime/image/index.js +2255 -0
  82. package/dist/src/control-plane/runtime/image-fingerprint-sidecar.js +1191 -0
  83. package/dist/src/control-plane/runtime/image.js +2255 -0
  84. package/dist/src/control-plane/runtime/index.js +8511 -0
  85. package/dist/src/control-plane/runtime/isolation/discovery.js +599 -0
  86. package/dist/src/control-plane/runtime/isolation/home.js +1217 -0
  87. package/dist/src/control-plane/runtime/isolation/index.js +8193 -0
  88. package/dist/src/control-plane/runtime/isolation/runner.js +2651 -0
  89. package/dist/src/control-plane/runtime/isolation/shared.js +501 -0
  90. package/dist/src/control-plane/runtime/isolation/toolchain.js +1892 -0
  91. package/dist/src/control-plane/runtime/isolation/types.js +1 -0
  92. package/dist/src/control-plane/runtime/isolation/worktree.js +509 -0
  93. package/dist/src/control-plane/runtime/isolation.js +8193 -0
  94. package/dist/src/control-plane/runtime/overlay.js +67 -0
  95. package/dist/src/control-plane/runtime/plugin-mode.js +41 -0
  96. package/dist/src/control-plane/runtime/plugins.js +1131 -0
  97. package/dist/src/control-plane/runtime/provisioning-env.js +220 -0
  98. package/dist/src/control-plane/runtime/queue.js +8358 -0
  99. package/dist/src/control-plane/runtime/rig-shell.js +205 -0
  100. package/dist/src/control-plane/runtime/rig-tools.js +182 -0
  101. package/dist/src/control-plane/runtime/runner-context.js +1 -0
  102. package/dist/src/control-plane/runtime/runtime-paths.js +184 -0
  103. package/dist/src/control-plane/runtime/sandbox/backend-bwrap.js +311 -0
  104. package/dist/src/control-plane/runtime/sandbox/backend-none.js +21 -0
  105. package/dist/src/control-plane/runtime/sandbox/backend-seatbelt.js +268 -0
  106. package/dist/src/control-plane/runtime/sandbox/backend.js +1718 -0
  107. package/dist/src/control-plane/runtime/sandbox/orchestrator.js +1745 -0
  108. package/dist/src/control-plane/runtime/sandbox/utils.js +137 -0
  109. package/dist/src/control-plane/runtime/sandbox-backend-bwrap.js +311 -0
  110. package/dist/src/control-plane/runtime/sandbox-backend-none.js +21 -0
  111. package/dist/src/control-plane/runtime/sandbox-backend-seatbelt.js +268 -0
  112. package/dist/src/control-plane/runtime/sandbox-backend.js +1718 -0
  113. package/dist/src/control-plane/runtime/sandbox-orchestrator.js +1745 -0
  114. package/dist/src/control-plane/runtime/sandbox-utils.js +137 -0
  115. package/dist/src/control-plane/runtime/snapshot/index.js +454 -0
  116. package/dist/src/control-plane/runtime/snapshot/sidecar.js +502 -0
  117. package/dist/src/control-plane/runtime/snapshot/task-run.js +1578 -0
  118. package/dist/src/control-plane/runtime/snapshot-sidecar.js +498 -0
  119. package/dist/src/control-plane/runtime/snapshot.js +454 -0
  120. package/dist/src/control-plane/runtime/task-run-snapshot.js +1578 -0
  121. package/dist/src/control-plane/runtime/tool-gateway.js +422 -0
  122. package/dist/src/control-plane/runtime/tooling/browser-tools.js +32 -0
  123. package/dist/src/control-plane/runtime/tooling/claude-router-binary.js +343 -0
  124. package/dist/src/control-plane/runtime/tooling/claude-router.js +524 -0
  125. package/dist/src/control-plane/runtime/tooling/file-tools.js +182 -0
  126. package/dist/src/control-plane/runtime/tooling/gateway.js +422 -0
  127. package/dist/src/control-plane/runtime/tooling/index.js +1290 -0
  128. package/dist/src/control-plane/runtime/tooling/shell.js +205 -0
  129. package/dist/src/control-plane/runtime/types.js +1 -0
  130. package/dist/src/control-plane/setup-version.js +14 -0
  131. package/dist/src/control-plane/state-sync/index.js +1509 -0
  132. package/dist/src/control-plane/state-sync/read.js +856 -0
  133. package/dist/src/control-plane/state-sync/reconcile.js +260 -0
  134. package/dist/src/control-plane/state-sync/repo.js +302 -0
  135. package/dist/src/control-plane/state-sync/types.js +111 -0
  136. package/dist/src/control-plane/state-sync/write.js +1469 -0
  137. package/dist/src/control-plane/task-fields.js +38 -0
  138. package/dist/src/control-plane/task-source-bootstrap.js +46 -0
  139. package/dist/src/control-plane/task-source.js +30 -0
  140. package/dist/src/control-plane/tasks/legacy-task-config-source.js +130 -0
  141. package/dist/src/control-plane/tasks/plugin-task-source.js +103 -0
  142. package/dist/src/control-plane/tasks/source-aware-task-config-source.js +611 -0
  143. package/dist/src/control-plane/tasks/source-lifecycle.js +1093 -0
  144. package/dist/src/control-plane/tasks/task-record-reader.js +9 -0
  145. package/dist/src/control-plane/validators/boundary/public-apis.js +107 -0
  146. package/dist/src/control-plane/validators/integration/_shared.js +51 -0
  147. package/dist/src/control-plane/validators/integration/adm-audit-http.js +85 -0
  148. package/dist/src/control-plane/validators/integration/adm-auth-http.js +78 -0
  149. package/dist/src/control-plane/validators/integration/adm-issuer-http.js +80 -0
  150. package/dist/src/control-plane/validators/integration/adm-migration.js +78 -0
  151. package/dist/src/control-plane/validators/integration/adm-scaffold.js +78 -0
  152. package/dist/src/control-plane/validators/runtime-registration.js +64 -0
  153. package/dist/src/control-plane/validators/shared.js +683 -0
  154. package/dist/src/events.js +218 -0
  155. package/dist/src/execution.js +35 -0
  156. package/dist/src/index.js +1633 -0
  157. package/dist/src/layout.js +145 -0
  158. package/dist/src/local-server.js +202 -0
  159. package/dist/src/plugins.js +329 -0
  160. package/dist/src/remote-http.js +83 -0
  161. package/dist/src/runtime-context.js +216 -0
  162. package/dist/src/types.js +1 -0
  163. package/native/darwin-arm64/bin/rig-git +0 -0
  164. package/native/darwin-arm64/bin/rig-shell +0 -0
  165. package/native/darwin-arm64/bin/rig-tools +0 -0
  166. package/native/darwin-arm64/lib/runtime-native-darwin-arm64.dylib +0 -0
  167. package/native/darwin-arm64/lib/runtime-native.dylib +0 -0
  168. package/native/darwin-arm64/manifest.json +1 -0
  169. package/native/linux-x64/bin/rig-git +0 -0
  170. package/native/linux-x64/bin/rig-shell +0 -0
  171. package/native/linux-x64/bin/rig-tools +0 -0
  172. package/native/linux-x64/lib/runtime-native-linux-x64.so +0 -0
  173. package/native/linux-x64/lib/runtime-native.so +0 -0
  174. package/native/linux-x64/manifest.json +1 -0
  175. package/package.json +74 -0
  176. package/skills/rig-task-run.md +71 -0
@@ -0,0 +1,2049 @@
1
+ // @bun
2
+ // packages/runtime/src/control-plane/memory-sync/types.ts
3
+ var NO_MATCH_RETRIEVAL_CANONICAL_KEY = "__memory_recall__:none";
4
+ // packages/runtime/src/control-plane/memory-sync/db.ts
5
+ import { Database } from "bun:sqlite";
6
+ import { mkdirSync } from "fs";
7
+ import { dirname } from "path";
8
+ var SCHEMA_STATEMENTS = [
9
+ `CREATE TABLE IF NOT EXISTS memory_events (
10
+ event_id TEXT PRIMARY KEY,
11
+ event_type TEXT NOT NULL,
12
+ canonical_key TEXT NOT NULL,
13
+ summary TEXT,
14
+ kind TEXT,
15
+ category TEXT,
16
+ confidence REAL,
17
+ source_run_id TEXT,
18
+ source_task_id TEXT,
19
+ branch TEXT,
20
+ source_canonical_key TEXT,
21
+ replacement_canonical_key TEXT,
22
+ retrieval_query TEXT,
23
+ retrieval_rank INTEGER,
24
+ feedback_outcome TEXT,
25
+ details_json TEXT,
26
+ created_at TEXT NOT NULL
27
+ )`,
28
+ `CREATE TABLE IF NOT EXISTS memory_items (
29
+ canonical_key TEXT PRIMARY KEY,
30
+ summary TEXT NOT NULL,
31
+ kind TEXT,
32
+ category TEXT,
33
+ status TEXT NOT NULL,
34
+ confidence REAL NOT NULL,
35
+ source_run_id TEXT,
36
+ source_task_id TEXT,
37
+ branch TEXT,
38
+ details_json TEXT,
39
+ created_at TEXT NOT NULL,
40
+ updated_at TEXT NOT NULL,
41
+ last_event_id TEXT NOT NULL,
42
+ superseded_by TEXT,
43
+ embedding TEXT
44
+ )`,
45
+ `CREATE TABLE IF NOT EXISTS memory_links (
46
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
47
+ from_key TEXT NOT NULL,
48
+ to_key TEXT NOT NULL,
49
+ relation TEXT NOT NULL,
50
+ source_event_id TEXT NOT NULL,
51
+ created_at TEXT NOT NULL
52
+ )`,
53
+ `CREATE TABLE IF NOT EXISTS task_runs (
54
+ run_id TEXT PRIMARY KEY,
55
+ task_id TEXT,
56
+ branch TEXT,
57
+ first_event_id TEXT,
58
+ last_event_id TEXT,
59
+ created_at TEXT NOT NULL,
60
+ updated_at TEXT NOT NULL
61
+ )`,
62
+ `CREATE TABLE IF NOT EXISTS retrieval_feedback (
63
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
64
+ canonical_key TEXT NOT NULL,
65
+ outcome TEXT NOT NULL,
66
+ retrieval_rank INTEGER,
67
+ source_run_id TEXT,
68
+ source_task_id TEXT,
69
+ query_text TEXT,
70
+ source_event_id TEXT NOT NULL,
71
+ created_at TEXT NOT NULL
72
+ )`
73
+ ];
74
+ var MEMORY_EVENT_COLUMNS = [
75
+ ["summary", "TEXT"],
76
+ ["kind", "TEXT"],
77
+ ["category", "TEXT"],
78
+ ["confidence", "REAL"],
79
+ ["source_run_id", "TEXT"],
80
+ ["source_task_id", "TEXT"],
81
+ ["branch", "TEXT"],
82
+ ["source_canonical_key", "TEXT"],
83
+ ["replacement_canonical_key", "TEXT"],
84
+ ["retrieval_query", "TEXT"],
85
+ ["retrieval_rank", "INTEGER"],
86
+ ["feedback_outcome", "TEXT"],
87
+ ["details_json", "TEXT"]
88
+ ];
89
+ var MEMORY_ITEM_COLUMNS = [
90
+ ["kind", "TEXT"],
91
+ ["category", "TEXT"],
92
+ ["branch", "TEXT"],
93
+ ["details_json", "TEXT"],
94
+ ["superseded_by", "TEXT"],
95
+ ["embedding", "TEXT"]
96
+ ];
97
+ function jsonText(value) {
98
+ if (value == null) {
99
+ return null;
100
+ }
101
+ return JSON.stringify(value);
102
+ }
103
+ function parseJsonRecord(value) {
104
+ if (typeof value !== "string" || value.length === 0) {
105
+ return null;
106
+ }
107
+ return JSON.parse(value);
108
+ }
109
+ function parseEmbedding(value) {
110
+ if (typeof value !== "string" || value.length === 0) {
111
+ return null;
112
+ }
113
+ return JSON.parse(value);
114
+ }
115
+ function rowString(row, key) {
116
+ const value = row[key];
117
+ return value == null ? null : String(value);
118
+ }
119
+ function eventSummary(event) {
120
+ return "summary" in event ? event.summary : null;
121
+ }
122
+ function eventKind(event) {
123
+ return "kind" in event ? event.kind : null;
124
+ }
125
+ function eventCategory(event) {
126
+ return "category" in event ? event.category ?? null : null;
127
+ }
128
+ function eventConfidence(event) {
129
+ return "confidence" in event ? event.confidence : null;
130
+ }
131
+ function eventDetails(event) {
132
+ return "details" in event ? event.details ?? null : null;
133
+ }
134
+ function eventSourceCanonicalKey(event) {
135
+ return "sourceCanonicalKey" in event ? event.sourceCanonicalKey : null;
136
+ }
137
+ function eventReplacementCanonicalKey(event) {
138
+ return "replacementCanonicalKey" in event ? event.replacementCanonicalKey : null;
139
+ }
140
+ function eventRetrievalQuery(event) {
141
+ return "retrievalQuery" in event ? event.retrievalQuery ?? null : null;
142
+ }
143
+ function eventRetrievalRank(event) {
144
+ return "retrievalRank" in event ? event.retrievalRank : null;
145
+ }
146
+ function eventFeedbackOutcome(event) {
147
+ return "feedbackOutcome" in event ? event.feedbackOutcome : null;
148
+ }
149
+ function normalizeStatement(statement, args) {
150
+ if (typeof statement === "string") {
151
+ return { sql: statement, args };
152
+ }
153
+ return {
154
+ sql: statement.sql,
155
+ args: statement.args ?? args
156
+ };
157
+ }
158
+ function normalizeBindings(bindings) {
159
+ return (bindings ?? []).map((binding) => binding === undefined ? null : binding);
160
+ }
161
+ function statementVerb(sql) {
162
+ const match = sql.trim().match(/^[A-Za-z]+/);
163
+ return match ? match[0].toUpperCase() : "";
164
+ }
165
+ function isMutationStatement(sql) {
166
+ return new Set([
167
+ "ALTER",
168
+ "ATTACH",
169
+ "BEGIN",
170
+ "COMMIT",
171
+ "CREATE",
172
+ "DELETE",
173
+ "DETACH",
174
+ "DROP",
175
+ "END",
176
+ "INSERT",
177
+ "REINDEX",
178
+ "RELEASE",
179
+ "REPLACE",
180
+ "ROLLBACK",
181
+ "SAVEPOINT",
182
+ "UPDATE",
183
+ "VACUUM"
184
+ ]).has(statementVerb(sql));
185
+ }
186
+ function executeSqlite(sqlite, statement, args) {
187
+ const normalized = normalizeStatement(statement, args);
188
+ const bindings = normalizeBindings(normalized.args);
189
+ if (isMutationStatement(normalized.sql)) {
190
+ const result = bindings.length > 0 ? sqlite.run(normalized.sql, ...bindings) : sqlite.run(normalized.sql);
191
+ return {
192
+ rows: [],
193
+ rowsAffected: Number(result.changes)
194
+ };
195
+ }
196
+ const query = sqlite.query(normalized.sql);
197
+ const rows = bindings.length > 0 ? query.all(...bindings) : query.all();
198
+ return {
199
+ rows,
200
+ rowsAffected: 0
201
+ };
202
+ }
203
+ function createTransaction(sqlite, mode) {
204
+ sqlite.run(mode === "write" ? "BEGIN IMMEDIATE" : "BEGIN");
205
+ let active = true;
206
+ return {
207
+ async execute(statement, args) {
208
+ if (!active) {
209
+ throw new Error("memory transaction is closed");
210
+ }
211
+ return executeSqlite(sqlite, statement, args);
212
+ },
213
+ async commit() {
214
+ if (!active) {
215
+ return;
216
+ }
217
+ sqlite.run("COMMIT");
218
+ active = false;
219
+ },
220
+ async rollback() {
221
+ if (!active) {
222
+ return;
223
+ }
224
+ sqlite.run("ROLLBACK");
225
+ active = false;
226
+ },
227
+ close() {
228
+ if (!active) {
229
+ return;
230
+ }
231
+ try {
232
+ sqlite.run("ROLLBACK");
233
+ } catch {} finally {
234
+ active = false;
235
+ }
236
+ }
237
+ };
238
+ }
239
+ function createMemoryDbClient(sqlite) {
240
+ return {
241
+ async execute(statement, args) {
242
+ return executeSqlite(sqlite, statement, args);
243
+ },
244
+ async transaction(mode) {
245
+ return createTransaction(sqlite, mode);
246
+ },
247
+ close() {
248
+ sqlite.close();
249
+ }
250
+ };
251
+ }
252
+ async function listColumns(executor, tableName) {
253
+ const result = await executor.execute(`PRAGMA table_info(${tableName})`);
254
+ return new Set(result.rows.map((row) => String(row.name)));
255
+ }
256
+ async function ensureColumns(executor, tableName, columns) {
257
+ const existing = await listColumns(executor, tableName);
258
+ for (const [columnName, definition] of columns) {
259
+ if (!existing.has(columnName)) {
260
+ await executor.execute(`ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${definition}`);
261
+ }
262
+ }
263
+ }
264
+ async function ensureSchema(db) {
265
+ for (const statement of SCHEMA_STATEMENTS) {
266
+ await db.client.execute(statement);
267
+ }
268
+ await ensureColumns(db.client, "memory_events", MEMORY_EVENT_COLUMNS);
269
+ await ensureColumns(db.client, "memory_items", MEMORY_ITEM_COLUMNS);
270
+ }
271
+ function toMemoryItemRow(row) {
272
+ return {
273
+ canonicalKey: String(row.canonical_key),
274
+ summary: String(row.summary),
275
+ kind: rowString(row, "kind"),
276
+ category: rowString(row, "category"),
277
+ status: String(row.status),
278
+ confidence: Number(row.confidence),
279
+ sourceRunId: rowString(row, "source_run_id"),
280
+ sourceTaskId: rowString(row, "source_task_id"),
281
+ branch: rowString(row, "branch"),
282
+ details: parseJsonRecord(row.details_json),
283
+ createdAt: String(row.created_at),
284
+ updatedAt: String(row.updated_at),
285
+ lastEventId: String(row.last_event_id),
286
+ supersededBy: rowString(row, "superseded_by"),
287
+ embedding: parseEmbedding(row.embedding)
288
+ };
289
+ }
290
+ function toMemoryEventRow(row) {
291
+ return {
292
+ eventId: String(row.event_id),
293
+ eventType: String(row.event_type),
294
+ canonicalKey: String(row.canonical_key),
295
+ summary: rowString(row, "summary") ?? "",
296
+ createdAt: String(row.created_at)
297
+ };
298
+ }
299
+ async function hasMemoryItem(executor, canonicalKey) {
300
+ const result = await executor.execute({
301
+ sql: "SELECT 1 AS present FROM memory_items WHERE canonical_key = ? LIMIT 1",
302
+ args: [canonicalKey]
303
+ });
304
+ return result.rows.length > 0;
305
+ }
306
+ async function assertMemoryItemExists(executor, canonicalKey, errorPrefix) {
307
+ if (!await hasMemoryItem(executor, canonicalKey)) {
308
+ throw new Error(`${errorPrefix}: unknown memory ${canonicalKey}`);
309
+ }
310
+ }
311
+ async function upsertTaskRun(executor, event) {
312
+ if (!event.sourceRunId) {
313
+ return;
314
+ }
315
+ await executor.execute({
316
+ sql: `
317
+ INSERT INTO task_runs (
318
+ run_id,
319
+ task_id,
320
+ branch,
321
+ first_event_id,
322
+ last_event_id,
323
+ created_at,
324
+ updated_at
325
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)
326
+ ON CONFLICT(run_id) DO UPDATE SET
327
+ task_id = COALESCE(excluded.task_id, task_runs.task_id),
328
+ branch = COALESCE(excluded.branch, task_runs.branch),
329
+ last_event_id = excluded.last_event_id,
330
+ updated_at = excluded.updated_at
331
+ `,
332
+ args: [
333
+ event.sourceRunId,
334
+ event.sourceTaskId ?? null,
335
+ event.branch ?? null,
336
+ event.eventId,
337
+ event.eventId,
338
+ event.createdAt,
339
+ event.createdAt
340
+ ]
341
+ });
342
+ }
343
+ async function insertEventRow(executor, event) {
344
+ await executor.execute({
345
+ sql: `
346
+ INSERT INTO memory_events (
347
+ event_id,
348
+ event_type,
349
+ canonical_key,
350
+ summary,
351
+ kind,
352
+ category,
353
+ confidence,
354
+ source_run_id,
355
+ source_task_id,
356
+ branch,
357
+ source_canonical_key,
358
+ replacement_canonical_key,
359
+ retrieval_query,
360
+ retrieval_rank,
361
+ feedback_outcome,
362
+ details_json,
363
+ created_at
364
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
365
+ `,
366
+ args: [
367
+ event.eventId,
368
+ event.eventType,
369
+ event.canonicalKey,
370
+ eventSummary(event),
371
+ eventKind(event),
372
+ eventCategory(event),
373
+ eventConfidence(event),
374
+ event.sourceRunId ?? null,
375
+ event.sourceTaskId ?? null,
376
+ event.branch ?? null,
377
+ eventSourceCanonicalKey(event),
378
+ eventReplacementCanonicalKey(event),
379
+ eventRetrievalQuery(event),
380
+ eventRetrievalRank(event),
381
+ eventFeedbackOutcome(event),
382
+ jsonText(eventDetails(event)),
383
+ event.createdAt
384
+ ]
385
+ });
386
+ }
387
+ async function upsertProjectedMemory(executor, event, status = "active") {
388
+ await executor.execute({
389
+ sql: `
390
+ INSERT INTO memory_items (
391
+ canonical_key,
392
+ summary,
393
+ kind,
394
+ category,
395
+ status,
396
+ confidence,
397
+ source_run_id,
398
+ source_task_id,
399
+ branch,
400
+ details_json,
401
+ created_at,
402
+ updated_at,
403
+ last_event_id,
404
+ superseded_by,
405
+ embedding
406
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)
407
+ ON CONFLICT(canonical_key) DO UPDATE SET
408
+ summary = excluded.summary,
409
+ kind = excluded.kind,
410
+ category = excluded.category,
411
+ status = excluded.status,
412
+ confidence = COALESCE(excluded.confidence, memory_items.confidence),
413
+ source_run_id = COALESCE(excluded.source_run_id, memory_items.source_run_id),
414
+ source_task_id = COALESCE(excluded.source_task_id, memory_items.source_task_id),
415
+ branch = COALESCE(excluded.branch, memory_items.branch),
416
+ details_json = COALESCE(excluded.details_json, memory_items.details_json),
417
+ updated_at = excluded.updated_at,
418
+ last_event_id = excluded.last_event_id,
419
+ superseded_by = excluded.superseded_by,
420
+ embedding = excluded.embedding
421
+ `,
422
+ args: [
423
+ event.canonicalKey,
424
+ eventSummary(event),
425
+ eventKind(event),
426
+ eventCategory(event),
427
+ status,
428
+ eventConfidence(event) ?? 0,
429
+ event.sourceRunId ?? null,
430
+ event.sourceTaskId ?? null,
431
+ event.branch ?? null,
432
+ jsonText(eventDetails(event)),
433
+ event.createdAt,
434
+ event.createdAt,
435
+ event.eventId,
436
+ eventReplacementCanonicalKey(event)
437
+ ]
438
+ });
439
+ }
440
+ async function insertMemoryLink(executor, fromKey, toKey, relation, event) {
441
+ await executor.execute({
442
+ sql: `
443
+ INSERT INTO memory_links (from_key, to_key, relation, source_event_id, created_at)
444
+ VALUES (?, ?, ?, ?, ?)
445
+ `,
446
+ args: [fromKey, toKey, relation, event.eventId, event.createdAt]
447
+ });
448
+ }
449
+ async function markSuperseded(executor, event) {
450
+ const result = await executor.execute({
451
+ sql: `
452
+ UPDATE memory_items
453
+ SET
454
+ status = 'superseded',
455
+ superseded_by = ?,
456
+ updated_at = ?,
457
+ last_event_id = ?
458
+ WHERE canonical_key = ?
459
+ `,
460
+ args: [eventReplacementCanonicalKey(event), event.createdAt, event.eventId, event.canonicalKey]
461
+ });
462
+ if ((result.rowsAffected ?? 0) === 0) {
463
+ throw new Error(`cannot supersede unknown memory ${event.canonicalKey}`);
464
+ }
465
+ if (eventReplacementCanonicalKey(event)) {
466
+ await insertMemoryLink(executor, event.canonicalKey, eventReplacementCanonicalKey(event), "superseded_by", event);
467
+ }
468
+ }
469
+ async function activeMemoryItem(executor, canonicalKey) {
470
+ const result = await executor.execute({
471
+ sql: `
472
+ SELECT
473
+ canonical_key,
474
+ summary,
475
+ kind,
476
+ category,
477
+ status,
478
+ confidence,
479
+ source_run_id,
480
+ source_task_id,
481
+ branch,
482
+ details_json,
483
+ created_at,
484
+ updated_at,
485
+ last_event_id,
486
+ superseded_by,
487
+ embedding
488
+ FROM memory_items
489
+ WHERE canonical_key = ?
490
+ LIMIT 1
491
+ `,
492
+ args: [canonicalKey]
493
+ });
494
+ const row = result.rows[0];
495
+ return row ? toMemoryItemRow(row) : null;
496
+ }
497
+ async function markRetracted(executor, event) {
498
+ const result = await executor.execute({
499
+ sql: `
500
+ UPDATE memory_items
501
+ SET
502
+ status = 'retracted',
503
+ updated_at = ?,
504
+ last_event_id = ?
505
+ WHERE canonical_key = ?
506
+ `,
507
+ args: [event.createdAt, event.eventId, event.canonicalKey]
508
+ });
509
+ if ((result.rowsAffected ?? 0) === 0) {
510
+ throw new Error(`cannot retract unknown memory ${event.canonicalKey}`);
511
+ }
512
+ }
513
+ async function recordRetrievalFeedback(executor, event) {
514
+ await executor.execute({
515
+ sql: `
516
+ INSERT INTO retrieval_feedback (
517
+ canonical_key,
518
+ outcome,
519
+ retrieval_rank,
520
+ source_run_id,
521
+ source_task_id,
522
+ query_text,
523
+ source_event_id,
524
+ created_at
525
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
526
+ `,
527
+ args: [
528
+ event.canonicalKey,
529
+ eventFeedbackOutcome(event) ?? "ignored",
530
+ eventRetrievalRank(event),
531
+ event.sourceRunId ?? null,
532
+ event.sourceTaskId ?? null,
533
+ eventRetrievalQuery(event),
534
+ event.eventId,
535
+ event.createdAt
536
+ ]
537
+ });
538
+ }
539
+ async function applyReinforcement(executor, event) {
540
+ const existing = await activeMemoryItem(executor, event.canonicalKey);
541
+ if (!existing) {
542
+ throw new Error(`cannot reinforce unknown memory ${event.canonicalKey}`);
543
+ }
544
+ if (existing.status !== "active") {
545
+ throw new Error(`cannot reinforce non-active memory ${event.canonicalKey}`);
546
+ }
547
+ const result = await executor.execute({
548
+ sql: `
549
+ UPDATE memory_items
550
+ SET
551
+ status = 'active',
552
+ confidence = ?,
553
+ source_run_id = COALESCE(?, source_run_id),
554
+ source_task_id = COALESCE(?, source_task_id),
555
+ branch = COALESCE(?, branch),
556
+ updated_at = ?,
557
+ last_event_id = ?,
558
+ superseded_by = NULL
559
+ WHERE canonical_key = ?
560
+ `,
561
+ args: [
562
+ eventConfidence(event),
563
+ event.sourceRunId ?? null,
564
+ event.sourceTaskId ?? null,
565
+ event.branch ?? null,
566
+ event.createdAt,
567
+ event.eventId,
568
+ event.canonicalKey
569
+ ]
570
+ });
571
+ if ((result.rowsAffected ?? 0) === 0) {
572
+ throw new Error(`cannot reinforce unknown memory ${event.canonicalKey}`);
573
+ }
574
+ }
575
+ async function validateEventTargets(executor, event) {
576
+ switch (event.eventType) {
577
+ case "observed":
578
+ return;
579
+ case "promoted":
580
+ case "corrected":
581
+ await assertMemoryItemExists(executor, event.sourceCanonicalKey, `cannot ${event.eventType}`);
582
+ return;
583
+ case "superseded":
584
+ await assertMemoryItemExists(executor, event.replacementCanonicalKey, "cannot supersede");
585
+ await assertMemoryItemExists(executor, event.canonicalKey, "cannot supersede");
586
+ return;
587
+ case "retracted":
588
+ case "feedback_recorded":
589
+ await assertMemoryItemExists(executor, event.canonicalKey, `cannot ${event.eventType}`);
590
+ return;
591
+ case "reinforced":
592
+ await assertMemoryItemExists(executor, event.canonicalKey, "cannot reinforce");
593
+ return;
594
+ case "retrieved":
595
+ if (event.retrievalRank === 0 && event.canonicalKey === NO_MATCH_RETRIEVAL_CANONICAL_KEY) {
596
+ return;
597
+ }
598
+ await assertMemoryItemExists(executor, event.canonicalKey, `cannot ${event.eventType}`);
599
+ return;
600
+ default: {
601
+ const _exhaustive = event;
602
+ return _exhaustive;
603
+ }
604
+ }
605
+ }
606
+ async function openMemoryDb(dbPath) {
607
+ mkdirSync(dirname(dbPath), { recursive: true });
608
+ const sqlite = new Database(dbPath, { create: true, strict: true });
609
+ const client = createMemoryDbClient(sqlite);
610
+ const db = {
611
+ path: dbPath,
612
+ client,
613
+ async close() {
614
+ client.close();
615
+ }
616
+ };
617
+ await ensureSchema(db);
618
+ return db;
619
+ }
620
+ async function applyMemoryEvent(db, event) {
621
+ const transaction = await db.client.transaction("write");
622
+ try {
623
+ await validateEventTargets(transaction, event);
624
+ await insertEventRow(transaction, event);
625
+ await upsertTaskRun(transaction, event);
626
+ switch (event.eventType) {
627
+ case "observed":
628
+ await upsertProjectedMemory(transaction, event, "active");
629
+ break;
630
+ case "promoted":
631
+ await upsertProjectedMemory(transaction, event, "active");
632
+ if (event.sourceCanonicalKey) {
633
+ await insertMemoryLink(transaction, event.canonicalKey, event.sourceCanonicalKey, "promoted_from", event);
634
+ }
635
+ break;
636
+ case "corrected":
637
+ await upsertProjectedMemory(transaction, event, "active");
638
+ if (event.sourceCanonicalKey) {
639
+ await insertMemoryLink(transaction, event.canonicalKey, event.sourceCanonicalKey, "corrected_from", event);
640
+ }
641
+ break;
642
+ case "superseded":
643
+ await markSuperseded(transaction, event);
644
+ break;
645
+ case "retracted":
646
+ await markRetracted(transaction, event);
647
+ break;
648
+ case "reinforced":
649
+ await applyReinforcement(transaction, event);
650
+ break;
651
+ case "retrieved":
652
+ break;
653
+ case "feedback_recorded":
654
+ await recordRetrievalFeedback(transaction, event);
655
+ break;
656
+ }
657
+ await transaction.commit();
658
+ } catch (error) {
659
+ await transaction.rollback();
660
+ throw error;
661
+ } finally {
662
+ transaction.close();
663
+ }
664
+ }
665
+ async function setMemoryItemEmbedding(db, canonicalKey, embedding) {
666
+ await db.client.execute({
667
+ sql: `
668
+ UPDATE memory_items
669
+ SET embedding = ?
670
+ WHERE canonical_key = ?
671
+ `,
672
+ args: [JSON.stringify(embedding), canonicalKey]
673
+ });
674
+ }
675
+ async function getMemoryItemByKey(db, canonicalKey) {
676
+ const result = await db.client.execute({
677
+ sql: `
678
+ SELECT
679
+ canonical_key,
680
+ summary,
681
+ kind,
682
+ category,
683
+ status,
684
+ confidence,
685
+ source_run_id,
686
+ source_task_id,
687
+ branch,
688
+ details_json,
689
+ created_at,
690
+ updated_at,
691
+ last_event_id,
692
+ superseded_by,
693
+ embedding
694
+ FROM memory_items
695
+ WHERE canonical_key = ?
696
+ LIMIT 1
697
+ `,
698
+ args: [canonicalKey]
699
+ });
700
+ const row = result.rows[0];
701
+ return row ? toMemoryItemRow(row) : null;
702
+ }
703
+ async function listActiveMemoryItems(db) {
704
+ const result = await db.client.execute(`
705
+ SELECT
706
+ canonical_key,
707
+ summary,
708
+ kind,
709
+ category,
710
+ status,
711
+ confidence,
712
+ source_run_id,
713
+ source_task_id,
714
+ branch,
715
+ details_json,
716
+ created_at,
717
+ updated_at,
718
+ last_event_id,
719
+ superseded_by,
720
+ embedding
721
+ FROM memory_items
722
+ WHERE status = 'active'
723
+ ORDER BY canonical_key
724
+ `);
725
+ return result.rows.map((row) => toMemoryItemRow(row));
726
+ }
727
+ async function hasMemoryEvent(db, eventId) {
728
+ const result = await db.client.execute({
729
+ sql: "SELECT 1 AS present FROM memory_events WHERE event_id = ? LIMIT 1",
730
+ args: [eventId]
731
+ });
732
+ return result.rows.length > 0;
733
+ }
734
+ async function listMemoryEvents(db) {
735
+ const result = await db.client.execute(`
736
+ SELECT event_id, event_type, canonical_key, summary, created_at
737
+ FROM memory_events
738
+ ORDER BY created_at, event_id
739
+ `);
740
+ return result.rows.map((row) => toMemoryEventRow(row));
741
+ }
742
+ // packages/runtime/src/control-plane/memory-sync/embed.ts
743
+ import { createHash } from "crypto";
744
+ var DEFAULT_EMBEDDING_API_BASE_URL = "https://api.openai.com/v1";
745
+ var DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small";
746
+ var DETERMINISTIC_EMBEDDER_MODE = "deterministic";
747
+ var DETERMINISTIC_VECTOR_DIMS = 32;
748
+ var MISSING_MEMORY_EMBEDDER_WARNING = "Shared memory embeddings disabled: OPENAI_API_KEY is not set. Continuing with lexical-only memory.";
749
+ var missingMemoryEmbedderWarningShown = false;
750
+ function embeddingTextForItem(item) {
751
+ const parts = [item.summary, item.kind ?? "", item.category ?? "", item.details ? JSON.stringify(item.details) : ""];
752
+ return parts.filter(Boolean).join(`
753
+ `);
754
+ }
755
+ function tokenizeForDeterministicEmbedding(text) {
756
+ const tokens = text.toLowerCase().match(/[a-z0-9_./:-]+/g) ?? [];
757
+ return tokens.length > 0 ? tokens : [text.toLowerCase()];
758
+ }
759
+ function deterministicTokenVector(token) {
760
+ const hash = createHash("sha256").update(token).digest();
761
+ const vector = new Array(DETERMINISTIC_VECTOR_DIMS).fill(0);
762
+ for (let index = 0;index < 8; index += 1) {
763
+ const slot = (hash[index] ?? 0) % DETERMINISTIC_VECTOR_DIMS;
764
+ const sign = ((hash[index + 8] ?? 0) & 1) === 0 ? 1 : -1;
765
+ const magnitude = ((hash[index + 16] ?? 0) + 1) / 256;
766
+ vector[slot] = (vector[slot] ?? 0) + sign * magnitude;
767
+ }
768
+ return vector;
769
+ }
770
+ function normalizeVector(vector) {
771
+ const norm = Math.sqrt(vector.reduce((sum, value) => sum + value * value, 0));
772
+ if (norm === 0) {
773
+ return vector.map(() => 0);
774
+ }
775
+ return vector.map((value) => Number((value / norm).toFixed(6)));
776
+ }
777
+ function createDeterministicMemoryEmbedder() {
778
+ return {
779
+ async embed(texts) {
780
+ return texts.map((text) => {
781
+ const vector = new Array(DETERMINISTIC_VECTOR_DIMS).fill(0);
782
+ for (const token of tokenizeForDeterministicEmbedding(text)) {
783
+ const tokenVector = deterministicTokenVector(token);
784
+ for (let index = 0;index < tokenVector.length; index += 1) {
785
+ vector[index] = (vector[index] ?? 0) + (tokenVector[index] ?? 0);
786
+ }
787
+ }
788
+ return normalizeVector(vector);
789
+ });
790
+ }
791
+ };
792
+ }
793
+ function embeddingResponseMessage(payload, status) {
794
+ if (typeof payload === "object" && payload !== null) {
795
+ const maybeMessage = payload.error?.message;
796
+ if (maybeMessage) {
797
+ return maybeMessage;
798
+ }
799
+ }
800
+ return `memory embedding request failed with status ${status}`;
801
+ }
802
+ function createOpenAiMemoryEmbedder(options) {
803
+ const apiKey = options.apiKey.trim();
804
+ const model = options.model?.trim() || DEFAULT_EMBEDDING_MODEL;
805
+ const apiBaseUrl = (options.apiBaseUrl?.trim() || DEFAULT_EMBEDDING_API_BASE_URL).replace(/\/+$/, "");
806
+ const fetchImpl = options.fetchImpl ?? fetch;
807
+ if (!apiKey) {
808
+ throw new Error("memory embedding api key must be non-empty");
809
+ }
810
+ return {
811
+ async embed(texts) {
812
+ if (texts.length === 0) {
813
+ return [];
814
+ }
815
+ const response = await fetchImpl(`${apiBaseUrl}/embeddings`, {
816
+ method: "POST",
817
+ headers: {
818
+ authorization: `Bearer ${apiKey}`,
819
+ "content-type": "application/json"
820
+ },
821
+ body: JSON.stringify({
822
+ input: texts,
823
+ model
824
+ })
825
+ });
826
+ const payload = await response.json();
827
+ if (!response.ok) {
828
+ throw new Error(embeddingResponseMessage(payload, response.status));
829
+ }
830
+ if (!Array.isArray(payload.data) || payload.data.length !== texts.length) {
831
+ throw new Error(`memory embedding provider returned ${payload.data?.length ?? 0} embeddings for ${texts.length} inputs`);
832
+ }
833
+ const byIndex = new Map;
834
+ for (const row of payload.data) {
835
+ if (typeof row.index !== "number" || !Array.isArray(row.embedding)) {
836
+ throw new Error("memory embedding provider returned an invalid response payload");
837
+ }
838
+ byIndex.set(row.index, row.embedding);
839
+ }
840
+ return texts.map((_text, index) => {
841
+ const embedding = byIndex.get(index);
842
+ if (!embedding) {
843
+ throw new Error(`memory embedding provider omitted embedding ${index}`);
844
+ }
845
+ return embedding;
846
+ });
847
+ }
848
+ };
849
+ }
850
+ function createConfiguredMemoryEmbedder(options = {}) {
851
+ const env = options.env ?? process.env;
852
+ const mode = env.RIG_MEMORY_EMBEDDER?.trim();
853
+ if (mode === DETERMINISTIC_EMBEDDER_MODE) {
854
+ return createDeterministicMemoryEmbedder();
855
+ }
856
+ const apiKey = env.OPENAI_API_KEY?.trim();
857
+ if (!apiKey) {
858
+ throw new Error("memory embeddings require OPENAI_API_KEY or RIG_MEMORY_EMBEDDER=deterministic");
859
+ }
860
+ return createOpenAiMemoryEmbedder({
861
+ apiKey,
862
+ model: env.RIG_MEMORY_EMBEDDING_MODEL?.trim() || DEFAULT_EMBEDDING_MODEL,
863
+ apiBaseUrl: options.apiBaseUrl ?? env.RIG_MEMORY_EMBEDDING_API_BASE_URL?.trim() ?? DEFAULT_EMBEDDING_API_BASE_URL,
864
+ fetchImpl: options.fetchImpl
865
+ });
866
+ }
867
+ function warnMissingMemoryEmbedderOnce(warn) {
868
+ if (missingMemoryEmbedderWarningShown) {
869
+ return;
870
+ }
871
+ missingMemoryEmbedderWarningShown = true;
872
+ warn(MISSING_MEMORY_EMBEDDER_WARNING);
873
+ }
874
+ function resetMemoryEmbeddingWarningsForTests() {
875
+ missingMemoryEmbedderWarningShown = false;
876
+ }
877
+ function embeddingTargetsForEvent(event) {
878
+ switch (event.eventType) {
879
+ case "observed":
880
+ case "promoted":
881
+ case "corrected":
882
+ case "reinforced":
883
+ return [event.canonicalKey];
884
+ case "superseded":
885
+ case "retracted":
886
+ case "retrieved":
887
+ case "feedback_recorded":
888
+ return [];
889
+ }
890
+ }
891
+ function memoryEventRequiresEmbedding(event) {
892
+ return embeddingTargetsForEvent(event).length > 0;
893
+ }
894
+ function maybeCreateConfiguredMemoryEmbedder(options = {}, warn = (message) => {
895
+ console.warn(message);
896
+ }) {
897
+ const env = options.env ?? process.env;
898
+ const mode = env.RIG_MEMORY_EMBEDDER?.trim();
899
+ if (mode === DETERMINISTIC_EMBEDDER_MODE) {
900
+ return createConfiguredMemoryEmbedder(options);
901
+ }
902
+ const apiKey = env.OPENAI_API_KEY?.trim();
903
+ if (!apiKey) {
904
+ warnMissingMemoryEmbedderOnce(warn);
905
+ return null;
906
+ }
907
+ return createConfiguredMemoryEmbedder(options);
908
+ }
909
+ async function embedChangedMemoryItems(db, event, embedder) {
910
+ const targets = [...new Set(embeddingTargetsForEvent(event))];
911
+ if (targets.length === 0) {
912
+ return [];
913
+ }
914
+ const items = [];
915
+ for (const canonicalKey of targets) {
916
+ const item = await getMemoryItemByKey(db, canonicalKey);
917
+ if (item && item.status === "active") {
918
+ items.push(item);
919
+ }
920
+ }
921
+ if (items.length === 0) {
922
+ return [];
923
+ }
924
+ const texts = items.map(embeddingTextForItem);
925
+ const embeddings = await embedder.embed(texts);
926
+ for (const [index, item] of items.entries()) {
927
+ const embedding = embeddings[index];
928
+ if (!embedding) {
929
+ throw new Error(`missing embedding for ${item.canonicalKey}`);
930
+ }
931
+ await setMemoryItemEmbedding(db, item.canonicalKey, embedding);
932
+ }
933
+ return texts;
934
+ }
935
+ // packages/runtime/src/control-plane/memory-sync/read.ts
936
+ import { mkdtempSync, rmSync as rmSync3, writeFileSync as writeFileSync2 } from "fs";
937
+ import { tmpdir as tmpdir3 } from "os";
938
+ import { join } from "path";
939
+
940
+ // packages/runtime/src/control-plane/native/git-native.ts
941
+ import { chmodSync, copyFileSync, existsSync, mkdirSync as mkdirSync2, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
942
+ import { tmpdir } from "os";
943
+ import { dirname as dirname2, isAbsolute, resolve } from "path";
944
+ import { createHash as createHash2 } from "crypto";
945
+ function isTextTreeCommitUpdate(update) {
946
+ return typeof update.content === "string";
947
+ }
948
+ var sharedGitNativeOutputDir = resolve(tmpdir(), "rig-native");
949
+ var sharedGitNativeOutputPath = resolve(sharedGitNativeOutputDir, `rig-git-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
950
+ var trackerCommandUsageProbe = "usage: rig-git fetch-ref <repo-path> <remote> <branch>";
951
+ function temporaryGitBinaryOutputPath(outputPath) {
952
+ const suffix = process.platform === "win32" ? ".exe" : "";
953
+ return resolve(dirname2(outputPath), `.rig-git-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}${suffix}`);
954
+ }
955
+ function publishGitBinary(tempOutputPath, outputPath) {
956
+ try {
957
+ renameSync(tempOutputPath, outputPath);
958
+ } catch (error) {
959
+ if (process.platform === "win32" && existsSync(outputPath)) {
960
+ rmSync(outputPath, { force: true });
961
+ renameSync(tempOutputPath, outputPath);
962
+ return;
963
+ }
964
+ throw error;
965
+ }
966
+ }
967
+ function runtimeRigGitFileName() {
968
+ return `rig-git${process.platform === "win32" ? ".exe" : ""}`;
969
+ }
970
+ function rigGitSourceCandidates() {
971
+ const execDir = process.execPath?.trim() ? dirname2(process.execPath.trim()) : "";
972
+ const cwd = process.cwd()?.trim() || "";
973
+ const projectRoot = process.env.PROJECT_RIG_ROOT?.trim() || "";
974
+ const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || "";
975
+ const moduleRelativeSource = resolve(import.meta.dir, "../../../native/rig-git.zig");
976
+ return [...new Set([
977
+ process.env.RIG_NATIVE_GIT_SOURCE?.trim() || "",
978
+ moduleRelativeSource,
979
+ projectRoot ? resolve(projectRoot, "packages/runtime/native/rig-git.zig") : "",
980
+ hostProjectRoot ? resolve(hostProjectRoot, "packages/runtime/native/rig-git.zig") : "",
981
+ cwd ? resolve(cwd, "packages/runtime/native/rig-git.zig") : "",
982
+ execDir ? resolve(execDir, "..", "..", "packages/runtime/native/rig-git.zig") : "",
983
+ execDir ? resolve(execDir, "..", "native", "rig-git.zig") : ""
984
+ ].filter(Boolean))];
985
+ }
986
+ function nativePackageBinaryCandidates(fromDir, fileName) {
987
+ const candidates = [];
988
+ let cursor = resolve(fromDir);
989
+ for (let index = 0;index < 8; index += 1) {
990
+ candidates.push(resolve(cursor, "native", `${process.platform}-${process.arch}`, fileName), resolve(cursor, "native", `${process.platform}-${process.arch}`, "bin", fileName), resolve(cursor, "native", fileName), resolve(cursor, "native", "bin", fileName));
991
+ const parent = dirname2(cursor);
992
+ if (parent === cursor)
993
+ break;
994
+ cursor = parent;
995
+ }
996
+ return candidates;
997
+ }
998
+ function rigGitBinaryCandidates() {
999
+ const execDir = process.execPath?.trim() ? dirname2(process.execPath.trim()) : "";
1000
+ const fileName = runtimeRigGitFileName();
1001
+ const explicit = process.env.RIG_NATIVE_GIT_BIN?.trim() || "";
1002
+ return [...new Set([
1003
+ explicit,
1004
+ ...nativePackageBinaryCandidates(import.meta.dir, fileName),
1005
+ execDir ? resolve(execDir, fileName) : "",
1006
+ execDir ? resolve(execDir, "..", fileName) : "",
1007
+ execDir ? resolve(execDir, "..", "bin", fileName) : "",
1008
+ sharedGitNativeOutputPath
1009
+ ].filter(Boolean))];
1010
+ }
1011
+ function resolveGitSourcePath() {
1012
+ for (const candidate of rigGitSourceCandidates()) {
1013
+ if (candidate && existsSync(candidate)) {
1014
+ return candidate;
1015
+ }
1016
+ }
1017
+ return null;
1018
+ }
1019
+ function resolveGitBinaryPath() {
1020
+ if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
1021
+ return null;
1022
+ }
1023
+ for (const candidate of rigGitBinaryCandidates()) {
1024
+ if (candidate && existsSync(candidate)) {
1025
+ return candidate;
1026
+ }
1027
+ }
1028
+ return null;
1029
+ }
1030
+ function preferredGitBinaryOutputPath() {
1031
+ const explicit = process.env.RIG_NATIVE_GIT_BIN?.trim() || "";
1032
+ return explicit || sharedGitNativeOutputPath;
1033
+ }
1034
+ function binarySupportsTrackerCommandsSync(binaryPath) {
1035
+ try {
1036
+ const probe = Bun.spawnSync([binaryPath, "fetch-ref", "."], {
1037
+ stdout: "pipe",
1038
+ stderr: "pipe"
1039
+ });
1040
+ const stdout = probe.stdout.toString().trim();
1041
+ const stderr = probe.stderr.toString().trim();
1042
+ if (stdout.includes('"error":"unknown command"')) {
1043
+ return false;
1044
+ }
1045
+ return probe.exitCode === 2 && stderr.includes(trackerCommandUsageProbe);
1046
+ } catch {
1047
+ return false;
1048
+ }
1049
+ }
1050
+ function nativeBuildManifestPath(outputPath) {
1051
+ return `${outputPath}.build-manifest.json`;
1052
+ }
1053
+ function hasMatchingNativeBuildManifestSync(manifestPath, buildKey) {
1054
+ if (!existsSync(manifestPath)) {
1055
+ return false;
1056
+ }
1057
+ try {
1058
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
1059
+ return manifest.version === 1 && manifest.buildKey === buildKey;
1060
+ } catch {
1061
+ return false;
1062
+ }
1063
+ }
1064
+ function sha256FileSync(path) {
1065
+ return createHash2("sha256").update(readFileSync(path)).digest("hex");
1066
+ }
1067
+ function ensureRigGitBinaryPathSync(outputPath = preferredGitBinaryOutputPath()) {
1068
+ if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
1069
+ throw new Error("Zig native git is disabled via RIG_DISABLE_ZIG_NATIVE=1");
1070
+ }
1071
+ const sourcePath = resolveGitSourcePath();
1072
+ if (!sourcePath) {
1073
+ const binaryPath = resolveGitBinaryPath();
1074
+ if (binaryPath) {
1075
+ return binaryPath;
1076
+ }
1077
+ throw new Error("rig-git.zig source file not found.");
1078
+ }
1079
+ const zigBinary = Bun.which("zig");
1080
+ if (!zigBinary) {
1081
+ throw new Error("zig is required to build native Rig git tools.");
1082
+ }
1083
+ mkdirSync2(dirname2(outputPath), { recursive: true });
1084
+ const sourceDigest = sha256FileSync(sourcePath);
1085
+ const buildKey = JSON.stringify({
1086
+ version: 1,
1087
+ zigBinary,
1088
+ platform: process.platform,
1089
+ arch: process.arch,
1090
+ sourcePath,
1091
+ sourceDigest
1092
+ });
1093
+ const manifestPath = nativeBuildManifestPath(outputPath);
1094
+ const needsBuild = !existsSync(outputPath) || !hasMatchingNativeBuildManifestSync(manifestPath, buildKey) || !binarySupportsTrackerCommandsSync(outputPath);
1095
+ if (!needsBuild) {
1096
+ chmodSync(outputPath, 493);
1097
+ return outputPath;
1098
+ }
1099
+ const tempOutputPath = temporaryGitBinaryOutputPath(outputPath);
1100
+ const build = Bun.spawnSync([
1101
+ zigBinary,
1102
+ "build-exe",
1103
+ sourcePath,
1104
+ "-O",
1105
+ "ReleaseFast",
1106
+ `-femit-bin=${tempOutputPath}`
1107
+ ], {
1108
+ cwd: dirname2(sourcePath),
1109
+ stdout: "pipe",
1110
+ stderr: "pipe"
1111
+ });
1112
+ if (build.exitCode !== 0 || !existsSync(tempOutputPath)) {
1113
+ const stderr = build.stderr.toString().trim();
1114
+ const stdout = build.stdout.toString().trim();
1115
+ const details = [stderr, stdout].filter(Boolean).join(`
1116
+ `);
1117
+ throw new Error(`Failed to build native Rig git tools: ${details || `zig exited with code ${build.exitCode}`}`);
1118
+ }
1119
+ chmodSync(tempOutputPath, 493);
1120
+ if (existsSync(outputPath) && hasMatchingNativeBuildManifestSync(manifestPath, buildKey)) {
1121
+ rmSync(tempOutputPath, { force: true });
1122
+ chmodSync(outputPath, 493);
1123
+ return outputPath;
1124
+ }
1125
+ publishGitBinary(tempOutputPath, outputPath);
1126
+ if (!binarySupportsTrackerCommandsSync(outputPath)) {
1127
+ rmSync(outputPath, { force: true });
1128
+ throw new Error("Failed to build native Rig git tools: tracker command probe failed");
1129
+ }
1130
+ writeFileSync(manifestPath, `${JSON.stringify({ version: 1, buildKey }, null, 2)}
1131
+ `, "utf8");
1132
+ return outputPath;
1133
+ }
1134
+ function runGitNative(command, args) {
1135
+ if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
1136
+ return { ok: false, error: "rig-git native disabled" };
1137
+ }
1138
+ const trackerCommand = command === "fetch-ref" || command === "read-blob-at-ref" || command === "write-tree-commit" || command === "push-ref-with-lease";
1139
+ let binaryPath = null;
1140
+ if (trackerCommand) {
1141
+ try {
1142
+ binaryPath = ensureRigGitBinaryPathSync(preferredGitBinaryOutputPath());
1143
+ } catch (error) {
1144
+ const message = error instanceof Error ? error.message : String(error);
1145
+ if (message.includes("rig-git.zig source file not found")) {
1146
+ return { ok: false, error: "rig-git binary not found" };
1147
+ }
1148
+ return { ok: false, error: message };
1149
+ }
1150
+ } else {
1151
+ const explicitBinaryPath = process.env.RIG_NATIVE_GIT_BIN?.trim() || "";
1152
+ binaryPath = explicitBinaryPath && existsSync(explicitBinaryPath) ? explicitBinaryPath : !explicitBinaryPath ? resolveGitBinaryPath() : null;
1153
+ if (!binaryPath) {
1154
+ try {
1155
+ binaryPath = ensureRigGitBinaryPathSync(preferredGitBinaryOutputPath());
1156
+ } catch (error) {
1157
+ const message = error instanceof Error ? error.message : String(error);
1158
+ if (message.includes("rig-git.zig source file not found")) {
1159
+ return { ok: false, error: "rig-git binary not found" };
1160
+ }
1161
+ return { ok: false, error: message };
1162
+ }
1163
+ }
1164
+ }
1165
+ try {
1166
+ const proc = Bun.spawnSync([binaryPath, command, ...args], {
1167
+ stdout: "pipe",
1168
+ stderr: "pipe",
1169
+ env: process.env
1170
+ });
1171
+ if (proc.exitCode !== 0) {
1172
+ const stdoutText = proc.stdout.toString().trim();
1173
+ if (stdoutText) {
1174
+ try {
1175
+ const parsed = JSON.parse(stdoutText);
1176
+ if (!parsed.ok) {
1177
+ return parsed;
1178
+ }
1179
+ } catch {}
1180
+ }
1181
+ const errText = proc.stderr.toString().trim() || `exit code ${proc.exitCode}`;
1182
+ return { ok: false, error: errText };
1183
+ }
1184
+ const output = proc.stdout.toString().trim();
1185
+ return JSON.parse(output);
1186
+ } catch (err) {
1187
+ return { ok: false, error: String(err) };
1188
+ }
1189
+ }
1190
+ function requireGitNative(command, args) {
1191
+ const result = runGitNative(command, args);
1192
+ if (!result.ok) {
1193
+ throw new Error(`rig-git ${command} failed: ${result.error}`);
1194
+ }
1195
+ return result;
1196
+ }
1197
+ function requireGitNativeString(command, args) {
1198
+ const result = requireGitNative(command, args);
1199
+ if ("value" in result && typeof result.value === "string") {
1200
+ return result.value;
1201
+ }
1202
+ throw new Error(`rig-git ${command} returned an unexpected result payload`);
1203
+ }
1204
+ function nativeFetchRef(repoPath, remote, branch) {
1205
+ return requireGitNativeString("fetch-ref", [repoPath, remote, branch]);
1206
+ }
1207
+ function nativeReadBlobBytesAtRef(repoPath, ref, path) {
1208
+ const requestDir = resolve(sharedGitNativeOutputDir, "reads", `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`);
1209
+ mkdirSync2(requestDir, { recursive: true });
1210
+ const outputPath = resolve(requestDir, "blob.bin");
1211
+ try {
1212
+ requireGitNative("read-blob-at-ref", [repoPath, ref, path, outputPath]);
1213
+ return readFileSync(outputPath);
1214
+ } finally {
1215
+ rmSync(requestDir, { recursive: true, force: true });
1216
+ }
1217
+ }
1218
+ function serializeTreeCommitUpdates(updates) {
1219
+ return updates.map((update) => {
1220
+ if (isTextTreeCommitUpdate(update)) {
1221
+ return { path: update.path, kind: "text", content: update.content };
1222
+ }
1223
+ if (!isAbsolute(update.sourceFilePath)) {
1224
+ throw new Error("tree commit binary updates require an absolute sourceFilePath");
1225
+ }
1226
+ return { path: update.path, kind: "file", sourceFilePath: update.sourceFilePath };
1227
+ });
1228
+ }
1229
+ function buildTreeCommitUpdatesJson(updates) {
1230
+ return `${JSON.stringify(serializeTreeCommitUpdates(updates), null, 2)}
1231
+ `;
1232
+ }
1233
+ function nativeWriteTreeCommit(repoPath, baseRef, updates, message) {
1234
+ const requestDir = resolve(sharedGitNativeOutputDir, "requests", `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`);
1235
+ mkdirSync2(requestDir, { recursive: true });
1236
+ const messagePath = resolve(requestDir, "message.txt");
1237
+ const updatesPath = resolve(requestDir, "updates.json");
1238
+ try {
1239
+ writeFileSync(messagePath, message, "utf8");
1240
+ writeFileSync(updatesPath, buildTreeCommitUpdatesJson(updates), "utf8");
1241
+ return requireGitNativeString("write-tree-commit", [repoPath, baseRef, messagePath, updatesPath]);
1242
+ } finally {
1243
+ rmSync(requestDir, { recursive: true, force: true });
1244
+ }
1245
+ }
1246
+ function nativePushRefWithLease(repoPath, localOid, remoteRef, expectedOldOid, remote = "origin") {
1247
+ return requireGitNativeString("push-ref-with-lease", [
1248
+ repoPath,
1249
+ localOid,
1250
+ remoteRef,
1251
+ expectedOldOid,
1252
+ remote
1253
+ ]);
1254
+ }
1255
+
1256
+ // packages/runtime/src/layout.ts
1257
+ import { existsSync as existsSync2 } from "fs";
1258
+ import { basename, dirname as dirname3, resolve as resolve2 } from "path";
1259
+ function resolveMonorepoRoot(projectRoot) {
1260
+ const normalizedProjectRoot = resolve2(projectRoot);
1261
+ const explicit = process.env.MONOREPO_ROOT?.trim();
1262
+ if (explicit) {
1263
+ const explicitRoot = resolve2(explicit);
1264
+ const explicitParent = dirname3(explicitRoot);
1265
+ if (basename(explicitParent) === ".worktrees") {
1266
+ const owner = dirname3(explicitParent);
1267
+ const ownerHasGit = existsSync2(resolve2(owner, ".git"));
1268
+ const ownerHasTaskConfig = existsSync2(resolve2(owner, ".rig", "task-config.json"));
1269
+ const ownerHasRigConfig = existsSync2(resolve2(owner, "rig.config.ts"));
1270
+ if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
1271
+ return owner;
1272
+ }
1273
+ throw new Error(`MONOREPO_ROOT points to worktree ${explicitRoot}, but the owner checkout is incomplete at ${owner}.`);
1274
+ }
1275
+ if (!existsSync2(resolve2(explicitRoot, ".git"))) {
1276
+ throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but no git checkout was found there.`);
1277
+ }
1278
+ const hasTaskConfig = existsSync2(resolve2(explicitRoot, ".rig", "task-config.json"));
1279
+ const hasRigConfig = existsSync2(resolve2(explicitRoot, "rig.config.ts"));
1280
+ if (!hasTaskConfig && !hasRigConfig) {
1281
+ throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but neither .rig/task-config.json nor rig.config.ts exists there.`);
1282
+ }
1283
+ return explicitRoot;
1284
+ }
1285
+ const projectParent = dirname3(normalizedProjectRoot);
1286
+ if (basename(projectParent) === ".worktrees") {
1287
+ const worktreeOwner = dirname3(projectParent);
1288
+ const ownerHasGit = existsSync2(resolve2(worktreeOwner, ".git"));
1289
+ const ownerHasTaskConfig = existsSync2(resolve2(worktreeOwner, ".rig", "task-config.json"));
1290
+ const ownerHasRigConfig = existsSync2(resolve2(worktreeOwner, "rig.config.ts"));
1291
+ if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
1292
+ return worktreeOwner;
1293
+ }
1294
+ }
1295
+ return normalizedProjectRoot;
1296
+ }
1297
+
1298
+ // packages/runtime/src/control-plane/native/runtime-native.ts
1299
+ import { dlopen, ptr, suffix, toBuffer } from "bun:ffi";
1300
+ import { copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, renameSync as renameSync2, rmSync as rmSync2, statSync } from "fs";
1301
+ import { tmpdir as tmpdir2 } from "os";
1302
+ import { dirname as dirname4, resolve as resolve3 } from "path";
1303
+ var sharedNativeRuntimeOutputDir = resolve3(tmpdir2(), "rig-native");
1304
+ var sharedNativeRuntimeOutputPath = resolve3(sharedNativeRuntimeOutputDir, `runtime-native-${process.platform}-${process.arch}.${suffix}`);
1305
+ var colocatedNativeRuntimeFileName = `runtime-native.${suffix}`;
1306
+ var nativeRuntimeLibrary = await loadNativeRuntimeLibrary();
1307
+ async function ensureNativeRuntimeLibraryPath(outputPath = sharedNativeRuntimeOutputPath, options = {}) {
1308
+ if (await buildNativeRuntimeLibrary(outputPath, options)) {
1309
+ return outputPath;
1310
+ }
1311
+ return !options.force && existsSync3(outputPath) ? outputPath : null;
1312
+ }
1313
+ async function loadNativeRuntimeLibrary() {
1314
+ if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
1315
+ return null;
1316
+ }
1317
+ for (const candidate of nativeRuntimeLibraryCandidates()) {
1318
+ if (!candidate || !existsSync3(candidate)) {
1319
+ continue;
1320
+ }
1321
+ const loaded = tryDlopenNativeRuntimeLibrary(candidate);
1322
+ if (loaded) {
1323
+ return loaded;
1324
+ }
1325
+ }
1326
+ const builtLibraryPath = await ensureNativeRuntimeLibraryPath(sharedNativeRuntimeOutputPath, { force: true });
1327
+ if (!builtLibraryPath) {
1328
+ return null;
1329
+ }
1330
+ return tryDlopenNativeRuntimeLibrary(builtLibraryPath);
1331
+ }
1332
+ function nativePackageLibraryCandidates(fromDir, names) {
1333
+ const candidates = [];
1334
+ let cursor = resolve3(fromDir);
1335
+ for (let index = 0;index < 8; index += 1) {
1336
+ for (const name of names) {
1337
+ candidates.push(resolve3(cursor, "native", `${process.platform}-${process.arch}`, name), resolve3(cursor, "native", `${process.platform}-${process.arch}`, "lib", name), resolve3(cursor, "native", name), resolve3(cursor, "native", "lib", name));
1338
+ }
1339
+ const parent = dirname4(cursor);
1340
+ if (parent === cursor)
1341
+ break;
1342
+ cursor = parent;
1343
+ }
1344
+ return candidates;
1345
+ }
1346
+ function nativeRuntimeLibraryCandidates() {
1347
+ const explicit = process.env.RIG_NATIVE_RUNTIME_LIB?.trim() || "";
1348
+ const execDir = process.execPath?.trim() ? dirname4(process.execPath.trim()) : "";
1349
+ const platformSpecific = `runtime-native-${process.platform}-${process.arch}.${suffix}`;
1350
+ return [...new Set([
1351
+ explicit,
1352
+ ...nativePackageLibraryCandidates(import.meta.dir, [colocatedNativeRuntimeFileName, platformSpecific]),
1353
+ execDir ? resolve3(execDir, colocatedNativeRuntimeFileName) : "",
1354
+ execDir ? resolve3(execDir, platformSpecific) : "",
1355
+ execDir ? resolve3(execDir, "..", colocatedNativeRuntimeFileName) : "",
1356
+ execDir ? resolve3(execDir, "..", platformSpecific) : "",
1357
+ execDir ? resolve3(execDir, "lib", colocatedNativeRuntimeFileName) : "",
1358
+ execDir ? resolve3(execDir, "..", "lib", colocatedNativeRuntimeFileName) : "",
1359
+ sharedNativeRuntimeOutputPath
1360
+ ].filter(Boolean))];
1361
+ }
1362
+ function resolveNativeRuntimeSourcePath() {
1363
+ const explicit = process.env.RIG_NATIVE_RUNTIME_SOURCE?.trim();
1364
+ if (explicit && existsSync3(explicit)) {
1365
+ return explicit;
1366
+ }
1367
+ const bundled = resolve3(import.meta.dir, "../../../native/snapshot.zig");
1368
+ return existsSync3(bundled) ? bundled : null;
1369
+ }
1370
+ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
1371
+ if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
1372
+ return false;
1373
+ }
1374
+ const zigBinary = Bun.which("zig");
1375
+ const sourcePath = resolveNativeRuntimeSourcePath();
1376
+ if (!zigBinary || !sourcePath) {
1377
+ return false;
1378
+ }
1379
+ const tempOutputPath = `${outputPath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
1380
+ try {
1381
+ mkdirSync3(dirname4(outputPath), { recursive: true });
1382
+ const needsBuild = options.force === true || !existsSync3(outputPath) || statSync(sourcePath).mtimeMs > statSync(outputPath).mtimeMs;
1383
+ if (!needsBuild) {
1384
+ return true;
1385
+ }
1386
+ const build = Bun.spawn([
1387
+ zigBinary,
1388
+ "build-lib",
1389
+ sourcePath,
1390
+ "-dynamic",
1391
+ "-O",
1392
+ "ReleaseFast",
1393
+ `-femit-bin=${tempOutputPath}`
1394
+ ], {
1395
+ cwd: import.meta.dir,
1396
+ stdout: "pipe",
1397
+ stderr: "pipe"
1398
+ });
1399
+ const exitCode = await build.exited;
1400
+ if (exitCode !== 0 || !existsSync3(tempOutputPath)) {
1401
+ rmSync2(tempOutputPath, { force: true });
1402
+ return false;
1403
+ }
1404
+ renameSync2(tempOutputPath, outputPath);
1405
+ return true;
1406
+ } catch {
1407
+ rmSync2(tempOutputPath, { force: true });
1408
+ return false;
1409
+ }
1410
+ }
1411
+ function tryDlopenNativeRuntimeLibrary(outputPath) {
1412
+ try {
1413
+ return dlopen(outputPath, {
1414
+ rig_scope_match: {
1415
+ args: ["ptr", "ptr"],
1416
+ returns: "u8"
1417
+ },
1418
+ snapshot_capture: {
1419
+ args: ["ptr", "u64", "ptr", "u64"],
1420
+ returns: "ptr"
1421
+ },
1422
+ snapshot_delta: {
1423
+ args: ["ptr", "ptr"],
1424
+ returns: "ptr"
1425
+ },
1426
+ snapshot_store_delta: {
1427
+ args: ["ptr", "ptr", "ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64"],
1428
+ returns: "ptr"
1429
+ },
1430
+ snapshot_inspect_delta: {
1431
+ args: ["ptr", "u64"],
1432
+ returns: "ptr"
1433
+ },
1434
+ snapshot_apply_delta: {
1435
+ args: ["ptr", "u64", "ptr", "u64"],
1436
+ returns: "ptr"
1437
+ },
1438
+ snapshot_release: {
1439
+ args: ["ptr"],
1440
+ returns: "void"
1441
+ },
1442
+ runtime_hash_file: {
1443
+ args: ["ptr", "u64"],
1444
+ returns: "ptr"
1445
+ },
1446
+ runtime_hash_tree: {
1447
+ args: ["ptr", "u64"],
1448
+ returns: "ptr"
1449
+ },
1450
+ runtime_prepare_paths: {
1451
+ args: ["ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64"],
1452
+ returns: "ptr"
1453
+ },
1454
+ runtime_link_dependency_layer: {
1455
+ args: ["ptr", "u64", "ptr", "u64"],
1456
+ returns: "ptr"
1457
+ },
1458
+ runtime_scan_worktrees: {
1459
+ args: ["ptr", "u64"],
1460
+ returns: "ptr"
1461
+ }
1462
+ });
1463
+ } catch {
1464
+ return null;
1465
+ }
1466
+ }
1467
+
1468
+ // packages/runtime/src/control-plane/native/utils.ts
1469
+ function resolveMonorepoRoot2(projectRoot) {
1470
+ return resolveMonorepoRoot(projectRoot);
1471
+ }
1472
+ var scopeRegexCache = new Map;
1473
+
1474
+ // packages/runtime/src/control-plane/memory-sync/read.ts
1475
+ var CANONICAL_MEMORY_DB_PATH = "rig/memory/project-memory.db";
1476
+ var DEFAULT_READ_DEPS = {
1477
+ fetchRef: nativeFetchRef,
1478
+ readBlobBytesAtRef: nativeReadBlobBytesAtRef,
1479
+ openMemoryDb,
1480
+ makeTempDir: () => mkdtempSync(join(tmpdir3(), "memory-sync-read-")),
1481
+ removeDir: (path) => rmSync3(path, { recursive: true, force: true })
1482
+ };
1483
+ function isMissingCanonicalMemoryBlobError(error) {
1484
+ const message = error instanceof Error ? error.message : String(error);
1485
+ return message.includes(`path '${CANONICAL_MEMORY_DB_PATH}' does not exist in`) || message.includes(`path '${CANONICAL_MEMORY_DB_PATH}' exists on disk, but not in`) || message.includes(`pathspec '${CANONICAL_MEMORY_DB_PATH}' did not match any file(s) known to git`);
1486
+ }
1487
+ async function validateReadableDatabase(dbPath, open) {
1488
+ const db = await open(dbPath);
1489
+ await db.close();
1490
+ }
1491
+ async function readCanonicalMemoryDb(projectRoot, deps = {}) {
1492
+ const readDeps = { ...DEFAULT_READ_DEPS, ...deps };
1493
+ const repoPath = resolveMonorepoRoot2(projectRoot);
1494
+ const baseOid = readDeps.fetchRef(repoPath, "origin", "main");
1495
+ const tempDir = readDeps.makeTempDir();
1496
+ const dbPath = join(tempDir, "project-memory.db");
1497
+ let createdFresh = false;
1498
+ try {
1499
+ try {
1500
+ const bytes = readDeps.readBlobBytesAtRef(repoPath, baseOid, CANONICAL_MEMORY_DB_PATH);
1501
+ writeFileSync2(dbPath, bytes);
1502
+ } catch (error) {
1503
+ if (!isMissingCanonicalMemoryBlobError(error)) {
1504
+ throw error;
1505
+ }
1506
+ const db = await readDeps.openMemoryDb(dbPath);
1507
+ await db.close();
1508
+ createdFresh = true;
1509
+ }
1510
+ await validateReadableDatabase(dbPath, readDeps.openMemoryDb);
1511
+ return {
1512
+ repoPath,
1513
+ baseOid,
1514
+ dbPath,
1515
+ createdFresh,
1516
+ async cleanup() {
1517
+ readDeps.removeDir(tempDir);
1518
+ }
1519
+ };
1520
+ } catch (error) {
1521
+ readDeps.removeDir(tempDir);
1522
+ throw error;
1523
+ }
1524
+ }
1525
+ // packages/runtime/src/control-plane/memory-sync/write.ts
1526
+ var CANONICAL_MEMORY_DB_PATH2 = "rig/memory/project-memory.db";
1527
+ var MAX_PROMOTION_ATTEMPTS = 2;
1528
+ var DEFAULT_WRITE_DEPS = {
1529
+ readCanonicalMemoryDb,
1530
+ openMemoryDb,
1531
+ applyMemoryEvent,
1532
+ hasMemoryEvent,
1533
+ embedChangedMemoryItems,
1534
+ writeTreeCommit: nativeWriteTreeCommit,
1535
+ pushRefWithLease: nativePushRefWithLease
1536
+ };
1537
+ async function promoteCanonicalMemoryEvent(projectRoot, input, deps = {}) {
1538
+ const writeDeps = { ...DEFAULT_WRITE_DEPS, ...deps };
1539
+ let lastError;
1540
+ for (let attempt = 0;attempt < MAX_PROMOTION_ATTEMPTS; attempt += 1) {
1541
+ const snapshot = await writeDeps.readCanonicalMemoryDb(projectRoot);
1542
+ try {
1543
+ const db = await writeDeps.openMemoryDb(snapshot.dbPath);
1544
+ try {
1545
+ if (await writeDeps.hasMemoryEvent(db, input.event.eventId)) {
1546
+ return {
1547
+ outcome: "applied",
1548
+ baseOid: snapshot.baseOid,
1549
+ commitOid: snapshot.baseOid
1550
+ };
1551
+ }
1552
+ await writeDeps.applyMemoryEvent(db, input.event);
1553
+ const embedder = input.embedder ?? (memoryEventRequiresEmbedding(input.event) ? maybeCreateConfiguredMemoryEmbedder() : null);
1554
+ if (embedder) {
1555
+ await writeDeps.embedChangedMemoryItems(db, input.event, embedder);
1556
+ }
1557
+ } finally {
1558
+ await db.close();
1559
+ }
1560
+ const updates = [
1561
+ {
1562
+ path: CANONICAL_MEMORY_DB_PATH2,
1563
+ sourceFilePath: snapshot.dbPath
1564
+ }
1565
+ ];
1566
+ const commitOid = writeDeps.writeTreeCommit(snapshot.repoPath, snapshot.baseOid, updates, input.message ?? `chore(memory): ${input.event.eventType} ${input.event.canonicalKey}`);
1567
+ try {
1568
+ await Promise.resolve(writeDeps.pushRefWithLease(snapshot.repoPath, commitOid, "refs/heads/main", snapshot.baseOid));
1569
+ return {
1570
+ outcome: "applied",
1571
+ baseOid: snapshot.baseOid,
1572
+ commitOid
1573
+ };
1574
+ } catch (error) {
1575
+ lastError = error;
1576
+ }
1577
+ } finally {
1578
+ await snapshot.cleanup();
1579
+ }
1580
+ }
1581
+ throw lastError instanceof Error ? lastError : new Error(String(lastError ?? "memory promotion failed"));
1582
+ }
1583
+ // packages/runtime/src/control-plane/runtime/context.ts
1584
+ var DEFAULT_RUNTIME_MEMORY_RETRIEVAL = {
1585
+ topK: 5,
1586
+ lexicalWeight: 0.35,
1587
+ vectorWeight: 0.45,
1588
+ recencyWeight: 0.1,
1589
+ confidenceWeight: 0.1
1590
+ };
1591
+
1592
+ // packages/runtime/src/control-plane/memory-sync/query.ts
1593
+ var DEFAULT_RESULT_LIMIT = DEFAULT_RUNTIME_MEMORY_RETRIEVAL.topK;
1594
+ var DAY_MS = 24 * 60 * 60 * 1000;
1595
+ var MIN_VECTOR_MATCH_SCORE = 0.2;
1596
+ function tokenize(text) {
1597
+ return (text.toLowerCase().match(/[a-z0-9_./:-]+/g) ?? []).flatMap((token) => {
1598
+ const split = token.split(/[./:_-]+/).filter(Boolean);
1599
+ return split.length > 0 ? [token, ...split] : [token];
1600
+ });
1601
+ }
1602
+ function lexicalScore(query, item) {
1603
+ const queryTokens = [...new Set(tokenize(query))];
1604
+ if (queryTokens.length === 0) {
1605
+ return 0;
1606
+ }
1607
+ const haystackTokens = new Set(tokenize(item.summary));
1608
+ let matched = 0;
1609
+ for (const token of queryTokens) {
1610
+ if (haystackTokens.has(token)) {
1611
+ matched += 1;
1612
+ }
1613
+ }
1614
+ return matched / queryTokens.length;
1615
+ }
1616
+ function cosineSimilarity(left, right) {
1617
+ if (left.length === 0 || left.length !== right.length) {
1618
+ return 0;
1619
+ }
1620
+ let dot = 0;
1621
+ let leftNorm = 0;
1622
+ let rightNorm = 0;
1623
+ for (let index = 0;index < left.length; index += 1) {
1624
+ const l = left[index] ?? 0;
1625
+ const r = right[index] ?? 0;
1626
+ dot += l * r;
1627
+ leftNorm += l * l;
1628
+ rightNorm += r * r;
1629
+ }
1630
+ if (leftNorm === 0 || rightNorm === 0) {
1631
+ return 0;
1632
+ }
1633
+ return dot / Math.sqrt(leftNorm * rightNorm);
1634
+ }
1635
+ function recencyScore(item, now) {
1636
+ const updatedAt = Date.parse(item.updatedAt);
1637
+ if (Number.isNaN(updatedAt)) {
1638
+ return 0;
1639
+ }
1640
+ const ageMs = Math.max(0, now.getTime() - updatedAt);
1641
+ return 1 / (1 + ageMs / DAY_MS);
1642
+ }
1643
+ async function maybeEmbedQuery(items, query, embedder) {
1644
+ if (!items.some((item) => Array.isArray(item.embedding) && item.embedding.length > 0)) {
1645
+ return null;
1646
+ }
1647
+ try {
1648
+ const resolvedEmbedder = embedder ?? createConfiguredMemoryEmbedder();
1649
+ const [queryEmbedding] = await resolvedEmbedder.embed([query]);
1650
+ return queryEmbedding ?? null;
1651
+ } catch {
1652
+ return null;
1653
+ }
1654
+ }
1655
+ async function queryRelevantMemory(db, input) {
1656
+ const retrieval = input.retrieval ?? DEFAULT_RUNTIME_MEMORY_RETRIEVAL;
1657
+ const now = input.now instanceof Date ? input.now : new Date(input.now ?? Date.now());
1658
+ const items = await listActiveMemoryItems(db);
1659
+ if (items.length === 0) {
1660
+ return [];
1661
+ }
1662
+ const queryEmbedding = await maybeEmbedQuery(items, input.query, input.embedder);
1663
+ const scored = items.map((item) => {
1664
+ const lexical = lexicalScore(input.query, item);
1665
+ const vector = queryEmbedding && item.embedding ? cosineSimilarity(queryEmbedding, item.embedding) : 0;
1666
+ const recency = recencyScore(item, now);
1667
+ const score = retrieval.lexicalWeight * lexical + retrieval.vectorWeight * vector + retrieval.recencyWeight * recency + retrieval.confidenceWeight * item.confidence;
1668
+ return {
1669
+ canonicalKey: item.canonicalKey,
1670
+ summary: item.summary,
1671
+ kind: item.kind,
1672
+ category: item.category,
1673
+ confidence: item.confidence,
1674
+ updatedAt: item.updatedAt,
1675
+ score,
1676
+ lexicalScore: lexical,
1677
+ vectorScore: vector,
1678
+ recencyScore: recency
1679
+ };
1680
+ }).filter((item) => item.lexicalScore > 0 || item.vectorScore >= MIN_VECTOR_MATCH_SCORE).sort((left, right) => right.score - left.score || Date.parse(right.updatedAt) - Date.parse(left.updatedAt) || right.confidence - left.confidence || left.canonicalKey.localeCompare(right.canonicalKey));
1681
+ return scored.slice(0, input.limit ?? retrieval.topK ?? DEFAULT_RESULT_LIMIT);
1682
+ }
1683
+ function formatMemoryQueryResults(results) {
1684
+ if (results.length === 0) {
1685
+ return "No shared memories matched.";
1686
+ }
1687
+ return results.map((result, index) => `${index + 1}. [${result.canonicalKey}] ${result.summary} (confidence ${result.confidence.toFixed(2)})`).join(`
1688
+ `);
1689
+ }
1690
+ // packages/runtime/src/control-plane/memory-sync/cli.ts
1691
+ import { existsSync as existsSync4 } from "fs";
1692
+ import { randomUUID } from "crypto";
1693
+ function takeOption(args, option) {
1694
+ const rest = [];
1695
+ let value;
1696
+ for (let index = 0;index < args.length; index += 1) {
1697
+ const current = args[index];
1698
+ if (current === option) {
1699
+ if (value !== undefined) {
1700
+ throw new Error(`Duplicate option ${option}`);
1701
+ }
1702
+ const next = args[index + 1];
1703
+ if (!next || next.startsWith("-")) {
1704
+ throw new Error(`Missing value for ${option}`);
1705
+ }
1706
+ value = next;
1707
+ index += 1;
1708
+ continue;
1709
+ }
1710
+ if (current !== undefined) {
1711
+ rest.push(current);
1712
+ }
1713
+ }
1714
+ return { value, rest };
1715
+ }
1716
+ function usage(verb) {
1717
+ switch (verb) {
1718
+ case "observe":
1719
+ return "Usage: rig-agent memory observe <canonical-key> <summary> [--kind <kind>] [--category <category>] [--confidence <number>]";
1720
+ case "supersede":
1721
+ return "Usage: rig-agent memory supersede <canonical-key> --replacement <replacement-key>";
1722
+ case "retract":
1723
+ return "Usage: rig-agent memory retract <canonical-key>";
1724
+ case "reinforce":
1725
+ return "Usage: rig-agent memory reinforce <canonical-key> --confidence <number>";
1726
+ case "recall":
1727
+ return "Usage: rig-agent memory recall [query]";
1728
+ default:
1729
+ return [
1730
+ "Usage:",
1731
+ " rig-agent memory observe <canonical-key> <summary> [--kind <kind>] [--category <category>] [--confidence <number>]",
1732
+ " rig-agent memory supersede <canonical-key> --replacement <replacement-key>",
1733
+ " rig-agent memory retract <canonical-key>",
1734
+ " rig-agent memory reinforce <canonical-key> --confidence <number>",
1735
+ " rig-agent memory recall [query]"
1736
+ ].join(`
1737
+ `);
1738
+ }
1739
+ }
1740
+ function parseConfidence(raw, fallback) {
1741
+ if (!raw) {
1742
+ return fallback;
1743
+ }
1744
+ const value = Number(raw);
1745
+ if (!Number.isFinite(value) || value < 0 || value > 1) {
1746
+ throw new Error("Confidence must be a number between 0 and 1.");
1747
+ }
1748
+ return value;
1749
+ }
1750
+ function currentBranch(projectRoot) {
1751
+ const proc = Bun.spawnSync(["git", "rev-parse", "--abbrev-ref", "HEAD"], {
1752
+ cwd: projectRoot,
1753
+ stdout: "pipe",
1754
+ stderr: "pipe"
1755
+ });
1756
+ return proc.exitCode === 0 ? proc.stdout.toString().trim() || "main" : "main";
1757
+ }
1758
+ function requireRuntimeMemoryContext(runtimeContext) {
1759
+ if (!runtimeContext?.memory) {
1760
+ throw new Error("Shared memory is unavailable without a hydrated runtime-context.json.");
1761
+ }
1762
+ return runtimeContext.memory;
1763
+ }
1764
+ async function ensureRuntimeMemoryUsable(runtimeContext) {
1765
+ const memory = requireRuntimeMemoryContext(runtimeContext);
1766
+ if (!existsSync4(memory.hydratedPath)) {
1767
+ throw new Error(`Shared memory database is missing: ${memory.hydratedPath}`);
1768
+ }
1769
+ const db = await openMemoryDb(memory.hydratedPath);
1770
+ await db.close();
1771
+ }
1772
+ async function syncRuntimeMemory(runtimeContext, event) {
1773
+ const memory = requireRuntimeMemoryContext(runtimeContext);
1774
+ const db = await openMemoryDb(memory.hydratedPath);
1775
+ try {
1776
+ if (await hasMemoryEvent(db, event.eventId)) {
1777
+ return;
1778
+ }
1779
+ await applyMemoryEvent(db, event);
1780
+ if (memoryEventRequiresEmbedding(event)) {
1781
+ const embedder = maybeCreateConfiguredMemoryEmbedder();
1782
+ if (!embedder) {
1783
+ return;
1784
+ }
1785
+ await embedChangedMemoryItems(db, event, embedder);
1786
+ }
1787
+ } finally {
1788
+ await db.close();
1789
+ }
1790
+ }
1791
+ async function lookupRelevantMemory(runtimeContext, query) {
1792
+ const memory = requireRuntimeMemoryContext(runtimeContext);
1793
+ const db = await openMemoryDb(memory.hydratedPath);
1794
+ try {
1795
+ return await queryRelevantMemory(db, {
1796
+ query,
1797
+ limit: memory.retrieval.topK,
1798
+ retrieval: memory.retrieval
1799
+ });
1800
+ } finally {
1801
+ await db.close();
1802
+ }
1803
+ }
1804
+ async function memorySummaryForKey(runtimeContext, canonicalKey) {
1805
+ const memory = requireRuntimeMemoryContext(runtimeContext);
1806
+ const db = await openMemoryDb(memory.hydratedPath);
1807
+ try {
1808
+ const item = await getMemoryItemByKey(db, canonicalKey);
1809
+ return item?.summary ?? null;
1810
+ } finally {
1811
+ await db.close();
1812
+ }
1813
+ }
1814
+ function formatRelatedMemorySection(results) {
1815
+ return formatMemoryQueryResults(results);
1816
+ }
1817
+ function defaultRecallQuery(options) {
1818
+ const role = options.runtimeContext?.role?.trim();
1819
+ const scopeTerms = (options.runtimeContext?.scopes ?? []).flatMap((scope) => scope.split("/").slice(-3)).map((term) => term.trim()).filter(Boolean);
1820
+ const validationTerms = (options.runtimeContext?.validation ?? []).map((command) => command.split(/\s+/)[0]?.trim() ?? "").filter(Boolean);
1821
+ const parts = [...new Set([role, ...scopeTerms, ...validationTerms].filter(Boolean))];
1822
+ return parts.join(" ").trim() || options.taskId;
1823
+ }
1824
+ function assertNoFlagTokens(args, usageText) {
1825
+ if (args.some((arg) => arg.startsWith("-"))) {
1826
+ throw new Error(usageText);
1827
+ }
1828
+ }
1829
+ function baseEventFields(options, branch) {
1830
+ return {
1831
+ eventId: `memory-${randomUUID()}`,
1832
+ sourceRunId: options.runtimeContext?.runtimeId || options.taskId,
1833
+ sourceTaskId: options.taskId,
1834
+ branch,
1835
+ createdAt: new Date().toISOString()
1836
+ };
1837
+ }
1838
+ function requestedPayload(verb, mutationKind, canonicalKey, extra) {
1839
+ return {
1840
+ command: verb,
1841
+ mutationKind,
1842
+ canonicalKey,
1843
+ ...extra
1844
+ };
1845
+ }
1846
+ function mutationKindForVerb(verb) {
1847
+ switch (verb) {
1848
+ case "observe":
1849
+ return "observed";
1850
+ case "supersede":
1851
+ return "superseded";
1852
+ case "retract":
1853
+ return "retracted";
1854
+ case "reinforce":
1855
+ return "reinforced";
1856
+ case "recall":
1857
+ return "retrieved";
1858
+ }
1859
+ }
1860
+ var DEFAULT_EXECUTE_MEMORY_COMMAND_DEPS = {
1861
+ currentBranch,
1862
+ ensureRuntimeMemoryUsable,
1863
+ syncRuntimeMemory,
1864
+ lookupRelevantMemory,
1865
+ memorySummaryForKey,
1866
+ promoteCanonicalMemoryEvent
1867
+ };
1868
+ async function executeMemoryCommand(options, deps = {}) {
1869
+ const [verbRaw, ...rest] = options.args;
1870
+ const verb = verbRaw;
1871
+ if (!verb || !["observe", "supersede", "retract", "reinforce", "recall"].includes(verb)) {
1872
+ throw new Error(usage());
1873
+ }
1874
+ const commandDeps = { ...DEFAULT_EXECUTE_MEMORY_COMMAND_DEPS, ...deps };
1875
+ let requested;
1876
+ try {
1877
+ switch (verb) {
1878
+ case "observe": {
1879
+ const kind = takeOption(rest, "--kind");
1880
+ const category = takeOption(kind.rest, "--category");
1881
+ const confidence = takeOption(category.rest, "--confidence");
1882
+ assertNoFlagTokens(confidence.rest, usage("observe"));
1883
+ const [canonicalKey, summary] = confidence.rest;
1884
+ if (!canonicalKey || !summary || confidence.rest.length !== 2) {
1885
+ throw new Error(usage("observe"));
1886
+ }
1887
+ await commandDeps.ensureRuntimeMemoryUsable(options.runtimeContext);
1888
+ const event = {
1889
+ ...baseEventFields(options, commandDeps.currentBranch(options.projectRoot)),
1890
+ eventType: "observed",
1891
+ canonicalKey,
1892
+ summary,
1893
+ kind: kind.value || "fact",
1894
+ category: category.value ?? null,
1895
+ confidence: parseConfidence(confidence.value, 0.7)
1896
+ };
1897
+ requested = requestedPayload("observe", "observed", canonicalKey);
1898
+ await options.eventBus?.emit("memory.command.requested", requested);
1899
+ await commandDeps.promoteCanonicalMemoryEvent(options.projectRoot, { event });
1900
+ await commandDeps.syncRuntimeMemory(options.runtimeContext, event);
1901
+ const relatedResults = await commandDeps.lookupRelevantMemory(options.runtimeContext, summary);
1902
+ const output = [`Observed memory ${canonicalKey}.`, "", "Related shared memories:", formatRelatedMemorySection(relatedResults)].join(`
1903
+ `);
1904
+ await options.eventBus?.emit("memory.command.applied", {
1905
+ ...requested,
1906
+ relatedCanonicalKeys: relatedResults.map((result) => result.canonicalKey)
1907
+ });
1908
+ return output;
1909
+ }
1910
+ case "supersede": {
1911
+ const replacement = takeOption(rest, "--replacement");
1912
+ assertNoFlagTokens(replacement.rest, usage("supersede"));
1913
+ const canonicalKey = replacement.rest[0];
1914
+ if (!canonicalKey || !replacement.value || replacement.rest.length !== 1) {
1915
+ throw new Error(usage("supersede"));
1916
+ }
1917
+ await commandDeps.ensureRuntimeMemoryUsable(options.runtimeContext);
1918
+ const event = {
1919
+ ...baseEventFields(options, commandDeps.currentBranch(options.projectRoot)),
1920
+ eventType: "superseded",
1921
+ canonicalKey,
1922
+ replacementCanonicalKey: replacement.value
1923
+ };
1924
+ requested = requestedPayload("supersede", "superseded", canonicalKey, { replacementCanonicalKey: replacement.value });
1925
+ await options.eventBus?.emit("memory.command.requested", requested);
1926
+ const relatedQuery = await commandDeps.memorySummaryForKey(options.runtimeContext, replacement.value) ?? replacement.value;
1927
+ await commandDeps.promoteCanonicalMemoryEvent(options.projectRoot, { event });
1928
+ await commandDeps.syncRuntimeMemory(options.runtimeContext, event);
1929
+ const relatedResults = await commandDeps.lookupRelevantMemory(options.runtimeContext, relatedQuery);
1930
+ const output = [`Superseded memory ${canonicalKey}.`, "", "Related shared memories:", formatRelatedMemorySection(relatedResults)].join(`
1931
+ `);
1932
+ await options.eventBus?.emit("memory.command.applied", {
1933
+ ...requested,
1934
+ relatedCanonicalKeys: relatedResults.map((result) => result.canonicalKey)
1935
+ });
1936
+ return output;
1937
+ }
1938
+ case "retract": {
1939
+ const canonicalKey = rest[0];
1940
+ assertNoFlagTokens(rest, usage("retract"));
1941
+ if (!canonicalKey || rest.length !== 1) {
1942
+ throw new Error(usage("retract"));
1943
+ }
1944
+ await commandDeps.ensureRuntimeMemoryUsable(options.runtimeContext);
1945
+ const event = {
1946
+ ...baseEventFields(options, commandDeps.currentBranch(options.projectRoot)),
1947
+ eventType: "retracted",
1948
+ canonicalKey
1949
+ };
1950
+ requested = requestedPayload("retract", "retracted", canonicalKey);
1951
+ await options.eventBus?.emit("memory.command.requested", requested);
1952
+ const relatedQuery = await commandDeps.memorySummaryForKey(options.runtimeContext, canonicalKey) ?? canonicalKey;
1953
+ await commandDeps.promoteCanonicalMemoryEvent(options.projectRoot, { event });
1954
+ await commandDeps.syncRuntimeMemory(options.runtimeContext, event);
1955
+ const relatedResults = await commandDeps.lookupRelevantMemory(options.runtimeContext, relatedQuery);
1956
+ const output = [`Retracted memory ${canonicalKey}.`, "", "Related shared memories:", formatRelatedMemorySection(relatedResults)].join(`
1957
+ `);
1958
+ await options.eventBus?.emit("memory.command.applied", {
1959
+ ...requested,
1960
+ relatedCanonicalKeys: relatedResults.map((result) => result.canonicalKey)
1961
+ });
1962
+ return output;
1963
+ }
1964
+ case "reinforce": {
1965
+ const confidence = takeOption(rest, "--confidence");
1966
+ assertNoFlagTokens(confidence.rest, usage("reinforce"));
1967
+ const canonicalKey = confidence.rest[0];
1968
+ if (!canonicalKey || !confidence.value || confidence.rest.length !== 1) {
1969
+ throw new Error(usage("reinforce"));
1970
+ }
1971
+ await commandDeps.ensureRuntimeMemoryUsable(options.runtimeContext);
1972
+ const event = {
1973
+ ...baseEventFields(options, commandDeps.currentBranch(options.projectRoot)),
1974
+ eventType: "reinforced",
1975
+ canonicalKey,
1976
+ confidence: parseConfidence(confidence.value, 0.7)
1977
+ };
1978
+ requested = requestedPayload("reinforce", "reinforced", canonicalKey);
1979
+ await options.eventBus?.emit("memory.command.requested", requested);
1980
+ const relatedQuery = await commandDeps.memorySummaryForKey(options.runtimeContext, canonicalKey) ?? canonicalKey;
1981
+ await commandDeps.promoteCanonicalMemoryEvent(options.projectRoot, { event });
1982
+ await commandDeps.syncRuntimeMemory(options.runtimeContext, event);
1983
+ const relatedResults = await commandDeps.lookupRelevantMemory(options.runtimeContext, relatedQuery);
1984
+ const output = [`Reinforced memory ${canonicalKey}.`, "", "Related shared memories:", formatRelatedMemorySection(relatedResults)].join(`
1985
+ `);
1986
+ await options.eventBus?.emit("memory.command.applied", {
1987
+ ...requested,
1988
+ relatedCanonicalKeys: relatedResults.map((result) => result.canonicalKey)
1989
+ });
1990
+ return output;
1991
+ }
1992
+ case "recall": {
1993
+ if (rest.some((arg) => arg.startsWith("--"))) {
1994
+ throw new Error(usage("recall"));
1995
+ }
1996
+ const query = rest.join(" ").trim() || defaultRecallQuery(options);
1997
+ await commandDeps.ensureRuntimeMemoryUsable(options.runtimeContext);
1998
+ requested = requestedPayload("recall", "retrieved", undefined, { query });
1999
+ await options.eventBus?.emit("memory.command.requested", requested);
2000
+ const relatedResults = await commandDeps.lookupRelevantMemory(options.runtimeContext, query);
2001
+ const topResult = relatedResults[0];
2002
+ const retrievedEvent = {
2003
+ ...baseEventFields(options, commandDeps.currentBranch(options.projectRoot)),
2004
+ eventType: "retrieved",
2005
+ canonicalKey: topResult?.canonicalKey ?? NO_MATCH_RETRIEVAL_CANONICAL_KEY,
2006
+ retrievalQuery: query,
2007
+ retrievalRank: topResult ? 1 : 0
2008
+ };
2009
+ await commandDeps.promoteCanonicalMemoryEvent(options.projectRoot, { event: retrievedEvent });
2010
+ await commandDeps.syncRuntimeMemory(options.runtimeContext, retrievedEvent);
2011
+ await options.eventBus?.emit("memory.command.applied", {
2012
+ ...requested,
2013
+ retrievedCanonicalKeys: relatedResults.map((result) => result.canonicalKey)
2014
+ });
2015
+ return formatRelatedMemorySection(relatedResults);
2016
+ }
2017
+ }
2018
+ } catch (error) {
2019
+ const fallbackRequested = requested ?? requestedPayload(verb, mutationKindForVerb(verb), ["observe", "supersede", "retract", "reinforce"].includes(verb) ? rest[0] : undefined);
2020
+ await options.eventBus?.emit("memory.command.failed", {
2021
+ ...fallbackRequested,
2022
+ error: error instanceof Error ? error.message : String(error)
2023
+ });
2024
+ throw error;
2025
+ }
2026
+ }
2027
+ export {
2028
+ setMemoryItemEmbedding,
2029
+ resetMemoryEmbeddingWarningsForTests,
2030
+ readCanonicalMemoryDb,
2031
+ queryRelevantMemory,
2032
+ promoteCanonicalMemoryEvent,
2033
+ openMemoryDb,
2034
+ memoryEventRequiresEmbedding,
2035
+ maybeCreateConfiguredMemoryEmbedder,
2036
+ listMemoryEvents,
2037
+ listActiveMemoryItems,
2038
+ hasMemoryEvent,
2039
+ getMemoryItemByKey,
2040
+ formatMemoryQueryResults,
2041
+ executeMemoryCommand,
2042
+ embedChangedMemoryItems,
2043
+ createOpenAiMemoryEmbedder,
2044
+ createDeterministicMemoryEmbedder,
2045
+ createConfiguredMemoryEmbedder,
2046
+ applyMemoryEvent,
2047
+ NO_MATCH_RETRIEVAL_CANONICAL_KEY,
2048
+ MISSING_MEMORY_EMBEDDER_WARNING
2049
+ };