@williambeto/ai-workflow 2.8.2 → 2.9.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/CHANGELOG.md +41 -0
- package/bin/ai-workflow.js +226 -172
- package/bin/ai-workflow.js.map +1 -1
- package/{chunk-4FI5ODAM.js → chunk-JDSEOEYW.js} +253 -76
- package/core/index.d.ts +65 -21
- package/core/index.js +9 -3
- package/dist-assets/docs/cli-reference.md +4 -2
- package/dist-assets/docs/compatibility/provider-usage.md +13 -2
- package/dist-assets/docs/compatibility/runtime-matrix.md +4 -4
- package/package.json +1 -1
|
@@ -235,6 +235,8 @@ function isDestructiveCommand(command) {
|
|
|
235
235
|
return gitCommandIsDestructive(command);
|
|
236
236
|
}
|
|
237
237
|
var OpenCodeAdapter = class {
|
|
238
|
+
runtime = "opencode";
|
|
239
|
+
provenance = "opencode-adapter";
|
|
238
240
|
cwd;
|
|
239
241
|
constructor({ cwd = process.cwd() } = {}) {
|
|
240
242
|
this.cwd = cwd;
|
|
@@ -572,8 +574,153 @@ AIWK_ORCHESTRATED_CHILD: The parent execute process exclusively owns collect-evi
|
|
|
572
574
|
}
|
|
573
575
|
};
|
|
574
576
|
|
|
575
|
-
// src/core/
|
|
577
|
+
// src/core/runtime/codex-runtime-adapter.ts
|
|
578
|
+
import { spawnSync as spawnSync2, execSync as execSync2 } from "child_process";
|
|
576
579
|
import fs from "fs/promises";
|
|
580
|
+
import os from "os";
|
|
581
|
+
import path from "path";
|
|
582
|
+
var SPECIALIZED_AGENTS = /* @__PURE__ */ new Set(["Nexus", "Orion", "Astra", "Sage", "Phoenix"]);
|
|
583
|
+
function nativeAgentName(agent) {
|
|
584
|
+
return agent.trim().toLowerCase();
|
|
585
|
+
}
|
|
586
|
+
var CodexRuntimeAdapter = class {
|
|
587
|
+
runtime = "codex";
|
|
588
|
+
provenance = "codex-cli-jsonl";
|
|
589
|
+
cwd;
|
|
590
|
+
constructor({ cwd = process.cwd() } = {}) {
|
|
591
|
+
this.cwd = cwd;
|
|
592
|
+
}
|
|
593
|
+
async isProjectTrusted() {
|
|
594
|
+
const codexHome = process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
|
|
595
|
+
const configPath = path.join(codexHome, "config.toml");
|
|
596
|
+
const config = await fs.readFile(configPath, "utf8").catch(() => "");
|
|
597
|
+
if (!config) return false;
|
|
598
|
+
const normalizedCwd = path.resolve(this.cwd).replaceAll("\\", "\\\\");
|
|
599
|
+
const section = new RegExp(
|
|
600
|
+
`(?:^|\\n)\\[projects\\.${JSON.stringify(normalizedCwd).replace(/[.*+?^${}()|[\\]\\\\]/g, "\\\\$&")}\\]\\s*\\n([\\s\\S]*?)(?=\\n\\[|$)`,
|
|
601
|
+
"m"
|
|
602
|
+
).exec(config)?.[1] || "";
|
|
603
|
+
return /^trust_level\s*=\s*["']trusted["']\s*$/m.test(section);
|
|
604
|
+
}
|
|
605
|
+
async inspect() {
|
|
606
|
+
try {
|
|
607
|
+
const help = spawnSync2("codex", ["exec", "--help"], { encoding: "utf8" });
|
|
608
|
+
const available = help.status === 0;
|
|
609
|
+
const helpText = `${help.stdout || ""}
|
|
610
|
+
${help.stderr || ""}`;
|
|
611
|
+
const projectTrusted = await this.isProjectTrusted();
|
|
612
|
+
const configuredAgents = await Promise.all(
|
|
613
|
+
[...SPECIALIZED_AGENTS].map(
|
|
614
|
+
(agent) => fs.access(path.join(this.cwd, ".codex", "agents", `${nativeAgentName(agent)}.toml`)).then(() => true).catch(() => false)
|
|
615
|
+
)
|
|
616
|
+
);
|
|
617
|
+
return {
|
|
618
|
+
available,
|
|
619
|
+
supports: {
|
|
620
|
+
run: available,
|
|
621
|
+
server: false,
|
|
622
|
+
formatJson: /--json\b/.test(helpText),
|
|
623
|
+
agent: projectTrusted && configuredAgents.every(Boolean),
|
|
624
|
+
model: /--model\b/.test(helpText)
|
|
625
|
+
},
|
|
626
|
+
projectTrusted
|
|
627
|
+
};
|
|
628
|
+
} catch {
|
|
629
|
+
return {
|
|
630
|
+
available: false,
|
|
631
|
+
supports: { run: false, server: false, formatJson: false, agent: false, model: false },
|
|
632
|
+
projectTrusted: false
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
async execute(_message, { agent = null, readOnly = false } = {}) {
|
|
637
|
+
const inspection = await this.inspect();
|
|
638
|
+
const requestedAgent = agent || null;
|
|
639
|
+
if (!readOnly) {
|
|
640
|
+
let branch = "";
|
|
641
|
+
try {
|
|
642
|
+
branch = execSync2("git branch --show-current", { cwd: this.cwd, encoding: "utf8", stdio: "pipe" }).trim();
|
|
643
|
+
} catch {
|
|
644
|
+
}
|
|
645
|
+
if (["main", "master"].includes(branch) && process.env.AI_WORKFLOW_BYPASS_PROTECTED_BRANCH !== "true") {
|
|
646
|
+
return {
|
|
647
|
+
success: false,
|
|
648
|
+
status: "BLOCKED",
|
|
649
|
+
error: "FAIL_PROTECTED_BRANCH: Direct writes to protected branch are prohibited.",
|
|
650
|
+
commandsRun: [],
|
|
651
|
+
eventCount: 0,
|
|
652
|
+
runtimeAgentRequested: requestedAgent,
|
|
653
|
+
runtimeAgentApplied: null,
|
|
654
|
+
runtimeAgentSupported: inspection.supports.agent,
|
|
655
|
+
runtimeAgentSelectionMode: "native-delegation",
|
|
656
|
+
runtimeActorConfirmation: "unavailable",
|
|
657
|
+
output: ""
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
if (!inspection.available || !inspection.supports.formatJson) {
|
|
662
|
+
return {
|
|
663
|
+
success: false,
|
|
664
|
+
status: "BLOCKED",
|
|
665
|
+
error: "Codex CLI with `exec --json` is required for observed workflow execution.",
|
|
666
|
+
commandsRun: [],
|
|
667
|
+
eventCount: 0,
|
|
668
|
+
runtimeAgentRequested: requestedAgent,
|
|
669
|
+
runtimeAgentApplied: null,
|
|
670
|
+
runtimeAgentSupported: inspection.supports.agent,
|
|
671
|
+
runtimeAgentSelectionMode: "native-delegation",
|
|
672
|
+
runtimeActorConfirmation: "unavailable",
|
|
673
|
+
output: ""
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
if (inspection.projectTrusted === false) {
|
|
677
|
+
return {
|
|
678
|
+
success: false,
|
|
679
|
+
status: "BLOCKED",
|
|
680
|
+
error: "Codex project is not trusted; project-local native agents are disabled until the repository is trusted in Codex.",
|
|
681
|
+
commandsRun: [],
|
|
682
|
+
eventCount: 0,
|
|
683
|
+
runtimeAgentRequested: requestedAgent,
|
|
684
|
+
runtimeAgentApplied: null,
|
|
685
|
+
runtimeAgentSupported: false,
|
|
686
|
+
runtimeAgentSelectionMode: "unavailable",
|
|
687
|
+
runtimeActorConfirmation: "unavailable",
|
|
688
|
+
output: ""
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
if (!inspection.supports.agent) {
|
|
692
|
+
return {
|
|
693
|
+
success: false,
|
|
694
|
+
status: "BLOCKED",
|
|
695
|
+
error: "Codex native agent configuration is incomplete; cannot confirm the requested workflow owner.",
|
|
696
|
+
commandsRun: [],
|
|
697
|
+
eventCount: 0,
|
|
698
|
+
runtimeAgentRequested: requestedAgent,
|
|
699
|
+
runtimeAgentApplied: null,
|
|
700
|
+
runtimeAgentSupported: false,
|
|
701
|
+
runtimeAgentSelectionMode: "unavailable",
|
|
702
|
+
runtimeActorConfirmation: "unavailable",
|
|
703
|
+
output: ""
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
return {
|
|
707
|
+
success: false,
|
|
708
|
+
status: "BLOCKED",
|
|
709
|
+
error: "Codex CLI `exec` does not provide stable custom-agent selection and observed ownership. AI Workflow Kit blocks CLI delivery rather than claiming Astra execution. Use interactive Codex in this trusted repository; a future app-server adapter is required for CLI orchestration.",
|
|
710
|
+
commandsRun: [],
|
|
711
|
+
eventCount: 0,
|
|
712
|
+
runtimeAgentRequested: requestedAgent,
|
|
713
|
+
runtimeAgentApplied: null,
|
|
714
|
+
runtimeAgentSupported: true,
|
|
715
|
+
runtimeAgentSelectionMode: "unavailable",
|
|
716
|
+
runtimeActorConfirmation: "unavailable",
|
|
717
|
+
output: ""
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
|
|
722
|
+
// src/core/sdd/validator.ts
|
|
723
|
+
import fs2 from "fs/promises";
|
|
577
724
|
var SpecValidator = class {
|
|
578
725
|
validateContent(content, requiredStatus = "APPROVED") {
|
|
579
726
|
const title = content.split(/\r?\n/, 1)[0]?.trim() || "";
|
|
@@ -622,7 +769,7 @@ var SpecValidator = class {
|
|
|
622
769
|
*/
|
|
623
770
|
async validate(filePath) {
|
|
624
771
|
try {
|
|
625
|
-
const content = await
|
|
772
|
+
const content = await fs2.readFile(filePath, "utf8");
|
|
626
773
|
return this.validateContent(content, "APPROVED");
|
|
627
774
|
} catch (error) {
|
|
628
775
|
if (error.code === "ENOENT") {
|
|
@@ -634,9 +781,9 @@ var SpecValidator = class {
|
|
|
634
781
|
};
|
|
635
782
|
|
|
636
783
|
// src/core/handoff/handoff-engine.ts
|
|
637
|
-
import { execSync as
|
|
638
|
-
import
|
|
639
|
-
import
|
|
784
|
+
import { execSync as execSync3 } from "child_process";
|
|
785
|
+
import fs3 from "fs/promises";
|
|
786
|
+
import path2 from "path";
|
|
640
787
|
var HandoffEngine = class {
|
|
641
788
|
cwd;
|
|
642
789
|
constructor({ cwd }) {
|
|
@@ -649,9 +796,9 @@ var HandoffEngine = class {
|
|
|
649
796
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
650
797
|
let specsContent = "";
|
|
651
798
|
for (const specPath of specPaths) {
|
|
652
|
-
const absolutePath =
|
|
799
|
+
const absolutePath = path2.isAbsolute(specPath) ? specPath : path2.join(this.cwd, specPath);
|
|
653
800
|
try {
|
|
654
|
-
const content = await
|
|
801
|
+
const content = await fs3.readFile(absolutePath, "utf8");
|
|
655
802
|
specsContent += `### File: ${specPath}
|
|
656
803
|
|
|
657
804
|
${content}
|
|
@@ -667,7 +814,7 @@ ${content}
|
|
|
667
814
|
}
|
|
668
815
|
let gitDiff = "No changes detected.";
|
|
669
816
|
try {
|
|
670
|
-
gitDiff =
|
|
817
|
+
gitDiff = execSync3("git diff HEAD", { cwd: this.cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim() || "No changes detected.";
|
|
671
818
|
} catch (err) {
|
|
672
819
|
gitDiff = `[Error capturing diff: ${err.message}]`;
|
|
673
820
|
}
|
|
@@ -678,9 +825,9 @@ ${content}
|
|
|
678
825
|
evidenceJson = JSON.stringify(data, null, 2);
|
|
679
826
|
evidenceSummary = `Status: ${data.status || data.internalStatus || "unknown"}, Commands: ${data.commands?.length || 0}`;
|
|
680
827
|
} else {
|
|
681
|
-
const evidencePath =
|
|
828
|
+
const evidencePath = path2.join(this.cwd, "EVIDENCE.json");
|
|
682
829
|
try {
|
|
683
|
-
const content = await
|
|
830
|
+
const content = await fs3.readFile(evidencePath, "utf8");
|
|
684
831
|
const data = JSON.parse(content);
|
|
685
832
|
evidenceJson = JSON.stringify(data, null, 2);
|
|
686
833
|
evidenceSummary = `Status: ${data.status}, Commands: ${data.commands?.length || 0}`;
|
|
@@ -688,16 +835,16 @@ ${content}
|
|
|
688
835
|
}
|
|
689
836
|
}
|
|
690
837
|
const possibleTemplatePaths = [
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
838
|
+
path2.join(this.cwd, ".ai-workflow/templates/HANDOFF.template.md"),
|
|
839
|
+
path2.join(this.cwd, ".ai-workflow/harness/handoffs/HANDOFF.template.md"),
|
|
840
|
+
path2.join(getPackageRoot(), "dist-assets/templates/HANDOFF.template.md"),
|
|
841
|
+
path2.join(getPackageRoot(), "dist-assets/harness/handoffs/HANDOFF.template.md")
|
|
695
842
|
];
|
|
696
843
|
let template = null;
|
|
697
844
|
let lastError = null;
|
|
698
845
|
for (const tPath of possibleTemplatePaths) {
|
|
699
846
|
try {
|
|
700
|
-
template = await
|
|
847
|
+
template = await fs3.readFile(tPath, "utf8");
|
|
701
848
|
break;
|
|
702
849
|
} catch (err) {
|
|
703
850
|
lastError = err;
|
|
@@ -709,18 +856,18 @@ ${possibleTemplatePaths.join("\n")}
|
|
|
709
856
|
Last error: ${lastError?.message}`);
|
|
710
857
|
}
|
|
711
858
|
const packet = template.replace("${TASK_ID}", taskId || "unknown").replace("${TIMESTAMP}", timestamp).replace("${AUTHOR}", author || "AI Workflow Kit").replace("${STATUS}", status || "IN_PROGRESS").replace("${SPECS_CONTENT}", specsContent || "No specs provided.").replace("${EVIDENCE_SUMMARY}", evidenceSummary).replace("${EVIDENCE_JSON}", evidenceJson).replace("${GIT_DIFF}", gitDiff).replace("${NEXT_ACTIONS}", nextActions || "Awaiting manager assignment.");
|
|
712
|
-
const handoffDir =
|
|
713
|
-
await
|
|
859
|
+
const handoffDir = path2.join(this.cwd, ".ai-workflow/handoffs");
|
|
860
|
+
await fs3.mkdir(handoffDir, { recursive: true });
|
|
714
861
|
const packetName = `HANDOFF-${taskId || "TMP"}-${Date.now()}.md`;
|
|
715
|
-
const packetPath =
|
|
716
|
-
await
|
|
862
|
+
const packetPath = path2.join(handoffDir, packetName);
|
|
863
|
+
await fs3.writeFile(packetPath, packet);
|
|
717
864
|
return packetPath;
|
|
718
865
|
}
|
|
719
866
|
};
|
|
720
867
|
|
|
721
868
|
// src/core/healing/healer-engine.ts
|
|
722
|
-
import
|
|
723
|
-
import
|
|
869
|
+
import fs4 from "fs/promises";
|
|
870
|
+
import path3 from "path";
|
|
724
871
|
import crypto from "crypto";
|
|
725
872
|
|
|
726
873
|
// src/core/statuses.ts
|
|
@@ -793,7 +940,7 @@ var HealerEngine = class {
|
|
|
793
940
|
this.ledger = ledger;
|
|
794
941
|
}
|
|
795
942
|
get statePath() {
|
|
796
|
-
return
|
|
943
|
+
return path3.join(this.cwd, ".ai-workflow", `healing-state-${this.taskSlug}.json`);
|
|
797
944
|
}
|
|
798
945
|
fingerprint(result) {
|
|
799
946
|
return crypto.createHash("sha256").update(stableJson(collectBlockingFindings(result))).digest("hex");
|
|
@@ -813,18 +960,18 @@ var HealerEngine = class {
|
|
|
813
960
|
return false;
|
|
814
961
|
}
|
|
815
962
|
async writeState(state) {
|
|
816
|
-
await
|
|
817
|
-
await
|
|
963
|
+
await fs4.mkdir(path3.dirname(this.statePath), { recursive: true });
|
|
964
|
+
await fs4.writeFile(this.statePath, JSON.stringify(state, null, 2));
|
|
818
965
|
}
|
|
819
966
|
async resetState() {
|
|
820
967
|
try {
|
|
821
|
-
await
|
|
968
|
+
await fs4.unlink(this.statePath);
|
|
822
969
|
} catch {
|
|
823
970
|
}
|
|
824
971
|
}
|
|
825
972
|
async writeRemediationRequest({ attempt, result }) {
|
|
826
|
-
const requestPath =
|
|
827
|
-
await
|
|
973
|
+
const requestPath = path3.join(this.cwd, ".ai-workflow", "remediation-request.json");
|
|
974
|
+
await fs4.mkdir(path3.dirname(requestPath), { recursive: true });
|
|
828
975
|
const request = {
|
|
829
976
|
taskSlug: this.taskSlug,
|
|
830
977
|
executionMode: this.mode,
|
|
@@ -835,7 +982,7 @@ var HealerEngine = class {
|
|
|
835
982
|
findingsFingerprint: this.fingerprint(result),
|
|
836
983
|
instruction: "Apply the smallest safe correction for the listed gates, then rerun validation. Do not broaden scope."
|
|
837
984
|
};
|
|
838
|
-
await
|
|
985
|
+
await fs4.writeFile(requestPath, JSON.stringify(request, null, 2));
|
|
839
986
|
return requestPath;
|
|
840
987
|
}
|
|
841
988
|
async run({
|
|
@@ -942,8 +1089,8 @@ var HealerEngine = class {
|
|
|
942
1089
|
};
|
|
943
1090
|
|
|
944
1091
|
// src/core/evidence/evidence-ledger.ts
|
|
945
|
-
import
|
|
946
|
-
import
|
|
1092
|
+
import fs5 from "fs/promises";
|
|
1093
|
+
import path4 from "path";
|
|
947
1094
|
import { createHash } from "crypto";
|
|
948
1095
|
var EvidenceLedger = class {
|
|
949
1096
|
cwd;
|
|
@@ -996,8 +1143,8 @@ var EvidenceLedger = class {
|
|
|
996
1143
|
* Saves the ledger events to a JSON file.
|
|
997
1144
|
*/
|
|
998
1145
|
async save(filePath) {
|
|
999
|
-
const targetPath =
|
|
1000
|
-
await
|
|
1146
|
+
const targetPath = path4.isAbsolute(filePath) ? filePath : path4.join(this.cwd, filePath);
|
|
1147
|
+
await fs5.mkdir(path4.dirname(targetPath), { recursive: true });
|
|
1001
1148
|
for (const event of this.events) {
|
|
1002
1149
|
if (event.workflowId !== this.workflowId) {
|
|
1003
1150
|
throw new Error(`Ledger workflowId conflict: '${event.workflowId}' does not match '${this.workflowId}'.`);
|
|
@@ -1005,9 +1152,9 @@ var EvidenceLedger = class {
|
|
|
1005
1152
|
}
|
|
1006
1153
|
const serialized = JSON.stringify(this.events, null, 2);
|
|
1007
1154
|
const contentHash = createHash("sha256").update(serialized).digest("hex");
|
|
1008
|
-
const targetExists = await
|
|
1155
|
+
const targetExists = await fs5.access(targetPath).then(() => true).catch(() => false);
|
|
1009
1156
|
if (targetExists) {
|
|
1010
|
-
const diskHash = createHash("sha256").update(await
|
|
1157
|
+
const diskHash = createHash("sha256").update(await fs5.readFile(targetPath)).digest("hex");
|
|
1011
1158
|
if (this.loadedPath !== targetPath || this.loadedContentHash === null || diskHash !== this.loadedContentHash) {
|
|
1012
1159
|
throw new Error(`Ledger changed on disk or was not loaded before update: '${targetPath}'.`);
|
|
1013
1160
|
}
|
|
@@ -1016,20 +1163,20 @@ var EvidenceLedger = class {
|
|
|
1016
1163
|
}
|
|
1017
1164
|
const temporaryPath = `${targetPath}.${process.pid}.${Date.now()}.tmp`;
|
|
1018
1165
|
try {
|
|
1019
|
-
await
|
|
1020
|
-
await
|
|
1166
|
+
await fs5.writeFile(temporaryPath, serialized, { encoding: "utf8", flag: "wx" });
|
|
1167
|
+
await fs5.rename(temporaryPath, targetPath);
|
|
1021
1168
|
this.loadedPath = targetPath;
|
|
1022
1169
|
this.loadedContentHash = contentHash;
|
|
1023
1170
|
} catch (error) {
|
|
1024
|
-
await
|
|
1171
|
+
await fs5.rm(temporaryPath, { force: true }).catch(() => {
|
|
1025
1172
|
});
|
|
1026
1173
|
throw error;
|
|
1027
1174
|
}
|
|
1028
1175
|
}
|
|
1029
1176
|
async load(filePath) {
|
|
1030
|
-
const targetPath =
|
|
1177
|
+
const targetPath = path4.isAbsolute(filePath) ? filePath : path4.join(this.cwd, filePath);
|
|
1031
1178
|
try {
|
|
1032
|
-
const content = await
|
|
1179
|
+
const content = await fs5.readFile(targetPath, "utf8");
|
|
1033
1180
|
const parsed = JSON.parse(content);
|
|
1034
1181
|
if (!Array.isArray(parsed) || parsed.some((event) => event.workflowId !== this.workflowId)) {
|
|
1035
1182
|
throw new Error(`Ledger is incompatible with workflow '${this.workflowId}'.`);
|
|
@@ -1157,9 +1304,9 @@ var DelegationController = class {
|
|
|
1157
1304
|
actor: supported ? actor : "Atlas",
|
|
1158
1305
|
actorType: supported ? "runtime-agent" : "control-plane",
|
|
1159
1306
|
observed: true,
|
|
1160
|
-
runtime:
|
|
1307
|
+
runtime: this.adapter.runtime,
|
|
1161
1308
|
eventType: startType,
|
|
1162
|
-
provenance:
|
|
1309
|
+
provenance: this.adapter.provenance,
|
|
1163
1310
|
data: {
|
|
1164
1311
|
phase,
|
|
1165
1312
|
runtimeAgentRequested: actor,
|
|
@@ -1190,7 +1337,7 @@ var DelegationController = class {
|
|
|
1190
1337
|
runResult = await this.adapter.execute(prompt, { agent: actor, readOnly, requireActorConfirmation: true, orchestratedChild: true });
|
|
1191
1338
|
}
|
|
1192
1339
|
if (runResult.success && requireExplicitActor) {
|
|
1193
|
-
if (!["explicit", "sdk-session"].includes(runResult.runtimeAgentSelectionMode || "") || runResult.runtimeAgentApplied !== actor || runResult.runtimeActorConfirmation !== "confirmed") {
|
|
1340
|
+
if (!["explicit", "sdk-session", "native-delegation"].includes(runResult.runtimeAgentSelectionMode || "") || runResult.runtimeAgentApplied !== actor || runResult.runtimeActorConfirmation !== "confirmed") {
|
|
1194
1341
|
runResult = {
|
|
1195
1342
|
...runResult,
|
|
1196
1343
|
success: false,
|
|
@@ -1216,9 +1363,9 @@ var DelegationController = class {
|
|
|
1216
1363
|
actor: runResult.runtimeAgentApplied === actor ? actor : "Atlas",
|
|
1217
1364
|
actorType: runResult.runtimeAgentApplied === actor ? "runtime-agent" : "control-plane",
|
|
1218
1365
|
observed: true,
|
|
1219
|
-
runtime:
|
|
1366
|
+
runtime: this.adapter.runtime,
|
|
1220
1367
|
eventType: completeType,
|
|
1221
|
-
provenance:
|
|
1368
|
+
provenance: this.adapter.provenance,
|
|
1222
1369
|
data: {
|
|
1223
1370
|
phase,
|
|
1224
1371
|
success: runResult.success,
|
|
@@ -1261,9 +1408,9 @@ var DelegationController = class {
|
|
|
1261
1408
|
actor: canApply ? owner : "Atlas",
|
|
1262
1409
|
actorType: canApply ? "runtime-agent" : "control-plane",
|
|
1263
1410
|
observed: true,
|
|
1264
|
-
runtime:
|
|
1411
|
+
runtime: this.adapter.runtime,
|
|
1265
1412
|
eventType: "implementation_start",
|
|
1266
|
-
provenance:
|
|
1413
|
+
provenance: this.adapter.provenance,
|
|
1267
1414
|
data: {
|
|
1268
1415
|
agent: owner,
|
|
1269
1416
|
prompt: promptMsg,
|
|
@@ -1287,9 +1434,9 @@ var DelegationController = class {
|
|
|
1287
1434
|
actor: isApplied ? owner : "Atlas",
|
|
1288
1435
|
actorType: isApplied ? "runtime-agent" : "control-plane",
|
|
1289
1436
|
observed: true,
|
|
1290
|
-
runtime:
|
|
1437
|
+
runtime: this.adapter.runtime,
|
|
1291
1438
|
eventType: "implementation_complete",
|
|
1292
|
-
provenance:
|
|
1439
|
+
provenance: this.adapter.provenance,
|
|
1293
1440
|
data: {
|
|
1294
1441
|
success: runResult.success,
|
|
1295
1442
|
commandsRun: runResult.commandsRun || [],
|
|
@@ -1337,9 +1484,9 @@ var DelegationController = class {
|
|
|
1337
1484
|
actor: canApply ? "Sage" : "Atlas",
|
|
1338
1485
|
actorType: canApply ? "auditor" : "control-plane",
|
|
1339
1486
|
observed: true,
|
|
1340
|
-
runtime:
|
|
1487
|
+
runtime: this.adapter.runtime,
|
|
1341
1488
|
eventType: "validation_start",
|
|
1342
|
-
provenance:
|
|
1489
|
+
provenance: this.adapter.provenance,
|
|
1343
1490
|
data: {
|
|
1344
1491
|
agent: "Sage",
|
|
1345
1492
|
event: "validation.started",
|
|
@@ -1357,8 +1504,8 @@ var DelegationController = class {
|
|
|
1357
1504
|
}
|
|
1358
1505
|
let gitDiff = "";
|
|
1359
1506
|
try {
|
|
1360
|
-
const { execSync:
|
|
1361
|
-
gitDiff =
|
|
1507
|
+
const { execSync: execSync6 } = await import("child_process");
|
|
1508
|
+
gitDiff = execSync6("git diff HEAD", { cwd: this.cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
1362
1509
|
} catch {
|
|
1363
1510
|
}
|
|
1364
1511
|
const prompt = `Please validate the implementation. Diff:
|
|
@@ -1372,9 +1519,9 @@ ${JSON.stringify(result, null, 2)}`;
|
|
|
1372
1519
|
actor: isApplied ? "Sage" : "Atlas",
|
|
1373
1520
|
actorType: isApplied ? "auditor" : "control-plane",
|
|
1374
1521
|
observed: true,
|
|
1375
|
-
runtime:
|
|
1522
|
+
runtime: this.adapter.runtime,
|
|
1376
1523
|
eventType: "validation_complete",
|
|
1377
|
-
provenance:
|
|
1524
|
+
provenance: this.adapter.provenance,
|
|
1378
1525
|
data: {
|
|
1379
1526
|
success: runResult.success,
|
|
1380
1527
|
commandsRun: runResult.commandsRun || [],
|
|
@@ -1401,11 +1548,38 @@ ${JSON.stringify(result, null, 2)}`;
|
|
|
1401
1548
|
}
|
|
1402
1549
|
};
|
|
1403
1550
|
|
|
1551
|
+
// src/core/runtime/runtime-factory.ts
|
|
1552
|
+
import fs6 from "fs/promises";
|
|
1553
|
+
import path5 from "path";
|
|
1554
|
+
function isRuntimeName(value) {
|
|
1555
|
+
return value === "opencode" || value === "codex";
|
|
1556
|
+
}
|
|
1557
|
+
async function resolveRuntime({ cwd, runtime }) {
|
|
1558
|
+
if (runtime !== void 0) {
|
|
1559
|
+
if (!isRuntimeName(runtime)) {
|
|
1560
|
+
throw new Error(`Unsupported runtime '${runtime}'. Expected opencode or codex.`);
|
|
1561
|
+
}
|
|
1562
|
+
return runtime;
|
|
1563
|
+
}
|
|
1564
|
+
try {
|
|
1565
|
+
const raw = await fs6.readFile(path5.join(cwd, ".ai-workflow", "config.json"), "utf8");
|
|
1566
|
+
const config = JSON.parse(raw);
|
|
1567
|
+
const configured = typeof config.runtime === "string" ? config.runtime.split("+").map((item) => item.trim()) : [];
|
|
1568
|
+
if (configured.length === 1 && configured[0] === "codex") return "codex";
|
|
1569
|
+
} catch {
|
|
1570
|
+
}
|
|
1571
|
+
return "opencode";
|
|
1572
|
+
}
|
|
1573
|
+
async function createRuntimeAdapter(options) {
|
|
1574
|
+
const runtime = await resolveRuntime(options);
|
|
1575
|
+
return runtime === "codex" ? new CodexRuntimeAdapter({ cwd: options.cwd }) : new OpenCodeAdapter({ cwd: options.cwd });
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1404
1578
|
// src/core/finalization/workspace-snapshot.ts
|
|
1405
|
-
import
|
|
1406
|
-
import
|
|
1579
|
+
import fs7 from "fs/promises";
|
|
1580
|
+
import path6 from "path";
|
|
1407
1581
|
import crypto2 from "crypto";
|
|
1408
|
-
import { execFileSync, execSync as
|
|
1582
|
+
import { execFileSync, execSync as execSync4 } from "child_process";
|
|
1409
1583
|
var WorkspaceSnapshot = class {
|
|
1410
1584
|
cwd;
|
|
1411
1585
|
fastTrack;
|
|
@@ -1437,7 +1611,7 @@ var WorkspaceSnapshot = class {
|
|
|
1437
1611
|
}
|
|
1438
1612
|
const execGit = (args) => {
|
|
1439
1613
|
try {
|
|
1440
|
-
return
|
|
1614
|
+
return execSync4(`git ${args}`, { cwd: this.cwd, encoding: "utf8", stdio: "pipe" }).trim();
|
|
1441
1615
|
} catch {
|
|
1442
1616
|
return "";
|
|
1443
1617
|
}
|
|
@@ -1483,10 +1657,10 @@ var WorkspaceSnapshot = class {
|
|
|
1483
1657
|
const normalizedPath = relativePath.replaceAll("\\", "/");
|
|
1484
1658
|
if (this.isIgnored(normalizedPath)) continue;
|
|
1485
1659
|
try {
|
|
1486
|
-
const fullPath =
|
|
1487
|
-
const stat = await
|
|
1660
|
+
const fullPath = path6.join(this.cwd, relativePath);
|
|
1661
|
+
const stat = await fs7.stat(fullPath);
|
|
1488
1662
|
if (!stat.isFile()) continue;
|
|
1489
|
-
const content = await
|
|
1663
|
+
const content = await fs7.readFile(fullPath);
|
|
1490
1664
|
const sha256 = crypto2.createHash("sha256").update(content).digest("hex");
|
|
1491
1665
|
const isExecutable = (stat.mode & 73) !== 0;
|
|
1492
1666
|
const mode = isExecutable ? "100755" : "100644";
|
|
@@ -1497,10 +1671,10 @@ var WorkspaceSnapshot = class {
|
|
|
1497
1671
|
}
|
|
1498
1672
|
async scanDir(dir, filesMap) {
|
|
1499
1673
|
try {
|
|
1500
|
-
const entries = await
|
|
1674
|
+
const entries = await fs7.readdir(dir, { withFileTypes: true });
|
|
1501
1675
|
for (const entry of entries) {
|
|
1502
|
-
const fullPath =
|
|
1503
|
-
const relativePath =
|
|
1676
|
+
const fullPath = path6.join(dir, entry.name);
|
|
1677
|
+
const relativePath = path6.relative(this.cwd, fullPath);
|
|
1504
1678
|
if (this.isIgnored(relativePath)) {
|
|
1505
1679
|
continue;
|
|
1506
1680
|
}
|
|
@@ -1508,8 +1682,8 @@ var WorkspaceSnapshot = class {
|
|
|
1508
1682
|
await this.scanDir(fullPath, filesMap);
|
|
1509
1683
|
} else if (entry.isFile()) {
|
|
1510
1684
|
try {
|
|
1511
|
-
const stat = await
|
|
1512
|
-
const content = await
|
|
1685
|
+
const stat = await fs7.stat(fullPath);
|
|
1686
|
+
const content = await fs7.readFile(fullPath);
|
|
1513
1687
|
const sha256 = crypto2.createHash("sha256").update(content).digest("hex");
|
|
1514
1688
|
const isExecutable = (stat.mode & 73) !== 0;
|
|
1515
1689
|
const mode = isExecutable ? "100755" : "100644";
|
|
@@ -1543,9 +1717,9 @@ var WorkspaceSnapshot = class {
|
|
|
1543
1717
|
};
|
|
1544
1718
|
|
|
1545
1719
|
// src/core/finalization/finalizer.ts
|
|
1546
|
-
import { execSync as
|
|
1547
|
-
import
|
|
1548
|
-
import
|
|
1720
|
+
import { execSync as execSync5 } from "child_process";
|
|
1721
|
+
import path7 from "path";
|
|
1722
|
+
import fs8 from "fs/promises";
|
|
1549
1723
|
var Finalizer = class {
|
|
1550
1724
|
cwd;
|
|
1551
1725
|
snapshotManager;
|
|
@@ -1558,9 +1732,9 @@ var Finalizer = class {
|
|
|
1558
1732
|
getChangedFilesFromGit() {
|
|
1559
1733
|
try {
|
|
1560
1734
|
const files = /* @__PURE__ */ new Set();
|
|
1561
|
-
const diff =
|
|
1735
|
+
const diff = execSync5("git diff --name-only HEAD", { cwd: this.cwd, encoding: "utf8" });
|
|
1562
1736
|
diff.split("\n").map((f) => f.trim()).filter(Boolean).forEach((f) => files.add(f));
|
|
1563
|
-
const status =
|
|
1737
|
+
const status = execSync5("git status --short --untracked-files=all", { cwd: this.cwd, encoding: "utf8" });
|
|
1564
1738
|
status.split("\n").forEach((line) => {
|
|
1565
1739
|
const match = line.match(/^(?:[ MADRCU?!]{2}\s+|[MADRCU?!]\s+)(.+)$/);
|
|
1566
1740
|
if (match) {
|
|
@@ -1618,8 +1792,8 @@ var Finalizer = class {
|
|
|
1618
1792
|
const verifyResult = await fidelityGate.verify(filesToCheck);
|
|
1619
1793
|
let passed = requestFidelity.passed && verifyResult.passed;
|
|
1620
1794
|
let reason = !requestFidelity.passed ? requestFidelity.reason : verifyResult.reason;
|
|
1621
|
-
const evidencePath =
|
|
1622
|
-
const hasEvidence = await
|
|
1795
|
+
const evidencePath = path7.join(this.cwd, "EVIDENCE.json");
|
|
1796
|
+
const hasEvidence = await fs8.access(evidencePath).then(() => true).catch(() => false);
|
|
1623
1797
|
if (hasEvidence) {
|
|
1624
1798
|
const { EvidenceValidator } = await import("./evidence-validator-HS3NTWAB.js");
|
|
1625
1799
|
const isTest = process.env.NODE_ENV === "test" || process.env.VITEST === "true";
|
|
@@ -1827,7 +2001,7 @@ var RequestClassifier = class {
|
|
|
1827
2001
|
};
|
|
1828
2002
|
|
|
1829
2003
|
// src/core/execution-planner.ts
|
|
1830
|
-
import
|
|
2004
|
+
import path8 from "path";
|
|
1831
2005
|
var ExecutionPlanner = class {
|
|
1832
2006
|
cwd;
|
|
1833
2007
|
constructor({ cwd = process.cwd() } = {}) {
|
|
@@ -1839,7 +2013,7 @@ var ExecutionPlanner = class {
|
|
|
1839
2013
|
plan(classification, taskSlug = "task") {
|
|
1840
2014
|
const remediationLimit = classification.remediationLimit;
|
|
1841
2015
|
const branchNeeded = classification.intent === "write";
|
|
1842
|
-
const specPath = classification.specNeeded ?
|
|
2016
|
+
const specPath = classification.specNeeded ? path8.join("docs/workflows", taskSlug, "spec.md") : null;
|
|
1843
2017
|
const owner = classification.routingDecision?.mutationOwner === "Astra" ? "Astra" : classification.routingDecision?.selectedActor || (classification.intent === "write" ? "Astra" : classification.owner);
|
|
1844
2018
|
const validationsExpected = [];
|
|
1845
2019
|
if (classification.validationNeeded) {
|
|
@@ -1932,6 +2106,7 @@ export {
|
|
|
1932
2106
|
isTerminalFailure,
|
|
1933
2107
|
COMPLETION_STATUS_TEXT,
|
|
1934
2108
|
OpenCodeAdapter,
|
|
2109
|
+
CodexRuntimeAdapter,
|
|
1935
2110
|
SpecValidator,
|
|
1936
2111
|
HandoffEngine,
|
|
1937
2112
|
HealerEngine,
|
|
@@ -1939,9 +2114,11 @@ export {
|
|
|
1939
2114
|
resolveWorkflowProfile,
|
|
1940
2115
|
EvidenceLedger,
|
|
1941
2116
|
DelegationController,
|
|
2117
|
+
resolveRuntime,
|
|
2118
|
+
createRuntimeAdapter,
|
|
1942
2119
|
Finalizer,
|
|
1943
2120
|
RequestClassifier,
|
|
1944
2121
|
ExecutionPlanner,
|
|
1945
2122
|
WorkflowStateMachine
|
|
1946
2123
|
};
|
|
1947
|
-
//# sourceMappingURL=chunk-
|
|
2124
|
+
//# sourceMappingURL=chunk-JDSEOEYW.js.map
|