opencastle 0.27.0 → 0.27.2

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 (242) hide show
  1. package/bin/cli.mjs +6 -0
  2. package/dist/cli/agents.d.ts +3 -0
  3. package/dist/cli/agents.d.ts.map +1 -0
  4. package/dist/cli/agents.js +161 -0
  5. package/dist/cli/agents.js.map +1 -0
  6. package/dist/cli/baselines.d.ts +3 -0
  7. package/dist/cli/baselines.d.ts.map +1 -0
  8. package/dist/cli/baselines.js +128 -0
  9. package/dist/cli/baselines.js.map +1 -0
  10. package/dist/cli/convoy/dashboard-types.d.ts +146 -0
  11. package/dist/cli/convoy/dashboard-types.d.ts.map +1 -0
  12. package/dist/cli/convoy/dashboard-types.js +2 -0
  13. package/dist/cli/convoy/dashboard-types.js.map +1 -0
  14. package/dist/cli/convoy/engine.d.ts +67 -2
  15. package/dist/cli/convoy/engine.d.ts.map +1 -1
  16. package/dist/cli/convoy/engine.js +2036 -28
  17. package/dist/cli/convoy/engine.js.map +1 -1
  18. package/dist/cli/convoy/engine.test.js +1659 -70
  19. package/dist/cli/convoy/engine.test.js.map +1 -1
  20. package/dist/cli/convoy/event-schemas.d.ts +9 -0
  21. package/dist/cli/convoy/event-schemas.d.ts.map +1 -0
  22. package/dist/cli/convoy/event-schemas.js +185 -0
  23. package/dist/cli/convoy/event-schemas.js.map +1 -0
  24. package/dist/cli/convoy/events.d.ts +12 -1
  25. package/dist/cli/convoy/events.d.ts.map +1 -1
  26. package/dist/cli/convoy/events.js +186 -13
  27. package/dist/cli/convoy/events.js.map +1 -1
  28. package/dist/cli/convoy/events.test.js +325 -28
  29. package/dist/cli/convoy/events.test.js.map +1 -1
  30. package/dist/cli/convoy/expertise.d.ts +16 -0
  31. package/dist/cli/convoy/expertise.d.ts.map +1 -0
  32. package/dist/cli/convoy/expertise.js +121 -0
  33. package/dist/cli/convoy/expertise.js.map +1 -0
  34. package/dist/cli/convoy/expertise.test.d.ts +2 -0
  35. package/dist/cli/convoy/expertise.test.d.ts.map +1 -0
  36. package/dist/cli/convoy/expertise.test.js +96 -0
  37. package/dist/cli/convoy/expertise.test.js.map +1 -0
  38. package/dist/cli/convoy/export.test.js +1 -0
  39. package/dist/cli/convoy/export.test.js.map +1 -1
  40. package/dist/cli/convoy/formula.d.ts +19 -0
  41. package/dist/cli/convoy/formula.d.ts.map +1 -0
  42. package/dist/cli/convoy/formula.js +142 -0
  43. package/dist/cli/convoy/formula.js.map +1 -0
  44. package/dist/cli/convoy/formula.test.d.ts +2 -0
  45. package/dist/cli/convoy/formula.test.d.ts.map +1 -0
  46. package/dist/cli/convoy/formula.test.js +342 -0
  47. package/dist/cli/convoy/formula.test.js.map +1 -0
  48. package/dist/cli/convoy/gates.d.ts +128 -0
  49. package/dist/cli/convoy/gates.d.ts.map +1 -0
  50. package/dist/cli/convoy/gates.js +606 -0
  51. package/dist/cli/convoy/gates.js.map +1 -0
  52. package/dist/cli/convoy/gates.test.d.ts +2 -0
  53. package/dist/cli/convoy/gates.test.d.ts.map +1 -0
  54. package/dist/cli/convoy/gates.test.js +976 -0
  55. package/dist/cli/convoy/gates.test.js.map +1 -0
  56. package/dist/cli/convoy/health.d.ts +11 -0
  57. package/dist/cli/convoy/health.d.ts.map +1 -1
  58. package/dist/cli/convoy/health.js +54 -0
  59. package/dist/cli/convoy/health.js.map +1 -1
  60. package/dist/cli/convoy/health.test.js +56 -1
  61. package/dist/cli/convoy/health.test.js.map +1 -1
  62. package/dist/cli/convoy/issues.d.ts +8 -0
  63. package/dist/cli/convoy/issues.d.ts.map +1 -0
  64. package/dist/cli/convoy/issues.js +98 -0
  65. package/dist/cli/convoy/issues.js.map +1 -0
  66. package/dist/cli/convoy/issues.test.d.ts +2 -0
  67. package/dist/cli/convoy/issues.test.d.ts.map +1 -0
  68. package/dist/cli/convoy/issues.test.js +107 -0
  69. package/dist/cli/convoy/issues.test.js.map +1 -0
  70. package/dist/cli/convoy/knowledge.d.ts +5 -0
  71. package/dist/cli/convoy/knowledge.d.ts.map +1 -0
  72. package/dist/cli/convoy/knowledge.js +116 -0
  73. package/dist/cli/convoy/knowledge.js.map +1 -0
  74. package/dist/cli/convoy/knowledge.test.d.ts +2 -0
  75. package/dist/cli/convoy/knowledge.test.d.ts.map +1 -0
  76. package/dist/cli/convoy/knowledge.test.js +87 -0
  77. package/dist/cli/convoy/knowledge.test.js.map +1 -0
  78. package/dist/cli/convoy/lessons.d.ts +17 -0
  79. package/dist/cli/convoy/lessons.d.ts.map +1 -0
  80. package/dist/cli/convoy/lessons.js +149 -0
  81. package/dist/cli/convoy/lessons.js.map +1 -0
  82. package/dist/cli/convoy/lessons.test.d.ts +2 -0
  83. package/dist/cli/convoy/lessons.test.d.ts.map +1 -0
  84. package/dist/cli/convoy/lessons.test.js +135 -0
  85. package/dist/cli/convoy/lessons.test.js.map +1 -0
  86. package/dist/cli/convoy/lock.d.ts +13 -0
  87. package/dist/cli/convoy/lock.d.ts.map +1 -0
  88. package/dist/cli/convoy/lock.js +88 -0
  89. package/dist/cli/convoy/lock.js.map +1 -0
  90. package/dist/cli/convoy/lock.test.d.ts +2 -0
  91. package/dist/cli/convoy/lock.test.d.ts.map +1 -0
  92. package/dist/cli/convoy/lock.test.js +136 -0
  93. package/dist/cli/convoy/lock.test.js.map +1 -0
  94. package/dist/cli/convoy/log-merge.test.d.ts +2 -0
  95. package/dist/cli/convoy/log-merge.test.d.ts.map +1 -0
  96. package/dist/cli/convoy/log-merge.test.js +147 -0
  97. package/dist/cli/convoy/log-merge.test.js.map +1 -0
  98. package/dist/cli/convoy/merge.d.ts +4 -0
  99. package/dist/cli/convoy/merge.d.ts.map +1 -1
  100. package/dist/cli/convoy/merge.js +18 -1
  101. package/dist/cli/convoy/merge.js.map +1 -1
  102. package/dist/cli/convoy/merge.test.js +6 -7
  103. package/dist/cli/convoy/merge.test.js.map +1 -1
  104. package/dist/cli/convoy/partition.d.ts +51 -0
  105. package/dist/cli/convoy/partition.d.ts.map +1 -0
  106. package/dist/cli/convoy/partition.js +186 -0
  107. package/dist/cli/convoy/partition.js.map +1 -0
  108. package/dist/cli/convoy/partition.test.d.ts +2 -0
  109. package/dist/cli/convoy/partition.test.d.ts.map +1 -0
  110. package/dist/cli/convoy/partition.test.js +315 -0
  111. package/dist/cli/convoy/partition.test.js.map +1 -0
  112. package/dist/cli/convoy/pipeline.test.js +6 -0
  113. package/dist/cli/convoy/pipeline.test.js.map +1 -1
  114. package/dist/cli/convoy/store.d.ts +99 -7
  115. package/dist/cli/convoy/store.d.ts.map +1 -1
  116. package/dist/cli/convoy/store.js +764 -31
  117. package/dist/cli/convoy/store.js.map +1 -1
  118. package/dist/cli/convoy/store.test.js +1810 -18
  119. package/dist/cli/convoy/store.test.js.map +1 -1
  120. package/dist/cli/convoy/types.d.ts +427 -5
  121. package/dist/cli/convoy/types.d.ts.map +1 -1
  122. package/dist/cli/convoy/types.js +42 -1
  123. package/dist/cli/convoy/types.js.map +1 -1
  124. package/dist/cli/log.d.ts +11 -0
  125. package/dist/cli/log.d.ts.map +1 -1
  126. package/dist/cli/log.js +114 -2
  127. package/dist/cli/log.js.map +1 -1
  128. package/dist/cli/run/adapters/claude.d.ts +2 -0
  129. package/dist/cli/run/adapters/claude.d.ts.map +1 -1
  130. package/dist/cli/run/adapters/claude.js +89 -49
  131. package/dist/cli/run/adapters/claude.js.map +1 -1
  132. package/dist/cli/run/adapters/claude.test.d.ts +2 -0
  133. package/dist/cli/run/adapters/claude.test.d.ts.map +1 -0
  134. package/dist/cli/run/adapters/claude.test.js +205 -0
  135. package/dist/cli/run/adapters/claude.test.js.map +1 -0
  136. package/dist/cli/run/adapters/copilot.d.ts +1 -0
  137. package/dist/cli/run/adapters/copilot.d.ts.map +1 -1
  138. package/dist/cli/run/adapters/copilot.js +84 -46
  139. package/dist/cli/run/adapters/copilot.js.map +1 -1
  140. package/dist/cli/run/adapters/copilot.test.d.ts +2 -0
  141. package/dist/cli/run/adapters/copilot.test.d.ts.map +1 -0
  142. package/dist/cli/run/adapters/copilot.test.js +195 -0
  143. package/dist/cli/run/adapters/copilot.test.js.map +1 -0
  144. package/dist/cli/run/adapters/cursor.d.ts +1 -0
  145. package/dist/cli/run/adapters/cursor.d.ts.map +1 -1
  146. package/dist/cli/run/adapters/cursor.js +83 -47
  147. package/dist/cli/run/adapters/cursor.js.map +1 -1
  148. package/dist/cli/run/adapters/cursor.test.d.ts +2 -0
  149. package/dist/cli/run/adapters/cursor.test.d.ts.map +1 -0
  150. package/dist/cli/run/adapters/cursor.test.js +129 -0
  151. package/dist/cli/run/adapters/cursor.test.js.map +1 -0
  152. package/dist/cli/run/adapters/opencode.d.ts +1 -0
  153. package/dist/cli/run/adapters/opencode.d.ts.map +1 -1
  154. package/dist/cli/run/adapters/opencode.js +81 -47
  155. package/dist/cli/run/adapters/opencode.js.map +1 -1
  156. package/dist/cli/run/adapters/opencode.test.d.ts +2 -0
  157. package/dist/cli/run/adapters/opencode.test.d.ts.map +1 -0
  158. package/dist/cli/run/adapters/opencode.test.js +119 -0
  159. package/dist/cli/run/adapters/opencode.test.js.map +1 -0
  160. package/dist/cli/run/executor.js +1 -1
  161. package/dist/cli/run/executor.js.map +1 -1
  162. package/dist/cli/run/schema.d.ts.map +1 -1
  163. package/dist/cli/run/schema.js +245 -4
  164. package/dist/cli/run/schema.js.map +1 -1
  165. package/dist/cli/run/schema.test.js +669 -0
  166. package/dist/cli/run/schema.test.js.map +1 -1
  167. package/dist/cli/run.d.ts.map +1 -1
  168. package/dist/cli/run.js +362 -22
  169. package/dist/cli/run.js.map +1 -1
  170. package/dist/cli/types.d.ts +85 -2
  171. package/dist/cli/types.d.ts.map +1 -1
  172. package/dist/cli/types.js.map +1 -1
  173. package/dist/cli/watch.d.ts +15 -0
  174. package/dist/cli/watch.d.ts.map +1 -0
  175. package/dist/cli/watch.js +279 -0
  176. package/dist/cli/watch.js.map +1 -0
  177. package/package.json +5 -1
  178. package/src/cli/agents.ts +177 -0
  179. package/src/cli/baselines.ts +143 -0
  180. package/src/cli/convoy/TELEMETRY.md +203 -0
  181. package/src/cli/convoy/dashboard-types.ts +141 -0
  182. package/src/cli/convoy/engine.test.ts +1937 -70
  183. package/src/cli/convoy/engine.ts +2350 -40
  184. package/src/cli/convoy/event-schemas.ts +195 -0
  185. package/src/cli/convoy/events.test.ts +384 -39
  186. package/src/cli/convoy/events.ts +202 -16
  187. package/src/cli/convoy/expertise.test.ts +128 -0
  188. package/src/cli/convoy/expertise.ts +163 -0
  189. package/src/cli/convoy/export.test.ts +1 -0
  190. package/src/cli/convoy/formula.test.ts +405 -0
  191. package/src/cli/convoy/formula.ts +174 -0
  192. package/src/cli/convoy/gates.test.ts +1169 -0
  193. package/src/cli/convoy/gates.ts +774 -0
  194. package/src/cli/convoy/health.test.ts +64 -2
  195. package/src/cli/convoy/health.ts +80 -2
  196. package/src/cli/convoy/issues.test.ts +143 -0
  197. package/src/cli/convoy/issues.ts +136 -0
  198. package/src/cli/convoy/knowledge.test.ts +101 -0
  199. package/src/cli/convoy/knowledge.ts +132 -0
  200. package/src/cli/convoy/lessons.test.ts +188 -0
  201. package/src/cli/convoy/lessons.ts +164 -0
  202. package/src/cli/convoy/lock.test.ts +181 -0
  203. package/src/cli/convoy/lock.ts +103 -0
  204. package/src/cli/convoy/log-merge.test.ts +179 -0
  205. package/src/cli/convoy/merge.test.ts +6 -7
  206. package/src/cli/convoy/merge.ts +19 -1
  207. package/src/cli/convoy/partition.test.ts +423 -0
  208. package/src/cli/convoy/partition.ts +232 -0
  209. package/src/cli/convoy/pipeline.test.ts +6 -0
  210. package/src/cli/convoy/store.test.ts +2041 -20
  211. package/src/cli/convoy/store.ts +945 -46
  212. package/src/cli/convoy/types.ts +278 -4
  213. package/src/cli/log.ts +120 -2
  214. package/src/cli/run/adapters/claude.test.ts +234 -0
  215. package/src/cli/run/adapters/claude.ts +45 -5
  216. package/src/cli/run/adapters/copilot.test.ts +224 -0
  217. package/src/cli/run/adapters/copilot.ts +34 -4
  218. package/src/cli/run/adapters/cursor.test.ts +144 -0
  219. package/src/cli/run/adapters/cursor.ts +33 -2
  220. package/src/cli/run/adapters/opencode.test.ts +135 -0
  221. package/src/cli/run/adapters/opencode.ts +30 -2
  222. package/src/cli/run/executor.ts +1 -1
  223. package/src/cli/run/schema.test.ts +758 -0
  224. package/src/cli/run/schema.ts +300 -25
  225. package/src/cli/run.ts +341 -21
  226. package/src/cli/types.ts +86 -1
  227. package/src/cli/watch.ts +298 -0
  228. package/src/dashboard/dist/_astro/{index.DtnyD8a5.css → index.6L3_HsPT.css} +1 -1
  229. package/src/dashboard/dist/data/.gitkeep +0 -0
  230. package/src/dashboard/dist/data/convoy-list.json +1 -0
  231. package/src/dashboard/dist/data/overall-stats.json +24 -0
  232. package/src/dashboard/dist/index.html +701 -3
  233. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
  234. package/src/dashboard/public/data/.gitkeep +0 -0
  235. package/src/dashboard/public/data/convoy-list.json +1 -0
  236. package/src/dashboard/public/data/overall-stats.json +24 -0
  237. package/src/dashboard/scripts/etl.test.ts +210 -0
  238. package/src/dashboard/scripts/etl.ts +108 -0
  239. package/src/dashboard/scripts/integration-test.ts +504 -0
  240. package/src/dashboard/src/pages/index.astro +854 -15
  241. package/src/dashboard/src/styles/dashboard.css +557 -1
  242. package/src/orchestrator/prompts/generate-convoy.prompt.md +212 -13
