opencastle 0.26.1 → 0.27.1

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 (226) hide show
  1. package/README.md +7 -1
  2. package/bin/cli.mjs +10 -0
  3. package/dist/cli/agents.d.ts +3 -0
  4. package/dist/cli/agents.d.ts.map +1 -0
  5. package/dist/cli/agents.js +161 -0
  6. package/dist/cli/agents.js.map +1 -0
  7. package/dist/cli/baselines.d.ts +3 -0
  8. package/dist/cli/baselines.d.ts.map +1 -0
  9. package/dist/cli/baselines.js +128 -0
  10. package/dist/cli/baselines.js.map +1 -0
  11. package/dist/cli/convoy/engine.d.ts +68 -2
  12. package/dist/cli/convoy/engine.d.ts.map +1 -1
  13. package/dist/cli/convoy/engine.js +2102 -26
  14. package/dist/cli/convoy/engine.js.map +1 -1
  15. package/dist/cli/convoy/engine.test.js +1572 -70
  16. package/dist/cli/convoy/engine.test.js.map +1 -1
  17. package/dist/cli/convoy/events.d.ts +4 -1
  18. package/dist/cli/convoy/events.d.ts.map +1 -1
  19. package/dist/cli/convoy/events.js +74 -13
  20. package/dist/cli/convoy/events.js.map +1 -1
  21. package/dist/cli/convoy/events.test.js +154 -27
  22. package/dist/cli/convoy/events.test.js.map +1 -1
  23. package/dist/cli/convoy/expertise.d.ts +16 -0
  24. package/dist/cli/convoy/expertise.d.ts.map +1 -0
  25. package/dist/cli/convoy/expertise.js +121 -0
  26. package/dist/cli/convoy/expertise.js.map +1 -0
  27. package/dist/cli/convoy/expertise.test.d.ts +2 -0
  28. package/dist/cli/convoy/expertise.test.d.ts.map +1 -0
  29. package/dist/cli/convoy/expertise.test.js +96 -0
  30. package/dist/cli/convoy/expertise.test.js.map +1 -0
  31. package/dist/cli/convoy/export.test.js +1 -0
  32. package/dist/cli/convoy/export.test.js.map +1 -1
  33. package/dist/cli/convoy/formula.d.ts +19 -0
  34. package/dist/cli/convoy/formula.d.ts.map +1 -0
  35. package/dist/cli/convoy/formula.js +142 -0
  36. package/dist/cli/convoy/formula.js.map +1 -0
  37. package/dist/cli/convoy/formula.test.d.ts +2 -0
  38. package/dist/cli/convoy/formula.test.d.ts.map +1 -0
  39. package/dist/cli/convoy/formula.test.js +342 -0
  40. package/dist/cli/convoy/formula.test.js.map +1 -0
  41. package/dist/cli/convoy/gates.d.ts +128 -0
  42. package/dist/cli/convoy/gates.d.ts.map +1 -0
  43. package/dist/cli/convoy/gates.js +606 -0
  44. package/dist/cli/convoy/gates.js.map +1 -0
  45. package/dist/cli/convoy/gates.test.d.ts +2 -0
  46. package/dist/cli/convoy/gates.test.d.ts.map +1 -0
  47. package/dist/cli/convoy/gates.test.js +976 -0
  48. package/dist/cli/convoy/gates.test.js.map +1 -0
  49. package/dist/cli/convoy/health.d.ts +11 -0
  50. package/dist/cli/convoy/health.d.ts.map +1 -1
  51. package/dist/cli/convoy/health.js +54 -0
  52. package/dist/cli/convoy/health.js.map +1 -1
  53. package/dist/cli/convoy/health.test.js +56 -1
  54. package/dist/cli/convoy/health.test.js.map +1 -1
  55. package/dist/cli/convoy/issues.d.ts +8 -0
  56. package/dist/cli/convoy/issues.d.ts.map +1 -0
  57. package/dist/cli/convoy/issues.js +98 -0
  58. package/dist/cli/convoy/issues.js.map +1 -0
  59. package/dist/cli/convoy/issues.test.d.ts +2 -0
  60. package/dist/cli/convoy/issues.test.d.ts.map +1 -0
  61. package/dist/cli/convoy/issues.test.js +107 -0
  62. package/dist/cli/convoy/issues.test.js.map +1 -0
  63. package/dist/cli/convoy/knowledge.d.ts +5 -0
  64. package/dist/cli/convoy/knowledge.d.ts.map +1 -0
  65. package/dist/cli/convoy/knowledge.js +116 -0
  66. package/dist/cli/convoy/knowledge.js.map +1 -0
  67. package/dist/cli/convoy/knowledge.test.d.ts +2 -0
  68. package/dist/cli/convoy/knowledge.test.d.ts.map +1 -0
  69. package/dist/cli/convoy/knowledge.test.js +87 -0
  70. package/dist/cli/convoy/knowledge.test.js.map +1 -0
  71. package/dist/cli/convoy/lessons.d.ts +17 -0
  72. package/dist/cli/convoy/lessons.d.ts.map +1 -0
  73. package/dist/cli/convoy/lessons.js +149 -0
  74. package/dist/cli/convoy/lessons.js.map +1 -0
  75. package/dist/cli/convoy/lessons.test.d.ts +2 -0
  76. package/dist/cli/convoy/lessons.test.d.ts.map +1 -0
  77. package/dist/cli/convoy/lessons.test.js +135 -0
  78. package/dist/cli/convoy/lessons.test.js.map +1 -0
  79. package/dist/cli/convoy/lock.d.ts +13 -0
  80. package/dist/cli/convoy/lock.d.ts.map +1 -0
  81. package/dist/cli/convoy/lock.js +88 -0
  82. package/dist/cli/convoy/lock.js.map +1 -0
  83. package/dist/cli/convoy/lock.test.d.ts +2 -0
  84. package/dist/cli/convoy/lock.test.d.ts.map +1 -0
  85. package/dist/cli/convoy/lock.test.js +136 -0
  86. package/dist/cli/convoy/lock.test.js.map +1 -0
  87. package/dist/cli/convoy/merge.d.ts +4 -0
  88. package/dist/cli/convoy/merge.d.ts.map +1 -1
  89. package/dist/cli/convoy/merge.js +18 -1
  90. package/dist/cli/convoy/merge.js.map +1 -1
  91. package/dist/cli/convoy/merge.test.js +6 -7
  92. package/dist/cli/convoy/merge.test.js.map +1 -1
  93. package/dist/cli/convoy/partition.d.ts +51 -0
  94. package/dist/cli/convoy/partition.d.ts.map +1 -0
  95. package/dist/cli/convoy/partition.js +186 -0
  96. package/dist/cli/convoy/partition.js.map +1 -0
  97. package/dist/cli/convoy/partition.test.d.ts +2 -0
  98. package/dist/cli/convoy/partition.test.d.ts.map +1 -0
  99. package/dist/cli/convoy/partition.test.js +315 -0
  100. package/dist/cli/convoy/partition.test.js.map +1 -0
  101. package/dist/cli/convoy/pipeline.test.js +6 -0
  102. package/dist/cli/convoy/pipeline.test.js.map +1 -1
  103. package/dist/cli/convoy/store.d.ts +47 -5
  104. package/dist/cli/convoy/store.d.ts.map +1 -1
  105. package/dist/cli/convoy/store.js +525 -19
  106. package/dist/cli/convoy/store.js.map +1 -1
  107. package/dist/cli/convoy/store.test.js +1345 -12
  108. package/dist/cli/convoy/store.test.js.map +1 -1
  109. package/dist/cli/convoy/types.d.ts +156 -2
  110. package/dist/cli/convoy/types.d.ts.map +1 -1
  111. package/dist/cli/destroy.d.ts +3 -0
  112. package/dist/cli/destroy.d.ts.map +1 -0
  113. package/dist/cli/destroy.js +69 -0
  114. package/dist/cli/destroy.js.map +1 -0
  115. package/dist/cli/destroy.test.d.ts +2 -0
  116. package/dist/cli/destroy.test.d.ts.map +1 -0
  117. package/dist/cli/destroy.test.js +116 -0
  118. package/dist/cli/destroy.test.js.map +1 -0
  119. package/dist/cli/gitignore.d.ts +9 -0
  120. package/dist/cli/gitignore.d.ts.map +1 -1
  121. package/dist/cli/gitignore.js +29 -0
  122. package/dist/cli/gitignore.js.map +1 -1
  123. package/dist/cli/plan.d.ts +3 -0
  124. package/dist/cli/plan.d.ts.map +1 -0
  125. package/dist/cli/plan.js +288 -0
  126. package/dist/cli/plan.js.map +1 -0
  127. package/dist/cli/run/adapters/claude.d.ts +2 -0
  128. package/dist/cli/run/adapters/claude.d.ts.map +1 -1
  129. package/dist/cli/run/adapters/claude.js +89 -49
  130. package/dist/cli/run/adapters/claude.js.map +1 -1
  131. package/dist/cli/run/adapters/claude.test.d.ts +2 -0
  132. package/dist/cli/run/adapters/claude.test.d.ts.map +1 -0
  133. package/dist/cli/run/adapters/claude.test.js +205 -0
  134. package/dist/cli/run/adapters/claude.test.js.map +1 -0
  135. package/dist/cli/run/adapters/copilot.d.ts +1 -0
  136. package/dist/cli/run/adapters/copilot.d.ts.map +1 -1
  137. package/dist/cli/run/adapters/copilot.js +84 -46
  138. package/dist/cli/run/adapters/copilot.js.map +1 -1
  139. package/dist/cli/run/adapters/copilot.test.d.ts +2 -0
  140. package/dist/cli/run/adapters/copilot.test.d.ts.map +1 -0
  141. package/dist/cli/run/adapters/copilot.test.js +195 -0
  142. package/dist/cli/run/adapters/copilot.test.js.map +1 -0
  143. package/dist/cli/run/adapters/cursor.d.ts +1 -0
  144. package/dist/cli/run/adapters/cursor.d.ts.map +1 -1
  145. package/dist/cli/run/adapters/cursor.js +83 -47
  146. package/dist/cli/run/adapters/cursor.js.map +1 -1
  147. package/dist/cli/run/adapters/cursor.test.d.ts +2 -0
  148. package/dist/cli/run/adapters/cursor.test.d.ts.map +1 -0
  149. package/dist/cli/run/adapters/cursor.test.js +129 -0
  150. package/dist/cli/run/adapters/cursor.test.js.map +1 -0
  151. package/dist/cli/run/adapters/opencode.d.ts +1 -0
  152. package/dist/cli/run/adapters/opencode.d.ts.map +1 -1
  153. package/dist/cli/run/adapters/opencode.js +81 -47
  154. package/dist/cli/run/adapters/opencode.js.map +1 -1
  155. package/dist/cli/run/adapters/opencode.test.d.ts +2 -0
  156. package/dist/cli/run/adapters/opencode.test.d.ts.map +1 -0
  157. package/dist/cli/run/adapters/opencode.test.js +119 -0
  158. package/dist/cli/run/adapters/opencode.test.js.map +1 -0
  159. package/dist/cli/run/executor.js +1 -1
  160. package/dist/cli/run/executor.js.map +1 -1
  161. package/dist/cli/run/schema.d.ts.map +1 -1
  162. package/dist/cli/run/schema.js +245 -4
  163. package/dist/cli/run/schema.js.map +1 -1
  164. package/dist/cli/run/schema.test.js +669 -0
  165. package/dist/cli/run/schema.test.js.map +1 -1
  166. package/dist/cli/run.d.ts.map +1 -1
  167. package/dist/cli/run.js +362 -22
  168. package/dist/cli/run.js.map +1 -1
  169. package/dist/cli/types.d.ts +85 -2
  170. package/dist/cli/types.d.ts.map +1 -1
  171. package/dist/cli/types.js.map +1 -1
  172. package/dist/cli/watch.d.ts +15 -0
  173. package/dist/cli/watch.d.ts.map +1 -0
  174. package/dist/cli/watch.js +279 -0
  175. package/dist/cli/watch.js.map +1 -0
  176. package/package.json +1 -1
  177. package/src/cli/agents.ts +177 -0
  178. package/src/cli/baselines.ts +143 -0
  179. package/src/cli/convoy/engine.test.ts +1839 -70
  180. package/src/cli/convoy/engine.ts +2417 -38
  181. package/src/cli/convoy/events.test.ts +179 -38
  182. package/src/cli/convoy/events.ts +88 -16
  183. package/src/cli/convoy/expertise.test.ts +128 -0
  184. package/src/cli/convoy/expertise.ts +163 -0
  185. package/src/cli/convoy/export.test.ts +1 -0
  186. package/src/cli/convoy/formula.test.ts +405 -0
  187. package/src/cli/convoy/formula.ts +174 -0
  188. package/src/cli/convoy/gates.test.ts +1169 -0
  189. package/src/cli/convoy/gates.ts +774 -0
  190. package/src/cli/convoy/health.test.ts +64 -2
  191. package/src/cli/convoy/health.ts +80 -2
  192. package/src/cli/convoy/issues.test.ts +143 -0
  193. package/src/cli/convoy/issues.ts +136 -0
  194. package/src/cli/convoy/knowledge.test.ts +101 -0
  195. package/src/cli/convoy/knowledge.ts +132 -0
  196. package/src/cli/convoy/lessons.test.ts +188 -0
  197. package/src/cli/convoy/lessons.ts +164 -0
  198. package/src/cli/convoy/lock.test.ts +181 -0
  199. package/src/cli/convoy/lock.ts +103 -0
  200. package/src/cli/convoy/merge.test.ts +6 -7
  201. package/src/cli/convoy/merge.ts +19 -1
  202. package/src/cli/convoy/partition.test.ts +423 -0
  203. package/src/cli/convoy/partition.ts +232 -0
  204. package/src/cli/convoy/pipeline.test.ts +6 -0
  205. package/src/cli/convoy/store.test.ts +1512 -14
  206. package/src/cli/convoy/store.ts +676 -30
  207. package/src/cli/convoy/types.ts +170 -1
  208. package/src/cli/destroy.test.ts +141 -0
  209. package/src/cli/destroy.ts +88 -0
  210. package/src/cli/gitignore.ts +36 -0
  211. package/src/cli/plan.ts +316 -0
  212. package/src/cli/run/adapters/claude.test.ts +234 -0
  213. package/src/cli/run/adapters/claude.ts +45 -5
  214. package/src/cli/run/adapters/copilot.test.ts +224 -0
  215. package/src/cli/run/adapters/copilot.ts +34 -4
  216. package/src/cli/run/adapters/cursor.test.ts +144 -0
  217. package/src/cli/run/adapters/cursor.ts +33 -2
  218. package/src/cli/run/adapters/opencode.test.ts +135 -0
  219. package/src/cli/run/adapters/opencode.ts +30 -2
  220. package/src/cli/run/executor.ts +1 -1
  221. package/src/cli/run/schema.test.ts +758 -0
  222. package/src/cli/run/schema.ts +300 -25
  223. package/src/cli/run.ts +341 -21
  224. package/src/cli/types.ts +86 -1
  225. package/src/cli/watch.ts +298 -0
  226. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/store.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,48 @@
