@yemi33/minions 0.1.2370 → 0.1.2372

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 (71) hide show
  1. package/bin/minions.js +38 -11
  2. package/dashboard/js/render-other.js +2 -30
  3. package/dashboard/js/render-work-items.js +0 -34
  4. package/dashboard/js/settings.js +12 -27
  5. package/dashboard/pages/tools.html +1 -1
  6. package/dashboard.js +80 -257
  7. package/docs/README.md +2 -3
  8. package/docs/architecture.excalidraw +2 -2
  9. package/docs/auto-discovery.md +3 -3
  10. package/docs/completion-reports.md +0 -121
  11. package/docs/copilot-cli-schema.md +9 -17
  12. package/docs/deprecated.json +0 -51
  13. package/docs/design-state-storage.md +4 -4
  14. package/docs/harness-propagation.md +33 -263
  15. package/docs/human-vs-automated.md +1 -1
  16. package/docs/named-agents.md +0 -2
  17. package/docs/plan-lifecycle.md +5 -6
  18. package/docs/qa-runbook-lifecycle.md +10 -25
  19. package/docs/shared-lifecycle-module-map.md +2 -10
  20. package/engine/ado-comment.js +5 -11
  21. package/engine/ado.js +10 -5
  22. package/engine/cleanup.js +16 -36
  23. package/engine/cli.js +13 -175
  24. package/engine/comment-format.js +8 -182
  25. package/engine/db/index.js +60 -10
  26. package/engine/db/migrations/018-sql-only-cutover.js +56 -0
  27. package/engine/dispatch-store.js +0 -114
  28. package/engine/dispatch.js +1 -6
  29. package/engine/gh-comment.js +2 -10
  30. package/engine/github.js +8 -6
  31. package/engine/lifecycle.js +58 -173
  32. package/engine/llm.js +9 -11
  33. package/engine/managed-spawn.js +1 -6
  34. package/engine/memory-store.js +8 -6
  35. package/engine/metrics-store.js +4 -128
  36. package/engine/pipeline.js +4 -7
  37. package/engine/playbook.js +8 -196
  38. package/engine/prd-store.js +115 -141
  39. package/engine/preflight.js +8 -55
  40. package/engine/projects.js +34 -41
  41. package/engine/pull-requests-store.js +9 -234
  42. package/engine/qa-runs.js +4 -15
  43. package/engine/qa-sessions.js +5 -17
  44. package/engine/queries.js +23 -103
  45. package/engine/routing.js +1 -1
  46. package/engine/runtimes/claude.js +1 -2
  47. package/engine/runtimes/codex.js +0 -2
  48. package/engine/runtimes/copilot.js +1 -4
  49. package/engine/shared-branch-pr-reconcile.js +2 -5
  50. package/engine/shared.js +174 -533
  51. package/engine/small-state-store.js +12 -647
  52. package/engine/spawn-agent.js +5 -96
  53. package/engine/state-operations.js +166 -0
  54. package/engine/supervisor.js +0 -1
  55. package/engine/watch-actions.js +2 -3
  56. package/engine/watches-store.js +2 -128
  57. package/engine/work-items-store.js +3 -254
  58. package/engine.js +102 -334
  59. package/package.json +2 -2
  60. package/playbooks/build-fix-complex.md +0 -4
  61. package/playbooks/fix.md +0 -4
  62. package/playbooks/implement-shared.md +0 -4
  63. package/playbooks/implement.md +0 -4
  64. package/playbooks/plan-to-prd.md +16 -11
  65. package/playbooks/plan.md +0 -4
  66. package/playbooks/review.md +0 -6
  67. package/playbooks/shared-rules.md +0 -65
  68. package/docs/harness-transparency.md +0 -199
  69. package/docs/project-skills.md +0 -193
  70. package/engine/discover-project-skills.js +0 -673
  71. package/engine/playbook-intents.js +0 -76
@@ -6,14 +6,7 @@
6
6
  // managed-processes.json <-> managed_processes ({specs:[]} → row-per-name)
7
7
  // worktree-pool.json <-> worktree_pool ({entries:[]} → row-per-entry)
8
8
  //
9
- // They share enough infrastructure (content-hash fingerprint, mirror
10
- // writer, withTransaction wiring) that it's clearer to keep them in one
11
- // module — each store is small, and the JSON-shape transformations are
12
- // the only per-file divergence.
13
-
14
- const fs = require('fs');
15
- const path = require('path');
16
- const crypto = require('crypto');
9
+ // They share transaction and JSON-shape transformation infrastructure.
17
10
 