@@ -0,0 +1,88 @@
1
+ import { hostname as getHostname } from 'node:os';
2
+ export class EngineAlreadyRunningError extends Error {
3
+ pid;
4
+ hostname;
5
+ constructor(pid, hostname) {
6
+ super(`Another opencastle process (PID ${pid} on ${hostname}) is already running against this database.`);
7
+ this.pid = pid;
8
+ this.hostname = hostname;
9
+ this.name = 'EngineAlreadyRunningError';
10
+ }
11
+ }
12
+ function checkStaleness(row) {
13
+ const heartbeatAge = Date.now() - new Date(row.last_heartbeat).getTime();
14
+ if (heartbeatAge <= 30_000)
15
+ return false;
16
+ if (row.hostname !== getHostname())
17
+ return true;
18
+ try {
19
+ process.kill(row.pid, 0);
20
+ return false; // PID is alive on this host
21
+ }
22
+ catch {
23
+ return true; // PID is dead
24
+ }
25
+ }
26
+ export function isLockStale(db) {
27
+ const row = db
28
+ .prepare('SELECT pid, hostname, last_heartbeat FROM engine_lock WHERE id = 1')
29
+ .get();
30
+ if (!row)
31
+ return true;
32
+ return checkStaleness(row);
33
+ }
34
+ export function releaseEngineLock(db) {
35
+ db.exec('DELETE FROM engine_lock WHERE id = 1');
36
+ }
37
+ export function acquireEngineLock(db, _dbPath) {
38
+ // BEGIN IMMEDIATE acquires a write lock upfront, preventing concurrent writers
39
+ try {
40
+ db.exec('BEGIN IMMEDIATE');
41
+ }
42
+ catch (err) {
43
+ const msg = err.message ?? '';
44
+ if (msg.includes('SQLITE_BUSY') || msg.includes('database is locked')) {
45
+ throw new EngineAlreadyRunningError(0, 'unknown');
46
+ }
47
+ throw err;
48
+ }
49
+ const existing = db
50
+ .prepare('SELECT pid, hostname, last_heartbeat FROM engine_lock WHERE id = 1')
51
+ .get();
52
+ if (existing) {
53
+ const stale = checkStaleness(existing);
54
+ if (!stale) {
55
+ db.exec('ROLLBACK');
56
+ throw new EngineAlreadyRunningError(existing.pid, existing.hostname);
57
+ }
58
+ }
59
+ const now = new Date().toISOString();
60
+ db.prepare('INSERT OR REPLACE INTO engine_lock (id, pid, hostname, started_at, last_heartbeat) VALUES (1, ?, ?, ?, ?)').run(process.pid, getHostname(), now, now);
61
+ db.exec('COMMIT');
62
+ let heartbeatInterval;
63
+ function startHeartbeat() {
64
+ heartbeatInterval = setInterval(() => {
65
+ try {
66
+ db.prepare('UPDATE engine_lock SET last_heartbeat = ? WHERE id = 1').run(new Date().toISOString());
67
+ }
68
+ catch {
69
+ // Ignore errors — DB may have been closed
70
+ }
71
+ }, 10_000);
72
+ return heartbeatInterval;
73
+ }
74
+ function release() {
75
+ if (heartbeatInterval !== undefined) {
76
+ clearInterval(heartbeatInterval);
77
+ heartbeatInterval = undefined;
78
+ }
79
+ try {
80
+ db.exec('DELETE FROM engine_lock WHERE id = 1');
81
+ }
82
+ catch {
83
+ // Ignore errors — DB may have been closed
84
+ }
85
+ }
86
+ return { release, startHeartbeat };
87
+ }
88
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../../../src/cli/convoy/lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=lock.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.test.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/lock.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,136 @@
1
+ import { mkdtempSync, rmSync } from 'node:fs';
2
+ import { realpathSync } from 'node:fs';
3
+ import { tmpdir, hostname } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { DatabaseSync } from 'node:sqlite';
6
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
+ import { acquireEngineLock, EngineAlreadyRunningError, isLockStale, } from './lock.js';
8
+ const LOCK_TABLE_SQL = `
9
+ CREATE TABLE IF NOT EXISTS engine_lock (
10
+ id INTEGER PRIMARY KEY CHECK (id = 1),
11
+ pid INTEGER NOT NULL,
12
+ hostname TEXT NOT NULL,
13
+ started_at TEXT NOT NULL,
14
+ last_heartbeat TEXT NOT NULL
15
+ )
16
+ `;
17
+ let tmpDir;
18
+ let dbPath;
19
+ let db;
20
+ beforeEach(() => {
21
+ tmpDir = realpathSync(mkdtempSync(join(tmpdir(), 'lock-test-')));
22
+ dbPath = join(tmpDir, 'test.db');
23
+ db = new DatabaseSync(dbPath);
24
+ db.exec('PRAGMA journal_mode = WAL');
25
+ db.exec(LOCK_TABLE_SQL);
26
+ });
27
+ afterEach(() => {
28
+ try {
29
+ db.close();
30
+ }
31
+ catch {
32
+ // already closed
33
+ }
34
+ rmSync(tmpDir, { recursive: true, force: true });
35
+ });
36
+ describe('engine lock', () => {
37
+ it('takes over a stale lock when heartbeat is expired and PID is dead', () => {
38
+ const staleTime = new Date(Date.now() - 60_000).toISOString();
39
+ const deadPid = 999999;
40
+ // Verify the PID is actually dead on this machine
41
+ expect(() => process.kill(deadPid, 0)).toThrow();
42
+ db.prepare('INSERT INTO engine_lock (id, pid, hostname, started_at, last_heartbeat) VALUES (1, ?, ?, ?, ?)').run(deadPid, hostname(), staleTime, staleTime);
43
+ const lock = acquireEngineLock(db, dbPath);
44
+ const row = db
45
+ .prepare('SELECT pid FROM engine_lock WHERE id = 1')
46
+ .get();
47
+ expect(row.pid).toBe(process.pid);
48
+ lock.release();
49
+ });
50
+ it('throws EngineAlreadyRunningError when lock is held by a live process', () => {
51
+ const now = new Date().toISOString();
52
+ db.prepare('INSERT INTO engine_lock (id, pid, hostname, started_at, last_heartbeat) VALUES (1, ?, ?, ?, ?)').run(process.pid, hostname(), now, now);
53
+ expect(() => acquireEngineLock(db, dbPath)).toThrow(EngineAlreadyRunningError);
54
+ });
55
+ it('takes over when hostname differs (treated as stale regardless of PID)', () => {
56
+ const staleTime = new Date(Date.now() - 60_000).toISOString();
57
+ db.prepare('INSERT INTO engine_lock (id, pid, hostname, started_at, last_heartbeat) VALUES (1, ?, ?, ?, ?)').run(process.pid, 'other-host.example.com', staleTime, staleTime);
58
+ const lock = acquireEngineLock(db, dbPath);
59
+ const row = db
60
+ .prepare('SELECT hostname FROM engine_lock WHERE id = 1')
61
+ .get();
62
+ expect(row.hostname).toBe(hostname());
63
+ lock.release();
64
+ });
65
+ it('release deletes the lock row', () => {
66
+ const lock = acquireEngineLock(db, dbPath);
67
+ lock.release();
68
+ const row = db.prepare('SELECT * FROM engine_lock WHERE id = 1').get();
69
+ expect(row).toBeUndefined();
70
+ });
71
+ it('startHeartbeat updates last_heartbeat after 10 seconds', () => {
72
+ vi.useFakeTimers();
73
+ try {
74
+ const lock = acquireEngineLock(db, dbPath);
75
+ const before = db
76
+ .prepare('SELECT last_heartbeat FROM engine_lock WHERE id = 1')
77
+ .get().last_heartbeat;
78
+ lock.startHeartbeat();
79
+ vi.advanceTimersByTime(10_000);
80
+ const after = db
81
+ .prepare('SELECT last_heartbeat FROM engine_lock WHERE id = 1')
82
+ .get().last_heartbeat;
83
+ expect(after).not.toBe(before);
84
+ lock.release();
85
+ }
86
+ finally {
87
+ vi.useRealTimers();
88
+ }
89
+ });
90
+ it('throws EngineAlreadyRunningError when SQLITE_BUSY from a concurrent write lock', () => {
91
+ // Hold a BEGIN IMMEDIATE transaction on a second connection so the first
92
+ // connection's BEGIN IMMEDIATE will return SQLITE_BUSY.
93
+ const db2 = new DatabaseSync(dbPath);
94
+ db2.exec('PRAGMA journal_mode = WAL');
95
+ db2.exec(LOCK_TABLE_SQL);
96
+ db2.exec('BEGIN IMMEDIATE');
97
+ try {
98
+ expect(() => acquireEngineLock(db, dbPath)).toThrow(EngineAlreadyRunningError);
99
+ }
100
+ finally {
101
+ db2.exec('ROLLBACK');
102
+ db2.close();
103
+ }
104
+ });
105
+ it('takes over lock from different hostname when heartbeat expired', () => {
106
+ const staleTime = new Date(Date.now() - 60_000).toISOString();
107
+ db.prepare('INSERT INTO engine_lock (id, pid, hostname, started_at, last_heartbeat) VALUES (1, ?, ?, ?, ?)').run(process.pid, 'ci-runner-42.example.com', staleTime, staleTime);
108
+ const lock = acquireEngineLock(db, dbPath);
109
+ const row = db
110
+ .prepare('SELECT hostname, pid FROM engine_lock WHERE id = 1')
111
+ .get();
112
+ expect(row.hostname).toBe(hostname());
113
+ expect(row.pid).toBe(process.pid);
114
+ lock.release();
115
+ });
116
+ it('does NOT take over lock from different hostname when heartbeat is fresh', () => {
117
+ const freshTime = new Date().toISOString();
118
+ db.prepare('INSERT INTO engine_lock (id, pid, hostname, started_at, last_heartbeat) VALUES (1, ?, ?, ?, ?)').run(12345, 'other-host.example.com', freshTime, freshTime);
119
+ expect(() => acquireEngineLock(db, dbPath)).toThrow(EngineAlreadyRunningError);
120
+ });
121
+ it('isLockStale returns true when no lock exists', () => {
122
+ expect(isLockStale(db)).toBe(true);
123
+ });
124
+ it('isLockStale returns false for fresh lock on same host', () => {
125
+ const now = new Date().toISOString();
126
+ db.prepare('INSERT INTO engine_lock (id, pid, hostname, started_at, last_heartbeat) VALUES (1, ?, ?, ?, ?)').run(process.pid, hostname(), now, now);
127
+ expect(isLockStale(db)).toBe(false);
128
+ });
129
+ it('isLockStale returns true for expired lock with dead PID on same host', () => {
130
+ const staleTime = new Date(Date.now() - 60_000).toISOString();
131
+ const deadPid = 999999;
132
+ db.prepare('INSERT INTO engine_lock (id, pid, hostname, started_at, last_heartbeat) VALUES (1, ?, ?, ?, ?)').run(deadPid, hostname(), staleTime, staleTime);
133
+ expect(isLockStale(db)).toBe(true);
134
+ });
135
+ });
136
+ //# sourceMappingURL=lock.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.test.js","sourceRoot":"","sources":["../../../src/cli/convoy/lock.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=log-merge.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-merge.test.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/log-merge.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,147 @@
1
+ import { mkdtempSync, rmSync, realpathSync, mkdirSync, writeFileSync, readFileSync, existsSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
5
+ import { mergeConvoyLogs } from '../log.js';
6
+ const CONVOYS_REL = '.opencastle/logs/convoys';
7
+ const OUTPUT_REL = '.opencastle/logs/convoy-events.ndjson';
8
+ function makeBase() {
9
+ const dir = realpathSync(mkdtempSync(join(tmpdir(), 'log-merge-test-')));
10
+ mkdirSync(join(dir, CONVOYS_REL), { recursive: true });
11
+ return dir;
12
+ }
13
+ function writeConvoyFile(base, convoyId, records) {
14
+ const path = join(base, CONVOYS_REL, `${convoyId}.ndjson`);
15
+ writeFileSync(path, records.map(r => JSON.stringify(r)).join('\n') + '\n', 'utf8');
16
+ }
17
+ let tmpDir;
18
+ beforeEach(() => {
19
+ tmpDir = makeBase();
20
+ });
21
+ afterEach(() => {
22
+ rmSync(tmpDir, { recursive: true, force: true });
23
+ });
24
+ describe('mergeConvoyLogs', () => {
25
+ it('returns zeros when convoys directory is missing', async () => {
26
+ rmSync(join(tmpDir, '.opencastle'), { recursive: true, force: true });
27
+ const result = await mergeConvoyLogs({ basePath: tmpDir });
28
+ expect(result).toEqual({ merged: 0, deduplicated: 0, written: 0 });
29
+ });
30
+ it('returns zeros when convoys directory is empty', async () => {
31
+ const result = await mergeConvoyLogs({ basePath: tmpDir });
32
+ expect(result).toEqual({ merged: 0, deduplicated: 0, written: 0 });
33
+ });
34
+ it('merges records from 3 convoy files', async () => {
35
+ writeConvoyFile(tmpDir, 'convoy-a', [
36
+ { _event_id: 1, timestamp: '2026-01-01T10:00:00.000Z', type: 'task_started' },
37
+ ]);
38
+ writeConvoyFile(tmpDir, 'convoy-b', [
39
+ { _event_id: 2, timestamp: '2026-01-02T10:00:00.000Z', type: 'task_done' },
40
+ ]);
41
+ writeConvoyFile(tmpDir, 'convoy-c', [
42
+ { _event_id: 3, timestamp: '2026-01-03T10:00:00.000Z', type: 'session' },
43
+ ]);
44
+ const result = await mergeConvoyLogs({ basePath: tmpDir });
45
+ expect(result.merged).toBe(3);
46
+ expect(result.written).toBe(3);
47
+ });
48
+ it('output is sorted by timestamp ascending', async () => {
49
+ writeConvoyFile(tmpDir, 'convoy-z', [
50
+ { _event_id: 10, timestamp: '2026-03-01T00:00:00.000Z', type: 'task_done' },
51
+ { _event_id: 11, timestamp: '2026-01-01T00:00:00.000Z', type: 'task_started' },
52
+ ]);
53
+ writeConvoyFile(tmpDir, 'convoy-a', [
54
+ { _event_id: 12, timestamp: '2026-02-01T00:00:00.000Z', type: 'session' },
55
+ ]);
56
+ const outputPath = join(tmpDir, 'merged.ndjson');
57
+ await mergeConvoyLogs({ basePath: tmpDir, output: outputPath });
58
+ const lines = readFileSync(outputPath, 'utf8').split('\n').filter(l => l.trim());
59
+ const timestamps = lines.map(l => JSON.parse(l).timestamp);
60
+ expect(timestamps).toEqual([
61
+ '2026-01-01T00:00:00.000Z',
62
+ '2026-02-01T00:00:00.000Z',
63
+ '2026-03-01T00:00:00.000Z',
64
+ ]);
65
+ });
66
+ it('deduplicates records by _event_id (keeps first occurrence)', async () => {
67
+ writeConvoyFile(tmpDir, 'convoy-a', [
68
+ { _event_id: 5, timestamp: '2026-01-01T00:00:00.000Z', type: 'task_started', note: 'first' },
69
+ ]);
70
+ writeConvoyFile(tmpDir, 'convoy-b', [
71
+ { _event_id: 5, timestamp: '2026-01-01T00:00:00.000Z', type: 'task_started', note: 'duplicate' },
72
+ { _event_id: 6, timestamp: '2026-01-02T00:00:00.000Z', type: 'task_done' },
73
+ ]);
74
+ const outputPath = join(tmpDir, 'merged.ndjson');
75
+ const result = await mergeConvoyLogs({ basePath: tmpDir, output: outputPath });
76
+ expect(result.merged).toBe(3);
77
+ expect(result.deduplicated).toBe(1);
78
+ expect(result.written).toBe(2);
79
+ const lines = readFileSync(outputPath, 'utf8').split('\n').filter(l => l.trim());
80
+ expect(lines).toHaveLength(2);
81
+ const first = JSON.parse(lines[0]);
82
+ expect(first.note).toBe('first');
83
+ });
84
+ it('filters by --since (inclusive)', async () => {
85
+ writeConvoyFile(tmpDir, 'convoy-a', [
86
+ { _event_id: 1, timestamp: '2026-01-01T00:00:00.000Z', type: 'session' },
87
+ { _event_id: 2, timestamp: '2026-02-01T00:00:00.000Z', type: 'session' },
88
+ { _event_id: 3, timestamp: '2026-03-01T00:00:00.000Z', type: 'session' },
89
+ ]);
90
+ const outputPath = join(tmpDir, 'merged.ndjson');
91
+ const result = await mergeConvoyLogs({ basePath: tmpDir, since: '2026-02-01T00:00:00.000Z', output: outputPath });
92
+ expect(result.written).toBe(2);
93
+ const lines = readFileSync(outputPath, 'utf8').split('\n').filter(l => l.trim());
94
+ expect(lines).toHaveLength(2);
95
+ });
96
+ it('filters by --until (inclusive)', async () => {
97
+ writeConvoyFile(tmpDir, 'convoy-a', [
98
+ { _event_id: 1, timestamp: '2026-01-01T00:00:00.000Z', type: 'session' },
99
+ { _event_id: 2, timestamp: '2026-02-01T00:00:00.000Z', type: 'session' },
100
+ { _event_id: 3, timestamp: '2026-03-01T00:00:00.000Z', type: 'session' },
101
+ ]);
102
+ const outputPath = join(tmpDir, 'merged.ndjson');
103
+ const result = await mergeConvoyLogs({ basePath: tmpDir, until: '2026-02-01T00:00:00.000Z', output: outputPath });
104
+ expect(result.written).toBe(2);
105
+ });
106
+ it('filters by --since and --until together', async () => {
107
+ writeConvoyFile(tmpDir, 'convoy-a', [
108
+ { _event_id: 1, timestamp: '2026-01-01T00:00:00.000Z', type: 'session' },
109
+ { _event_id: 2, timestamp: '2026-02-15T00:00:00.000Z', type: 'session' },
110
+ { _event_id: 3, timestamp: '2026-03-01T00:00:00.000Z', type: 'session' },
111
+ ]);
112
+ const outputPath = join(tmpDir, 'merged.ndjson');
113
+ const result = await mergeConvoyLogs({
114
+ basePath: tmpDir,
115
+ since: '2026-02-01T00:00:00.000Z',
116
+ until: '2026-02-28T23:59:59.999Z',
117
+ output: outputPath,
118
+ });
119
+ expect(result.written).toBe(1);
120
+ const lines = readFileSync(outputPath, 'utf8').split('\n').filter(l => l.trim());
121
+ const record = JSON.parse(lines[0]);
122
+ expect(record.timestamp).toBe('2026-02-15T00:00:00.000Z');
123
+ });
124
+ it('writes to default output path when --output not specified', async () => {
125
+ writeConvoyFile(tmpDir, 'convoy-a', [
126
+ { _event_id: 1, timestamp: '2026-01-01T00:00:00.000Z', type: 'session' },
127
+ ]);
128
+ await mergeConvoyLogs({ basePath: tmpDir });
129
+ const defaultPath = join(tmpDir, '.opencastle', 'logs', 'convoy-events.ndjson');
130
+ expect(existsSync(defaultPath)).toBe(true);
131
+ });
132
+ it('returns written: 0 when all records filtered out', async () => {
133
+ writeConvoyFile(tmpDir, 'convoy-a', [
134
+ { _event_id: 1, timestamp: '2026-01-01T00:00:00.000Z', type: 'session' },
135
+ ]);
136
+ const result = await mergeConvoyLogs({ basePath: tmpDir, since: '2027-01-01T00:00:00.000Z' });
137
+ expect(result.written).toBe(0);
138
+ expect(result.merged).toBe(1);
139
+ });
140
+ it('skips malformed JSON lines gracefully', async () => {
141
+ const path = join(tmpDir, CONVOYS_REL, 'convoy-bad.ndjson');
142
+ writeFileSync(path, '{"_event_id":1,"timestamp":"2026-01-01T00:00:00.000Z","type":"session"}\nnot-valid-json\n{"_event_id":2,"timestamp":"2026-01-02T00:00:00.000Z","type":"task_done"}\n', 'utf8');
143
+ const result = await mergeConvoyLogs({ basePath: tmpDir });
144
+ expect(result.written).toBe(2);
145
+ });
146
+ });
147
+ //# sourceMappingURL=log-merge.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-merge.test.js","sourceRoot":"","sources":["../../../src/cli/convoy/log-merge.test.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,10 @@ export interface MergeResult {
3
3
  conflicted: boolean;
4
4
  message: string;
5
5
  }
