@williambeto/ai-workflow 2.6.4 → 2.6.7

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 CHANGED
@@ -1,3 +1,8 @@
1
+ ## [unreleased]
2
+
3
+ ### 🧪 Testing
4
+
5
+ - Align E2E assertions with updated requestedActor routing mechanics
1
6
  ## [2.6.4] - 2026-07-04
2
7
 
3
8
  ### 🐛 Bug Fixes
@@ -21,13 +21,13 @@ import {
21
21
  isTerminalFailure,
22
22
  readPackageFile,
23
23
  resolveWorkflowProfile
24
- } from "../chunk-UHLZX2EG.js";
24
+ } from "../chunk-W4RTQWVQ.js";
25
25
  import {
26
26
  EvidenceCollector,
27
27
  QualityGuard,
28
28
  ValidationPlanner
29
- } from "../chunk-6EMG6FAO.js";
30
- import "../chunk-2AOV2ATY.js";
29
+ } from "../chunk-BDZPUAEX.js";
30
+ import "../chunk-XW747GIG.js";
31
31
  import "../chunk-5WRI5ZAA.js";
32
32
 
33
33
  // src/cli/commands/init.ts
@@ -1486,11 +1486,7 @@ async function isSymlink(filePath) {
1486
1486
  return false;
1487
1487
  }
1488
1488
  }
