@zoebuildsai/trace 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/.gitignore +115 -0
  2. package/.trace/progress.json +22 -0
  3. package/README.md +466 -0
  4. package/RELEASE-NOTES-1.5.0.md +410 -0
  5. package/STATUS.md +245 -0
  6. package/dist/auto-commit.d.ts +66 -0
  7. package/dist/auto-commit.d.ts.map +1 -0
  8. package/dist/auto-commit.js +180 -0
  9. package/dist/auto-commit.js.map +1 -0
  10. package/dist/cli.d.ts +7 -0
  11. package/dist/cli.d.ts.map +1 -0
  12. package/dist/cli.js +246 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/commands.d.ts +46 -0
  15. package/dist/commands.d.ts.map +1 -0
  16. package/dist/commands.js +256 -0
  17. package/dist/commands.js.map +1 -0
  18. package/dist/diff.d.ts +23 -0
  19. package/dist/diff.d.ts.map +1 -0
  20. package/dist/diff.js +106 -0
  21. package/dist/diff.js.map +1 -0
  22. package/dist/github.d.ts.map +1 -0
  23. package/dist/github.js.map +1 -0
  24. package/dist/index-cache.d.ts +35 -0
  25. package/dist/index-cache.d.ts.map +1 -0
  26. package/dist/index-cache.js +114 -0
  27. package/dist/index-cache.js.map +1 -0
  28. package/dist/index.d.ts +15 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +25 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/storage.d.ts +45 -0
  33. package/dist/storage.d.ts.map +1 -0
  34. package/dist/storage.js +151 -0
  35. package/dist/storage.js.map +1 -0
  36. package/dist/sync.d.ts +60 -0
  37. package/dist/sync.js +184 -0
  38. package/dist/tags.d.ts +85 -0
  39. package/dist/tags.d.ts.map +1 -0
  40. package/dist/tags.js +219 -0
  41. package/dist/tags.js.map +1 -0
  42. package/dist/types.d.ts +102 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +6 -0
  45. package/dist/types.js.map +1 -0
  46. package/docs/.nojekyll +0 -0
  47. package/docs/README.md +73 -0
  48. package/docs/_config.yml +2 -0
  49. package/docs/index.html +960 -0
  50. package/docs-website/package.json +20 -0
  51. package/jest.config.js +21 -0
  52. package/package.json +50 -0
  53. package/scripts/init.ts +290 -0
  54. package/src/agent-audit.ts +270 -0
  55. package/src/agent-checkout.ts +227 -0
  56. package/src/agent-coordination.ts +318 -0
  57. package/src/async-queue.ts +203 -0
  58. package/src/auto-branching.ts +279 -0
  59. package/src/auto-commit.ts +166 -0
  60. package/src/cherry-pick.ts +252 -0
  61. package/src/chunked-upload.ts +224 -0
  62. package/src/cli-v2.ts +335 -0
  63. package/src/cli.ts +318 -0
  64. package/src/cliff-detection.ts +232 -0
  65. package/src/commands.ts +267 -0
  66. package/src/commit-hash-system.ts +351 -0
  67. package/src/compression.ts +176 -0
  68. package/src/conflict-resolution-ui.ts +277 -0
  69. package/src/conflict-visualization.ts +238 -0
  70. package/src/diff-formatter.ts +184 -0
  71. package/src/diff.ts +124 -0
  72. package/src/distributed-coordination.ts +273 -0
  73. package/src/git-interop.ts +316 -0
  74. package/src/index-cache.ts +88 -0
  75. package/src/index.ts +38 -0
  76. package/src/merge-engine.ts +143 -0
  77. package/src/message-search.ts +370 -0
  78. package/src/performance-monitoring.ts +236 -0
  79. package/src/rebase.ts +327 -0
  80. package/src/rollback.ts +215 -0
  81. package/src/semantic-grouping.ts +245 -0
  82. package/src/stage-area.ts +324 -0
  83. package/src/stash.ts +278 -0
  84. package/src/storage.ts +131 -0
  85. package/src/sync.ts +205 -0
  86. package/src/tags.ts +244 -0
  87. package/src/types.ts +119 -0
  88. package/src/webhooks.ts +119 -0
  89. package/src/workspace-isolation.ts +298 -0
  90. package/tests/auto-commit.test.ts +308 -0
  91. package/tests/checkout.test.ts +136 -0
  92. package/tests/commit.test.ts +118 -0
  93. package/tests/diff.test.ts +191 -0
  94. package/tests/github.test.ts +94 -0
  95. package/tests/integration.test.ts +267 -0
  96. package/tests/log.test.ts +125 -0
  97. package/tests/phase2-integration.test.ts +370 -0
  98. package/tests/storage.test.ts +167 -0
  99. package/tests/tags.test.ts +477 -0
  100. package/tests/types.test.ts +75 -0
  101. package/tests/v1.1/agent-audit.test.ts +472 -0
  102. package/tests/v1.1/agent-coordination.test.ts +308 -0
  103. package/tests/v1.1/async-queue.test.ts +253 -0
  104. package/tests/v1.1/comprehensive.test.ts +521 -0
  105. package/tests/v1.1/diff-formatter.test.ts +238 -0
  106. package/tests/v1.1/integration.test.ts +389 -0
  107. package/tests/v1.1/onboarding.test.ts +365 -0
  108. package/tests/v1.1/rollback.test.ts +370 -0
  109. package/tests/v1.1/semantic-grouping.test.ts +230 -0
  110. package/tests/v1.2/chunked-upload.test.ts +301 -0
  111. package/tests/v1.2/cliff-detection.test.ts +272 -0
  112. package/tests/v1.2/commit-hash-system.test.ts +288 -0
  113. package/tests/v1.2/compression.test.ts +220 -0
  114. package/tests/v1.2/conflict-visualization.test.ts +263 -0
  115. package/tests/v1.2/distributed.test.ts +261 -0
  116. package/tests/v1.2/performance-monitoring.test.ts +328 -0
  117. package/tests/v1.3/auto-branching.test.ts +270 -0
  118. package/tests/v1.3/message-search.test.ts +264 -0
  119. package/tests/v1.3/stage-area.test.ts +330 -0
  120. package/tests/v1.3/stash-rebase-cherry-pick.test.ts +361 -0
  121. package/tests/v1.4/cli.test.ts +171 -0
  122. package/tests/v1.4/conflict-resolution-advanced.test.ts +429 -0
  123. package/tests/v1.4/conflict-resolution-ui.test.ts +286 -0
  124. package/tests/v1.4/workspace-isolation-advanced.test.ts +382 -0
  125. package/tests/v1.4/workspace-isolation.test.ts +268 -0
  126. package/tests/v1.5/agent-coordination.real.test.ts +401 -0
  127. package/tests/v1.5/cli-v2.test.ts +354 -0
  128. package/tests/v1.5/git-interop.real.test.ts +358 -0
  129. package/tests/v1.5/integration-testing.real.test.ts +440 -0
  130. package/tsconfig.json +26 -0
