trellis 2.0.13 → 2.1.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 (96) hide show
  1. package/dist/cli/index.js +1 -1
  2. package/dist/embeddings/index.js +1 -1
  3. package/dist/{index-7gvjxt27.js → index-2917tjd8.js} +1 -1
  4. package/package.json +2 -10
  5. package/dist/transformers.node-bx3q9d7k.js +0 -33130
  6. package/src/cli/index.ts +0 -3356
  7. package/src/core/agents/harness.ts +0 -380
  8. package/src/core/agents/index.ts +0 -18
  9. package/src/core/agents/types.ts +0 -90
  10. package/src/core/index.ts +0 -118
  11. package/src/core/kernel/middleware.ts +0 -44
  12. package/src/core/kernel/trellis-kernel.ts +0 -593
  13. package/src/core/ontology/builtins.ts +0 -248
  14. package/src/core/ontology/index.ts +0 -34
  15. package/src/core/ontology/registry.ts +0 -209
  16. package/src/core/ontology/types.ts +0 -124
  17. package/src/core/ontology/validator.ts +0 -382
  18. package/src/core/persist/backend.ts +0 -74
  19. package/src/core/persist/sqlite-backend.ts +0 -298
  20. package/src/core/plugins/index.ts +0 -17
  21. package/src/core/plugins/registry.ts +0 -322
  22. package/src/core/plugins/types.ts +0 -126
  23. package/src/core/query/datalog.ts +0 -188
  24. package/src/core/query/engine.ts +0 -370
  25. package/src/core/query/index.ts +0 -34
  26. package/src/core/query/parser.ts +0 -481
  27. package/src/core/query/types.ts +0 -200
  28. package/src/core/store/eav-store.ts +0 -467
  29. package/src/decisions/auto-capture.ts +0 -136
  30. package/src/decisions/hooks.ts +0 -163
  31. package/src/decisions/index.ts +0 -261
  32. package/src/decisions/types.ts +0 -103
  33. package/src/embeddings/auto-embed.ts +0 -248
  34. package/src/embeddings/chunker.ts +0 -327
  35. package/src/embeddings/index.ts +0 -48
  36. package/src/embeddings/model.ts +0 -112
  37. package/src/embeddings/search.ts +0 -305
  38. package/src/embeddings/store.ts +0 -313
  39. package/src/embeddings/types.ts +0 -92
  40. package/src/engine.ts +0 -1125
  41. package/src/garden/cluster.ts +0 -330
  42. package/src/garden/garden.ts +0 -306
  43. package/src/garden/index.ts +0 -29
  44. package/src/git/git-exporter.ts +0 -286
  45. package/src/git/git-importer.ts +0 -329
  46. package/src/git/git-reader.ts +0 -189
  47. package/src/git/index.ts +0 -22
  48. package/src/identity/governance.ts +0 -211
  49. package/src/identity/identity.ts +0 -224
  50. package/src/identity/index.ts +0 -30
  51. package/src/identity/signing-middleware.ts +0 -97
  52. package/src/index.ts +0 -29
  53. package/src/links/index.ts +0 -49
  54. package/src/links/lifecycle.ts +0 -400
  55. package/src/links/parser.ts +0 -484
  56. package/src/links/ref-index.ts +0 -186
  57. package/src/links/resolver.ts +0 -314
  58. package/src/links/types.ts +0 -108
  59. package/src/mcp/index.ts +0 -22
  60. package/src/mcp/server.ts +0 -1278
  61. package/src/semantic/csharp-parser.ts +0 -493
  62. package/src/semantic/go-parser.ts +0 -585
  63. package/src/semantic/index.ts +0 -34
  64. package/src/semantic/java-parser.ts +0 -456
  65. package/src/semantic/python-parser.ts +0 -659
  66. package/src/semantic/ruby-parser.ts +0 -446
  67. package/src/semantic/rust-parser.ts +0 -784
  68. package/src/semantic/semantic-merge.ts +0 -210
  69. package/src/semantic/ts-parser.ts +0 -681
  70. package/src/semantic/types.ts +0 -175
  71. package/src/sync/http-transport.ts +0 -144
  72. package/src/sync/index.ts +0 -43
  73. package/src/sync/memory-transport.ts +0 -66
  74. package/src/sync/multi-repo.ts +0 -200
  75. package/src/sync/reconciler.ts +0 -237
  76. package/src/sync/sync-engine.ts +0 -258
  77. package/src/sync/types.ts +0 -104
  78. package/src/sync/ws-transport.ts +0 -145
  79. package/src/ui/client.html +0 -695
  80. package/src/ui/server.ts +0 -419
  81. package/src/vcs/blob-store.ts +0 -124
  82. package/src/vcs/branch.ts +0 -150
  83. package/src/vcs/checkpoint.ts +0 -64
  84. package/src/vcs/decompose.ts +0 -469
  85. package/src/vcs/diff.ts +0 -409
  86. package/src/vcs/engine-context.ts +0 -26
  87. package/src/vcs/index.ts +0 -23
  88. package/src/vcs/issue.ts +0 -800
  89. package/src/vcs/merge.ts +0 -425
  90. package/src/vcs/milestone.ts +0 -124
  91. package/src/vcs/ops.ts +0 -59
  92. package/src/vcs/types.ts +0 -213
  93. package/src/vcs/vcs-middleware.ts +0 -81
  94. package/src/watcher/fs-watcher.ts +0 -255
  95. package/src/watcher/index.ts +0 -9
  96. package/src/watcher/ingestion.ts +0 -116