6
+ export declare class MergeConflictError extends Error {
7
+ readonly conflictingFiles: string[];
8
+ constructor(conflictingFiles: string[], message?: string);
9
+ }
6
10
  export interface MergeQueue {
7
11
  /**
8
12
  * Merge a single worktree's changes back onto the target branch.
@@ -1 +1 @@
1
- {"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/merge.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,OAAO,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,UAAU;IACzB;;;;OAIG;IACH,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;CAChG;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAmE7D"}
1
+ {"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/merge.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,OAAO,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,qBAAa,kBAAmB,SAAQ,KAAK;aAEzB,gBAAgB,EAAE,MAAM,EAAE;gBAA1B,gBAAgB,EAAE,MAAM,EAAE,EAC1C,OAAO,CAAC,EAAE,MAAM;CAKnB;AAED,MAAM,WAAW,UAAU;IACzB;;;;OAIG;IACH,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;CAChG;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CA2E7D"}
@@ -2,6 +2,14 @@ import { execFile as execFileCb } from 'node:child_process';
2
2
  import { resolve, join, sep } from 'node:path';
3
3
  import { promisify } from 'node:util';
4
4
  const execFile = promisify(execFileCb);
5
+ export class MergeConflictError extends Error {
6
+ conflictingFiles;
7
+ constructor(conflictingFiles, message) {
8
+ super(message ?? `Merge conflict in: ${conflictingFiles.join(', ')}`);
9
+ this.conflictingFiles = conflictingFiles;
10
+ this.name = 'MergeConflictError';
11
+ }
12
+ }
5
13
  export function createMergeQueue(repoPath) {
6
14
  const worktreesDir = resolve(join(repoPath, '.opencastle', 'worktrees'));
7
15
  async function merge(worktreePath, worktreeBranch, targetBranch) {
@@ -51,8 +59,17 @@ export function createMergeQueue(repoPath) {
51
59
  const isConflict = error.code === 1 &&
52
60
  ((error.stderr ?? '').includes('CONFLICT') || (error.stdout ?? '').includes('CONFLICT'));
53
61
  if (isConflict) {
62
+ // Collect conflicting files before aborting
63
+ let conflictingFiles = [];
64
+ try {
65
+ const { stdout: conflictOut } = await execFile('git', [
66
+ '-C', repoPath, 'diff', '--name-only', '--diff-filter=U',
67
+ ]);
68
+ conflictingFiles = conflictOut.split('\n').filter(Boolean);
69
+ }
70
+ catch { /* ignore — we still abort */ }
54
71
  await execFile('git', ['-C', repoPath, 'merge', '--abort']);