@@ -0,0 +1,401 @@
1
+ /**
2
+ * Real Agent Coordination Tests
3
+ * Not mocks. Actual concurrent simulation.
4
+ * Tests whether coordination actually prevents collisions
5
+ */
6
+
7
+ import { AgentCoordination } from '../../src/agent-coordination';
8
+
9
+ describe('AgentCoordination - Real Scenarios', () => {
10
+ let coord: AgentCoordination;
11
+
12
+ beforeEach(() => {
13
+ coord = new AgentCoordination({
14
+ allowParallel: true,
15
+ maxConcurrent: 10,
16
+ lockTimeout: 100, // Short timeout for testing
17
+ conflictStrategy: 'block',
18
+ });
19
+ });
20
+
21
+ afterEach(() => {
22
+ coord.clear();
23
+ });
24
+
25
+ describe('Collision Prevention', () => {
26
+ test('prevents two agents from editing same file', () => {
27
+ // Agent A starts editing file X
28
+ const taskA = coord.registerTask('agent-a', ['src/main.ts'], 1);
29
+ expect(taskA.canStart).toBe(true);
30
+
31
+ const lockA = coord.requestLock('src/main.ts', 'agent-a');
32
+ expect(lockA.locked).toBe(true);
33
+
34
+ // Agent B tries to edit same file
35
+ const taskB = coord.registerTask('agent-b', ['src/main.ts'], 1);
36
+ expect(taskB.canStart).toBe(false);
37
+ expect(taskB.blockedBy).toContain(taskA.taskId);
38
+
39
+ // Verify lock is held
40
+ expect(coord.getLockHolder('src/main.ts')).toBe('agent-a');
41
+
42
+ // Agent A releases lock
43
+ coord.releaseLock('src/main.ts', 'agent-a');
44
+ coord.completeTask(taskA.taskId);
45
+
46
+ // Now Agent B should be able to proceed
47
+ const lockB = coord.requestLock('src/main.ts', 'agent-b');
48
+ expect(lockB.locked).toBe(true);
49
+ });
50
+
51
+ test('allows parallel edits to different files', () => {
52
+ const taskA = coord.registerTask('agent-a', ['src/api.ts'], 1);
53
+ const taskB = coord.registerTask('agent-b', ['src/utils.ts'], 1);
54
+ const taskC = coord.registerTask('agent-c', ['tests/main.test.ts'], 1);
55
+
56
+ expect(taskA.canStart).toBe(true);
57
+ expect(taskB.canStart).toBe(true);
58
+ expect(taskC.canStart).toBe(true);
59
+
60
+ // All should get locks
61
+ expect(coord.requestLock('src/api.ts', 'agent-a').locked).toBe(true);
62
+ expect(coord.requestLock('src/utils.ts', 'agent-b').locked).toBe(true);
63
+ expect(coord.requestLock('tests/main.test.ts', 'agent-c').locked).toBe(true);
64
+ });
65
+
66
+ test('detects multi-file conflicts', () => {
67
+ // Agent A edits files X and Y
68
+ const taskA = coord.registerTask('agent-a', ['src/types.ts', 'src/main.ts'], 2);
69
+ expect(taskA.canStart).toBe(true);
70
+
71
+ // Agent B edits files Y and Z
72
+ const taskB = coord.registerTask('agent-b', ['src/main.ts', 'src/utils.ts'], 1);
73
+ expect(taskB.canStart).toBe(false);
74
+ expect(taskB.blockedBy).toContain(taskA.taskId);
75
+ });
76
+
77
+ test('handles task completion and auto-unblocking', () => {
78
+ const taskA = coord.registerTask('agent-a', ['file.ts'], 1);
79
+ const taskB = coord.registerTask('agent-b', ['file.ts'], 1);
80
+
81
+ expect(taskB.canStart).toBe(false);
82
+
83
+ const result = coord.completeTask(taskA.taskId);
84
+ expect(result.success).toBe(true);
85
+ expect(result.unblocked).toContain(taskB.taskId);
86
+
87
+ const updated = coord.getTaskStatus(taskB.taskId);
88
+ expect(updated?.status).toBe('executing');
89
+ });
90
+ });
91
+
92
+ describe('Lock Management', () => {
93
+ test('lock is exclusive (only one owner)', () => {
94
+ const lock1 = coord.requestLock('file.ts', 'agent-1');
95
+ expect(lock1.locked).toBe(true);
96
+
97
+ const lock2 = coord.requestLock('file.ts', 'agent-2');
98
+ expect(lock2.locked).toBe(false);
99
+ expect(lock2.owner).toBe('agent-1');
100
+ });
101
+
102
+ test('agent can acquire own lock multiple times', () => {
103
+ const lock1 = coord.requestLock('file.ts', 'agent-a');
104
+ expect(lock1.locked).toBe(true);
105
+
106
+ const lock2 = coord.requestLock('file.ts', 'agent-a');
107
+ expect(lock2.locked).toBe(true);
108
+ });
109
+
110
+ test('only lock owner can release', () => {
111
+ coord.requestLock('file.ts', 'agent-a');
112
+
113
+ const release1 = coord.releaseLock('file.ts', 'agent-b');
114
+ expect(release1).toBe(false); // Wrong owner
115
+
116
+ const release2 = coord.releaseLock('file.ts', 'agent-a');
117
+ expect(release2).toBe(true); // Correct owner
118
+ });
119
+ });
120
+
121
+ describe('Complex Dependencies', () => {
122
+ test('chains tasks correctly (A -> B -> C)', () => {
123
+ // Task A edits types.ts
124
+ const taskA = coord.registerTask('agent-a', ['src/types.ts'], 3);
125
+ expect(taskA.canStart).toBe(true);
126
+
127
+ // Task B edits api.ts (depends on types.ts being done)
128
+ const taskB = coord.registerTask('agent-b', ['src/api.ts', 'src/types.ts'], 2);
129
+ expect(taskB.canStart).toBe(false); // Blocked by A
130
+ expect(taskB.blockedBy).toContain(taskA.taskId);
131
+
132
+ // Task C edits tests (depends on both)
133
+ const taskC = coord.registerTask('agent-c', ['src/types.ts', 'src/api.ts'], 1);
134
+ expect(taskC.canStart).toBe(false); // Blocked by A
135
+ expect(taskC.blockedBy).toContain(taskA.taskId);
136
+
137
+ // Complete A
138
+ coord.completeTask(taskA.taskId);
139
+ const unblocked1 = coord.completeTask(taskA.taskId);
140
+
141
+ // Now B should be unblocked
142
+ const statusB = coord.getTaskStatus(taskB.taskId);
143
+ expect(statusB?.status).toBe('executing');
144
+
145
+ // But C still blocked by B
146
+ const statusC = coord.getTaskStatus(taskC.taskId);
147
+ expect(statusC?.status).toBe('blocked');
148
+
149
+ // Complete B
150
+ coord.completeTask(taskB.taskId);
151
+
152
+ // Now C should be unblocked
153
+ const statusC2 = coord.getTaskStatus(taskC.taskId);
154
+ expect(statusC2?.status).toBe('executing');
155
+ });
156
+
157
+ test('suggests optimal task order', () => {
158
+ // Create tasks with priority
159
+ const high = coord.registerTask('agent-1', ['file.ts'], 10);
160
+ const medium = coord.registerTask('agent-2', ['other.ts'], 5);
161
+ const low = coord.registerTask('agent-3', ['file.ts'], 1); // Blocked by high
162
+
163
+ const order = coord.suggestOrder();
164
+
165
+ // High priority should be first
166
+ const highIdx = order.indexOf(high.taskId);
167
+ const mediumIdx = order.indexOf(medium.taskId);
168
+ const lowIdx = order.indexOf(low.taskId);
169
+
170
+ expect(highIdx).toBeLessThan(mediumIdx);
171
+ // Low is blocked, so should be last
172
+ expect(lowIdx).toBeGreaterThan(highIdx);
173
+ });
174
+ });
175
+
176
+ describe('Concurrent Agents', () => {
177
+ test('handles 10 agents registering tasks simultaneously', () => {
178
+ const agents = Array.from({ length: 10 }, (_, i) => `agent-${i}`);
179
+ const files = Array.from({ length: 10 }, (_, i) => `file${i}.ts`);
180
+
181
+ const tasks = agents.map((agent, i) => {
182
+ // Each agent edits a unique file
183
+ return coord.registerTask(agent, [files[i]], i);
184
+ });
185
+
186
+ // All should start without blocking
187
+ tasks.forEach(task => {
188
+ expect(task.canStart).toBe(true);
189
+ });
190
+
191
+ // All should have locks
192
+ files.forEach((file, i) => {
193
+ expect(coord.getLockHolder(file)).toBe(`agent-${i}`);
194
+ });
195
+ });
196
+
197
+ test('handles 10 agents all editing same file (serial)', () => {
198
+ const agents = Array.from({ length: 10 }, (_, i) => `agent-${i}`);
199
+
200
+ const tasks = agents.map((agent, i) => {
201
+ return coord.registerTask(agent, ['shared.ts'], 10 - i); // Higher priority = earlier
202
+ });
203
+
204
+ // First should start
205
+ expect(tasks[0].canStart).toBe(true);
206
+
207
+ // Rest should be blocked
208
+ for (let i = 1; i < tasks.length; i++) {
209
+ expect(tasks[i].canStart).toBe(false);
210
+ }
211
+
212
+ // Simulate completion chain
213
+ let unblocked: string[] = [];
214
+ coord.completeTask(tasks[0].taskId);
215
+
216
+ // Each completion should unblock the next
217
+ for (let i = 1; i < tasks.length; i++) {
218
+ unblocked = coord.completeTask(tasks[i - 1].taskId).unblocked;
219
+ if (i < tasks.length - 1) {
220
+ expect(unblocked).toContain(tasks[i].taskId);
221
+ }
222
+ }
223
+ });
224
+
225
+ test('high priority tasks wait if file is locked', () => {
226
+ // Low priority agent gets lock first (registered first)
227
+ const low = coord.registerTask('agent-low', ['file.ts'], 1);
228
+ expect(low.canStart).toBe(true);
229
+
230
+ // Lock it
231
+ coord.requestLock('file.ts', 'agent-low');
232
+
233
+ // High priority agent tries to use same file
234
+ const high = coord.registerTask('agent-high', ['file.ts'], 100);
235
+ expect(high.canStart).toBe(false); // Still blocked by collision, not priority
236
+ expect(high.blockedBy).toContain(low.taskId);
237
+ });
238
+ });
239
+
240
+ describe('Statistics and Monitoring', () => {
241
+ test('tracks task count correctly', () => {
242
+ let stats = coord.getStats();
243
+ expect(stats.totalTasks).toBe(0);
244
+
245
+ coord.registerTask('agent-a', ['file.ts'], 1);
246
+ stats = coord.getStats();
247
+ expect(stats.totalTasks).toBe(1);
248
+ expect(stats.executing).toBe(1);
249
+
250
+ coord.registerTask('agent-b', ['file.ts'], 1);
251
+ stats = coord.getStats();
252
+ expect(stats.totalTasks).toBe(2);
253
+ expect(stats.blocked).toBe(1);
254
+ });
255
+
256
+ test('tracks lock count', () => {
257
+ let stats = coord.getStats();
258
+ expect(stats.currentLocks).toBe(0);
259
+
260
+ coord.requestLock('file1.ts', 'agent-a');
261
+ stats = coord.getStats();
262
+ expect(stats.currentLocks).toBe(1);
263
+
264
+ coord.requestLock('file2.ts', 'agent-b');
265
+ stats = coord.getStats();
266
+ expect(stats.currentLocks).toBe(2);
267
+ });
268
+
269
+ test('calculates average wait time for blocked tasks', () => {
270
+ const taskA = coord.registerTask('agent-a', ['file.ts'], 1);
271
+ const taskB = coord.registerTask('agent-b', ['file.ts'], 1);
272
+
273
+ let stats = coord.getStats();
274
+ // taskB is blocked
275
+ expect(stats.blocked).toBe(1);
276
+ expect(stats.avgWaitTime).toBeGreaterThanOrEqual(0);
277
+
278
+ // Wait a bit
279
+ const wait = 50;
280
+ const before = Date.now();
281
+ while (Date.now() - before < wait) {
282
+ // Spin
283
+ }
284
+
285
+ coord.completeTask(taskA.taskId);
286
+ stats = coord.getStats();
287
+ // Wait time should be at least the time we waited
288
+ expect(stats.avgWaitTime).toBeGreaterThanOrEqual(0);
289
+ });
290
+
291
+ test('formats state for display', () => {
292
+ coord.registerTask('agent-a', ['file.ts'], 1);
293
+ coord.registerTask('agent-b', ['file.ts'], 1);
294
+
295
+ const state = coord.formatState();
296
+ expect(state).toContain('AGENT COORDINATION STATE');
297
+ expect(state).toContain('BLOCKED TASKS');
298
+ expect(state).toContain('agent-b');
299
+ });
300
+ });
301
+
302
+ describe('Policy Configuration', () => {
303
+ test('respects conflict strategy', () => {
304
+ coord.setPolicy({ conflictStrategy: 'merge' });
305
+
306
+ const taskA = coord.registerTask('agent-a', ['file.ts'], 1);
307
+ const taskB = coord.registerTask('agent-b', ['file.ts'], 1);
308
+
309
+ // With 'merge' strategy, both could theoretically proceed
310
+ // (Though in practice, merge conflict resolution is handled elsewhere)
311
+ expect(taskA.canStart).toBe(true);
312
+ // taskB is still blocked because it's the same file
313
+ });
314
+
315
+ test('respects max concurrent policy', () => {
316
+ coord.setPolicy({ maxConcurrent: 2 });
317
+
318
+ const t1 = coord.registerTask('agent-1', ['f1.ts'], 1);
319
+ const t2 = coord.registerTask('agent-2', ['f2.ts'], 1);
320
+ const t3 = coord.registerTask('agent-3', ['f3.ts'], 1); // 3rd task
321
+
322
+ // All can still start because they don't conflict
323
+ // maxConcurrent is advisory, not enforced here
324
+ // (Enforcement would be at higher level)
325
+ });
326
+ });
327
+
328
+ describe('Edge Cases', () => {
329
+ test('empty file list in task', () => {
330
+ const task = coord.registerTask('agent-a', [], 1);
331
+ expect(task.canStart).toBe(true);
332
+ });
333
+
334
+ test('very long file list', () => {
335
+ const files = Array.from({ length: 1000 }, (_, i) => `file${i}.ts`);
336
+ const task = coord.registerTask('agent-a', files, 1);
337
+ expect(task.canStart).toBe(true);
338
+ });
339
+
340
+ test('non-existent task completion returns false', () => {
341
+ const result = coord.completeTask('non-existent-task');
342
+ expect(result.success).toBe(false);
343
+ });
344
+
345
+ test('multiple completion calls are idempotent', () => {
346
+ const task = coord.registerTask('agent-a', ['file.ts'], 1);
347
+
348
+ const result1 = coord.completeTask(task.taskId);
349
+ expect(result1.success).toBe(true);
350
+
351
+ const result2 = coord.completeTask(task.taskId);
352
+ expect(result2.success).toBe(false); // Already completed
353
+ });
354
+ });
355
+
356
+ describe('Performance', () => {
357
+ test('registers 1000 tasks in <500ms', () => {
358
+ const start = Date.now();
359
+
360
+ for (let i = 0; i < 1000; i++) {
361
+ coord.registerTask(`agent-${i % 10}`, [`file${i % 100}.ts`], 1);
362
+ }
363
+
364
+ const elapsed = Date.now() - start;
365
+ expect(elapsed).toBeLessThan(500);
366
+ });
367
+
368
+ test('conflict detection is O(N) not O(N²)', () => {
369
+ // Register 100 non-conflicting tasks
370
+ const start1 = Date.now();
371
+ for (let i = 0; i < 100; i++) {
372
+ coord.registerTask(`agent-${i}`, [`file${i}.ts`], 1);
373
+ }
374
+ const time1 = Date.now() - start1;
375
+
376
+ coord.clear();
377
+
378
+ // Register 200 non-conflicting tasks
379
+ const start2 = Date.now();
380
+ for (let i = 0; i < 200; i++) {
381
+ coord.registerTask(`agent-${i}`, [`file${i}.ts`], 1);
382
+ }
383
+ const time2 = Date.now() - start2;
384
+
385
+ // Time should roughly double (O(N))
386
+ // Not quadruple (O(N²))
387
+ expect(time2).toBeLessThan(time1 * 3); // Allow some overhead
388
+ });
389
+
390
+ test('lock operations are instant', () => {
391
+ const start = Date.now();
392
+
393
+ for (let i = 0; i < 1000; i++) {
394
+ coord.requestLock(`file${i % 50}.ts`, `agent-${i % 10}`);
395
+ }
396
+
397
+ const elapsed = Date.now() - start;
398
+ expect(elapsed).toBeLessThan(100);
399
+ });
400
+ });
401
+ });