trellis 3.1.31 → 3.1.34
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-r5064492.js → index-nq520y6k.js} +7 -3
- package/dist/{index-v9b4hqa7.js → index-nzb3am4f.js} +4 -1
- package/dist/{index-8f2z3b0h.js → index-rv1p47gp.js} +996 -172
- package/dist/{index-1tv9sbwp.js → index-w5wccer3.js} +1 -1
- package/dist/{index-p3nnc7ac.js → index-xhcp6xrn.js} +462 -31
- 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-8qbz3mrn.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
|
@@ -7,8 +7,9 @@ import {
|
|
|
7
7
|
fileEntityId,
|
|
8
8
|
init_ops,
|
|
9
9
|
init_types,
|
|
10
|
-
issueEntityId
|
|
11
|
-
|
|
10
|
+
issueEntityId,
|
|
11
|
+
laneEntityId
|
|
12
|
+
} from "./index-nzb3am4f.js";
|
|
12
13
|
import {
|
|
13
14
|
__esm,
|
|
14
15
|
__require
|
|
@@ -16,6 +17,22 @@ import {
|
|
|
16
17
|
|
|
17
18
|
// src/vcs/decompose.ts
|
|
18
19
|
import { dirname } from "path";
|
|
20
|
+
function pickFacts(input) {
|
|
21
|
+
if (!Array.isArray(input))
|
|
22
|
+
return [];
|
|
23
|
+
return input.filter((item) => {
|
|
24
|
+
const fact = item;
|
|
25
|
+
return typeof fact.e === "string" && typeof fact.a === "string" && (typeof fact.v === "string" || typeof fact.v === "number" || typeof fact.v === "boolean");
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function pickLinks(input) {
|
|
29
|
+
if (!Array.isArray(input))
|
|
30
|
+
return [];
|
|
31
|
+
return input.filter((item) => {
|
|
32
|
+
const link = item;
|
|
33
|
+
return typeof link.e1 === "string" && typeof link.a === "string" && typeof link.e2 === "string";
|
|
34
|
+
});
|
|
35
|
+
}
|
|
19
36
|
function decompose(op) {
|
|
20
37
|
const result = {
|
|
21
38
|
addFacts: [],
|
|
@@ -230,6 +247,20 @@ function decompose(op) {
|
|
|
230
247
|
v: vcs.issueDescription
|
|
231
248
|
});
|
|
232
249
|
}
|
|
250
|
+
if (vcs.oldParentIssueId) {
|
|
251
|
+
result.deleteLinks.push({
|
|
252
|
+
e1: eid,
|
|
253
|
+
a: "childOf",
|
|
254
|
+
e2: issueEntityId(vcs.oldParentIssueId)
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
if (vcs.parentIssueId) {
|
|
258
|
+
result.addLinks.push({
|
|
259
|
+
e1: eid,
|
|
260
|
+
a: "childOf",
|
|
261
|
+
e2: issueEntityId(vcs.parentIssueId)
|
|
262
|
+
});
|
|
263
|
+
}
|
|
233
264
|
break;
|
|
234
265
|
}
|
|
235
266
|
case "vcs:issueStart": {
|
|
@@ -384,6 +415,102 @@ function decompose(op) {
|
|
|
384
415
|
}
|
|
385
416
|
break;
|
|
386
417
|
}
|
|
418
|
+
case "vcs:laneCreate": {
|
|
419
|
+
if (!vcs.laneId)
|
|
420
|
+
break;
|
|
421
|
+
const lid = laneEntityId(vcs.laneId);
|
|
422
|
+
result.addFacts.push({ e: lid, a: "type", v: "AgentLane" }, { e: lid, a: "status", v: "active" }, { e: lid, a: "createdAt", v: op.timestamp }, { e: lid, a: "createdBy", v: op.agentId });
|
|
423
|
+
if (vcs.baseBranch) {
|
|
424
|
+
result.addFacts.push({ e: lid, a: "baseBranch", v: vcs.baseBranch });
|
|
425
|
+
}
|
|
426
|
+
if (vcs.baseOpHash) {
|
|
427
|
+
result.addFacts.push({ e: lid, a: "baseOpHash", v: vcs.baseOpHash });
|
|
428
|
+
}
|
|
429
|
+
if (vcs.targetBranch) {
|
|
430
|
+
result.addFacts.push({ e: lid, a: "targetBranch", v: vcs.targetBranch });
|
|
431
|
+
}
|
|
432
|
+
if (vcs.baseOpHash) {
|
|
433
|
+
result.addFacts.push({ e: lid, a: "headOpHash", v: vcs.baseOpHash });
|
|
434
|
+
}
|
|
435
|
+
if (vcs.issueId) {
|
|
436
|
+
result.addFacts.push({ e: lid, a: "issueId", v: vcs.issueId });
|
|
437
|
+
}
|
|
438
|
+
if (vcs.sessionId) {
|
|
439
|
+
result.addFacts.push({ e: lid, a: "sessionId", v: vcs.sessionId });
|
|
440
|
+
}
|
|
441
|
+
if (vcs.parentLaneId) {
|
|
442
|
+
result.addFacts.push({ e: lid, a: "parentLaneId", v: vcs.parentLaneId });
|
|
443
|
+
result.addLinks.push({
|
|
444
|
+
e1: lid,
|
|
445
|
+
a: "forkedFrom",
|
|
446
|
+
e2: laneEntityId(vcs.parentLaneId)
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
if (vcs.forkKind) {
|
|
450
|
+
result.addFacts.push({ e: lid, a: "forkKind", v: vcs.forkKind });
|
|
451
|
+
}
|
|
452
|
+
if (vcs.virtualBaseOpHash) {
|
|
453
|
+
result.addFacts.push({
|
|
454
|
+
e: lid,
|
|
455
|
+
a: "virtualBaseOpHash",
|
|
456
|
+
v: vcs.virtualBaseOpHash
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
case "vcs:laneDrop": {
|
|
462
|
+
if (!vcs.laneId)
|
|
463
|
+
break;
|
|
464
|
+
const lid = laneEntityId(vcs.laneId);
|
|
465
|
+
if (vcs.laneStatus) {
|
|
466
|
+
result.deleteFacts.push({ e: lid, a: "status", v: "active" });
|
|
467
|
+
result.addFacts.push({ e: lid, a: "status", v: vcs.laneStatus });
|
|
468
|
+
}
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
case "vcs:lanePromoteStart": {
|
|
472
|
+
if (!vcs.laneId)
|
|
473
|
+
break;
|
|
474
|
+
const lid = laneEntityId(vcs.laneId);
|
|
475
|
+
result.deleteFacts.push({ e: lid, a: "status", v: "active" });
|
|
476
|
+
result.addFacts.push({ e: lid, a: "status", v: "promoting" });
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
case "vcs:lanePromoteComplete": {
|
|
480
|
+
if (!vcs.laneId)
|
|
481
|
+
break;
|
|
482
|
+
const lid = laneEntityId(vcs.laneId);
|
|
483
|
+
result.deleteFacts.push({ e: lid, a: "status", v: "promoting" });
|
|
484
|
+
result.addFacts.push({ e: lid, a: "status", v: "promoted" });
|
|
485
|
+
if (vcs.targetBranch) {
|
|
486
|
+
result.addFacts.push({ e: lid, a: "promotedToBranch", v: vcs.targetBranch });
|
|
487
|
+
}
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
case "vcs:lanePromoteAbort": {
|
|
491
|
+
if (!vcs.laneId)
|
|
492
|
+
break;
|
|
493
|
+
const lid = laneEntityId(vcs.laneId);
|
|
494
|
+
result.deleteFacts.push({ e: lid, a: "status", v: "promoting" });
|
|
495
|
+
result.addFacts.push({ e: lid, a: "status", v: "active" });
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
case "vcs:storeAssert": {
|
|
499
|
+
result.addFacts.push(...pickFacts(vcs.facts));
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
case "vcs:storeRetract": {
|
|
503
|
+
result.deleteFacts.push(...pickFacts(vcs.facts));
|
|
504
|
+
break;
|
|
505
|
+
}
|
|
506
|
+
case "vcs:storeLink": {
|
|
507
|
+
result.addLinks.push(...pickLinks(vcs.links));
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
case "vcs:storeUnlink": {
|
|
511
|
+
result.deleteLinks.push(...pickLinks(vcs.links));
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
387
514
|
}
|
|
388
515
|
return result;
|
|
389
516
|
}
|
|
@@ -474,6 +601,13 @@ var init_blob_store = () => {};
|
|
|
474
601
|
// src/vcs/branch.ts
|
|
475
602
|
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
476
603
|
import { join as join2 } from "path";
|
|
604
|
+
function shouldAdvanceBranchHead(kind) {
|
|
605
|
+
return !BRANCH_ADVANCE_SKIP_KINDS.has(kind);
|
|
606
|
+
}
|
|
607
|
+
function getBranchHeadOpHash(ctx, branchName) {
|
|
608
|
+
const facts = ctx.store.getFactsByEntity(`branch:${branchName}`).filter((f) => f.a === "headOpHash");
|
|
609
|
+
return facts[facts.length - 1]?.v;
|
|
610
|
+
}
|
|
477
611
|
async function createBranch(ctx, name, currentBranch) {
|
|
478
612
|
const existing = ctx.store.getFactsByAttribute("type").filter((f) => f.v === "Branch" && f.e === `branch:${name}`);
|
|
479
613
|
if (existing.length > 0) {
|
|
@@ -488,7 +622,7 @@ async function createBranch(ctx, name, currentBranch) {
|
|
|
488
622
|
targetOpHash: ctx.getLastOp()?.hash
|
|
489
623
|
}
|
|
490
624
|
});
|
|
491
|
-
ctx.applyOp(op);
|
|
625
|
+
await ctx.applyOp(op);
|
|
492
626
|
return op;
|
|
493
627
|
}
|
|
494
628
|
function switchBranch(ctx, name) {
|
|
@@ -523,7 +657,7 @@ async function deleteBranch(ctx, name, currentBranch) {
|
|
|
523
657
|
previousHash: ctx.getLastOp()?.hash,
|
|
524
658
|
vcs: { branchName: name }
|
|
525
659
|
});
|
|
526
|
-
ctx.applyOp(op);
|
|
660
|
+
await ctx.applyOp(op);
|
|
527
661
|
return op;
|
|
528
662
|
}
|
|
529
663
|
function saveBranchState(rootPath, state) {
|
|
@@ -537,14 +671,24 @@ function loadBranchState(rootPath) {
|
|
|
537
671
|
const raw = readFileSync2(statePath, "utf-8");
|
|
538
672
|
const state = JSON.parse(raw);
|
|
539
673
|
if (state.currentBranch) {
|
|
540
|
-
return {
|
|
674
|
+
return {
|
|
675
|
+
currentBranch: state.currentBranch,
|
|
676
|
+
activeLaneId: state.activeLaneId
|
|
677
|
+
};
|
|
541
678
|
}
|
|
542
679
|
} catch {}
|
|
543
680
|
}
|
|
544
681
|
return { currentBranch: "main" };
|
|
545
682
|
}
|
|
683
|
+
var BRANCH_ADVANCE_SKIP_KINDS;
|
|
546
684
|
var init_branch = __esm(() => {
|
|
547
685
|
init_ops();
|
|
686
|
+
BRANCH_ADVANCE_SKIP_KINDS = new Set([
|
|
687
|
+
"vcs:branchAdvance",
|
|
688
|
+
"vcs:branchCreate",
|
|
689
|
+
"vcs:branchDelete",
|
|
690
|
+
"vcs:checkpointCreate"
|
|
691
|
+
]);
|
|
548
692
|
});
|
|
549
693
|
|
|
550
694
|
// src/vcs/milestone.ts
|
|
@@ -583,7 +727,7 @@ async function createMilestone(ctx, message, opts) {
|
|
|
583
727
|
toOpHash
|
|
584
728
|
}
|
|
585
729
|
});
|
|
586
|
-
ctx.applyOp(op);
|
|
730
|
+
await ctx.applyOp(op);
|
|
587
731
|
for (const file of affectedFiles) {
|
|
588
732
|
ctx.store.addFacts([{ e: milestoneId, a: "affectsFile", v: file }]);
|
|
589
733
|
}
|
|
@@ -617,7 +761,7 @@ async function createCheckpoint(ctx, trigger = "manual") {
|
|
|
617
761
|
previousHash: ctx.getLastOp()?.hash,
|
|
618
762
|
vcs: { trigger }
|
|
619
763
|
});
|
|
620
|
-
ctx.applyOp(op);
|
|
764
|
+
await ctx.applyOp(op);
|
|
621
765
|
return op;
|
|
622
766
|
}
|
|
623
767
|
function listCheckpoints(ctx) {
|
|
@@ -1294,7 +1438,7 @@ async function createIssue(ctx, rootPath, title, opts) {
|
|
|
1294
1438
|
parentIssueId: opts?.parentId
|
|
1295
1439
|
}
|
|
1296
1440
|
});
|
|
1297
|
-
ctx.applyOp(op);
|
|
1441
|
+
await ctx.applyOp(op);
|
|
1298
1442
|
if (opts?.criteria) {
|
|
1299
1443
|
for (let i = 0;i < opts.criteria.length; i++) {
|
|
1300
1444
|
await addCriterion(ctx, id, opts.criteria[i].description, opts.criteria[i].command);
|
|
@@ -1303,21 +1447,50 @@ async function createIssue(ctx, rootPath, title, opts) {
|
|
|
1303
1447
|
return op;
|
|
1304
1448
|
}
|
|
1305
1449
|
async function updateIssue(ctx, id, updates) {
|
|
1450
|
+
const issue = getIssue(ctx, id);
|
|
1451
|
+
if (!issue) {
|
|
1452
|
+
throw new Error(`Issue ${id} not found.`);
|
|
1453
|
+
}
|
|
1454
|
+
const vcs = { issueId: id };
|
|
1455
|
+
if (updates.title !== undefined)
|
|
1456
|
+
vcs.issueTitle = updates.title;
|
|
1457
|
+
if (updates.description !== undefined)
|
|
1458
|
+
vcs.issueDescription = updates.description;
|
|
1459
|
+
if (updates.status !== undefined) {
|
|
1460
|
+
vcs.oldIssueStatus = getIssueFact(ctx, issueEntityId(id), "status");
|
|
1461
|
+
vcs.issueStatus = updates.status;
|
|
1462
|
+
}
|
|
1463
|
+
if (updates.priority !== undefined)
|
|
1464
|
+
vcs.issuePriority = updates.priority;
|
|
1465
|
+
if (updates.labels !== undefined)
|
|
1466
|
+
vcs.issueLabels = updates.labels;
|
|
1467
|
+
if (updates.assignee !== undefined)
|
|
1468
|
+
vcs.issueAssignee = updates.assignee;
|
|
1469
|
+
if (updates.parentId !== undefined) {
|
|
1470
|
+
const newParent = updates.parentId;
|
|
1471
|
+
if (newParent === id) {
|
|
1472
|
+
throw new Error(`Issue ${id} cannot be its own parent.`);
|
|
1473
|
+
}
|
|
1474
|
+
if (newParent) {
|
|
1475
|
+
const parent = getIssue(ctx, newParent);
|
|
1476
|
+
if (!parent) {
|
|
1477
|
+
throw new Error(`Parent issue ${newParent} not found.`);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
const currentParent = issue.parentId;
|
|
1481
|
+
if (newParent !== currentParent) {
|
|
1482
|
+
if (currentParent)
|
|
1483
|
+
vcs.oldParentIssueId = currentParent;
|
|
1484
|
+
if (newParent)
|
|
1485
|
+
vcs.parentIssueId = newParent;
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1306
1488
|
const op = await createVcsOp("vcs:issueUpdate", {
|
|
1307
1489
|
agentId: ctx.agentId,
|
|
1308
1490
|
previousHash: ctx.getLastOp()?.hash,
|
|
1309
|
-
vcs
|
|
1310
|
-
issueId: id,
|
|
1311
|
-
issueTitle: updates.title,
|
|
1312
|
-
issueDescription: updates.description,
|
|
1313
|
-
oldIssueStatus: updates.status ? getIssueFact(ctx, issueEntityId(id), "status") : undefined,
|
|
1314
|
-
issueStatus: updates.status,
|
|
1315
|
-
issuePriority: updates.priority,
|
|
1316
|
-
issueLabels: updates.labels,
|
|
1317
|
-
issueAssignee: updates.assignee
|
|
1318
|
-
}
|
|
1491
|
+
vcs
|
|
1319
1492
|
});
|
|
1320
|
-
ctx.applyOp(op);
|
|
1493
|
+
await ctx.applyOp(op);
|
|
1321
1494
|
return op;
|
|
1322
1495
|
}
|
|
1323
1496
|
async function startIssue(ctx, id, branchName) {
|
|
@@ -1339,7 +1512,7 @@ async function startIssue(ctx, id, branchName) {
|
|
|
1339
1512
|
branchName
|
|
1340
1513
|
}
|
|
1341
1514
|
});
|
|
1342
|
-
ctx.applyOp(op);
|
|
1515
|
+
await ctx.applyOp(op);
|
|
1343
1516
|
return op;
|
|
1344
1517
|
}
|
|
1345
1518
|
async function pauseIssue(ctx, id, note) {
|
|
@@ -1360,7 +1533,7 @@ async function pauseIssue(ctx, id, note) {
|
|
|
1360
1533
|
pauseNote: note.trim()
|
|
1361
1534
|
}
|
|
1362
1535
|
});
|
|
1363
|
-
ctx.applyOp(op);
|
|
1536
|
+
await ctx.applyOp(op);
|
|
1364
1537
|
return op;
|
|
1365
1538
|
}
|
|
1366
1539
|
async function resumeIssue(ctx, id) {
|
|
@@ -1374,7 +1547,7 @@ async function resumeIssue(ctx, id) {
|
|
|
1374
1547
|
previousHash: ctx.getLastOp()?.hash,
|
|
1375
1548
|
vcs: { issueId: id, oldIssueStatus: status }
|
|
1376
1549
|
});
|
|
1377
|
-
ctx.applyOp(op);
|
|
1550
|
+
await ctx.applyOp(op);
|
|
1378
1551
|
return op;
|
|
1379
1552
|
}
|
|
1380
1553
|
async function closeIssue(ctx, id, opts) {
|
|
@@ -1406,7 +1579,7 @@ async function closeIssue(ctx, id, opts) {
|
|
|
1406
1579
|
previousHash: ctx.getLastOp()?.hash,
|
|
1407
1580
|
vcs: { issueId: id, oldIssueStatus: status }
|
|
1408
1581
|
});
|
|
1409
|
-
ctx.applyOp(op);
|
|
1582
|
+
await ctx.applyOp(op);
|
|
1410
1583
|
if (startedAt) {
|
|
1411
1584
|
const durationMs = Date.now() - new Date(startedAt).getTime();
|
|
1412
1585
|
ctx.store.addFacts([{ e: eid, a: "durationMs", v: durationMs }]);
|
|
@@ -1428,7 +1601,7 @@ async function triageIssue(ctx, id) {
|
|
|
1428
1601
|
issueStatus: "queue"
|
|
1429
1602
|
}
|
|
1430
1603
|
});
|
|
1431
|
-
ctx.applyOp(op);
|
|
1604
|
+
await ctx.applyOp(op);
|
|
1432
1605
|
return op;
|
|
1433
1606
|
}
|
|
1434
1607
|
async function reopenIssue(ctx, id) {
|
|
@@ -1442,7 +1615,7 @@ async function reopenIssue(ctx, id) {
|
|
|
1442
1615
|
previousHash: ctx.getLastOp()?.hash,
|
|
1443
1616
|
vcs: { issueId: id, oldIssueStatus: status }
|
|
1444
1617
|
});
|
|
1445
|
-
ctx.applyOp(op);
|
|
1618
|
+
await ctx.applyOp(op);
|
|
1446
1619
|
return op;
|
|
1447
1620
|
}
|
|
1448
1621
|
async function assignIssue(ctx, id, agentId) {
|
|
@@ -1465,7 +1638,7 @@ async function blockIssue(ctx, id, blockedById) {
|
|
|
1465
1638
|
previousHash: ctx.getLastOp()?.hash,
|
|
1466
1639
|
vcs: { issueId: id, blockedByIssueId: blockedById }
|
|
1467
1640
|
});
|
|
1468
|
-
ctx.applyOp(op);
|
|
1641
|
+
await ctx.applyOp(op);
|
|
1469
1642
|
return op;
|
|
1470
1643
|
}
|
|
1471
1644
|
async function unblockIssue(ctx, id, blockedById) {
|
|
@@ -1474,7 +1647,7 @@ async function unblockIssue(ctx, id, blockedById) {
|
|
|
1474
1647
|
previousHash: ctx.getLastOp()?.hash,
|
|
1475
1648
|
vcs: { issueId: id, blockedByIssueId: blockedById }
|
|
1476
1649
|
});
|
|
1477
|
-
ctx.applyOp(op);
|
|
1650
|
+
await ctx.applyOp(op);
|
|
1478
1651
|
return op;
|
|
1479
1652
|
}
|
|
1480
1653
|
async function addCriterion(ctx, issueId, description, command) {
|
|
@@ -1491,7 +1664,7 @@ async function addCriterion(ctx, issueId, description, command) {
|
|
|
1491
1664
|
criterionCommand: command
|
|
1492
1665
|
}
|
|
1493
1666
|
});
|
|
1494
|
-
ctx.applyOp(op);
|
|
1667
|
+
await ctx.applyOp(op);
|
|
1495
1668
|
return op;
|
|
1496
1669
|
}
|
|
1497
1670
|
async function setCriterionStatus(ctx, issueId, criterionIndex, status) {
|
|
@@ -1509,7 +1682,7 @@ async function setCriterionStatus(ctx, issueId, criterionIndex, status) {
|
|
|
1509
1682
|
criterionStatus: status
|
|
1510
1683
|
}
|
|
1511
1684
|
});
|
|
1512
|
-
ctx.applyOp(op);
|
|
1685
|
+
await ctx.applyOp(op);
|
|
1513
1686
|
return op;
|
|
1514
1687
|
}
|
|
1515
1688
|
async function runCriteria(ctx, issueId, rootPath) {
|
|
@@ -1552,7 +1725,7 @@ async function runCriteria(ctx, issueId, rootPath) {
|
|
|
1552
1725
|
criterionOutput: output.slice(0, 4096)
|
|
1553
1726
|
}
|
|
1554
1727
|
});
|
|
1555
|
-
ctx.applyOp(updateOp);
|
|
1728
|
+
await ctx.applyOp(updateOp);
|
|
1556
1729
|
results.push({
|
|
1557
1730
|
id: c.id,
|
|
1558
1731
|
description: c.description,
|
|
@@ -1625,4 +1798,262 @@ var init_issue = __esm(() => {
|
|
|
1625
1798
|
execAsync = promisify(exec);
|
|
1626
1799
|
});
|
|
1627
1800
|
|
|
1628
|
-
|
|
1801
|
+
// src/vcs/op-log.ts
|
|
1802
|
+
import {
|
|
1803
|
+
existsSync as existsSync4,
|
|
1804
|
+
mkdirSync as mkdirSync3,
|
|
1805
|
+
readFileSync as readFileSync4,
|
|
1806
|
+
writeFileSync as writeFileSync4,
|
|
1807
|
+
copyFileSync,
|
|
1808
|
+
openSync as openSync2,
|
|
1809
|
+
closeSync as closeSync2,
|
|
1810
|
+
unlinkSync as unlinkSync2,
|
|
1811
|
+
renameSync
|
|
1812
|
+
} from "fs";
|
|
1813
|
+
import { dirname as dirname3 } from "path";
|
|
1814
|
+
function lockTimeoutMs() {
|
|
1815
|
+
const raw = process.env.TRELLIS_OPLOG_LOCK_MS;
|
|
1816
|
+
if (!raw)
|
|
1817
|
+
return 5000;
|
|
1818
|
+
const parsed = Number(raw);
|
|
1819
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 5000;
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
class JsonOpLog {
|
|
1823
|
+
ops = [];
|
|
1824
|
+
filePath;
|
|
1825
|
+
lockPath;
|
|
1826
|
+
constructor(filePath) {
|
|
1827
|
+
this.filePath = filePath;
|
|
1828
|
+
this.lockPath = `${filePath}.lock`;
|
|
1829
|
+
}
|
|
1830
|
+
get path() {
|
|
1831
|
+
return this.filePath;
|
|
1832
|
+
}
|
|
1833
|
+
load() {
|
|
1834
|
+
if (existsSync4(this.filePath)) {
|
|
1835
|
+
const raw = readFileSync4(this.filePath, "utf-8");
|
|
1836
|
+
try {
|
|
1837
|
+
this.ops = JSON.parse(raw);
|
|
1838
|
+
} catch {
|
|
1839
|
+
const backupPath = this.filePath + ".bak";
|
|
1840
|
+
if (existsSync4(backupPath)) {
|
|
1841
|
+
const backupRaw = readFileSync4(backupPath, "utf-8");
|
|
1842
|
+
this.ops = JSON.parse(backupRaw);
|
|
1843
|
+
writeFileSync4(this.filePath, backupRaw);
|
|
1844
|
+
} else {
|
|
1845
|
+
throw new Error(`Corrupted ops log at ${this.filePath} and no backup found. Run \`trellis repair\` to attempt recovery.`);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
append(op) {
|
|
1851
|
+
this.withLock(() => {
|
|
1852
|
+
const diskOps = this.readOpsFromDisk();
|
|
1853
|
+
this.ops = diskOps;
|
|
1854
|
+
if (this.ops.some((existing) => existing.hash === op.hash)) {
|
|
1855
|
+
return;
|
|
1856
|
+
}
|
|
1857
|
+
this.ops.push(op);
|
|
1858
|
+
this.flush();
|
|
1859
|
+
});
|
|
1860
|
+
}
|
|
1861
|
+
readAll() {
|
|
1862
|
+
return [...this.ops];
|
|
1863
|
+
}
|
|
1864
|
+
getLastOp() {
|
|
1865
|
+
return this.ops.length > 0 ? this.ops[this.ops.length - 1] : undefined;
|
|
1866
|
+
}
|
|
1867
|
+
count() {
|
|
1868
|
+
return this.ops.length;
|
|
1869
|
+
}
|
|
1870
|
+
flush() {
|
|
1871
|
+
const dir = dirname3(this.filePath);
|
|
1872
|
+
if (!existsSync4(dir))
|
|
1873
|
+
mkdirSync3(dir, { recursive: true });
|
|
1874
|
+
if (existsSync4(this.filePath)) {
|
|
1875
|
+
const backupPath = this.filePath + ".bak";
|
|
1876
|
+
try {
|
|
1877
|
+
copyFileSync(this.filePath, backupPath);
|
|
1878
|
+
} catch {}
|
|
1879
|
+
}
|
|
1880
|
+
const tempPath = `${this.filePath}.tmp`;
|
|
1881
|
+
writeFileSync4(tempPath, JSON.stringify(this.ops, null, 2));
|
|
1882
|
+
renameSync(tempPath, this.filePath);
|
|
1883
|
+
}
|
|
1884
|
+
readOpsFromDisk() {
|
|
1885
|
+
if (!existsSync4(this.filePath)) {
|
|
1886
|
+
return [];
|
|
1887
|
+
}
|
|
1888
|
+
const raw = readFileSync4(this.filePath, "utf-8");
|
|
1889
|
+
try {
|
|
1890
|
+
const parsed = JSON.parse(raw);
|
|
1891
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
1892
|
+
} catch {
|
|
1893
|
+
const backupPath = this.filePath + ".bak";
|
|
1894
|
+
if (existsSync4(backupPath)) {
|
|
1895
|
+
const backupRaw = readFileSync4(backupPath, "utf-8");
|
|
1896
|
+
const parsedBackup = JSON.parse(backupRaw);
|
|
1897
|
+
writeFileSync4(this.filePath, backupRaw);
|
|
1898
|
+
return Array.isArray(parsedBackup) ? parsedBackup : [];
|
|
1899
|
+
}
|
|
1900
|
+
throw new Error(`Corrupted ops log at ${this.filePath} and no backup found. Run \`trellis repair\` to attempt recovery.`);
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
withLock(fn) {
|
|
1904
|
+
const dir = dirname3(this.filePath);
|
|
1905
|
+
if (!existsSync4(dir))
|
|
1906
|
+
mkdirSync3(dir, { recursive: true });
|
|
1907
|
+
const deadline = Date.now() + lockTimeoutMs();
|
|
1908
|
+
let lockFd;
|
|
1909
|
+
while (Date.now() < deadline) {
|
|
1910
|
+
try {
|
|
1911
|
+
lockFd = openSync2(this.lockPath, "wx");
|
|
1912
|
+
break;
|
|
1913
|
+
} catch (err) {
|
|
1914
|
+
if (err?.code !== "EEXIST") {
|
|
1915
|
+
throw err;
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
if (lockFd === undefined) {
|
|
1920
|
+
throw new Error(`Timed out waiting for ops log lock: ${this.lockPath}. Another Trellis process may be stalled.`);
|
|
1921
|
+
}
|
|
1922
|
+
try {
|
|
1923
|
+
fn();
|
|
1924
|
+
} finally {
|
|
1925
|
+
closeSync2(lockFd);
|
|
1926
|
+
try {
|
|
1927
|
+
unlinkSync2(this.lockPath);
|
|
1928
|
+
} catch {}
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
static repair(filePath) {
|
|
1932
|
+
if (!existsSync4(filePath)) {
|
|
1933
|
+
return { recovered: 0, lost: 0 };
|
|
1934
|
+
}
|
|
1935
|
+
const raw = readFileSync4(filePath, "utf-8");
|
|
1936
|
+
try {
|
|
1937
|
+
const ops = JSON.parse(raw);
|
|
1938
|
+
return { recovered: ops.length, lost: 0 };
|
|
1939
|
+
} catch {}
|
|
1940
|
+
const lastHash = raw.lastIndexOf('"hash": "trellis:op:');
|
|
1941
|
+
if (lastHash === -1) {
|
|
1942
|
+
const bakPath = filePath + ".bak";
|
|
1943
|
+
if (existsSync4(bakPath)) {
|
|
1944
|
+
const bakRaw = readFileSync4(bakPath, "utf-8");
|
|
1945
|
+
try {
|
|
1946
|
+
const ops = JSON.parse(bakRaw);
|
|
1947
|
+
writeFileSync4(filePath, bakRaw);
|
|
1948
|
+
return { recovered: ops.length, lost: 0 };
|
|
1949
|
+
} catch {}
|
|
1950
|
+
}
|
|
1951
|
+
writeFileSync4(filePath, "[]");
|
|
1952
|
+
return { recovered: 0, lost: -1 };
|
|
1953
|
+
}
|
|
1954
|
+
const endOfLine = raw.indexOf(`
|
|
1955
|
+
`, lastHash);
|
|
1956
|
+
const closingBrace = raw.indexOf(" }", endOfLine);
|
|
1957
|
+
if (closingBrace === -1) {
|
|
1958
|
+
writeFileSync4(filePath, "[]");
|
|
1959
|
+
return { recovered: 0, lost: -1 };
|
|
1960
|
+
}
|
|
1961
|
+
const fixed = raw.slice(0, closingBrace + 3) + `
|
|
1962
|
+
]`;
|
|
1963
|
+
try {
|
|
1964
|
+
const ops = JSON.parse(fixed);
|
|
1965
|
+
writeFileSync4(filePath + ".corrupted", raw);
|
|
1966
|
+
writeFileSync4(filePath, fixed);
|
|
1967
|
+
return { recovered: ops.length, lost: 0 };
|
|
1968
|
+
} catch {
|
|
1969
|
+
writeFileSync4(filePath + ".corrupted", raw);
|
|
1970
|
+
writeFileSync4(filePath, "[]");
|
|
1971
|
+
return { recovered: 0, lost: -1 };
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
var LaneOpLog;
|
|
1976
|
+
var init_op_log = __esm(() => {
|
|
1977
|
+
LaneOpLog = class LaneOpLog extends JsonOpLog {
|
|
1978
|
+
constructor(laneDir) {
|
|
1979
|
+
super(`${laneDir}/ops.json`);
|
|
1980
|
+
}
|
|
1981
|
+
};
|
|
1982
|
+
});
|
|
1983
|
+
|
|
1984
|
+
// src/vcs/lane.ts
|
|
1985
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync5, readdirSync } from "fs";
|
|
1986
|
+
import { join as join4 } from "path";
|
|
1987
|
+
import { randomUUID } from "crypto";
|
|
1988
|
+
function lanesRoot(trellisDir) {
|
|
1989
|
+
return join4(trellisDir, "lanes");
|
|
1990
|
+
}
|
|
1991
|
+
function laneDir(trellisDir, laneId) {
|
|
1992
|
+
return join4(lanesRoot(trellisDir), laneId);
|
|
1993
|
+
}
|
|
1994
|
+
function laneMetaPath(trellisDir, laneId) {
|
|
1995
|
+
return join4(laneDir(trellisDir, laneId), "meta.json");
|
|
1996
|
+
}
|
|
1997
|
+
function newLaneId() {
|
|
1998
|
+
return `lane-${randomUUID()}`;
|
|
1999
|
+
}
|
|
2000
|
+
function loadLaneMeta(trellisDir, laneId) {
|
|
2001
|
+
const path = laneMetaPath(trellisDir, laneId);
|
|
2002
|
+
if (!existsSync5(path))
|
|
2003
|
+
return;
|
|
2004
|
+
return JSON.parse(readFileSync5(path, "utf-8"));
|
|
2005
|
+
}
|
|
2006
|
+
function saveLaneMeta(trellisDir, meta) {
|
|
2007
|
+
const dir = laneDir(trellisDir, meta.id);
|
|
2008
|
+
if (!existsSync5(dir))
|
|
2009
|
+
mkdirSync4(dir, { recursive: true });
|
|
2010
|
+
writeFileSync5(laneMetaPath(trellisDir, meta.id), JSON.stringify(meta, null, 2) + `
|
|
2011
|
+
`);
|
|
2012
|
+
}
|
|
2013
|
+
function listLaneIds(trellisDir) {
|
|
2014
|
+
const root = lanesRoot(trellisDir);
|
|
2015
|
+
if (!existsSync5(root))
|
|
2016
|
+
return [];
|
|
2017
|
+
return readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory() && d.name.startsWith("lane-")).map((d) => d.name);
|
|
2018
|
+
}
|
|
2019
|
+
function resolveLaneHeadFromJournal(meta, laneOps) {
|
|
2020
|
+
return laneOps.at(-1)?.hash ?? meta.headOpHash ?? meta.baseOpHash;
|
|
2021
|
+
}
|
|
2022
|
+
function createLaneMeta(trellisDir, params) {
|
|
2023
|
+
const now = new Date().toISOString();
|
|
2024
|
+
const meta = {
|
|
2025
|
+
id: newLaneId(),
|
|
2026
|
+
status: "active",
|
|
2027
|
+
baseBranch: params.baseBranch,
|
|
2028
|
+
baseOpHash: params.baseOpHash,
|
|
2029
|
+
targetBranch: params.targetBranch ?? params.baseBranch,
|
|
2030
|
+
headOpHash: params.baseOpHash,
|
|
2031
|
+
agentId: params.agentId,
|
|
2032
|
+
issueId: params.issueId,
|
|
2033
|
+
sessionId: params.sessionId,
|
|
2034
|
+
parentLaneId: params.parentLaneId,
|
|
2035
|
+
forkKind: params.forkKind,
|
|
2036
|
+
forkedAt: params.forkedAt,
|
|
2037
|
+
virtualBaseOpHash: params.virtualBaseOpHash,
|
|
2038
|
+
worktreePath: params.worktreePath,
|
|
2039
|
+
leaseExpiresAt: params.leaseExpiresAt,
|
|
2040
|
+
createdAt: now,
|
|
2041
|
+
updatedAt: now
|
|
2042
|
+
};
|
|
2043
|
+
saveLaneMeta(trellisDir, meta);
|
|
2044
|
+
return meta;
|
|
2045
|
+
}
|
|
2046
|
+
function updateLaneHead(trellisDir, laneId, headOpHash) {
|
|
2047
|
+
const meta = loadLaneMeta(trellisDir, laneId);
|
|
2048
|
+
if (!meta)
|
|
2049
|
+
return;
|
|
2050
|
+
meta.headOpHash = headOpHash;
|
|
2051
|
+
meta.updatedAt = new Date().toISOString();
|
|
2052
|
+
saveLaneMeta(trellisDir, meta);
|
|
2053
|
+
}
|
|
2054
|
+
function listLaneMetas(trellisDir) {
|
|
2055
|
+
return listLaneIds(trellisDir).map((id) => loadLaneMeta(trellisDir, id)).filter((m) => m !== undefined);
|
|
2056
|
+
}
|
|
2057
|
+
var init_lane = () => {};
|
|
2058
|
+
|
|
2059
|
+
export { decompose, init_decompose, BlobStore, init_blob_store, shouldAdvanceBranchHead, getBranchHeadOpHash, createBranch, switchBranch, listBranches, deleteBranch, saveBranchState, loadBranchState, init_branch, createMilestone, listMilestones, init_milestone, createCheckpoint, listCheckpoints, init_checkpoint, diffFileStates, buildFileStateAtOp, diffOpRange, generateUnifiedDiff, myersDiff, init_diff, threeWayMerge, threeWayTextMerge, init_merge, createIssue, updateIssue, startIssue, pauseIssue, resumeIssue, closeIssue, triageIssue, reopenIssue, assignIssue, blockIssue, unblockIssue, addCriterion, setCriterionStatus, runCriteria, listIssues, getIssue, getActiveIssues, checkCompletionReadiness, init_issue, JsonOpLog, LaneOpLog, init_op_log, lanesRoot, laneDir, laneMetaPath, newLaneId, loadLaneMeta, saveLaneMeta, listLaneIds, resolveLaneHeadFromJournal, createLaneMeta, updateLaneHead, listLaneMetas, init_lane };
|