@abelxiaoxing/cadence 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -4
- package/config/.env.example +6 -0
- package/config/plan-draft.example.json +3 -0
- package/config/plan-draft.multiple-tasks.example.json +30 -0
- package/package.json +1 -1
- package/prompts/abel-design.md +33 -3
- package/prompts/abel-implement.md +36 -4
- package/src/apply-transaction.ts +28 -8
- package/src/build-windows-job.mjs +95 -0
- package/src/candidate-workspace.ts +6 -0
- package/src/change-verification.ts +764 -67
- package/src/contracts.ts +8 -0
- package/src/delivery-compiler.ts +452 -9
- package/src/design-control.ts +2 -2
- package/src/design-diagnostics.ts +6 -4
- package/src/durable-contracts.ts +21 -3
- package/src/durable-workflow.ts +55 -40
- package/src/execution-profile.ts +28 -2
- package/src/execution-retention.ts +77 -0
- package/src/implement-continuation.ts +559 -0
- package/src/implement-graph.ts +114 -0
- package/src/implement-plan.ts +2 -0
- package/src/index.ts +151 -1
- package/src/isolation-backend.ts +2 -1
- package/src/operator-cli.mjs +664 -104
- package/src/operator-tools.ts +7 -1
- package/src/package-state.ts +11 -0
- package/src/package-verification.ts +66 -18
- package/src/package-workflow.ts +6 -0
- package/src/phase-execution.ts +18 -7
- package/src/plan-draft-summary.ts +385 -7
- package/src/plan-draft.ts +9 -0
- package/src/remove-path.ts +32 -0
- package/src/subagent-activity.ts +3 -1
- package/src/verification-capability.ts +18 -6
- package/src/verification-environment-io.ts +123 -14
- package/src/verification-environment.ts +50 -3
- package/src/windows-job-backend.ts +419 -0
- package/src/windows-job.c +149 -0
- package/src/workflow-policy.ts +296 -5
- package/src/workflow-recovery-policy.ts +2 -0
- package/src/workflow-state-machine.ts +314 -80
- package/src/workflow-status.ts +251 -59
- package/src/workspace-io-entry.mjs +2 -2
- package/src/workspace-io-worker.mjs +207 -110
package/src/index.ts
CHANGED
|
@@ -48,6 +48,11 @@ import {
|
|
|
48
48
|
DesignFinalizationError,
|
|
49
49
|
validateDesignControlRequest,
|
|
50
50
|
} from "./design-control.ts";
|
|
51
|
+
import {
|
|
52
|
+
ImplementContinuationDriver,
|
|
53
|
+
implementChangeFromInvocation,
|
|
54
|
+
implementPromptBindsChange,
|
|
55
|
+
} from "./implement-continuation.ts";
|
|
51
56
|
import { canonicalJson } from "./implement-graph.ts";
|
|
52
57
|
import { PACKET_ACTIONS, PacketRuntime } from "./packet-runtime.ts";
|
|
53
58
|
|
|
@@ -707,7 +712,9 @@ export function registerWorkflowControl(
|
|
|
707
712
|
const engines = new Map<string, Promise<WorkflowControlEngine>>();
|
|
708
713
|
const designOperations = new Set<Promise<void>>();
|
|
709
714
|
const designFailures = new Map<string, SafeDesignFailure>();
|
|
715
|
+
const implementContinuation = new ImplementContinuationDriver();
|
|
710
716
|
let pendingPrompt: EligiblePrompt | undefined;
|
|
717
|
+
let pendingImplementChange: string | undefined;
|
|
711
718
|
let pendingInit = false;
|
|
712
719
|
let exitingStage = false;
|
|
713
720
|
let activePrompt: EligiblePrompt | undefined;
|
|
@@ -797,6 +804,7 @@ export function registerWorkflowControl(
|
|
|
797
804
|
};
|
|
798
805
|
const deactivateStage = async () => {
|
|
799
806
|
activePrompt = undefined;
|
|
807
|
+
implementContinuation.deactivate();
|
|
800
808
|
await packetRuntime.drain();
|
|
801
809
|
deactivate();
|
|
802
810
|
};
|
|
@@ -1349,6 +1357,13 @@ export function registerWorkflowControl(
|
|
|
1349
1357
|
registerDispatchTool("packet");
|
|
1350
1358
|
|
|
1351
1359
|
pi.on("tool_result", (event) => {
|
|
1360
|
+
implementContinuation.noteToolResult({
|
|
1361
|
+
toolName: event.toolName,
|
|
1362
|
+
input: event.input,
|
|
1363
|
+
content: event.content,
|
|
1364
|
+
details: event.details,
|
|
1365
|
+
isError: event.isError,
|
|
1366
|
+
});
|
|
1352
1367
|
if (
|
|
1353
1368
|
event.toolName !== DISPATCH_TOOL ||
|
|
1354
1369
|
!event.isError ||
|
|
@@ -1385,7 +1400,9 @@ export function registerWorkflowControl(
|
|
|
1385
1400
|
};
|
|
1386
1401
|
});
|
|
1387
1402
|
pi.on("input", (event) => {
|
|
1403
|
+
implementContinuation.noteInput();
|
|
1388
1404
|
pendingPrompt = undefined;
|
|
1405
|
+
pendingImplementChange = undefined;
|
|
1389
1406
|
pendingInit = false;
|
|
1390
1407
|
const prompt = invokedPrompt(event.text);
|
|
1391
1408
|
const init = /^\/abel-init(?:\s|$)/u.test(event.text);
|
|
@@ -1395,6 +1412,10 @@ export function registerWorkflowControl(
|
|
|
1395
1412
|
return { action: prompt || init ? "handled" : "continue" };
|
|
1396
1413
|
}
|
|
1397
1414
|
pendingPrompt = prompt;
|
|
1415
|
+
pendingImplementChange =
|
|
1416
|
+
prompt === "abel-implement"
|
|
1417
|
+
? implementChangeFromInvocation(event.text)
|
|
1418
|
+
: undefined;
|
|
1398
1419
|
pendingInit = init && hasPackageProvenance(pi, "abel-init");
|
|
1399
1420
|
if (
|
|
1400
1421
|
activePrompt &&
|
|
@@ -1408,11 +1429,13 @@ export function registerWorkflowControl(
|
|
|
1408
1429
|
}
|
|
1409
1430
|
return { action: "continue" };
|
|
1410
1431
|
});
|
|
1411
|
-
pi.on("before_agent_start", (event) => {
|
|
1432
|
+
pi.on("before_agent_start", (event, ctx) => {
|
|
1412
1433
|
const prompt = pendingPrompt;
|
|
1434
|
+
const implementChange = pendingImplementChange;
|
|
1413
1435
|
const init =
|
|
1414
1436
|
pendingInit && hasExpandedPromptMarker(event.prompt, "abel-init");
|
|
1415
1437
|
pendingPrompt = undefined;
|
|
1438
|
+
pendingImplementChange = undefined;
|
|
1416
1439
|
pendingInit = false;
|
|
1417
1440
|
const verified =
|
|
1418
1441
|
prompt && isVerifiedStageInvocation(pi, activation, prompt, event.prompt);
|
|
@@ -1422,10 +1445,30 @@ export function registerWorkflowControl(
|
|
|
1422
1445
|
}
|
|
1423
1446
|
registerDispatchTool(prompt === "abel-implement" ? "command" : "packet");
|
|
1424
1447
|
activePrompt = prompt;
|
|
1448
|
+
if (prompt === "abel-implement") {
|
|
1449
|
+
if (
|
|
1450
|
+
implementChange &&
|
|
1451
|
+
implementPromptBindsChange(event.prompt, implementChange) &&
|
|
1452
|
+
typeof ctx.cwd === "string"
|
|
1453
|
+
)
|
|
1454
|
+
implementContinuation.activate({
|
|
1455
|
+
cwd: ctx.cwd,
|
|
1456
|
+
change: implementChange,
|
|
1457
|
+
});
|
|
1458
|
+
else implementContinuation.deactivate();
|
|
1459
|
+
} else {
|
|
1460
|
+
implementContinuation.deactivate();
|
|
1461
|
+
}
|
|
1425
1462
|
}
|
|
1426
1463
|
if (prompt) activateDispatcher(pi, activation, prompt, event.prompt);
|
|
1427
1464
|
if (activation.isActive() && activePrompt === "abel-design")
|
|
1428
1465
|
enforceDesignTools();
|
|
1466
|
+
if (
|
|
1467
|
+
activation.isActive() &&
|
|
1468
|
+
activePrompt === "abel-implement" &&
|
|
1469
|
+
typeof ctx.cwd === "string"
|
|
1470
|
+
)
|
|
1471
|
+
implementContinuation.beginParentTurn(ctx.cwd);
|
|
1429
1472
|
const boundary = activePrompt
|
|
1430
1473
|
? `Abel stage ${activePrompt} is active only for the invoked task and its direct follow-ups. If the user ends it or requests an unrelated task, first call abel_dispatch with {"action":"finish"}, then handle that task normally with the restored tools. A successful finish ends stage authority immediately, including within this turn. Do not extend Gates or workflow rules to that task. A direct Gate answer or same-task continuation stays in this stage. Never invoke another Abel stage automatically.`
|
|
1431
1474
|
: init
|
|
@@ -1445,10 +1488,113 @@ export function registerWorkflowControl(
|
|
|
1445
1488
|
}
|
|
1446
1489
|
return { ...event.payload, parallel_tool_calls: true };
|
|
1447
1490
|
});
|
|
1491
|
+
pi.on("agent_end", async (event, ctx) => {
|
|
1492
|
+
// The host may replace its current signal after abort/settlement. Retain
|
|
1493
|
+
// this run's signal so a late status result cannot revive an aborted turn.
|
|
1494
|
+
const runSignal = ctx.signal;
|
|
1495
|
+
const aborted = () => runSignal?.aborted || ctx.signal?.aborted;
|
|
1496
|
+
if (
|
|
1497
|
+
aborted() ||
|
|
1498
|
+
exitingStage ||
|
|
1499
|
+
!activation.isActive() ||
|
|
1500
|
+
activePrompt !== "abel-implement"
|
|
1501
|
+
) {
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
if (
|
|
1505
|
+
typeof ctx.hasPendingMessages === "function" &&
|
|
1506
|
+
ctx.hasPendingMessages()
|
|
1507
|
+
) {
|
|
1508
|
+
return;
|
|
1509
|
+
}
|
|
1510
|
+
const probe = implementContinuation.prepareSettlement({
|
|
1511
|
+
cwd: ctx.cwd,
|
|
1512
|
+
messages: event.messages,
|
|
1513
|
+
});
|
|
1514
|
+
if (!probe) return;
|
|
1515
|
+
|
|
1516
|
+
let status: Record<string, unknown>;
|
|
1517
|
+
try {
|
|
1518
|
+
const engine = await engineFor(ctx);
|
|
1519
|
+
if (
|
|
1520
|
+
aborted() ||
|
|
1521
|
+
exitingStage ||
|
|
1522
|
+
!activation.isActive() ||
|
|
1523
|
+
activePrompt !== "abel-implement"
|
|
1524
|
+
) {
|
|
1525
|
+
return;
|
|
1526
|
+
}
|
|
1527
|
+
status = await engine.execute(
|
|
1528
|
+
{
|
|
1529
|
+
command: "status",
|
|
1530
|
+
stage: "abel-implement",
|
|
1531
|
+
change: probe.change,
|
|
1532
|
+
},
|
|
1533
|
+
ctx,
|
|
1534
|
+
runSignal,
|
|
1535
|
+
);
|
|
1536
|
+
if (
|
|
1537
|
+
aborted() ||
|
|
1538
|
+
(typeof ctx.hasPendingMessages === "function" &&
|
|
1539
|
+
ctx.hasPendingMessages())
|
|
1540
|
+
) {
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
} catch {
|
|
1544
|
+
// A host reminder cannot replace a trustworthy local status read.
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
const decision = implementContinuation.finishSettlement(probe, status);
|
|
1549
|
+
if (decision?.kind === "terminal") {
|
|
1550
|
+
await deactivateStage();
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1553
|
+
if (!decision) return;
|
|
1554
|
+
if (
|
|
1555
|
+
aborted() ||
|
|
1556
|
+
(typeof ctx.hasPendingMessages === "function" && ctx.hasPendingMessages())
|
|
1557
|
+
) {
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
if (decision.kind === "stalled") {
|
|
1562
|
+
pi.sendMessage(
|
|
1563
|
+
{
|
|
1564
|
+
customType: "abel-implement-continuation-stalled",
|
|
1565
|
+
content: [{ type: "text", text: decision.message }],
|
|
1566
|
+
display: true,
|
|
1567
|
+
details: {
|
|
1568
|
+
code: decision.code,
|
|
1569
|
+
change: decision.change,
|
|
1570
|
+
state: decision.state,
|
|
1571
|
+
statusFingerprint: decision.statusFingerprint,
|
|
1572
|
+
},
|
|
1573
|
+
},
|
|
1574
|
+
{ triggerTurn: false },
|
|
1575
|
+
);
|
|
1576
|
+
return;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
pi.sendMessage(
|
|
1580
|
+
{
|
|
1581
|
+
customType: "abel-implement-continuation",
|
|
1582
|
+
content: [{ type: "text", text: decision.message }],
|
|
1583
|
+
display: false,
|
|
1584
|
+
details: {
|
|
1585
|
+
change: decision.change,
|
|
1586
|
+
statusFingerprint: decision.statusFingerprint,
|
|
1587
|
+
},
|
|
1588
|
+
},
|
|
1589
|
+
{ triggerTurn: true, deliverAs: "followUp" },
|
|
1590
|
+
);
|
|
1591
|
+
});
|
|
1448
1592
|
pi.on("session_start", async (_event, ctx) => {
|
|
1449
1593
|
pendingPrompt = undefined;
|
|
1594
|
+
pendingImplementChange = undefined;
|
|
1450
1595
|
pendingInit = false;
|
|
1451
1596
|
activePrompt = undefined;
|
|
1597
|
+
implementContinuation.deactivate();
|
|
1452
1598
|
designFailures.clear();
|
|
1453
1599
|
activity.detach();
|
|
1454
1600
|
await packetRuntime.drain();
|
|
@@ -1457,7 +1603,11 @@ export function registerWorkflowControl(
|
|
|
1457
1603
|
if (ctx.mode === "tui") activity.attach(ctx.ui);
|
|
1458
1604
|
});
|
|
1459
1605
|
pi.on("session_shutdown", async () => {
|
|
1606
|
+
pendingPrompt = undefined;
|
|
1607
|
+
pendingImplementChange = undefined;
|
|
1608
|
+
pendingInit = false;
|
|
1460
1609
|
activePrompt = undefined;
|
|
1610
|
+
implementContinuation.deactivate();
|
|
1461
1611
|
designFailures.clear();
|
|
1462
1612
|
activity.detach();
|
|
1463
1613
|
await packetRuntime.drain();
|
package/src/isolation-backend.ts
CHANGED
|
@@ -37,6 +37,7 @@ export type IsolationRunResult =
|
|
|
37
37
|
code:
|
|
38
38
|
| "isolation-backend-unavailable"
|
|
39
39
|
| "isolation-backend-launch-failed"
|
|
40
|
+
| "isolation-termination-unconfirmed"
|
|
40
41
|
| "isolation-execution-timeout";
|
|
41
42
|
}
|
|
42
43
|
| { ok: false; state: "cancelled"; code: "cancelled" };
|
|
@@ -72,7 +73,7 @@ function validEnvironmentName(name: string): boolean {
|
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
/** Retains independent head/tail copies; discarded chunks never stay referenced. */
|
|
75
|
-
class BoundedLog {
|
|
76
|
+
export class BoundedLog {
|
|
76
77
|
bytes = 0;
|
|
77
78
|
#head = Buffer.alloc(0);
|
|
78
79
|
#tail = Buffer.alloc(0);
|