@guanlin4924/devflow-pi 0.1.37 → 0.1.38
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 +1 -1
- package/package.json +1 -1
- package/plugins/devflow-core/extensions/devflow-core.ts +39 -12
- package/src/constants.ts +1 -1
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1285,6 +1285,22 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
1285
1285
|
return { result, snapshot: parseJsonResult(result) };
|
|
1286
1286
|
}
|
|
1287
1287
|
|
|
1288
|
+
async function inspectWorkflowWithRegistryRecovery(cwd: string): Promise<{ result: ProcessResult; snapshot: Record<string, unknown> | null }> {
|
|
1289
|
+
let inspected = await inspectWorkflow(cwd);
|
|
1290
|
+
const errors = Array.isArray(inspected.snapshot?.state_validation && (inspected.snapshot.state_validation as Record<string, unknown>).errors)
|
|
1291
|
+
? (inspected.snapshot!.state_validation as Record<string, unknown>).errors as Array<Record<string, unknown>>
|
|
1292
|
+
: [];
|
|
1293
|
+
const onlyRegistryDrift = inspected.snapshot?.reason === "state_validation_failed" &&
|
|
1294
|
+
errors.length > 0 && errors.every(error => error.code === "artifact_registry_revision_mismatch");
|
|
1295
|
+
if (!onlyRegistryDrift) return inspected;
|
|
1296
|
+
const synced = await runRuby(cwd, "workflow-orchestrator/scripts/sync_artifacts.rb", [
|
|
1297
|
+
"--write", "--no-preserve", "--json",
|
|
1298
|
+
]);
|
|
1299
|
+
if (!synced.ok) return inspected;
|
|
1300
|
+
inspected = await inspectWorkflow(cwd);
|
|
1301
|
+
return inspected;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1288
1304
|
let activeWorkflowTurn = false;
|
|
1289
1305
|
let pendingProjectInitialization: ProjectInitializationRequest | undefined;
|
|
1290
1306
|
let pendingRollover: { snapshot: Record<string, unknown>; preparedRevision: number; rolloverId: string } | undefined;
|
|
@@ -1362,7 +1378,7 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
1362
1378
|
}
|
|
1363
1379
|
}
|
|
1364
1380
|
if (rolloverState && typeof rolloverState.revision === "number" && rollover?.status === "prepared" && typeof rollover.id === "string") {
|
|
1365
|
-
const workflow = await
|
|
1381
|
+
const workflow = await inspectWorkflowWithRegistryRecovery(ctx.cwd);
|
|
1366
1382
|
const expectedStateRevision = typeof rollover.expected_state_revision === "number" ? rollover.expected_state_revision : undefined;
|
|
1367
1383
|
if (workflow.result.ok && workflow.snapshot && expectedStateRevision !== undefined && expectedStateRevision + 1 === rolloverState.revision) {
|
|
1368
1384
|
pendingRollover = { snapshot: workflow.snapshot, preparedRevision: rolloverState.revision, rolloverId: rollover.id };
|
|
@@ -1373,8 +1389,13 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
1373
1389
|
const consumed = await runRuby(ctx.cwd, "workflow-orchestrator/scripts/session_rollover.rb", [
|
|
1374
1390
|
"consume", "--write", "--json", "--expected-revision", String(rolloverState.revision), "--target-session-id", currentSessionId,
|
|
1375
1391
|
]);
|
|
1376
|
-
const after = await
|
|
1392
|
+
const after = await inspectWorkflowWithRegistryRecovery(ctx.cwd);
|
|
1377
1393
|
if (consumed.ok && after.result.ok && after.snapshot) {
|
|
1394
|
+
if (after.snapshot.action === "blocked") {
|
|
1395
|
+
setControlState(ctx, { intent: "workflow-execute", phase: "blocked", label: "启动恢复校验失败" });
|
|
1396
|
+
ctx.ui.notify(`会话已恢复,但工作流校验失败,未启动 AI:${String(after.snapshot.reason ?? "state validation failed")}`, "error");
|
|
1397
|
+
return;
|
|
1398
|
+
}
|
|
1378
1399
|
setControlState(ctx, executingState("恢复已认领的干净会话"));
|
|
1379
1400
|
await triggerWorkflow(after.snapshot, "approval");
|
|
1380
1401
|
} else if (!consumed.ok) {
|
|
@@ -1421,8 +1442,14 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
1421
1442
|
pendingRollover = undefined;
|
|
1422
1443
|
activeContract = undefined;
|
|
1423
1444
|
contractAgentCalls = 0;
|
|
1445
|
+
const next = await inspectWorkflowWithRegistryRecovery(ctx.cwd);
|
|
1446
|
+
if (!next.result.ok || !next.snapshot || next.snapshot.action === "blocked") {
|
|
1447
|
+
setControlState(ctx, { intent: "workflow-execute", phase: "blocked", label: "启动恢复校验失败" });
|
|
1448
|
+
ctx.ui.notify(`会话已切换,但工作流校验失败,未启动 AI:${String(next.snapshot?.reason ?? next.result.stderr ?? next.result.stdout ?? "state validation failed")}`, "error");
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1424
1451
|
setControlState(ctx, executingState("在干净会话中执行下一工作流步骤"));
|
|
1425
|
-
await triggerWorkflow(
|
|
1452
|
+
await triggerWorkflow(next.snapshot, "approval");
|
|
1426
1453
|
});
|
|
1427
1454
|
|
|
1428
1455
|
pi.on("before_agent_start", async event => ({
|
|
@@ -1444,7 +1471,7 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
1444
1471
|
if (controlState.intent === "requirement-draft" && controlState.phase === "planning") {
|
|
1445
1472
|
const requirementDraft = event.text.trim();
|
|
1446
1473
|
if (!requirementDraft) return { handled: true };
|
|
1447
|
-
const inspected = await
|
|
1474
|
+
const inspected = await inspectWorkflowWithRegistryRecovery(ctx.cwd);
|
|
1448
1475
|
if (!inspected.result.ok || !inspected.snapshot) {
|
|
1449
1476
|
ctx.ui.notify(`需求分诊启动失败:${inspected.result.stderr || inspected.result.stdout || "invalid inspector JSON"}`, "error");
|
|
1450
1477
|
return { handled: true };
|
|
@@ -1472,7 +1499,7 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
1472
1499
|
// fresh-session handoff. Keep approval useful in this recovery state, but
|
|
1473
1500
|
// retry only the handoff; never repeat the already-persisted transition.
|
|
1474
1501
|
if (controlState.phase === "blocked" && controlState.label === "会话轮换准备失败" && controlAction === "approve") {
|
|
1475
|
-
const inspected = await
|
|
1502
|
+
const inspected = await inspectWorkflowWithRegistryRecovery(ctx.cwd);
|
|
1476
1503
|
if (!inspected.result.ok || !inspected.snapshot) {
|
|
1477
1504
|
ctx.ui.notify(`会话交接重试失败:${inspected.result.stderr || inspected.result.stdout || "invalid inspector JSON"}`, "error");
|
|
1478
1505
|
return { handled: true };
|
|
@@ -1498,7 +1525,7 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
1498
1525
|
return { handled: true };
|
|
1499
1526
|
}
|
|
1500
1527
|
if (controlAction === "approve") {
|
|
1501
|
-
const inspected = await
|
|
1528
|
+
const inspected = await inspectWorkflowWithRegistryRecovery(ctx.cwd);
|
|
1502
1529
|
if (!inspected.result.ok || !inspected.snapshot) {
|
|
1503
1530
|
ctx.ui.notify(`审批处理失败:${inspected.result.stderr || inspected.result.stdout || "invalid inspector JSON"}`, "error");
|
|
1504
1531
|
return { handled: true };
|
|
@@ -1523,7 +1550,7 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
1523
1550
|
ctx.ui.notify(`未推进:${result.stderr || result.stdout}`, "error");
|
|
1524
1551
|
return { handled: true };
|
|
1525
1552
|
}
|
|
1526
|
-
const after = await
|
|
1553
|
+
const after = await inspectWorkflowWithRegistryRecovery(ctx.cwd);
|
|
1527
1554
|
activeContract = undefined;
|
|
1528
1555
|
contractAgentCalls = 0;
|
|
1529
1556
|
if (!after.result.ok || !after.snapshot || after.snapshot.action === "workflow_complete") {
|
|
@@ -2513,7 +2540,7 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
2513
2540
|
}
|
|
2514
2541
|
args.push("--checkpoint-decision", params.decision);
|
|
2515
2542
|
} else if (params.action === "cancel-feature") {
|
|
2516
|
-
const inspected = await
|
|
2543
|
+
const inspected = await inspectWorkflowWithRegistryRecovery(ctx.cwd);
|
|
2517
2544
|
const snapshot = inspected.snapshot;
|
|
2518
2545
|
const feature = typeof snapshot?.current_feature === "string" ? snapshot.current_feature : "当前需求";
|
|
2519
2546
|
const revision = typeof snapshot?.revision === "number" ? snapshot.revision : undefined;
|
|
@@ -2641,7 +2668,7 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
2641
2668
|
return;
|
|
2642
2669
|
}
|
|
2643
2670
|
if (trimmed === "explain-state") {
|
|
2644
|
-
const inspected = await
|
|
2671
|
+
const inspected = await inspectWorkflowWithRegistryRecovery(ctx.cwd);
|
|
2645
2672
|
ctx.ui.notify(
|
|
2646
2673
|
inspected.result.ok ? explainWorkflowSnapshot(inspected.snapshot) : `状态读取失败:${inspected.result.stderr || inspected.result.stdout}`,
|
|
2647
2674
|
inspected.result.ok ? "info" : "error",
|
|
@@ -2650,7 +2677,7 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
2650
2677
|
return;
|
|
2651
2678
|
}
|
|
2652
2679
|
if (trimmed === "recover") {
|
|
2653
|
-
const inspected = await
|
|
2680
|
+
const inspected = await inspectWorkflowWithRegistryRecovery(ctx.cwd);
|
|
2654
2681
|
const plan = inspected.snapshot?.recovery_plan as Record<string, unknown> | undefined;
|
|
2655
2682
|
const revision = plan?.expected_revision;
|
|
2656
2683
|
if (!inspected.result.ok || !plan || plan.classification !== "safe_repairable" || typeof revision !== "number") {
|
|
@@ -2689,7 +2716,7 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
2689
2716
|
return;
|
|
2690
2717
|
}
|
|
2691
2718
|
if (trimmed === "abandon" || trimmed.startsWith("abandon ") || trimmed === "cancel" || trimmed.startsWith("cancel ")) {
|
|
2692
|
-
const inspected = await
|
|
2719
|
+
const inspected = await inspectWorkflowWithRegistryRecovery(ctx.cwd);
|
|
2693
2720
|
const snapshot = inspected.snapshot;
|
|
2694
2721
|
const revision = typeof snapshot?.revision === "number" ? snapshot.revision : undefined;
|
|
2695
2722
|
const feature = typeof snapshot?.current_feature === "string" ? snapshot.current_feature : undefined;
|
|
@@ -2758,7 +2785,7 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
2758
2785
|
ctx.ui.notify(formatDoctorReport(report).slice(0, 10000), "error");
|
|
2759
2786
|
return;
|
|
2760
2787
|
}
|
|
2761
|
-
const inspected = await
|
|
2788
|
+
const inspected = await inspectWorkflowWithRegistryRecovery(ctx.cwd);
|
|
2762
2789
|
if (!inspected.result.ok || !inspected.snapshot) {
|
|
2763
2790
|
ctx.ui.notify(
|
|
2764
2791
|
`Devflow resume failed: ${inspected.result.stderr || inspected.result.stdout || "invalid inspector JSON"}`,
|
package/src/constants.ts
CHANGED