@akagilnc/pi-workflow-roles 0.1.3999 → 0.1.4021
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/dist/acp-host/production-host.js +10 -0
- package/dist/headless-host/description.js +319 -21
- package/dist/headless-host/production-host.js +462 -52
- package/dist/host-descriptions.js +19 -6
- package/dist/public-cli/main.js +10 -0
- package/package.json +1 -1
- package/src/headless-host/description.ts +381 -20
- package/src/headless-host/production-host.ts +5 -5
- package/src/headless-host/role-turn-host.ts +290 -27
- package/src/host-descriptions.ts +20 -7
|
@@ -417,7 +417,7 @@ function normalizeReviewComment(raw) {
|
|
|
417
417
|
function createGhApiRunner(options = {}) {
|
|
418
418
|
const spawnImpl = options.spawnImpl ?? spawn;
|
|
419
419
|
return async (args, runOptions = {}) => {
|
|
420
|
-
return await new Promise((
|
|
420
|
+
return await new Promise((resolve21, reject) => {
|
|
421
421
|
const signal = runOptions.signal;
|
|
422
422
|
if (signal?.aborted) {
|
|
423
423
|
reject(signal.reason ?? new Error("aborted"));
|
|
@@ -490,11 +490,11 @@ function createGhApiRunner(options = {}) {
|
|
|
490
490
|
const value = line2.slice(idx + 1).trim();
|
|
491
491
|
headers[name] = value;
|
|
492
492
|
}
|
|
493
|
-
|
|
493
|
+
resolve21({ status, headers, bodyText });
|
|
494
494
|
return;
|
|
495
495
|
}
|
|
496
496
|
if (code === 0) {
|
|
497
|
-
|
|
497
|
+
resolve21({ status: 200, headers: {}, bodyText: stdout });
|
|
498
498
|
return;
|
|
499
499
|
}
|
|
500
500
|
const failure2 = new Error(
|
|
@@ -1549,7 +1549,7 @@ async function spawnEngineDetourOnce(input) {
|
|
|
1549
1549
|
}
|
|
1550
1550
|
const command = input.argv[0];
|
|
1551
1551
|
const args = input.argv.slice(1);
|
|
1552
|
-
return await new Promise((
|
|
1552
|
+
return await new Promise((resolve21, reject) => {
|
|
1553
1553
|
let settled = false;
|
|
1554
1554
|
const signal = input.signal;
|
|
1555
1555
|
const child = spawn2(command, args, {
|
|
@@ -1579,7 +1579,7 @@ async function spawnEngineDetourOnce(input) {
|
|
|
1579
1579
|
if (signal !== void 0) {
|
|
1580
1580
|
signal.removeEventListener("abort", onAbort);
|
|
1581
1581
|
}
|
|
1582
|
-
|
|
1582
|
+
resolve21(result);
|
|
1583
1583
|
};
|
|
1584
1584
|
const onAbort = () => {
|
|
1585
1585
|
fail4(signal !== void 0 ? abortReasonError(signal) : new Error("aborted"));
|
|
@@ -3195,6 +3195,7 @@ var init_host_descriptions = __esm({
|
|
|
3195
3195
|
});
|
|
3196
3196
|
HEADLESS_HOST_DESCRIPTIONS = Object.freeze({
|
|
3197
3197
|
"claude": Object.freeze({
|
|
3198
|
+
protocol: "claude-print",
|
|
3198
3199
|
binaryFromHome: Object.freeze([".local", "bin", "claude"]),
|
|
3199
3200
|
sessionBindingFile: "claude-headless-session.json",
|
|
3200
3201
|
fixedArgs: Object.freeze([
|
|
@@ -3220,6 +3221,15 @@ var init_host_descriptions = __esm({
|
|
|
3220
3221
|
mcpConfigFlag: "--mcp-config",
|
|
3221
3222
|
sessionIdFlag: "--session-id",
|
|
3222
3223
|
resumeFlag: "--resume"
|
|
3224
|
+
}),
|
|
3225
|
+
/**
|
|
3226
|
+
* Codex headless (#646). Binary under operator home; auth stays in CODEX_HOME.
|
|
3227
|
+
* Argv/parse/schema-close are codex-exec helpers — not Claude flag mapping.
|
|
3228
|
+
*/
|
|
3229
|
+
"codex": Object.freeze({
|
|
3230
|
+
protocol: "codex-exec",
|
|
3231
|
+
binaryFromHome: Object.freeze([".local", "bin", "codex"]),
|
|
3232
|
+
sessionBindingFile: "codex-headless-session.json"
|
|
3223
3233
|
})
|
|
3224
3234
|
});
|
|
3225
3235
|
}
|
|
@@ -10976,12 +10986,12 @@ function createSystemCollectorClock() {
|
|
|
10976
10986
|
return {
|
|
10977
10987
|
wallNow: () => /* @__PURE__ */ new Date(),
|
|
10978
10988
|
monoNow: () => Number(process.hrtime.bigint() - start) / 1e6,
|
|
10979
|
-
sleep: (ms, signal) => new Promise((
|
|
10989
|
+
sleep: (ms, signal) => new Promise((resolve21, reject) => {
|
|
10980
10990
|
if (signal?.aborted) {
|
|
10981
10991
|
reject(signal.reason ?? new Error("aborted"));
|
|
10982
10992
|
return;
|
|
10983
10993
|
}
|
|
10984
|
-
const timer = setTimeout(
|
|
10994
|
+
const timer = setTimeout(resolve21, ms);
|
|
10985
10995
|
const onAbort = () => {
|
|
10986
10996
|
clearTimeout(timer);
|
|
10987
10997
|
reject(signal?.reason ?? new Error("aborted"));
|
|
@@ -14515,10 +14525,10 @@ function presentFailureTerminal(terminal, io) {
|
|
|
14515
14525
|
}
|
|
14516
14526
|
function defaultNavigatorGraceSleep() {
|
|
14517
14527
|
let timer;
|
|
14518
|
-
const sleep = ((ms) => new Promise((
|
|
14528
|
+
const sleep = ((ms) => new Promise((resolve21) => {
|
|
14519
14529
|
timer = setTimeout(() => {
|
|
14520
14530
|
timer = void 0;
|
|
14521
|
-
|
|
14531
|
+
resolve21();
|
|
14522
14532
|
}, ms);
|
|
14523
14533
|
}));
|
|
14524
14534
|
sleep.cancel = () => {
|
|
@@ -14530,7 +14540,7 @@ function defaultNavigatorGraceSleep() {
|
|
|
14530
14540
|
return sleep;
|
|
14531
14541
|
}
|
|
14532
14542
|
function raceNavigatorGrace(work, graceMs = NAVIGATOR_POST_ROLE_GRACE_MS, sleep = defaultNavigatorGraceSleep()) {
|
|
14533
|
-
return new Promise((
|
|
14543
|
+
return new Promise((resolve21, reject) => {
|
|
14534
14544
|
let settled = false;
|
|
14535
14545
|
const finish = (action) => {
|
|
14536
14546
|
if (settled) return;
|
|
@@ -14539,11 +14549,11 @@ function raceNavigatorGrace(work, graceMs = NAVIGATOR_POST_ROLE_GRACE_MS, sleep
|
|
|
14539
14549
|
action();
|
|
14540
14550
|
};
|
|
14541
14551
|
void work.then(
|
|
14542
|
-
(value) => finish(() =>
|
|
14552
|
+
(value) => finish(() => resolve21({ status: "done", value })),
|
|
14543
14553
|
(error) => finish(() => reject(error))
|
|
14544
14554
|
);
|
|
14545
14555
|
void sleep(graceMs).then(() => {
|
|
14546
|
-
finish(() =>
|
|
14556
|
+
finish(() => resolve21({ status: "timeout" }));
|
|
14547
14557
|
});
|
|
14548
14558
|
});
|
|
14549
14559
|
}
|
|
@@ -22946,11 +22956,11 @@ function buildSkillExpansion(methodSkills, prompt) {
|
|
|
22946
22956
|
});
|
|
22947
22957
|
}
|
|
22948
22958
|
async function listen(server, path) {
|
|
22949
|
-
await new Promise((
|
|
22959
|
+
await new Promise((resolve21, reject) => {
|
|
22950
22960
|
server.once("error", reject);
|
|
22951
22961
|
server.listen(path, () => {
|
|
22952
22962
|
server.off("error", reject);
|
|
22953
|
-
|
|
22963
|
+
resolve21();
|
|
22954
22964
|
});
|
|
22955
22965
|
});
|
|
22956
22966
|
}
|
|
@@ -23345,8 +23355,8 @@ async function prepareRoleEnvelope(options) {
|
|
|
23345
23355
|
try {
|
|
23346
23356
|
const closeAll = server.closeAllConnections;
|
|
23347
23357
|
if (typeof closeAll === "function") closeAll.call(server);
|
|
23348
|
-
await new Promise((
|
|
23349
|
-
server.close((error) => error ? reject(error) :
|
|
23358
|
+
await new Promise((resolve21, reject) => {
|
|
23359
|
+
server.close((error) => error ? reject(error) : resolve21());
|
|
23350
23360
|
});
|
|
23351
23361
|
} catch (error) {
|
|
23352
23362
|
cleanupFailures.push(error);
|
|
@@ -23478,6 +23488,12 @@ init_session_identity();
|
|
|
23478
23488
|
|
|
23479
23489
|
// src/headless-host/description.ts
|
|
23480
23490
|
import { join as join37 } from "node:path";
|
|
23491
|
+
function isClaudePrintDescription(description) {
|
|
23492
|
+
return description.protocol === "claude-print";
|
|
23493
|
+
}
|
|
23494
|
+
function isCodexExecDescription(description) {
|
|
23495
|
+
return description.protocol === "codex-exec";
|
|
23496
|
+
}
|
|
23481
23497
|
function resolveHeadlessBinary(description, operatorHome) {
|
|
23482
23498
|
return join37(operatorHome, ...description.binaryFromHome);
|
|
23483
23499
|
}
|
|
@@ -23508,6 +23524,214 @@ function headlessTurnArgs(options) {
|
|
|
23508
23524
|
}
|
|
23509
23525
|
return args;
|
|
23510
23526
|
}
|
|
23527
|
+
function codexTomlString(value) {
|
|
23528
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
23529
|
+
}
|
|
23530
|
+
function codexTomlStringArray(values) {
|
|
23531
|
+
return `[${values.map(codexTomlString).join(",")}]`;
|
|
23532
|
+
}
|
|
23533
|
+
function codexTomlStringTable(entries) {
|
|
23534
|
+
const parts = Object.entries(entries).map(
|
|
23535
|
+
([key, value]) => `${key}=${codexTomlString(value)}`
|
|
23536
|
+
);
|
|
23537
|
+
return `{${parts.join(",")}}`;
|
|
23538
|
+
}
|
|
23539
|
+
var CODEX_JSON_VALUE_DEF = "codexJsonValue";
|
|
23540
|
+
var CODEX_JSON_VALUE_REF = `#/$defs/${CODEX_JSON_VALUE_DEF}`;
|
|
23541
|
+
var CODEX_JSON_VALUE_SCHEMA = Object.freeze({
|
|
23542
|
+
anyOf: Object.freeze([
|
|
23543
|
+
Object.freeze({ type: "string" }),
|
|
23544
|
+
Object.freeze({ type: "number" }),
|
|
23545
|
+
Object.freeze({ type: "boolean" }),
|
|
23546
|
+
Object.freeze({ type: "null" }),
|
|
23547
|
+
Object.freeze({ type: "array", items: Object.freeze({ $ref: CODEX_JSON_VALUE_REF }) }),
|
|
23548
|
+
Object.freeze({
|
|
23549
|
+
type: "object",
|
|
23550
|
+
properties: Object.freeze({}),
|
|
23551
|
+
required: Object.freeze([]),
|
|
23552
|
+
additionalProperties: Object.freeze({ $ref: CODEX_JSON_VALUE_REF })
|
|
23553
|
+
})
|
|
23554
|
+
])
|
|
23555
|
+
});
|
|
23556
|
+
function closeJsonSchemaForCodex(schema) {
|
|
23557
|
+
const closed = closeSchemaNode(schema);
|
|
23558
|
+
const existingDefs = isPlainObject(closed.$defs) ? closed.$defs : {};
|
|
23559
|
+
return {
|
|
23560
|
+
...closed,
|
|
23561
|
+
$defs: {
|
|
23562
|
+
...existingDefs,
|
|
23563
|
+
[CODEX_JSON_VALUE_DEF]: CODEX_JSON_VALUE_SCHEMA
|
|
23564
|
+
}
|
|
23565
|
+
};
|
|
23566
|
+
}
|
|
23567
|
+
function isPlainObject(value) {
|
|
23568
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23569
|
+
}
|
|
23570
|
+
function isPureNullTypeSchema(value) {
|
|
23571
|
+
if (!isPlainObject(value)) return false;
|
|
23572
|
+
if (value.type === "null") return true;
|
|
23573
|
+
if (Array.isArray(value.type) && value.type.length > 0 && value.type.every((t) => t === "null")) {
|
|
23574
|
+
return true;
|
|
23575
|
+
}
|
|
23576
|
+
return false;
|
|
23577
|
+
}
|
|
23578
|
+
function stripNullFromLeafType(leaf) {
|
|
23579
|
+
if (!isPlainObject(leaf) || !Array.isArray(leaf.type)) return leaf;
|
|
23580
|
+
const nonNull = leaf.type.filter((t) => t !== "null");
|
|
23581
|
+
if (nonNull.length === leaf.type.length) return leaf;
|
|
23582
|
+
if (nonNull.length === 0) return { ...leaf, type: "null" };
|
|
23583
|
+
if (nonNull.length === 1) return { ...leaf, type: nonNull[0] };
|
|
23584
|
+
return { ...leaf, type: nonNull };
|
|
23585
|
+
}
|
|
23586
|
+
function flattenUnionLeaves(schema) {
|
|
23587
|
+
if (!isPlainObject(schema)) return [schema];
|
|
23588
|
+
if (Array.isArray(schema.anyOf)) {
|
|
23589
|
+
return schema.anyOf.flatMap(flattenUnionLeaves);
|
|
23590
|
+
}
|
|
23591
|
+
return [schema];
|
|
23592
|
+
}
|
|
23593
|
+
function nonNullLeaves(schema) {
|
|
23594
|
+
return flattenUnionLeaves(schema).map(stripNullFromLeafType).filter((leaf) => !isPureNullTypeSchema(leaf));
|
|
23595
|
+
}
|
|
23596
|
+
function closePropertySchema(schema, optional) {
|
|
23597
|
+
const leaves = nonNullLeaves(schema).map(closeSchemaNode);
|
|
23598
|
+
if (leaves.length === 0) return { type: "null" };
|
|
23599
|
+
if (!optional) {
|
|
23600
|
+
return leaves.length === 1 ? leaves[0] : { anyOf: leaves };
|
|
23601
|
+
}
|
|
23602
|
+
return { anyOf: [...leaves, { type: "null" }] };
|
|
23603
|
+
}
|
|
23604
|
+
function ensureTypedLeaf(schema) {
|
|
23605
|
+
if (schema.type !== void 0) return schema;
|
|
23606
|
+
if (typeof schema.$ref === "string") return schema;
|
|
23607
|
+
if (isPlainObject(schema.properties) || schema.additionalProperties !== void 0) {
|
|
23608
|
+
return { ...schema, type: "object" };
|
|
23609
|
+
}
|
|
23610
|
+
if (schema.items !== void 0) {
|
|
23611
|
+
return { ...schema, type: "array" };
|
|
23612
|
+
}
|
|
23613
|
+
if (schema.const !== void 0) {
|
|
23614
|
+
const value = schema.const;
|
|
23615
|
+
if (value === null) return { ...schema, type: "null" };
|
|
23616
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
23617
|
+
return { ...schema, type: typeof value };
|
|
23618
|
+
}
|
|
23619
|
+
}
|
|
23620
|
+
if (Array.isArray(schema.enum) && schema.enum.length > 0) {
|
|
23621
|
+
const sample = schema.enum.find((item) => item !== null);
|
|
23622
|
+
if (typeof sample === "string" || typeof sample === "number" || typeof sample === "boolean") {
|
|
23623
|
+
return { ...schema, type: typeof sample };
|
|
23624
|
+
}
|
|
23625
|
+
}
|
|
23626
|
+
return { $ref: CODEX_JSON_VALUE_REF };
|
|
23627
|
+
}
|
|
23628
|
+
function originalRequiredNames(node) {
|
|
23629
|
+
if (!Array.isArray(node.required)) return /* @__PURE__ */ new Set();
|
|
23630
|
+
return new Set(node.required.filter((item) => typeof item === "string"));
|
|
23631
|
+
}
|
|
23632
|
+
function closeSchemaNode(node) {
|
|
23633
|
+
if (!isPlainObject(node)) return node;
|
|
23634
|
+
if (typeof node.$ref === "string") return node;
|
|
23635
|
+
if (Array.isArray(node.anyOf)) {
|
|
23636
|
+
const leaves = nonNullLeaves(node).map(closeSchemaNode);
|
|
23637
|
+
if (leaves.length === 0) return { type: "null" };
|
|
23638
|
+
if (leaves.length === 1) return leaves[0];
|
|
23639
|
+
return { anyOf: leaves };
|
|
23640
|
+
}
|
|
23641
|
+
let out = { ...node };
|
|
23642
|
+
if (node.items !== void 0) {
|
|
23643
|
+
out.items = closeSchemaNode(node.items);
|
|
23644
|
+
}
|
|
23645
|
+
if (isPlainObject(node.$defs)) {
|
|
23646
|
+
out.$defs = Object.fromEntries(
|
|
23647
|
+
Object.entries(node.$defs).map(([key, value]) => [key, closeSchemaNode(value)])
|
|
23648
|
+
);
|
|
23649
|
+
}
|
|
23650
|
+
const hasProperties = isPlainObject(node.properties);
|
|
23651
|
+
const isObjectType = node.type === "object" || Array.isArray(node.type) && node.type.includes("object") || hasProperties || node.additionalProperties !== void 0;
|
|
23652
|
+
if (hasProperties) {
|
|
23653
|
+
const props = node.properties;
|
|
23654
|
+
const wasRequired = originalRequiredNames(node);
|
|
23655
|
+
const closedProps = {};
|
|
23656
|
+
const required = [];
|
|
23657
|
+
for (const [name, propSchema] of Object.entries(props)) {
|
|
23658
|
+
required.push(name);
|
|
23659
|
+
closedProps[name] = closePropertySchema(propSchema, !wasRequired.has(name));
|
|
23660
|
+
}
|
|
23661
|
+
out.properties = closedProps;
|
|
23662
|
+
out.required = required;
|
|
23663
|
+
out.additionalProperties = false;
|
|
23664
|
+
if (out.type === void 0) out.type = "object";
|
|
23665
|
+
delete out.anyOf;
|
|
23666
|
+
} else if (isObjectType) {
|
|
23667
|
+
out.additionalProperties = false;
|
|
23668
|
+
if (!Array.isArray(out.required)) out.required = [];
|
|
23669
|
+
if (out.type === void 0) out.type = "object";
|
|
23670
|
+
} else {
|
|
23671
|
+
out = ensureTypedLeaf(out);
|
|
23672
|
+
}
|
|
23673
|
+
return out;
|
|
23674
|
+
}
|
|
23675
|
+
function stringEnvironment(value) {
|
|
23676
|
+
const entries = Array.isArray(value) ? value.flatMap((item) => {
|
|
23677
|
+
if (!isPlainObject(item) || typeof item.name !== "string" || typeof item.value !== "string") return [];
|
|
23678
|
+
return [[item.name, item.value]];
|
|
23679
|
+
}) : isPlainObject(value) ? Object.entries(value).filter((entry) => typeof entry[1] === "string") : [];
|
|
23680
|
+
return entries.length === 0 ? void 0 : Object.fromEntries(entries);
|
|
23681
|
+
}
|
|
23682
|
+
function codexMcpConfigArgs(mcpServers) {
|
|
23683
|
+
const args = [];
|
|
23684
|
+
for (const row of mcpServers) {
|
|
23685
|
+
const name = typeof row.name === "string" ? row.name : void 0;
|
|
23686
|
+
const command = typeof row.command === "string" ? row.command : void 0;
|
|
23687
|
+
if (name === void 0 || name === "" || command === void 0 || command === "") continue;
|
|
23688
|
+
const prefix = `mcp_servers.${name}`;
|
|
23689
|
+
args.push("-c", `${prefix}.command=${codexTomlString(command)}`);
|
|
23690
|
+
args.push("-c", `${prefix}.required=true`);
|
|
23691
|
+
if (Array.isArray(row.args) && row.args.every((item) => typeof item === "string")) {
|
|
23692
|
+
args.push("-c", `${prefix}.args=${codexTomlStringArray(row.args)}`);
|
|
23693
|
+
}
|
|
23694
|
+
const env = stringEnvironment(row.env);
|
|
23695
|
+
if (env !== void 0) {
|
|
23696
|
+
args.push("-c", `${prefix}.env=${codexTomlStringTable(env)}`);
|
|
23697
|
+
}
|
|
23698
|
+
}
|
|
23699
|
+
return args;
|
|
23700
|
+
}
|
|
23701
|
+
function codexTurnArgs(options) {
|
|
23702
|
+
const args = ["exec", "--approve-for-me"];
|
|
23703
|
+
if (options.session.kind === "resume") {
|
|
23704
|
+
args.push("resume", options.session.id);
|
|
23705
|
+
}
|
|
23706
|
+
args.push("--json");
|
|
23707
|
+
args.push("--ignore-user-config", "--ignore-rules");
|
|
23708
|
+
const roots = (options.writableRoots ?? []).filter((root) => root !== "");
|
|
23709
|
+
if (roots.length > 0) {
|
|
23710
|
+
args.push(
|
|
23711
|
+
"-c",
|
|
23712
|
+
`sandbox_workspace_write.writable_roots=${codexTomlStringArray(roots)}`
|
|
23713
|
+
);
|
|
23714
|
+
if (options.session.kind === "new") {
|
|
23715
|
+
for (const root of roots) {
|
|
23716
|
+
args.push("--add-dir", root);
|
|
23717
|
+
}
|
|
23718
|
+
}
|
|
23719
|
+
}
|
|
23720
|
+
args.push("-c", `model_instructions_file=${codexTomlString(options.systemPromptPath)}`);
|
|
23721
|
+
args.push("--output-schema", options.outputSchemaPath);
|
|
23722
|
+
args.push(...codexMcpConfigArgs(options.mcpServers));
|
|
23723
|
+
if (options.model !== void 0 && options.model !== "") {
|
|
23724
|
+
args.push("-m", options.model);
|
|
23725
|
+
}
|
|
23726
|
+
if (options.effort !== void 0 && options.effort !== "") {
|
|
23727
|
+
args.push("-c", `model_reasoning_effort=${codexTomlString(options.effort)}`);
|
|
23728
|
+
}
|
|
23729
|
+
if (options.skipGitRepoCheck === true) {
|
|
23730
|
+
args.push("--skip-git-repo-check");
|
|
23731
|
+
}
|
|
23732
|
+
args.push("--", options.prompt);
|
|
23733
|
+
return args;
|
|
23734
|
+
}
|
|
23511
23735
|
function headlessMcpConfigDocument(mcpServers) {
|
|
23512
23736
|
const servers = {};
|
|
23513
23737
|
for (const row of mcpServers) {
|
|
@@ -23516,29 +23740,19 @@ function headlessMcpConfigDocument(mcpServers) {
|
|
|
23516
23740
|
if (name === void 0 || name === "" || command === void 0 || command === "") continue;
|
|
23517
23741
|
const entry = { command };
|
|
23518
23742
|
if (Array.isArray(row.args)) entry.args = row.args;
|
|
23519
|
-
|
|
23520
|
-
|
|
23521
|
-
for (const item of row.env) {
|
|
23522
|
-
if (typeof item !== "object" || item === null) continue;
|
|
23523
|
-
const record4 = item;
|
|
23524
|
-
if (typeof record4.name === "string" && typeof record4.value === "string") {
|
|
23525
|
-
env[record4.name] = record4.value;
|
|
23526
|
-
}
|
|
23527
|
-
}
|
|
23528
|
-
if (Object.keys(env).length > 0) entry.env = env;
|
|
23529
|
-
} else if (typeof row.env === "object" && row.env !== null && !Array.isArray(row.env)) {
|
|
23530
|
-
entry.env = row.env;
|
|
23531
|
-
}
|
|
23743
|
+
const env = stringEnvironment(row.env);
|
|
23744
|
+
if (env !== void 0) entry.env = env;
|
|
23532
23745
|
servers[name] = entry;
|
|
23533
23746
|
}
|
|
23534
23747
|
return Object.freeze({ mcpServers: Object.freeze(servers) });
|
|
23535
23748
|
}
|
|
23536
23749
|
|
|
23537
23750
|
// src/headless-host/role-turn-host.ts
|
|
23538
|
-
import { spawn as spawn4 } from "node:child_process";
|
|
23751
|
+
import { spawn as spawn4, spawnSync } from "node:child_process";
|
|
23539
23752
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
23753
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
23540
23754
|
import { writeFile as writeFile11 } from "node:fs/promises";
|
|
23541
|
-
import { join as join38 } from "node:path";
|
|
23755
|
+
import { dirname as dirname21, isAbsolute as isAbsolute11, join as join38, resolve as resolve20 } from "node:path";
|
|
23542
23756
|
|
|
23543
23757
|
// src/external-host-turn-loop.ts
|
|
23544
23758
|
var EXTERNAL_ROLE_TURN_ROUND_LIMIT = 8;
|
|
@@ -23667,7 +23881,7 @@ function failure(cause, name, code, details, diagnostic) {
|
|
|
23667
23881
|
};
|
|
23668
23882
|
}
|
|
23669
23883
|
function isHeadlessResultCandidate(value) {
|
|
23670
|
-
if (
|
|
23884
|
+
if (!isPlainObject(value)) return false;
|
|
23671
23885
|
const record4 = value;
|
|
23672
23886
|
return record4.type === void 0 || record4.type === "result" || record4.structured_output !== void 0;
|
|
23673
23887
|
}
|
|
@@ -23685,7 +23899,7 @@ function parseHeadlessCliStdout(stdout) {
|
|
|
23685
23899
|
if (text === "") continue;
|
|
23686
23900
|
try {
|
|
23687
23901
|
const value = JSON.parse(text);
|
|
23688
|
-
if (
|
|
23902
|
+
if (!isPlainObject(value)) continue;
|
|
23689
23903
|
const record4 = value;
|
|
23690
23904
|
if (record4.type === "result" || record4.structured_output !== void 0) {
|
|
23691
23905
|
last = record4;
|
|
@@ -23705,8 +23919,87 @@ function resultCandidateText(line2) {
|
|
|
23705
23919
|
return void 0;
|
|
23706
23920
|
}
|
|
23707
23921
|
}
|
|
23922
|
+
function createCodexExecTurnObserver() {
|
|
23923
|
+
let threadId;
|
|
23924
|
+
let finalMessage;
|
|
23925
|
+
let failureDiagnostic;
|
|
23926
|
+
let turnCompleted = false;
|
|
23927
|
+
return {
|
|
23928
|
+
observe(value) {
|
|
23929
|
+
if (!isPlainObject(value)) return;
|
|
23930
|
+
const type = typeof value.type === "string" ? value.type : void 0;
|
|
23931
|
+
if (type === "thread.started" && typeof value.thread_id === "string" && value.thread_id !== "") {
|
|
23932
|
+
threadId = value.thread_id;
|
|
23933
|
+
} else if (type === "item.completed" && isPlainObject(value.item)) {
|
|
23934
|
+
if (value.item.type === "agent_message" && typeof value.item.text === "string") {
|
|
23935
|
+
finalMessage = value.item.text;
|
|
23936
|
+
}
|
|
23937
|
+
} else if (type === "turn.completed") {
|
|
23938
|
+
turnCompleted = true;
|
|
23939
|
+
failureDiagnostic = void 0;
|
|
23940
|
+
} else if (type === "turn.failed") {
|
|
23941
|
+
turnCompleted = false;
|
|
23942
|
+
failureDiagnostic = formatCodexFailurePayload(value.error ?? value);
|
|
23943
|
+
}
|
|
23944
|
+
},
|
|
23945
|
+
result() {
|
|
23946
|
+
return {
|
|
23947
|
+
...threadId === void 0 ? {} : { threadId },
|
|
23948
|
+
...finalMessage === void 0 ? {} : { finalMessage },
|
|
23949
|
+
...failureDiagnostic === void 0 ? {} : { failureDiagnostic },
|
|
23950
|
+
turnCompleted
|
|
23951
|
+
};
|
|
23952
|
+
}
|
|
23953
|
+
};
|
|
23954
|
+
}
|
|
23955
|
+
function formatCodexFailurePayload(payload) {
|
|
23956
|
+
if (typeof payload === "string" && payload.trim() !== "") return payload;
|
|
23957
|
+
if (isPlainObject(payload)) {
|
|
23958
|
+
if (typeof payload.message === "string" && payload.message.trim() !== "") return payload.message;
|
|
23959
|
+
try {
|
|
23960
|
+
return JSON.stringify(payload);
|
|
23961
|
+
} catch {
|
|
23962
|
+
return "codex turn failed";
|
|
23963
|
+
}
|
|
23964
|
+
}
|
|
23965
|
+
return String(payload);
|
|
23966
|
+
}
|
|
23967
|
+
function cwdIsGitWorkTree(cwd) {
|
|
23968
|
+
let dir = cwd;
|
|
23969
|
+
for (; ; ) {
|
|
23970
|
+
if (existsSync12(join38(dir, ".git"))) return true;
|
|
23971
|
+
const parent = dirname21(dir);
|
|
23972
|
+
if (parent === dir) return false;
|
|
23973
|
+
dir = parent;
|
|
23974
|
+
}
|
|
23975
|
+
}
|
|
23976
|
+
function resolveGitCommonDir(cwd) {
|
|
23977
|
+
if (!cwdIsGitWorkTree(cwd)) return void 0;
|
|
23978
|
+
let result;
|
|
23979
|
+
try {
|
|
23980
|
+
result = spawnSync("git", ["rev-parse", "--git-common-dir"], {
|
|
23981
|
+
cwd,
|
|
23982
|
+
encoding: "utf8"
|
|
23983
|
+
});
|
|
23984
|
+
} catch (error) {
|
|
23985
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
23986
|
+
throw new Error(`git rev-parse --git-common-dir failed: ${message}`);
|
|
23987
|
+
}
|
|
23988
|
+
if (result.error !== void 0) {
|
|
23989
|
+
throw new Error(`git rev-parse --git-common-dir failed: ${result.error.message}`);
|
|
23990
|
+
}
|
|
23991
|
+
if (result.status !== 0) {
|
|
23992
|
+
const detail = result.stderr.trim() || `exit ${String(result.status)}`;
|
|
23993
|
+
throw new Error(`git rev-parse --git-common-dir failed: ${detail}`);
|
|
23994
|
+
}
|
|
23995
|
+
const raw = result.stdout.trim();
|
|
23996
|
+
if (raw === "") {
|
|
23997
|
+
throw new Error("git rev-parse --git-common-dir returned empty stdout");
|
|
23998
|
+
}
|
|
23999
|
+
return isAbsolute11(raw) ? raw : resolve20(cwd, raw);
|
|
24000
|
+
}
|
|
23708
24001
|
function spawnHeadlessTurn(options) {
|
|
23709
|
-
return new Promise((
|
|
24002
|
+
return new Promise((resolve21, reject) => {
|
|
23710
24003
|
if (options.signal?.aborted) {
|
|
23711
24004
|
reject(hostAbortedError("headless host aborted"));
|
|
23712
24005
|
return;
|
|
@@ -23765,7 +24058,7 @@ function spawnHeadlessTurn(options) {
|
|
|
23765
24058
|
settled = true;
|
|
23766
24059
|
if (timer !== void 0) clearTimeout(timer);
|
|
23767
24060
|
options.signal?.removeEventListener("abort", onAbort);
|
|
23768
|
-
|
|
24061
|
+
resolve21({ code, stdout: resultStdout, stderr, timedOut });
|
|
23769
24062
|
};
|
|
23770
24063
|
const onAbort = () => {
|
|
23771
24064
|
child.kill("SIGTERM");
|
|
@@ -23821,28 +24114,70 @@ function terminalFromSpawned(spawned, knownFailure) {
|
|
|
23821
24114
|
}
|
|
23822
24115
|
};
|
|
23823
24116
|
}
|
|
24117
|
+
function buildTurnArgs(options) {
|
|
24118
|
+
if (isCodexExecDescription(options.description)) {
|
|
24119
|
+
if (options.sessionKind === "resume" && !options.sessionId) {
|
|
24120
|
+
throw new Error("codex resume requires a bound thread_id");
|
|
24121
|
+
}
|
|
24122
|
+
if (options.outputSchemaPath === void 0) throw new Error("codex requires an output schema path");
|
|
24123
|
+
return codexTurnArgs({
|
|
24124
|
+
prompt: options.prompt,
|
|
24125
|
+
systemPromptPath: options.systemPromptPath,
|
|
24126
|
+
outputSchemaPath: options.outputSchemaPath,
|
|
24127
|
+
mcpServers: options.mcpServers,
|
|
24128
|
+
...options.model === void 0 ? {} : { model: options.model },
|
|
24129
|
+
...options.effort === void 0 ? {} : { effort: options.effort },
|
|
24130
|
+
session: options.sessionKind === "resume" ? { kind: "resume", id: options.sessionId } : { kind: "new" },
|
|
24131
|
+
skipGitRepoCheck: !cwdIsGitWorkTree(options.cwd),
|
|
24132
|
+
...!options.writableRoots?.length ? {} : { writableRoots: options.writableRoots }
|
|
24133
|
+
});
|
|
24134
|
+
}
|
|
24135
|
+
if (!isClaudePrintDescription(options.description)) throw new Error("unsupported headless host protocol");
|
|
24136
|
+
if (!options.sessionId) throw new Error("claude print-mode requires a session id");
|
|
24137
|
+
if (options.mcpConfigPath === void 0) throw new Error("claude print-mode requires an MCP config path");
|
|
24138
|
+
return headlessTurnArgs({
|
|
24139
|
+
description: options.description,
|
|
24140
|
+
prompt: options.prompt,
|
|
24141
|
+
systemPromptPath: options.systemPromptPath,
|
|
24142
|
+
jsonSchema: options.jsonSchema,
|
|
24143
|
+
mcpConfigPath: options.mcpConfigPath,
|
|
24144
|
+
...options.model === void 0 ? {} : { model: options.model },
|
|
24145
|
+
...options.effort === void 0 ? {} : { effort: options.effort },
|
|
24146
|
+
session: { kind: options.sessionKind, id: options.sessionId }
|
|
24147
|
+
});
|
|
24148
|
+
}
|
|
23824
24149
|
function createHeadlessRoleTurnHost(config) {
|
|
23825
24150
|
return createSerializedRoleTurnHost(async (request) => {
|
|
23826
24151
|
const prepared = await config.prepare(request);
|
|
23827
24152
|
const systemPrompt = renderSystemPromptOverride(prepared.systemPrompt);
|
|
24153
|
+
const codex = isCodexExecDescription(config.description);
|
|
23828
24154
|
let outcome = failure("session", "HeadlessNoOutcome", "no-outcome");
|
|
23829
24155
|
try {
|
|
23830
24156
|
let sessionId = await config.sessionIdentity.load(request.principal);
|
|
23831
24157
|
let sessionKind = request.continuation.kind === "resume" && sessionId !== void 0 && sessionId !== "" ? "resume" : "new";
|
|
23832
|
-
if (sessionKind === "new") {
|
|
24158
|
+
if (sessionKind === "new" && !codex) {
|
|
23833
24159
|
sessionId = randomUUID8();
|
|
23834
24160
|
await config.sessionIdentity.bind(request.principal, sessionId);
|
|
23835
24161
|
}
|
|
23836
24162
|
const env = { ...process.env, ...config.env ?? {} };
|
|
23837
24163
|
const systemPromptPath = join38(request.runDirectory, "headless-system-prompt.txt");
|
|
23838
24164
|
await writeFile11(systemPromptPath, systemPrompt, "utf8");
|
|
23839
|
-
|
|
23840
|
-
|
|
23841
|
-
|
|
23842
|
-
|
|
24165
|
+
let mcpConfigPath;
|
|
24166
|
+
let outputSchemaPath;
|
|
24167
|
+
if (codex) {
|
|
24168
|
+
outputSchemaPath = join38(request.runDirectory, "headless-output-schema.json");
|
|
24169
|
+
const closed = closeJsonSchemaForCodex(prepared.jsonSchema);
|
|
24170
|
+
await writeFile11(outputSchemaPath, `${JSON.stringify(closed, null, 2)}
|
|
24171
|
+
`, "utf8");
|
|
24172
|
+
} else {
|
|
24173
|
+
mcpConfigPath = join38(request.runDirectory, "headless-mcp-config.json");
|
|
24174
|
+
await writeFile11(
|
|
24175
|
+
mcpConfigPath,
|
|
24176
|
+
`${JSON.stringify(headlessMcpConfigDocument(prepared.mcpServers), null, 2)}
|
|
23843
24177
|
`,
|
|
23844
|
-
|
|
23845
|
-
|
|
24178
|
+
"utf8"
|
|
24179
|
+
);
|
|
24180
|
+
}
|
|
23846
24181
|
const sessionParent = config.sessionIdentity.resolveSessionFile(request.principal);
|
|
23847
24182
|
outcome = await driveExternalRoleTurnRounds(prepared, request, {
|
|
23848
24183
|
roundLimitName: "HeadlessRoundLimit",
|
|
@@ -23851,16 +24186,32 @@ function createHeadlessRoleTurnHost(config) {
|
|
|
23851
24186
|
sessionKind = "resume";
|
|
23852
24187
|
},
|
|
23853
24188
|
async runRound({ prompt, abortSignal }) {
|
|
23854
|
-
|
|
23855
|
-
|
|
23856
|
-
|
|
23857
|
-
|
|
23858
|
-
|
|
23859
|
-
|
|
23860
|
-
|
|
23861
|
-
|
|
23862
|
-
|
|
23863
|
-
|
|
24189
|
+
let args;
|
|
24190
|
+
try {
|
|
24191
|
+
const gitCommonDir = codex ? resolveGitCommonDir(request.cwd) : void 0;
|
|
24192
|
+
args = buildTurnArgs({
|
|
24193
|
+
description: config.description,
|
|
24194
|
+
prompt,
|
|
24195
|
+
systemPromptPath,
|
|
24196
|
+
jsonSchema: prepared.jsonSchema,
|
|
24197
|
+
mcpServers: prepared.mcpServers,
|
|
24198
|
+
...mcpConfigPath === void 0 ? {} : { mcpConfigPath },
|
|
24199
|
+
...outputSchemaPath === void 0 ? {} : { outputSchemaPath },
|
|
24200
|
+
...request.model?.model !== void 0 ? { model: request.model.model } : {},
|
|
24201
|
+
...request.model?.thinking !== void 0 ? { effort: request.model.thinking } : {},
|
|
24202
|
+
sessionId,
|
|
24203
|
+
sessionKind,
|
|
24204
|
+
cwd: request.cwd,
|
|
24205
|
+
...gitCommonDir === void 0 ? {} : { writableRoots: [gitCommonDir] }
|
|
24206
|
+
});
|
|
24207
|
+
} catch (error) {
|
|
24208
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
24209
|
+
return {
|
|
24210
|
+
status: "terminal",
|
|
24211
|
+
result: failure("session", "HeadlessArgvFailure", "argv-failed", { diagnostic: message }, message)
|
|
24212
|
+
};
|
|
24213
|
+
}
|
|
24214
|
+
const codexObserver = codex ? createCodexExecTurnObserver() : void 0;
|
|
23864
24215
|
let spawned;
|
|
23865
24216
|
try {
|
|
23866
24217
|
spawned = await spawnHeadlessTurn({
|
|
@@ -23886,6 +24237,7 @@ function createHeadlessRoleTurnHost(config) {
|
|
|
23886
24237
|
source: "headless-host",
|
|
23887
24238
|
event
|
|
23888
24239
|
});
|
|
24240
|
+
codexObserver?.observe(event);
|
|
23889
24241
|
}
|
|
23890
24242
|
});
|
|
23891
24243
|
} catch (error) {
|
|
@@ -23919,6 +24271,64 @@ function createHeadlessRoleTurnHost(config) {
|
|
|
23919
24271
|
details: { sessionId }
|
|
23920
24272
|
});
|
|
23921
24273
|
}
|
|
24274
|
+
if (codex) {
|
|
24275
|
+
const observation = codexObserver.result();
|
|
24276
|
+
if (observation.threadId === void 0 || observation.threadId === "") {
|
|
24277
|
+
return terminalFromSpawned(spawned, {
|
|
24278
|
+
cause: "session",
|
|
24279
|
+
identity: { name: "HeadlessMissingThreadId", code: "missing-thread-id" },
|
|
24280
|
+
diagnostic: "codex exec emitted no thread.started thread_id",
|
|
24281
|
+
details: { sessionId, exitCode: spawned.code }
|
|
24282
|
+
});
|
|
24283
|
+
}
|
|
24284
|
+
sessionId = observation.threadId;
|
|
24285
|
+
await config.sessionIdentity.bind(request.principal, sessionId);
|
|
24286
|
+
if (observation.failureDiagnostic !== void 0) {
|
|
24287
|
+
return terminalFromSpawned(spawned, {
|
|
24288
|
+
cause: "output",
|
|
24289
|
+
identity: { name: "HeadlessCliError", code: "codex-turn-failed" },
|
|
24290
|
+
diagnostic: observation.failureDiagnostic,
|
|
24291
|
+
details: { sessionId, exitCode: spawned.code }
|
|
24292
|
+
});
|
|
24293
|
+
}
|
|
24294
|
+
if (spawned.code !== 0 && spawned.code !== null) {
|
|
24295
|
+
return terminalFromSpawned(spawned, {
|
|
24296
|
+
cause: "output",
|
|
24297
|
+
identity: { name: "HeadlessCliError", code: "codex-nonzero-exit" },
|
|
24298
|
+
diagnostic: spawned.stderr.trim() || `codex exec exited ${String(spawned.code)}`,
|
|
24299
|
+
details: { sessionId, exitCode: spawned.code }
|
|
24300
|
+
});
|
|
24301
|
+
}
|
|
24302
|
+
if (!observation.turnCompleted) {
|
|
24303
|
+
return terminalFromSpawned(spawned, {
|
|
24304
|
+
cause: "output",
|
|
24305
|
+
identity: { name: "HeadlessCliError", code: "codex-missing-terminal-event" },
|
|
24306
|
+
diagnostic: "codex exec exited without turn.completed",
|
|
24307
|
+
details: { sessionId, exitCode: spawned.code }
|
|
24308
|
+
});
|
|
24309
|
+
}
|
|
24310
|
+
if (observation.finalMessage === void 0) {
|
|
24311
|
+
return terminalFromSpawned(spawned, {
|
|
24312
|
+
cause: "output",
|
|
24313
|
+
identity: { name: "HeadlessEmptyOutput", code: "empty-stdout" },
|
|
24314
|
+
diagnostic: spawned.stderr.trim() || "codex exec produced no agent_message",
|
|
24315
|
+
details: { sessionId, exitCode: spawned.code }
|
|
24316
|
+
});
|
|
24317
|
+
}
|
|
24318
|
+
let receipt;
|
|
24319
|
+
try {
|
|
24320
|
+
receipt = JSON.parse(observation.finalMessage);
|
|
24321
|
+
} catch {
|
|
24322
|
+
return terminalFromSpawned(spawned, {
|
|
24323
|
+
cause: "output",
|
|
24324
|
+
identity: { name: "HeadlessEmptyOutput", code: "unparseable-final-message" },
|
|
24325
|
+
diagnostic: "codex final agent_message was not JSON",
|
|
24326
|
+
details: { sessionId, exitCode: spawned.code }
|
|
24327
|
+
});
|
|
24328
|
+
}
|
|
24329
|
+
await prepared.ingestStructuredOutput(receipt);
|
|
24330
|
+
return { status: "delivered", stderr: spawned.stderr };
|
|
24331
|
+
}
|
|
23922
24332
|
const envelope = parseHeadlessCliStdout(spawned.stdout);
|
|
23923
24333
|
if (envelope === void 0) {
|
|
23924
24334
|
return terminalFromSpawned(spawned, {
|