@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 +5 -0
- package/bin/ai-workflow.js +231 -202
- package/bin/ai-workflow.js.map +1 -1
- package/{chunk-6EMG6FAO.js → chunk-BDZPUAEX.js} +2 -2
- package/{chunk-UHLZX2EG.js → chunk-W4RTQWVQ.js} +2 -2
- package/{chunk-2AOV2ATY.js → chunk-XW747GIG.js} +11 -5
- package/core/index.js +2 -2
- package/package.json +1 -1
- package/{validate-Q2NLLQ5G.js → validate-A46WUBVZ.js} +3 -3
package/CHANGELOG.md
CHANGED
package/bin/ai-workflow.js
CHANGED
|
@@ -21,13 +21,13 @@ import {
|
|
|
21
21
|
isTerminalFailure,
|
|
22
22
|
readPackageFile,
|
|
23
23
|
resolveWorkflowProfile
|
|
24
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-W4RTQWVQ.js";
|
|
25
25
|
import {
|
|
26
26
|
EvidenceCollector,
|
|
27
27
|
QualityGuard,
|
|
28
28
|
ValidationPlanner
|
|
29
|
-
} from "../chunk-
|
|
30
|
-
import "../chunk-
|
|
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
|
|
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
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
}
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
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
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
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
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
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
|
-
|
|
1602
|
-
|
|
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
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
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
|
-
|
|
1614
|
-
|
|
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
|
-
|
|
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
|
|
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 (
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
2458
|
+
const finalState = computeFinalState(finalStatus);
|
|
2431
2459
|
stateMachine.transitionTo(finalState);
|
|
2432
|
-
|
|
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
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
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
|
-
|
|
2615
|
-
|
|
2616
|
-
if (command === "run") {
|
|
2632
|
+
},
|
|
2633
|
+
run: async (_, flags) => {
|
|
2617
2634
|
await runMasterOrchestrator({
|
|
2618
2635
|
cwd: process.cwd(),
|
|
2619
|
-
...
|
|
2636
|
+
...flags
|
|
2620
2637
|
});
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
if (command === "init") {
|
|
2638
|
+
},
|
|
2639
|
+
init: async (_, flags) => {
|
|
2624
2640
|
await runInit({
|
|
2625
2641
|
cwd: process.cwd(),
|
|
2626
|
-
...
|
|
2642
|
+
...flags
|
|
2627
2643
|
});
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
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
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
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
|
-
|
|
2655
|
-
|
|
2656
|
-
if (command === "doctor") {
|
|
2668
|
+
},
|
|
2669
|
+
doctor: async () => {
|
|
2657
2670
|
await runDoctor({ cwd: process.cwd() });
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
if (command === "clean") {
|
|
2671
|
+
},
|
|
2672
|
+
clean: async (_, flags) => {
|
|
2661
2673
|
await runClean({
|
|
2662
2674
|
cwd: process.cwd(),
|
|
2663
|
-
...
|
|
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}`);
|