opencastle 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/convoy/events.d.ts +10 -0
- package/dist/cli/convoy/events.d.ts.map +1 -0
- package/dist/cli/convoy/events.js +27 -0
- package/dist/cli/convoy/events.js.map +1 -0
- package/dist/cli/convoy/events.test.d.ts +2 -0
- package/dist/cli/convoy/events.test.d.ts.map +1 -0
- package/dist/cli/convoy/events.test.js +94 -0
- package/dist/cli/convoy/events.test.js.map +1 -0
- package/dist/cli/convoy/merge.d.ts +15 -0
- package/dist/cli/convoy/merge.d.ts.map +1 -0
- package/dist/cli/convoy/merge.js +62 -0
- package/dist/cli/convoy/merge.js.map +1 -0
- package/dist/cli/convoy/merge.test.d.ts +2 -0
- package/dist/cli/convoy/merge.test.d.ts.map +1 -0
- package/dist/cli/convoy/merge.test.js +134 -0
- package/dist/cli/convoy/merge.test.js.map +1 -0
- package/dist/cli/convoy/store.d.ts +23 -0
- package/dist/cli/convoy/store.d.ts.map +1 -0
- package/dist/cli/convoy/store.js +210 -0
- package/dist/cli/convoy/store.js.map +1 -0
- package/dist/cli/convoy/store.test.d.ts +2 -0
- package/dist/cli/convoy/store.test.d.ts.map +1 -0
- package/dist/cli/convoy/store.test.js +387 -0
- package/dist/cli/convoy/store.test.js.map +1 -0
- package/dist/cli/convoy/types.d.ts +56 -0
- package/dist/cli/convoy/types.d.ts.map +1 -0
- package/dist/cli/convoy/types.js +2 -0
- package/dist/cli/convoy/types.js.map +1 -0
- package/dist/cli/convoy/worktree.d.ts +13 -0
- package/dist/cli/convoy/worktree.d.ts.map +1 -0
- package/dist/cli/convoy/worktree.js +90 -0
- package/dist/cli/convoy/worktree.js.map +1 -0
- package/dist/cli/convoy/worktree.test.d.ts +2 -0
- package/dist/cli/convoy/worktree.test.d.ts.map +1 -0
- package/dist/cli/convoy/worktree.test.js +146 -0
- package/dist/cli/convoy/worktree.test.js.map +1 -0
- package/dist/cli/run/adapters/claude-code.js +1 -1
- package/dist/cli/run/adapters/claude-code.js.map +1 -1
- package/dist/cli/run/adapters/copilot.d.ts.map +1 -1
- package/dist/cli/run/adapters/copilot.js +5 -0
- package/dist/cli/run/adapters/copilot.js.map +1 -1
- package/dist/cli/run/adapters/cursor.js +1 -1
- package/dist/cli/run/adapters/cursor.js.map +1 -1
- package/dist/cli/run/executor.test.js +1 -0
- package/dist/cli/run/executor.test.js.map +1 -1
- package/dist/cli/run/loop-executor.d.ts.map +1 -1
- package/dist/cli/run/loop-executor.js +1 -0
- package/dist/cli/run/loop-executor.js.map +1 -1
- package/dist/cli/run/schema.d.ts +4 -0
- package/dist/cli/run/schema.d.ts.map +1 -1
- package/dist/cli/run/schema.js +78 -2
- package/dist/cli/run/schema.js.map +1 -1
- package/dist/cli/run/schema.test.js +384 -1
- package/dist/cli/run/schema.test.js.map +1 -1
- package/dist/cli/types.d.ts +21 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/cli/convoy/events.test.ts +118 -0
- package/src/cli/convoy/events.ts +41 -0
- package/src/cli/convoy/merge.test.ts +184 -0
- package/src/cli/convoy/merge.ts +89 -0
- package/src/cli/convoy/store.test.ts +446 -0
- package/src/cli/convoy/store.ts +308 -0
- package/src/cli/convoy/types.ts +68 -0
- package/src/cli/convoy/worktree.test.ts +177 -0
- package/src/cli/convoy/worktree.ts +116 -0
- package/src/cli/run/adapters/claude-code.ts +1 -1
- package/src/cli/run/adapters/copilot.ts +5 -0
- package/src/cli/run/adapters/cursor.ts +1 -1
- package/src/cli/run/executor.test.ts +1 -0
- package/src/cli/run/loop-executor.ts +1 -0
- package/src/cli/run/schema.test.ts +462 -1
- package/src/cli/run/schema.ts +96 -2
- package/src/cli/types.ts +22 -0
- package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ConvoyStore } from './store.js';
|
|
2
|
+
export interface ConvoyEventEmitter {
|
|
3
|
+
emit(type: string, data?: Record<string, unknown>, ids?: {
|
|
4
|
+
convoy_id?: string;
|
|
5
|
+
task_id?: string;
|
|
6
|
+
worker_id?: string;
|
|
7
|
+
}): void;
|
|
8
|
+
}
|
|
9
|
+
export declare function createEventEmitter(store: ConvoyStore, logsDir?: string): ConvoyEventEmitter;
|
|
10
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/events.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,MAAM,WAAW,kBAAkB;IACjC,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,GAAG,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GACjE,IAAI,CAAA;CACR;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,kBAAkB,CA6B3F"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { appendEvent as appendNdjson } from '../log.js';
|
|
2
|
+
export function createEventEmitter(store, logsDir) {
|
|
3
|
+
return {
|
|
4
|
+
emit(type, data, ids) {
|
|
5
|
+
const now = new Date().toISOString();
|
|
6
|
+
store.insertEvent({
|
|
7
|
+
convoy_id: ids?.convoy_id ?? null,
|
|
8
|
+
task_id: ids?.task_id ?? null,
|
|
9
|
+
worker_id: ids?.worker_id ?? null,
|
|
10
|
+
type,
|
|
11
|
+
data: data !== undefined ? JSON.stringify(data) : null,
|
|
12
|
+
created_at: now,
|
|
13
|
+
});
|
|
14
|
+
appendNdjson({
|
|
15
|
+
timestamp: now,
|
|
16
|
+
type,
|
|
17
|
+
convoy_id: ids?.convoy_id ?? null,
|
|
18
|
+
task_id: ids?.task_id ?? null,
|
|
19
|
+
worker_id: ids?.worker_id ?? null,
|
|
20
|
+
...(data ?? {}),
|
|
21
|
+
}, logsDir ?? null).catch(() => {
|
|
22
|
+
// fire-and-forget: NDJSON write failure must not crash the convoy engine
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/cli/convoy/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,MAAM,WAAW,CAAA;AAWvD,MAAM,UAAU,kBAAkB,CAAC,KAAkB,EAAE,OAAgB;IACrE,OAAO;QACL,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG;YAClB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;YAEpC,KAAK,CAAC,WAAW,CAAC;gBAChB,SAAS,EAAE,GAAG,EAAE,SAAS,IAAI,IAAI;gBACjC,OAAO,EAAE,GAAG,EAAE,OAAO,IAAI,IAAI;gBAC7B,SAAS,EAAE,GAAG,EAAE,SAAS,IAAI,IAAI;gBACjC,IAAI;gBACJ,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;gBACtD,UAAU,EAAE,GAAG;aAChB,CAAC,CAAA;YAEF,YAAY,CACV;gBACE,SAAS,EAAE,GAAG;gBACd,IAAI;gBACJ,SAAS,EAAE,GAAG,EAAE,SAAS,IAAI,IAAI;gBACjC,OAAO,EAAE,GAAG,EAAE,OAAO,IAAI,IAAI;gBAC7B,SAAS,EAAE,GAAG,EAAE,SAAS,IAAI,IAAI;gBACjC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;aAChB,EACD,OAAO,IAAI,IAAI,CAChB,CAAC,KAAK,CAAC,GAAG,EAAE;gBACX,yEAAyE;YAC3E,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.test.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/events.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
5
|
+
import { createConvoyStore } from './store.js';
|
|
6
|
+
import { createEventEmitter } from './events.js';
|
|
7
|
+
vi.mock('../log.js', () => ({
|
|
8
|
+
appendEvent: vi.fn().mockResolvedValue(undefined),
|
|
9
|
+
}));
|
|
10
|
+
import { appendEvent } from '../log.js';
|
|
11
|
+
const mockAppend = vi.mocked(appendEvent);
|
|
12
|
+
let tmpDir;
|
|
13
|
+
let store;
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'emitter-test-'));
|
|
16
|
+
store = createConvoyStore(join(tmpDir, 'test.db'));
|
|
17
|
+
vi.clearAllMocks();
|
|
18
|
+
store.insertConvoy({
|
|
19
|
+
id: 'c1',
|
|
20
|
+
name: 'Test',
|
|
21
|
+
spec_hash: 'x',
|
|
22
|
+
status: 'pending',
|
|
23
|
+
branch: null,
|
|
24
|
+
created_at: new Date().toISOString(),
|
|
25
|
+
spec_yaml: 'name: test',
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
store.close();
|
|
30
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
31
|
+
});
|
|
32
|
+
describe('createEventEmitter', () => {
|
|
33
|
+
it('inserts the event into SQLite', () => {
|
|
34
|
+
const emitter = createEventEmitter(store);
|
|
35
|
+
emitter.emit('task_started', { msg: 'started' }, { convoy_id: 'c1' });
|
|
36
|
+
const events = store.getEvents('c1');
|
|
37
|
+
expect(events).toHaveLength(1);
|
|
38
|
+
expect(events[0].type).toBe('task_started');
|
|
39
|
+
expect(events[0].convoy_id).toBe('c1');
|
|
40
|
+
});
|
|
41
|
+
it('serializes event data to JSON in SQLite', () => {
|
|
42
|
+
const emitter = createEventEmitter(store);
|
|
43
|
+
emitter.emit('task_done', { exitCode: 0, output: 'ok' }, { convoy_id: 'c1' });
|
|
44
|
+
const events = store.getEvents('c1');
|
|
45
|
+
const parsed = JSON.parse(events[0].data);
|
|
46
|
+
expect(parsed.exitCode).toBe(0);
|
|
47
|
+
expect(parsed.output).toBe('ok');
|
|
48
|
+
});
|
|
49
|
+
it('stores null data when no data object is provided', () => {
|
|
50
|
+
const emitter = createEventEmitter(store);
|
|
51
|
+
emitter.emit('heartbeat', undefined, { convoy_id: 'c1' });
|
|
52
|
+
const events = store.getEvents('c1');
|
|
53
|
+
expect(events[0].data).toBeNull();
|
|
54
|
+
});
|
|
55
|
+
it('calls appendEvent for NDJSON dual-write', () => {
|
|
56
|
+
const emitter = createEventEmitter(store);
|
|
57
|
+
emitter.emit('convoy_started', { name: 'test' }, { convoy_id: 'c1' });
|
|
58
|
+
expect(mockAppend).toHaveBeenCalledOnce();
|
|
59
|
+
});
|
|
60
|
+
it('passes logs dir to appendEvent', () => {
|
|
61
|
+
const emitter = createEventEmitter(store, '/some/logs');
|
|
62
|
+
emitter.emit('convoy_started', {}, { convoy_id: 'c1' });
|
|
63
|
+
expect(mockAppend).toHaveBeenCalledWith(expect.objectContaining({ type: 'convoy_started', convoy_id: 'c1' }), '/some/logs');
|
|
64
|
+
});
|
|
65
|
+
it('defaults all ids to null when ids are not provided', () => {
|
|
66
|
+
const emitter = createEventEmitter(store);
|
|
67
|
+
emitter.emit('generic_event');
|
|
68
|
+
const db = require('node:sqlite').DatabaseSync;
|
|
69
|
+
// Verify via NDJSON mock payload
|
|
70
|
+
expect(mockAppend).toHaveBeenCalledWith(expect.objectContaining({
|
|
71
|
+
convoy_id: null,
|
|
72
|
+
task_id: null,
|
|
73
|
+
worker_id: null,
|
|
74
|
+
}), null);
|
|
75
|
+
});
|
|
76
|
+
it('includes all provided ids in the NDJSON record', () => {
|
|
77
|
+
const emitter = createEventEmitter(store, tmpDir);
|
|
78
|
+
emitter.emit('worker_spawned', {}, { convoy_id: 'c1', task_id: 't1', worker_id: 'w1' });
|
|
79
|
+
expect(mockAppend).toHaveBeenCalledWith(expect.objectContaining({ convoy_id: 'c1', task_id: 't1', worker_id: 'w1' }), tmpDir);
|
|
80
|
+
});
|
|
81
|
+
it('SQLite event stores correct ids', () => {
|
|
82
|
+
const emitter = createEventEmitter(store);
|
|
83
|
+
emitter.emit('worker_done', {}, { convoy_id: 'c1', task_id: 'task-x', worker_id: 'wkr-y' });
|
|
84
|
+
const events = store.getEvents('c1');
|
|
85
|
+
expect(events[0].task_id).toBe('task-x');
|
|
86
|
+
expect(events[0].worker_id).toBe('wkr-y');
|
|
87
|
+
});
|
|
88
|
+
it('does not throw if NDJSON write fails', () => {
|
|
89
|
+
mockAppend.mockRejectedValueOnce(new Error('disk full'));
|
|
90
|
+
const emitter = createEventEmitter(store);
|
|
91
|
+
expect(() => emitter.emit('test', {}, { convoy_id: 'c1' })).not.toThrow();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=events.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.test.js","sourceRoot":"","sources":["../../../src/cli/convoy/events.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgB,MAAM,EAAc,MAAM,SAAS,CAAA;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAGhD,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;IAC1B,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;CAClD,CAAC,CAAC,CAAA;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AACvC,MAAM,UAAU,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;AAEzC,IAAI,MAAc,CAAA;AAClB,IAAI,KAAkB,CAAA;AAEtB,UAAU,CAAC,GAAG,EAAE;IACd,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAA;IACrD,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;IAClD,EAAE,CAAC,aAAa,EAAE,CAAA;IAElB,KAAK,CAAC,YAAY,CAAC;QACjB,EAAE,EAAE,IAAI;QACR,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,GAAG;QACd,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,SAAS,EAAE,YAAY;KACxB,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,SAAS,CAAC,GAAG,EAAE;IACb,KAAK,CAAC,KAAK,EAAE,CAAA;IACb,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;AAClD,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;QACzC,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACrE,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QACpC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;QACzC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC7E,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAK,CAAC,CAAA;QAC1C,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC/B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;QACzC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACzD,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QACpC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;QACzC,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACrE,MAAM,CAAC,UAAU,CAAC,CAAC,oBAAoB,EAAE,CAAA;IAC3C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAA;QACvD,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACvD,MAAM,CAAC,UAAU,CAAC,CAAC,oBAAoB,CACrC,MAAM,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EACpE,YAAY,CACb,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;QACzC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;QAC7B,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,YAAY,CAAA;QAC9C,iCAAiC;QACjC,MAAM,CAAC,UAAU,CAAC,CAAC,oBAAoB,CACrC,MAAM,CAAC,gBAAgB,CAAC;YACtB,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI;SAChB,CAAC,EACF,IAAI,CACL,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;QACjD,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACvF,MAAM,CAAC,UAAU,CAAC,CAAC,oBAAoB,CACrC,MAAM,CAAC,gBAAgB,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAC5E,MAAM,CACP,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;QACzC,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAA;QAC3F,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QACpC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC3C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,UAAU,CAAC,qBAAqB,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC,CAAA;QACxD,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;QACzC,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAA;IAC3E,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface MergeResult {
|
|
2
|
+
success: boolean;
|
|
3
|
+
conflicted: boolean;
|
|
4
|
+
message: string;
|
|
5
|
+
}
|
|
6
|
+
export interface MergeQueue {
|
|
7
|
+
/**
|
|
8
|
+
* Merge a single worktree's changes back onto the target branch.
|
|
9
|
+
* Stages all changes in the worktree, commits them if necessary, then merges
|
|
10
|
+
* the worktree branch into the target branch.
|
|
11
|
+
*/
|
|
12
|
+
merge(worktreePath: string, worktreeBranch: string, targetBranch: string): Promise<MergeResult>;
|
|
13
|
+
}
|
|
14
|
+
export declare function createMergeQueue(repoPath: string): MergeQueue;
|
|
15
|
+
//# sourceMappingURL=merge.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { execFile as execFileCb } from 'node:child_process';
|
|
2
|
+
import { resolve, join, sep } from 'node:path';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
const execFile = promisify(execFileCb);
|
|
5
|
+
export function createMergeQueue(repoPath) {
|
|
6
|
+
const worktreesDir = resolve(join(repoPath, '.opencastle', 'worktrees'));
|
|
7
|
+
async function merge(worktreePath, worktreeBranch, targetBranch) {
|
|
8
|
+
const resolvedWorktree = resolve(worktreePath);
|
|
9
|
+
if (!resolvedWorktree.startsWith(worktreesDir + sep)) {
|
|
10
|
+
throw new Error(`Path "${worktreePath}" is outside the managed worktrees directory`);
|
|
11
|
+
}
|
|
12
|
+
// Stage all untracked/modified files in the worktree
|
|
13
|
+
await execFile('git', ['-C', resolvedWorktree, 'add', '-A']);
|
|
14
|
+
// List staged files — non-empty output means there are changes to commit.
|
|
15
|
+
// Uses --name-only (exits 0 regardless of diff size) rather than --quiet
|
|
16
|
+
// (exits 1 when changes exist) so the check is output-based, not exit-code-based.
|
|
17
|
+
const { stdout: staged } = await execFile('git', [
|
|
18
|
+
'-C',
|
|
19
|
+
resolvedWorktree,
|
|
20
|
+
'diff',
|
|
21
|
+
'--cached',
|
|
22
|
+
'--name-only',
|
|
23
|
+
]);
|
|
24
|
+
const hasUncommitted = staged.trim().length > 0;
|
|
25
|
+
if (hasUncommitted) {
|
|
26
|
+
await execFile('git', [
|
|
27
|
+
'-C',
|
|
28
|
+
resolvedWorktree,
|
|
29
|
+
'commit',
|
|
30
|
+
'-m',
|
|
31
|
+
`convoy: ${worktreeBranch} completed`,
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
34
|
+
// Merge the worktree branch into the target branch in the main repo
|
|
35
|
+
await execFile('git', ['-C', repoPath, 'checkout', targetBranch]);
|
|
36
|
+
try {
|
|
37
|
+
const { stdout } = await execFile('git', [
|
|
38
|
+
'-C',
|
|
39
|
+
repoPath,
|
|
40
|
+
'merge',
|
|
41
|
+
worktreeBranch,
|
|
42
|
+
'--no-edit',
|
|
43
|
+
]);
|
|
44
|
+
if (stdout.includes('Already up to date')) {
|
|
45
|
+
return { success: true, conflicted: false, message: 'No changes to merge' };
|
|
46
|
+
}
|
|
47
|
+
return { success: true, conflicted: false, message: 'Merged successfully' };
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
const error = err;
|
|
51
|
+
const isConflict = error.code === 1 &&
|
|
52
|
+
((error.stderr ?? '').includes('CONFLICT') || (error.stdout ?? '').includes('CONFLICT'));
|
|
53
|
+
if (isConflict) {
|
|
54
|
+
await execFile('git', ['-C', repoPath, 'merge', '--abort']);
|
|
55
|
+
return { success: false, conflicted: true, message: 'Merge conflict detected; merge aborted' };
|
|
56
|
+
}
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { merge };
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../src/cli/convoy/merge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.test.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/merge.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync, realpathSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { execFile as execFileCb } from 'node:child_process';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
7
|
+
import { createMergeQueue } from './merge.js';
|
|
8
|
+
const execFile = promisify(execFileCb);
|
|
9
|
+
// ── helpers ───────────────────────────────────────────────────────────────────
|
|
10
|
+
let repoPath;
|
|
11
|
+
let featureBranch;
|
|
12
|
+
let queue;
|
|
13
|
+
async function setupTestRepo() {
|
|
14
|
+
const path = realpathSync(mkdtempSync(join(tmpdir(), 'merge-test-')));
|
|
15
|
+
await execFile('git', ['init', path]);
|
|
16
|
+
await execFile('git', ['-C', path, 'config', 'user.email', 'test@test.com']);
|
|
17
|
+
await execFile('git', ['-C', path, 'config', 'user.name', 'Test']);
|
|
18
|
+
writeFileSync(join(path, 'README.md'), '# Test');
|
|
19
|
+
await execFile('git', ['-C', path, 'add', '-A']);
|
|
20
|
+
await execFile('git', ['-C', path, 'commit', '-m', 'Initial commit']);
|
|
21
|
+
await execFile('git', ['-C', path, 'checkout', '-b', 'feat/test']);
|
|
22
|
+
return { repoPath: path, featureBranch: 'feat/test' };
|
|
23
|
+
}
|
|
24
|
+
async function addWorktree(repo, workerId, branch) {
|
|
25
|
+
const worktreesDir = join(repo, '.opencastle', 'worktrees');
|
|
26
|
+
mkdirSync(worktreesDir, { recursive: true });
|
|
27
|
+
const worktreePath = join(worktreesDir, workerId);
|
|
28
|
+
await execFile('git', ['-C', repo, 'worktree', 'add', worktreePath, '-b', `convoy-${workerId}`, branch]);
|
|
29
|
+
return worktreePath;
|
|
30
|
+
}
|
|
31
|
+
beforeEach(async () => {
|
|
32
|
+
const result = await setupTestRepo();
|
|
33
|
+
repoPath = result.repoPath;
|
|
34
|
+
featureBranch = result.featureBranch;
|
|
35
|
+
queue = createMergeQueue(repoPath);
|
|
36
|
+
});
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
rmSync(repoPath, { recursive: true, force: true });
|
|
39
|
+
});
|
|
40
|
+
// ── successful merge ──────────────────────────────────────────────────────────
|
|
41
|
+
describe('merge - successful merge', () => {
|
|
42
|
+
it('stages, commits, and merges worktree changes to the target branch', async () => {
|
|
43
|
+
const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
|
|
44
|
+
writeFileSync(join(worktreePath, 'output.txt'), 'worker output');
|
|
45
|
+
const result = await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
|
|
46
|
+
expect(result).toEqual({ success: true, conflicted: false, message: 'Merged successfully' });
|
|
47
|
+
});
|
|
48
|
+
it('makes the merged file available in the target branch working tree', async () => {
|
|
49
|
+
const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
|
|
50
|
+
writeFileSync(join(worktreePath, 'output.txt'), 'worker output');
|
|
51
|
+
await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
|
|
52
|
+
const { existsSync } = await import('node:fs');
|
|
53
|
+
expect(existsSync(join(repoPath, 'output.txt'))).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
it('creates an auto-commit on the worktree branch with the convoy message', async () => {
|
|
56
|
+
const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
|
|
57
|
+
writeFileSync(join(worktreePath, 'output.txt'), 'worker output');
|
|
58
|
+
await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
|
|
59
|
+
const { stdout } = await execFile('git', ['-C', repoPath, 'log', '--oneline', 'convoy-worker1']);
|
|
60
|
+
expect(stdout).toContain('convoy: convoy-worker1 completed');
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
// ── no changes ────────────────────────────────────────────────────────────────
|
|
64
|
+
describe('merge - no changes', () => {
|
|
65
|
+
it('returns success with "No changes to merge" when the worker made no file changes', async () => {
|
|
66
|
+
const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
|
|
67
|
+
const result = await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
|
|
68
|
+
expect(result).toEqual({ success: true, conflicted: false, message: 'No changes to merge' });
|
|
69
|
+
});
|
|
70
|
+
it('does not create a commit when there is nothing to stage', async () => {
|
|
71
|
+
const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
|
|
72
|
+
await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
|
|
73
|
+
const { stdout } = await execFile('git', ['-C', repoPath, 'log', '--oneline', 'convoy-worker1']);
|
|
74
|
+
expect(stdout).not.toContain('convoy: convoy-worker1 completed');
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
// ── merge conflict ────────────────────────────────────────────────────────────
|
|
78
|
+
describe('merge - conflict', () => {
|
|
79
|
+
it('returns conflicted: true and aborts when two worktrees edit the same file', async () => {
|
|
80
|
+
const worktree1 = await addWorktree(repoPath, 'worker1', featureBranch);
|
|
81
|
+
const worktree2 = await addWorktree(repoPath, 'worker2', featureBranch);
|
|
82
|
+
writeFileSync(join(worktree1, 'shared.txt'), 'content from worker 1');
|
|
83
|
+
writeFileSync(join(worktree2, 'shared.txt'), 'content from worker 2');
|
|
84
|
+
const first = await queue.merge(worktree1, 'convoy-worker1', featureBranch);
|
|
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');
|
|
90
|
+
});
|
|
91
|
+
it('leaves the repo in a clean state (no pending merge) after aborting a conflict', async () => {
|
|
92
|
+
const worktree1 = await addWorktree(repoPath, 'worker1', featureBranch);
|
|
93
|
+
const worktree2 = await addWorktree(repoPath, 'worker2', featureBranch);
|
|
94
|
+
writeFileSync(join(worktree1, 'shared.txt'), 'content from worker 1');
|
|
95
|
+
writeFileSync(join(worktree2, 'shared.txt'), 'content from worker 2');
|
|
96
|
+
await queue.merge(worktree1, 'convoy-worker1', featureBranch);
|
|
97
|
+
await queue.merge(worktree2, 'convoy-worker2', featureBranch);
|
|
98
|
+
// --untracked-files=no excludes the .opencastle/worktrees/ dir from the check;
|
|
99
|
+
// we only want to verify there is no pending merge (no staged/modified tracked files).
|
|
100
|
+
const { stdout } = await execFile('git', ['-C', repoPath, 'status', '--porcelain', '--untracked-files=no']);
|
|
101
|
+
expect(stdout.trim()).toBe('');
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
// ── already committed changes ─────────────────────────────────────────────────
|
|
105
|
+
describe('merge - already committed changes', () => {
|
|
106
|
+
it('merges pre-committed changes without auto-committing', async () => {
|
|
107
|
+
const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
|
|
108
|
+
writeFileSync(join(worktreePath, 'output.txt'), 'pre-committed content');
|
|
109
|
+
await execFile('git', ['-C', worktreePath, 'add', '-A']);
|
|
110
|
+
await execFile('git', ['-C', worktreePath, 'commit', '-m', 'Worker manual commit']);
|
|
111
|
+
const result = await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
|
|
112
|
+
expect(result).toEqual({ success: true, conflicted: false, message: 'Merged successfully' });
|
|
113
|
+
});
|
|
114
|
+
it('makes pre-committed files available in the target branch after merge', async () => {
|
|
115
|
+
const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
|
|
116
|
+
writeFileSync(join(worktreePath, 'output.txt'), 'pre-committed content');
|
|
117
|
+
await execFile('git', ['-C', worktreePath, 'add', '-A']);
|
|
118
|
+
await execFile('git', ['-C', worktreePath, 'commit', '-m', 'Worker manual commit']);
|
|
119
|
+
await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
|
|
120
|
+
const { existsSync } = await import('node:fs');
|
|
121
|
+
expect(existsSync(join(repoPath, 'output.txt'))).toBe(true);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
// ── error handling ────────────────────────────────────────────────────────────
|
|
125
|
+
describe('merge - error handling', () => {
|
|
126
|
+
it('throws when the worktree branch does not exist in the repo', async () => {
|
|
127
|
+
const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
|
|
128
|
+
await expect(queue.merge(worktreePath, 'nonexistent-branch', featureBranch)).rejects.toThrow();
|
|
129
|
+
});
|
|
130
|
+
it('throws when path is outside the managed worktrees directory', async () => {
|
|
131
|
+
await expect(queue.merge('/tmp/evil', 'some-branch', featureBranch)).rejects.toThrow(/outside the managed worktrees directory/);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
//# sourceMappingURL=merge.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.test.js","sourceRoot":"","sources":["../../../src/cli/convoy/merge.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ConvoyRecord, ConvoyStatus, TaskRecord, ConvoyTaskStatus, WorkerRecord, WorkerStatus, EventRecord } from './types.js';
|
|
2
|
+
export interface ConvoyStore {
|
|
3
|
+
insertConvoy(record: Omit<ConvoyRecord, 'started_at' | 'finished_at'>): void;
|
|
4
|
+
getConvoy(id: string): ConvoyRecord | undefined;
|
|
5
|
+
updateConvoyStatus(id: string, status: ConvoyStatus, extra?: {
|
|
6
|
+
started_at?: string;
|
|
7
|
+
finished_at?: string;
|
|
8
|
+
}): void;
|
|
9
|
+
insertTask(record: Omit<TaskRecord, 'worker_id' | 'worktree' | 'output' | 'exit_code' | 'started_at' | 'finished_at'>): void;
|
|
10
|
+
getTask(id: string, convoyId: string): TaskRecord | undefined;
|
|
11
|
+
getTasksByConvoy(convoyId: string): TaskRecord[];
|
|
12
|
+
updateTaskStatus(id: string, convoyId: string, status: ConvoyTaskStatus, extra?: Partial<Pick<TaskRecord, 'worker_id' | 'worktree' | 'output' | 'exit_code' | 'started_at' | 'finished_at' | 'retries'>>): void;
|
|
13
|
+
getReadyTasks(convoyId: string): TaskRecord[];
|
|
14
|
+
insertWorker(record: Omit<WorkerRecord, 'finished_at' | 'last_heartbeat'>): void;
|
|
15
|
+
getWorker(id: string): WorkerRecord | undefined;
|
|
16
|
+
updateWorkerStatus(id: string, status: WorkerStatus, extra?: Partial<Pick<WorkerRecord, 'finished_at' | 'last_heartbeat' | 'pid'>>): void;
|
|
17
|
+
insertEvent(record: Omit<EventRecord, 'id'>): void;
|
|
18
|
+
getEvents(convoyId: string): EventRecord[];
|
|
19
|
+
withTransaction<T>(fn: () => T): T;
|
|
20
|
+
close(): void;
|
|
21
|
+
}
|
|
22
|
+
export declare function createConvoyStore(dbPath: string): ConvoyStore;
|
|
23
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,WAAW,EACZ,MAAM,YAAY,CAAA;AAInB,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,GAAG,aAAa,CAAC,GAAG,IAAI,CAAA;IAC5E,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAA;IAC/C,kBAAkB,CAChB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,YAAY,EACpB,KAAK,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GACpD,IAAI,CAAA;IACP,UAAU,CACR,MAAM,EAAE,IAAI,CACV,UAAU,EACV,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,YAAY,GAAG,aAAa,CACjF,GACA,IAAI,CAAA;IACP,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAA;IAC7D,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CAAA;IAChD,gBAAgB,CACd,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,gBAAgB,EACxB,KAAK,CAAC,EAAE,OAAO,CACb,IAAI,CAAC,UAAU,EAAE,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,YAAY,GAAG,aAAa,GAAG,SAAS,CAAC,CAC/G,GACA,IAAI,CAAA;IACP,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CAAA;IAC7C,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,aAAa,GAAG,gBAAgB,CAAC,GAAG,IAAI,CAAA;IAChF,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAA;IAC/C,kBAAkB,CAChB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,YAAY,EACpB,KAAK,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,aAAa,GAAG,gBAAgB,GAAG,KAAK,CAAC,CAAC,GAC5E,IAAI,CAAA;IACP,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,IAAI,CAAA;IAClD,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CAAA;IAC1C,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAA;IAClC,KAAK,IAAI,IAAI,CAAA;CACd;AAgQD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAE7D"}
|