poe-code 3.0.223 → 3.0.225
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/bin/poe-gemini.js +23 -0
- package/dist/cli/commands/configure-payload.js +100 -13
- package/dist/cli/commands/configure-payload.js.map +1 -1
- package/dist/cli/commands/configure.js +2 -2
- package/dist/cli/commands/configure.js.map +1 -1
- package/dist/cli/commands/pipeline.js +4 -2
- package/dist/cli/commands/pipeline.js.map +1 -1
- package/dist/cli/commands/provider.d.ts +1 -0
- package/dist/cli/commands/provider.js +94 -3
- package/dist/cli/commands/provider.js.map +1 -1
- package/dist/cli/commands/ralph.js +1 -0
- package/dist/cli/commands/ralph.js.map +1 -1
- package/dist/cli/commands/shared.d.ts +8 -1
- package/dist/cli/commands/shared.js +88 -7
- package/dist/cli/commands/shared.js.map +1 -1
- package/dist/cli/commands/spawn.js +20 -0
- package/dist/cli/commands/spawn.js.map +1 -1
- package/dist/cli/commands/test.d.ts +5 -1
- package/dist/cli/commands/test.js +58 -6
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/constants.d.ts +2 -2
- package/dist/cli/constants.js +3 -14
- package/dist/cli/constants.js.map +1 -1
- package/dist/cli/isolated-env.d.ts +2 -1
- package/dist/cli/isolated-env.js +20 -2
- package/dist/cli/isolated-env.js.map +1 -1
- package/dist/cli/options.d.ts +2 -5
- package/dist/cli/options.js +10 -1
- package/dist/cli/options.js.map +1 -1
- package/dist/cli/poe-code-command-runner.js +7 -2
- package/dist/cli/poe-code-command-runner.js.map +1 -1
- package/dist/cli/prompt-runner.js +4 -2
- package/dist/cli/prompt-runner.js.map +1 -1
- package/dist/cli/prompts.d.ts +23 -13
- package/dist/cli/prompts.js +13 -0
- package/dist/cli/prompts.js.map +1 -1
- package/dist/cli/service-registry.d.ts +12 -3
- package/dist/cli/service-registry.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +4936 -2415
- package/dist/index.js.map +4 -4
- package/dist/providers/claude-code.js +924 -174
- package/dist/providers/claude-code.js.map +4 -4
- package/dist/providers/codex.js +916 -178
- package/dist/providers/codex.js.map +4 -4
- package/dist/providers/create-provider.d.ts +1 -0
- package/dist/providers/create-provider.js +1 -0
- package/dist/providers/create-provider.js.map +1 -1
- package/dist/providers/gemini-cli.d.ts +16 -0
- package/dist/providers/gemini-cli.js +11349 -0
- package/dist/providers/gemini-cli.js.map +7 -0
- package/dist/providers/goose.js +881 -183
- package/dist/providers/goose.js.map +4 -4
- package/dist/providers/kimi.js +905 -165
- package/dist/providers/kimi.js.map +4 -4
- package/dist/providers/opencode.js +905 -165
- package/dist/providers/opencode.js.map +4 -4
- package/dist/providers/poe-agent.js +1155 -357
- package/dist/providers/poe-agent.js.map +4 -4
- package/dist/providers/spawn-options.d.ts +3 -0
- package/dist/sdk/pipeline.d.ts +1 -1
- package/dist/sdk/pipeline.js +22 -19
- package/dist/sdk/pipeline.js.map +1 -1
- package/dist/sdk/ralph.js +5 -0
- package/dist/sdk/ralph.js.map +1 -1
- package/dist/sdk/spawn-core.d.ts +3 -0
- package/dist/sdk/spawn-core.js +6 -8
- package/dist/sdk/spawn-core.js.map +1 -1
- package/dist/sdk/spawn.d.ts +8 -8
- package/dist/sdk/spawn.js +26 -3
- package/dist/sdk/spawn.js.map +1 -1
- package/dist/sdk/types.d.ts +7 -0
- package/dist/utils/command-checks.d.ts +8 -0
- package/dist/utils/command-checks.js +35 -9
- package/dist/utils/command-checks.js.map +1 -1
- package/dist/utils/dry-run.js +7 -1
- package/dist/utils/dry-run.js.map +1 -1
- package/dist/workflow-templates/github-issue-opened.caller.yml +2 -1
- package/dist/workflow-templates/github-issue-opened.ejected.yml +2 -1
- package/package.json +2 -1
- package/packages/agent-skill-config/dist/configs.js +4 -0
- package/packages/agent-skill-config/dist/git-exclude.d.ts +6 -2
- package/packages/agent-skill-config/dist/git-exclude.js +12 -12
- package/packages/memory/dist/index.js +924 -200
- package/packages/memory/dist/index.js.map +4 -4
- package/packages/superintendent/dist/index.d.ts +2 -1
- package/packages/superintendent/dist/runtime/loop.d.ts +1 -0
- package/packages/superintendent/dist/runtime/loop.js +14 -2
package/dist/providers/codex.js
CHANGED
|
@@ -48,7 +48,7 @@ var require_requirements_txt = __commonJS({
|
|
|
48
48
|
// src/templates/codex/config.toml.mustache
|
|
49
49
|
var require_config_toml = __commonJS({
|
|
50
50
|
"src/templates/codex/config.toml.mustache"(exports, module) {
|
|
51
|
-
module.exports = 'model_provider = "{{providerId}}"\n\n[profiles."{{{profileName}}}"]\nmodel = "{{{model}}}"\nmodel_provider = "{{providerId}}"\nmodel_reasoning_effort = "{{reasoningEffort}}"\nmodel_verbosity = "medium"\n\n[model_providers.{{providerId}}]\nname = "{{providerId}}"\nbase_url = "{{{baseUrl}}}"\nwire_api = "responses"\nexperimental_bearer_token = "{{apiKey}}"\nrequires_openai_auth = false\nsupports_websockets = false\n';
|
|
51
|
+
module.exports = 'model_provider = "{{providerId}}"\nmodel = "{{{model}}}"\nmodel_reasoning_effort = "{{reasoningEffort}}"\nmodel_verbosity = "medium"\n\n[profiles."{{{profileName}}}"]\nmodel = "{{{model}}}"\nmodel_provider = "{{providerId}}"\nmodel_reasoning_effort = "{{reasoningEffort}}"\nmodel_verbosity = "medium"\n\n[model_providers.{{providerId}}]\nname = "{{providerId}}"\nbase_url = "{{{baseUrl}}}"\nwire_api = "responses"\nexperimental_bearer_token = "{{apiKey}}"\nrequires_openai_auth = false\nsupports_websockets = false\n';
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
54
|
|
|
@@ -804,17 +804,17 @@ function isPidRunning(pid) {
|
|
|
804
804
|
}
|
|
805
805
|
function createDefaultFs() {
|
|
806
806
|
return {
|
|
807
|
-
open: (
|
|
808
|
-
readFile: (
|
|
807
|
+
open: (path37, flags) => fsPromises.open(path37, flags),
|
|
808
|
+
readFile: (path37, encoding) => fsPromises.readFile(path37, encoding),
|
|
809
809
|
stat: fsPromises.stat,
|
|
810
810
|
unlink: fsPromises.unlink
|
|
811
811
|
};
|
|
812
812
|
}
|
|
813
|
-
async function removeLockFile(
|
|
813
|
+
async function removeLockFile(fs4, lockPath, signal) {
|
|
814
814
|
for (let attempt = 0; attempt <= 4; attempt += 1) {
|
|
815
815
|
throwIfAborted(signal);
|
|
816
816
|
try {
|
|
817
|
-
await
|
|
817
|
+
await fs4.unlink(lockPath);
|
|
818
818
|
return;
|
|
819
819
|
} catch (error2) {
|
|
820
820
|
if (hasErrorCode(error2, "ENOENT")) {
|
|
@@ -845,12 +845,12 @@ function parseLockMetadata(content) {
|
|
|
845
845
|
}
|
|
846
846
|
return void 0;
|
|
847
847
|
}
|
|
848
|
-
async function readLockMetadata(
|
|
849
|
-
if (!
|
|
848
|
+
async function readLockMetadata(fs4, lockPath) {
|
|
849
|
+
if (!fs4.readFile) {
|
|
850
850
|
return void 0;
|
|
851
851
|
}
|
|
852
852
|
try {
|
|
853
|
-
return parseLockMetadata(await
|
|
853
|
+
return parseLockMetadata(await fs4.readFile(lockPath, "utf8"));
|
|
854
854
|
} catch (error2) {
|
|
855
855
|
if (hasErrorCode(error2, "ENOENT")) {
|
|
856
856
|
return null;
|
|
@@ -884,7 +884,7 @@ async function writeLockMetadata(handle) {
|
|
|
884
884
|
}
|
|
885
885
|
}
|
|
886
886
|
async function acquireFileLock(filePath, options = {}) {
|
|
887
|
-
const
|
|
887
|
+
const fs4 = options.fs ?? createDefaultFs();
|
|
888
888
|
const retries = options.retries ?? 20;
|
|
889
889
|
const minTimeout = options.minTimeout ?? 25;
|
|
890
890
|
const maxTimeout = options.maxTimeout ?? 250;
|
|
@@ -895,7 +895,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
895
895
|
while (attempt <= retries) {
|
|
896
896
|
throwIfAborted(options.signal);
|
|
897
897
|
try {
|
|
898
|
-
const handle = await
|
|
898
|
+
const handle = await fs4.open(lockPath, "wx");
|
|
899
899
|
await writeLockMetadata(handle);
|
|
900
900
|
let released = false;
|
|
901
901
|
return async () => {
|
|
@@ -903,7 +903,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
903
903
|
return;
|
|
904
904
|
}
|
|
905
905
|
released = true;
|
|
906
|
-
await removeLockFile(
|
|
906
|
+
await removeLockFile(fs4, lockPath, options.signal);
|
|
907
907
|
};
|
|
908
908
|
} catch (error2) {
|
|
909
909
|
if (!hasErrorCode(error2, "EEXIST")) {
|
|
@@ -912,7 +912,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
912
912
|
}
|
|
913
913
|
let stat3;
|
|
914
914
|
try {
|
|
915
|
-
stat3 = await
|
|
915
|
+
stat3 = await fs4.stat(lockPath);
|
|
916
916
|
} catch (statError) {
|
|
917
917
|
if (hasErrorCode(statError, "ENOENT")) {
|
|
918
918
|
continue;
|
|
@@ -920,7 +920,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
920
920
|
throw statError;
|
|
921
921
|
}
|
|
922
922
|
const reclaimLock = await shouldReclaimLock({
|
|
923
|
-
fs:
|
|
923
|
+
fs: fs4,
|
|
924
924
|
isPidRunning: pidIsRunning,
|
|
925
925
|
lockPath,
|
|
926
926
|
staleMs,
|
|
@@ -930,7 +930,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
930
930
|
continue;
|
|
931
931
|
}
|
|
932
932
|
if (reclaimLock) {
|
|
933
|
-
await removeLockFile(
|
|
933
|
+
await removeLockFile(fs4, lockPath, options.signal);
|
|
934
934
|
continue;
|
|
935
935
|
}
|
|
936
936
|
if (attempt >= retries) {
|
|
@@ -1107,6 +1107,24 @@ var codexAgent = {
|
|
|
1107
1107
|
}
|
|
1108
1108
|
};
|
|
1109
1109
|
|
|
1110
|
+
// packages/agent-defs/src/agents/gemini-cli.ts
|
|
1111
|
+
var geminiCliAgent = {
|
|
1112
|
+
id: "gemini-cli",
|
|
1113
|
+
name: "gemini-cli",
|
|
1114
|
+
aliases: ["gemini"],
|
|
1115
|
+
label: "Gemini CLI",
|
|
1116
|
+
summary: "Configure Google's Gemini CLI to use a compatible Google generations API.",
|
|
1117
|
+
binaryName: "gemini",
|
|
1118
|
+
configPath: "~/.gemini/settings.json",
|
|
1119
|
+
apiShapes: ["google-generations"],
|
|
1120
|
+
branding: {
|
|
1121
|
+
colors: {
|
|
1122
|
+
dark: "#8AB4F8",
|
|
1123
|
+
light: "#1A73E8"
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
|
|
1110
1128
|
// packages/agent-defs/src/agents/opencode.ts
|
|
1111
1129
|
var openCodeAgent = {
|
|
1112
1130
|
id: "opencode",
|
|
@@ -1180,6 +1198,7 @@ var allAgents = [
|
|
|
1180
1198
|
claudeCodeAgent,
|
|
1181
1199
|
claudeDesktopAgent,
|
|
1182
1200
|
codexAgent,
|
|
1201
|
+
geminiCliAgent,
|
|
1183
1202
|
openCodeAgent,
|
|
1184
1203
|
kimiAgent,
|
|
1185
1204
|
gooseAgent,
|
|
@@ -1230,29 +1249,29 @@ function wrapForLogTee(argv, jobId) {
|
|
|
1230
1249
|
return ["sh", "-c", script];
|
|
1231
1250
|
}
|
|
1232
1251
|
async function* streamLogFile(env, jobId, opts) {
|
|
1233
|
-
const
|
|
1252
|
+
const fs4 = env.fs ?? nodeFs;
|
|
1234
1253
|
const file = jobLogPath(jobId);
|
|
1235
1254
|
let byteOffset = opts.sinceByte ?? 0;
|
|
1236
1255
|
while (true) {
|
|
1237
|
-
if (opts.since !== void 0 && !await wasModifiedSince(
|
|
1238
|
-
await waitForLogChange(
|
|
1256
|
+
if (opts.since !== void 0 && !await wasModifiedSince(fs4, file, opts.since)) {
|
|
1257
|
+
await waitForLogChange(fs4, file);
|
|
1239
1258
|
continue;
|
|
1240
1259
|
}
|
|
1241
|
-
const result = await readLogChunk(
|
|
1260
|
+
const result = await readLogChunk(fs4, file, byteOffset);
|
|
1242
1261
|
if (result !== null) {
|
|
1243
1262
|
byteOffset = result.nextByteOffset;
|
|
1244
1263
|
yield result.chunk;
|
|
1245
1264
|
continue;
|
|
1246
1265
|
}
|
|
1247
|
-
await waitForLogChange(
|
|
1266
|
+
await waitForLogChange(fs4, file);
|
|
1248
1267
|
}
|
|
1249
1268
|
}
|
|
1250
|
-
async function wasModifiedSince(
|
|
1251
|
-
if (
|
|
1269
|
+
async function wasModifiedSince(fs4, file, since) {
|
|
1270
|
+
if (fs4.promises.stat === void 0) {
|
|
1252
1271
|
return true;
|
|
1253
1272
|
}
|
|
1254
1273
|
try {
|
|
1255
|
-
const stat3 = await
|
|
1274
|
+
const stat3 = await fs4.promises.stat(file);
|
|
1256
1275
|
return stat3.mtimeMs >= since.getTime();
|
|
1257
1276
|
} catch (error2) {
|
|
1258
1277
|
if (isNodeError(error2) && error2.code === "ENOENT") {
|
|
@@ -1262,11 +1281,11 @@ async function wasModifiedSince(fs3, file, since) {
|
|
|
1262
1281
|
}
|
|
1263
1282
|
}
|
|
1264
1283
|
async function waitForExit(env, jobId, opts = {}) {
|
|
1265
|
-
const
|
|
1284
|
+
const fs4 = env.fs ?? nodeFs;
|
|
1266
1285
|
const file = jobExitPath(jobId);
|
|
1267
1286
|
while (true) {
|
|
1268
1287
|
throwIfAborted2(opts.signal);
|
|
1269
|
-
const contents = await readTextFileIfExists(
|
|
1288
|
+
const contents = await readTextFileIfExists(fs4, file);
|
|
1270
1289
|
if (contents !== null) {
|
|
1271
1290
|
const text5 = contents.trim();
|
|
1272
1291
|
const exitCode = Number(text5);
|
|
@@ -1284,8 +1303,8 @@ function jobLogPath(jobId) {
|
|
|
1284
1303
|
function jobExitPath(jobId) {
|
|
1285
1304
|
return `${JOB_DIR}/${jobId}.exit`;
|
|
1286
1305
|
}
|
|
1287
|
-
async function readLogChunk(
|
|
1288
|
-
const contents = await readFileIfExists(
|
|
1306
|
+
async function readLogChunk(fs4, file, byteOffset) {
|
|
1307
|
+
const contents = await readFileIfExists(fs4, file);
|
|
1289
1308
|
if (contents === null || byteOffset >= contents.byteLength) {
|
|
1290
1309
|
return null;
|
|
1291
1310
|
}
|
|
@@ -1297,13 +1316,13 @@ async function readLogChunk(fs3, file, byteOffset) {
|
|
|
1297
1316
|
nextByteOffset: contents.byteLength
|
|
1298
1317
|
};
|
|
1299
1318
|
}
|
|
1300
|
-
async function readTextFileIfExists(
|
|
1301
|
-
const contents = await readFileIfExists(
|
|
1319
|
+
async function readTextFileIfExists(fs4, file) {
|
|
1320
|
+
const contents = await readFileIfExists(fs4, file);
|
|
1302
1321
|
return contents?.toString("utf8") ?? null;
|
|
1303
1322
|
}
|
|
1304
|
-
async function readFileIfExists(
|
|
1323
|
+
async function readFileIfExists(fs4, file) {
|
|
1305
1324
|
try {
|
|
1306
|
-
const contents = await
|
|
1325
|
+
const contents = await fs4.promises.readFile(file);
|
|
1307
1326
|
return Buffer.isBuffer(contents) ? contents : Buffer.from(contents);
|
|
1308
1327
|
} catch (error2) {
|
|
1309
1328
|
if (isNodeError(error2) && error2.code === "ENOENT") {
|
|
@@ -1312,8 +1331,8 @@ async function readFileIfExists(fs3, file) {
|
|
|
1312
1331
|
throw error2;
|
|
1313
1332
|
}
|
|
1314
1333
|
}
|
|
1315
|
-
async function waitForLogChange(
|
|
1316
|
-
const watch =
|
|
1334
|
+
async function waitForLogChange(fs4, file) {
|
|
1335
|
+
const watch = fs4.watch;
|
|
1317
1336
|
if (typeof watch !== "function") {
|
|
1318
1337
|
await sleep2(POLL_INTERVAL_MS);
|
|
1319
1338
|
return;
|
|
@@ -2279,7 +2298,7 @@ import path14 from "node:path";
|
|
|
2279
2298
|
|
|
2280
2299
|
// packages/config-extends/src/discover.ts
|
|
2281
2300
|
import path10 from "node:path";
|
|
2282
|
-
async function findBase(name, bases,
|
|
2301
|
+
async function findBase(name, bases, fs4) {
|
|
2283
2302
|
const checkedPaths = [];
|
|
2284
2303
|
for (const basePath of bases) {
|
|
2285
2304
|
for (const extension of [".md", ".yaml", ".yml", ".json"]) {
|
|
@@ -2287,7 +2306,7 @@ async function findBase(name, bases, fs3) {
|
|
|
2287
2306
|
checkedPaths.push(filePath);
|
|
2288
2307
|
try {
|
|
2289
2308
|
return {
|
|
2290
|
-
content: await
|
|
2309
|
+
content: await fs4.readFile(filePath, "utf8"),
|
|
2291
2310
|
filePath
|
|
2292
2311
|
};
|
|
2293
2312
|
} catch (error2) {
|
|
@@ -2367,11 +2386,11 @@ function stripBom(content) {
|
|
|
2367
2386
|
function mergeLayers(layers) {
|
|
2368
2387
|
return mergeObjectLayers(layers, []);
|
|
2369
2388
|
}
|
|
2370
|
-
function mergeObjectLayers(layers,
|
|
2389
|
+
function mergeObjectLayers(layers, path37) {
|
|
2371
2390
|
const data = {};
|
|
2372
2391
|
const sources = {};
|
|
2373
2392
|
for (const key of collectKeys(layers)) {
|
|
2374
|
-
const resolved = resolveKey(layers, key,
|
|
2393
|
+
const resolved = resolveKey(layers, key, path37);
|
|
2375
2394
|
if (resolved === void 0) {
|
|
2376
2395
|
continue;
|
|
2377
2396
|
}
|
|
@@ -2389,7 +2408,7 @@ function collectKeys(layers) {
|
|
|
2389
2408
|
}
|
|
2390
2409
|
return [...keys];
|
|
2391
2410
|
}
|
|
2392
|
-
function resolveKey(layers, key,
|
|
2411
|
+
function resolveKey(layers, key, path37) {
|
|
2393
2412
|
let winningSource;
|
|
2394
2413
|
let winningValue;
|
|
2395
2414
|
const objectLayers = [];
|
|
@@ -2419,9 +2438,9 @@ function resolveKey(layers, key, path32) {
|
|
|
2419
2438
|
if (winningSource === void 0) {
|
|
2420
2439
|
return void 0;
|
|
2421
2440
|
}
|
|
2422
|
-
const fullPath = buildPath(
|
|
2441
|
+
const fullPath = buildPath(path37, key);
|
|
2423
2442
|
if (isPlainObject(winningValue)) {
|
|
2424
|
-
const merged = mergeObjectLayers(objectLayers, [...
|
|
2443
|
+
const merged = mergeObjectLayers(objectLayers, [...path37, key]);
|
|
2425
2444
|
return {
|
|
2426
2445
|
value: merged.data,
|
|
2427
2446
|
sources: {
|
|
@@ -2446,8 +2465,8 @@ function isWinningCandidate(key, value) {
|
|
|
2446
2465
|
}
|
|
2447
2466
|
return true;
|
|
2448
2467
|
}
|
|
2449
|
-
function buildPath(
|
|
2450
|
-
return [...
|
|
2468
|
+
function buildPath(path37, key) {
|
|
2469
|
+
return [...path37, key].join(".");
|
|
2451
2470
|
}
|
|
2452
2471
|
function isPlainObject(value) {
|
|
2453
2472
|
if (value === null || Array.isArray(value) || typeof value !== "object") {
|
|
@@ -3835,16 +3854,16 @@ function getConfigFormat(pathOrFormat) {
|
|
|
3835
3854
|
}
|
|
3836
3855
|
return formatRegistry[formatName];
|
|
3837
3856
|
}
|
|
3838
|
-
function detectFormat2(
|
|
3839
|
-
const ext = getExtension(
|
|
3857
|
+
function detectFormat2(path37) {
|
|
3858
|
+
const ext = getExtension(path37);
|
|
3840
3859
|
return extensionMap[ext];
|
|
3841
3860
|
}
|
|
3842
|
-
function getExtension(
|
|
3843
|
-
const lastDot =
|
|
3861
|
+
function getExtension(path37) {
|
|
3862
|
+
const lastDot = path37.lastIndexOf(".");
|
|
3844
3863
|
if (lastDot === -1) {
|
|
3845
3864
|
return "";
|
|
3846
3865
|
}
|
|
3847
|
-
return
|
|
3866
|
+
return path37.slice(lastDot).toLowerCase();
|
|
3848
3867
|
}
|
|
3849
3868
|
|
|
3850
3869
|
// packages/config-mutations/src/execution/path-utils.ts
|
|
@@ -3895,9 +3914,9 @@ function resolvePath(rawPath, homeDir, pathMapper) {
|
|
|
3895
3914
|
function isNotFound(error2) {
|
|
3896
3915
|
return typeof error2 === "object" && error2 !== null && "code" in error2 && error2.code === "ENOENT";
|
|
3897
3916
|
}
|
|
3898
|
-
async function readFileIfExists2(
|
|
3917
|
+
async function readFileIfExists2(fs4, target) {
|
|
3899
3918
|
try {
|
|
3900
|
-
return await
|
|
3919
|
+
return await fs4.readFile(target, "utf8");
|
|
3901
3920
|
} catch (error2) {
|
|
3902
3921
|
if (isNotFound(error2)) {
|
|
3903
3922
|
return null;
|
|
@@ -3905,9 +3924,9 @@ async function readFileIfExists2(fs3, target) {
|
|
|
3905
3924
|
throw error2;
|
|
3906
3925
|
}
|
|
3907
3926
|
}
|
|
3908
|
-
async function pathExists(
|
|
3927
|
+
async function pathExists(fs4, target) {
|
|
3909
3928
|
try {
|
|
3910
|
-
await
|
|
3929
|
+
await fs4.stat(target);
|
|
3911
3930
|
return true;
|
|
3912
3931
|
} catch (error2) {
|
|
3913
3932
|
if (isNotFound(error2)) {
|
|
@@ -3931,9 +3950,9 @@ function createInvalidDocumentBackupPath(targetPath) {
|
|
|
3931
3950
|
const ext = targetPath.includes(".") ? targetPath.split(".").pop() : "bak";
|
|
3932
3951
|
return `${targetPath}.invalid-${createTimestamp()}.${ext}`;
|
|
3933
3952
|
}
|
|
3934
|
-
async function backupInvalidDocument(
|
|
3953
|
+
async function backupInvalidDocument(fs4, targetPath, content) {
|
|
3935
3954
|
const backupPath = createInvalidDocumentBackupPath(targetPath);
|
|
3936
|
-
await
|
|
3955
|
+
await fs4.writeFile(backupPath, content, { encoding: "utf8" });
|
|
3937
3956
|
}
|
|
3938
3957
|
function describeMutation(kind, targetPath) {
|
|
3939
3958
|
const displayPath = targetPath ?? "target";
|
|
@@ -4496,12 +4515,12 @@ function isConfigObject5(value) {
|
|
|
4496
4515
|
}
|
|
4497
4516
|
|
|
4498
4517
|
// packages/poe-code-config/src/store.ts
|
|
4499
|
-
async function readMergedDocument(
|
|
4500
|
-
const globalDocument = await readStoredDocument(
|
|
4518
|
+
async function readMergedDocument(fs4, globalPath, projectPath) {
|
|
4519
|
+
const globalDocument = await readStoredDocument(fs4, globalPath);
|
|
4501
4520
|
if (!projectPath || projectPath === globalPath) {
|
|
4502
4521
|
return globalDocument.data;
|
|
4503
4522
|
}
|
|
4504
|
-
const projectDocument = await readStoredDocument(
|
|
4523
|
+
const projectDocument = await readStoredDocument(fs4, projectPath);
|
|
4505
4524
|
const resolved = await resolve(
|
|
4506
4525
|
[
|
|
4507
4526
|
{
|
|
@@ -4515,16 +4534,16 @@ async function readMergedDocument(fs3, globalPath, projectPath) {
|
|
|
4515
4534
|
}
|
|
4516
4535
|
],
|
|
4517
4536
|
{
|
|
4518
|
-
fs: createResolvedConfigFs(
|
|
4537
|
+
fs: createResolvedConfigFs(fs4, globalPath, globalDocument.content),
|
|
4519
4538
|
autoExtend: true
|
|
4520
4539
|
}
|
|
4521
4540
|
);
|
|
4522
4541
|
return normalizeDocument(resolved.data);
|
|
4523
4542
|
}
|
|
4524
|
-
async function readStoredDocument(
|
|
4543
|
+
async function readStoredDocument(fs4, filePath) {
|
|
4525
4544
|
try {
|
|
4526
|
-
const raw = await
|
|
4527
|
-
return await parseStoredDocument(
|
|
4545
|
+
const raw = await fs4.readFile(filePath, "utf8");
|
|
4546
|
+
return await parseStoredDocument(fs4, filePath, raw);
|
|
4528
4547
|
} catch (error2) {
|
|
4529
4548
|
if (isNotFound(error2)) {
|
|
4530
4549
|
return {
|
|
@@ -4535,7 +4554,7 @@ async function readStoredDocument(fs3, filePath) {
|
|
|
4535
4554
|
throw error2;
|
|
4536
4555
|
}
|
|
4537
4556
|
}
|
|
4538
|
-
async function parseStoredDocument(
|
|
4557
|
+
async function parseStoredDocument(fs4, filePath, raw) {
|
|
4539
4558
|
try {
|
|
4540
4559
|
return {
|
|
4541
4560
|
content: raw,
|
|
@@ -4543,7 +4562,7 @@ async function parseStoredDocument(fs3, filePath, raw) {
|
|
|
4543
4562
|
};
|
|
4544
4563
|
} catch (error2) {
|
|
4545
4564
|
if (error2 instanceof SyntaxError) {
|
|
4546
|
-
await recoverInvalidDocument(
|
|
4565
|
+
await recoverInvalidDocument(fs4, filePath, raw);
|
|
4547
4566
|
return {
|
|
4548
4567
|
content: EMPTY_DOCUMENT,
|
|
4549
4568
|
data: {}
|
|
@@ -4577,21 +4596,21 @@ function normalizeScopeValues(value) {
|
|
|
4577
4596
|
}
|
|
4578
4597
|
return normalized;
|
|
4579
4598
|
}
|
|
4580
|
-
function createResolvedConfigFs(
|
|
4599
|
+
function createResolvedConfigFs(fs4, globalPath, globalContent) {
|
|
4581
4600
|
return {
|
|
4582
4601
|
readFile(filePath, _encoding) {
|
|
4583
4602
|
if (filePath === globalPath) {
|
|
4584
4603
|
return Promise.resolve(globalContent);
|
|
4585
4604
|
}
|
|
4586
|
-
return
|
|
4605
|
+
return fs4.readFile(filePath, "utf8");
|
|
4587
4606
|
}
|
|
4588
4607
|
};
|
|
4589
4608
|
}
|
|
4590
|
-
async function recoverInvalidDocument(
|
|
4591
|
-
await
|
|
4609
|
+
async function recoverInvalidDocument(fs4, filePath, content) {
|
|
4610
|
+
await fs4.mkdir(path14.dirname(filePath), { recursive: true });
|
|
4592
4611
|
const backupPath = createInvalidBackupPath(filePath);
|
|
4593
|
-
await
|
|
4594
|
-
await
|
|
4612
|
+
await fs4.writeFile(backupPath, content, { encoding: "utf8" });
|
|
4613
|
+
await fs4.writeFile(filePath, EMPTY_DOCUMENT, { encoding: "utf8" });
|
|
4595
4614
|
}
|
|
4596
4615
|
function createInvalidBackupPath(filePath) {
|
|
4597
4616
|
const directory = path14.dirname(filePath);
|
|
@@ -4715,7 +4734,7 @@ function mergeScope(scope, baseScope, overrideScope) {
|
|
|
4715
4734
|
...Object.fromEntries(scopeEntries)
|
|
4716
4735
|
};
|
|
4717
4736
|
}
|
|
4718
|
-
function mergeRuntimeScope(baseScope, overrideScope,
|
|
4737
|
+
function mergeRuntimeScope(baseScope, overrideScope, path37 = []) {
|
|
4719
4738
|
const merged = {};
|
|
4720
4739
|
const keys = /* @__PURE__ */ new Set([...Object.keys(baseScope), ...Object.keys(overrideScope)]);
|
|
4721
4740
|
for (const key of keys) {
|
|
@@ -4727,20 +4746,20 @@ function mergeRuntimeScope(baseScope, overrideScope, path32 = []) {
|
|
|
4727
4746
|
}
|
|
4728
4747
|
continue;
|
|
4729
4748
|
}
|
|
4730
|
-
if (isRuntimeConcatenativeArray([...
|
|
4749
|
+
if (isRuntimeConcatenativeArray([...path37, key]) && Array.isArray(baseValue) && Array.isArray(overrideValue)) {
|
|
4731
4750
|
merged[key] = [...baseValue, ...overrideValue];
|
|
4732
4751
|
continue;
|
|
4733
4752
|
}
|
|
4734
4753
|
if (isRecord4(baseValue) && isRecord4(overrideValue)) {
|
|
4735
|
-
merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...
|
|
4754
|
+
merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...path37, key]);
|
|
4736
4755
|
continue;
|
|
4737
4756
|
}
|
|
4738
4757
|
merged[key] = overrideValue;
|
|
4739
4758
|
}
|
|
4740
4759
|
return merged;
|
|
4741
4760
|
}
|
|
4742
|
-
function isRuntimeConcatenativeArray(
|
|
4743
|
-
return
|
|
4761
|
+
function isRuntimeConcatenativeArray(path37) {
|
|
4762
|
+
return path37.join(".") === "mounts" || path37.join(".") === "runner.workspace.exclude";
|
|
4744
4763
|
}
|
|
4745
4764
|
function isRecord4(value) {
|
|
4746
4765
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -4928,6 +4947,7 @@ var poeProvider = {
|
|
|
4928
4947
|
label: "Poe",
|
|
4929
4948
|
summary: "Route AI coding agents through Poe's API.",
|
|
4930
4949
|
baseUrl: "https://api.poe.com",
|
|
4950
|
+
agentBaseUrl: "https://api.poe.com",
|
|
4931
4951
|
auth: {
|
|
4932
4952
|
kind: "api-key",
|
|
4933
4953
|
envVar: "POE_API_KEY",
|
|
@@ -4935,6 +4955,12 @@ var poeProvider = {
|
|
|
4935
4955
|
prompt: { title: "Poe API key" },
|
|
4936
4956
|
preferredLogin: "oauth"
|
|
4937
4957
|
},
|
|
4958
|
+
env: {
|
|
4959
|
+
ANTHROPIC_CUSTOM_HEADERS: {
|
|
4960
|
+
kind: "providerCredential",
|
|
4961
|
+
prefix: "Authorization: Bearer "
|
|
4962
|
+
}
|
|
4963
|
+
},
|
|
4938
4964
|
apiShapes: [
|
|
4939
4965
|
{
|
|
4940
4966
|
id: "openai-chat-completions",
|
|
@@ -4963,6 +4989,9 @@ var anthropicProvider = {
|
|
|
4963
4989
|
storageKey: "provider:anthropic",
|
|
4964
4990
|
prompt: { title: "Anthropic API key" }
|
|
4965
4991
|
},
|
|
4992
|
+
env: {
|
|
4993
|
+
ANTHROPIC_API_KEY: { kind: "providerCredential" }
|
|
4994
|
+
},
|
|
4966
4995
|
apiShapes: [
|
|
4967
4996
|
{
|
|
4968
4997
|
id: "anthropic-messages",
|
|
@@ -4975,30 +5004,38 @@ var anthropicProvider = {
|
|
|
4975
5004
|
var cloudflareProvider = {
|
|
4976
5005
|
id: "cloudflare",
|
|
4977
5006
|
label: "Cloudflare AI Gateway",
|
|
4978
|
-
summary: "Route
|
|
4979
|
-
|
|
5007
|
+
summary: "Route coding agents through Cloudflare AI Gateway.",
|
|
5008
|
+
baseUrlEnvVar: "CF_AIG_BASE_URL",
|
|
5009
|
+
requiresBaseUrl: true,
|
|
5010
|
+
modelInput: { kind: "freeform" },
|
|
4980
5011
|
auth: {
|
|
4981
5012
|
kind: "api-key",
|
|
4982
|
-
envVar: "
|
|
5013
|
+
envVar: "CF_AIG_TOKEN",
|
|
4983
5014
|
storageKey: "provider:cloudflare",
|
|
4984
|
-
prompt: { title: "Cloudflare
|
|
5015
|
+
prompt: { title: "Cloudflare AI Gateway token" }
|
|
5016
|
+
},
|
|
5017
|
+
env: {
|
|
5018
|
+
ANTHROPIC_CUSTOM_HEADERS: {
|
|
5019
|
+
kind: "providerCredential",
|
|
5020
|
+
prefix: "Authorization: Bearer "
|
|
5021
|
+
}
|
|
4985
5022
|
},
|
|
4986
5023
|
apiShapes: [
|
|
4987
5024
|
{
|
|
4988
5025
|
id: "openai-chat-completions",
|
|
4989
|
-
|
|
5026
|
+
baseUrlPath: "compat"
|
|
4990
5027
|
},
|
|
4991
5028
|
{
|
|
4992
5029
|
id: "openai-responses",
|
|
4993
|
-
|
|
5030
|
+
baseUrlPath: "openai"
|
|
4994
5031
|
},
|
|
4995
5032
|
{
|
|
4996
5033
|
id: "anthropic-messages",
|
|
4997
|
-
|
|
5034
|
+
baseUrlPath: "anthropic"
|
|
4998
5035
|
},
|
|
4999
5036
|
{
|
|
5000
5037
|
id: "google-generations",
|
|
5001
|
-
|
|
5038
|
+
baseUrlPath: "google-ai-studio"
|
|
5002
5039
|
}
|
|
5003
5040
|
]
|
|
5004
5041
|
};
|
|
@@ -5027,7 +5064,7 @@ function isNotFoundError(error2) {
|
|
|
5027
5064
|
}
|
|
5028
5065
|
|
|
5029
5066
|
// packages/poe-code-config/src/state/jobs.ts
|
|
5030
|
-
function createJobRegistry(homeDir,
|
|
5067
|
+
function createJobRegistry(homeDir, fs4 = defaultStateFs) {
|
|
5031
5068
|
const jobsDir = path17.join(homeDir, ".poe-code", "state", "jobs");
|
|
5032
5069
|
function jobPath(id) {
|
|
5033
5070
|
assertSafeJobId(id);
|
|
@@ -5035,7 +5072,7 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5035
5072
|
}
|
|
5036
5073
|
async function get(id) {
|
|
5037
5074
|
try {
|
|
5038
|
-
return parseJobEntry(await
|
|
5075
|
+
return parseJobEntry(await fs4.readFile(jobPath(id), "utf8"));
|
|
5039
5076
|
} catch (error2) {
|
|
5040
5077
|
if (isNotFoundError(error2)) {
|
|
5041
5078
|
return null;
|
|
@@ -5046,8 +5083,8 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5046
5083
|
async function put(entry) {
|
|
5047
5084
|
assertJobEntry(entry);
|
|
5048
5085
|
const filePath = jobPath(entry.id);
|
|
5049
|
-
await
|
|
5050
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5086
|
+
await fs4.mkdir(jobsDir, { recursive: true });
|
|
5087
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5051
5088
|
try {
|
|
5052
5089
|
await writeJobAtomically(filePath, entry);
|
|
5053
5090
|
} finally {
|
|
@@ -5056,8 +5093,8 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5056
5093
|
}
|
|
5057
5094
|
async function update(id, patch) {
|
|
5058
5095
|
const filePath = jobPath(id);
|
|
5059
|
-
await
|
|
5060
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5096
|
+
await fs4.mkdir(jobsDir, { recursive: true });
|
|
5097
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5061
5098
|
try {
|
|
5062
5099
|
const current = await get(id);
|
|
5063
5100
|
if (current === null) {
|
|
@@ -5078,7 +5115,7 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5078
5115
|
async function list(filter = {}) {
|
|
5079
5116
|
let entries;
|
|
5080
5117
|
try {
|
|
5081
|
-
entries = await
|
|
5118
|
+
entries = await fs4.readdir(jobsDir);
|
|
5082
5119
|
} catch (error2) {
|
|
5083
5120
|
if (isNotFoundError(error2)) {
|
|
5084
5121
|
return [];
|
|
@@ -5091,11 +5128,11 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5091
5128
|
continue;
|
|
5092
5129
|
}
|
|
5093
5130
|
const filePath = path17.join(jobsDir, entry);
|
|
5094
|
-
const stat3 = await
|
|
5131
|
+
const stat3 = await fs4.stat(filePath);
|
|
5095
5132
|
if (!stat3.isFile()) {
|
|
5096
5133
|
continue;
|
|
5097
5134
|
}
|
|
5098
|
-
const job = parseJobEntry(await
|
|
5135
|
+
const job = parseJobEntry(await fs4.readFile(filePath, "utf8"));
|
|
5099
5136
|
if (matchesFilter(job, filter)) {
|
|
5100
5137
|
jobs.push(job);
|
|
5101
5138
|
}
|
|
@@ -5105,16 +5142,16 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5105
5142
|
async function remove2(id) {
|
|
5106
5143
|
const filePath = jobPath(id);
|
|
5107
5144
|
try {
|
|
5108
|
-
await
|
|
5145
|
+
await fs4.stat(jobsDir);
|
|
5109
5146
|
} catch (error2) {
|
|
5110
5147
|
if (isNotFoundError(error2)) {
|
|
5111
5148
|
return;
|
|
5112
5149
|
}
|
|
5113
5150
|
throw error2;
|
|
5114
5151
|
}
|
|
5115
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5152
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5116
5153
|
try {
|
|
5117
|
-
await
|
|
5154
|
+
await fs4.unlink(filePath);
|
|
5118
5155
|
} catch (error2) {
|
|
5119
5156
|
if (!isNotFoundError(error2)) {
|
|
5120
5157
|
throw error2;
|
|
@@ -5124,14 +5161,14 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5124
5161
|
}
|
|
5125
5162
|
}
|
|
5126
5163
|
async function writeJobAtomically(filePath, entry) {
|
|
5127
|
-
await
|
|
5164
|
+
await fs4.mkdir(path17.dirname(filePath), { recursive: true });
|
|
5128
5165
|
const tempPath = `${filePath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
5129
5166
|
try {
|
|
5130
|
-
await
|
|
5167
|
+
await fs4.writeFile(tempPath, `${JSON.stringify(entry, null, 2)}
|
|
5131
5168
|
`, {
|
|
5132
5169
|
encoding: "utf8"
|
|
5133
5170
|
});
|
|
5134
|
-
await
|
|
5171
|
+
await fs4.rename(tempPath, filePath);
|
|
5135
5172
|
} catch (error2) {
|
|
5136
5173
|
await removeTempFile(tempPath);
|
|
5137
5174
|
throw error2;
|
|
@@ -5139,7 +5176,7 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5139
5176
|
}
|
|
5140
5177
|
async function removeTempFile(tempPath) {
|
|
5141
5178
|
try {
|
|
5142
|
-
await
|
|
5179
|
+
await fs4.unlink(tempPath);
|
|
5143
5180
|
} catch (error2) {
|
|
5144
5181
|
if (!isNotFoundError(error2)) {
|
|
5145
5182
|
throw error2;
|
|
@@ -5186,11 +5223,11 @@ function isRecord5(value) {
|
|
|
5186
5223
|
|
|
5187
5224
|
// packages/poe-code-config/src/state/templates.ts
|
|
5188
5225
|
import path18 from "node:path";
|
|
5189
|
-
function createTemplateRegistry(homeDir,
|
|
5226
|
+
function createTemplateRegistry(homeDir, fs4 = defaultStateFs) {
|
|
5190
5227
|
const filePath = path18.join(homeDir, ".poe-code", "state", "templates.json");
|
|
5191
5228
|
async function readState() {
|
|
5192
5229
|
try {
|
|
5193
|
-
const raw = await
|
|
5230
|
+
const raw = await fs4.readFile(filePath, "utf8");
|
|
5194
5231
|
return normalizeTemplateState(JSON.parse(raw));
|
|
5195
5232
|
} catch (error2) {
|
|
5196
5233
|
if (isNotFoundError(error2)) {
|
|
@@ -5200,14 +5237,14 @@ function createTemplateRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5200
5237
|
}
|
|
5201
5238
|
}
|
|
5202
5239
|
async function writeState(state) {
|
|
5203
|
-
await
|
|
5240
|
+
await fs4.writeFile(filePath, `${JSON.stringify(state, null, 2)}
|
|
5204
5241
|
`, {
|
|
5205
5242
|
encoding: "utf8"
|
|
5206
5243
|
});
|
|
5207
5244
|
}
|
|
5208
5245
|
async function updateState(mutator) {
|
|
5209
|
-
await
|
|
5210
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5246
|
+
await fs4.mkdir(path18.dirname(filePath), { recursive: true });
|
|
5247
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5211
5248
|
try {
|
|
5212
5249
|
const state = await readState();
|
|
5213
5250
|
mutator(state);
|
|
@@ -5277,10 +5314,10 @@ function isRecord6(value) {
|
|
|
5277
5314
|
}
|
|
5278
5315
|
|
|
5279
5316
|
// packages/poe-code-config/src/state/index.ts
|
|
5280
|
-
function createStateManager(homeDir,
|
|
5317
|
+
function createStateManager(homeDir, fs4) {
|
|
5281
5318
|
return {
|
|
5282
|
-
templates: createTemplateRegistry(homeDir,
|
|
5283
|
-
jobs: createJobRegistry(homeDir,
|
|
5319
|
+
templates: createTemplateRegistry(homeDir, fs4),
|
|
5320
|
+
jobs: createJobRegistry(homeDir, fs4)
|
|
5284
5321
|
};
|
|
5285
5322
|
}
|
|
5286
5323
|
|
|
@@ -5595,7 +5632,7 @@ import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream"
|
|
|
5595
5632
|
import path21 from "node:path";
|
|
5596
5633
|
var JOB_DIR2 = "/tmp/poe-jobs";
|
|
5597
5634
|
function createE2bJobHandle(input) {
|
|
5598
|
-
const
|
|
5635
|
+
const fs4 = createE2bLogStreamFs(input.sandbox);
|
|
5599
5636
|
return {
|
|
5600
5637
|
id: input.jobId,
|
|
5601
5638
|
envId: input.envId,
|
|
@@ -5611,10 +5648,10 @@ function createE2bJobHandle(input) {
|
|
|
5611
5648
|
return isRunning ? "running" : "lost";
|
|
5612
5649
|
},
|
|
5613
5650
|
stream(opts = {}) {
|
|
5614
|
-
return streamLogFile({ fs:
|
|
5651
|
+
return streamLogFile({ fs: fs4 }, input.jobId, opts);
|
|
5615
5652
|
},
|
|
5616
5653
|
async wait() {
|
|
5617
|
-
const result = await waitForExit({ fs:
|
|
5654
|
+
const result = await waitForExit({ fs: fs4 }, input.jobId);
|
|
5618
5655
|
const preserveMs = input.preserveAfterExitHours * 60 * 60 * 1e3;
|
|
5619
5656
|
if (preserveMs > 0) {
|
|
5620
5657
|
await input.sandbox.setTimeout(preserveMs);
|
|
@@ -6111,10 +6148,10 @@ var e2bAuthScope = defineScope("e2b", {
|
|
|
6111
6148
|
});
|
|
6112
6149
|
async function resolveE2bApiKey(input) {
|
|
6113
6150
|
const homeDir = input.homeDir ?? os4.homedir();
|
|
6114
|
-
const
|
|
6151
|
+
const fs4 = input.fs ?? nodeFs4;
|
|
6115
6152
|
const env = input.env ?? process.env;
|
|
6116
6153
|
const document = await readMergedDocument(
|
|
6117
|
-
|
|
6154
|
+
fs4,
|
|
6118
6155
|
resolveConfigPath(homeDir),
|
|
6119
6156
|
resolveProjectConfigPath(input.cwd)
|
|
6120
6157
|
);
|
|
@@ -6621,6 +6658,23 @@ var gooseAcpSpawnConfig = {
|
|
|
6621
6658
|
skipAuth: true
|
|
6622
6659
|
};
|
|
6623
6660
|
|
|
6661
|
+
// packages/agent-spawn/src/configs/gemini-cli.ts
|
|
6662
|
+
var geminiCliAcpSpawnConfig = {
|
|
6663
|
+
kind: "acp",
|
|
6664
|
+
agentId: "gemini-cli",
|
|
6665
|
+
acpArgs: ({ model, mcpServers }) => [
|
|
6666
|
+
"--acp",
|
|
6667
|
+
...model ? ["--model", model] : [],
|
|
6668
|
+
...mcpServers ? ["--allowed-mcp-server-names", Object.keys(mcpServers).join(",")] : [],
|
|
6669
|
+
...mcpServers ? ["--skip-trust"] : [],
|
|
6670
|
+
"--yolo"
|
|
6671
|
+
],
|
|
6672
|
+
env: {
|
|
6673
|
+
GEMINI_SANDBOX: "false"
|
|
6674
|
+
},
|
|
6675
|
+
skipAuth: true
|
|
6676
|
+
};
|
|
6677
|
+
|
|
6624
6678
|
// packages/agent-spawn/src/configs/index.ts
|
|
6625
6679
|
var allSpawnConfigs = [
|
|
6626
6680
|
claudeCodeSpawnConfig,
|
|
@@ -6637,6 +6691,7 @@ var acpLookup = /* @__PURE__ */ new Map();
|
|
|
6637
6691
|
acpLookup.set(openCodeAcpSpawnConfig.agentId, openCodeAcpSpawnConfig);
|
|
6638
6692
|
acpLookup.set(kimiAcpSpawnConfig.agentId, kimiAcpSpawnConfig);
|
|
6639
6693
|
acpLookup.set(gooseAcpSpawnConfig.agentId, gooseAcpSpawnConfig);
|
|
6694
|
+
acpLookup.set(geminiCliAcpSpawnConfig.agentId, geminiCliAcpSpawnConfig);
|
|
6640
6695
|
function getSpawnConfig(input) {
|
|
6641
6696
|
const resolvedId = resolveAgentId(input);
|
|
6642
6697
|
if (!resolvedId) {
|
|
@@ -6656,8 +6711,8 @@ function listMcpSupportedAgents() {
|
|
|
6656
6711
|
}
|
|
6657
6712
|
|
|
6658
6713
|
// packages/agent-spawn/src/spawn.ts
|
|
6659
|
-
import { mkdirSync as
|
|
6660
|
-
import
|
|
6714
|
+
import { mkdirSync as mkdirSync5, openSync as openSync2, writeSync, closeSync as closeSync2 } from "node:fs";
|
|
6715
|
+
import path34 from "node:path";
|
|
6661
6716
|
|
|
6662
6717
|
// packages/agent-spawn/src/configs/resolve-config.ts
|
|
6663
6718
|
function resolveConfig(agentId) {
|
|
@@ -7058,7 +7113,7 @@ function createEventQueue() {
|
|
|
7058
7113
|
|
|
7059
7114
|
// packages/agent-spawn/src/skill-bridge.ts
|
|
7060
7115
|
import crypto from "node:crypto";
|
|
7061
|
-
import
|
|
7116
|
+
import os7 from "node:os";
|
|
7062
7117
|
|
|
7063
7118
|
// packages/agent-skill-config/src/configs.ts
|
|
7064
7119
|
import os5 from "node:os";
|
|
@@ -7072,6 +7127,10 @@ var agentSkillConfigs = {
|
|
|
7072
7127
|
globalSkillDir: "~/.codex/skills",
|
|
7073
7128
|
localSkillDir: ".codex/skills"
|
|
7074
7129
|
},
|
|
7130
|
+
"gemini-cli": {
|
|
7131
|
+
globalSkillDir: "~/.gemini/skills",
|
|
7132
|
+
localSkillDir: ".gemini/skills"
|
|
7133
|
+
},
|
|
7075
7134
|
opencode: {
|
|
7076
7135
|
globalSkillDir: "~/.config/opencode/skills",
|
|
7077
7136
|
localSkillDir: ".opencode/skills"
|
|
@@ -7214,7 +7273,7 @@ function resolveSkillReference(ref, cwd, homeDir) {
|
|
|
7214
7273
|
import { execFileSync } from "node:child_process";
|
|
7215
7274
|
import * as fs from "node:fs";
|
|
7216
7275
|
import path27 from "node:path";
|
|
7217
|
-
var
|
|
7276
|
+
var defaultMarkerPrefix = "poe-code-spawn-skills";
|
|
7218
7277
|
function defaultGitDirRunner(cwd) {
|
|
7219
7278
|
try {
|
|
7220
7279
|
return execFileSync("git", ["rev-parse", "--git-dir"], {
|
|
@@ -7234,10 +7293,10 @@ function resolveExcludePath(cwd) {
|
|
|
7234
7293
|
}
|
|
7235
7294
|
return path27.join(path27.isAbsolute(gitDir) ? gitDir : path27.resolve(cwd, gitDir), "info/exclude");
|
|
7236
7295
|
}
|
|
7237
|
-
function markers(runId) {
|
|
7296
|
+
function markers(runId, markerPrefix) {
|
|
7238
7297
|
return {
|
|
7239
|
-
begin:
|
|
7240
|
-
end:
|
|
7298
|
+
begin: `# ${markerPrefix}:${runId} begin`,
|
|
7299
|
+
end: `# ${markerPrefix}:${runId} end`
|
|
7241
7300
|
};
|
|
7242
7301
|
}
|
|
7243
7302
|
function readExcludeFile(excludePath) {
|
|
@@ -7253,8 +7312,8 @@ function readExcludeFile(excludePath) {
|
|
|
7253
7312
|
function isNodeError2(error2) {
|
|
7254
7313
|
return error2 instanceof Error && "code" in error2;
|
|
7255
7314
|
}
|
|
7256
|
-
function removeBlock(content, runId) {
|
|
7257
|
-
const { begin, end } = markers(runId);
|
|
7315
|
+
function removeBlock(content, runId, markerPrefix) {
|
|
7316
|
+
const { begin, end } = markers(runId, markerPrefix);
|
|
7258
7317
|
const lines = content.split("\n");
|
|
7259
7318
|
const result = [];
|
|
7260
7319
|
for (let index = 0; index < lines.length; index += 1) {
|
|
@@ -7269,23 +7328,27 @@ function removeBlock(content, runId) {
|
|
|
7269
7328
|
}
|
|
7270
7329
|
return result.join("\n");
|
|
7271
7330
|
}
|
|
7272
|
-
function appendBlock(content, runId, entries) {
|
|
7273
|
-
const { begin, end } = markers(runId);
|
|
7331
|
+
function appendBlock(content, runId, entries, markerPrefix) {
|
|
7332
|
+
const { begin, end } = markers(runId, markerPrefix);
|
|
7274
7333
|
const existing = content ?? "";
|
|
7275
7334
|
const prefix = existing.length === 0 || existing.endsWith("\n") ? existing : `${existing}
|
|
7276
7335
|
`;
|
|
7277
7336
|
return `${prefix}${[begin, ...entries, end, ""].join("\n")}`;
|
|
7278
7337
|
}
|
|
7279
|
-
function appendExcludeBlock(cwd, runId, entries) {
|
|
7338
|
+
function appendExcludeBlock(cwd, runId, entries, opts) {
|
|
7280
7339
|
const excludePath = resolveExcludePath(cwd);
|
|
7281
7340
|
if (excludePath === void 0) {
|
|
7282
7341
|
return;
|
|
7283
7342
|
}
|
|
7284
7343
|
fs.mkdirSync(path27.dirname(excludePath), { recursive: true });
|
|
7285
7344
|
const content = readExcludeFile(excludePath);
|
|
7286
|
-
fs.writeFileSync(
|
|
7345
|
+
fs.writeFileSync(
|
|
7346
|
+
excludePath,
|
|
7347
|
+
appendBlock(content, runId, entries, opts?.markerPrefix ?? defaultMarkerPrefix),
|
|
7348
|
+
"utf8"
|
|
7349
|
+
);
|
|
7287
7350
|
}
|
|
7288
|
-
function removeExcludeBlock(cwd, runId) {
|
|
7351
|
+
function removeExcludeBlock(cwd, runId, opts) {
|
|
7289
7352
|
const excludePath = resolveExcludePath(cwd);
|
|
7290
7353
|
if (excludePath === void 0) {
|
|
7291
7354
|
return;
|
|
@@ -7294,7 +7357,11 @@ function removeExcludeBlock(cwd, runId) {
|
|
|
7294
7357
|
if (content === void 0) {
|
|
7295
7358
|
return;
|
|
7296
7359
|
}
|
|
7297
|
-
fs.writeFileSync(
|
|
7360
|
+
fs.writeFileSync(
|
|
7361
|
+
excludePath,
|
|
7362
|
+
removeBlock(content, runId, opts?.markerPrefix ?? defaultMarkerPrefix),
|
|
7363
|
+
"utf8"
|
|
7364
|
+
);
|
|
7298
7365
|
}
|
|
7299
7366
|
|
|
7300
7367
|
// packages/agent-skill-config/src/bridge-active-skills.ts
|
|
@@ -7500,22 +7567,679 @@ function cleanupBridgedSkills(manifest) {
|
|
|
7500
7567
|
removeExcludeBlock(manifest.cwd, manifest.runId);
|
|
7501
7568
|
}
|
|
7502
7569
|
|
|
7570
|
+
// packages/agent-hook-config/src/configs.ts
|
|
7571
|
+
import os6 from "node:os";
|
|
7572
|
+
import path29 from "node:path";
|
|
7573
|
+
var agentHookConfigs = {
|
|
7574
|
+
"claude-code": {
|
|
7575
|
+
globalHookPath: "~/.claude/settings.json",
|
|
7576
|
+
localHookPath: ".claude/settings.json",
|
|
7577
|
+
format: "claude-settings-json",
|
|
7578
|
+
supportedEvents: [
|
|
7579
|
+
"SessionStart",
|
|
7580
|
+
"SessionEnd",
|
|
7581
|
+
"UserPromptSubmit",
|
|
7582
|
+
"PreToolUse",
|
|
7583
|
+
"PostToolUse",
|
|
7584
|
+
"PermissionRequest",
|
|
7585
|
+
"Stop",
|
|
7586
|
+
"StopFailure",
|
|
7587
|
+
"Notification",
|
|
7588
|
+
"PreCompact",
|
|
7589
|
+
"PostCompact",
|
|
7590
|
+
"SubagentStart",
|
|
7591
|
+
"SubagentStop"
|
|
7592
|
+
],
|
|
7593
|
+
supportedHandlerTypes: ["command", "http", "mcp_tool", "prompt", "agent"],
|
|
7594
|
+
placeholders: {
|
|
7595
|
+
projectDir: "${CLAUDE_PROJECT_DIR}",
|
|
7596
|
+
pluginRoot: "${CLAUDE_PLUGIN_ROOT}",
|
|
7597
|
+
pluginData: "${CLAUDE_PLUGIN_DATA}"
|
|
7598
|
+
}
|
|
7599
|
+
},
|
|
7600
|
+
codex: {
|
|
7601
|
+
globalHookPath: "~/.codex/hooks.json",
|
|
7602
|
+
localHookPath: ".codex/hooks.json",
|
|
7603
|
+
format: "codex-hooks-json",
|
|
7604
|
+
supportedEvents: [
|
|
7605
|
+
"SessionStart",
|
|
7606
|
+
"UserPromptSubmit",
|
|
7607
|
+
"PreToolUse",
|
|
7608
|
+
"PostToolUse",
|
|
7609
|
+
"PermissionRequest",
|
|
7610
|
+
"Stop"
|
|
7611
|
+
],
|
|
7612
|
+
supportedHandlerTypes: ["command"],
|
|
7613
|
+
placeholders: {
|
|
7614
|
+
projectDir: "$(git rev-parse --show-toplevel)",
|
|
7615
|
+
pluginRoot: "$PLUGIN_ROOT",
|
|
7616
|
+
pluginData: "$PLUGIN_DATA"
|
|
7617
|
+
}
|
|
7618
|
+
}
|
|
7619
|
+
};
|
|
7620
|
+
var supportedHookAgents = Object.keys(agentHookConfigs);
|
|
7621
|
+
function resolveAgentSupport2(input, registry = agentHookConfigs) {
|
|
7622
|
+
const resolvedId = resolveAgentId(input);
|
|
7623
|
+
if (!resolvedId) {
|
|
7624
|
+
return { status: "unknown", input };
|
|
7625
|
+
}
|
|
7626
|
+
const config = registry[resolvedId];
|
|
7627
|
+
if (!config) {
|
|
7628
|
+
return { status: "unsupported", input, id: resolvedId };
|
|
7629
|
+
}
|
|
7630
|
+
return { status: "supported", input, id: resolvedId, config };
|
|
7631
|
+
}
|
|
7632
|
+
function getAgentConfig2(agentId) {
|
|
7633
|
+
const support = resolveAgentSupport2(agentId);
|
|
7634
|
+
return support.status === "supported" ? support.config : void 0;
|
|
7635
|
+
}
|
|
7636
|
+
function expandHome3(targetPath, homeDir = os6.homedir()) {
|
|
7637
|
+
if (!targetPath?.startsWith("~")) {
|
|
7638
|
+
return targetPath;
|
|
7639
|
+
}
|
|
7640
|
+
if (targetPath === "~") {
|
|
7641
|
+
return homeDir;
|
|
7642
|
+
}
|
|
7643
|
+
if (targetPath.startsWith("~./")) {
|
|
7644
|
+
targetPath = `~/.${targetPath.slice(3)}`;
|
|
7645
|
+
}
|
|
7646
|
+
let remainder = targetPath.slice(1);
|
|
7647
|
+
if (remainder.startsWith("/") || remainder.startsWith("\\")) {
|
|
7648
|
+
remainder = remainder.slice(1);
|
|
7649
|
+
} else if (remainder.startsWith(".")) {
|
|
7650
|
+
remainder = remainder.slice(1);
|
|
7651
|
+
if (remainder.startsWith("/") || remainder.startsWith("\\")) {
|
|
7652
|
+
remainder = remainder.slice(1);
|
|
7653
|
+
}
|
|
7654
|
+
}
|
|
7655
|
+
return remainder.length === 0 ? homeDir : path29.join(homeDir, remainder);
|
|
7656
|
+
}
|
|
7657
|
+
function resolveHookPath(config, scope, cwd, homeDir) {
|
|
7658
|
+
if (scope === "global") {
|
|
7659
|
+
return path29.resolve(expandHome3(config.globalHookPath, homeDir));
|
|
7660
|
+
}
|
|
7661
|
+
return config.localHookPath ? path29.resolve(cwd, config.localHookPath) : void 0;
|
|
7662
|
+
}
|
|
7663
|
+
|
|
7664
|
+
// packages/agent-hook-config/src/read-hooks.ts
|
|
7665
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
7666
|
+
import path30 from "node:path";
|
|
7667
|
+
function readSettingsFile(filePath) {
|
|
7668
|
+
let content;
|
|
7669
|
+
try {
|
|
7670
|
+
content = readFileSync3(filePath, "utf8");
|
|
7671
|
+
} catch (error2) {
|
|
7672
|
+
if (error2.code === "ENOENT") {
|
|
7673
|
+
return void 0;
|
|
7674
|
+
}
|
|
7675
|
+
throw error2;
|
|
7676
|
+
}
|
|
7677
|
+
try {
|
|
7678
|
+
return JSON.parse(content);
|
|
7679
|
+
} catch (error2) {
|
|
7680
|
+
throw new Error(`Malformed JSON in ${filePath}`, { cause: error2 });
|
|
7681
|
+
}
|
|
7682
|
+
}
|
|
7683
|
+
function readClaudeHooks(cwd, homeDir, opts) {
|
|
7684
|
+
const projectPath = path30.resolve(cwd, ".claude/settings.json");
|
|
7685
|
+
const userPath = path30.resolve(homeDir, ".claude/settings.json");
|
|
7686
|
+
const scope = opts?.scope ?? "merged";
|
|
7687
|
+
const sourcePaths = scope === "project" ? [projectPath] : scope === "user" ? [userPath] : [userPath, projectPath];
|
|
7688
|
+
const result = { entries: [], readPaths: [] };
|
|
7689
|
+
for (const sourcePath of sourcePaths) {
|
|
7690
|
+
const settings = readSettingsFile(sourcePath);
|
|
7691
|
+
if (settings === void 0) {
|
|
7692
|
+
continue;
|
|
7693
|
+
}
|
|
7694
|
+
result.readPaths.push(sourcePath);
|
|
7695
|
+
for (const [event, groups] of Object.entries(settings.hooks ?? {})) {
|
|
7696
|
+
for (const group of groups) {
|
|
7697
|
+
for (const handler of group.hooks) {
|
|
7698
|
+
result.entries.push({ event, matcher: group.matcher, handler });
|
|
7699
|
+
}
|
|
7700
|
+
}
|
|
7701
|
+
}
|
|
7702
|
+
}
|
|
7703
|
+
return result;
|
|
7704
|
+
}
|
|
7705
|
+
|
|
7706
|
+
// packages/agent-hook-config/src/event-mapping.ts
|
|
7707
|
+
function requireAgentConfig(agentId) {
|
|
7708
|
+
const config = getAgentConfig2(agentId);
|
|
7709
|
+
if (!config) {
|
|
7710
|
+
throw new Error(`Unknown hook agent "${agentId}"`);
|
|
7711
|
+
}
|
|
7712
|
+
return config;
|
|
7713
|
+
}
|
|
7714
|
+
function getEventMappings(sourceAgentId, targetAgentId) {
|
|
7715
|
+
const source = requireAgentConfig(sourceAgentId);
|
|
7716
|
+
const target = requireAgentConfig(targetAgentId);
|
|
7717
|
+
return source.supportedEvents.map((sourceEvent) => {
|
|
7718
|
+
if (target.supportedEvents.includes(sourceEvent)) {
|
|
7719
|
+
return { sourceEvent, targetEvent: sourceEvent };
|
|
7720
|
+
}
|
|
7721
|
+
return {
|
|
7722
|
+
sourceEvent,
|
|
7723
|
+
targetEvent: null,
|
|
7724
|
+
dropReason: `${targetAgentId} has no ${sourceEvent} hook`
|
|
7725
|
+
};
|
|
7726
|
+
});
|
|
7727
|
+
}
|
|
7728
|
+
function getHandlerTypeRules(targetAgentId) {
|
|
7729
|
+
const target = requireAgentConfig(targetAgentId);
|
|
7730
|
+
const registeredTypes = supportedHookAgents.flatMap(
|
|
7731
|
+
(agentId) => requireAgentConfig(agentId).supportedHandlerTypes
|
|
7732
|
+
);
|
|
7733
|
+
const sourceTypes = [...new Set(registeredTypes)];
|
|
7734
|
+
const supportedTypes = target.supportedHandlerTypes.map((handlerType) => `"${handlerType}"`).join(", ");
|
|
7735
|
+
return sourceTypes.map((sourceType) => {
|
|
7736
|
+
if (target.supportedHandlerTypes.includes(sourceType)) {
|
|
7737
|
+
return { sourceType, allowed: true };
|
|
7738
|
+
}
|
|
7739
|
+
return {
|
|
7740
|
+
sourceType,
|
|
7741
|
+
allowed: false,
|
|
7742
|
+
dropReason: `${targetAgentId} only honors handlers of type ${supportedTypes}`
|
|
7743
|
+
};
|
|
7744
|
+
});
|
|
7745
|
+
}
|
|
7746
|
+
function getPlaceholderRewrites(sourceAgentId, targetAgentId) {
|
|
7747
|
+
const source = requireAgentConfig(sourceAgentId);
|
|
7748
|
+
const target = requireAgentConfig(targetAgentId);
|
|
7749
|
+
return Object.keys(source.placeholders).flatMap((key) => {
|
|
7750
|
+
const from = source.placeholders[key];
|
|
7751
|
+
const to = target.placeholders[key];
|
|
7752
|
+
if (!from || !to || from === to) {
|
|
7753
|
+
return [];
|
|
7754
|
+
}
|
|
7755
|
+
return [{ from, to }];
|
|
7756
|
+
});
|
|
7757
|
+
}
|
|
7758
|
+
|
|
7759
|
+
// packages/agent-hook-config/src/transform-hooks.ts
|
|
7760
|
+
function applyPlaceholderRewrites(value, rewrites) {
|
|
7761
|
+
return rewrites.reduce((rewrittenValue, rewrite) => {
|
|
7762
|
+
return rewrittenValue.replaceAll(rewrite.from, rewrite.to);
|
|
7763
|
+
}, value);
|
|
7764
|
+
}
|
|
7765
|
+
function transformHooks(source, sourceAgentId, targetAgentId, opts) {
|
|
7766
|
+
const eventMappings = getEventMappings(sourceAgentId, targetAgentId);
|
|
7767
|
+
const handlerRules = getHandlerTypeRules(targetAgentId);
|
|
7768
|
+
const placeholderRewrites = getPlaceholderRewrites(sourceAgentId, targetAgentId);
|
|
7769
|
+
const result = { entries: [], drops: [] };
|
|
7770
|
+
for (const sourceEntry of source) {
|
|
7771
|
+
const eventMapping = eventMappings.find((mapping) => mapping.sourceEvent === sourceEntry.event);
|
|
7772
|
+
if (!eventMapping || eventMapping.targetEvent === null) {
|
|
7773
|
+
result.drops.push({
|
|
7774
|
+
reason: "unsupported-event",
|
|
7775
|
+
detail: eventMapping?.dropReason ?? `${targetAgentId} has no ${sourceEntry.event} hook`,
|
|
7776
|
+
source: sourceEntry
|
|
7777
|
+
});
|
|
7778
|
+
continue;
|
|
7779
|
+
}
|
|
7780
|
+
const handlerRule = handlerRules.find((rule) => rule.sourceType === sourceEntry.handler.type);
|
|
7781
|
+
if (!handlerRule?.allowed) {
|
|
7782
|
+
result.drops.push({
|
|
7783
|
+
reason: "unsupported-handler-type",
|
|
7784
|
+
detail: `Unsupported handler type "${sourceEntry.handler.type}": ${handlerRule?.dropReason ?? `${targetAgentId} does not honor it`}`,
|
|
7785
|
+
source: sourceEntry
|
|
7786
|
+
});
|
|
7787
|
+
continue;
|
|
7788
|
+
}
|
|
7789
|
+
const handler = {
|
|
7790
|
+
type: "command",
|
|
7791
|
+
command: applyPlaceholderRewrites(sourceEntry.handler.command ?? "", placeholderRewrites),
|
|
7792
|
+
statusMessage: `[generated:${opts.runId}] ${sourceEntry.handler.statusMessage ?? ""}`
|
|
7793
|
+
};
|
|
7794
|
+
if (sourceEntry.handler.args !== void 0) {
|
|
7795
|
+
handler.args = sourceEntry.handler.args.map(
|
|
7796
|
+
(arg) => applyPlaceholderRewrites(arg, placeholderRewrites)
|
|
7797
|
+
);
|
|
7798
|
+
}
|
|
7799
|
+
if (sourceEntry.handler.timeout !== void 0) {
|
|
7800
|
+
handler.timeout = sourceEntry.handler.timeout;
|
|
7801
|
+
}
|
|
7802
|
+
result.entries.push({
|
|
7803
|
+
event: eventMapping.targetEvent,
|
|
7804
|
+
matcher: sourceEntry.matcher,
|
|
7805
|
+
handler,
|
|
7806
|
+
generatedId: `generated-${opts.runId}-${result.entries.length}`
|
|
7807
|
+
});
|
|
7808
|
+
}
|
|
7809
|
+
return result;
|
|
7810
|
+
}
|
|
7811
|
+
|
|
7812
|
+
// packages/agent-hook-config/src/write-hooks.ts
|
|
7813
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
7814
|
+
import path31 from "node:path";
|
|
7815
|
+
function isGeneratedHandler(handler) {
|
|
7816
|
+
return handler.statusMessage?.startsWith("[generated:") ?? false;
|
|
7817
|
+
}
|
|
7818
|
+
function parseHooksFile(targetPath) {
|
|
7819
|
+
let content;
|
|
7820
|
+
try {
|
|
7821
|
+
content = readFileSync4(targetPath, "utf8");
|
|
7822
|
+
} catch (error2) {
|
|
7823
|
+
if (error2.code === "ENOENT") {
|
|
7824
|
+
return { file: { hooks: {} }, fileCreated: true };
|
|
7825
|
+
}
|
|
7826
|
+
throw error2;
|
|
7827
|
+
}
|
|
7828
|
+
try {
|
|
7829
|
+
return { file: JSON.parse(content), fileCreated: false };
|
|
7830
|
+
} catch (error2) {
|
|
7831
|
+
throw new Error(`Malformed JSON in ${targetPath}`, { cause: error2 });
|
|
7832
|
+
}
|
|
7833
|
+
}
|
|
7834
|
+
function validateEntries(entries) {
|
|
7835
|
+
for (const entry of entries) {
|
|
7836
|
+
if (!isGeneratedHandler(entry.handler)) {
|
|
7837
|
+
throw new Error(
|
|
7838
|
+
`Generated hook entry "${entry.generatedId}" has statusMessage that must start with "[generated:"`
|
|
7839
|
+
);
|
|
7840
|
+
}
|
|
7841
|
+
}
|
|
7842
|
+
}
|
|
7843
|
+
function removeGeneratedHandlers(file) {
|
|
7844
|
+
let removed = 0;
|
|
7845
|
+
const hooks = file.hooks ?? (file.hooks = {});
|
|
7846
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
7847
|
+
hooks[event] = groups.filter((group) => {
|
|
7848
|
+
const initialCount = group.hooks.length;
|
|
7849
|
+
const remainingHandlers = group.hooks.filter((handler) => {
|
|
7850
|
+
if (isGeneratedHandler(handler)) {
|
|
7851
|
+
removed += 1;
|
|
7852
|
+
return false;
|
|
7853
|
+
}
|
|
7854
|
+
return true;
|
|
7855
|
+
});
|
|
7856
|
+
group.hooks = remainingHandlers;
|
|
7857
|
+
return group.hooks.length > 0 || group.hooks.length === initialCount;
|
|
7858
|
+
});
|
|
7859
|
+
}
|
|
7860
|
+
return removed;
|
|
7861
|
+
}
|
|
7862
|
+
function appendEntries(file, entries) {
|
|
7863
|
+
const hooks = file.hooks ?? (file.hooks = {});
|
|
7864
|
+
for (const entry of entries) {
|
|
7865
|
+
const groups = hooks[entry.event] ?? (hooks[entry.event] = []);
|
|
7866
|
+
let group = groups.find((candidate) => candidate.matcher === entry.matcher);
|
|
7867
|
+
if (!group) {
|
|
7868
|
+
group = entry.matcher === void 0 ? { hooks: [] } : { matcher: entry.matcher, hooks: [] };
|
|
7869
|
+
groups.push(group);
|
|
7870
|
+
}
|
|
7871
|
+
group.hooks.push(entry.handler);
|
|
7872
|
+
}
|
|
7873
|
+
}
|
|
7874
|
+
function writeCodexHooks(targetPath, entries, _runId) {
|
|
7875
|
+
const { file, fileCreated } = parseHooksFile(targetPath);
|
|
7876
|
+
validateEntries(entries);
|
|
7877
|
+
const previousGeneratedRemoved = removeGeneratedHandlers(file);
|
|
7878
|
+
appendEntries(file, entries);
|
|
7879
|
+
mkdirSync3(path31.dirname(targetPath), { recursive: true });
|
|
7880
|
+
const temporaryPath = `${targetPath}.tmp`;
|
|
7881
|
+
writeFileSync2(temporaryPath, `${JSON.stringify(file, null, 2)}
|
|
7882
|
+
`);
|
|
7883
|
+
renameSync(temporaryPath, targetPath);
|
|
7884
|
+
return {
|
|
7885
|
+
path: targetPath,
|
|
7886
|
+
fileCreated,
|
|
7887
|
+
previousGeneratedRemoved,
|
|
7888
|
+
generatedWritten: entries.length
|
|
7889
|
+
};
|
|
7890
|
+
}
|
|
7891
|
+
|
|
7892
|
+
// packages/agent-hook-config/src/symlink-hooks.ts
|
|
7893
|
+
import {
|
|
7894
|
+
closeSync,
|
|
7895
|
+
lstatSync,
|
|
7896
|
+
mkdirSync as mkdirSync4,
|
|
7897
|
+
openSync,
|
|
7898
|
+
readlinkSync,
|
|
7899
|
+
readSync,
|
|
7900
|
+
symlinkSync,
|
|
7901
|
+
unlinkSync
|
|
7902
|
+
} from "node:fs";
|
|
7903
|
+
import path32 from "node:path";
|
|
7904
|
+
function requireAgentConfig2(agentId) {
|
|
7905
|
+
const config = getAgentConfig2(agentId);
|
|
7906
|
+
if (!config) {
|
|
7907
|
+
throw new Error(`No hook configuration found for agent "${agentId}"`);
|
|
7908
|
+
}
|
|
7909
|
+
return config;
|
|
7910
|
+
}
|
|
7911
|
+
function resolveScopedPath(config, agentId, cwd, homeDir, scope) {
|
|
7912
|
+
const targetPath = resolveHookPath(
|
|
7913
|
+
config,
|
|
7914
|
+
scope === "project" ? "local" : "global",
|
|
7915
|
+
cwd,
|
|
7916
|
+
homeDir
|
|
7917
|
+
);
|
|
7918
|
+
if (!targetPath) {
|
|
7919
|
+
throw new Error(`Agent "${agentId}" has no ${scope} hook path`);
|
|
7920
|
+
}
|
|
7921
|
+
return targetPath;
|
|
7922
|
+
}
|
|
7923
|
+
function readFirstKilobyte(filePath) {
|
|
7924
|
+
const descriptor = openSync(filePath, "r");
|
|
7925
|
+
const buffer = Buffer.alloc(1024);
|
|
7926
|
+
try {
|
|
7927
|
+
const length = readSync(descriptor, buffer, 0, buffer.length, 0);
|
|
7928
|
+
return buffer.toString("utf8", 0, length);
|
|
7929
|
+
} finally {
|
|
7930
|
+
closeSync(descriptor);
|
|
7931
|
+
}
|
|
7932
|
+
}
|
|
7933
|
+
function isRecord7(value) {
|
|
7934
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7935
|
+
}
|
|
7936
|
+
function isFullyGeneratedFile(filePath) {
|
|
7937
|
+
let parsed;
|
|
7938
|
+
try {
|
|
7939
|
+
parsed = JSON.parse(readFirstKilobyte(filePath));
|
|
7940
|
+
} catch {
|
|
7941
|
+
return false;
|
|
7942
|
+
}
|
|
7943
|
+
if (!isRecord7(parsed)) {
|
|
7944
|
+
return false;
|
|
7945
|
+
}
|
|
7946
|
+
if (Object.keys(parsed).some((key) => key !== "hooks")) {
|
|
7947
|
+
return false;
|
|
7948
|
+
}
|
|
7949
|
+
const hooks = parsed.hooks;
|
|
7950
|
+
if (!isRecord7(hooks)) {
|
|
7951
|
+
return false;
|
|
7952
|
+
}
|
|
7953
|
+
let handlerFound = false;
|
|
7954
|
+
for (const groups of Object.values(hooks)) {
|
|
7955
|
+
if (!Array.isArray(groups)) {
|
|
7956
|
+
return false;
|
|
7957
|
+
}
|
|
7958
|
+
for (const group of groups) {
|
|
7959
|
+
if (!isRecord7(group) || !Array.isArray(group.hooks)) {
|
|
7960
|
+
return false;
|
|
7961
|
+
}
|
|
7962
|
+
for (const handler of group.hooks) {
|
|
7963
|
+
if (!isRecord7(handler)) {
|
|
7964
|
+
return false;
|
|
7965
|
+
}
|
|
7966
|
+
handlerFound = true;
|
|
7967
|
+
const statusMessage = handler.statusMessage;
|
|
7968
|
+
if (typeof statusMessage !== "string" || !statusMessage.startsWith("[generated:")) {
|
|
7969
|
+
return false;
|
|
7970
|
+
}
|
|
7971
|
+
}
|
|
7972
|
+
}
|
|
7973
|
+
}
|
|
7974
|
+
return handlerFound;
|
|
7975
|
+
}
|
|
7976
|
+
function symlinkHooks(sourceAgentId, targetAgentId, cwd, homeDir, scope) {
|
|
7977
|
+
const source = requireAgentConfig2(sourceAgentId);
|
|
7978
|
+
const target = requireAgentConfig2(targetAgentId);
|
|
7979
|
+
if (source.format !== target.format) {
|
|
7980
|
+
throw new Error(
|
|
7981
|
+
`Cannot symlink hook formats "${source.format}" and "${target.format}"; use transformation instead`
|
|
7982
|
+
);
|
|
7983
|
+
}
|
|
7984
|
+
const targetPath = resolveScopedPath(source, sourceAgentId, cwd, homeDir, scope);
|
|
7985
|
+
const symlinkPath = resolveScopedPath(target, targetAgentId, cwd, homeDir, scope);
|
|
7986
|
+
let replaced = "none";
|
|
7987
|
+
try {
|
|
7988
|
+
const existing = lstatSync(symlinkPath);
|
|
7989
|
+
if (existing.isSymbolicLink()) {
|
|
7990
|
+
if (readlinkSync(symlinkPath) === targetPath) {
|
|
7991
|
+
return { symlinkPath, targetPath, replaced };
|
|
7992
|
+
}
|
|
7993
|
+
unlinkSync(symlinkPath);
|
|
7994
|
+
replaced = "stale-symlink";
|
|
7995
|
+
} else if (existing.isFile() && isFullyGeneratedFile(symlinkPath)) {
|
|
7996
|
+
unlinkSync(symlinkPath);
|
|
7997
|
+
replaced = "generated-file";
|
|
7998
|
+
} else {
|
|
7999
|
+
throw new Error(`Refuse to replace user-authored hook file at ${symlinkPath}`);
|
|
8000
|
+
}
|
|
8001
|
+
} catch (error2) {
|
|
8002
|
+
if (error2.code !== "ENOENT") {
|
|
8003
|
+
throw error2;
|
|
8004
|
+
}
|
|
8005
|
+
}
|
|
8006
|
+
mkdirSync4(path32.dirname(symlinkPath), { recursive: true });
|
|
8007
|
+
symlinkSync(targetPath, symlinkPath);
|
|
8008
|
+
return { symlinkPath, targetPath, replaced };
|
|
8009
|
+
}
|
|
8010
|
+
|
|
8011
|
+
// packages/agent-hook-config/src/bridge-hooks.ts
|
|
8012
|
+
import * as fs3 from "node:fs";
|
|
8013
|
+
import path33 from "node:path";
|
|
8014
|
+
var hookExcludeMarkerPrefix = "poe-code-spawn-hooks";
|
|
8015
|
+
function isNodeError4(error2) {
|
|
8016
|
+
return error2 instanceof Error && "code" in error2;
|
|
8017
|
+
}
|
|
8018
|
+
function pathExists3(targetPath) {
|
|
8019
|
+
try {
|
|
8020
|
+
fs3.lstatSync(targetPath);
|
|
8021
|
+
return true;
|
|
8022
|
+
} catch (error2) {
|
|
8023
|
+
if (isNodeError4(error2) && error2.code === "ENOENT") {
|
|
8024
|
+
return false;
|
|
8025
|
+
}
|
|
8026
|
+
throw error2;
|
|
8027
|
+
}
|
|
8028
|
+
}
|
|
8029
|
+
function collectMissingParents2(targetPath) {
|
|
8030
|
+
const parents = [];
|
|
8031
|
+
let current = path33.dirname(targetPath);
|
|
8032
|
+
while (!pathExists3(current)) {
|
|
8033
|
+
parents.push(current);
|
|
8034
|
+
const parent = path33.dirname(current);
|
|
8035
|
+
if (parent === current) {
|
|
8036
|
+
break;
|
|
8037
|
+
}
|
|
8038
|
+
current = parent;
|
|
8039
|
+
}
|
|
8040
|
+
return parents.reverse();
|
|
8041
|
+
}
|
|
8042
|
+
function removeDirectoryIfEmpty2(targetPath) {
|
|
8043
|
+
try {
|
|
8044
|
+
fs3.rmdirSync(targetPath);
|
|
8045
|
+
} catch (error2) {
|
|
8046
|
+
if (isNodeError4(error2) && (error2.code === "ENOENT" || error2.code === "ENOTEMPTY" || error2.code === "EEXIST")) {
|
|
8047
|
+
return;
|
|
8048
|
+
}
|
|
8049
|
+
throw error2;
|
|
8050
|
+
}
|
|
8051
|
+
}
|
|
8052
|
+
function requireSupport(input, role) {
|
|
8053
|
+
const support = resolveAgentSupport2(input);
|
|
8054
|
+
if (support.status !== "supported" || !support.id || !support.config) {
|
|
8055
|
+
throw new Error(
|
|
8056
|
+
`Unsupported ${role} hook agent "${input}". Supported hook agents: ${supportedHookAgents.join(", ")}.`
|
|
8057
|
+
);
|
|
8058
|
+
}
|
|
8059
|
+
return { id: support.id, config: support.config };
|
|
8060
|
+
}
|
|
8061
|
+
function requireTargetPath(targetId, config, cwd, homeDir) {
|
|
8062
|
+
const targetPath = resolveHookPath(config, "local", cwd, homeDir);
|
|
8063
|
+
if (!targetPath) {
|
|
8064
|
+
throw new Error(`Agent "${targetId}" has no project hook path`);
|
|
8065
|
+
}
|
|
8066
|
+
return targetPath;
|
|
8067
|
+
}
|
|
8068
|
+
function readCodexFile(targetPath) {
|
|
8069
|
+
let content;
|
|
8070
|
+
try {
|
|
8071
|
+
content = fs3.readFileSync(targetPath, "utf8");
|
|
8072
|
+
} catch (error2) {
|
|
8073
|
+
if (isNodeError4(error2) && error2.code === "ENOENT") {
|
|
8074
|
+
return void 0;
|
|
8075
|
+
}
|
|
8076
|
+
throw error2;
|
|
8077
|
+
}
|
|
8078
|
+
try {
|
|
8079
|
+
return JSON.parse(content);
|
|
8080
|
+
} catch (error2) {
|
|
8081
|
+
throw new Error(`Malformed JSON in ${targetPath}`, { cause: error2 });
|
|
8082
|
+
}
|
|
8083
|
+
}
|
|
8084
|
+
function writeCodexFile(targetPath, file) {
|
|
8085
|
+
fs3.writeFileSync(targetPath, `${JSON.stringify(file, null, 2)}
|
|
8086
|
+
`, "utf8");
|
|
8087
|
+
}
|
|
8088
|
+
function hasOnlyEmptyHooks(file) {
|
|
8089
|
+
return Object.keys(file).every((key) => key === "hooks") && Object.values(file.hooks ?? {}).every((groups) => groups.length === 0);
|
|
8090
|
+
}
|
|
8091
|
+
function relativeToCwd(cwd, targetPath) {
|
|
8092
|
+
return path33.relative(cwd, targetPath);
|
|
8093
|
+
}
|
|
8094
|
+
function matcherKey(event, matcher) {
|
|
8095
|
+
return `${event}\0${matcher === void 0 ? "<undefined>" : matcher}`;
|
|
8096
|
+
}
|
|
8097
|
+
function bridgeHooks(sourceAgentId, targetAgentId, cwd, homeDir, runId, opts) {
|
|
8098
|
+
const source = requireSupport(sourceAgentId, "source");
|
|
8099
|
+
const target = requireSupport(targetAgentId, "target");
|
|
8100
|
+
const strategy = opts?.strategy ?? (source.config.format === target.config.format ? "symlink" : "transform");
|
|
8101
|
+
const manifest = {
|
|
8102
|
+
sourceAgentId,
|
|
8103
|
+
targetAgentId,
|
|
8104
|
+
cwd,
|
|
8105
|
+
runId,
|
|
8106
|
+
strategy,
|
|
8107
|
+
drops: []
|
|
8108
|
+
};
|
|
8109
|
+
if (strategy === "symlink") {
|
|
8110
|
+
const symlinkPath = requireTargetPath(target.id, target.config, cwd, homeDir);
|
|
8111
|
+
manifest.createdParents = collectMissingParents2(symlinkPath);
|
|
8112
|
+
const result = symlinkHooks(source.id, target.id, cwd, homeDir, "project");
|
|
8113
|
+
manifest.symlinkPath = result.symlinkPath;
|
|
8114
|
+
manifest.symlinkTarget = result.targetPath;
|
|
8115
|
+
manifest.symlinkReplaced = result.replaced;
|
|
8116
|
+
appendExcludeBlock(cwd, runId, [relativeToCwd(cwd, result.symlinkPath)], {
|
|
8117
|
+
markerPrefix: hookExcludeMarkerPrefix
|
|
8118
|
+
});
|
|
8119
|
+
return manifest;
|
|
8120
|
+
}
|
|
8121
|
+
if (source.id !== "claude-code") {
|
|
8122
|
+
throw new Error(`Transforming hooks from "${source.id}" is not supported yet`);
|
|
8123
|
+
}
|
|
8124
|
+
if (target.config.format !== "codex-hooks-json") {
|
|
8125
|
+
throw new Error(
|
|
8126
|
+
`Transforming hooks to "${target.id}" is not supported yet; only codex-hook targets can be written`
|
|
8127
|
+
);
|
|
8128
|
+
}
|
|
8129
|
+
const targetPath = requireTargetPath(target.id, target.config, cwd, homeDir);
|
|
8130
|
+
const priorFile = readCodexFile(targetPath);
|
|
8131
|
+
const sourceHooks = readClaudeHooks(cwd, homeDir, { scope: opts?.scope ?? "merged" });
|
|
8132
|
+
const transformed = transformHooks(sourceHooks.entries, source.id, target.id, { runId });
|
|
8133
|
+
const createdParents = collectMissingParents2(targetPath);
|
|
8134
|
+
const writeResult = writeCodexHooks(targetPath, transformed.entries, runId);
|
|
8135
|
+
manifest.writtenPath = targetPath;
|
|
8136
|
+
manifest.generatedEntryIds = transformed.entries.map((entry) => entry.generatedId);
|
|
8137
|
+
manifest.drops = transformed.drops;
|
|
8138
|
+
manifest.createdParents = createdParents;
|
|
8139
|
+
manifest.fileCreated = writeResult.fileCreated;
|
|
8140
|
+
manifest.preExistingEvents = Object.keys(priorFile?.hooks ?? {});
|
|
8141
|
+
manifest.preExistingMatchers = Object.entries(priorFile?.hooks ?? {}).flatMap(
|
|
8142
|
+
([event, groups]) => groups.map((group) => ({
|
|
8143
|
+
event,
|
|
8144
|
+
...group.matcher === void 0 ? {} : { matcher: group.matcher }
|
|
8145
|
+
}))
|
|
8146
|
+
);
|
|
8147
|
+
appendExcludeBlock(cwd, runId, [relativeToCwd(cwd, targetPath)], {
|
|
8148
|
+
markerPrefix: hookExcludeMarkerPrefix
|
|
8149
|
+
});
|
|
8150
|
+
return manifest;
|
|
8151
|
+
}
|
|
8152
|
+
function cleanupBridgedHooks(manifest) {
|
|
8153
|
+
if (manifest.strategy === "symlink" && manifest.symlinkPath && manifest.symlinkTarget) {
|
|
8154
|
+
try {
|
|
8155
|
+
if (fs3.lstatSync(manifest.symlinkPath).isSymbolicLink() && fs3.readlinkSync(manifest.symlinkPath) === manifest.symlinkTarget) {
|
|
8156
|
+
fs3.unlinkSync(manifest.symlinkPath);
|
|
8157
|
+
}
|
|
8158
|
+
} catch (error2) {
|
|
8159
|
+
if (!isNodeError4(error2) || error2.code !== "ENOENT") {
|
|
8160
|
+
throw error2;
|
|
8161
|
+
}
|
|
8162
|
+
}
|
|
8163
|
+
for (const parent of [...manifest.createdParents ?? []].reverse()) {
|
|
8164
|
+
removeDirectoryIfEmpty2(parent);
|
|
8165
|
+
}
|
|
8166
|
+
}
|
|
8167
|
+
if (manifest.strategy === "transform" && manifest.writtenPath) {
|
|
8168
|
+
const file = readCodexFile(manifest.writtenPath);
|
|
8169
|
+
if (file) {
|
|
8170
|
+
const generatedPrefix = `[generated:${manifest.runId}]`;
|
|
8171
|
+
const preExistingEvents = new Set(manifest.preExistingEvents ?? []);
|
|
8172
|
+
const preExistingMatchers = new Set(
|
|
8173
|
+
(manifest.preExistingMatchers ?? []).map((group) => matcherKey(group.event, group.matcher))
|
|
8174
|
+
);
|
|
8175
|
+
const hooks = file.hooks ?? {};
|
|
8176
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
8177
|
+
hooks[event] = groups.filter((group) => {
|
|
8178
|
+
const priorLength = group.hooks.length;
|
|
8179
|
+
group.hooks = group.hooks.filter(
|
|
8180
|
+
(handler) => !handler.statusMessage?.startsWith(generatedPrefix)
|
|
8181
|
+
);
|
|
8182
|
+
return group.hooks.length > 0 || group.hooks.length === priorLength || preExistingMatchers.has(matcherKey(event, group.matcher));
|
|
8183
|
+
});
|
|
8184
|
+
if (hooks[event].length === 0 && !preExistingEvents.has(event)) {
|
|
8185
|
+
delete hooks[event];
|
|
8186
|
+
}
|
|
8187
|
+
}
|
|
8188
|
+
file.hooks = hooks;
|
|
8189
|
+
if (manifest.fileCreated && hasOnlyEmptyHooks(file)) {
|
|
8190
|
+
fs3.unlinkSync(manifest.writtenPath);
|
|
8191
|
+
} else {
|
|
8192
|
+
writeCodexFile(manifest.writtenPath, file);
|
|
8193
|
+
}
|
|
8194
|
+
}
|
|
8195
|
+
for (const parent of [...manifest.createdParents ?? []].reverse()) {
|
|
8196
|
+
removeDirectoryIfEmpty2(parent);
|
|
8197
|
+
}
|
|
8198
|
+
}
|
|
8199
|
+
removeExcludeBlock(manifest.cwd, manifest.runId, { markerPrefix: hookExcludeMarkerPrefix });
|
|
8200
|
+
}
|
|
8201
|
+
|
|
7503
8202
|
// packages/agent-spawn/src/skill-bridge.ts
|
|
7504
|
-
function
|
|
7505
|
-
if (!skills || skills.length === 0) {
|
|
8203
|
+
function bridgeResourcesForRun(agentId, cwd, skills, hooks) {
|
|
8204
|
+
if ((!skills || skills.length === 0) && !hooks) {
|
|
7506
8205
|
return void 0;
|
|
7507
8206
|
}
|
|
7508
|
-
const
|
|
7509
|
-
|
|
7510
|
-
|
|
8207
|
+
const runId = crypto.randomUUID();
|
|
8208
|
+
const manifests = {};
|
|
8209
|
+
try {
|
|
8210
|
+
if (skills && skills.length > 0) {
|
|
8211
|
+
manifests.skills = bridgeActiveSkills(agentId, cwd, skills, os7.homedir(), runId);
|
|
8212
|
+
for (const warning2 of manifests.skills.warnings) {
|
|
8213
|
+
logger.warn(warning2.message);
|
|
8214
|
+
}
|
|
8215
|
+
}
|
|
8216
|
+
if (hooks) {
|
|
8217
|
+
manifests.hooks = bridgeHooks(hooks.from, agentId, cwd, os7.homedir(), runId, {
|
|
8218
|
+
strategy: hooks.strategy === "auto" ? void 0 : hooks.strategy,
|
|
8219
|
+
scope: hooks.scope
|
|
8220
|
+
});
|
|
8221
|
+
for (const drop of manifests.hooks.drops) {
|
|
8222
|
+
logger.warn(
|
|
8223
|
+
`Dropped bridged hook event "${drop.source.event}" with handler type "${drop.source.handler.type}": ${drop.detail}`
|
|
8224
|
+
);
|
|
8225
|
+
}
|
|
8226
|
+
}
|
|
8227
|
+
} catch (error2) {
|
|
8228
|
+
cleanupResourcesForRun(manifests);
|
|
8229
|
+
throw error2;
|
|
7511
8230
|
}
|
|
7512
|
-
return
|
|
8231
|
+
return manifests;
|
|
7513
8232
|
}
|
|
7514
|
-
function
|
|
8233
|
+
function cleanupResourcesForRun(manifest) {
|
|
7515
8234
|
if (!manifest) {
|
|
7516
8235
|
return;
|
|
7517
8236
|
}
|
|
7518
|
-
|
|
8237
|
+
if (manifest.hooks) {
|
|
8238
|
+
cleanupBridgedHooks(manifest.hooks);
|
|
8239
|
+
}
|
|
8240
|
+
if (manifest.skills) {
|
|
8241
|
+
cleanupBridgedSkills(manifest.skills);
|
|
8242
|
+
}
|
|
7519
8243
|
}
|
|
7520
8244
|
|
|
7521
8245
|
// packages/agent-spawn/src/adapters/utils.ts
|
|
@@ -7641,21 +8365,21 @@ async function* adaptClaude(lines) {
|
|
|
7641
8365
|
if (blockType !== "tool_result") continue;
|
|
7642
8366
|
const kind = toolKindsById.get(item.tool_use_id);
|
|
7643
8367
|
toolKindsById.delete(item.tool_use_id);
|
|
7644
|
-
let
|
|
8368
|
+
let path37;
|
|
7645
8369
|
if (typeof item.content === "string") {
|
|
7646
|
-
|
|
8370
|
+
path37 = item.content;
|
|
7647
8371
|
} else {
|
|
7648
8372
|
try {
|
|
7649
|
-
|
|
8373
|
+
path37 = JSON.stringify(item.content);
|
|
7650
8374
|
} catch {
|
|
7651
|
-
|
|
8375
|
+
path37 = String(item.content);
|
|
7652
8376
|
}
|
|
7653
8377
|
}
|
|
7654
8378
|
yield {
|
|
7655
8379
|
event: "tool_complete",
|
|
7656
8380
|
id: item.tool_use_id,
|
|
7657
8381
|
kind,
|
|
7658
|
-
path:
|
|
8382
|
+
path: path37
|
|
7659
8383
|
};
|
|
7660
8384
|
}
|
|
7661
8385
|
}
|
|
@@ -7751,10 +8475,10 @@ async function* adaptCodex(lines) {
|
|
|
7751
8475
|
const kindFromStart = toolKindById.get(item.id);
|
|
7752
8476
|
const kind = kindFromStart ?? (itemType === "command_execution" ? "exec" : itemType === "file_edit" ? "edit" : "other");
|
|
7753
8477
|
const titleFromEvent = isNonEmptyString(item.path) ? item.path : itemType === "mcp_tool_call" ? `${isNonEmptyString(item.server) ? item.server : "unknown"}.${isNonEmptyString(item.tool) ? item.tool : "unknown"}` : void 0;
|
|
7754
|
-
const
|
|
8478
|
+
const path37 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
|
|
7755
8479
|
toolTitleById.delete(item.id);
|
|
7756
8480
|
toolKindById.delete(item.id);
|
|
7757
|
-
yield { event: "tool_complete", id: item.id, kind, path:
|
|
8481
|
+
yield { event: "tool_complete", id: item.id, kind, path: path37 };
|
|
7758
8482
|
}
|
|
7759
8483
|
}
|
|
7760
8484
|
}
|
|
@@ -8282,7 +9006,7 @@ function spawnStreaming(options) {
|
|
|
8282
9006
|
};
|
|
8283
9007
|
}
|
|
8284
9008
|
};
|
|
8285
|
-
const manifest =
|
|
9009
|
+
const manifest = bridgeResourcesForRun(options.agentId, cwd, options.skills, options.hooks);
|
|
8286
9010
|
void (async () => {
|
|
8287
9011
|
try {
|
|
8288
9012
|
for await (const output of adapter(queue.lines())) {
|
|
@@ -8333,7 +9057,7 @@ function spawnStreaming(options) {
|
|
|
8333
9057
|
...ctx.logFile && !result.logFile ? { logFile: ctx.logFile } : {}
|
|
8334
9058
|
};
|
|
8335
9059
|
} finally {
|
|
8336
|
-
|
|
9060
|
+
cleanupResourcesForRun(manifest);
|
|
8337
9061
|
}
|
|
8338
9062
|
})();
|
|
8339
9063
|
return {
|
|
@@ -8475,7 +9199,7 @@ async function runSpawn(agentId, options, context) {
|
|
|
8475
9199
|
return { stdout: "", stderr: "", exitCode: 0 };
|
|
8476
9200
|
}
|
|
8477
9201
|
const cwd = options.cwd ?? process.cwd();
|
|
8478
|
-
const manifest =
|
|
9202
|
+
const manifest = bridgeResourcesForRun(agentId, cwd, options.skills, options.hooks);
|
|
8479
9203
|
let logFd;
|
|
8480
9204
|
try {
|
|
8481
9205
|
const logFilePath = resolveSpawnLogPath(options);
|
|
@@ -8543,7 +9267,7 @@ async function runSpawn(agentId, options, context) {
|
|
|
8543
9267
|
};
|
|
8544
9268
|
} finally {
|
|
8545
9269
|
closeSpawnLog(logFd);
|
|
8546
|
-
|
|
9270
|
+
cleanupResourcesForRun(manifest);
|
|
8547
9271
|
}
|
|
8548
9272
|
}
|
|
8549
9273
|
spawn4.retry = createSpawnRetry((service, options) => {
|
|
@@ -8565,12 +9289,12 @@ function resolveSpawnLogPath(options) {
|
|
|
8565
9289
|
if (!options.logDir || !options.logFileName) {
|
|
8566
9290
|
return void 0;
|
|
8567
9291
|
}
|
|
8568
|
-
return
|
|
9292
|
+
return path34.join(options.logDir, options.logFileName);
|
|
8569
9293
|
}
|
|
8570
9294
|
function openSpawnLog(filePath) {
|
|
8571
9295
|
try {
|
|
8572
|
-
|
|
8573
|
-
return
|
|
9296
|
+
mkdirSync5(path34.dirname(filePath), { recursive: true });
|
|
9297
|
+
return openSync2(filePath, "a");
|
|
8574
9298
|
} catch {
|
|
8575
9299
|
return void 0;
|
|
8576
9300
|
}
|
|
@@ -8585,7 +9309,7 @@ function appendSpawnLog(fd, chunk) {
|
|
|
8585
9309
|
function closeSpawnLog(fd) {
|
|
8586
9310
|
if (fd === void 0) return;
|
|
8587
9311
|
try {
|
|
8588
|
-
|
|
9312
|
+
closeSync2(fd);
|
|
8589
9313
|
} catch {
|
|
8590
9314
|
}
|
|
8591
9315
|
}
|
|
@@ -8594,7 +9318,7 @@ function closeSpawnLog(fd) {
|
|
|
8594
9318
|
var DEFAULT_ACTIVITY_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
8595
9319
|
|
|
8596
9320
|
// packages/agent-spawn/src/acp/replay.ts
|
|
8597
|
-
import
|
|
9321
|
+
import path35 from "node:path";
|
|
8598
9322
|
import { homedir as homedir2 } from "node:os";
|
|
8599
9323
|
import { open as open2, readdir as readdir2 } from "node:fs/promises";
|
|
8600
9324
|
import { createInterface } from "node:readline";
|
|
@@ -8613,7 +9337,7 @@ import { homedir } from "node:os";
|
|
|
8613
9337
|
import { join } from "node:path";
|
|
8614
9338
|
|
|
8615
9339
|
// packages/agent-spawn/src/acp/middlewares/spawn-log.ts
|
|
8616
|
-
import
|
|
9340
|
+
import path36 from "node:path";
|
|
8617
9341
|
import { homedir as homedir3 } from "node:os";
|
|
8618
9342
|
import { mkdir, open as open3 } from "node:fs/promises";
|
|
8619
9343
|
|
|
@@ -8627,9 +9351,30 @@ stderr:
|
|
|
8627
9351
|
${stderr}`;
|
|
8628
9352
|
}
|
|
8629
9353
|
function createSpawnHealthCheck(agentId, options) {
|
|
8630
|
-
const
|
|
8631
|
-
|
|
8632
|
-
|
|
9354
|
+
const {
|
|
9355
|
+
binaryName,
|
|
9356
|
+
args,
|
|
9357
|
+
env: modeEnv
|
|
9358
|
+
} = options.hooks ? {
|
|
9359
|
+
binaryName: "poe-code",
|
|
9360
|
+
args: [
|
|
9361
|
+
"spawn",
|
|
9362
|
+
"--hooks-from",
|
|
9363
|
+
options.hooks.from,
|
|
9364
|
+
...options.hooks.strategy ? ["--hooks-strategy", options.hooks.strategy] : [],
|
|
9365
|
+
...options.model ? ["--model", options.model] : [],
|
|
9366
|
+
"--mode",
|
|
9367
|
+
"yolo",
|
|
9368
|
+
agentId,
|
|
9369
|
+
`Output exactly: ${options.expectedOutput}`
|
|
9370
|
+
],
|
|
9371
|
+
env: void 0
|
|
9372
|
+
} : options.invocation ? {
|
|
9373
|
+
binaryName: options.invocation.command,
|
|
9374
|
+
args: options.invocation.args,
|
|
9375
|
+
env: options.invocation.env
|
|
9376
|
+
} : buildSpawnArgs(agentId, {
|
|
9377
|
+
prompt: `Output exactly: ${options.expectedOutput}`,
|
|
8633
9378
|
model: options.model,
|
|
8634
9379
|
mode: "yolo"
|
|
8635
9380
|
});
|
|
@@ -8644,6 +9389,13 @@ function createSpawnHealthCheck(agentId, options) {
|
|
|
8644
9389
|
return;
|
|
8645
9390
|
}
|
|
8646
9391
|
const result = modeEnv ? await context.runCommand(binaryName, args, { env: modeEnv }) : await context.runCommand(binaryName, args);
|
|
9392
|
+
if (options.hooks) {
|
|
9393
|
+
for (const line of result.stdout.split("\n")) {
|
|
9394
|
+
if (line.includes("Dropped bridged hook event")) {
|
|
9395
|
+
context.logWarning?.(line);
|
|
9396
|
+
}
|
|
9397
|
+
}
|
|
9398
|
+
}
|
|
8647
9399
|
if (result.exitCode !== 0) {
|
|
8648
9400
|
throw new Error(
|
|
8649
9401
|
`spawn ${agentId} failed with exit code ${result.exitCode}.
|
|
@@ -8781,6 +9533,7 @@ function createProvider(opts) {
|
|
|
8781
9533
|
configurePrompts: opts.configurePrompts,
|
|
8782
9534
|
postConfigureMessages: opts.postConfigureMessages,
|
|
8783
9535
|
extendConfigurePayload: opts.extendConfigurePayload,
|
|
9536
|
+
runtimeEnv: opts.runtimeEnv,
|
|
8784
9537
|
isolatedEnv: opts.isolatedEnv,
|
|
8785
9538
|
async configure(context, runOptions) {
|
|
8786
9539
|
await runMutations(opts.manifest.configure, {
|
|
@@ -8841,19 +9594,7 @@ function stripModelNamespace2(model) {
|
|
|
8841
9594
|
const id = slashIndex === -1 ? model : model.slice(slashIndex + 1);
|
|
8842
9595
|
return id.toLowerCase();
|
|
8843
9596
|
}
|
|
8844
|
-
var
|
|
8845
|
-
"openai/gpt-5.5",
|
|
8846
|
-
"openai/gpt-5.4",
|
|
8847
|
-
"openai/gpt-5.3-codex",
|
|
8848
|
-
"openai/gpt-5.2-codex",
|
|
8849
|
-
"openai/gpt-5.2",
|
|
8850
|
-
"openai/gpt-5.2-chat",
|
|
8851
|
-
"openai/gpt-5.2-pro",
|
|
8852
|
-
"openai/gpt-5.1",
|
|
8853
|
-
"openai/gpt-5.1-codex-mini",
|
|
8854
|
-
"anthropic/claude-opus-4.7"
|
|
8855
|
-
];
|
|
8856
|
-
var DEFAULT_CODEX_MODEL = CODEX_MODELS[0];
|
|
9597
|
+
var DEFAULT_CODEX_MODEL = "openai/gpt-5.5";
|
|
8857
9598
|
var KIMI_MODELS = [
|
|
8858
9599
|
"novitaai/kimi-k2.5",
|
|
8859
9600
|
"novitaai/kimi-k2-thinking",
|
|
@@ -8873,14 +9614,14 @@ function deriveCodexProfileName(model) {
|
|
|
8873
9614
|
}
|
|
8874
9615
|
return stripped;
|
|
8875
9616
|
}
|
|
9617
|
+
function resolveCodexConfigModel(options) {
|
|
9618
|
+
const model = options.model ?? DEFAULT_CODEX_MODEL;
|
|
9619
|
+
return options.provider?.modelInput?.kind === "freeform" ? model : stripModelNamespace2(model);
|
|
9620
|
+
}
|
|
8876
9621
|
var CODEX_INSTALL_DEFINITION = {
|
|
8877
9622
|
id: "codex",
|
|
8878
9623
|
summary: "Codex CLI",
|
|
8879
|
-
check: createBinaryExistsCheck(
|
|
8880
|
-
"codex",
|
|
8881
|
-
"codex-cli-binary",
|
|
8882
|
-
"Codex CLI binary must exist"
|
|
8883
|
-
),
|
|
9624
|
+
check: createBinaryExistsCheck("codex", "codex-cli-binary", "Codex CLI binary must exist"),
|
|
8884
9625
|
steps: [
|
|
8885
9626
|
{
|
|
8886
9627
|
id: "install-codex-cli-npm",
|
|
@@ -8963,11 +9704,7 @@ var codexService = createProvider({
|
|
|
8963
9704
|
configurePrompts: {
|
|
8964
9705
|
model: {
|
|
8965
9706
|
label: "Codex model",
|
|
8966
|
-
defaultValue: DEFAULT_CODEX_MODEL
|
|
8967
|
-
choices: CODEX_MODELS.map((id) => ({
|
|
8968
|
-
title: id,
|
|
8969
|
-
value: id
|
|
8970
|
-
}))
|
|
9707
|
+
defaultValue: DEFAULT_CODEX_MODEL
|
|
8971
9708
|
},
|
|
8972
9709
|
reasoningEffort: {
|
|
8973
9710
|
label: "Codex reasoning effort",
|
|
@@ -8986,7 +9723,8 @@ var codexService = createProvider({
|
|
|
8986
9723
|
return context.runCheck(
|
|
8987
9724
|
createSpawnHealthCheck("codex", {
|
|
8988
9725
|
model: context.model ?? DEFAULT_CODEX_MODEL,
|
|
8989
|
-
expectedOutput: "CODEX_OK"
|
|
9726
|
+
expectedOutput: "CODEX_OK",
|
|
9727
|
+
hooks: context.hooks
|
|
8990
9728
|
})
|
|
8991
9729
|
);
|
|
8992
9730
|
},
|
|
@@ -9007,11 +9745,11 @@ var codexService = createProvider({
|
|
|
9007
9745
|
templateId: "codex/config.toml.mustache",
|
|
9008
9746
|
context: (ctx) => {
|
|
9009
9747
|
const options = ctx;
|
|
9010
|
-
const model = options
|
|
9748
|
+
const model = resolveCodexConfigModel(options);
|
|
9011
9749
|
return {
|
|
9012
9750
|
apiKey: options.provider?.credential,
|
|
9013
9751
|
baseUrl: options.provider?.baseUrl ?? "",
|
|
9014
|
-
model
|
|
9752
|
+
model,
|
|
9015
9753
|
providerId: options.provider?.id ?? PROVIDER_NAME,
|
|
9016
9754
|
reasoningEffort: options.reasoningEffort,
|
|
9017
9755
|
profileName: deriveCodexProfileName(model)
|