@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 CHANGED
@@ -11,7 +11,7 @@ Devflow Pi 是一个面向项目研发交付的独立 OMP 产品入口,内置
11
11
  安装与启动:
12
12
 
13
13
  ```bash
14
- npm install -g @guanlin4924/devflow-pi@0.1.37
14
+ npm install -g @guanlin4924/devflow-pi@0.1.38
15
15
  cd /path/to/your-project
16
16
  devflow-pi init
17
17
  devflow-pi doctor
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guanlin4924/devflow-pi",
3
- "version": "0.1.37",
3
+ "version": "0.1.38",
4
4
  "type": "module",
5
5
  "description": "Devflow 专项研发 Pi,基于固定版本 OMP Runtime 组装研发状态机、代码智能、设计、实现与质量门禁。",
6
6
  "license": "UNLICENSED",
@@ -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 inspectWorkflow(ctx.cwd);
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 inspectWorkflow(ctx.cwd);
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(pending.snapshot, "approval");
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 inspectWorkflow(ctx.cwd);
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 inspectWorkflow(ctx.cwd);
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 inspectWorkflow(ctx.cwd);
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 inspectWorkflow(ctx.cwd);
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 inspectWorkflow(ctx.cwd);
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 inspectWorkflow(ctx.cwd);
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 inspectWorkflow(ctx.cwd);
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 inspectWorkflow(ctx.cwd);
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 inspectWorkflow(ctx.cwd);
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
@@ -1,5 +1,5 @@
1
1
  export const PRODUCT_NAME = "Devflow Pi";
2
- export const PRODUCT_VERSION = "0.1.37";
2
+ export const PRODUCT_VERSION = "0.1.38";
3
3
  export const PROJECT_SCHEMA_VERSION = 1;
4
4
  export const OMP_RUNTIME_VERSION = "17.2.7";
5
5