@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,252 @@
1
+ /**
2
+ * Cherry-Pick for Trace
3
+ * Apply specific commits to current branch
4
+ */
5
+
6
+ export interface CherryPickOperation {
7
+ sourceCommit: string;
8
+ sourceMessage: string;
9
+ targetBranch: string;
10
+ newCommitHash: string;
11
+ timestamp: number;
12
+ success: boolean;
13
+ conflicts?: string[];
14
+ }
15
+
16
+ export interface CherryPickOptions {
17
+ author?: string;
18
+ timestamp?: number;
19
+ signoff?: boolean;
20
+ }
21
+
22
+ export class CherryPick {
23
+ private operations: CherryPickOperation[] = [];
24
+ private cherryPickedCommits: Set<string> = new Set();
25
+
26
+ /**
27
+ * Cherry-pick commit to current branch
28
+ */
29
+ pick(
30
+ sourceCommit: any, // commit object
31
+ targetBranch: string,
32
+ options?: CherryPickOptions
33
+ ): {
34
+ success: boolean;
35
+ newHash?: string;
36
+ conflicts: string[];
37
+ } {
38
+ const conflicts: string[] = [];
39
+
40
+ // Check if already cherry-picked
41
+ if (this.cherryPickedCommits.has(sourceCommit.hash)) {
42
+ conflicts.push(`Commit ${sourceCommit.hash} already cherry-picked`);
43
+ return { success: false, conflicts };
44
+ }
45
+
46
+ // Simulate conflict detection
47
+ const hasConflict = Math.random() < 0.05; // 5% conflict rate
48
+
49
+ if (hasConflict) {
50
+ conflicts.push('src/file.ts'); // Would detect actual conflicts
51
+ }
52
+
53
+ // Generate new commit hash
54
+ const message = options?.signoff
55
+ ? `${sourceCommit.message}\n\n(cherry picked from commit ${sourceCommit.hash})`
56
+ : sourceCommit.message;
57
+
58
+ const newHash = this.generateNewHash(sourceCommit, targetBranch, message);
59
+
60
+ const operation: CherryPickOperation = {
61
+ sourceCommit: sourceCommit.hash,
62
+ sourceMessage: sourceCommit.message,
63
+ targetBranch,
64
+ newCommitHash: newHash,
65
+ timestamp: options?.timestamp || Date.now(),
66
+ success: conflicts.length === 0,
67
+ conflicts: conflicts.length > 0 ? conflicts : undefined,
68
+ };
69
+
70
+ this.operations.push(operation);
71
+
72
+ if (operation.success) {
73
+ this.cherryPickedCommits.add(sourceCommit.hash);
74
+ }
75
+
76
+ return {
77
+ success: operation.success,
78
+ newHash: newHash,
79
+ conflicts,
80
+ };
81
+ }
82
+
83
+ /**
84
+ * Pick multiple commits
85
+ */
86
+ pickMultiple(
87
+ sourceCommits: any[],
88
+ targetBranch: string,
89
+ options?: CherryPickOptions
90
+ ): {
91
+ success: boolean;
92
+ picked: number;
93
+ failed: number;
94
+ allConflicts: string[];
95
+ } {
96
+ let picked = 0;
97
+ let failed = 0;
98
+ const allConflicts: string[] = [];
99
+
100
+ for (const commit of sourceCommits) {
101
+ const result = this.pick(commit, targetBranch, options);
102
+ if (result.success) {
103
+ picked++;
104
+ } else {
105
+ failed++;
106
+ allConflicts.push(...result.conflicts);
107
+ }
108
+ }
109
+
110
+ return {
111
+ success: failed === 0,
112
+ picked,
113
+ failed,
114
+ allConflicts,
115
+ };
116
+ }
117
+
118
+ /**
119
+ * Continue after conflict resolution
120
+ */
121
+ continueAfterResolution(resolvedFiles: Map<string, string>): boolean {
122
+ // In real implementation, would verify conflicts are resolved
123
+ // and continue applying changes
124
+ return true;
125
+ }
126
+
127
+ /**
128
+ * Abort cherry-pick (rollback)
129
+ */
130
+ abort(): boolean {
131
+ if (this.operations.length === 0) {
132
+ return false;
133
+ }
134
+
135
+ const lastOp = this.operations[this.operations.length - 1];
136
+ this.cherryPickedCommits.delete(lastOp.sourceCommit);
137
+ this.operations.pop();
138
+
139
+ return true;
140
+ }
141
+
142
+ /**
143
+ * Get cherry-pick history
144
+ */
145
+ getHistory(): CherryPickOperation[] {
146
+ return [...this.operations];
147
+ }
148
+
149
+ /**
150
+ * Check if commit was cherry-picked
151
+ */
152
+ isPickedBefore(commitHash: string): boolean {
153
+ return this.cherryPickedCommits.has(commitHash);
154
+ }
155
+
156
+ /**
157
+ * Get all picked commits
158
+ */
159
+ getPickedCommits(): string[] {
160
+ return Array.from(this.cherryPickedCommits);
161
+ }
162
+
163
+ /**
164
+ * Get operations by branch
165
+ */
166
+ getOperationsByBranch(branch: string): CherryPickOperation[] {
167
+ return this.operations.filter(op => op.targetBranch === branch);
168
+ }
169
+
170
+ /**
171
+ * Get failed picks (with conflicts)
172
+ */
173
+ getFailedPicks(): CherryPickOperation[] {
174
+ return this.operations.filter(op => !op.success);
175
+ }
176
+
177
+ /**
178
+ * Get stats
179
+ */
180
+ getStats(): {
181
+ totalPicks: number;
182
+ successfulPicks: number;
183
+ failedPicks: number;
184
+ successRate: number;
185
+ } {
186
+ const successful = this.operations.filter(op => op.success).length;
187
+ const failed = this.operations.length - successful;
188
+
189
+ return {
190
+ totalPicks: this.operations.length,
191
+ successfulPicks: successful,
192
+ failedPicks: failed,
193
+ successRate:
194
+ this.operations.length > 0 ? (successful / this.operations.length) * 100 : 0,
195
+ };
196
+ }
197
+
198
+ /**
199
+ * Format operation for display
200
+ */
201
+ static formatOperation(op: CherryPickOperation): string {
202
+ const status = op.success ? '✓' : '✗';
203
+ let output = `${status} ${op.sourceCommit.substring(0, 7)} - ${op.sourceMessage}\n`;
204
+ output += ` Target: ${op.targetBranch} → ${op.newCommitHash.substring(0, 7)}\n`;
205
+
206
+ if (op.conflicts && op.conflicts.length > 0) {
207
+ output += ` Conflicts: ${op.conflicts.join(', ')}\n`;
208
+ }
209
+
210
+ return output;
211
+ }
212
+
213
+ /**
214
+ * Format history for display
215
+ */
216
+ static formatHistory(operations: CherryPickOperation[]): string {
217
+ if (operations.length === 0) {
218
+ return 'No cherry-pick operations.';
219
+ }
220
+
221
+ let output = `\n🍒 CHERRY-PICKS (${operations.length} total):\n`;
222
+
223
+ for (const op of operations) {
224
+ output += this.formatOperation(op);
225
+ }
226
+
227
+ return output;
228
+ }
229
+
230
+ /**
231
+ * Generate new hash for cherry-picked commit
232
+ */
233
+ private generateNewHash(commit: any, targetBranch: string, message: string): string {
234
+ const content = [commit.hash, targetBranch, message].join('|');
235
+ const hash = require('crypto')
236
+ .createHash('sha256')
237
+ .update(content)
238
+ .digest('hex')
239
+ .substring(0, 16);
240
+ return hash;
241
+ }
242
+
243
+ /**
244
+ * Clear history (for testing)
245
+ */
246
+ clearHistory(): void {
247
+ this.operations = [];
248
+ this.cherryPickedCommits.clear();
249
+ }
250
+ }
251
+
252
+ export default CherryPick;
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Chunked Upload Engine for Trace
3
+ * Handle large files (100MB+) efficiently
4
+ */
5
+
6
+ export interface Chunk {
7
+ id: string;
8
+ fileId: string;
9
+ index: number;
10
+ totalChunks: number;
11
+ hash: string;
12
+ size: number;
13
+ compressed: boolean;
14
+ }
15
+
16
+ export interface ChunkedFile {
17
+ fileId: string;
18
+ fileName: string;
19
+ totalSize: number;
20
+ chunkSize: number;
21
+ totalChunks: number;
22
+ chunks: Chunk[];
23
+ status: 'uploading' | 'completed' | 'failed';
24
+ progress: number;
25
+ }
26
+
27
+ export class ChunkedUploadEngine {
28
+ private uploads: Map<string, ChunkedFile> = new Map();
29
+ private chunkStore: Map<string, Buffer> = new Map();
30
+ private defaultChunkSize: number = 5 * 1024 * 1024; // 5MB
31
+
32
+ /**
33
+ * Start chunked upload
34
+ */
35
+ initUpload(fileId: string, fileName: string, totalSize: number, chunkSize?: number): ChunkedFile {
36
+ const size = chunkSize || this.defaultChunkSize;
37
+ const totalChunks = Math.ceil(totalSize / size);
38
+
39
+ const file: ChunkedFile = {
40
+ fileId,
41
+ fileName,
42
+ totalSize,
43
+ chunkSize: size,
44
+ totalChunks,
45
+ chunks: [],
46
+ status: 'uploading',
47
+ progress: 0,
48
+ };
49
+
50
+ this.uploads.set(fileId, file);
51
+ return file;
52
+ }
53
+
54
+ /**
55
+ * Upload single chunk
56
+ */
57
+ uploadChunk(fileId: string, index: number, data: Buffer, hash: string): Chunk {
58
+ const file = this.uploads.get(fileId);
59
+ if (!file) throw new Error(`Upload ${fileId} not found`);
60
+
61
+ const chunk: Chunk = {
62
+ id: `${fileId}-${index}`,
63
+ fileId,
64
+ index,
65
+ totalChunks: file.totalChunks,
66
+ hash,
67
+ size: data.length,
68
+ compressed: false,
69
+ };
70
+
71
+ // Store chunk
72
+ this.chunkStore.set(chunk.id, data);
73
+ file.chunks.push(chunk);
74
+
75
+ // Update progress
76
+ file.progress = (file.chunks.length / file.totalChunks) * 100;
77
+
78
+ // Mark complete if all chunks received
79
+ if (file.chunks.length === file.totalChunks) {
80
+ file.status = 'completed';
81
+ }
82
+
83
+ return chunk;
84
+ }
85
+
86
+ /**
87
+ * Verify chunk integrity
88
+ */
89
+ verifyChunk(chunkId: string, expectedHash: string): boolean {
90
+ const data = this.chunkStore.get(chunkId);
91
+ if (!data) return false;
92
+
93
+ // Simple checksum (in production, use SHA-256)
94
+ const hash = this.calculateHash(data);
95
+ return hash === expectedHash;
96
+ }
97
+
98
+ /**
99
+ * Get upload status
100
+ */
101
+ getUploadStatus(fileId: string): ChunkedFile | undefined {
102
+ return this.uploads.get(fileId);
103
+ }
104
+
105
+ /**
106
+ * Reconstruct file from chunks
107
+ */
108
+ reconstructFile(fileId: string): Buffer {
109
+ const file = this.uploads.get(fileId);
110
+ if (!file || file.status !== 'completed') {
111
+ throw new Error(`Upload ${fileId} not complete`);
112
+ }
113
+
114
+ // Sort chunks by index
115
+ const sortedChunks = [...file.chunks].sort((a, b) => a.index - b.index);
116
+
117
+ // Concatenate chunks
118
+ const buffers: Buffer[] = [];
119
+ for (const chunk of sortedChunks) {
120
+ const data = this.chunkStore.get(chunk.id);
121
+ if (!data) throw new Error(`Chunk ${chunk.id} not found`);
122
+ buffers.push(data);
123
+ }
124
+
125
+ return Buffer.concat(buffers);
126
+ }
127
+
128
+ /**
129
+ * Resume interrupted upload
130
+ */
131
+ getMissingChunks(fileId: string): number[] {
132
+ const file = this.uploads.get(fileId);
133
+ if (!file) return [];
134
+
135
+ const uploadedIndices = new Set(file.chunks.map(c => c.index));
136
+ const missing: number[] = [];
137
+
138
+ for (let i = 0; i < file.totalChunks; i++) {
139
+ if (!uploadedIndices.has(i)) {
140
+ missing.push(i);
141
+ }
142
+ }
143
+
144
+ return missing;
145
+ }
146
+
147
+ /**
148
+ * Cancel upload
149
+ */
150
+ cancelUpload(fileId: string): boolean {
151
+ const file = this.uploads.get(fileId);
152
+ if (!file) return false;
153
+
154
+ // Clean up chunks
155
+ for (const chunk of file.chunks) {
156
+ this.chunkStore.delete(chunk.id);
157
+ }
158
+
159
+ this.uploads.delete(fileId);
160
+ return true;
161
+ }
162
+
163
+ /**
164
+ * Get upload progress
165
+ */
166
+ getProgress(fileId: string): number {
167
+ const file = this.uploads.get(fileId);
168
+ return file?.progress || 0;
169
+ }
170
+
171
+ /**
172
+ * Calculate hash for chunk
173
+ */
174
+ private calculateHash(data: Buffer): string {
175
+ let hash = 0;
176
+ for (let i = 0; i < data.length; i++) {
177
+ hash = (hash << 5) - hash + data[i];
178
+ hash = hash & hash;
179
+ }
180
+ return Math.abs(hash).toString(36);
181
+ }
182
+
183
+ /**
184
+ * Estimate upload time
185
+ */
186
+ estimateUploadTime(fileSize: number, uploadSpeedMbps: number = 5): { chunks: number; timeSeconds: number } {
187
+ const chunks = Math.ceil(fileSize / this.defaultChunkSize);
188
+ const timeSec = (fileSize / (1024 * 1024)) / uploadSpeedMbps;
189
+ return { chunks, timeSeconds: Math.ceil(timeSec) };
190
+ }
191
+
192
+ /**
193
+ * Get all active uploads
194
+ */
195
+ getActiveUploads(): ChunkedFile[] {
196
+ return Array.from(this.uploads.values()).filter(f => f.status === 'uploading');
197
+ }
198
+
199
+ /**
200
+ * Clean up completed/failed uploads
201
+ */
202
+ cleanup(fileId?: string): void {
203
+ if (fileId) {
204
+ const file = this.uploads.get(fileId);
205
+ if (file && file.status !== 'uploading') {
206
+ for (const chunk of file.chunks) {
207
+ this.chunkStore.delete(chunk.id);
208
+ }
209
+ this.uploads.delete(fileId);
210
+ }
211
+ } else {
212
+ for (const [fid, file] of this.uploads) {
213
+ if (file.status !== 'uploading') {
214
+ for (const chunk of file.chunks) {
215
+ this.chunkStore.delete(chunk.id);
216
+ }
217
+ this.uploads.delete(fid);
218
+ }
219
+ }
220
+ }
221
+ }
222
+ }
223
+
224
+ export default ChunkedUploadEngine;