1489
- async function runDoctor({ cwd }) {
1490
- let hasFailure = false;
1491
- let hasWarning = false;
1492
- let managedBlocks = [];
1493
- console.log("Doctor report:");
1489
+ async function checkOpenCodeRuntime(cwd, state) {
1494
1490
  const adapter = new OpenCodeAdapter({ cwd });
1495
1491
  const inspection = await adapter.inspect();
1496
1492
  if (inspection.available) {
@@ -1500,22 +1496,26 @@ async function runDoctor({ cwd }) {
1500
1496
  if (inspection.supports.agent) {
1501
1497
  console.log("PASS opencode --agent selection is supported");
1502
1498
  } else {
1503
- hasWarning = true;
1499
+ state.hasWarning = true;
1504
1500
  console.log("WARN opencode --agent selection is not supported; prompt fallback is available");
1505
1501
  }
1506
1502
  } else {
1507
- hasFailure = true;
1503
+ state.hasFailure = true;
1508
1504
  console.log("FAIL opencode CLI is not installed or not available in PATH");
1509
1505
  }
1506
+ }
1507
+ async function checkRequiredFiles(cwd, state) {
1510
1508
  for (const relativePath of REQUIRED_FILES) {
1511
1509
  const ok = await exists(path10.join(cwd, relativePath));
1512
1510
  if (ok) {
1513
1511
  console.log(`PASS ${relativePath}`);
1514
1512
  } else {
1515
- hasFailure = true;
1513
+ state.hasFailure = true;
1516
1514
  console.log(`FAIL ${relativePath} missing`);
1517
1515
  }
1518
1516
  }
1517
+ }
1518
+ async function checkAiWorkflowConfig(cwd, state) {
1519
1519
  const configPathV2 = path10.join(cwd, ".ai-workflow/config.json");
1520
1520
  const configPathLegacy = path10.join(cwd, ".ai-workflow.json");
1521
1521
  let configPath = null;
@@ -1524,122 +1524,137 @@ async function runDoctor({ cwd }) {
1524
1524
  } else if (await exists(configPathLegacy)) {
1525
1525
  configPath = configPathLegacy;
1526
1526
  }
1527
- if (configPath) {
1528
- try {
1529
- const config = await readJson(configPath);
1530
- if (config.installMode === "project-local" || config.mode === "standalone") {
1531
- console.log("PASS install mode is project-local/standalone");
1532
- } else {
1533
- hasWarning = true;
1534
- console.log(`WARN install mode is not project-local/standalone in ${path10.basename(configPath)}`);
1535
- }
1536
- if (config.profile) {
1537
- console.log(`PASS profile detected: ${config.profile}`);
1538
- } else {
1539
- hasWarning = true;
1540
- console.log(`WARN profile is missing in ${path10.basename(configPath)}`);
1541
- }
1542
- if (config.runtime) {
1543
- console.log(`PASS runtime: ${config.runtime}`);
1544
- } else {
1545
- console.log(`NOTE runtime field not present in ${path10.basename(configPath)}`);
1546
- }
1547
- if (Array.isArray(config.managedBlocks)) {
1548
- managedBlocks = config.managedBlocks;
1549
- } else {
1550
- console.log(`NOTE managedBlocks not present in ${path10.basename(configPath)} (legacy field)`);
1551
- }
1552
- if (Array.isArray(config.managedFiles)) {
1553
- for (const relativePath of config.managedFiles) {
1554
- const fileExists = await exists(path10.join(cwd, relativePath));
1555
- if (!fileExists) {
1556
- hasWarning = true;
1557
- console.log(`WARN managed file missing: ${relativePath}`);
1558
- }
1527
+ if (!configPath) return;
1528
+ try {
1529
+ const config = await readJson(configPath);
1530
+ const basename = path10.basename(configPath);
1531
+ if (config.installMode === "project-local" || config.mode === "standalone") {
1532
+ console.log("PASS install mode is project-local/standalone");
1533
+ } else {
1534
+ state.hasWarning = true;
1535
+ console.log(`WARN install mode is not project-local/standalone in ${basename}`);
1536
+ }
1537
+ if (config.profile) {
1538
+ console.log(`PASS profile detected: ${config.profile}`);
1539
+ } else {
1540
+ state.hasWarning = true;
1541
+ console.log(`WARN profile is missing in ${basename}`);
1542
+ }
1543
+ if (config.runtime) {
1544
+ console.log(`PASS runtime: ${config.runtime}`);
1545
+ } else {
1546
+ console.log(`NOTE runtime field not present in ${basename}`);
1547
+ }
1548
+ if (Array.isArray(config.managedBlocks)) {
1549
+ state.managedBlocks = config.managedBlocks;
1550
+ } else {
1551
+ console.log(`NOTE managedBlocks not present in ${basename} (legacy field)`);
1552
+ }
1553
+ if (Array.isArray(config.managedFiles)) {
1554
+ for (const relativePath of config.managedFiles) {
1555
+ const fileExists = await exists(path10.join(cwd, relativePath));
1556
+ if (!fileExists) {
1557
+ state.hasWarning = true;
1558
+ console.log(`WARN managed file missing: ${relativePath}`);
1559
1559
  }
1560
1560
  }
1561
- if (Array.isArray(config.managedLinks)) {
1562
- for (const relativePath of config.managedLinks) {
1563
- const absolutePath = path10.join(cwd, relativePath);
1564
- const linkExists = await exists(absolutePath);
1565
- if (!linkExists) {
1566
- hasWarning = true;
1567
- console.log(`WARN managed link missing: ${relativePath}`);
1568
- continue;
1569
- }
1570
- const isLink = await isSymlink(absolutePath);
1571
- if (!isLink) {
1572
- hasWarning = true;
1573
- console.log(`WARN managed link is not a symlink: ${relativePath}`);
1574
- }
1561
+ }
1562
+ if (Array.isArray(config.managedLinks)) {
1563
+ for (const relativePath of config.managedLinks) {
1564
+ const absolutePath = path10.join(cwd, relativePath);
1565
+ if (!await exists(absolutePath)) {
1566
+ state.hasWarning = true;
1567
+ console.log(`WARN managed link missing: ${relativePath}`);
1568
+ continue;
1569
+ }
1570
+ if (!await isSymlink(absolutePath)) {
1571
+ state.hasWarning = true;
1572
+ console.log(`WARN managed link is not a symlink: ${relativePath}`);
1575
1573
  }
1576
1574
  }
1577
- } catch {
1578
- hasFailure = true;
1579
- console.log(`FAIL ${path10.basename(configPath)} is not valid JSON`);
1580
1575
  }
1576
+ } catch {
1577
+ state.hasFailure = true;
1578
+ console.log(`FAIL ${path10.basename(configPath)} is not valid JSON`);
1581
1579
  }
1580
+ }
1581
+ async function checkOpencodeJson(cwd, state) {
1582
1582
  const opencodePath = path10.join(cwd, "opencode.jsonc");
1583
1583
  if (!await exists(opencodePath)) {
1584
- hasFailure = true;
1584
+ state.hasFailure = true;
1585
1585
  console.log("FAIL opencode.jsonc missing");
1586
- } else {
1587
- try {
1588
- const opencodeConfig = await readJsonc(opencodePath);
1589
- console.log("PASS opencode.jsonc is valid JSONC");
1590
- const needsAgentDefault = managedBlocks.includes("opencode.jsonc:agent.default");
1591
- if (!needsAgentDefault || opencodeConfig.agent?.default) {
1592
- console.log("PASS opencode agent.default available");
1593
- } else {
1594
- hasFailure = true;
1595
- console.log("FAIL opencode agent.default missing");
1596
- }
1597
- const requiredCommands = managedBlocks.filter((block) => block.startsWith("opencode.jsonc:command.")).map((block) => block.replace("opencode.jsonc:command.", ""));
1598
- if (requiredCommands.length === 0) {
1599
- console.log("PASS no managed opencode commands required");
1586
+ return;
1587
+ }
1588
+ try {
1589
+ const opencodeConfig = await readJsonc(opencodePath);
1590
+ console.log("PASS opencode.jsonc is valid JSONC");
1591
+ const needsAgentDefault = state.managedBlocks.includes("opencode.jsonc:agent.default");
1592
+ if (!needsAgentDefault || opencodeConfig.agent?.default) {
1593
+ console.log("PASS opencode agent.default available");
1594
+ } else {
1595
+ state.hasFailure = true;
1596
+ console.log("FAIL opencode agent.default missing");
1597
+ }
1598
+ const requiredCommands = state.managedBlocks.filter((block) => block.startsWith("opencode.jsonc:command.")).map((block) => block.replace("opencode.jsonc:command.", ""));
1599
+ if (requiredCommands.length === 0) {
1600
+ console.log("PASS no managed opencode commands required");
1601
+ } else {
1602
+ const missingCommands = requiredCommands.filter((command) => !opencodeConfig.command?.[command]);
1603
+ if (missingCommands.length === 0) {
1604
+ console.log(`PASS opencode managed commands available (${requiredCommands.length})`);
1600
1605
  } else {
1601
- const missingCommands = requiredCommands.filter((command) => !opencodeConfig.command?.[command]);
1602
- if (missingCommands.length === 0) {
1603
- console.log(`PASS opencode managed commands available (${requiredCommands.length})`);
1604
- } else {
1605
- hasFailure = true;
1606
- console.log(`FAIL opencode command entries missing: ${missingCommands.join(", ")}`);
1607
- }
1606
+ state.hasFailure = true;
1607
+ console.log(`FAIL opencode command entries missing: ${missingCommands.join(", ")}`);
1608
1608
  }
1609
- const requiredAgents = managedBlocks.filter((block) => block.startsWith("opencode.jsonc:agent.") && !block.endsWith(".default")).map((block) => block.replace("opencode.jsonc:agent.", ""));
1610
- if (requiredAgents.length === 0) {
1611
- console.log("PASS no managed opencode agents required");
1609
+ }
1610
+ const requiredAgents = state.managedBlocks.filter((block) => block.startsWith("opencode.jsonc:agent.") && !block.endsWith(".default")).map((block) => block.replace("opencode.jsonc:agent.", ""));
1611
+ if (requiredAgents.length === 0) {
1612
+ console.log("PASS no managed opencode agents required");
1613
+ } else {
1614
+ const missingAgents = requiredAgents.filter((agent) => !opencodeConfig.agent?.[agent]);
1615
+ if (missingAgents.length === 0) {
1616
+ console.log(`PASS opencode managed agents available (${requiredAgents.length})`);
1612
1617
  } else {
1613
- const missingAgents = requiredAgents.filter((agent) => !opencodeConfig.agent?.[agent]);
1614
- if (missingAgents.length === 0) {
1615
- console.log(`PASS opencode managed agents available (${requiredAgents.length})`);
1616
- } else {
1617
- hasFailure = true;
1618
- console.log(`FAIL opencode agent entries missing: ${missingAgents.join(", ")}`);
1619
- }
1618
+ state.hasFailure = true;
1619
+ console.log(`FAIL opencode agent entries missing: ${missingAgents.join(", ")}`);
1620
1620
  }
1621
- } catch {
1622
- hasFailure = true;
1623
- console.log("FAIL opencode.jsonc is not valid JSONC");
1624
1621
  }
1622
+ } catch {
1623
+ state.hasFailure = true;
1624
+ console.log("FAIL opencode.jsonc is not valid JSONC");
1625
1625
  }
1626
+ }
1627
+ async function checkPackageJson(cwd, state) {
1626
1628
  const packageJsonPath = path10.join(cwd, "package.json");
1627
1629
  if (await exists(packageJsonPath)) {
1628
1630
  try {
1629
1631
  const packageJson = await readJson(packageJsonPath);
1630
1632
  const scripts = packageJson.scripts ?? {};
1631
1633
  if (!scripts.validate) {
1632
- hasWarning = true;
1634
+ state.hasWarning = true;
1633
1635
  console.log("WARN package.json has no validate script");
1634
1636
  }
1635
1637
  } catch {
1636
- hasFailure = true;
1638
+ state.hasFailure = true;
1637
1639
  console.log("FAIL package.json is not valid JSON");
1638
1640
  }
1639
1641
  }
1640
- const finalStatus = hasFailure ? "FAIL" : hasWarning ? "PASS_WITH_NOTES" : "PASS";
1642
+ }
1643
+ async function runDoctor({ cwd }) {
1644
+ const state = {
1645
+ hasFailure: false,
1646
+ hasWarning: false,
1647
+ managedBlocks: []
1648
+ };
1649
+ console.log("Doctor report:");
1650
+ await checkOpenCodeRuntime(cwd, state);
1651
+ await checkRequiredFiles(cwd, state);
1652
+ await checkAiWorkflowConfig(cwd, state);
1653
+ await checkOpencodeJson(cwd, state);
1654
+ await checkPackageJson(cwd, state);
1655
+ const finalStatus = state.hasFailure ? "FAIL" : state.hasWarning ? "PASS_WITH_NOTES" : "PASS";
1641
1656
  console.log(`Final status: ${finalStatus}`);
1642
- if (hasFailure) {
1657
+ if (state.hasFailure) {
1643
1658
  process.exitCode = 1;
1644
1659
  }
1645
1660
  }
@@ -2288,6 +2303,71 @@ async function generateFinalHandoff(plan, taskSlug, cwd, finalState, evidence) {
2288
2303
  `);
2289
2304
  return handoffPath;
2290
2305
  }
2306
+ async function runFastTrackValidation(cwd, result, checkBranchSafety) {
2307
+ console.log(`
2308
+ --- [FAST-TRACK] Running Lightweight Validation Gates ---`);
2309
+ checkBranchSafety();
2310
+ const changedFiles = result.evidence?.changedFiles || [];
2311
+ console.log(`[FAST-TRACK] Changed files detected:`, changedFiles);
2312
+ const evidencePath = path14.join(cwd, "EVIDENCE.json");
2313
+ const hasEvidence = await fs12.access(evidencePath).then(() => true).catch(() => false);
2314
+ if (hasEvidence) {
2315
+ const { EvidenceValidator } = await import("../evidence-validator-76ZQQYDU.js");
2316
+ const isTest = process.env.NODE_ENV === "test" || process.env.VITEST === "true";
2317
+ const evidenceValidator = new EvidenceValidator({ cwd, skipFileCheck: isTest, skipGitCheck: isTest });
2318
+ const valResult = await evidenceValidator.validate();
2319
+ if (!valResult.valid) {
2320
+ console.error(`
2321
+ [FAST-TRACK BLOCKED] EVIDENCE.json validation failed: ${valResult.reason}`);
2322
+ return "FAIL_QUALITY_GATE";
2323
+ }
2324
+ }
2325
+ return result.overallStatus;
2326
+ }
2327
+ async function runFidelityValidation(naturalRequest, result, finalizer) {
2328
+ const fidelityResult = await finalizer.verifyFidelity({
2329
+ userRequest: naturalRequest,
2330
+ projectContext: result.evidence?.deliveryDecision?.projectContext || null,
2331
+ deliveryDecision: result.evidence?.deliveryDecision || null,
2332
+ changedFiles: result.evidence?.changedFiles || [],
2333
+ evidence: result.evidence || null,
2334
+ explicitApprovals: process.env.AI_WORKFLOW_APPROVALS ? process.env.AI_WORKFLOW_APPROVALS.split(",").map((a) => a.trim()) : []
2335
+ });
2336
+ if (!fidelityResult.passed) {
2337
+ console.log(`
2338
+ [FINALIZER BLOCKED] BLOCKED: Artifact fidelity check failed!`);
2339
+ console.log(`Reason: ${fidelityResult.reason}`);
2340
+ return "FAIL_QUALITY_GATE";
2341
+ }
2342
+ return result.overallStatus;
2343
+ }
2344
+ function computeFinalState(finalStatus) {
2345
+ if (finalStatus === "PASS") return "COMPLETED";
2346
+ if (finalStatus === "PASS_WITH_NOTES") return "COMPLETED_WITH_NOTES";
2347
+ return "BLOCKED";
2348
+ }
2349
+ async function executeReadOnlyWorkflow(cwd, stateMachine, readOnlyStateBefore, fastTrack) {
2350
+ await runReadOnlyConfinementCheck(readOnlyStateBefore, cwd, stateMachine, fastTrack);
2351
+ stateMachine.transitionTo("IMPLEMENTED");
2352
+ stateMachine.transitionTo("VALIDATING");
2353
+ stateMachine.transitionTo("COMPLETED");
2354
+ console.log("\n--- Final Handoff ---");
2355
+ console.log(`
2356
+ [AI WORKFLOW COMPLETE] COMPLETED`);
2357
+ console.log(`Handoff Packet: [IN-MEMORY] (No handoff file written in read-only mode)
2358
+ `);
2359
+ return {
2360
+ overallStatus: "PASS",
2361
+ evidence: {
2362
+ internalStatus: "PASS",
2363
+ commandsRun: []
2364
+ },
2365
+ quality: {
2366
+ overallStatus: "PASS"
2367
+ },
2368
+ stateHistory: stateMachine.getHistory()
2369
+ };
2370
+ }
2291
2371
  async function runExecute({ cwd, naturalRequest, taskSlug: taskSlugOverride }) {
2292
2372
  if (!naturalRequest || !naturalRequest.trim()) {
2293
2373
  throw new Error("Missing request. Please provide a natural request string via positional arguments or --request flag.");
@@ -2303,16 +2383,15 @@ async function runExecute({ cwd, naturalRequest, taskSlug: taskSlugOverride }) {
2303
2383
  const stateMachine = new WorkflowStateMachine();
2304
2384
  const { plan: planObj, classification } = await classifyAndPlanExecution(naturalRequest, cwd, taskSlug, delegationController, stateMachine);
2305
2385
  plan = planObj;
2306
- const fastTrack = plan.riskLevel === "low" && (plan.branchNeeded ? plan.evidencePolicy === "optional" : true);
2386
+ const fastTrack = plan.riskLevel === "low" && (!plan.branchNeeded || plan.evidencePolicy === "optional");
2307
2387
  const branchGate = new BranchGate({ memoryDir: path14.join(cwd, ".ai-workflow"), cwd });
2308
2388
  const gateResult = runBranchGate(plan, taskSlug, cwd, stateMachine, branchGate);
2309
2389
  const checkBranchSafety = () => {
2310
- if (plan.branchNeeded) {
2311
- const currentBranch = branchGate.getCurrentBranch();
2312
- if (branchGate.protectedBranches.includes(currentBranch)) {
2313
- stateMachine.transitionTo("BLOCKED");
2314
- throw new Error(`[WORKFLOW BLOCKED] Security violation: current branch is protected '${currentBranch}'!`);
2315
- }
2390
+ if (!planObj.branchNeeded) return;
2391
+ const currentBranch = branchGate.getCurrentBranch();
2392
+ if (branchGate.protectedBranches.includes(currentBranch)) {
2393
+ stateMachine.transitionTo("BLOCKED");
2394
+ throw new Error(`[WORKFLOW BLOCKED] Security violation: current branch is protected '${currentBranch}'!`);
2316
2395
  }
2317
2396
  };
2318
2397
  await createSpecIfRequired(plan, classification, taskSlug, cwd);
@@ -2321,27 +2400,8 @@ async function runExecute({ cwd, naturalRequest, taskSlug: taskSlugOverride }) {
2321
2400
  readOnlyStateBefore = await captureReadOnlyState(cwd, fastTrack);
2322
2401
  }
2323
2402
  await runImplementation(plan, classification, delegationController, stateMachine, fastTrack);
2324
- if (!plan.branchNeeded) {
2325
- await runReadOnlyConfinementCheck(readOnlyStateBefore, cwd, stateMachine, fastTrack);
2326
- stateMachine.transitionTo("IMPLEMENTED");
2327
- stateMachine.transitionTo("VALIDATING");
2328
- stateMachine.transitionTo("COMPLETED");
2329
- console.log("\n--- Final Handoff ---");
2330
- console.log(`
2331
- [AI WORKFLOW COMPLETE] COMPLETED`);
2332
- console.log(`Handoff Packet: [IN-MEMORY] (No handoff file written in read-only mode)
2333
- `);
2334
- return {
2335
- overallStatus: "PASS",
2336
- evidence: {
2337
- internalStatus: "PASS",
2338
- commandsRun: []
2339
- },
2340
- quality: {
2341
- overallStatus: "PASS"
2342
- },
2343
- stateHistory: stateMachine.getHistory()
2344
- };
2403
+ if (!plan.branchNeeded && readOnlyStateBefore) {
2404
+ return await executeReadOnlyWorkflow(cwd, stateMachine, readOnlyStateBefore, fastTrack);
2345
2405
  }
2346
2406
  stateMachine.transitionTo("IMPLEMENTED");
2347
2407
  checkBranchSafety();
@@ -2369,7 +2429,6 @@ async function runExecute({ cwd, naturalRequest, taskSlug: taskSlugOverride }) {
2369
2429
  }
2370
2430
  checkBranchSafety();
2371
2431
  let integrity = { valid: true, changes: { added: [], modified: [], deleted: [] } };
2372
- let stabResult = result;
2373
2432
  if (!fastTrack) {
2374
2433
  const stab = await runFinalizerStabilization(
2375
2434
  plan,
@@ -2382,54 +2441,23 @@ async function runExecute({ cwd, naturalRequest, taskSlug: taskSlugOverride }) {
2382
2441
  snapshotRef,
2383
2442
  checkBranchSafety
2384
2443
  );
2385
- stabResult = stab.result;
2444
+ result = stab.result;
2386
2445
  integrity = stab.integrity;
2387
2446
  }
2388
- result = stabResult;
2389
2447
  let finalStatus = result.overallStatus;
2390
2448
  if (fastTrack) {
2391
- console.log(`
2392
- --- [FAST-TRACK] Running Lightweight Validation Gates ---`);
2393
- checkBranchSafety();
2394
- const changedFiles = result.evidence?.changedFiles || [];
2395
- console.log(`[FAST-TRACK] Changed files detected:`, changedFiles);
2396
- const evidencePath = path14.join(cwd, "EVIDENCE.json");
2397
- const hasEvidence = await fs12.access(evidencePath).then(() => true).catch(() => false);
2398
- if (hasEvidence) {
2399
- const { EvidenceValidator } = await import("../evidence-validator-76ZQQYDU.js");
2400
- const isTest = process.env.NODE_ENV === "test" || process.env.VITEST === "true";
2401
- const evidenceValidator = new EvidenceValidator({ cwd, skipFileCheck: isTest, skipGitCheck: isTest });
2402
- const valResult2 = await evidenceValidator.validate();
2403
- if (!valResult2.valid) {
2404
- console.error(`
2405
- [FAST-TRACK BLOCKED] EVIDENCE.json validation failed: ${valResult2.reason}`);
2406
- finalStatus = "FAIL_QUALITY_GATE";
2407
- }
2408
- }
2449
+ finalStatus = await runFastTrackValidation(cwd, result, checkBranchSafety);
2409
2450
  } else if (!integrity.valid) {
2410
2451
  console.log(`
2411
2452
  [FINALIZER BLOCKED] BLOCKED: workspace did not stabilize`);
2412
2453
  console.log(`Final changes detected:`, integrity.changes);
2413
2454
  finalStatus = "FAIL_QUALITY_GATE";
2414
2455
  } else {
2415
- const fidelityResult = await finalizer.verifyFidelity({
2416
- userRequest: naturalRequest,
2417
- projectContext: result.evidence?.deliveryDecision?.projectContext || null,
2418
- deliveryDecision: result.evidence?.deliveryDecision || null,
2419
- changedFiles: result.evidence?.changedFiles || [],
2420
- evidence: result.evidence || null,
2421
- explicitApprovals: process.env.AI_WORKFLOW_APPROVALS ? process.env.AI_WORKFLOW_APPROVALS.split(",").map((a) => a.trim()) : []
2422
- });
2423
- if (!fidelityResult.passed) {
2424
- console.log(`
2425
- [FINALIZER BLOCKED] BLOCKED: Artifact fidelity check failed!`);
2426
- console.log(`Reason: ${fidelityResult.reason}`);
2427
- finalStatus = "FAIL_QUALITY_GATE";
2428
- }
2456
+ finalStatus = await runFidelityValidation(naturalRequest, result, finalizer);
2429
2457
  }
2430
- const finalState = finalStatus === "PASS" ? "COMPLETED" : finalStatus === "PASS_WITH_NOTES" ? "COMPLETED_WITH_NOTES" : "BLOCKED";
2458
+ const finalState = computeFinalState(finalStatus);
2431
2459
  stateMachine.transitionTo(finalState);
2432
- const handoffPath = await generateFinalHandoff(plan, taskSlug, cwd, finalState, result.evidence);
2460
+ await generateFinalHandoff(plan, taskSlug, cwd, finalState, result.evidence);
2433
2461
  return { ...result, overallStatus: finalStatus, stateHistory: stateMachine.getHistory() };
2434
2462
  } finally {
2435
2463
  if (plan && !plan.branchNeeded) {
@@ -2589,19 +2617,9 @@ function parseFlags(args) {
2589
2617
  purgeAgents: args.includes("--purge-agents") || args.includes("--purge")
2590
2618
  };
2591
2619
  }
2592
- async function runCli(args) {
2593
- const [command] = args;
2594
- if (command === "--version" || command === "-v") {
2595
- console.log(getPackageVersion() || "unknown");
2596
- return;
2597
- }
2598
- if (!command || command === "--help" || command === "-h") {
2599
- printHelp();
2600
- return;
2601
- }
2602
- if (command === "execute") {
2603
- const flags = parseFlags(args.slice(1));
2604
- const positionals = args.slice(1).filter((arg) => !arg.startsWith("-"));
2620
+ var commandMap = {
2621
+ execute: async (args, flags) => {
2622
+ const positionals = args.filter((arg) => !arg.startsWith("-"));
2605
2623
  const request = flags.request || positionals.join(" ");
2606
2624
  const result = await runExecute({
2607
2625
  cwd: process.cwd(),
@@ -2611,25 +2629,23 @@ async function runCli(args) {
2611
2629
  if (result && (result.overallStatus === "FAIL_QUALITY_GATE" || result.overallStatus === "BLOCKED" || result.overallStatus === "FAIL")) {
2612
2630
  process.exit(1);
2613
2631
  }
2614
- return;
2615
- }
2616
- if (command === "run") {
2632
+ },
2633
+ run: async (_, flags) => {
2617
2634
  await runMasterOrchestrator({
2618
2635
  cwd: process.cwd(),
2619
- ...parseFlags(args.slice(1))
2636
+ ...flags
2620
2637
  });
2621
- return;
2622
- }
2623
- if (command === "init") {
2638
+ },
2639
+ init: async (_, flags) => {
2624
2640
  await runInit({
2625
2641
  cwd: process.cwd(),
2626
- ...parseFlags(args.slice(1))
2642
+ ...flags
2627
2643
  });
2628
- return;
2629
- }
2630
- if (command === "collect-evidence") {
2631
- const flags = parseFlags(args.slice(1));
2632
- if (flags.mode && !["quick", "standard", "full"].includes(flags.mode)) throw new Error("--mode must be quick, standard, or full");
2644
+ },
2645
+ "collect-evidence": async (_, flags) => {
2646
+ if (flags.mode && !["quick", "standard", "full"].includes(flags.mode)) {
2647
+ throw new Error("--mode must be quick, standard, or full");
2648
+ }
2633
2649
  await runCollectEvidence({
2634
2650
  cwd: process.cwd(),
2635
2651
  taskSlug: flags.taskSlug,
@@ -2639,11 +2655,9 @@ async function runCli(args) {
2639
2655
  visualDist: flags.visualDist,
2640
2656
  port: flags.port
2641
2657
  });
2642
- return;
2643
- }
2644
- if (command === "validate") {
2645
- const flags = parseFlags(args.slice(1));
2646
- const { runValidate } = await import("../validate-Q2NLLQ5G.js");
2658
+ },
2659
+ validate: async (_, flags) => {
2660
+ const { runValidate } = await import("../validate-A46WUBVZ.js");
2647
2661
  await runValidate({
2648
2662
  cwd: process.cwd(),
2649
2663
  taskSlug: flags.taskSlug,
@@ -2651,17 +2665,32 @@ async function runCli(args) {
2651
2665
  visualDist: flags.visualDist,
2652
2666
  port: flags.port
2653
2667
  });
2654
- return;
2655
- }
2656
- if (command === "doctor") {
2668
+ },
2669
+ doctor: async () => {
2657
2670
  await runDoctor({ cwd: process.cwd() });
2658
- return;
2659
- }
2660
- if (command === "clean") {
2671
+ },
2672
+ clean: async (_, flags) => {
2661
2673
  await runClean({
2662
2674
  cwd: process.cwd(),
2663
- ...parseFlags(args.slice(1))
2675
+ ...flags
2664
2676
  });
2677
+ }
2678
+ };
2679
+ async function runCli(args) {
2680
+ const [command] = args;
2681
+ if (command === "--version" || command === "-v") {
2682
+ console.log(getPackageVersion() || "unknown");
2683
+ return;
2684
+ }
2685
+ if (!command || command === "--help" || command === "-h") {
2686
+ printHelp();
2687
+ return;
2688
+ }
2689
+ const handler = commandMap[command];
2690
+ if (handler) {
2691
+ const argsSlice = args.slice(1);
2692
+ const flags = parseFlags(argsSlice);
2693
+ await handler(argsSlice, flags);
2665
2694
  return;
2666
2695
  }
2667
2696
  throw new Error(`unknown command: ${command}`);