trellis 3.1.30 → 3.1.33
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/CHANGELOG.md +10 -0
- package/README.md +1 -1
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +320 -24
- package/dist/cli/lane.d.ts +6 -0
- package/dist/cli/lane.d.ts.map +1 -0
- package/dist/cms/client.d.ts +1 -1
- package/dist/cms/client.d.ts.map +1 -1
- package/dist/cms/index.js +0 -16
- package/dist/cms/types.d.ts +1 -1
- package/dist/cms/types.d.ts.map +1 -1
- package/dist/context/manager.d.ts +1 -1
- package/dist/context/manager.d.ts.map +1 -1
- package/dist/context/types.d.ts +1 -1
- package/dist/context/types.d.ts.map +1 -1
- package/dist/decisions/index.js +2 -2
- package/dist/engine.d.ts +86 -2
- package/dist/engine.d.ts.map +1 -1
- package/dist/{index-65z0xfjw.js → index-4cdr7x2x.js} +2 -2
- package/dist/{index-hy73j9z8.js → index-nq520y6k.js} +7 -3
- package/dist/{index-v9b4hqa7.js → index-nzb3am4f.js} +4 -1
- package/dist/{index-ncckgtrk.js → index-rv1p47gp.js} +1000 -114
- package/dist/{index-4gknc19b.js → index-w5wccer3.js} +1 -1
- package/dist/{index-a2a394zz.js → index-xhcp6xrn.js} +503 -41
- package/dist/index.js +39 -7
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/plugins/agent-memory/graph-context-manager.d.ts +5 -0
- package/dist/plugins/agent-memory/graph-context-manager.d.ts.map +1 -1
- package/dist/{remote-manager-n71bmcy1.js → remote-manager-xvbg4230.js} +4 -4
- package/dist/vcs/branch.d.ts +6 -0
- package/dist/vcs/branch.d.ts.map +1 -1
- package/dist/vcs/decompose.d.ts.map +1 -1
- package/dist/vcs/engine-context.d.ts +9 -2
- package/dist/vcs/engine-context.d.ts.map +1 -1
- package/dist/vcs/index.d.ts +2 -0
- package/dist/vcs/index.d.ts.map +1 -1
- package/dist/vcs/index.js +36 -4
- package/dist/vcs/issue.d.ts +2 -0
- package/dist/vcs/issue.d.ts.map +1 -1
- package/dist/vcs/lane-materialize.d.ts +45 -0
- package/dist/vcs/lane-materialize.d.ts.map +1 -0
- package/dist/vcs/lane-promote.d.ts +56 -0
- package/dist/vcs/lane-promote.d.ts.map +1 -0
- package/dist/vcs/lane.d.ts +55 -0
- package/dist/vcs/lane.d.ts.map +1 -0
- package/dist/vcs/op-log.d.ts +29 -0
- package/dist/vcs/op-log.d.ts.map +1 -0
- package/dist/vcs/types.d.ts +15 -1
- package/dist/vcs/types.d.ts.map +1 -1
- package/dist/watcher/ingestion.d.ts +1 -0
- package/dist/watcher/ingestion.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
BlobStore,
|
|
4
|
+
JsonOpLog,
|
|
5
|
+
LaneOpLog,
|
|
4
6
|
addCriterion,
|
|
5
7
|
assignIssue,
|
|
6
8
|
blockIssue,
|
|
@@ -10,12 +12,14 @@ import {
|
|
|
10
12
|
createBranch,
|
|
11
13
|
createCheckpoint,
|
|
12
14
|
createIssue,
|
|
15
|
+
createLaneMeta,
|
|
13
16
|
createMilestone,
|
|
14
17
|
decompose,
|
|
15
18
|
deleteBranch,
|
|
16
19
|
diffFileStates,
|
|
17
20
|
diffOpRange,
|
|
18
21
|
getActiveIssues,
|
|
22
|
+
getBranchHeadOpHash,
|
|
19
23
|
getIssue,
|
|
20
24
|
init_blob_store,
|
|
21
25
|
init_branch,
|
|
@@ -23,39 +27,50 @@ import {
|
|
|
23
27
|
init_decompose,
|
|
24
28
|
init_diff,
|
|
25
29
|
init_issue,
|
|
30
|
+
init_lane,
|
|
26
31
|
init_merge,
|
|
27
32
|
init_milestone,
|
|
33
|
+
init_op_log,
|
|
34
|
+
laneDir,
|
|
28
35
|
listBranches,
|
|
29
36
|
listCheckpoints,
|
|
30
37
|
listIssues,
|
|
38
|
+
listLaneMetas,
|
|
31
39
|
listMilestones,
|
|
32
40
|
loadBranchState,
|
|
41
|
+
loadLaneMeta,
|
|
33
42
|
pauseIssue,
|
|
34
43
|
reopenIssue,
|
|
44
|
+
resolveLaneHeadFromJournal,
|
|
35
45
|
resumeIssue,
|
|
36
46
|
runCriteria,
|
|
37
47
|
saveBranchState,
|
|
48
|
+
saveLaneMeta,
|
|
38
49
|
setCriterionStatus,
|
|
50
|
+
shouldAdvanceBranchHead,
|
|
39
51
|
startIssue,
|
|
40
52
|
switchBranch,
|
|
41
53
|
threeWayMerge,
|
|
54
|
+
threeWayTextMerge,
|
|
42
55
|
triageIssue,
|
|
43
56
|
unblockIssue,
|
|
44
|
-
updateIssue
|
|
45
|
-
|
|
57
|
+
updateIssue,
|
|
58
|
+
updateLaneHead
|
|
59
|
+
} from "./index-xhcp6xrn.js";
|
|
46
60
|
import {
|
|
47
61
|
getDecision,
|
|
48
62
|
getDecisionChain,
|
|
49
63
|
init_decisions,
|
|
50
64
|
queryDecisions,
|
|
51
65
|
recordDecision
|
|
52
|
-
} from "./index-
|
|
66
|
+
} from "./index-4cdr7x2x.js";
|
|
53
67
|
import {
|
|
54
68
|
DEFAULT_CONFIG,
|
|
55
69
|
createVcsOp,
|
|
56
70
|
init_ops,
|
|
57
|
-
init_types
|
|
58
|
-
|
|
71
|
+
init_types,
|
|
72
|
+
isVcsOpKind
|
|
73
|
+
} from "./index-nzb3am4f.js";
|
|
59
74
|
import {
|
|
60
75
|
EAVStore,
|
|
61
76
|
init_eav_store
|
|
@@ -308,6 +323,9 @@ class Ingestion {
|
|
|
308
323
|
getLastOpHash() {
|
|
309
324
|
return this.lastOpHash;
|
|
310
325
|
}
|
|
326
|
+
setLastOpHash(hash) {
|
|
327
|
+
this.lastOpHash = hash;
|
|
328
|
+
}
|
|
311
329
|
}
|
|
312
330
|
var EXT_LANGUAGE;
|
|
313
331
|
var init_ingestion = __esm(() => {
|
|
@@ -5333,109 +5351,443 @@ var init_semantic = __esm(() => {
|
|
|
5333
5351
|
init_semantic_merge();
|
|
5334
5352
|
});
|
|
5335
5353
|
|
|
5336
|
-
// src/
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5354
|
+
// src/vcs/lane-promote.ts
|
|
5355
|
+
function replayOpIntoStore(store, op) {
|
|
5356
|
+
const d = decompose(op);
|
|
5357
|
+
if (d.deleteFacts.length > 0)
|
|
5358
|
+
store.deleteFacts(d.deleteFacts);
|
|
5359
|
+
if (d.deleteLinks.length > 0)
|
|
5360
|
+
store.deleteLinks(d.deleteLinks);
|
|
5361
|
+
if (d.addFacts.length > 0)
|
|
5362
|
+
store.addFacts(d.addFacts);
|
|
5363
|
+
if (d.addLinks.length > 0)
|
|
5364
|
+
store.addLinks(d.addLinks);
|
|
5365
|
+
}
|
|
5366
|
+
function resolveBranchHeadFromOps(ops, branchName) {
|
|
5367
|
+
for (let i = ops.length - 1;i >= 0; i--) {
|
|
5368
|
+
const op = ops[i];
|
|
5369
|
+
if (op.kind === "vcs:branchAdvance" && op.vcs?.branchName === branchName && op.vcs.targetOpHash) {
|
|
5370
|
+
return op.vcs.targetOpHash;
|
|
5371
|
+
}
|
|
5372
|
+
}
|
|
5373
|
+
return ops[ops.length - 1]?.hash;
|
|
5374
|
+
}
|
|
5375
|
+
function buildStoreUpTo(ops, atOpHash) {
|
|
5376
|
+
const store = new EAVStore;
|
|
5377
|
+
for (const op of ops) {
|
|
5378
|
+
replayOpIntoStore(store, op);
|
|
5379
|
+
if (atOpHash && op.hash === atOpHash)
|
|
5380
|
+
break;
|
|
5352
5381
|
}
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5382
|
+
return store;
|
|
5383
|
+
}
|
|
5384
|
+
function getFactValue(store, entity, attribute) {
|
|
5385
|
+
const facts = store.getFactsByEntity(entity).filter((f) => f.a === attribute);
|
|
5386
|
+
return facts[facts.length - 1]?.v;
|
|
5387
|
+
}
|
|
5388
|
+
function entityAttributes(store, entity) {
|
|
5389
|
+
const map = new Map;
|
|
5390
|
+
for (const fact of store.getFactsByEntity(entity)) {
|
|
5391
|
+
map.set(fact.a, fact.v);
|
|
5392
|
+
}
|
|
5393
|
+
return map;
|
|
5394
|
+
}
|
|
5395
|
+
function collectTouchedAttributes(op) {
|
|
5396
|
+
const d = decompose(op);
|
|
5397
|
+
const map = new Map;
|
|
5398
|
+
const touch = (fact) => {
|
|
5399
|
+
if (!map.has(fact.e))
|
|
5400
|
+
map.set(fact.e, new Set);
|
|
5401
|
+
map.get(fact.e).add(fact.a);
|
|
5402
|
+
};
|
|
5403
|
+
for (const f of d.addFacts)
|
|
5404
|
+
touch(f);
|
|
5405
|
+
for (const f of d.deleteFacts)
|
|
5406
|
+
touch(f);
|
|
5407
|
+
return map;
|
|
5408
|
+
}
|
|
5409
|
+
function collectTouchedEntities(op) {
|
|
5410
|
+
const d = decompose(op);
|
|
5411
|
+
const entities = new Set;
|
|
5412
|
+
for (const f of [...d.addFacts, ...d.deleteFacts])
|
|
5413
|
+
entities.add(f.e);
|
|
5414
|
+
for (const l of [...d.addLinks, ...d.deleteLinks]) {
|
|
5415
|
+
entities.add(l.e1);
|
|
5416
|
+
entities.add(l.e2);
|
|
5417
|
+
}
|
|
5418
|
+
return entities;
|
|
5419
|
+
}
|
|
5420
|
+
function atomsEqual(a, b) {
|
|
5421
|
+
if (a === b)
|
|
5422
|
+
return true;
|
|
5423
|
+
if (a === undefined || b === undefined)
|
|
5424
|
+
return false;
|
|
5425
|
+
return String(a) === String(b);
|
|
5426
|
+
}
|
|
5427
|
+
function buildLaneFileState(laneOps, throughIndex) {
|
|
5428
|
+
const slice = laneOps.slice(0, throughIndex + 1);
|
|
5429
|
+
return buildFileStateAtOp(slice);
|
|
5430
|
+
}
|
|
5431
|
+
function filePathsFromOp(op) {
|
|
5432
|
+
const paths = [];
|
|
5433
|
+
if (op.vcs?.filePath)
|
|
5434
|
+
paths.push(op.vcs.filePath);
|
|
5435
|
+
if (op.vcs?.oldFilePath)
|
|
5436
|
+
paths.push(op.vcs.oldFilePath);
|
|
5437
|
+
return paths;
|
|
5438
|
+
}
|
|
5439
|
+
function detectEntityConflicts(op, baseStore, headStore) {
|
|
5440
|
+
const conflicts = [];
|
|
5441
|
+
const d = decompose(op);
|
|
5442
|
+
const touchedEntities = collectTouchedEntities(op);
|
|
5443
|
+
const laneAttrsByEntity = collectTouchedAttributes(op);
|
|
5444
|
+
for (const fact of d.addFacts) {
|
|
5445
|
+
const headValue = getFactValue(headStore, fact.e, fact.a);
|
|
5446
|
+
const baseValue = getFactValue(baseStore, fact.e, fact.a);
|
|
5447
|
+
if (atomsEqual(headValue, fact.v))
|
|
5448
|
+
continue;
|
|
5449
|
+
if (!atomsEqual(headValue, baseValue) && headValue !== undefined) {
|
|
5450
|
+
conflicts.push({
|
|
5451
|
+
class: "hard",
|
|
5452
|
+
laneOpHash: op.hash,
|
|
5453
|
+
entityId: fact.e,
|
|
5454
|
+
attribute: fact.a,
|
|
5455
|
+
integrationValue: headValue,
|
|
5456
|
+
laneValue: fact.v,
|
|
5457
|
+
suggestion: "manual",
|
|
5458
|
+
message: `Integration changed ${fact.e}.${fact.a} since fork`
|
|
5459
|
+
});
|
|
5460
|
+
}
|
|
5461
|
+
}
|
|
5462
|
+
for (const entityId of touchedEntities) {
|
|
5463
|
+
const laneAttrs = laneAttrsByEntity.get(entityId) ?? new Set;
|
|
5464
|
+
if (laneAttrs.size === 0)
|
|
5465
|
+
continue;
|
|
5466
|
+
const baseAttrs = entityAttributes(baseStore, entityId);
|
|
5467
|
+
const headAttrs = entityAttributes(headStore, entityId);
|
|
5468
|
+
for (const [attribute, headValue] of headAttrs) {
|
|
5469
|
+
if (laneAttrs.has(attribute))
|
|
5470
|
+
continue;
|
|
5471
|
+
const baseValue = baseAttrs.get(attribute);
|
|
5472
|
+
if (!atomsEqual(headValue, baseValue)) {
|
|
5473
|
+
conflicts.push({
|
|
5474
|
+
class: "soft",
|
|
5475
|
+
laneOpHash: op.hash,
|
|
5476
|
+
entityId,
|
|
5477
|
+
attribute,
|
|
5478
|
+
integrationValue: headValue,
|
|
5479
|
+
suggestion: "manual",
|
|
5480
|
+
message: `Integration updated ${entityId}.${attribute} while lane touched the same entity`
|
|
5481
|
+
});
|
|
5367
5482
|
}
|
|
5368
5483
|
}
|
|
5369
5484
|
}
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5485
|
+
return conflicts;
|
|
5486
|
+
}
|
|
5487
|
+
function blobText(blobStore, hash) {
|
|
5488
|
+
if (!hash || !blobStore)
|
|
5489
|
+
return;
|
|
5490
|
+
const content = blobStore.get(hash);
|
|
5491
|
+
if (!content)
|
|
5492
|
+
return;
|
|
5493
|
+
const text = content.toString("utf-8");
|
|
5494
|
+
return text.endsWith(`
|
|
5495
|
+
`) ? text.slice(0, -1) : text;
|
|
5496
|
+
}
|
|
5497
|
+
function mergeLaneFile(path, base, ours, theirs, blobStore) {
|
|
5498
|
+
const b = base.get(path);
|
|
5499
|
+
const o = ours.get(path);
|
|
5500
|
+
const t = theirs.get(path);
|
|
5501
|
+
const baseHash = b && !b.deleted ? b.contentHash : undefined;
|
|
5502
|
+
const oursHash = o && !o.deleted ? o.contentHash : undefined;
|
|
5503
|
+
const theirsHash = t && !t.deleted ? t.contentHash : undefined;
|
|
5504
|
+
if (oursHash === theirsHash)
|
|
5505
|
+
return { clean: true };
|
|
5506
|
+
if (theirsHash === baseHash && oursHash !== baseHash)
|
|
5507
|
+
return { clean: true };
|
|
5508
|
+
if (oursHash === baseHash && theirsHash !== baseHash) {
|
|
5509
|
+
const theirsContent2 = blobText(blobStore, theirsHash);
|
|
5510
|
+
return { clean: true, merged: theirsContent2 };
|
|
5511
|
+
}
|
|
5512
|
+
const baseContent = blobText(blobStore, baseHash) ?? "";
|
|
5513
|
+
const oursContent = blobText(blobStore, oursHash);
|
|
5514
|
+
const theirsContent = blobText(blobStore, theirsHash);
|
|
5515
|
+
if (oursContent === undefined || theirsContent === undefined) {
|
|
5516
|
+
return { clean: false, conflictKind: "modify-modify" };
|
|
5517
|
+
}
|
|
5518
|
+
const textResult = threeWayTextMerge(baseContent, oursContent, theirsContent);
|
|
5519
|
+
if (textResult.clean) {
|
|
5520
|
+
return { clean: true, merged: textResult.merged };
|
|
5521
|
+
}
|
|
5522
|
+
return { clean: false, conflictKind: "modify-modify" };
|
|
5523
|
+
}
|
|
5524
|
+
function detectFileConflict(op, integrationOps, laneOps, laneOpIndex, baseOpHash, snapshotHead, blobStore) {
|
|
5525
|
+
const paths = filePathsFromOp(op);
|
|
5526
|
+
if (paths.length === 0)
|
|
5527
|
+
return {};
|
|
5528
|
+
const base = buildFileStateAtOp(integrationOps, baseOpHash);
|
|
5529
|
+
const ours = buildFileStateAtOp(integrationOps, snapshotHead);
|
|
5530
|
+
const theirs = buildLaneFileState(laneOps, laneOpIndex);
|
|
5531
|
+
for (const path of paths) {
|
|
5532
|
+
const baseState = base.get(path);
|
|
5533
|
+
const headState = ours.get(path);
|
|
5534
|
+
const laneState = theirs.get(path);
|
|
5535
|
+
const baseHash = baseState && !baseState.deleted ? baseState.contentHash : undefined;
|
|
5536
|
+
const headHash = headState && !headState.deleted ? headState.contentHash : undefined;
|
|
5537
|
+
const laneHash = laneState && !laneState.deleted ? laneState.contentHash : undefined;
|
|
5538
|
+
if (headHash === laneHash)
|
|
5539
|
+
continue;
|
|
5540
|
+
if (headHash === baseHash && laneHash !== baseHash)
|
|
5541
|
+
continue;
|
|
5542
|
+
if (laneHash === baseHash && headHash !== baseHash)
|
|
5543
|
+
continue;
|
|
5544
|
+
const mergeResult = mergeLaneFile(path, base, ours, theirs, blobStore);
|
|
5545
|
+
if (mergeResult.clean) {
|
|
5546
|
+
if (mergeResult.merged !== undefined) {
|
|
5547
|
+
return { mergedContent: mergeResult.merged };
|
|
5548
|
+
}
|
|
5549
|
+
continue;
|
|
5550
|
+
}
|
|
5551
|
+
return {
|
|
5552
|
+
conflict: {
|
|
5553
|
+
class: "file",
|
|
5554
|
+
laneOpHash: op.hash,
|
|
5555
|
+
filePath: path,
|
|
5556
|
+
suggestion: "manual",
|
|
5557
|
+
message: `File conflict on ${path} (${mergeResult.conflictKind ?? "modify-modify"})`
|
|
5558
|
+
}
|
|
5559
|
+
};
|
|
5373
5560
|
}
|
|
5374
|
-
|
|
5375
|
-
|
|
5561
|
+
return {};
|
|
5562
|
+
}
|
|
5563
|
+
function isBlockingConflict(conflict) {
|
|
5564
|
+
return conflict.class === "soft" || conflict.class === "hard" || conflict.class === "file";
|
|
5565
|
+
}
|
|
5566
|
+
async function planLanePromote(params) {
|
|
5567
|
+
const {
|
|
5568
|
+
laneId,
|
|
5569
|
+
meta,
|
|
5570
|
+
targetBranch,
|
|
5571
|
+
snapshotHead,
|
|
5572
|
+
integrationOps,
|
|
5573
|
+
laneOps,
|
|
5574
|
+
parentLaneOps,
|
|
5575
|
+
blobStore
|
|
5576
|
+
} = params;
|
|
5577
|
+
const baseStore = buildStoreUpTo(integrationOps, meta.baseOpHash);
|
|
5578
|
+
const headStore = buildStoreUpTo(integrationOps, snapshotHead);
|
|
5579
|
+
const fileLaneOps = meta.forkKind === "child" && parentLaneOps?.length ? [...parentLaneOps, ...laneOps] : laneOps;
|
|
5580
|
+
const childOpOffset = parentLaneOps?.length ?? 0;
|
|
5581
|
+
const opsToReplay = [];
|
|
5582
|
+
const conflicts = [];
|
|
5583
|
+
let safeOpCount = 0;
|
|
5584
|
+
for (let i = 0;i < laneOps.length; i++) {
|
|
5585
|
+
const op = laneOps[i];
|
|
5586
|
+
if (SKIP_PROMOTE_KINDS.has(op.kind))
|
|
5587
|
+
continue;
|
|
5588
|
+
if (FILE_OP_KINDS2.has(op.kind)) {
|
|
5589
|
+
const fileResult = detectFileConflict(op, integrationOps, fileLaneOps, childOpOffset + i, meta.baseOpHash, snapshotHead, blobStore);
|
|
5590
|
+
if (fileResult.conflict) {
|
|
5591
|
+
conflicts.push(fileResult.conflict);
|
|
5592
|
+
continue;
|
|
5593
|
+
}
|
|
5594
|
+
opsToReplay.push({
|
|
5595
|
+
sourceOp: op,
|
|
5596
|
+
mergedContent: fileResult.mergedContent
|
|
5597
|
+
});
|
|
5598
|
+
safeOpCount++;
|
|
5599
|
+
continue;
|
|
5600
|
+
}
|
|
5601
|
+
const decomposed = decompose(op);
|
|
5602
|
+
if (decomposed.addFacts.length > 0 && decomposed.deleteFacts.length === 0 && decomposed.addFacts.every((fact) => atomsEqual(getFactValue(headStore, fact.e, fact.a), fact.v))) {
|
|
5603
|
+
continue;
|
|
5604
|
+
}
|
|
5605
|
+
const entityConflicts = detectEntityConflicts(op, baseStore, headStore);
|
|
5606
|
+
const blockingEntity = entityConflicts.filter(isBlockingConflict);
|
|
5607
|
+
conflicts.push(...entityConflicts);
|
|
5608
|
+
if (blockingEntity.length > 0)
|
|
5609
|
+
continue;
|
|
5610
|
+
opsToReplay.push({ sourceOp: op });
|
|
5611
|
+
safeOpCount++;
|
|
5612
|
+
replayOpIntoStore(headStore, op);
|
|
5376
5613
|
}
|
|
5377
|
-
|
|
5378
|
-
|
|
5614
|
+
const blockingConflicts = conflicts.filter(isBlockingConflict);
|
|
5615
|
+
return {
|
|
5616
|
+
laneId,
|
|
5617
|
+
targetBranch,
|
|
5618
|
+
snapshotHead,
|
|
5619
|
+
baseOpHash: meta.baseOpHash,
|
|
5620
|
+
opsToReplay,
|
|
5621
|
+
conflicts,
|
|
5622
|
+
blockingConflicts,
|
|
5623
|
+
safeOpCount,
|
|
5624
|
+
canPromote: blockingConflicts.length === 0 && opsToReplay.length > 0
|
|
5625
|
+
};
|
|
5626
|
+
}
|
|
5627
|
+
async function rechainOpForIntegration(op, previousHash) {
|
|
5628
|
+
if (!isVcsOpKindSafe(op.kind)) {
|
|
5629
|
+
throw new Error(`Cannot rechain op kind '${op.kind}' for integration replay`);
|
|
5379
5630
|
}
|
|
5380
|
-
|
|
5381
|
-
|
|
5631
|
+
return createVcsOp(op.kind, {
|
|
5632
|
+
agentId: op.agentId,
|
|
5633
|
+
previousHash,
|
|
5634
|
+
vcs: { ...op.vcs }
|
|
5635
|
+
});
|
|
5636
|
+
}
|
|
5637
|
+
function isVcsOpKindSafe(kind) {
|
|
5638
|
+
return kind.startsWith("vcs:");
|
|
5639
|
+
}
|
|
5640
|
+
function formatPromoteExplain(plan) {
|
|
5641
|
+
const lines = [
|
|
5642
|
+
`Lane promote plan: ${plan.laneId}`,
|
|
5643
|
+
` Target branch: ${plan.targetBranch}`,
|
|
5644
|
+
` Fork base: ${plan.baseOpHash}`,
|
|
5645
|
+
` Snapshot head: ${plan.snapshotHead}`,
|
|
5646
|
+
` Ops to replay: ${plan.opsToReplay.length}`,
|
|
5647
|
+
` Safe ops: ${plan.safeOpCount}`
|
|
5648
|
+
];
|
|
5649
|
+
if (plan.blockingConflicts.length === 0) {
|
|
5650
|
+
lines.push("", plan.canPromote ? "\u2713 Ready to promote" : "No ops to replay");
|
|
5651
|
+
return lines.join(`
|
|
5652
|
+
`);
|
|
5382
5653
|
}
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
if (
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
} catch {}
|
|
5654
|
+
lines.push("", `Blocking conflicts (${plan.blockingConflicts.length}):`);
|
|
5655
|
+
for (const c of plan.blockingConflicts) {
|
|
5656
|
+
const where = c.filePath ?? (c.entityId && c.attribute ? `${c.entityId}.${c.attribute}` : c.entityId);
|
|
5657
|
+
lines.push(` [${c.class}] ${where ?? c.laneOpHash.slice(0, 24)}`);
|
|
5658
|
+
if (c.message)
|
|
5659
|
+
lines.push(` ${c.message}`);
|
|
5660
|
+
if (c.integrationValue !== undefined) {
|
|
5661
|
+
lines.push(` integration: ${String(c.integrationValue)}`);
|
|
5392
5662
|
}
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
static repair(filePath) {
|
|
5396
|
-
if (!existsSync4(filePath)) {
|
|
5397
|
-
return { recovered: 0, lost: 0 };
|
|
5663
|
+
if (c.laneValue !== undefined) {
|
|
5664
|
+
lines.push(` lane: ${String(c.laneValue)}`);
|
|
5398
5665
|
}
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5666
|
+
}
|
|
5667
|
+
return lines.join(`
|
|
5668
|
+
`);
|
|
5669
|
+
}
|
|
5670
|
+
var SKIP_PROMOTE_KINDS, FILE_OP_KINDS2;
|
|
5671
|
+
var init_lane_promote = __esm(() => {
|
|
5672
|
+
init_eav_store();
|
|
5673
|
+
init_decompose();
|
|
5674
|
+
init_diff();
|
|
5675
|
+
init_merge();
|
|
5676
|
+
init_ops();
|
|
5677
|
+
SKIP_PROMOTE_KINDS = new Set([
|
|
5678
|
+
"vcs:branchAdvance",
|
|
5679
|
+
"vcs:laneCreate",
|
|
5680
|
+
"vcs:laneDrop",
|
|
5681
|
+
"vcs:lanePromoteStart",
|
|
5682
|
+
"vcs:lanePromoteComplete",
|
|
5683
|
+
"vcs:lanePromoteAbort"
|
|
5684
|
+
]);
|
|
5685
|
+
FILE_OP_KINDS2 = new Set([
|
|
5686
|
+
"vcs:fileAdd",
|
|
5687
|
+
"vcs:fileModify",
|
|
5688
|
+
"vcs:fileDelete",
|
|
5689
|
+
"vcs:fileRename"
|
|
5690
|
+
]);
|
|
5691
|
+
});
|
|
5692
|
+
|
|
5693
|
+
// src/vcs/lane-materialize.ts
|
|
5694
|
+
function emptyMaterializationStats() {
|
|
5695
|
+
return {
|
|
5696
|
+
integrationOpsReplayed: 0,
|
|
5697
|
+
laneOpsReplayed: 0,
|
|
5698
|
+
integrationCacheHit: false
|
|
5699
|
+
};
|
|
5700
|
+
}
|
|
5701
|
+
function replayOpIntoStore2(store, op) {
|
|
5702
|
+
const d = decompose(op);
|
|
5703
|
+
if (d.deleteFacts.length > 0)
|
|
5704
|
+
store.deleteFacts(d.deleteFacts);
|
|
5705
|
+
if (d.deleteLinks.length > 0)
|
|
5706
|
+
store.deleteLinks(d.deleteLinks);
|
|
5707
|
+
if (d.addFacts.length > 0)
|
|
5708
|
+
store.addFacts(d.addFacts);
|
|
5709
|
+
if (d.addLinks.length > 0)
|
|
5710
|
+
store.addLinks(d.addLinks);
|
|
5711
|
+
}
|
|
5712
|
+
function cloneStore(source) {
|
|
5713
|
+
const clone = new EAVStore;
|
|
5714
|
+
clone.restore(source.snapshot());
|
|
5715
|
+
return clone;
|
|
5716
|
+
}
|
|
5717
|
+
function materializeIntegrationOps(ops, cache, tailHash) {
|
|
5718
|
+
if (cache && cache.tailHash === tailHash) {
|
|
5719
|
+
return {
|
|
5720
|
+
store: cache.store,
|
|
5721
|
+
cache,
|
|
5722
|
+
stats: {
|
|
5723
|
+
integrationOpsReplayed: 0,
|
|
5724
|
+
laneOpsReplayed: 0,
|
|
5725
|
+
integrationCacheHit: true,
|
|
5726
|
+
integrationTailHash: tailHash
|
|
5414
5727
|
}
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
writeFileSync3(filePath + ".corrupted", raw);
|
|
5430
|
-
writeFileSync3(filePath, fixed);
|
|
5431
|
-
return { recovered: ops.length, lost: 0 };
|
|
5432
|
-
} catch {
|
|
5433
|
-
writeFileSync3(filePath + ".corrupted", raw);
|
|
5434
|
-
writeFileSync3(filePath, "[]");
|
|
5435
|
-
return { recovered: 0, lost: -1 };
|
|
5728
|
+
};
|
|
5729
|
+
}
|
|
5730
|
+
const store = new EAVStore;
|
|
5731
|
+
for (const op of ops) {
|
|
5732
|
+
replayOpIntoStore2(store, op);
|
|
5733
|
+
}
|
|
5734
|
+
return {
|
|
5735
|
+
store,
|
|
5736
|
+
cache: { tailHash, store },
|
|
5737
|
+
stats: {
|
|
5738
|
+
integrationOpsReplayed: ops.length,
|
|
5739
|
+
laneOpsReplayed: 0,
|
|
5740
|
+
integrationCacheHit: false,
|
|
5741
|
+
integrationTailHash: tailHash
|
|
5436
5742
|
}
|
|
5743
|
+
};
|
|
5744
|
+
}
|
|
5745
|
+
function overlayLaneOps(integrationStore, laneOps) {
|
|
5746
|
+
const store = cloneStore(integrationStore);
|
|
5747
|
+
for (const op of laneOps) {
|
|
5748
|
+
replayOpIntoStore2(store, op);
|
|
5437
5749
|
}
|
|
5750
|
+
return { store, laneOpsReplayed: laneOps.length };
|
|
5438
5751
|
}
|
|
5752
|
+
function materializeChildForkEntry(integrationOps, baseOpHash, parentLaneOps, childLaneOps) {
|
|
5753
|
+
const store = new EAVStore;
|
|
5754
|
+
let integrationReplayed = 0;
|
|
5755
|
+
for (const op of integrationOps) {
|
|
5756
|
+
replayOpIntoStore2(store, op);
|
|
5757
|
+
integrationReplayed++;
|
|
5758
|
+
if (op.hash === baseOpHash)
|
|
5759
|
+
break;
|
|
5760
|
+
}
|
|
5761
|
+
for (const op of parentLaneOps) {
|
|
5762
|
+
replayOpIntoStore2(store, op);
|
|
5763
|
+
}
|
|
5764
|
+
for (const op of childLaneOps) {
|
|
5765
|
+
replayOpIntoStore2(store, op);
|
|
5766
|
+
}
|
|
5767
|
+
return {
|
|
5768
|
+
store,
|
|
5769
|
+
stats: {
|
|
5770
|
+
integrationOpsReplayed: integrationReplayed,
|
|
5771
|
+
laneOpsReplayed: parentLaneOps.length + childLaneOps.length,
|
|
5772
|
+
integrationCacheHit: false,
|
|
5773
|
+
integrationTailHash: integrationOps[integrationOps.length - 1]?.hash
|
|
5774
|
+
}
|
|
5775
|
+
};
|
|
5776
|
+
}
|
|
5777
|
+
var init_lane_materialize = __esm(() => {
|
|
5778
|
+
init_eav_store();
|
|
5779
|
+
init_decompose();
|
|
5780
|
+
});
|
|
5781
|
+
|
|
5782
|
+
// src/engine.ts
|
|
5783
|
+
import {
|
|
5784
|
+
existsSync as existsSync4,
|
|
5785
|
+
mkdirSync as mkdirSync3,
|
|
5786
|
+
readFileSync as readFileSync4,
|
|
5787
|
+
writeFileSync as writeFileSync3
|
|
5788
|
+
} from "fs";
|
|
5789
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
5790
|
+
import { join as join5 } from "path";
|
|
5439
5791
|
function parseIgnoreFile(filePath) {
|
|
5440
5792
|
if (!existsSync4(filePath))
|
|
5441
5793
|
return [];
|
|
@@ -5489,6 +5841,10 @@ class TrellisVcsEngine {
|
|
|
5489
5841
|
checkpointThreshold = 100;
|
|
5490
5842
|
_pendingAutoCheckpoint = false;
|
|
5491
5843
|
_blobStore = null;
|
|
5844
|
+
activeLaneId;
|
|
5845
|
+
activeLaneLog = null;
|
|
5846
|
+
integrationCache = null;
|
|
5847
|
+
materializationStats = emptyMaterializationStats();
|
|
5492
5848
|
constructor(opts) {
|
|
5493
5849
|
const gitignorePatterns = readIgnorePatterns(opts.rootPath);
|
|
5494
5850
|
const mergedIgnore = [
|
|
@@ -5533,7 +5889,7 @@ class TrellisVcsEngine {
|
|
|
5533
5889
|
branchName: this.config.defaultBranch
|
|
5534
5890
|
}
|
|
5535
5891
|
});
|
|
5536
|
-
this.applyOp(branchOp);
|
|
5892
|
+
await this.applyOp(branchOp);
|
|
5537
5893
|
const scanner = new FileWatcher({
|
|
5538
5894
|
rootPath: this.config.rootPath,
|
|
5539
5895
|
ignorePatterns: [...this.config.ignorePatterns, ".trellis"],
|
|
@@ -5577,7 +5933,7 @@ class TrellisVcsEngine {
|
|
|
5577
5933
|
size: event.size
|
|
5578
5934
|
}
|
|
5579
5935
|
});
|
|
5580
|
-
this.applyOp(op);
|
|
5936
|
+
await this.applyOp(op);
|
|
5581
5937
|
opsCreated++;
|
|
5582
5938
|
const scannedFiles = opsCreated - 1;
|
|
5583
5939
|
if (scannedFiles % 25 === 0 || scannedFiles === events.length) {
|
|
@@ -5626,16 +5982,19 @@ class TrellisVcsEngine {
|
|
|
5626
5982
|
this.config.defaultBranch = persisted.defaultBranch;
|
|
5627
5983
|
}
|
|
5628
5984
|
this.loadCurrentBranch();
|
|
5629
|
-
const
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5985
|
+
const integrationOps = this.opLog.readAll();
|
|
5986
|
+
const laneOps = this.activeLaneLog ? this.activeLaneLog.readAll() : undefined;
|
|
5987
|
+
const activeMeta = this.activeLaneId ? this.getLaneMeta(this.activeLaneId) : undefined;
|
|
5988
|
+
this.refreshMaterializedStore(integrationOps, laneOps, activeMeta);
|
|
5989
|
+
const laneReplayed = this.materializationStats.laneOpsReplayed;
|
|
5990
|
+
return {
|
|
5991
|
+
opsReplayed: this.materializationStats.integrationOpsReplayed + laneReplayed
|
|
5992
|
+
};
|
|
5634
5993
|
}
|
|
5635
5994
|
watch() {
|
|
5636
5995
|
this.ingestion = new Ingestion({
|
|
5637
5996
|
agentId: this.agentId,
|
|
5638
|
-
lastOpHash: this.
|
|
5997
|
+
lastOpHash: this.getActiveJournal().getLastOp()?.hash,
|
|
5639
5998
|
onOp: (op) => this.applyOp(op)
|
|
5640
5999
|
});
|
|
5641
6000
|
this.watcher = new FileWatcher({
|
|
@@ -5740,7 +6099,11 @@ class TrellisVcsEngine {
|
|
|
5740
6099
|
switchBranch(name) {
|
|
5741
6100
|
switchBranch(this._ctx(), name);
|
|
5742
6101
|
this.currentBranch = name;
|
|
5743
|
-
|
|
6102
|
+
const state = loadBranchState(this.config.rootPath);
|
|
6103
|
+
saveBranchState(this.config.rootPath, {
|
|
6104
|
+
...state,
|
|
6105
|
+
currentBranch: name
|
|
6106
|
+
});
|
|
5744
6107
|
}
|
|
5745
6108
|
listBranches() {
|
|
5746
6109
|
return listBranches(this._ctx(), this.currentBranch);
|
|
@@ -5753,6 +6116,344 @@ class TrellisVcsEngine {
|
|
|
5753
6116
|
getCurrentBranch() {
|
|
5754
6117
|
return this.currentBranch;
|
|
5755
6118
|
}
|
|
6119
|
+
getBranchHeadOpHash(branchName = this.currentBranch) {
|
|
6120
|
+
return getBranchHeadOpHash(this._ctx(), branchName);
|
|
6121
|
+
}
|
|
6122
|
+
getActiveLaneId() {
|
|
6123
|
+
return this.activeLaneId;
|
|
6124
|
+
}
|
|
6125
|
+
getMaterializationStats() {
|
|
6126
|
+
return { ...this.materializationStats };
|
|
6127
|
+
}
|
|
6128
|
+
listLanes() {
|
|
6129
|
+
return listLaneMetas(this.trellisDir());
|
|
6130
|
+
}
|
|
6131
|
+
getIntegrationOpCount() {
|
|
6132
|
+
return this.opLog.count();
|
|
6133
|
+
}
|
|
6134
|
+
getLaneOpCount(laneId) {
|
|
6135
|
+
const log = new LaneOpLog(laneDir(this.trellisDir(), laneId));
|
|
6136
|
+
log.load();
|
|
6137
|
+
return log.count();
|
|
6138
|
+
}
|
|
6139
|
+
getLaneMeta(laneId) {
|
|
6140
|
+
return loadLaneMeta(this.trellisDir(), laneId);
|
|
6141
|
+
}
|
|
6142
|
+
findLaneForIssue(issueId) {
|
|
6143
|
+
const normalized = issueId.startsWith("issue:") ? issueId : `issue:${issueId}`;
|
|
6144
|
+
return this.listLanes().find((lane) => lane.issueId === normalized && lane.status === "active");
|
|
6145
|
+
}
|
|
6146
|
+
async syncEnvLaneFromEnv() {
|
|
6147
|
+
const laneId = process.env.TRELLIS_LANE_ID?.trim();
|
|
6148
|
+
if (!laneId)
|
|
6149
|
+
return;
|
|
6150
|
+
if (this.activeLaneId === laneId)
|
|
6151
|
+
return;
|
|
6152
|
+
if (this.activeLaneId) {
|
|
6153
|
+
throw new Error(`TRELLIS_LANE_ID=${laneId} conflicts with active lane '${this.activeLaneId}'`);
|
|
6154
|
+
}
|
|
6155
|
+
await this.enterLane(laneId);
|
|
6156
|
+
}
|
|
6157
|
+
summarizeLane(laneId) {
|
|
6158
|
+
const meta = this.getLaneMeta(laneId);
|
|
6159
|
+
if (!meta) {
|
|
6160
|
+
throw new Error(`Lane not found: ${laneId}`);
|
|
6161
|
+
}
|
|
6162
|
+
const log = new LaneOpLog(laneDir(this.trellisDir(), laneId));
|
|
6163
|
+
log.load();
|
|
6164
|
+
const ops = log.readAll();
|
|
6165
|
+
const filePaths = [
|
|
6166
|
+
...new Set(ops.map((op) => op.vcs?.filePath ?? op.vcs?.oldFilePath).filter((p) => Boolean(p)))
|
|
6167
|
+
];
|
|
6168
|
+
return {
|
|
6169
|
+
meta,
|
|
6170
|
+
ops,
|
|
6171
|
+
filePaths,
|
|
6172
|
+
integrationHead: this.getBranchHeadOpHash(meta.targetBranch)
|
|
6173
|
+
};
|
|
6174
|
+
}
|
|
6175
|
+
async createLane(opts) {
|
|
6176
|
+
if (this.activeLaneId) {
|
|
6177
|
+
throw new Error(`Cannot create a lane while inside lane '${this.activeLaneId}' \u2014 leave first`);
|
|
6178
|
+
}
|
|
6179
|
+
const baseBranch = opts?.fromBranch ?? this.currentBranch;
|
|
6180
|
+
const baseOpHash = getBranchHeadOpHash(this._ctx(), baseBranch) ?? this.opLog.getLastOp()?.hash;
|
|
6181
|
+
if (!baseOpHash) {
|
|
6182
|
+
throw new Error(`No integration head on branch '${baseBranch}' to fork lane from`);
|
|
6183
|
+
}
|
|
6184
|
+
const meta = createLaneMeta(this.trellisDir(), {
|
|
6185
|
+
baseBranch,
|
|
6186
|
+
baseOpHash,
|
|
6187
|
+
targetBranch: opts?.targetBranch ?? baseBranch,
|
|
6188
|
+
agentId: this.agentId,
|
|
6189
|
+
issueId: opts?.issueId,
|
|
6190
|
+
sessionId: opts?.sessionId,
|
|
6191
|
+
worktreePath: opts?.worktreePath
|
|
6192
|
+
});
|
|
6193
|
+
const op = await createVcsOp("vcs:laneCreate", {
|
|
6194
|
+
agentId: this.agentId,
|
|
6195
|
+
previousHash: this.opLog.getLastOp()?.hash,
|
|
6196
|
+
vcs: {
|
|
6197
|
+
laneId: meta.id,
|
|
6198
|
+
baseBranch: meta.baseBranch,
|
|
6199
|
+
baseOpHash: meta.baseOpHash,
|
|
6200
|
+
targetBranch: meta.targetBranch,
|
|
6201
|
+
issueId: meta.issueId
|
|
6202
|
+
}
|
|
6203
|
+
});
|
|
6204
|
+
await this.applyOp(op);
|
|
6205
|
+
return meta;
|
|
6206
|
+
}
|
|
6207
|
+
async forkLane(parentLaneId, opts) {
|
|
6208
|
+
if (this.activeLaneId) {
|
|
6209
|
+
throw new Error(`Cannot fork a lane while inside lane '${this.activeLaneId}' \u2014 leave first`);
|
|
6210
|
+
}
|
|
6211
|
+
const parent = loadLaneMeta(this.trellisDir(), parentLaneId);
|
|
6212
|
+
if (!parent) {
|
|
6213
|
+
throw new Error(`Lane not found: ${parentLaneId}`);
|
|
6214
|
+
}
|
|
6215
|
+
if (parent.status !== "active") {
|
|
6216
|
+
throw new Error(`Lane '${parentLaneId}' is ${parent.status} \u2014 cannot fork`);
|
|
6217
|
+
}
|
|
6218
|
+
const forkKind = opts?.forkKind ?? "sibling";
|
|
6219
|
+
const forkedAt = new Date().toISOString();
|
|
6220
|
+
const parentLog = new LaneOpLog(laneDir(this.trellisDir(), parentLaneId));
|
|
6221
|
+
parentLog.load();
|
|
6222
|
+
const parentLaneOps = parentLog.readAll();
|
|
6223
|
+
const parentHead = resolveLaneHeadFromJournal(parent, parentLaneOps);
|
|
6224
|
+
if (forkKind === "child") {
|
|
6225
|
+
const meta2 = createLaneMeta(this.trellisDir(), {
|
|
6226
|
+
baseBranch: parent.baseBranch,
|
|
6227
|
+
baseOpHash: parent.baseOpHash,
|
|
6228
|
+
targetBranch: parent.targetBranch,
|
|
6229
|
+
agentId: this.agentId,
|
|
6230
|
+
issueId: opts?.issueId ?? parent.issueId,
|
|
6231
|
+
sessionId: opts?.sessionId,
|
|
6232
|
+
worktreePath: opts?.worktreePath,
|
|
6233
|
+
parentLaneId: parent.id,
|
|
6234
|
+
forkKind: "child",
|
|
6235
|
+
forkedAt,
|
|
6236
|
+
virtualBaseOpHash: parentHead
|
|
6237
|
+
});
|
|
6238
|
+
const op2 = await createVcsOp("vcs:laneCreate", {
|
|
6239
|
+
agentId: this.agentId,
|
|
6240
|
+
previousHash: this.opLog.getLastOp()?.hash,
|
|
6241
|
+
vcs: {
|
|
6242
|
+
laneId: meta2.id,
|
|
6243
|
+
baseBranch: meta2.baseBranch,
|
|
6244
|
+
baseOpHash: meta2.baseOpHash,
|
|
6245
|
+
targetBranch: meta2.targetBranch,
|
|
6246
|
+
issueId: meta2.issueId,
|
|
6247
|
+
sessionId: meta2.sessionId,
|
|
6248
|
+
parentLaneId: parent.id,
|
|
6249
|
+
forkKind: "child",
|
|
6250
|
+
virtualBaseOpHash: parentHead
|
|
6251
|
+
}
|
|
6252
|
+
});
|
|
6253
|
+
await this.applyOp(op2);
|
|
6254
|
+
return meta2;
|
|
6255
|
+
}
|
|
6256
|
+
const meta = createLaneMeta(this.trellisDir(), {
|
|
6257
|
+
baseBranch: parent.baseBranch,
|
|
6258
|
+
baseOpHash: parent.baseOpHash,
|
|
6259
|
+
targetBranch: parent.targetBranch,
|
|
6260
|
+
agentId: this.agentId,
|
|
6261
|
+
issueId: opts?.issueId ?? parent.issueId,
|
|
6262
|
+
sessionId: opts?.sessionId,
|
|
6263
|
+
worktreePath: opts?.worktreePath,
|
|
6264
|
+
parentLaneId: parent.id,
|
|
6265
|
+
forkKind: "sibling",
|
|
6266
|
+
forkedAt
|
|
6267
|
+
});
|
|
6268
|
+
const op = await createVcsOp("vcs:laneCreate", {
|
|
6269
|
+
agentId: this.agentId,
|
|
6270
|
+
previousHash: this.opLog.getLastOp()?.hash,
|
|
6271
|
+
vcs: {
|
|
6272
|
+
laneId: meta.id,
|
|
6273
|
+
baseBranch: meta.baseBranch,
|
|
6274
|
+
baseOpHash: meta.baseOpHash,
|
|
6275
|
+
targetBranch: meta.targetBranch,
|
|
6276
|
+
issueId: meta.issueId,
|
|
6277
|
+
sessionId: meta.sessionId,
|
|
6278
|
+
parentLaneId: parent.id,
|
|
6279
|
+
forkKind: "sibling"
|
|
6280
|
+
}
|
|
6281
|
+
});
|
|
6282
|
+
await this.applyOp(op);
|
|
6283
|
+
return meta;
|
|
6284
|
+
}
|
|
6285
|
+
async enterLane(laneId) {
|
|
6286
|
+
if (this.activeLaneId) {
|
|
6287
|
+
throw new Error(`Already in lane '${this.activeLaneId}' \u2014 leave before entering another`);
|
|
6288
|
+
}
|
|
6289
|
+
const meta = loadLaneMeta(this.trellisDir(), laneId);
|
|
6290
|
+
if (!meta) {
|
|
6291
|
+
throw new Error(`Lane not found: ${laneId}`);
|
|
6292
|
+
}
|
|
6293
|
+
if (meta.status !== "active") {
|
|
6294
|
+
throw new Error(`Lane '${laneId}' is ${meta.status} \u2014 cannot enter`);
|
|
6295
|
+
}
|
|
6296
|
+
this.activeLaneId = laneId;
|
|
6297
|
+
this.activeLaneLog = new LaneOpLog(laneDir(this.trellisDir(), laneId));
|
|
6298
|
+
this.activeLaneLog.load();
|
|
6299
|
+
this.refreshMaterializedStore(this.opLog.readAll(), this.activeLaneLog.readAll(), meta);
|
|
6300
|
+
saveBranchState(this.config.rootPath, {
|
|
6301
|
+
currentBranch: this.currentBranch,
|
|
6302
|
+
activeLaneId: laneId
|
|
6303
|
+
});
|
|
6304
|
+
this.syncIngestionLastOpHash();
|
|
6305
|
+
return meta;
|
|
6306
|
+
}
|
|
6307
|
+
async leaveLane() {
|
|
6308
|
+
if (!this.activeLaneId)
|
|
6309
|
+
return;
|
|
6310
|
+
this.activeLaneId = undefined;
|
|
6311
|
+
this.activeLaneLog = null;
|
|
6312
|
+
saveBranchState(this.config.rootPath, {
|
|
6313
|
+
currentBranch: this.currentBranch
|
|
6314
|
+
});
|
|
6315
|
+
this.restoreIntegrationOnlyStore();
|
|
6316
|
+
this.syncIngestionLastOpHash();
|
|
6317
|
+
}
|
|
6318
|
+
async dropLane(laneId) {
|
|
6319
|
+
if (this.activeLaneId === laneId) {
|
|
6320
|
+
await this.leaveLane();
|
|
6321
|
+
}
|
|
6322
|
+
const meta = loadLaneMeta(this.trellisDir(), laneId);
|
|
6323
|
+
if (!meta) {
|
|
6324
|
+
throw new Error(`Lane not found: ${laneId}`);
|
|
6325
|
+
}
|
|
6326
|
+
if (meta.status === "dropped")
|
|
6327
|
+
return;
|
|
6328
|
+
meta.status = "dropped";
|
|
6329
|
+
meta.updatedAt = new Date().toISOString();
|
|
6330
|
+
saveLaneMeta(this.trellisDir(), meta);
|
|
6331
|
+
const op = await createVcsOp("vcs:laneDrop", {
|
|
6332
|
+
agentId: this.agentId,
|
|
6333
|
+
previousHash: this.opLog.getLastOp()?.hash,
|
|
6334
|
+
vcs: {
|
|
6335
|
+
laneId: meta.id,
|
|
6336
|
+
laneStatus: "dropped"
|
|
6337
|
+
}
|
|
6338
|
+
});
|
|
6339
|
+
await this.applyOp(op);
|
|
6340
|
+
}
|
|
6341
|
+
async promoteLane(laneId, opts) {
|
|
6342
|
+
const meta = this.getLaneMeta(laneId);
|
|
6343
|
+
if (!meta) {
|
|
6344
|
+
throw new Error(`Lane not found: ${laneId}`);
|
|
6345
|
+
}
|
|
6346
|
+
if (meta.status !== "active") {
|
|
6347
|
+
throw new Error(`Lane '${laneId}' is ${meta.status} \u2014 cannot promote`);
|
|
6348
|
+
}
|
|
6349
|
+
if (this.activeLaneId === laneId) {
|
|
6350
|
+
await this.leaveLane();
|
|
6351
|
+
} else if (this.activeLaneId) {
|
|
6352
|
+
throw new Error(`Cannot promote while inside lane '${this.activeLaneId}' \u2014 leave first`);
|
|
6353
|
+
}
|
|
6354
|
+
const targetBranch = opts?.toBranch ?? meta.targetBranch;
|
|
6355
|
+
const integrationOps = this.opLog.readAll();
|
|
6356
|
+
const snapshotHead = resolveBranchHeadFromOps(integrationOps, targetBranch) ?? getBranchHeadOpHash(this._ctx(), targetBranch);
|
|
6357
|
+
if (!snapshotHead) {
|
|
6358
|
+
throw new Error(`No head on branch '${targetBranch}' to promote onto`);
|
|
6359
|
+
}
|
|
6360
|
+
const laneLog = new LaneOpLog(laneDir(this.trellisDir(), laneId));
|
|
6361
|
+
laneLog.load();
|
|
6362
|
+
const laneOps = laneLog.readAll();
|
|
6363
|
+
let parentLaneOps;
|
|
6364
|
+
if (meta.forkKind === "child" && meta.parentLaneId) {
|
|
6365
|
+
parentLaneOps = this.loadLaneJournalOps(meta.parentLaneId);
|
|
6366
|
+
}
|
|
6367
|
+
const plan = await planLanePromote({
|
|
6368
|
+
laneId,
|
|
6369
|
+
meta,
|
|
6370
|
+
targetBranch,
|
|
6371
|
+
snapshotHead,
|
|
6372
|
+
integrationOps: this.opLog.readAll(),
|
|
6373
|
+
laneOps,
|
|
6374
|
+
parentLaneOps,
|
|
6375
|
+
blobStore: this._blobStore
|
|
6376
|
+
});
|
|
6377
|
+
if (opts?.dryRun || !plan.canPromote) {
|
|
6378
|
+
return { ...plan, promoted: false };
|
|
6379
|
+
}
|
|
6380
|
+
meta.status = "promoting";
|
|
6381
|
+
meta.updatedAt = new Date().toISOString();
|
|
6382
|
+
saveLaneMeta(this.trellisDir(), meta);
|
|
6383
|
+
const startOp = await createVcsOp("vcs:lanePromoteStart", {
|
|
6384
|
+
agentId: this.agentId,
|
|
6385
|
+
previousHash: this.opLog.getLastOp()?.hash,
|
|
6386
|
+
vcs: {
|
|
6387
|
+
laneId,
|
|
6388
|
+
targetBranch,
|
|
6389
|
+
baseOpHash: meta.baseOpHash
|
|
6390
|
+
}
|
|
6391
|
+
});
|
|
6392
|
+
await this.applyOp(startOp, { skipBranchAdvance: true });
|
|
6393
|
+
const currentHead = resolveBranchHeadFromOps(this.opLog.readAll(), targetBranch) ?? getBranchHeadOpHash(this._ctx(), targetBranch);
|
|
6394
|
+
if (currentHead !== snapshotHead) {
|
|
6395
|
+
meta.status = "active";
|
|
6396
|
+
meta.updatedAt = new Date().toISOString();
|
|
6397
|
+
saveLaneMeta(this.trellisDir(), meta);
|
|
6398
|
+
const abortOp = await createVcsOp("vcs:lanePromoteAbort", {
|
|
6399
|
+
agentId: this.agentId,
|
|
6400
|
+
previousHash: this.opLog.getLastOp()?.hash,
|
|
6401
|
+
vcs: { laneId }
|
|
6402
|
+
});
|
|
6403
|
+
await this.applyOp(abortOp, { skipBranchAdvance: true });
|
|
6404
|
+
throw new Error(`Integration head moved during promote \u2014 retry after integration settles`);
|
|
6405
|
+
}
|
|
6406
|
+
let previousHash = this.opLog.getLastOp()?.hash;
|
|
6407
|
+
let lastReplayedHash;
|
|
6408
|
+
let opsAppended = 0;
|
|
6409
|
+
for (const action of plan.opsToReplay) {
|
|
6410
|
+
let opToApply;
|
|
6411
|
+
if (action.mergedContent !== undefined && action.sourceOp.vcs?.filePath) {
|
|
6412
|
+
const contentHash = await this._blobStore.put(Buffer.from(action.mergedContent, "utf-8"));
|
|
6413
|
+
opToApply = await createVcsOp("vcs:fileModify", {
|
|
6414
|
+
agentId: action.sourceOp.agentId,
|
|
6415
|
+
previousHash,
|
|
6416
|
+
vcs: {
|
|
6417
|
+
filePath: action.sourceOp.vcs.filePath,
|
|
6418
|
+
contentHash,
|
|
6419
|
+
laneId: action.sourceOp.vcs.laneId ?? laneId
|
|
6420
|
+
}
|
|
6421
|
+
});
|
|
6422
|
+
} else {
|
|
6423
|
+
opToApply = await rechainOpForIntegration(action.sourceOp, previousHash);
|
|
6424
|
+
}
|
|
6425
|
+
await this.applyOp(opToApply, { skipBranchAdvance: true });
|
|
6426
|
+
previousHash = opToApply.hash;
|
|
6427
|
+
lastReplayedHash = opToApply.hash;
|
|
6428
|
+
opsAppended++;
|
|
6429
|
+
}
|
|
6430
|
+
if (lastReplayedHash) {
|
|
6431
|
+
await this.appendBranchAdvance(lastReplayedHash);
|
|
6432
|
+
}
|
|
6433
|
+
const completeOp = await createVcsOp("vcs:lanePromoteComplete", {
|
|
6434
|
+
agentId: this.agentId,
|
|
6435
|
+
previousHash: this.opLog.getLastOp()?.hash,
|
|
6436
|
+
vcs: {
|
|
6437
|
+
laneId,
|
|
6438
|
+
targetBranch,
|
|
6439
|
+
laneStatus: "promoted"
|
|
6440
|
+
}
|
|
6441
|
+
});
|
|
6442
|
+
await this.applyOp(completeOp, { skipBranchAdvance: true });
|
|
6443
|
+
meta.status = "promoted";
|
|
6444
|
+
meta.headOpHash = lastReplayedHash ?? meta.headOpHash;
|
|
6445
|
+
meta.updatedAt = new Date().toISOString();
|
|
6446
|
+
saveLaneMeta(this.trellisDir(), meta);
|
|
6447
|
+
this.invalidateIntegrationCache();
|
|
6448
|
+
this.refreshMaterializedStore(this.opLog.readAll());
|
|
6449
|
+
this.syncIngestionLastOpHash();
|
|
6450
|
+
return {
|
|
6451
|
+
...plan,
|
|
6452
|
+
promoted: true,
|
|
6453
|
+
integrationOpsAppended: opsAppended + 2,
|
|
6454
|
+
completeOpHash: completeOp.hash
|
|
6455
|
+
};
|
|
6456
|
+
}
|
|
5756
6457
|
async createMilestone(message, opts) {
|
|
5757
6458
|
const op = await createMilestone(this._ctx(), message, opts);
|
|
5758
6459
|
await this.flushAutoCheckpoint();
|
|
@@ -5885,7 +6586,10 @@ class TrellisVcsEngine {
|
|
|
5885
6586
|
await this.flushAutoCheckpoint();
|
|
5886
6587
|
return op;
|
|
5887
6588
|
}
|
|
5888
|
-
async startIssue(id) {
|
|
6589
|
+
async startIssue(id, opts) {
|
|
6590
|
+
if (this.activeLaneId) {
|
|
6591
|
+
await this.leaveLane();
|
|
6592
|
+
}
|
|
5889
6593
|
const issue = getIssue(this._ctx(), id);
|
|
5890
6594
|
if (!issue)
|
|
5891
6595
|
throw new Error(`Issue ${id} not found.`);
|
|
@@ -5894,16 +6598,27 @@ class TrellisVcsEngine {
|
|
|
5894
6598
|
await this.createBranch(branchName);
|
|
5895
6599
|
const op = await startIssue(this._ctx(), id, branchName);
|
|
5896
6600
|
this.switchBranch(branchName);
|
|
6601
|
+
if (opts?.lane !== false) {
|
|
6602
|
+
const issueKey = id.startsWith("issue:") ? id : `issue:${id}`;
|
|
6603
|
+
let lane = this.findLaneForIssue(issueKey);
|
|
6604
|
+
if (!lane) {
|
|
6605
|
+
lane = await this.createLane({ issueId: issueKey });
|
|
6606
|
+
}
|
|
6607
|
+
await this.enterLane(lane.id);
|
|
6608
|
+
}
|
|
5897
6609
|
await this.flushAutoCheckpoint();
|
|
5898
6610
|
return op;
|
|
5899
6611
|
}
|
|
5900
6612
|
async pauseIssue(id, note) {
|
|
6613
|
+
if (this.activeLaneId) {
|
|
6614
|
+
await this.leaveLane();
|
|
6615
|
+
}
|
|
5901
6616
|
const op = await pauseIssue(this._ctx(), id, note);
|
|
5902
6617
|
this.switchBranch(this.config.defaultBranch);
|
|
5903
6618
|
await this.flushAutoCheckpoint();
|
|
5904
6619
|
return op;
|
|
5905
6620
|
}
|
|
5906
|
-
async resumeIssue(id) {
|
|
6621
|
+
async resumeIssue(id, opts) {
|
|
5907
6622
|
const issue = getIssue(this._ctx(), id);
|
|
5908
6623
|
if (!issue)
|
|
5909
6624
|
throw new Error(`Issue ${id} not found.`);
|
|
@@ -5911,10 +6626,20 @@ class TrellisVcsEngine {
|
|
|
5911
6626
|
throw new Error(`Issue ${id} has no tracked branch.`);
|
|
5912
6627
|
const op = await resumeIssue(this._ctx(), id);
|
|
5913
6628
|
this.switchBranch(issue.branchName);
|
|
6629
|
+
if (opts?.lane !== false) {
|
|
6630
|
+
const issueKey = id.startsWith("issue:") ? id : `issue:${id}`;
|
|
6631
|
+
const lane = this.findLaneForIssue(issueKey);
|
|
6632
|
+
if (lane) {
|
|
6633
|
+
await this.enterLane(lane.id);
|
|
6634
|
+
}
|
|
6635
|
+
}
|
|
5914
6636
|
await this.flushAutoCheckpoint();
|
|
5915
6637
|
return op;
|
|
5916
6638
|
}
|
|
5917
6639
|
async closeIssue(id, opts) {
|
|
6640
|
+
if (this.activeLaneId) {
|
|
6641
|
+
await this.leaveLane();
|
|
6642
|
+
}
|
|
5918
6643
|
const result = await closeIssue(this._ctx(), id, opts);
|
|
5919
6644
|
if (result.op) {
|
|
5920
6645
|
await this.flushAutoCheckpoint();
|
|
@@ -5989,13 +6714,106 @@ class TrellisVcsEngine {
|
|
|
5989
6714
|
return {
|
|
5990
6715
|
store: this.store,
|
|
5991
6716
|
agentId: this.agentId,
|
|
5992
|
-
readAllOps: () => this.
|
|
5993
|
-
getLastOp: () => this.
|
|
5994
|
-
applyOp: (op) => this.applyOp(op)
|
|
6717
|
+
readAllOps: () => this.getActiveJournal().readAll(),
|
|
6718
|
+
getLastOp: () => this.getActiveJournal().getLastOp(),
|
|
6719
|
+
applyOp: (op, opts) => this.applyOp(op, opts)
|
|
5995
6720
|
};
|
|
5996
6721
|
}
|
|
5997
|
-
|
|
5998
|
-
|
|
6722
|
+
trellisDir() {
|
|
6723
|
+
return join5(this.config.rootPath, ".trellis");
|
|
6724
|
+
}
|
|
6725
|
+
getActiveJournal() {
|
|
6726
|
+
if (this.activeLaneId && this.activeLaneLog) {
|
|
6727
|
+
return this.activeLaneLog;
|
|
6728
|
+
}
|
|
6729
|
+
return this.opLog;
|
|
6730
|
+
}
|
|
6731
|
+
invalidateIntegrationCache() {
|
|
6732
|
+
this.integrationCache = null;
|
|
6733
|
+
}
|
|
6734
|
+
loadLaneJournalOps(laneId) {
|
|
6735
|
+
const log = new LaneOpLog(laneDir(this.trellisDir(), laneId));
|
|
6736
|
+
log.load();
|
|
6737
|
+
return log.readAll();
|
|
6738
|
+
}
|
|
6739
|
+
refreshMaterializedStore(integrationOps, laneOps, meta) {
|
|
6740
|
+
const laneMeta = meta ?? (this.activeLaneId ? this.getLaneMeta(this.activeLaneId) : undefined);
|
|
6741
|
+
if (laneMeta?.forkKind === "child" && laneMeta.parentLaneId) {
|
|
6742
|
+
const parentLaneOps = this.loadLaneJournalOps(laneMeta.parentLaneId);
|
|
6743
|
+
const { store: store2, stats: stats2 } = materializeChildForkEntry(integrationOps, laneMeta.baseOpHash, parentLaneOps, laneOps ?? []);
|
|
6744
|
+
this.store = store2;
|
|
6745
|
+
this.materializationStats = stats2;
|
|
6746
|
+
return;
|
|
6747
|
+
}
|
|
6748
|
+
const tailHash = integrationOps[integrationOps.length - 1]?.hash;
|
|
6749
|
+
const { store, cache, stats } = materializeIntegrationOps(integrationOps, this.integrationCache, tailHash);
|
|
6750
|
+
this.integrationCache = cache;
|
|
6751
|
+
if (laneOps !== undefined) {
|
|
6752
|
+
const overlay = overlayLaneOps(store, laneOps);
|
|
6753
|
+
this.store = overlay.store;
|
|
6754
|
+
this.materializationStats = {
|
|
6755
|
+
...stats,
|
|
6756
|
+
laneOpsReplayed: overlay.laneOpsReplayed
|
|
6757
|
+
};
|
|
6758
|
+
return;
|
|
6759
|
+
}
|
|
6760
|
+
this.store = store;
|
|
6761
|
+
this.materializationStats = stats;
|
|
6762
|
+
}
|
|
6763
|
+
restoreIntegrationOnlyStore() {
|
|
6764
|
+
const integrationOps = this.opLog.readAll();
|
|
6765
|
+
const tailHash = integrationOps[integrationOps.length - 1]?.hash;
|
|
6766
|
+
const { store, cache, stats } = materializeIntegrationOps(integrationOps, this.integrationCache, tailHash);
|
|
6767
|
+
this.integrationCache = cache;
|
|
6768
|
+
this.store = store;
|
|
6769
|
+
this.materializationStats = {
|
|
6770
|
+
...stats,
|
|
6771
|
+
laneOpsReplayed: 0
|
|
6772
|
+
};
|
|
6773
|
+
}
|
|
6774
|
+
rebuildStore(ops) {
|
|
6775
|
+
this.store = new EAVStore;
|
|
6776
|
+
for (const op of ops) {
|
|
6777
|
+
this.replayOp(op);
|
|
6778
|
+
}
|
|
6779
|
+
}
|
|
6780
|
+
syncIngestionLastOpHash() {
|
|
6781
|
+
if (this.ingestion) {
|
|
6782
|
+
this.ingestion.setLastOpHash(this.getActiveJournal().getLastOp()?.hash);
|
|
6783
|
+
}
|
|
6784
|
+
}
|
|
6785
|
+
stampLaneId(op) {
|
|
6786
|
+
if (!this.activeLaneId)
|
|
6787
|
+
return;
|
|
6788
|
+
op.vcs = { ...op.vcs, laneId: this.activeLaneId };
|
|
6789
|
+
}
|
|
6790
|
+
requireActiveLaneLog() {
|
|
6791
|
+
if (!this.activeLaneId || !this.activeLaneLog) {
|
|
6792
|
+
throw new Error("No active lane journal");
|
|
6793
|
+
}
|
|
6794
|
+
return this.activeLaneLog;
|
|
6795
|
+
}
|
|
6796
|
+
isIssueIntegrationOp(kind) {
|
|
6797
|
+
return ISSUE_INTEGRATION_KINDS.has(kind);
|
|
6798
|
+
}
|
|
6799
|
+
async applyOp(op, opts) {
|
|
6800
|
+
const inLane = Boolean(this.activeLaneId);
|
|
6801
|
+
const forceIntegration = Boolean(opts?.allowIntegrationWrite) || inLane && this.isIssueIntegrationOp(op.kind);
|
|
6802
|
+
let opToApply = op;
|
|
6803
|
+
if (inLane && forceIntegration) {
|
|
6804
|
+
const intLast = this.opLog.getLastOp();
|
|
6805
|
+
if (intLast?.hash !== op.previousHash && isVcsOpKind(op.kind)) {
|
|
6806
|
+
opToApply = await createVcsOp(op.kind, {
|
|
6807
|
+
agentId: op.agentId,
|
|
6808
|
+
previousHash: intLast?.hash,
|
|
6809
|
+
vcs: op.vcs ?? {}
|
|
6810
|
+
});
|
|
6811
|
+
}
|
|
6812
|
+
}
|
|
6813
|
+
if (inLane && !forceIntegration) {
|
|
6814
|
+
this.stampLaneId(opToApply);
|
|
6815
|
+
}
|
|
6816
|
+
const decomposed = decompose(opToApply);
|
|
5999
6817
|
if (decomposed.deleteFacts.length > 0) {
|
|
6000
6818
|
this.store.deleteFacts(decomposed.deleteFacts);
|
|
6001
6819
|
}
|
|
@@ -6008,13 +6826,55 @@ class TrellisVcsEngine {
|
|
|
6008
6826
|
if (decomposed.addLinks.length > 0) {
|
|
6009
6827
|
this.store.addLinks(decomposed.addLinks);
|
|
6010
6828
|
}
|
|
6011
|
-
|
|
6012
|
-
|
|
6829
|
+
if (inLane && !forceIntegration) {
|
|
6830
|
+
const laneLog = this.requireActiveLaneLog();
|
|
6831
|
+
laneLog.append(opToApply);
|
|
6832
|
+
updateLaneHead(this.trellisDir(), this.activeLaneId, opToApply.hash);
|
|
6833
|
+
if (opToApply.kind !== "vcs:checkpointCreate" && this.checkpointThreshold > 0) {
|
|
6834
|
+
this.checkpointOpCount++;
|
|
6835
|
+
if (this.checkpointOpCount >= this.checkpointThreshold) {
|
|
6836
|
+
this._pendingAutoCheckpoint = true;
|
|
6837
|
+
}
|
|
6838
|
+
}
|
|
6839
|
+
return;
|
|
6840
|
+
}
|
|
6841
|
+
this.opLog.append(opToApply);
|
|
6842
|
+
if (inLane && forceIntegration) {
|
|
6843
|
+
const meta = this.getLaneMeta(this.activeLaneId);
|
|
6844
|
+
this.refreshMaterializedStore(this.opLog.readAll(), this.activeLaneLog.readAll(), meta);
|
|
6845
|
+
} else if (!inLane) {
|
|
6846
|
+
if (!this.integrationCache) {
|
|
6847
|
+
this.integrationCache = {
|
|
6848
|
+
tailHash: opToApply.hash,
|
|
6849
|
+
store: this.store
|
|
6850
|
+
};
|
|
6851
|
+
} else {
|
|
6852
|
+
this.integrationCache.tailHash = opToApply.hash;
|
|
6853
|
+
}
|
|
6854
|
+
}
|
|
6855
|
+
if (opToApply.kind !== "vcs:checkpointCreate" && this.checkpointThreshold > 0) {
|
|
6013
6856
|
this.checkpointOpCount++;
|
|
6014
6857
|
if (this.checkpointOpCount >= this.checkpointThreshold) {
|
|
6015
6858
|
this._pendingAutoCheckpoint = true;
|
|
6016
6859
|
}
|
|
6017
6860
|
}
|
|
6861
|
+
if (!opts?.skipBranchAdvance && shouldAdvanceBranchHead(opToApply.kind)) {
|
|
6862
|
+
await this.appendBranchAdvance(opToApply.hash);
|
|
6863
|
+
}
|
|
6864
|
+
}
|
|
6865
|
+
async appendBranchAdvance(targetOpHash) {
|
|
6866
|
+
const advanceOp = await createVcsOp("vcs:branchAdvance", {
|
|
6867
|
+
agentId: this.agentId,
|
|
6868
|
+
previousHash: this.opLog.getLastOp()?.hash,
|
|
6869
|
+
vcs: {
|
|
6870
|
+
branchName: this.currentBranch,
|
|
6871
|
+
targetOpHash
|
|
6872
|
+
}
|
|
6873
|
+
});
|
|
6874
|
+
await this.applyOp(advanceOp, {
|
|
6875
|
+
skipBranchAdvance: true,
|
|
6876
|
+
allowIntegrationWrite: true
|
|
6877
|
+
});
|
|
6018
6878
|
}
|
|
6019
6879
|
async flushAutoCheckpoint() {
|
|
6020
6880
|
if (this._pendingAutoCheckpoint) {
|
|
@@ -6025,6 +6885,17 @@ class TrellisVcsEngine {
|
|
|
6025
6885
|
loadCurrentBranch() {
|
|
6026
6886
|
const state = loadBranchState(this.config.rootPath);
|
|
6027
6887
|
this.currentBranch = state.currentBranch;
|
|
6888
|
+
this.activeLaneId = state.activeLaneId;
|
|
6889
|
+
this.activeLaneLog = null;
|
|
6890
|
+
if (this.activeLaneId) {
|
|
6891
|
+
const meta = loadLaneMeta(this.trellisDir(), this.activeLaneId);
|
|
6892
|
+
if (meta && meta.status === "active") {
|
|
6893
|
+
this.activeLaneLog = new LaneOpLog(laneDir(this.trellisDir(), this.activeLaneId));
|
|
6894
|
+
this.activeLaneLog.load();
|
|
6895
|
+
} else {
|
|
6896
|
+
this.activeLaneId = undefined;
|
|
6897
|
+
}
|
|
6898
|
+
}
|
|
6028
6899
|
}
|
|
6029
6900
|
replayOp(op) {
|
|
6030
6901
|
const decomposed = decompose(op);
|
|
@@ -6042,7 +6913,7 @@ class TrellisVcsEngine {
|
|
|
6042
6913
|
}
|
|
6043
6914
|
}
|
|
6044
6915
|
}
|
|
6045
|
-
var TRELLIS_GITIGNORE_ENTRY = ".trellis/";
|
|
6916
|
+
var TRELLIS_GITIGNORE_ENTRY = ".trellis/", ISSUE_INTEGRATION_KINDS;
|
|
6046
6917
|
var init_engine = __esm(() => {
|
|
6047
6918
|
init_eav_store();
|
|
6048
6919
|
init_fs_watcher();
|
|
@@ -6063,6 +6934,21 @@ var init_engine = __esm(() => {
|
|
|
6063
6934
|
init_infer();
|
|
6064
6935
|
init_profile();
|
|
6065
6936
|
init_write();
|
|
6937
|
+
init_op_log();
|
|
6938
|
+
init_lane();
|
|
6939
|
+
init_lane_promote();
|
|
6940
|
+
init_lane_materialize();
|
|
6941
|
+
ISSUE_INTEGRATION_KINDS = new Set([
|
|
6942
|
+
"vcs:issueCreate",
|
|
6943
|
+
"vcs:issueStart",
|
|
6944
|
+
"vcs:issuePause",
|
|
6945
|
+
"vcs:issueResume",
|
|
6946
|
+
"vcs:issueClose",
|
|
6947
|
+
"vcs:issueReopen",
|
|
6948
|
+
"vcs:criterionUpdate",
|
|
6949
|
+
"vcs:issueBlock",
|
|
6950
|
+
"vcs:issueUnblock"
|
|
6951
|
+
]);
|
|
6066
6952
|
});
|
|
6067
6953
|
|
|
6068
|
-
export { FileWatcher, init_fs_watcher, Ingestion, init_ingestion, inferProjectContext, init_infer, loadProfile, saveProfile, hasProfile, promptForProfile, updateProfile, init_profile, writeAgentScaffold, writeIdeScaffold, init_write, TrellisVcsEngine, init_engine };
|
|
6954
|
+
export { FileWatcher, init_fs_watcher, Ingestion, init_ingestion, inferProjectContext, init_infer, loadProfile, saveProfile, hasProfile, promptForProfile, updateProfile, init_profile, writeAgentScaffold, writeIdeScaffold, init_write, formatPromoteExplain, init_lane_promote, TrellisVcsEngine, init_engine };
|