55
- return { success: false, conflicted: true, message: 'Merge conflict detected; merge aborted' };
72
+ throw new MergeConflictError(conflictingFiles);
56
73
  }
57
74
  throw err;
58
75
  }
@@ -1 +1 @@
1
- {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../src/cli/convoy/merge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../src/cli/convoy/merge.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ import { join } from 'node:path';
4
4
  import { execFile as execFileCb } from 'node:child_process';
5
5
  import { promisify } from 'node:util';
6
6
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
7
- import { createMergeQueue } from './merge.js';
7
+ import { createMergeQueue, MergeConflictError } from './merge.js';
8
8
  const execFile = promisify(execFileCb);
9
9
  // ── helpers ───────────────────────────────────────────────────────────────────
10
10
  let repoPath;
@@ -76,17 +76,15 @@ describe('merge - no changes', () => {
76
76
  });
77
77
  // ── merge conflict ────────────────────────────────────────────────────────────
78
78
  describe('merge - conflict', () => {
79
- it('returns conflicted: true and aborts when two worktrees edit the same file', async () => {
79
+ it('throws MergeConflictError and aborts when two worktrees edit the same file', async () => {
80
80
  const worktree1 = await addWorktree(repoPath, 'worker1', featureBranch);
81
81
  const worktree2 = await addWorktree(repoPath, 'worker2', featureBranch);
82
82
  writeFileSync(join(worktree1, 'shared.txt'), 'content from worker 1');
83
83
  writeFileSync(join(worktree2, 'shared.txt'), 'content from worker 2');
84
84
  const first = await queue.merge(worktree1, 'convoy-worker1', featureBranch);
85
85
  expect(first).toEqual({ success: true, conflicted: false, message: 'Merged successfully' });
86
- const second = await queue.merge(worktree2, 'convoy-worker2', featureBranch);
87
- expect(second.success).toBe(false);
88
- expect(second.conflicted).toBe(true);
89
- expect(second.message).toContain('conflict');
86
+ await expect(queue.merge(worktree2, 'convoy-worker2', featureBranch))
87
+ .rejects.toThrow(MergeConflictError);
90
88
  });
91
89
  it('leaves the repo in a clean state (no pending merge) after aborting a conflict', async () => {
92
90
  const worktree1 = await addWorktree(repoPath, 'worker1', featureBranch);
@@ -94,7 +92,8 @@ describe('merge - conflict', () => {
94
92
  writeFileSync(join(worktree1, 'shared.txt'), 'content from worker 1');
95
93
  writeFileSync(join(worktree2, 'shared.txt'), 'content from worker 2');
96
94
  await queue.merge(worktree1, 'convoy-worker1', featureBranch);
97
- await queue.merge(worktree2, 'convoy-worker2', featureBranch);
95
+ await expect(queue.merge(worktree2, 'convoy-worker2', featureBranch))
96
+ .rejects.toBeInstanceOf(MergeConflictError);
98
97
  // --untracked-files=no excludes the .opencastle/worktrees/ dir from the check;
99
98
  // we only want to verify there is no pending merge (no staged/modified tracked files).
100
99
  const { stdout } = await execFile('git', ['-C', repoPath, 'status', '--porcelain', '--untracked-files=no']);
@@ -1 +1 @@
1
- {"version":3,"file":"merge.test.js","sourceRoot":"","sources":["../../../src/cli/convoy/merge.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"merge.test.js","sourceRoot":"","sources":["../../../src/cli/convoy/merge.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import type { Task } from '../types.js';
2
+ /**
3
+ * Normalize a file path for partition comparison.
4
+ * - Rejects glob patterns (* or ?)
5
+ * - Strips leading ./ and /
6
+ * - Replaces backslashes with forward slashes
7
+ * - Resolves . and .. via path.normalize()
8
+ * - Preserves trailing slash for directories
9
+ */
10
+ export declare function normalizePath(p: string): string;
11
+ /**
12
+ * Returns true if path a and path b overlap (exact match or prefix containment).
13
+ * Example: 'src/auth/' overlaps 'src/auth/service.ts' in both directions.
14
+ */
15
+ export declare function pathsOverlap(a: string, b: string): boolean;
16
+ export interface PartitionConflict {
17
+ phase: number;
18
+ taskA: string;
19
+ taskB: string;
20
+ overlapping: string[];
21
+ }
22
+ export interface PartitionValidationResult {
23
+ valid: boolean;
24
+ conflicts: PartitionConflict[];
25
+ }
26
+ /**
27
+ * Validate that tasks within the same parallel phase do not have overlapping file partitions.
28
+ * Tasks in different phases (sequential) are allowed to share files.
29
+ */
30
+ export declare function validateFilePartitions(_tasks: Task[], phases: Task[][]): PartitionValidationResult;
31
+ /**
32
+ * Probe whether the filesystem is case-sensitive by creating a mixed-case temp file
33
+ * and checking if the lowercase path resolves to the same inode.
34
+ *
35
+ * Uses realpathSync per LES-003: on macOS, os.tmpdir() returns /var/... which is a
36
+ * symlink to /private/var/... — realpathSync resolves this to the canonical path.
37
+ *
38
+ * Returns true if case-sensitive (git-compatible default), false if case-insensitive.
39
+ */
40
+ export declare function determineFsCaseSensitivity(): boolean;
41
+ /**
42
+ * Before task execution: scan each file in the task's files[] partition.
43
+ * If any resolved symlink target escapes the basePath directory, throw symlink_escape.
44
+ */
45
+ export declare function scanSymlinks(files: string[], basePath: string): void;
46
+ /**
47
+ * After task execution: scan files[] in the worktree for new symlinks that escape the partition.
48
+ * Throws symlink_escape_post_task if any symlink target is outside worktreePath.
49
+ */
50
+ export declare function scanNewSymlinks(worktreePath: string, files: string[]): void;
51
+ //# sourceMappingURL=partition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"partition.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/partition.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAIvC;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAuC/C;AAID;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAM1D;AAID,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,OAAO,CAAA;IACd,SAAS,EAAE,iBAAiB,EAAE,CAAA;CAC/B;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,IAAI,EAAE,EACd,MAAM,EAAE,IAAI,EAAE,EAAE,GACf,yBAAyB,CAsC3B;AAID;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAmBpD;AAID;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CA2BpE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CA6B3E"}