18
11
  function _toMs(v) {
19
12
  if (v == null) return null;
@@ -22,66 +15,10 @@ function _toMs(v) {
22
15
  return Number.isFinite(parsed) ? parsed : null;
23
16
  }
24
17
 
25
- function _fileContentHash(filePath) {
26
- try {
27
- const buf = fs.readFileSync(filePath);
28
- return crypto.createHash('sha1').update(buf).digest('hex');
29
- }
30
- catch { return null; }
31
- }
32
-
33
- function _readJson(filePath) {
34
- let raw;
35
- try { raw = fs.readFileSync(filePath, 'utf8'); }
36
- catch { return null; }
37
- try { return JSON.parse(raw); }
38
- catch (e) {
39
- try {
40
- // eslint-disable-next-line no-console
41
- console.warn(`[small-state-store] corrupt JSON in ${filePath}: ${e.message}`);
42
- } catch { /* console wrapped */ }
43
- return null;
44
- }
45
- }
46
-
47
- function _resolveFilePath(rel) {
48
- const shared = require('./shared');
49
- return path.join(shared.MINIONS_DIR, 'engine', rel);
50
- }
51
-
52
18
  // ─── schedule_runs ──────────────────────────────────────────────────────────
53
19
  // Shape: { [scheduleId]: { lastRun, lastWorkItemId, lastResult, lastCompletedAt } }
54
20
  // SQL: row per scheduleId, data = the value blob.
55
21
 
56
- let _scheduleRunsHash = null;
57
-
58
- function _hydrateScheduleRuns(db) {
59
- const fp = _resolveFilePath('schedule-runs.json');
60
- const raw = _readJson(fp) || {};
61
- db.prepare('DELETE FROM schedule_runs').run();
62
- const now = Date.now();
63
- const ins = db.prepare('INSERT INTO schedule_runs (schedule_id, data, updated_at) VALUES (?, ?, ?) ON CONFLICT(schedule_id) DO NOTHING');
64
- for (const [id, value] of Object.entries(raw)) {
65
- ins.run(id, JSON.stringify(value), now);
66
- }
67
- }
68
-
69
- function _resyncScheduleRunsIfDiverged(db) {
70
- const fp = _resolveFilePath('schedule-runs.json');
71
- const currentHash = _fileContentHash(fp);
72
- if (currentHash == null) return;
73
- if (_scheduleRunsHash != null && currentHash === _scheduleRunsHash) return;
74
- if (_scheduleRunsHash == null) {
75
- const sqlHas = db.prepare('SELECT 1 FROM schedule_runs LIMIT 1').get();
76
- if (sqlHas) {
77
- _scheduleRunsHash = currentHash;
78
- return;
79
- }
80
- }
81
- _hydrateScheduleRuns(db);
82
- _scheduleRunsHash = currentHash;
83
- }
84
-
85
22
  function _readScheduleRunsFromSql(db) {
86
23
  const rows = db.prepare('SELECT schedule_id, data FROM schedule_runs').all();
87
24
  const out = {};
@@ -94,15 +31,7 @@ function _readScheduleRunsFromSql(db) {
94
31
 
95
32
  function readScheduleRuns() {
96
33
  const { getDb } = require('./db');
97
- const db = getDb();
98
- _resyncScheduleRunsIfDiverged(db);
99
- const out = _readScheduleRunsFromSql(db);
100
- if (Object.keys(out).length === 0) {
101
- const fallback = _readJson(_resolveFilePath('schedule-runs.json'));
102
- if (fallback && Object.keys(fallback).length > 0) return fallback;
103
- return {};
104
- }
105
- return out;
34
+ return _readScheduleRunsFromSql(getDb());
106
35
  }
107
36
 
108
37
  function applyScheduleRunsMutation(mutator) {
@@ -112,7 +41,6 @@ function applyScheduleRunsMutation(mutator) {
112
41
  catch (e) { throw new Error(`small-state-store: SQLite unavailable (${e.message})`); }
113
42
 
114
43
  return withTransaction(db, () => {
115
- _resyncScheduleRunsIfDiverged(db);
116
44
  const before = _readScheduleRunsFromSql(db);
117
45
  const beforeSnap = JSON.parse(JSON.stringify(before));
118
46
  const next = mutator(before);
@@ -140,56 +68,10 @@ function applyScheduleRunsMutation(mutator) {
140
68
  });
141
69
  }
142
70
 
143
- function _mirrorScheduleRunsJson(filePath) {
144
- try {
145
- const shared = require('./shared');
146
- const { getDb } = require('./db');
147
- const obj = _readScheduleRunsFromSql(getDb());
148
- const target = filePath || _resolveFilePath('schedule-runs.json');
149
- shared.safeWrite(target, obj);
150
- const h = _fileContentHash(target);
151
- if (h != null) _scheduleRunsHash = h;
152
- } catch { /* mirror best-effort */ }
153
- }
154
-
155
71
  // ─── pipeline_runs ──────────────────────────────────────────────────────────
156
72
  // Shape: { [pipelineId]: [run, run, ...] }
157
73
  // SQL: row per (pipelineId, runId). Reconstruct on read by grouping.
158
74
 
159
- let _pipelineRunsHash = null;
160
-
161
- function _hydratePipelineRuns(db) {
162
- const fp = _resolveFilePath('pipeline-runs.json');
163
- const raw = _readJson(fp) || {};
164
- db.prepare('DELETE FROM pipeline_runs').run();
165
- const now = Date.now();
166
- const ins = db.prepare(`
167
- INSERT INTO pipeline_runs (pipeline_id, run_id, status, started_at, data, updated_at)
168
- VALUES (?, ?, ?, ?, ?, ?)
169
- ON CONFLICT(pipeline_id, run_id) DO NOTHING
170
- `);
171
- for (const [pipelineId, runs] of Object.entries(raw)) {
172
- if (!Array.isArray(runs)) continue;
173
- for (const run of runs) {
174
- if (!run || !run.runId) continue;
175
- ins.run(pipelineId, String(run.runId), run.status || null, _toMs(run.startedAt), JSON.stringify(run), now);
176
- }
177
- }
178
- }
179
-
180
- function _resyncPipelineRunsIfDiverged(db) {
181
- const fp = _resolveFilePath('pipeline-runs.json');
182
- const currentHash = _fileContentHash(fp);
183
- if (currentHash == null) return;
184
- if (_pipelineRunsHash != null && currentHash === _pipelineRunsHash) return;
185
- if (_pipelineRunsHash == null) {
186
- const sqlHas = db.prepare('SELECT 1 FROM pipeline_runs LIMIT 1').get();
187
- if (sqlHas) { _pipelineRunsHash = currentHash; return; }
188
- }
189
- _hydratePipelineRuns(db);
190
- _pipelineRunsHash = currentHash;
191
- }
192
-
193
75
  function _readPipelineRunsFromSql(db) {
194
76
  const rows = db.prepare('SELECT pipeline_id, data FROM pipeline_runs ORDER BY pipeline_id, rowid').all();
195
77
  const out = {};
@@ -205,15 +87,7 @@ function _readPipelineRunsFromSql(db) {
205
87
 
206
88
  function readPipelineRuns() {
207
89
  const { getDb } = require('./db');
208
- const db = getDb();
209
- _resyncPipelineRunsIfDiverged(db);
210
- const out = _readPipelineRunsFromSql(db);
211
- if (Object.keys(out).length === 0) {
212
- const fallback = _readJson(_resolveFilePath('pipeline-runs.json'));
213
- if (fallback && Object.keys(fallback).length > 0) return fallback;
214
- return {};
215
- }
216
- return out;
90
+ return _readPipelineRunsFromSql(getDb());
217
91
  }
218
92
 
219
93
  function applyPipelineRunsMutation(mutator) {
@@ -223,7 +97,6 @@ function applyPipelineRunsMutation(mutator) {
223
97
  catch (e) { throw new Error(`small-state-store: SQLite unavailable (${e.message})`); }
224
98
 
225
99
  return withTransaction(db, () => {
226
- _resyncPipelineRunsIfDiverged(db);
227
100
  const before = _readPipelineRunsFromSql(db);
228
101
  const beforeSnap = JSON.parse(JSON.stringify(before));
229
102
  const next = mutator(before);
@@ -270,50 +143,10 @@ function applyPipelineRunsMutation(mutator) {
270
143
  });
271
144
  }
272
145
 
273
- function _mirrorPipelineRunsJson(filePath) {
274
- try {
275
- const shared = require('./shared');
276
- const { getDb } = require('./db');
277
- const obj = _readPipelineRunsFromSql(getDb());
278
- const target = filePath || _resolveFilePath('pipeline-runs.json');
279
- shared.safeWrite(target, obj);
280
- const h = _fileContentHash(target);
281
- if (h != null) _pipelineRunsHash = h;
282
- } catch { /* mirror best-effort */ }
283
- }
284
-
285
146
  // ─── managed_processes ─────────────────────────────────────────────────────
286
147
  // Shape: { specs: [ {name, ...}, ... ] }
287
148
  // SQL: row per name.
288
149
 
289
- let _managedProcessesHash = null;
290
-
291
- function _hydrateManagedProcesses(db) {
292
- const fp = _resolveFilePath('managed-processes.json');
293
- const raw = _readJson(fp) || {};
294
- db.prepare('DELETE FROM managed_processes').run();
295
- const specs = Array.isArray(raw.specs) ? raw.specs : [];
296
- const now = Date.now();
297
- const ins = db.prepare('INSERT INTO managed_processes (name, data, updated_at) VALUES (?, ?, ?) ON CONFLICT(name) DO NOTHING');
298
- for (const spec of specs) {
299
- if (!spec || !spec.name) continue;
300
- ins.run(String(spec.name), JSON.stringify(spec), now);
301
- }
302
- }
303
-
304
- function _resyncManagedProcessesIfDiverged(db) {
305
- const fp = _resolveFilePath('managed-processes.json');
306
- const currentHash = _fileContentHash(fp);
307
- if (currentHash == null) return;
308
- if (_managedProcessesHash != null && currentHash === _managedProcessesHash) return;
309
- if (_managedProcessesHash == null) {
310
- const sqlHas = db.prepare('SELECT 1 FROM managed_processes LIMIT 1').get();
311
- if (sqlHas) { _managedProcessesHash = currentHash; return; }
312
- }
313
- _hydrateManagedProcesses(db);
314
- _managedProcessesHash = currentHash;
315
- }
316
-
317
150
  function _readManagedProcessesFromSql(db) {
318
151
  const rows = db.prepare('SELECT data FROM managed_processes ORDER BY rowid').all();
319
152
  const specs = [];
@@ -325,15 +158,7 @@ function _readManagedProcessesFromSql(db) {
325
158
 
326
159
  function readManagedProcesses() {
327
160
  const { getDb } = require('./db');
328
- const db = getDb();
329
- _resyncManagedProcessesIfDiverged(db);
330
- const out = _readManagedProcessesFromSql(db);
331
- if (out.specs.length === 0) {
332
- const fallback = _readJson(_resolveFilePath('managed-processes.json'));
333
- if (fallback && Array.isArray(fallback.specs) && fallback.specs.length > 0) return fallback;
334
- return { specs: [] };
335
- }
336
- return out;
161
+ return _readManagedProcessesFromSql(getDb());
337
162
  }
338
163
 
339
164
  function applyManagedProcessesMutation(mutator) {
@@ -343,7 +168,6 @@ function applyManagedProcessesMutation(mutator) {
343
168
  catch (e) { throw new Error(`small-state-store: SQLite unavailable (${e.message})`); }
344
169
 
345
170
  return withTransaction(db, () => {
346
- _resyncManagedProcessesIfDiverged(db);
347
171
  const before = _readManagedProcessesFromSql(db);
348
172
  const beforeSnap = JSON.parse(JSON.stringify(before));
349
173
  const next = mutator(before);
@@ -382,56 +206,15 @@ function applyManagedProcessesMutation(mutator) {
382
206
  });
383
207
  }
384
208
 
385
- function _mirrorManagedProcessesJson(filePath) {
386
- try {
387
- const shared = require('./shared');
388
- const { getDb } = require('./db');
389
- const obj = _readManagedProcessesFromSql(getDb());
390
- const target = filePath || _resolveFilePath('managed-processes.json');
391
- shared.safeWrite(target, obj);
392
- const h = _fileContentHash(target);
393
- if (h != null) _managedProcessesHash = h;
394
- } catch { /* mirror best-effort */ }
395
- }
396
-
397
209
  // ─── worktree_pool ─────────────────────────────────────────────────────────
398
210
  // Shape: { entries: [ {path, ...}, ... ] }
399
211
  // SQL: row per entry, keyed by the worktree path (unique).
400
212
 
401
- let _worktreePoolHash = null;
402
-
403
213
  function _entryKey(entry) {
404
214
  if (!entry || typeof entry !== 'object') return null;
405
215
  return entry.path || entry.id || null;
406
216
  }
407
217
 
408
- function _hydrateWorktreePool(db) {
409
- const fp = _resolveFilePath('worktree-pool.json');
410
- const raw = _readJson(fp) || {};
411
- db.prepare('DELETE FROM worktree_pool').run();
412
- const entries = Array.isArray(raw.entries) ? raw.entries : [];
413
- const now = Date.now();
414
- const ins = db.prepare('INSERT INTO worktree_pool (entry_id, data, updated_at) VALUES (?, ?, ?) ON CONFLICT(entry_id) DO NOTHING');
415
- for (const entry of entries) {
416
- const id = _entryKey(entry);
417
- if (!id) continue;
418
- ins.run(String(id), JSON.stringify(entry), now);
419
- }
420
- }
421
-
422
- function _resyncWorktreePoolIfDiverged(db) {
423
- const fp = _resolveFilePath('worktree-pool.json');
424
- const currentHash = _fileContentHash(fp);
425
- if (currentHash == null) return;
426
- if (_worktreePoolHash != null && currentHash === _worktreePoolHash) return;
427
- if (_worktreePoolHash == null) {
428
- const sqlHas = db.prepare('SELECT 1 FROM worktree_pool LIMIT 1').get();
429
- if (sqlHas) { _worktreePoolHash = currentHash; return; }
430
- }
431
- _hydrateWorktreePool(db);
432
- _worktreePoolHash = currentHash;
433
- }
434
-
435
218
  function _readWorktreePoolFromSql(db) {
436
219
  const rows = db.prepare('SELECT data FROM worktree_pool ORDER BY rowid').all();
437
220
  const entries = [];
@@ -443,15 +226,7 @@ function _readWorktreePoolFromSql(db) {
443
226
 
444
227
  function readWorktreePool() {
445
228
  const { getDb } = require('./db');
446
- const db = getDb();
447
- _resyncWorktreePoolIfDiverged(db);
448
- const out = _readWorktreePoolFromSql(db);
449
- if (out.entries.length === 0) {
450
- const fallback = _readJson(_resolveFilePath('worktree-pool.json'));
451
- if (fallback && Array.isArray(fallback.entries) && fallback.entries.length > 0) return fallback;
452
- return { entries: [] };
453
- }
454
- return out;
229
+ return _readWorktreePoolFromSql(getDb());
455
230
  }
456
231
 
457
232
  function applyWorktreePoolMutation(mutator) {
@@ -461,7 +236,6 @@ function applyWorktreePoolMutation(mutator) {
461
236
  catch (e) { throw new Error(`small-state-store: SQLite unavailable (${e.message})`); }
462
237
 
463
238
  return withTransaction(db, () => {
464
- _resyncWorktreePoolIfDiverged(db);
465
239
  const before = _readWorktreePoolFromSql(db);
466
240
  const beforeSnap = JSON.parse(JSON.stringify(before));
467
241
  const next = mutator(before);
@@ -501,67 +275,12 @@ function applyWorktreePoolMutation(mutator) {
501
275
  });
502
276
  }
503
277
 
504
- function _mirrorWorktreePoolJson(filePath) {
505
- try {
506
- const shared = require('./shared');
507
- const { getDb } = require('./db');
508
- const obj = _readWorktreePoolFromSql(getDb());
509
- const target = filePath || _resolveFilePath('worktree-pool.json');
510
- shared.safeWrite(target, obj);
511
- const h = _fileContentHash(target);
512
- if (h != null) _worktreePoolHash = h;
513
- } catch { /* mirror best-effort */ }
514
- }
515
-
516
278
  // ─── qa_runs ───────────────────────────────────────────────────────────────
517
279
  // Shape: [ {id, runbookId, targetName, project, workItemId, status, startedAt,
518
280
  // completedAt, createdAt, artifacts, summary, ...}, ... ]
519
281
  // SQL: row per id, extracted query columns + JSON blob `data`.
520
282
  // Pattern: mirrors watches-store (top-level array, id-keyed diff).
521
283
 
522
- let _qaRunsHash = null;
523
-
524
- function _hydrateQaRuns(db) {
525
- const fp = _resolveFilePath('qa-runs.json');
526
- const raw = _readJson(fp) || [];
527
- if (!Array.isArray(raw)) return;
528
- db.prepare('DELETE FROM qa_runs').run();
529
- const now = Date.now();
530
- const ins = db.prepare(`
531
- INSERT INTO qa_runs (id, runbook_id, target_name, project, work_item_id, status, started_at, completed_at, created_at, data)
532
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
533
- ON CONFLICT(id) DO NOTHING
534
- `);
535
- for (const run of raw) {
536
- if (!run || !run.id) continue;
537
- ins.run(
538
- String(run.id),
539
- String(run.runbookId || ''),
540
- String(run.targetName || ''),
541
- run.project || null,
542
- run.workItemId || null,
543
- String(run.status || 'pending'),
544
- _toMs(run.startedAt),
545
- _toMs(run.completedAt),
546
- _toMs(run.createdAt) || now,
547
- JSON.stringify(run),
548
- );
549
- }
550
- }
551
-
552
- function _resyncQaRunsIfDiverged(db) {
553
- const fp = _resolveFilePath('qa-runs.json');
554
- const currentHash = _fileContentHash(fp);
555
- if (currentHash == null) return;
556
- if (_qaRunsHash != null && currentHash === _qaRunsHash) return;
557
- if (_qaRunsHash == null) {
558
- const sqlHas = db.prepare('SELECT 1 FROM qa_runs LIMIT 1').get();
559
- if (sqlHas) { _qaRunsHash = currentHash; return; }
560
- }
561
- _hydrateQaRuns(db);
562
- _qaRunsHash = currentHash;
563
- }
564
-
565
284
  function _readQaRunsFromSqlOnly(db) {
566
285
  const rows = db.prepare('SELECT data FROM qa_runs ORDER BY created_at, rowid').all();
567
286
  const out = [];
@@ -573,15 +292,7 @@ function _readQaRunsFromSqlOnly(db) {
573
292
 
574
293
  function readQaRuns() {
575
294
  const { getDb } = require('./db');
576
- const db = getDb();
577
- _resyncQaRunsIfDiverged(db);
578
- const out = _readQaRunsFromSqlOnly(db);
579
- if (out.length === 0) {
580
- const fallback = _readJson(_resolveFilePath('qa-runs.json'));
581
- if (Array.isArray(fallback) && fallback.length > 0) return fallback;
582
- return [];
583
- }
584
- return out;
295
+ return _readQaRunsFromSqlOnly(getDb());
585
296
  }
586
297
 
587
298
  function applyQaRunsMutation(mutator) {
@@ -591,7 +302,6 @@ function applyQaRunsMutation(mutator) {
591
302
  catch (e) { throw new Error(`small-state-store: SQLite unavailable (${e.message})`); }
592
303
 
593
304
  return withTransaction(db, () => {
594
- _resyncQaRunsIfDiverged(db);
595
305
  const before = _readQaRunsFromSqlOnly(db);
596
306
  const beforeSnap = JSON.parse(JSON.stringify(before));
597
307
  const next = mutator(before);
@@ -651,26 +361,12 @@ function applyQaRunsMutation(mutator) {
651
361
  });
652
362
  }
653
363
 
654
- function _mirrorQaRunsJson(filePath) {
655
- try {
656
- const shared = require('./shared');
657
- const { getDb } = require('./db');
658
- const arr = _readQaRunsFromSqlOnly(getDb());
659
- const target = filePath || _resolveFilePath('qa-runs.json');
660
- shared.safeWrite(target, arr);
661
- const h = _fileContentHash(target);
662
- if (h != null) _qaRunsHash = h;
663
- } catch { /* mirror best-effort */ }
664
- }
665
-
666
364
  // ─── qa_sessions ───────────────────────────────────────────────────────────
667
365
  // Shape: [ {id, state, spec:{...}, primaryProject, coServices, setupStatus,
668
366
  // workItems, managedSpawnName, qaRunId, testFile, summary,
669
367
  // failureClass, error, createdAt, updatedAt, completedAt, ...}, ... ]
670
368
  // SQL: row per id, extracted query columns + JSON blob.
671
369
 
672
- let _qaSessionsHash = null;
673
-
674
370
  function _qaSessionPrimaryProject(session) {
675
371
  if (!session || typeof session !== 'object') return null;
676
372
  if (session.primaryProject) return String(session.primaryProject);
@@ -681,45 +377,6 @@ function _qaSessionPrimaryProject(session) {
681
377
  return null;
682
378
  }
683
379
 
684
- function _hydrateQaSessions(db) {
685
- const fp = _resolveFilePath('qa-sessions.json');
686
- const raw = _readJson(fp) || [];
687
- if (!Array.isArray(raw)) return;
688
- db.prepare('DELETE FROM qa_sessions').run();
689
- const now = Date.now();
690
- const ins = db.prepare(`
691
- INSERT INTO qa_sessions (id, state, primary_project, qa_run_id, created_at, updated_at, completed_at, data)
692
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
693
- ON CONFLICT(id) DO NOTHING
694
- `);
695
- for (const session of raw) {
696
- if (!session || !session.id) continue;
697
- ins.run(
698
- String(session.id),
699
- String(session.state || 'pending'),
700
- _qaSessionPrimaryProject(session),
701
- session.qaRunId || null,
702
- _toMs(session.createdAt) || now,
703
- _toMs(session.updatedAt) || _toMs(session.createdAt) || now,
704
- _toMs(session.completedAt),
705
- JSON.stringify(session),
706
- );
707
- }
708
- }
709
-
710
- function _resyncQaSessionsIfDiverged(db) {
711
- const fp = _resolveFilePath('qa-sessions.json');
712
- const currentHash = _fileContentHash(fp);
713
- if (currentHash == null) return;
714
- if (_qaSessionsHash != null && currentHash === _qaSessionsHash) return;
715
- if (_qaSessionsHash == null) {
716
- const sqlHas = db.prepare('SELECT 1 FROM qa_sessions LIMIT 1').get();
717
- if (sqlHas) { _qaSessionsHash = currentHash; return; }
718
- }
719
- _hydrateQaSessions(db);
720
- _qaSessionsHash = currentHash;
721
- }
722
-
723
380
  function _readQaSessionsFromSqlOnly(db) {
724
381
  const rows = db.prepare('SELECT data FROM qa_sessions ORDER BY created_at, rowid').all();
725
382
  const out = [];
@@ -731,15 +388,7 @@ function _readQaSessionsFromSqlOnly(db) {
731
388
 
732
389
  function readQaSessions() {
733
390
  const { getDb } = require('./db');
734
- const db = getDb();
735
- _resyncQaSessionsIfDiverged(db);
736
- const out = _readQaSessionsFromSqlOnly(db);
737
- if (out.length === 0) {
738
- const fallback = _readJson(_resolveFilePath('qa-sessions.json'));
739
- if (Array.isArray(fallback) && fallback.length > 0) return fallback;
740
- return [];
741
- }
742
- return out;
391
+ return _readQaSessionsFromSqlOnly(getDb());
743
392
  }
744
393
 
745
394
  function applyQaSessionsMutation(mutator) {
@@ -749,7 +398,6 @@ function applyQaSessionsMutation(mutator) {
749
398
  catch (e) { throw new Error(`small-state-store: SQLite unavailable (${e.message})`); }
750
399
 
751
400
  return withTransaction(db, () => {
752
- _resyncQaSessionsIfDiverged(db);
753
401
  const before = _readQaSessionsFromSqlOnly(db);
754
402
  const beforeSnap = JSON.parse(JSON.stringify(before));
755
403
  const next = mutator(before);
@@ -805,52 +453,10 @@ function applyQaSessionsMutation(mutator) {
805
453
  });
806
454
  }
807
455
 
808
- function _mirrorQaSessionsJson(filePath) {
809
- try {
810
- const shared = require('./shared');
811
- const { getDb } = require('./db');
812
- const arr = _readQaSessionsFromSqlOnly(getDb());
813
- const target = filePath || _resolveFilePath('qa-sessions.json');
814
- shared.safeWrite(target, arr);
815
- const h = _fileContentHash(target);
816
- if (h != null) _qaSessionsHash = h;
817
- } catch { /* mirror best-effort */ }
818
- }
819
-
820
456
  // ─── pr_links ───────────────────────────────────────────────────────────────
821
457
  // Shape: { [prId]: <value> } where <value> is typically array of item IDs
822
458
  // but may also be a bare string (legacy). Readers normalize.
823
459
 
824
- let _prLinksHash = null;
825
-
826
- function _hydratePrLinks(db) {
827
- const fp = _resolveFilePath('pr-links.json');
828
- const raw = _readJson(fp) || {};
829
- db.prepare('DELETE FROM pr_links').run();
830
- if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return;
831
- const now = Date.now();
832
- const ins = db.prepare('INSERT INTO pr_links (pr_id, data, updated_at) VALUES (?, ?, ?) ON CONFLICT(pr_id) DO NOTHING');
833
- for (const [prId, value] of Object.entries(raw)) {
834
- ins.run(String(prId), JSON.stringify(value), now);
835
- }
836
- }
837
-
838
- function _resyncPrLinksIfDiverged(db) {
839
- const fp = _resolveFilePath('pr-links.json');
840
- const currentHash = _fileContentHash(fp);
841
- if (currentHash == null) return;
842
- if (_prLinksHash != null && currentHash === _prLinksHash) return;
843
- if (_prLinksHash == null) {
844
- const sqlHas = db.prepare('SELECT 1 FROM pr_links LIMIT 1').get();
845
- if (sqlHas) {
846
- _prLinksHash = currentHash;
847
- return;
848
- }
849
- }
850
- _hydratePrLinks(db);
851
- _prLinksHash = currentHash;
852
- }
853
-
854
460
  function _readPrLinksFromSql(db) {
855
461
  const rows = db.prepare('SELECT pr_id, data FROM pr_links').all();
856
462
  const out = {};
@@ -863,18 +469,7 @@ function _readPrLinksFromSql(db) {
863
469
 
864
470
  function readPrLinks() {
865
471
  const { getDb } = require('./db');
866
- const db = getDb();
867
- try { _resyncPrLinksIfDiverged(db); }
868
- catch { /* table may be missing on a stale install — fall back to JSON */ }
869
- let out;
870
- try { out = _readPrLinksFromSql(db); }
871
- catch { return _readJson(_resolveFilePath('pr-links.json')) || {}; }
872
- if (Object.keys(out).length === 0) {
873
- const fallback = _readJson(_resolveFilePath('pr-links.json'));
874
- if (fallback && Object.keys(fallback).length > 0) return fallback;
875
- return {};
876
- }
877
- return out;
472
+ return _readPrLinksFromSql(getDb());
878
473
  }
879
474
 
880
475
  function applyPrLinksMutation(mutator) {
@@ -884,7 +479,6 @@ function applyPrLinksMutation(mutator) {
884
479
  catch (e) { throw new Error(`small-state-store: SQLite unavailable (${e.message})`); }
885
480
 
886
481
  return withTransaction(db, () => {
887
- _resyncPrLinksIfDiverged(db);
888
482
  const before = _readPrLinksFromSql(db);
889
483
  const beforeSnap = JSON.parse(JSON.stringify(before));
890
484
  const next = mutator(before);
@@ -915,49 +509,10 @@ function applyPrLinksMutation(mutator) {
915
509
  });
916
510
  }
917
511
 
918
- function _mirrorPrLinksJson(filePath) {
919
- try {
920
- const shared = require('./shared');
921
- const { getDb } = require('./db');
922
- const obj = _readPrLinksFromSql(getDb());
923
- const target = filePath || _resolveFilePath('pr-links.json');
924
- shared.safeWrite(target, obj);
925
- const h = _fileContentHash(target);
926
- if (h != null) _prLinksHash = h;
927
- } catch { /* mirror best-effort */ }
928
- }
929
-
930
512
  // ─── cooldowns ─────────────────────────────────────────────────────────────
931
513
  // Shape: { [key]: { timestamp, failures, ... } }
932
514
  // SQL: row per key.
933
515
 
934
- let _cooldownsHash = null;
935
-
936
- function _hydrateCooldowns(db) {
937
- const fp = _resolveFilePath('cooldowns.json');
938
- const raw = _readJson(fp) || {};
939
- db.prepare('DELETE FROM cooldowns').run();
940
- if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return;
941
- const now = Date.now();
942
- const ins = db.prepare('INSERT INTO cooldowns (key, data, updated_at) VALUES (?, ?, ?) ON CONFLICT(key) DO NOTHING');
943
- for (const [key, value] of Object.entries(raw)) {
944
- ins.run(String(key), JSON.stringify(value), now);
945
- }
946
- }
947
-
948
- function _resyncCooldownsIfDiverged(db) {
949
- const fp = _resolveFilePath('cooldowns.json');
950
- const currentHash = _fileContentHash(fp);
951
- if (currentHash == null) return;
952
- if (_cooldownsHash != null && currentHash === _cooldownsHash) return;
953
- if (_cooldownsHash == null) {
954
- const sqlHas = db.prepare('SELECT 1 FROM cooldowns LIMIT 1').get();
955
- if (sqlHas) { _cooldownsHash = currentHash; return; }
956
- }
957
- _hydrateCooldowns(db);
958
- _cooldownsHash = currentHash;
959
- }
960
-
961
516
  function _readCooldownsFromSql(db) {
962
517
  const rows = db.prepare('SELECT key, data FROM cooldowns').all();
963
518
  const out = {};
@@ -970,18 +525,7 @@ function _readCooldownsFromSql(db) {
970
525
 
971
526
  function readCooldowns() {
972
527
  const { getDb } = require('./db');
973
- const db = getDb();
974
- try { _resyncCooldownsIfDiverged(db); }
975
- catch { /* table may be missing on stale install */ }
976
- let out;
977
- try { out = _readCooldownsFromSql(db); }
978
- catch { return _readJson(_resolveFilePath('cooldowns.json')) || {}; }
979
- if (Object.keys(out).length === 0) {
980
- const fallback = _readJson(_resolveFilePath('cooldowns.json'));
981
- if (fallback && Object.keys(fallback).length > 0) return fallback;
982
- return {};
983
- }
984
- return out;
528
+ return _readCooldownsFromSql(getDb());
985
529
  }
986
530
 
987
531
  function applyCooldownsMutation(mutator) {
@@ -991,7 +535,6 @@ function applyCooldownsMutation(mutator) {
991
535
  catch (e) { throw new Error(`small-state-store: SQLite unavailable (${e.message})`); }
992
536
 
993
537
  return withTransaction(db, () => {
994
- _resyncCooldownsIfDiverged(db);
995
538
  const before = _readCooldownsFromSql(db);
996
539
  const beforeSnap = JSON.parse(JSON.stringify(before));
997
540
  const next = mutator(before);
@@ -1022,51 +565,11 @@ function applyCooldownsMutation(mutator) {
1022
565
  });
1023
566
  }
1024
567
 
1025
- function _mirrorCooldownsJson(filePath) {
1026
- try {
1027
- const shared = require('./shared');
1028
- const { getDb } = require('./db');
1029
- const obj = _readCooldownsFromSql(getDb());
1030
- const target = filePath || _resolveFilePath('cooldowns.json');
1031
- shared.safeWrite(target, obj);
1032
- const h = _fileContentHash(target);
1033
- if (h != null) _cooldownsHash = h;
1034
- } catch { /* mirror best-effort */ }
1035
- }
1036
-
1037
568
  // ─── pending_rebases ───────────────────────────────────────────────────────
1038
569
  // Shape: [ { prId, branch, projectName, mergedItemId, queuedAt, attempts, ... }, ... ]
1039
570
  // SQL: row per array entry (rowid auto-increment preserves insertion order).
1040
571
  // No stable natural key, so mutations are full clear+insert.
1041
572
 
1042
- let _pendingRebasesHash = null;
1043
-
1044
- function _hydratePendingRebases(db) {
1045
- const fp = _resolveFilePath('pending-rebases.json');
1046
- const raw = _readJson(fp) || [];
1047
- db.prepare('DELETE FROM pending_rebases').run();
1048
- if (!Array.isArray(raw)) return;
1049
- const now = Date.now();
1050
- const ins = db.prepare('INSERT INTO pending_rebases (data, updated_at) VALUES (?, ?)');
1051
- for (const entry of raw) {
1052
- if (!entry || typeof entry !== 'object') continue;
1053
- ins.run(JSON.stringify(entry), now);
1054
- }
1055
- }
1056
-
1057
- function _resyncPendingRebasesIfDiverged(db) {
1058
- const fp = _resolveFilePath('pending-rebases.json');
1059
- const currentHash = _fileContentHash(fp);
1060
- if (currentHash == null) return;
1061
- if (_pendingRebasesHash != null && currentHash === _pendingRebasesHash) return;
1062
- if (_pendingRebasesHash == null) {
1063
- const sqlHas = db.prepare('SELECT 1 FROM pending_rebases LIMIT 1').get();
1064
- if (sqlHas) { _pendingRebasesHash = currentHash; return; }
1065
- }
1066
- _hydratePendingRebases(db);
1067
- _pendingRebasesHash = currentHash;
1068
- }
1069
-
1070
573
  function _readPendingRebasesFromSql(db) {
1071
574
  const rows = db.prepare('SELECT data FROM pending_rebases ORDER BY seq').all();
1072
575
  const out = [];
@@ -1079,18 +582,7 @@ function _readPendingRebasesFromSql(db) {
1079
582
 
1080
583
  function readPendingRebases() {
1081
584
  const { getDb } = require('./db');
1082
- const db = getDb();
1083
- try { _resyncPendingRebasesIfDiverged(db); }
1084
- catch { /* table missing */ }
1085
- let out;
1086
- try { out = _readPendingRebasesFromSql(db); }
1087
- catch { return _readJson(_resolveFilePath('pending-rebases.json')) || []; }
1088
- if (out.length === 0) {
1089
- const fallback = _readJson(_resolveFilePath('pending-rebases.json'));
1090
- if (Array.isArray(fallback) && fallback.length > 0) return fallback;
1091
- return [];
1092
- }
1093
- return out;
585
+ return _readPendingRebasesFromSql(getDb());
1094
586
  }
1095
587
 
1096
588
  function applyPendingRebasesMutation(mutator) {
@@ -1100,7 +592,6 @@ function applyPendingRebasesMutation(mutator) {
1100
592
  catch (e) { throw new Error(`small-state-store: SQLite unavailable (${e.message})`); }
1101
593
 
1102
594
  return withTransaction(db, () => {
1103
- _resyncPendingRebasesIfDiverged(db);
1104
595
  const before = _readPendingRebasesFromSql(db);
1105
596
  const beforeSnap = JSON.parse(JSON.stringify(before));
1106
597
  const next = mutator(before);
@@ -1123,50 +614,10 @@ function applyPendingRebasesMutation(mutator) {
1123
614
  });
1124
615
  }
1125
616
 
1126
- function _mirrorPendingRebasesJson(filePath) {
1127
- try {
1128
- const shared = require('./shared');
1129
- const { getDb } = require('./db');
1130
- const arr = _readPendingRebasesFromSql(getDb());
1131
- const target = filePath || _resolveFilePath('pending-rebases.json');
1132
- shared.safeWrite(target, arr);
1133
- const h = _fileContentHash(target);
1134
- if (h != null) _pendingRebasesHash = h;
1135
- } catch { /* mirror best-effort */ }
1136
- }
1137
-
1138
617
  // ─── cc_sessions ───────────────────────────────────────────────────────────
1139
618
  // Shape: [ { id, sessionId, title, _promptHash, lastActiveAt, ... }, ... ]
1140
619
  // SQL: row per id (each entry has a unique `id` tab key).
1141
620
 
1142
- let _ccSessionsHash = null;
1143
-
1144
- function _hydrateCcSessions(db) {
1145
- const fp = _resolveFilePath('cc-sessions.json');
1146
- const raw = _readJson(fp) || [];
1147
- db.prepare('DELETE FROM cc_sessions').run();
1148
- if (!Array.isArray(raw)) return;
1149
- const now = Date.now();
1150
- const ins = db.prepare('INSERT INTO cc_sessions (id, data, updated_at) VALUES (?, ?, ?) ON CONFLICT(id) DO NOTHING');
1151
- for (const entry of raw) {
1152
- if (!entry || typeof entry !== 'object' || !entry.id) continue;
1153
- ins.run(String(entry.id), JSON.stringify(entry), now);
1154
- }
1155
- }
1156
-
1157
- function _resyncCcSessionsIfDiverged(db) {
1158
- const fp = _resolveFilePath('cc-sessions.json');
1159
- const currentHash = _fileContentHash(fp);
1160
- if (currentHash == null) return;
1161
- if (_ccSessionsHash != null && currentHash === _ccSessionsHash) return;
1162
- if (_ccSessionsHash == null) {
1163
- const sqlHas = db.prepare('SELECT 1 FROM cc_sessions LIMIT 1').get();
1164
- if (sqlHas) { _ccSessionsHash = currentHash; return; }
1165
- }
1166
- _hydrateCcSessions(db);
1167
- _ccSessionsHash = currentHash;
1168
- }
1169
-
1170
621
  function _readCcSessionsFromSql(db) {
1171
622
  const rows = db.prepare('SELECT data FROM cc_sessions ORDER BY updated_at, id').all();
1172
623
  const out = [];
@@ -1179,18 +630,7 @@ function _readCcSessionsFromSql(db) {
1179
630
 
1180
631
  function readCcSessions() {
1181
632
  const { getDb } = require('./db');
1182
- const db = getDb();
1183
- try { _resyncCcSessionsIfDiverged(db); }
1184
- catch { /* table missing */ }
1185
- let out;
1186
- try { out = _readCcSessionsFromSql(db); }
1187
- catch { return _readJson(_resolveFilePath('cc-sessions.json')) || []; }
1188
- if (out.length === 0) {
1189
- const fallback = _readJson(_resolveFilePath('cc-sessions.json'));
1190
- if (Array.isArray(fallback) && fallback.length > 0) return fallback;
1191
- return [];
1192
- }
1193
- return out;
633
+ return _readCcSessionsFromSql(getDb());
1194
634
  }
1195
635
 
1196
636
  function applyCcSessionsMutation(mutator) {
@@ -1200,7 +640,6 @@ function applyCcSessionsMutation(mutator) {
1200
640
  catch (e) { throw new Error(`small-state-store: SQLite unavailable (${e.message})`); }
1201
641
 
1202
642
  return withTransaction(db, () => {
1203
- _resyncCcSessionsIfDiverged(db);
1204
643
  const before = _readCcSessionsFromSql(db);
1205
644
  const beforeSnap = JSON.parse(JSON.stringify(before));
1206
645
  const next = mutator(before);
@@ -1232,49 +671,10 @@ function applyCcSessionsMutation(mutator) {
1232
671
  });
1233
672
  }
1234
673
 
1235
- function _mirrorCcSessionsJson(filePath) {
1236
- try {
1237
- const shared = require('./shared');
1238
- const { getDb } = require('./db');
1239
- const arr = _readCcSessionsFromSql(getDb());
1240
- const target = filePath || _resolveFilePath('cc-sessions.json');
1241
- shared.safeWrite(target, arr);
1242
- const h = _fileContentHash(target);
1243
- if (h != null) _ccSessionsHash = h;
1244
- } catch { /* mirror best-effort */ }
1245
- }
1246
-
1247
674
  // ─── doc_sessions ──────────────────────────────────────────────────────────
1248
675
  // Shape: { [filePath]: { sessionId, lastActiveAt, turnCount, ... } }
1249
676
  // SQL: row per filePath key.
1250
677
 
1251
- let _docSessionsHash = null;
1252
-
1253
- function _hydrateDocSessions(db) {
1254
- const fp = _resolveFilePath('doc-sessions.json');
1255
- const raw = _readJson(fp) || {};
1256
- db.prepare('DELETE FROM doc_sessions').run();
1257
- if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return;
1258
- const now = Date.now();
1259
- const ins = db.prepare('INSERT INTO doc_sessions (key, data, updated_at) VALUES (?, ?, ?) ON CONFLICT(key) DO NOTHING');
1260
- for (const [key, value] of Object.entries(raw)) {
1261
- ins.run(String(key), JSON.stringify(value), now);
1262
- }
1263
- }
1264
-
1265
- function _resyncDocSessionsIfDiverged(db) {
1266
- const fp = _resolveFilePath('doc-sessions.json');
1267
- const currentHash = _fileContentHash(fp);
1268
- if (currentHash == null) return;
1269
- if (_docSessionsHash != null && currentHash === _docSessionsHash) return;
1270
- if (_docSessionsHash == null) {
1271
- const sqlHas = db.prepare('SELECT 1 FROM doc_sessions LIMIT 1').get();
1272
- if (sqlHas) { _docSessionsHash = currentHash; return; }
1273
- }
1274
- _hydrateDocSessions(db);
1275
- _docSessionsHash = currentHash;
1276
- }
1277
-
1278
678
  function _readDocSessionsFromSql(db) {
1279
679
  const rows = db.prepare('SELECT key, data FROM doc_sessions').all();
1280
680
  const out = {};
@@ -1287,18 +687,7 @@ function _readDocSessionsFromSql(db) {
1287
687
 
1288
688
  function readDocSessions() {
1289
689
  const { getDb } = require('./db');
1290
- const db = getDb();
1291
- try { _resyncDocSessionsIfDiverged(db); }
1292
- catch { /* table missing */ }
1293
- let out;
1294
- try { out = _readDocSessionsFromSql(db); }
1295
- catch { return _readJson(_resolveFilePath('doc-sessions.json')) || {}; }
1296
- if (Object.keys(out).length === 0) {
1297
- const fallback = _readJson(_resolveFilePath('doc-sessions.json'));
1298
- if (fallback && Object.keys(fallback).length > 0) return fallback;
1299
- return {};
1300
- }
1301
- return out;
690
+ return _readDocSessionsFromSql(getDb());
1302
691
  }
1303
692
 
1304
693
  function applyDocSessionsMutation(mutator) {
@@ -1308,7 +697,6 @@ function applyDocSessionsMutation(mutator) {
1308
697
  catch (e) { throw new Error(`small-state-store: SQLite unavailable (${e.message})`); }
1309
698
 
1310
699
  return withTransaction(db, () => {
1311
- _resyncDocSessionsIfDiverged(db);
1312
700
  const before = _readDocSessionsFromSql(db);
1313
701
  const beforeSnap = JSON.parse(JSON.stringify(before));
1314
702
  const next = mutator(before);
@@ -1339,61 +727,38 @@ function applyDocSessionsMutation(mutator) {
1339
727
  });
1340
728
  }
1341
729
 
1342
- function _mirrorDocSessionsJson(filePath) {
1343
- try {
1344
- const shared = require('./shared');
1345
- const { getDb } = require('./db');
1346
- const obj = _readDocSessionsFromSql(getDb());
1347
- const target = filePath || _resolveFilePath('doc-sessions.json');
1348
- shared.safeWrite(target, obj);
1349
- const h = _fileContentHash(target);
1350
- if (h != null) _docSessionsHash = h;
1351
- } catch { /* mirror best-effort */ }
1352
- }
1353
-
1354
730
  module.exports = {
1355
731
  // schedule_runs
1356
732
  readScheduleRuns,
1357
733
  applyScheduleRunsMutation,
1358
- _mirrorScheduleRunsJson,
1359
734
  // pipeline_runs
1360
735
  readPipelineRuns,
1361
736
  applyPipelineRunsMutation,
1362
- _mirrorPipelineRunsJson,
1363
737
  // managed_processes
1364
738
  readManagedProcesses,
1365
739
  applyManagedProcessesMutation,
1366
- _mirrorManagedProcessesJson,
1367
740
  // worktree_pool
1368
741
  readWorktreePool,
1369
742
  applyWorktreePoolMutation,
1370
- _mirrorWorktreePoolJson,
1371
743
  // qa_runs
1372
744
  readQaRuns,
1373
745
  applyQaRunsMutation,
1374
- _mirrorQaRunsJson,
1375
746
  // qa_sessions
1376
747
  readQaSessions,
1377
748
  applyQaSessionsMutation,
1378
- _mirrorQaSessionsJson,
1379
749
  // pr_links
1380
750
  readPrLinks,
1381
751
  applyPrLinksMutation,
1382
- _mirrorPrLinksJson,
1383
752
  // cooldowns
1384
753
  readCooldowns,
1385
754
  applyCooldownsMutation,
1386
- _mirrorCooldownsJson,
1387
755
  // pending_rebases
1388
756
  readPendingRebases,
1389
757
  applyPendingRebasesMutation,
1390
- _mirrorPendingRebasesJson,
1391
758
  // cc_sessions
1392
759
  readCcSessions,
1393
760
  applyCcSessionsMutation,
1394
- _mirrorCcSessionsJson,
1395
761
  // doc_sessions
1396
762
  readDocSessions,
1397
763
  applyDocSessionsMutation,
1398
- _mirrorDocSessionsJson,
1399
764
  };