package/src/vcs/merge.ts DELETED
@@ -1,425 +0,0 @@
1
- /**
2
- * Merge Engine
3
- *
4
- * Three-way file-level merge with text-based fallback (Tier 0 / P3).
5
- * Merges a source branch into the current branch by:
6
- * 1. Finding the common ancestor (fork point) in the op stream
7
- * 2. Building file states at ancestor, ours, and theirs
8
- * 3. Producing a merged file state or conflicts
9
- *
10
- * DESIGN.md §4.4 — Patch Commutativity and Conflict Detection
11
- */
12
-
13
- import type { VcsOp } from './types.js';
14
- import type { BlobStore } from './blob-store.js';
15
- import { buildFileStateAtOp, type FileState } from './diff.js';
16
-
17
- // ---------------------------------------------------------------------------
18
- // Types
19
- // ---------------------------------------------------------------------------
20
-
21
- export interface MergeConflict {
22
- path: string;
23
- kind: 'modify-modify' | 'modify-delete' | 'add-add';
24
- /** Content from the current (ours) branch. */
25
- ours?: string;
26
- /** Content from the source (theirs) branch. */
27
- theirs?: string;
28
- /** Content from the common ancestor. */
29
- base?: string;
30
- /** For text conflicts: attempted merge with conflict markers. */
31
- mergedWithMarkers?: string;
32
- }
33
-
34
- export interface MergeResult {
35
- /** True if merge completed without conflicts. */
36
- clean: boolean;
37
- /** Merged file states to apply (path → content string). */
38
- mergedFiles: Map<string, string | null>; // null = delete
39
- /** Conflicts requiring manual resolution. */
40
- conflicts: MergeConflict[];
41
- /** Summary stats. */
42
- stats: {
43
- added: number;
44
- modified: number;
45
- deleted: number;
46
- conflicted: number;
47
- };
48
- }
49
-
50
- // ---------------------------------------------------------------------------
51
- // Three-way merge
52
- // ---------------------------------------------------------------------------
53
-
54
- /**
55
- * Perform a three-way merge given ancestor, ours, and theirs file states.
56
- */
57
- export function threeWayMerge(
58
- base: Map<string, FileState>,
59
- ours: Map<string, FileState>,
60
- theirs: Map<string, FileState>,
61
- blobStore?: BlobStore | null,
62
- ): MergeResult {
63
- const mergedFiles = new Map<string, string | null>();
64
- const conflicts: MergeConflict[] = [];
65
-
66
- // Collect all file paths across all three states
67
- const allPaths = new Set<string>();
68
- for (const [p, s] of base) if (!s.deleted) allPaths.add(p);
69
- for (const [p, s] of ours) if (!s.deleted) allPaths.add(p);
70
- for (const [p, s] of theirs) if (!s.deleted) allPaths.add(p);
71
-
72
- // Also track deleted paths
73
- for (const [p, s] of ours) if (s.deleted) allPaths.add(p);
74
- for (const [p, s] of theirs) if (s.deleted) allPaths.add(p);
75
-
76
- for (const path of allPaths) {
77
- const b = base.get(path);
78
- const o = ours.get(path);
79
- const t = theirs.get(path);
80
-
81
- const baseExists = b && !b.deleted;
82
- const oursExists = o && !o.deleted;
83
- const theirsExists = t && !t.deleted;
84
-
85
- const baseHash = baseExists ? b.contentHash : undefined;
86
- const oursHash = oursExists ? o.contentHash : undefined;
87
- const theirsHash = theirsExists ? t.contentHash : undefined;
88
-
89
- // Neither side changed
90
- if (oursHash === theirsHash) {
91
- // Both same — no-op (keep ours)
92
- continue;
93
- }
94
-
95
- // Only ours changed (theirs same as base)
96
- if (theirsHash === baseHash && oursHash !== baseHash) {
97
- if (!oursExists) {
98
- mergedFiles.set(path, null); // we deleted
99
- }
100
- // else keep ours (already in our state)
101
- continue;
102
- }
103
-
104
- // Only theirs changed (ours same as base)
105
- if (oursHash === baseHash && theirsHash !== baseHash) {
106
- if (!theirsExists) {
107
- mergedFiles.set(path, null); // they deleted
108
- } else if (theirsHash && blobStore) {
109
- const content = blobStore.get(theirsHash);
110
- if (content) {
111
- mergedFiles.set(path, content.toString('utf-8'));
112
- }
113
- }
114
- continue;
115
- }
116
-
117
- // Both sides changed — potential conflict
118
-
119
- // Case: both added (not in base)
120
- if (!baseExists && oursExists && theirsExists) {
121
- if (oursHash === theirsHash) {
122
- continue; // identical add — no conflict
123
- }
124
- const oursContent = oursHash && blobStore ? blobStore.get(oursHash)?.toString('utf-8') : undefined;
125
- const theirsContent = theirsHash && blobStore ? blobStore.get(theirsHash)?.toString('utf-8') : undefined;
126
-
127
- // Try text merge with empty base
128
- if (oursContent !== undefined && theirsContent !== undefined) {
129
- const textResult = threeWayTextMerge('', oursContent, theirsContent);
130
- if (textResult.clean) {
131
- mergedFiles.set(path, textResult.merged);
132
- continue;
133
- }
134
- conflicts.push({
135
- path,
136
- kind: 'add-add',
137
- ours: oursContent,
138
- theirs: theirsContent,
139
- mergedWithMarkers: textResult.merged,
140
- });
141
- } else {
142
- conflicts.push({ path, kind: 'add-add', ours: oursContent, theirs: theirsContent });
143
- }
144
- continue;
145
- }
146
-
147
- // Case: one side deleted, other modified
148
- if (oursExists && !theirsExists) {
149
- conflicts.push({
150
- path,
151
- kind: 'modify-delete',
152
- ours: oursHash && blobStore ? blobStore.get(oursHash)?.toString('utf-8') : undefined,
153
- });
154
- continue;
155
- }
156
- if (!oursExists && theirsExists) {
157
- conflicts.push({
158
- path,
159
- kind: 'modify-delete',
160
- theirs: theirsHash && blobStore ? blobStore.get(theirsHash)?.toString('utf-8') : undefined,
161
- });
162
- continue;
163
- }
164
-
165
- // Case: both modified (both exist, different hashes)
166
- if (oursExists && theirsExists && oursHash !== theirsHash) {
167
- const baseContent = baseHash && blobStore ? blobStore.get(baseHash)?.toString('utf-8') : undefined;
168
- const oursContent = oursHash && blobStore ? blobStore.get(oursHash)?.toString('utf-8') : undefined;
169
- const theirsContent = theirsHash && blobStore ? blobStore.get(theirsHash)?.toString('utf-8') : undefined;
170
-
171
- if (baseContent !== undefined && oursContent !== undefined && theirsContent !== undefined) {
172
- const textResult = threeWayTextMerge(baseContent, oursContent, theirsContent);
173
- if (textResult.clean) {
174
- mergedFiles.set(path, textResult.merged);
175
- } else {
176
- conflicts.push({
177
- path,
178
- kind: 'modify-modify',
179
- base: baseContent,
180
- ours: oursContent,
181
- theirs: theirsContent,
182
- mergedWithMarkers: textResult.merged,
183
- });
184
- }
185
- } else {
186
- conflicts.push({
187
- path,
188
- kind: 'modify-modify',
189
- base: baseContent,
190
- ours: oursContent,
191
- theirs: theirsContent,
192
- });
193
- }
194
- continue;
195
- }
196
- }
197
-
198
- const added = [...mergedFiles.values()].filter((v) => v !== null).length;
199
- const deleted = [...mergedFiles.values()].filter((v) => v === null).length;
200
-
201
- return {
202
- clean: conflicts.length === 0,
203
- mergedFiles,
204
- conflicts,
205
- stats: {
206
- added,
207
- modified: added, // in a merge context, additions from theirs are "modified"
208
- deleted,
209
- conflicted: conflicts.length,
210
- },
211
- };
212
- }
213
-
214
- // ---------------------------------------------------------------------------
215
- // Three-way text merge
216
- // ---------------------------------------------------------------------------
217
-
218
- export interface TextMergeResult {
219
- clean: boolean;
220
- merged: string;
221
- }
222
-
223
- /**
224
- * Three-way line-level text merge.
225
- * Uses a simple approach: diff base→ours and base→theirs, then interleave.
226
- * Produces conflict markers when both sides change the same region.
227
- */
228
- export function threeWayTextMerge(
229
- baseText: string,
230
- oursText: string,
231
- theirsText: string,
232
- ): TextMergeResult {
233
- const baseLines = baseText.split('\n');
234
- const oursLines = oursText.split('\n');
235
- const theirsLines = theirsText.split('\n');
236
-
237
- // Build change maps: line index in base → what each side did
238
- const oursChanges = computeLineChanges(baseLines, oursLines);
239
- const theirsChanges = computeLineChanges(baseLines, theirsLines);
240
-
241
- const result: string[] = [];
242
- let clean = true;
243
-
244
- let baseIdx = 0;
245
- let oursIdx = 0;
246
- let theirsIdx = 0;
247
-
248
- while (baseIdx < baseLines.length || oursIdx < oursLines.length || theirsIdx < theirsLines.length) {
249
- const oursChange = oursChanges.get(baseIdx);
250
- const theirsChange = theirsChanges.get(baseIdx);
251
-
252
- if (baseIdx >= baseLines.length) {
253
- // Past base — append remaining from both sides
254
- // Ours remaining
255
- while (oursIdx < oursLines.length) {
256
- result.push(oursLines[oursIdx++]);
257
- }
258
- // Theirs remaining
259
- while (theirsIdx < theirsLines.length) {
260
- result.push(theirsLines[theirsIdx++]);
261
- }
262
- break;
263
- }
264
-
265
- if (!oursChange && !theirsChange) {
266
- // Both kept the line unchanged
267
- result.push(baseLines[baseIdx]);
268
- baseIdx++;
269
- oursIdx++;
270
- theirsIdx++;
271
- } else if (oursChange && !theirsChange) {
272
- // Only ours changed
273
- applyChange(oursChange, result);
274
- baseIdx += oursChange.baseCount;
275
- oursIdx += oursChange.newCount;
276
- theirsIdx += oursChange.baseCount;
277
- } else if (!oursChange && theirsChange) {
278
- // Only theirs changed
279
- applyChange(theirsChange, result);
280
- baseIdx += theirsChange.baseCount;
281
- oursIdx += theirsChange.baseCount;
282
- theirsIdx += theirsChange.newCount;
283
- } else if (oursChange && theirsChange) {
284
- // Both changed — check if identical
285
- if (
286
- oursChange.baseCount === theirsChange.baseCount &&
287
- oursChange.newLines.join('\n') === theirsChange.newLines.join('\n')
288
- ) {
289
- // Identical change — apply once
290
- applyChange(oursChange, result);
291
- baseIdx += oursChange.baseCount;
292
- oursIdx += oursChange.newCount;
293
- theirsIdx += theirsChange.newCount;
294
- } else {
295
- // Conflict
296
- clean = false;
297
- result.push('<<<<<<< ours');
298
- for (const line of oursChange.newLines) result.push(line);
299
- result.push('=======');
300
- for (const line of theirsChange.newLines) result.push(line);
301
- result.push('>>>>>>> theirs');
302
- baseIdx += Math.max(oursChange.baseCount, theirsChange.baseCount);
303
- oursIdx += oursChange.newCount;
304
- theirsIdx += theirsChange.newCount;
305
- }
306
- }
307
- }
308
-
309
- return { clean, merged: result.join('\n') };
310
- }
311
-
312
- // ---------------------------------------------------------------------------
313
- // Line change detection
314
- // ---------------------------------------------------------------------------
315
-
316
- interface LineChange {
317
- baseStart: number;
318
- baseCount: number;
319
- newCount: number;
320
- newLines: string[];
321
- }
322
-
323
- function applyChange(change: LineChange, result: string[]): void {
324
- for (const line of change.newLines) {
325
- result.push(line);
326
- }
327
- }
328
-
329
- /**
330
- * Compute a map of base line index → change region.
331
- * Uses LCS (longest common subsequence) to detect changed regions.
332
- */
333
- function computeLineChanges(
334
- baseLines: string[],
335
- newLines: string[],
336
- ): Map<number, LineChange> {
337
- const changes = new Map<number, LineChange>();
338
- const matches = lcsMatch(baseLines, newLines);
339
-
340
- let baseIdx = 0;
341
- let newIdx = 0;
342
-
343
- for (const match of matches) {
344
- // Process gap before this match
345
- if (baseIdx < match.baseIdx || newIdx < match.newIdx) {
346
- const baseCount = match.baseIdx - baseIdx;
347
- const newCount = match.newIdx - newIdx;
348
- if (baseCount > 0 || newCount > 0) {
349
- changes.set(baseIdx, {
350
- baseStart: baseIdx,
351
- baseCount,
352
- newCount,
353
- newLines: newLines.slice(newIdx, newIdx + newCount),
354
- });
355
- }
356
- }
357
- baseIdx = match.baseIdx + 1;
358
- newIdx = match.newIdx + 1;
359
- }
360
-
361
- // Handle trailing gap
362
- if (baseIdx < baseLines.length || newIdx < newLines.length) {
363
- const baseCount = baseLines.length - baseIdx;
364
- const newCount = newLines.length - newIdx;
365
- if (baseCount > 0 || newCount > 0) {
366
- changes.set(baseIdx, {
367
- baseStart: baseIdx,
368
- baseCount,
369
- newCount,
370
- newLines: newLines.slice(newIdx),
371
- });
372
- }
373
- }
374
-
375
- return changes;
376
- }
377
-
378
- interface LCSMatch {
379
- baseIdx: number;
380
- newIdx: number;
381
- }
382
-
383
- /**
384
- * Find the LCS (longest common subsequence) matches between two line arrays.
385
- * Returns an ordered list of matched line index pairs.
386
- */
387
- function lcsMatch(a: string[], b: string[]): LCSMatch[] {
388
- const n = a.length;
389
- const m = b.length;
390
-
391
- if (n === 0 || m === 0) return [];
392
-
393
- // DP table
394
- const dp: number[][] = Array.from({ length: n + 1 }, () =>
395
- new Array(m + 1).fill(0),
396
- );
397
-
398
- for (let i = 1; i <= n; i++) {
399
- for (let j = 1; j <= m; j++) {
400
- if (a[i - 1] === b[j - 1]) {
401
- dp[i][j] = dp[i - 1][j - 1] + 1;
402
- } else {
403
- dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
404
- }
405
- }
406
- }
407
-
408
- // Backtrack
409
- const matches: LCSMatch[] = [];
410
- let i = n;
411
- let j = m;
412
- while (i > 0 && j > 0) {
413
- if (a[i - 1] === b[j - 1]) {
414
- matches.unshift({ baseIdx: i - 1, newIdx: j - 1 });
415
- i--;
416
- j--;
417
- } else if (dp[i - 1][j] > dp[i][j - 1]) {
418
- i--;
419
- } else {
420
- j--;
421
- }
422
- }
423
-
424
- return matches;
425
- }
@@ -1,124 +0,0 @@
1
- /**
2
- * Milestone Module
3
- *
4
- * Extracted from engine.ts per DESIGN.md §8.1.
5
- * Handles milestone creation, listing, and op-range computation.
6
- */
7
-
8
- import { createVcsOp } from './ops.js';
9
- import type { VcsOp } from './types.js';
10
- import type { EngineContext } from './engine-context.js';
11
-
12
- // ---------------------------------------------------------------------------
13
- // Types
14
- // ---------------------------------------------------------------------------
15
-
16
- export interface MilestoneInfo {
17
- id: string;
18
- message?: string;
19
- createdAt?: string;
20
- createdBy?: string;
21
- fromOpHash?: string;
22
- toOpHash?: string;
23
- affectedFiles: string[];
24
- }
25
-
26
- // ---------------------------------------------------------------------------
27
- // Operations
28
- // ---------------------------------------------------------------------------
29
-
30
- /**
31
- * Create a milestone spanning a range of ops.
32
- * If no fromOpHash is specified, spans from the last milestone (or start).
33
- */
34
- export async function createMilestone(
35
- ctx: EngineContext,
36
- message: string,
37
- opts?: {
38
- fromOpHash?: string;
39
- toOpHash?: string;
40
- },
41
- ): Promise<VcsOp> {
42
- const ops = ctx.readAllOps();
43
- const toOpHash = opts?.toOpHash ?? ops[ops.length - 1]?.hash;
44
-
45
- // Find the start: either specified, or the op after the last milestone
46
- let fromOpHash = opts?.fromOpHash;
47
- if (!fromOpHash) {
48
- const milestones = ops.filter((o) => o.kind === 'vcs:milestoneCreate');
49
- if (milestones.length > 0) {
50
- const lastMilestone = milestones[milestones.length - 1];
51
- fromOpHash = lastMilestone.vcs?.toOpHash ?? lastMilestone.hash;
52
- } else {
53
- fromOpHash = ops[0]?.hash;
54
- }
55
- }
56
-
57
- // Generate milestone ID
58
- const idBase = `${message}:${Date.now()}`;
59
- const msgUint8 = new TextEncoder().encode(idBase);
60
- const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8);
61
- const hashArray = Array.from(new Uint8Array(hashBuffer));
62
- const hashHex = hashArray
63
- .map((b) => b.toString(16).padStart(2, '0'))
64
- .join('');
65
- const milestoneId = `milestone:${hashHex.slice(0, 12)}`;
66
-
67
- // Determine affected files in the range
68
- const fromIdx = ops.findIndex((o) => o.hash === fromOpHash);
69
- const toIdx = ops.findIndex((o) => o.hash === toOpHash);
70
- const rangeOps =
71
- fromIdx >= 0 && toIdx >= 0 ? ops.slice(fromIdx, toIdx + 1) : ops;
72
- const affectedFiles = [
73
- ...new Set(
74
- rangeOps.filter((o) => o.vcs?.filePath).map((o) => o.vcs!.filePath!),
75
- ),
76
- ];
77
-
78
- const op = await createVcsOp('vcs:milestoneCreate', {
79
- agentId: ctx.agentId,
80
- previousHash: ctx.getLastOp()?.hash,
81
- vcs: {
82
- milestoneId,
83
- message,
84
- fromOpHash,
85
- toOpHash,
86
- },
87
- });
88
- ctx.applyOp(op);
89
-
90
- // Store affected files as multi-valued facts
91
- for (const file of affectedFiles) {
92
- ctx.store.addFacts([{ e: milestoneId, a: 'affectsFile', v: file }]);
93
- }
94
-
95
- return op;
96
- }
97
-
98
- /**
99
- * List all milestones from the EAV store.
100
- */
101
- export function listMilestones(ctx: EngineContext): MilestoneInfo[] {
102
- const milestoneFacts = ctx.store
103
- .getFactsByAttribute('type')
104
- .filter((f) => f.v === 'Milestone');
105
-
106
- return milestoneFacts.map((f) => {
107
- const facts = ctx.store.getFactsByEntity(f.e);
108
- const get = (attr: string) =>
109
- facts.find((ef) => ef.a === attr)?.v as string | undefined;
110
- const affectedFiles = facts
111
- .filter((ef) => ef.a === 'affectsFile')
112
- .map((ef) => ef.v as string);
113
-
114
- return {
115
- id: f.e,
116
- message: get('message'),
117
- createdAt: get('createdAt'),
118
- createdBy: get('createdBy'),
119
- fromOpHash: get('fromOpHash'),
120
- toOpHash: get('toOpHash'),
121
- affectedFiles,
122
- };
123
- });
124
- }
package/src/vcs/ops.ts DELETED
@@ -1,59 +0,0 @@
1
- /**
2
- * VCS Operation Constructors
3
- *
4
- * Helpers to create content-addressed VcsOps with proper
5
- * causality chaining and metadata.
6
- */
7
-
8
- import type { VcsOp, VcsOpKind, VcsPayload } from './types.js';
9
-
10
- /**
11
- * Creates a VcsOp with full metadata, hash, and causal chain link.
12
- */
13
- export async function createVcsOp(
14
- kind: VcsOpKind,
15
- params: {
16
- agentId: string;
17
- previousHash?: string;
18
- vcs: VcsPayload;
19
- },
20
- ): Promise<VcsOp> {
21
- const opBase = {
22
- kind,
23
- timestamp: new Date().toISOString(),
24
- agentId: params.agentId,
25
- previousHash: params.previousHash,
26
- vcs: params.vcs,
27
- };
28
-
29
- // Hash covers the full op including VCS payload for content-addressability.
30
- const content = JSON.stringify(opBase);
31
- const msgUint8 = new TextEncoder().encode(content);
32
- const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8);
33
- const hashArray = Array.from(new Uint8Array(hashBuffer));
34
- const hashHex = hashArray
35
- .map((b) => b.toString(16).padStart(2, '0'))
36
- .join('');
37
-
38
- return {
39
- ...opBase,
40
- hash: `trellis:op:${hashHex}`,
41
- };
42
- }
43
-
44
- /**
45
- * Checks whether a KernelOp is a VcsOp (has a vcs payload).
46
- */
47
- export function isVcsOp(op: { kind: string; vcs?: unknown }): op is VcsOp {
48
- return (
49
- op.vcs !== undefined ||
50
- (typeof op.kind === 'string' && op.kind.startsWith('vcs:'))
51
- );
52
- }
53
-
54
- /**
55
- * Checks whether an op kind is a VCS kind.
56
- */
57
- export function isVcsOpKind(kind: string): kind is VcsOpKind {
58
- return kind.startsWith('vcs:');
59
- }