1
+ import { copyFileSync } from 'node:fs';
1
2
  import { DatabaseSync } from 'node:sqlite';
2
- const SCHEMA_VERSION = 4;
3
+ const SCHEMA_VERSION = 9;
4
+ // ── Size limits (bytes) ────────────────────────────────────────────────────────
5
+ const LIMIT_SPEC_YAML = 256 * 1024; // 256 KB
6
+ const LIMIT_OUTPUT = 1024 * 1024; // 1 MB (head 512KB + tail 512KB)
7
+ const LIMIT_OUTPUT_HALF = 512 * 1024; // 512 KB per half
8
+ const LIMIT_EVENT_DATA = 64 * 1024; // 64 KB
9
+ const LIMIT_SUMMARY = 4096; // 4 KB
10
+ export class FieldSizeLimitError extends Error {
11
+ constructor(field, actual, limit) {
12
+ super(`Field "${field}" exceeds size limit: ${actual} bytes > ${limit} bytes`);
13
+ this.name = 'FieldSizeLimitError';
14
+ }
15
+ }
16
+ function enforceLimit(value, field, limit) {
17
+ if (value == null)
18
+ return;
19
+ const size = Buffer.byteLength(value, 'utf8');
20
+ if (size > limit) {
21
+ throw new FieldSizeLimitError(field, size, limit);
22
+ }
23
+ }
24
+ function truncateOutput(value) {
25
+ if (value == null)
26
+ return null;
27
+ const size = Buffer.byteLength(value, 'utf8');
28
+ if (size <= LIMIT_OUTPUT)
29
+ return value;
30
+ // Head + tail truncation with marker
31
+ const head = value.slice(0, LIMIT_OUTPUT_HALF);
32
+ const tail = value.slice(-LIMIT_OUTPUT_HALF);
33
+ return head + '\n\n... [truncated: ' + size + ' bytes total, showing first/last 512KB] ...\n\n' + tail;
34
+ }
35
+ export class ConvoyArtifactLimitError extends Error {
36
+ constructor(convoyId) {
37
+ super(`Convoy ${convoyId} has reached the maximum of 50 artifacts`);
38
+ this.name = 'ConvoyArtifactLimitError';
39
+ }
40
+ }
3
41
  class ConvoyStoreImpl {
4
42
  db;
43
+ dbPath;
5
44
  constructor(dbPath) {
45
+ this.dbPath = dbPath;
6
46
  this.db = new DatabaseSync(dbPath);
7
47
  this.db.exec('PRAGMA journal_mode = WAL');
8
48
  this.db.exec('PRAGMA synchronous = NORMAL');
@@ -13,18 +53,21 @@ class ConvoyStoreImpl {
13
53
  if (version === 0) {
14
54
  this.db.exec(`
15
55
  CREATE TABLE IF NOT EXISTS convoy (
16
- id TEXT PRIMARY KEY,
17
- name TEXT NOT NULL,
18
- spec_hash TEXT NOT NULL,
19
- status TEXT NOT NULL DEFAULT 'pending',
20
- branch TEXT,
21
- created_at TEXT NOT NULL,
22
- started_at TEXT,
23
- finished_at TEXT,
24
- spec_yaml TEXT NOT NULL,
25
- total_tokens INTEGER,
26
- total_cost_usd TEXT,
27
- pipeline_id TEXT
56
+ id TEXT PRIMARY KEY,
57
+ name TEXT NOT NULL,
58
+ spec_hash TEXT NOT NULL,
59
+ status TEXT NOT NULL DEFAULT 'pending',
60
+ branch TEXT,
61
+ created_at TEXT NOT NULL,
62
+ started_at TEXT,
63
+ finished_at TEXT,
64
+ spec_yaml TEXT NOT NULL,
65
+ total_tokens INTEGER,
66
+ total_cost_usd TEXT,
67
+ pipeline_id TEXT,
68
+ circuit_state TEXT,
69
+ review_tokens_total INTEGER,
70
+ review_budget INTEGER
28
71
  );
29
72
 
30
73
  CREATE TABLE IF NOT EXISTS pipeline (
@@ -64,7 +107,41 @@ class ConvoyStoreImpl {
64
107
  prompt_tokens INTEGER,
65
108
  completion_tokens INTEGER,
66
109
  total_tokens INTEGER,
67
- cost_usd TEXT
110
+ cost_usd TEXT,
111
+ gates TEXT,
112
+ on_exhausted TEXT NOT NULL DEFAULT 'dlq',
113
+ injected INTEGER NOT NULL DEFAULT 0,
114
+ provenance TEXT,
115
+ idempotency_key TEXT,
116
+ current_step INTEGER,
117
+ total_steps INTEGER,
118
+ review_level TEXT,
119
+ review_verdict TEXT,
120
+ review_tokens INTEGER,
121
+ review_model TEXT,
122
+ panel_attempts INTEGER NOT NULL DEFAULT 0,
123
+ dispute_id TEXT,
124
+ drift_score REAL,
125
+ drift_retried INTEGER NOT NULL DEFAULT 0,
126
+ outputs TEXT,
127
+ inputs TEXT,
128
+ discovered_issues TEXT
129
+ );
130
+
131
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_task_idempotency ON task(convoy_id, idempotency_key)
132
+ WHERE idempotency_key IS NOT NULL;
133
+
134
+ CREATE TABLE IF NOT EXISTS task_step (
135
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
136
+ task_id TEXT NOT NULL REFERENCES task(id),
137
+ step_index INTEGER NOT NULL,
138
+ prompt TEXT NOT NULL,
139
+ gates TEXT,
140
+ status TEXT NOT NULL DEFAULT 'pending',
141
+ exit_code INTEGER,
142
+ output TEXT,
143
+ started_at TEXT,
144
+ finished_at TEXT
68
145
  );
69
146
 
70
147
  CREATE TABLE IF NOT EXISTS worker (
@@ -89,6 +166,57 @@ class ConvoyStoreImpl {
89
166
  data TEXT,
90
167
  created_at TEXT NOT NULL
91
168
  );
169
+
170
+ CREATE TABLE IF NOT EXISTS dlq (
171
+ id TEXT PRIMARY KEY,
172
+ convoy_id TEXT NOT NULL REFERENCES convoy(id),
173
+ task_id TEXT NOT NULL REFERENCES task(id),
174
+ agent TEXT NOT NULL,
175
+ failure_type TEXT NOT NULL,
176
+ error_output TEXT,
177
+ attempts INTEGER NOT NULL,
178
+ tokens_spent INTEGER,
179
+ escalation_task_id TEXT,
180
+ resolved INTEGER NOT NULL DEFAULT 0,
181
+ resolution TEXT,
182
+ created_at TEXT NOT NULL,
183
+ resolved_at TEXT
184
+ );
185
+
186
+ CREATE TABLE IF NOT EXISTS artifact (
187
+ id TEXT PRIMARY KEY,
188
+ convoy_id TEXT NOT NULL REFERENCES convoy(id),
189
+ task_id TEXT NOT NULL REFERENCES task(id),
190
+ name TEXT NOT NULL,
191
+ type TEXT NOT NULL,
192
+ content TEXT NOT NULL CHECK (length(content) <= 1048576),
193
+ created_at TEXT NOT NULL,
194
+ UNIQUE(convoy_id, name)
195
+ );
196
+
197
+ CREATE TABLE IF NOT EXISTS agent_identity (
198
+ id TEXT PRIMARY KEY,
199
+ agent TEXT NOT NULL,
200
+ convoy_id TEXT NOT NULL,
201
+ task_id TEXT NOT NULL,
202
+ summary TEXT NOT NULL,
203
+ created_at TEXT NOT NULL,
204
+ retention_days INTEGER NOT NULL DEFAULT 90
205
+ );
206
+
207
+ CREATE TABLE IF NOT EXISTS scratchpad (
208
+ key TEXT PRIMARY KEY,
209
+ value TEXT NOT NULL,
210
+ updated_at TEXT NOT NULL
211
+ );
212
+
213
+ CREATE TABLE IF NOT EXISTS engine_lock (
214
+ id INTEGER PRIMARY KEY,
215
+ pid INTEGER NOT NULL,
216
+ hostname TEXT NOT NULL,
217
+ started_at TEXT NOT NULL,
218
+ last_heartbeat TEXT NOT NULL
219
+ );
92
220
  `);
93
221
  this.db.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);
94
222
  version = SCHEMA_VERSION;
@@ -128,11 +256,36 @@ class ConvoyStoreImpl {
128
256
  this.db.exec('PRAGMA user_version = 4');
129
257
  version = 4;
130
258
  }
259
+ if (version === 4) {
260
+ migrateSchema(this.db, this.dbPath, 4, 5);
261
+ version = 5;
262
+ }
263
+ if (version === 5) {
264
+ migrateSchema(this.db, this.dbPath, 5, 6);
265
+ version = 6;
266
+ }
267
+ if (version === 6) {
268
+ migrateSchema(this.db, this.dbPath, 6, 7);
269
+ version = 7;
270
+ }
271
+ if (version === 7) {
272
+ migrateSchema(this.db, this.dbPath, 7, 8);
273
+ version = 8;
274
+ }
275
+ if (version === 8) {
276
+ migrateSchema(this.db, this.dbPath, 8, 9);
277
+ version = 9;
278
+ }
131
279
  }
132
280
  insertConvoy(record) {
281
+ enforceLimit(record.spec_yaml, 'spec_yaml', LIMIT_SPEC_YAML);
133
282
  this.db
134
- .prepare(`INSERT INTO convoy (id, name, spec_hash, status, branch, created_at, started_at, finished_at, spec_yaml, pipeline_id)
135
- VALUES (:id, :name, :spec_hash, :status, :branch, :created_at, NULL, NULL, :spec_yaml, :pipeline_id)`)
283
+ .prepare(`INSERT INTO convoy
284
+ (id, name, spec_hash, status, branch, created_at, started_at, finished_at,
285
+ spec_yaml, pipeline_id)
286
+ VALUES
287
+ (:id, :name, :spec_hash, :status, :branch, :created_at, NULL, NULL,
288
+ :spec_yaml, :pipeline_id)`)
136
289
  .run({ ...record, pipeline_id: record.pipeline_id ?? null });
137
290
  }
138
291
  getConvoy(id) {
@@ -166,16 +319,52 @@ class ConvoyStoreImpl {
166
319
  }
167
320
  this.db.prepare(`UPDATE convoy SET ${sets.join(', ')} WHERE id = :id`).run(params);
168
321
  }
322
+ updateConvoyReviewTokens(convoyId, tokens) {
323
+ this.db
324
+ .prepare(`UPDATE convoy
325
+ SET review_tokens_total = :tokens
326
+ WHERE id = :id`)
327
+ .run({ id: convoyId, tokens });
328
+ }
329
+ updateConvoyCircuitState(convoyId, state) {
330
+ this.db
331
+ .prepare('UPDATE convoy SET circuit_state = :state WHERE id = :id')
332
+ .run({ id: convoyId, state: state ?? null });
333
+ }
169
334
  insertTask(record) {
170
335
  this.db
171
336
  .prepare(`INSERT INTO task
172
337
  (id, convoy_id, phase, prompt, agent, adapter, model, timeout_ms, status,
173
338
  worker_id, worktree, output, exit_code, started_at, finished_at,
174
- retries, max_retries, files, depends_on)
339
+ retries, max_retries, files, depends_on, gates,
340
+ on_exhausted, injected, provenance, idempotency_key,
341
+ outputs, inputs)
175
342
  VALUES
176
343
  (:id, :convoy_id, :phase, :prompt, :agent, :adapter, :model, :timeout_ms, :status,
177
344
  NULL, NULL, NULL, NULL, NULL, NULL,
178
- :retries, :max_retries, :files, :depends_on)`)
345
+ :retries, :max_retries, :files, :depends_on, :gates,
346
+ 'dlq', 0, NULL, NULL,
347
+ :outputs, :inputs)`)
348
+ .run({ ...record, outputs: record.outputs ?? null, inputs: record.inputs ?? null });
349
+ }
350
+ insertInjectedTask(record) {
351
+ this.db
352
+ .prepare(`INSERT INTO task
353
+ (id, convoy_id, phase, prompt, agent, adapter, model, timeout_ms, status,
354
+ worker_id, worktree, output, exit_code, started_at, finished_at,
355
+ retries, max_retries, files, depends_on, gates,
356
+ on_exhausted, injected, provenance, idempotency_key,
357
+ current_step, total_steps, review_level, review_verdict,
358
+ review_tokens, review_model, panel_attempts, dispute_id,
359
+ drift_score, drift_retried, outputs, inputs, discovered_issues)
360
+ VALUES
361
+ (:id, :convoy_id, :phase, :prompt, :agent, :adapter, :model, :timeout_ms, :status,
362
+ :worker_id, :worktree, :output, :exit_code, :started_at, :finished_at,
363
+ :retries, :max_retries, :files, :depends_on, :gates,
364
+ :on_exhausted, :injected, :provenance, :idempotency_key,
365
+ :current_step, :total_steps, :review_level, :review_verdict,
366
+ :review_tokens, :review_model, :panel_attempts, :dispute_id,
367
+ :drift_score, :drift_retried, :outputs, :inputs, :discovered_issues)`)
179
368
  .run(record);
180
369
  }
181
370
  getTask(id, convoyId) {
@@ -188,10 +377,36 @@ class ConvoyStoreImpl {
188
377
  .prepare('SELECT * FROM task WHERE convoy_id = :convoy_id ORDER BY phase, id')
189
378
  .all({ convoy_id: convoyId });
190
379
  }
380
+ getTaskByIdempotencyKey(convoyId, key) {
381
+ return this.db
382
+ .prepare('SELECT * FROM task WHERE convoy_id = :convoy_id AND idempotency_key = :key')
383
+ .get({ convoy_id: convoyId, key });
384
+ }
385
+ getTaskByDisputeId(disputeId) {
386
+ return this.db
387
+ .prepare('SELECT * FROM task WHERE dispute_id = :dispute_id LIMIT 1')
388
+ .get({ dispute_id: disputeId });
389
+ }
390
+ getDisputedTasks(convoyId) {
391
+ if (convoyId) {
392
+ return this.db
393
+ .prepare("SELECT * FROM task WHERE status = 'disputed' AND convoy_id = :convoy_id ORDER BY phase, id")
394
+ .all({ convoy_id: convoyId });
395
+ }
396
+ return this.db
397
+ .prepare("SELECT * FROM task WHERE status = 'disputed' ORDER BY convoy_id, phase, id")
398
+ .all({});
399
+ }
191
400
  updateTaskStatus(id, convoyId, status, extra) {
401
+ if (extra?.output !== undefined) {
402
+ extra = { ...extra, output: truncateOutput(extra.output) };
403
+ }
192
404
  const sets = ['status = :status'];
193
405
  const params = { id, convoy_id: convoyId, status };
194
- const extraFields = ['worker_id', 'worktree', 'output', 'exit_code', 'started_at', 'finished_at', 'retries', 'prompt_tokens', 'completion_tokens', 'total_tokens', 'cost_usd'];
406
+ const extraFields = [
407
+ 'worker_id', 'worktree', 'output', 'exit_code', 'started_at', 'finished_at',
408
+ 'retries', 'prompt_tokens', 'completion_tokens', 'total_tokens', 'cost_usd', 'prompt',
409
+ ];
195
410
  if (extra) {
196
411
  for (const field of extraFields) {
197
412
  if (field in extra && extra[field] !== undefined) {
@@ -216,6 +431,65 @@ class ConvoyStoreImpl {
216
431
  return deps.length === 0 || deps.every(depId => doneTaskIds.has(depId));
217
432
  });
218
433
  }
434
+ insertTaskStep(record) {
435
+ this.db
436
+ .prepare(`INSERT INTO task_step
437
+ (task_id, step_index, prompt, gates, status, exit_code, output, started_at, finished_at)
438
+ VALUES
439
+ (:task_id, :step_index, :prompt, :gates, :status, :exit_code, :output, :started_at, :finished_at)`)
440
+ .run(record);
441
+ const row = this.db.prepare('SELECT last_insert_rowid() AS id').get();
442
+ return row.id;
443
+ }
444
+ updateTaskStep(id, fields) {
445
+ const sets = [];
446
+ const params = { id };
447
+ const stepFields = ['status', 'exit_code', 'output', 'started_at', 'finished_at'];
448
+ for (const field of stepFields) {
449
+ if (field in fields && fields[field] !== undefined) {
450
+ sets.push(`${field} = :${field}`);
451
+ params[field] = fields[field];
452
+ }
453
+ }
454
+ if (sets.length === 0)
455
+ return;
456
+ this.db.prepare(`UPDATE task_step SET ${sets.join(', ')} WHERE id = :id`).run(params);
457
+ }
458
+ updateTaskReview(taskId, convoyId, fields) {
459
+ const sets = [];
460
+ const params = { id: taskId, convoy_id: convoyId };
461
+ const reviewFields = ['review_level', 'review_verdict', 'review_tokens', 'review_model', 'panel_attempts', 'dispute_id'];
462
+ for (const field of reviewFields) {
463
+ if (field in fields && fields[field] !== undefined) {
464
+ sets.push(`${field} = :${field}`);
465
+ params[field] = fields[field];
466
+ }
467
+ }
468
+ if (sets.length === 0)
469
+ return;
470
+ this.db.prepare(`UPDATE task SET ${sets.join(', ')} WHERE id = :id AND convoy_id = :convoy_id`).run(params);
471
+ }
472
+ updateTaskDrift(taskId, convoyId, fields) {
473
+ const sets = [];
474
+ const params = { id: taskId, convoy_id: convoyId };
475
+ if (fields.drift_score !== undefined) {
476
+ sets.push('drift_score = :drift_score');
477
+ params.drift_score = fields.drift_score;
478
+ }
479
+ if (fields.drift_retried !== undefined) {
480
+ sets.push('drift_retried = :drift_retried');
481
+ params.drift_retried = fields.drift_retried;
482
+ }
483
+ if (sets.length === 0)
484
+ return;
485
+ this.db.prepare(`UPDATE task SET ${sets.join(', ')} WHERE id = :id AND convoy_id = :convoy_id`).run(params);
486
+ }
487
+ updateTaskDisputeStatus(taskId, convoyId, status, disputeId) {
488
+ this.db
489
+ .prepare(`UPDATE task SET status = :status, dispute_id = :dispute_id
490
+ WHERE id = :id AND convoy_id = :convoy_id`)
491
+ .run({ id: taskId, convoy_id: convoyId, status, dispute_id: disputeId });
492
+ }
219
493
  insertWorker(record) {
220
494
  this.db
221
495
  .prepare(`INSERT INTO worker
@@ -249,17 +523,137 @@ class ConvoyStoreImpl {
249
523
  this.db.prepare(`UPDATE worker SET ${sets.join(', ')} WHERE id = :id`).run(params);
250
524
  }
251
525
  insertEvent(record) {
526
+ enforceLimit(record.data, 'event.data', LIMIT_EVENT_DATA);
252
527
  this.db
253
528
  .prepare(`INSERT INTO event (convoy_id, task_id, worker_id, type, data, created_at)
254
529
  VALUES (:convoy_id, :task_id, :worker_id, :type, :data, :created_at)`)
255
530
  .run(record);
531
+ const row = this.db.prepare('SELECT last_insert_rowid() AS id').get();
532
+ return row.id;
256
533
  }
257
534
  getEvents(convoyId) {
258
535
  return this.db
259
536
  .prepare('SELECT * FROM event WHERE convoy_id = :convoy_id ORDER BY id')
260
537
  .all({ convoy_id: convoyId });
261
538
  }
539
+ insertDlqEntry(record) {
540
+ this.db
541
+ .prepare(`INSERT INTO dlq
542
+ (id, convoy_id, task_id, agent, failure_type, error_output, attempts,
543
+ tokens_spent, escalation_task_id, resolved, resolution, created_at, resolved_at)
544
+ VALUES
545
+ (:id, :convoy_id, :task_id, :agent, :failure_type, :error_output, :attempts,
546
+ :tokens_spent, :escalation_task_id, :resolved, :resolution, :created_at, :resolved_at)`)
547
+ .run(record);
548
+ }
549
+ listDlqEntries(convoyIdFilter) {
550
+ if (convoyIdFilter) {
551
+ return this.db
552
+ .prepare('SELECT * FROM dlq WHERE convoy_id = :convoy_id ORDER BY created_at DESC')
553
+ .all({ convoy_id: convoyIdFilter });
554
+ }
555
+ return this.db
556
+ .prepare('SELECT * FROM dlq ORDER BY created_at DESC')
557
+ .all();
558
+ }
559
+ resolveDlqEntry(id, resolution) {
560
+ this.db
561
+ .prepare(`UPDATE dlq SET resolved = 1, resolution = :resolution, resolved_at = :resolved_at
562
+ WHERE id = :id`)
563
+ .run({ id, resolution, resolved_at: new Date().toISOString() });
564
+ }
565
+ insertArtifact(record) {
566
+ const count = this.db
567
+ .prepare('SELECT COUNT(*) AS cnt FROM artifact WHERE convoy_id = :convoy_id')
568
+ .get({ convoy_id: record.convoy_id }).cnt;
569
+ if (count >= 50) {
570
+ throw new ConvoyArtifactLimitError(record.convoy_id);
571
+ }
572
+ this.db
573
+ .prepare(`INSERT INTO artifact (id, convoy_id, task_id, name, type, content, created_at)
574
+ VALUES (:id, :convoy_id, :task_id, :name, :type, :content, :created_at)`)
575
+ .run(record);
576
+ }
577
+ getArtifact(convoyId, name) {
578
+ return this.db
579
+ .prepare('SELECT * FROM artifact WHERE convoy_id = :convoy_id AND name = :name')
580
+ .get({ convoy_id: convoyId, name });
581
+ }
582
+ getArtifactsByTask(taskId) {
583
+ return this.db
584
+ .prepare('SELECT * FROM artifact WHERE task_id = :task_id ORDER BY created_at')
585
+ .all({ task_id: taskId });
586
+ }
587
+ deleteArtifactsOlderThan(days) {
588
+ const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
589
+ const result = this.db
590
+ .prepare(`DELETE FROM artifact WHERE convoy_id IN (
591
+ SELECT id FROM convoy WHERE finished_at IS NOT NULL AND finished_at < :cutoff
592
+ )`)
593
+ .run({ cutoff });
594
+ return result.changes;
595
+ }
596
+ insertAgentIdentity(record) {
597
+ const summarySize = Buffer.byteLength(record.summary, 'utf8');
598
+ const truncatedSummary = summarySize > LIMIT_SUMMARY
599
+ ? record.summary.slice(0, LIMIT_SUMMARY)
600
+ : record.summary;
601
+ this.db
602
+ .prepare(`INSERT INTO agent_identity
603
+ (id, agent, convoy_id, task_id, summary, created_at, retention_days)
604
+ VALUES
605
+ (:id, :agent, :convoy_id, :task_id, :summary, :created_at, :retention_days)`)
606
+ .run({ ...record, summary: truncatedSummary });
607
+ }
608
+ getAgentIdentities(agent, limit) {
609
+ return this.db
610
+ .prepare('SELECT * FROM agent_identity WHERE agent = :agent ORDER BY created_at DESC LIMIT :limit')
611
+ .all({ agent, limit });
612
+ }
613
+ listAgentIdentitySummary() {
614
+ return this.db
615
+ .prepare(`SELECT agent, COUNT(*) AS task_count, MAX(created_at) AS latest_date
616
+ FROM agent_identity GROUP BY agent ORDER BY agent`)
617
+ .all();
618
+ }
619
+ purgeAgentIdentities(agent) {
620
+ const result = this.db
621
+ .prepare('DELETE FROM agent_identity WHERE agent = :agent')
622
+ .run({ agent });
623
+ return result.changes;
624
+ }
625
+ deleteAgentIdentitiesOlderThan(days) {
626
+ const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
627
+ const result = this.db
628
+ .prepare(`DELETE FROM agent_identity
629
+ WHERE created_at < :cutoff
630
+ OR (retention_days IS NOT NULL
631
+ AND created_at < datetime('now', '-' || retention_days || ' days'))`)
632
+ .run({ cutoff });
633
+ return result.changes;
634
+ }
635
+ getScratchpadValue(key) {
636
+ const row = this.db
637
+ .prepare('SELECT value FROM scratchpad WHERE key = :key')
638
+ .get({ key });
639
+ return row?.value ?? null;
640
+ }
641
+ setScratchpadValue(key, value) {
642
+ this.db
643
+ .prepare(`INSERT INTO scratchpad (key, value, updated_at)
644
+ VALUES (:key, :value, :updated_at)
645
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`)
646
+ .run({ key, value, updated_at: new Date().toISOString() });
647
+ }
648
+ clearScratchpad() {
649
+ this.db.exec('DELETE FROM scratchpad');
650
+ }
651
+ clearScratchpadOlderThan(days) {
652
+ const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
653
+ this.db.prepare('DELETE FROM scratchpad WHERE updated_at < :cutoff').run({ cutoff });
654
+ }
262
655
  insertPipeline(record) {
656
+ enforceLimit(record.spec_yaml, 'pipeline.spec_yaml', LIMIT_SPEC_YAML);
263
657
  this.db
264
658
  .prepare(`INSERT INTO pipeline (id, name, status, branch, spec_yaml, convoy_specs, created_at,
265
659
  started_at, finished_at, total_tokens, total_cost_usd)
@@ -319,6 +713,118 @@ class ConvoyStoreImpl {
319
713
  this.db.close();
320
714
  }
321
715
  }
716
+ export function migrateSchema(db, dbPath, fromVersion, toVersion) {
717
+ for (let v = fromVersion; v < toVersion; v++) {
718
+ const backupPath = `${dbPath}.v${v}.bak`;
719
+ copyFileSync(dbPath, backupPath);
720
+ db.exec('BEGIN');
721
+ try {
722
+ if (v === 4) {
723
+ db.exec(`
724
+ ALTER TABLE task ADD COLUMN gates TEXT;
725
+ ALTER TABLE task ADD COLUMN on_exhausted TEXT NOT NULL DEFAULT 'dlq';
726
+ ALTER TABLE task ADD COLUMN injected INTEGER NOT NULL DEFAULT 0;
727
+ ALTER TABLE task ADD COLUMN provenance TEXT;
728
+ ALTER TABLE task ADD COLUMN idempotency_key TEXT;
729
+ CREATE UNIQUE INDEX idx_task_idempotency ON task(convoy_id, idempotency_key)
730
+ WHERE idempotency_key IS NOT NULL;
731
+ ALTER TABLE convoy ADD COLUMN circuit_state TEXT;
732
+ CREATE TABLE dlq (
733
+ id TEXT PRIMARY KEY,
734
+ convoy_id TEXT NOT NULL REFERENCES convoy(id),
735
+ task_id TEXT NOT NULL REFERENCES task(id),
736
+ agent TEXT NOT NULL,
737
+ failure_type TEXT NOT NULL,
738
+ error_output TEXT,
739
+ attempts INTEGER NOT NULL,
740
+ tokens_spent INTEGER,
741
+ escalation_task_id TEXT,
742
+ resolved INTEGER NOT NULL DEFAULT 0,
743
+ resolution TEXT,
744
+ created_at TEXT NOT NULL,
745
+ resolved_at TEXT
746
+ );
747
+ `);
748
+ }
749
+ if (v === 5) {
750
+ db.exec(`
751
+ ALTER TABLE task ADD COLUMN current_step INTEGER;
752
+ ALTER TABLE task ADD COLUMN total_steps INTEGER;
753
+ ALTER TABLE task ADD COLUMN review_level TEXT;
754
+ ALTER TABLE task ADD COLUMN review_verdict TEXT;
755
+ ALTER TABLE task ADD COLUMN review_tokens INTEGER;
756
+ ALTER TABLE task ADD COLUMN review_model TEXT;
757
+ ALTER TABLE task ADD COLUMN panel_attempts INTEGER NOT NULL DEFAULT 0;
758
+ ALTER TABLE task ADD COLUMN dispute_id TEXT;
759
+ ALTER TABLE convoy ADD COLUMN review_tokens_total INTEGER;
760
+ ALTER TABLE convoy ADD COLUMN review_budget INTEGER;
761
+ CREATE TABLE task_step (
762
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
763
+ task_id TEXT NOT NULL REFERENCES task(id),
764
+ step_index INTEGER NOT NULL,
765
+ prompt TEXT NOT NULL,
766
+ gates TEXT,
767
+ status TEXT NOT NULL DEFAULT 'pending',
768
+ exit_code INTEGER,
769
+ output TEXT,
770
+ started_at TEXT,
771
+ finished_at TEXT
772
+ );
773
+ `);
774
+ }
775
+ if (v === 6) {
776
+ db.exec(`
777
+ ALTER TABLE task ADD COLUMN drift_score REAL;
778
+ ALTER TABLE task ADD COLUMN drift_retried INTEGER NOT NULL DEFAULT 0;
779
+ `);
780
+ }
781
+ if (v === 7) {
782
+ db.exec(`
783
+ ALTER TABLE task ADD COLUMN outputs TEXT;
784
+ ALTER TABLE task ADD COLUMN inputs TEXT;
785
+ ALTER TABLE task ADD COLUMN discovered_issues TEXT;
786
+ CREATE TABLE artifact (
787
+ id TEXT PRIMARY KEY,
788
+ convoy_id TEXT NOT NULL REFERENCES convoy(id),
789
+ task_id TEXT NOT NULL REFERENCES task(id),
790
+ name TEXT NOT NULL,
791
+ type TEXT NOT NULL,
792
+ content TEXT NOT NULL CHECK (length(content) <= 1048576),
793
+ created_at TEXT NOT NULL,
794
+ UNIQUE(convoy_id, name)
795
+ );
796
+ CREATE TABLE agent_identity (
797
+ id TEXT PRIMARY KEY,
798
+ agent TEXT NOT NULL,
799
+ convoy_id TEXT NOT NULL,
800
+ task_id TEXT NOT NULL,
801
+ summary TEXT NOT NULL,
802
+ created_at TEXT NOT NULL,
803
+ retention_days INTEGER NOT NULL DEFAULT 90
804
+ );
805
+ `);
806
+ }
807
+ if (v === 8) {
808
+ db.exec(`
809
+ CREATE TABLE scratchpad (
810
+ key TEXT PRIMARY KEY,
811
+ value TEXT NOT NULL,
812
+ updated_at TEXT NOT NULL
813
+ );
814
+ `);
815
+ }
816
+ db.exec('COMMIT');
817
+ }
818
+ catch (err) {
819
+ try {
820
+ db.exec('ROLLBACK');
821
+ }
822
+ catch { /* ignore */ }
823
+ throw new Error(`Migration v${v}→v${v + 1} failed. Backup at ${backupPath}. Original error: ${err.message}`);
824
+ }
825
+ db.exec(`PRAGMA user_version = ${v + 1}`);
826
+ }
827
+ }
322
828
  export function createConvoyStore(dbPath) {
323
829
  return new ConvoyStoreImpl(dbPath);
324
830
  }