poe-code 3.0.224 → 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 +50 -3
- package/dist/cli/commands/configure-payload.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/ralph.js +1 -0
- package/dist/cli/commands/ralph.js.map +1 -1
- package/dist/cli/commands/shared.d.ts +4 -0
- package/dist/cli/commands/shared.js +33 -2
- 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 +1 -0
- package/dist/cli/constants.js +2 -1
- 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/poe-code-command-runner.js +7 -2
- package/dist/cli/poe-code-command-runner.js.map +1 -1
- package/dist/cli/prompts.d.ts +21 -13
- 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 +4694 -2378
- package/dist/index.js.map +4 -4
- package/dist/providers/claude-code.js +913 -152
- package/dist/providers/claude-code.js.map +4 -4
- package/dist/providers/codex.js +897 -149
- 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 +870 -161
- package/dist/providers/goose.js.map +4 -4
- package/dist/providers/kimi.js +894 -143
- package/dist/providers/kimi.js.map +4 -4
- package/dist/providers/opencode.js +894 -143
- package/dist/providers/opencode.js.map +4 -4
- package/dist/providers/poe-agent.js +1144 -335
- 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 +914 -192
- 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
|
@@ -827,17 +827,17 @@ function isPidRunning(pid) {
|
|
|
827
827
|
}
|
|
828
828
|
function createDefaultFs() {
|
|
829
829
|
return {
|
|
830
|
-
open: (
|
|
831
|
-
readFile: (
|
|
830
|
+
open: (path37, flags) => fsPromises.open(path37, flags),
|
|
831
|
+
readFile: (path37, encoding) => fsPromises.readFile(path37, encoding),
|
|
832
832
|
stat: fsPromises.stat,
|
|
833
833
|
unlink: fsPromises.unlink
|
|
834
834
|
};
|
|
835
835
|
}
|
|
836
|
-
async function removeLockFile(
|
|
836
|
+
async function removeLockFile(fs4, lockPath, signal) {
|
|
837
837
|
for (let attempt = 0; attempt <= 4; attempt += 1) {
|
|
838
838
|
throwIfAborted(signal);
|
|
839
839
|
try {
|
|
840
|
-
await
|
|
840
|
+
await fs4.unlink(lockPath);
|
|
841
841
|
return;
|
|
842
842
|
} catch (error2) {
|
|
843
843
|
if (hasErrorCode(error2, "ENOENT")) {
|
|
@@ -868,12 +868,12 @@ function parseLockMetadata(content) {
|
|
|
868
868
|
}
|
|
869
869
|
return void 0;
|
|
870
870
|
}
|
|
871
|
-
async function readLockMetadata(
|
|
872
|
-
if (!
|
|
871
|
+
async function readLockMetadata(fs4, lockPath) {
|
|
872
|
+
if (!fs4.readFile) {
|
|
873
873
|
return void 0;
|
|
874
874
|
}
|
|
875
875
|
try {
|
|
876
|
-
return parseLockMetadata(await
|
|
876
|
+
return parseLockMetadata(await fs4.readFile(lockPath, "utf8"));
|
|
877
877
|
} catch (error2) {
|
|
878
878
|
if (hasErrorCode(error2, "ENOENT")) {
|
|
879
879
|
return null;
|
|
@@ -907,7 +907,7 @@ async function writeLockMetadata(handle) {
|
|
|
907
907
|
}
|
|
908
908
|
}
|
|
909
909
|
async function acquireFileLock(filePath, options = {}) {
|
|
910
|
-
const
|
|
910
|
+
const fs4 = options.fs ?? createDefaultFs();
|
|
911
911
|
const retries = options.retries ?? 20;
|
|
912
912
|
const minTimeout = options.minTimeout ?? 25;
|
|
913
913
|
const maxTimeout = options.maxTimeout ?? 250;
|
|
@@ -918,7 +918,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
918
918
|
while (attempt <= retries) {
|
|
919
919
|
throwIfAborted(options.signal);
|
|
920
920
|
try {
|
|
921
|
-
const handle = await
|
|
921
|
+
const handle = await fs4.open(lockPath, "wx");
|
|
922
922
|
await writeLockMetadata(handle);
|
|
923
923
|
let released = false;
|
|
924
924
|
return async () => {
|
|
@@ -926,7 +926,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
926
926
|
return;
|
|
927
927
|
}
|
|
928
928
|
released = true;
|
|
929
|
-
await removeLockFile(
|
|
929
|
+
await removeLockFile(fs4, lockPath, options.signal);
|
|
930
930
|
};
|
|
931
931
|
} catch (error2) {
|
|
932
932
|
if (!hasErrorCode(error2, "EEXIST")) {
|
|
@@ -935,7 +935,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
935
935
|
}
|
|
936
936
|
let stat3;
|
|
937
937
|
try {
|
|
938
|
-
stat3 = await
|
|
938
|
+
stat3 = await fs4.stat(lockPath);
|
|
939
939
|
} catch (statError) {
|
|
940
940
|
if (hasErrorCode(statError, "ENOENT")) {
|
|
941
941
|
continue;
|
|
@@ -943,7 +943,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
943
943
|
throw statError;
|
|
944
944
|
}
|
|
945
945
|
const reclaimLock = await shouldReclaimLock({
|
|
946
|
-
fs:
|
|
946
|
+
fs: fs4,
|
|
947
947
|
isPidRunning: pidIsRunning,
|
|
948
948
|
lockPath,
|
|
949
949
|
staleMs,
|
|
@@ -953,7 +953,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
953
953
|
continue;
|
|
954
954
|
}
|
|
955
955
|
if (reclaimLock) {
|
|
956
|
-
await removeLockFile(
|
|
956
|
+
await removeLockFile(fs4, lockPath, options.signal);
|
|
957
957
|
continue;
|
|
958
958
|
}
|
|
959
959
|
if (attempt >= retries) {
|
|
@@ -1130,6 +1130,24 @@ var codexAgent = {
|
|
|
1130
1130
|
}
|
|
1131
1131
|
};
|
|
1132
1132
|
|
|
1133
|
+
// packages/agent-defs/src/agents/gemini-cli.ts
|
|
1134
|
+
var geminiCliAgent = {
|
|
1135
|
+
id: "gemini-cli",
|
|
1136
|
+
name: "gemini-cli",
|
|
1137
|
+
aliases: ["gemini"],
|
|
1138
|
+
label: "Gemini CLI",
|
|
1139
|
+
summary: "Configure Google's Gemini CLI to use a compatible Google generations API.",
|
|
1140
|
+
binaryName: "gemini",
|
|
1141
|
+
configPath: "~/.gemini/settings.json",
|
|
1142
|
+
apiShapes: ["google-generations"],
|
|
1143
|
+
branding: {
|
|
1144
|
+
colors: {
|
|
1145
|
+
dark: "#8AB4F8",
|
|
1146
|
+
light: "#1A73E8"
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
|
|
1133
1151
|
// packages/agent-defs/src/agents/opencode.ts
|
|
1134
1152
|
var openCodeAgent = {
|
|
1135
1153
|
id: "opencode",
|
|
@@ -1203,6 +1221,7 @@ var allAgents = [
|
|
|
1203
1221
|
claudeCodeAgent,
|
|
1204
1222
|
claudeDesktopAgent,
|
|
1205
1223
|
codexAgent,
|
|
1224
|
+
geminiCliAgent,
|
|
1206
1225
|
openCodeAgent,
|
|
1207
1226
|
kimiAgent,
|
|
1208
1227
|
gooseAgent,
|
|
@@ -1253,29 +1272,29 @@ function wrapForLogTee(argv, jobId) {
|
|
|
1253
1272
|
return ["sh", "-c", script];
|
|
1254
1273
|
}
|
|
1255
1274
|
async function* streamLogFile(env, jobId, opts) {
|
|
1256
|
-
const
|
|
1275
|
+
const fs4 = env.fs ?? nodeFs;
|
|
1257
1276
|
const file = jobLogPath(jobId);
|
|
1258
1277
|
let byteOffset = opts.sinceByte ?? 0;
|
|
1259
1278
|
while (true) {
|
|
1260
|
-
if (opts.since !== void 0 && !await wasModifiedSince(
|
|
1261
|
-
await waitForLogChange(
|
|
1279
|
+
if (opts.since !== void 0 && !await wasModifiedSince(fs4, file, opts.since)) {
|
|
1280
|
+
await waitForLogChange(fs4, file);
|
|
1262
1281
|
continue;
|
|
1263
1282
|
}
|
|
1264
|
-
const result = await readLogChunk(
|
|
1283
|
+
const result = await readLogChunk(fs4, file, byteOffset);
|
|
1265
1284
|
if (result !== null) {
|
|
1266
1285
|
byteOffset = result.nextByteOffset;
|
|
1267
1286
|
yield result.chunk;
|
|
1268
1287
|
continue;
|
|
1269
1288
|
}
|
|
1270
|
-
await waitForLogChange(
|
|
1289
|
+
await waitForLogChange(fs4, file);
|
|
1271
1290
|
}
|
|
1272
1291
|
}
|
|
1273
|
-
async function wasModifiedSince(
|
|
1274
|
-
if (
|
|
1292
|
+
async function wasModifiedSince(fs4, file, since) {
|
|
1293
|
+
if (fs4.promises.stat === void 0) {
|
|
1275
1294
|
return true;
|
|
1276
1295
|
}
|
|
1277
1296
|
try {
|
|
1278
|
-
const stat3 = await
|
|
1297
|
+
const stat3 = await fs4.promises.stat(file);
|
|
1279
1298
|
return stat3.mtimeMs >= since.getTime();
|
|
1280
1299
|
} catch (error2) {
|
|
1281
1300
|
if (isNodeError(error2) && error2.code === "ENOENT") {
|
|
@@ -1285,11 +1304,11 @@ async function wasModifiedSince(fs3, file, since) {
|
|
|
1285
1304
|
}
|
|
1286
1305
|
}
|
|
1287
1306
|
async function waitForExit(env, jobId, opts = {}) {
|
|
1288
|
-
const
|
|
1307
|
+
const fs4 = env.fs ?? nodeFs;
|
|
1289
1308
|
const file = jobExitPath(jobId);
|
|
1290
1309
|
while (true) {
|
|
1291
1310
|
throwIfAborted2(opts.signal);
|
|
1292
|
-
const contents = await readTextFileIfExists(
|
|
1311
|
+
const contents = await readTextFileIfExists(fs4, file);
|
|
1293
1312
|
if (contents !== null) {
|
|
1294
1313
|
const text5 = contents.trim();
|
|
1295
1314
|
const exitCode = Number(text5);
|
|
@@ -1307,8 +1326,8 @@ function jobLogPath(jobId) {
|
|
|
1307
1326
|
function jobExitPath(jobId) {
|
|
1308
1327
|
return `${JOB_DIR}/${jobId}.exit`;
|
|
1309
1328
|
}
|
|
1310
|
-
async function readLogChunk(
|
|
1311
|
-
const contents = await readFileIfExists(
|
|
1329
|
+
async function readLogChunk(fs4, file, byteOffset) {
|
|
1330
|
+
const contents = await readFileIfExists(fs4, file);
|
|
1312
1331
|
if (contents === null || byteOffset >= contents.byteLength) {
|
|
1313
1332
|
return null;
|
|
1314
1333
|
}
|
|
@@ -1320,13 +1339,13 @@ async function readLogChunk(fs3, file, byteOffset) {
|
|
|
1320
1339
|
nextByteOffset: contents.byteLength
|
|
1321
1340
|
};
|
|
1322
1341
|
}
|
|
1323
|
-
async function readTextFileIfExists(
|
|
1324
|
-
const contents = await readFileIfExists(
|
|
1342
|
+
async function readTextFileIfExists(fs4, file) {
|
|
1343
|
+
const contents = await readFileIfExists(fs4, file);
|
|
1325
1344
|
return contents?.toString("utf8") ?? null;
|
|
1326
1345
|
}
|
|
1327
|
-
async function readFileIfExists(
|
|
1346
|
+
async function readFileIfExists(fs4, file) {
|
|
1328
1347
|
try {
|
|
1329
|
-
const contents = await
|
|
1348
|
+
const contents = await fs4.promises.readFile(file);
|
|
1330
1349
|
return Buffer.isBuffer(contents) ? contents : Buffer.from(contents);
|
|
1331
1350
|
} catch (error2) {
|
|
1332
1351
|
if (isNodeError(error2) && error2.code === "ENOENT") {
|
|
@@ -1335,8 +1354,8 @@ async function readFileIfExists(fs3, file) {
|
|
|
1335
1354
|
throw error2;
|
|
1336
1355
|
}
|
|
1337
1356
|
}
|
|
1338
|
-
async function waitForLogChange(
|
|
1339
|
-
const watch =
|
|
1357
|
+
async function waitForLogChange(fs4, file) {
|
|
1358
|
+
const watch = fs4.watch;
|
|
1340
1359
|
if (typeof watch !== "function") {
|
|
1341
1360
|
await sleep2(POLL_INTERVAL_MS);
|
|
1342
1361
|
return;
|
|
@@ -2302,7 +2321,7 @@ import path14 from "node:path";
|
|
|
2302
2321
|
|
|
2303
2322
|
// packages/config-extends/src/discover.ts
|
|
2304
2323
|
import path10 from "node:path";
|
|
2305
|
-
async function findBase(name, bases,
|
|
2324
|
+
async function findBase(name, bases, fs4) {
|
|
2306
2325
|
const checkedPaths = [];
|
|
2307
2326
|
for (const basePath of bases) {
|
|
2308
2327
|
for (const extension of [".md", ".yaml", ".yml", ".json"]) {
|
|
@@ -2310,7 +2329,7 @@ async function findBase(name, bases, fs3) {
|
|
|
2310
2329
|
checkedPaths.push(filePath);
|
|
2311
2330
|
try {
|
|
2312
2331
|
return {
|
|
2313
|
-
content: await
|
|
2332
|
+
content: await fs4.readFile(filePath, "utf8"),
|
|
2314
2333
|
filePath
|
|
2315
2334
|
};
|
|
2316
2335
|
} catch (error2) {
|
|
@@ -2390,11 +2409,11 @@ function stripBom(content) {
|
|
|
2390
2409
|
function mergeLayers(layers) {
|
|
2391
2410
|
return mergeObjectLayers(layers, []);
|
|
2392
2411
|
}
|
|
2393
|
-
function mergeObjectLayers(layers,
|
|
2412
|
+
function mergeObjectLayers(layers, path37) {
|
|
2394
2413
|
const data = {};
|
|
2395
2414
|
const sources = {};
|
|
2396
2415
|
for (const key of collectKeys(layers)) {
|
|
2397
|
-
const resolved = resolveKey(layers, key,
|
|
2416
|
+
const resolved = resolveKey(layers, key, path37);
|
|
2398
2417
|
if (resolved === void 0) {
|
|
2399
2418
|
continue;
|
|
2400
2419
|
}
|
|
@@ -2412,7 +2431,7 @@ function collectKeys(layers) {
|
|
|
2412
2431
|
}
|
|
2413
2432
|
return [...keys];
|
|
2414
2433
|
}
|
|
2415
|
-
function resolveKey(layers, key,
|
|
2434
|
+
function resolveKey(layers, key, path37) {
|
|
2416
2435
|
let winningSource;
|
|
2417
2436
|
let winningValue;
|
|
2418
2437
|
const objectLayers = [];
|
|
@@ -2442,9 +2461,9 @@ function resolveKey(layers, key, path32) {
|
|
|
2442
2461
|
if (winningSource === void 0) {
|
|
2443
2462
|
return void 0;
|
|
2444
2463
|
}
|
|
2445
|
-
const fullPath = buildPath(
|
|
2464
|
+
const fullPath = buildPath(path37, key);
|
|
2446
2465
|
if (isPlainObject(winningValue)) {
|
|
2447
|
-
const merged = mergeObjectLayers(objectLayers, [...
|
|
2466
|
+
const merged = mergeObjectLayers(objectLayers, [...path37, key]);
|
|
2448
2467
|
return {
|
|
2449
2468
|
value: merged.data,
|
|
2450
2469
|
sources: {
|
|
@@ -2469,8 +2488,8 @@ function isWinningCandidate(key, value) {
|
|
|
2469
2488
|
}
|
|
2470
2489
|
return true;
|
|
2471
2490
|
}
|
|
2472
|
-
function buildPath(
|
|
2473
|
-
return [...
|
|
2491
|
+
function buildPath(path37, key) {
|
|
2492
|
+
return [...path37, key].join(".");
|
|
2474
2493
|
}
|
|
2475
2494
|
function isPlainObject(value) {
|
|
2476
2495
|
if (value === null || Array.isArray(value) || typeof value !== "object") {
|
|
@@ -3824,16 +3843,16 @@ function getConfigFormat(pathOrFormat) {
|
|
|
3824
3843
|
}
|
|
3825
3844
|
return formatRegistry[formatName];
|
|
3826
3845
|
}
|
|
3827
|
-
function detectFormat2(
|
|
3828
|
-
const ext = getExtension(
|
|
3846
|
+
function detectFormat2(path37) {
|
|
3847
|
+
const ext = getExtension(path37);
|
|
3829
3848
|
return extensionMap[ext];
|
|
3830
3849
|
}
|
|
3831
|
-
function getExtension(
|
|
3832
|
-
const lastDot =
|
|
3850
|
+
function getExtension(path37) {
|
|
3851
|
+
const lastDot = path37.lastIndexOf(".");
|
|
3833
3852
|
if (lastDot === -1) {
|
|
3834
3853
|
return "";
|
|
3835
3854
|
}
|
|
3836
|
-
return
|
|
3855
|
+
return path37.slice(lastDot).toLowerCase();
|
|
3837
3856
|
}
|
|
3838
3857
|
|
|
3839
3858
|
// packages/config-mutations/src/execution/path-utils.ts
|
|
@@ -3884,9 +3903,9 @@ function resolvePath(rawPath, homeDir, pathMapper) {
|
|
|
3884
3903
|
function isNotFound(error2) {
|
|
3885
3904
|
return typeof error2 === "object" && error2 !== null && "code" in error2 && error2.code === "ENOENT";
|
|
3886
3905
|
}
|
|
3887
|
-
async function readFileIfExists2(
|
|
3906
|
+
async function readFileIfExists2(fs4, target) {
|
|
3888
3907
|
try {
|
|
3889
|
-
return await
|
|
3908
|
+
return await fs4.readFile(target, "utf8");
|
|
3890
3909
|
} catch (error2) {
|
|
3891
3910
|
if (isNotFound(error2)) {
|
|
3892
3911
|
return null;
|
|
@@ -3894,9 +3913,9 @@ async function readFileIfExists2(fs3, target) {
|
|
|
3894
3913
|
throw error2;
|
|
3895
3914
|
}
|
|
3896
3915
|
}
|
|
3897
|
-
async function pathExists(
|
|
3916
|
+
async function pathExists(fs4, target) {
|
|
3898
3917
|
try {
|
|
3899
|
-
await
|
|
3918
|
+
await fs4.stat(target);
|
|
3900
3919
|
return true;
|
|
3901
3920
|
} catch (error2) {
|
|
3902
3921
|
if (isNotFound(error2)) {
|
|
@@ -3920,9 +3939,9 @@ function createInvalidDocumentBackupPath(targetPath) {
|
|
|
3920
3939
|
const ext = targetPath.includes(".") ? targetPath.split(".").pop() : "bak";
|
|
3921
3940
|
return `${targetPath}.invalid-${createTimestamp()}.${ext}`;
|
|
3922
3941
|
}
|
|
3923
|
-
async function backupInvalidDocument(
|
|
3942
|
+
async function backupInvalidDocument(fs4, targetPath, content) {
|
|
3924
3943
|
const backupPath = createInvalidDocumentBackupPath(targetPath);
|
|
3925
|
-
await
|
|
3944
|
+
await fs4.writeFile(backupPath, content, { encoding: "utf8" });
|
|
3926
3945
|
}
|
|
3927
3946
|
function describeMutation(kind, targetPath) {
|
|
3928
3947
|
const displayPath = targetPath ?? "target";
|
|
@@ -4480,12 +4499,12 @@ async function executeMutation(mutation, context, options) {
|
|
|
4480
4499
|
}
|
|
4481
4500
|
|
|
4482
4501
|
// packages/poe-code-config/src/store.ts
|
|
4483
|
-
async function readMergedDocument(
|
|
4484
|
-
const globalDocument = await readStoredDocument(
|
|
4502
|
+
async function readMergedDocument(fs4, globalPath, projectPath) {
|
|
4503
|
+
const globalDocument = await readStoredDocument(fs4, globalPath);
|
|
4485
4504
|
if (!projectPath || projectPath === globalPath) {
|
|
4486
4505
|
return globalDocument.data;
|
|
4487
4506
|
}
|
|
4488
|
-
const projectDocument = await readStoredDocument(
|
|
4507
|
+
const projectDocument = await readStoredDocument(fs4, projectPath);
|
|
4489
4508
|
const resolved = await resolve(
|
|
4490
4509
|
[
|
|
4491
4510
|
{
|
|
@@ -4499,16 +4518,16 @@ async function readMergedDocument(fs3, globalPath, projectPath) {
|
|
|
4499
4518
|
}
|
|
4500
4519
|
],
|
|
4501
4520
|
{
|
|
4502
|
-
fs: createResolvedConfigFs(
|
|
4521
|
+
fs: createResolvedConfigFs(fs4, globalPath, globalDocument.content),
|
|
4503
4522
|
autoExtend: true
|
|
4504
4523
|
}
|
|
4505
4524
|
);
|
|
4506
4525
|
return normalizeDocument(resolved.data);
|
|
4507
4526
|
}
|
|
4508
|
-
async function readStoredDocument(
|
|
4527
|
+
async function readStoredDocument(fs4, filePath) {
|
|
4509
4528
|
try {
|
|
4510
|
-
const raw = await
|
|
4511
|
-
return await parseStoredDocument(
|
|
4529
|
+
const raw = await fs4.readFile(filePath, "utf8");
|
|
4530
|
+
return await parseStoredDocument(fs4, filePath, raw);
|
|
4512
4531
|
} catch (error2) {
|
|
4513
4532
|
if (isNotFound(error2)) {
|
|
4514
4533
|
return {
|
|
@@ -4519,7 +4538,7 @@ async function readStoredDocument(fs3, filePath) {
|
|
|
4519
4538
|
throw error2;
|
|
4520
4539
|
}
|
|
4521
4540
|
}
|
|
4522
|
-
async function parseStoredDocument(
|
|
4541
|
+
async function parseStoredDocument(fs4, filePath, raw) {
|
|
4523
4542
|
try {
|
|
4524
4543
|
return {
|
|
4525
4544
|
content: raw,
|
|
@@ -4527,7 +4546,7 @@ async function parseStoredDocument(fs3, filePath, raw) {
|
|
|
4527
4546
|
};
|
|
4528
4547
|
} catch (error2) {
|
|
4529
4548
|
if (error2 instanceof SyntaxError) {
|
|
4530
|
-
await recoverInvalidDocument(
|
|
4549
|
+
await recoverInvalidDocument(fs4, filePath, raw);
|
|
4531
4550
|
return {
|
|
4532
4551
|
content: EMPTY_DOCUMENT,
|
|
4533
4552
|
data: {}
|
|
@@ -4561,21 +4580,21 @@ function normalizeScopeValues(value) {
|
|
|
4561
4580
|
}
|
|
4562
4581
|
return normalized;
|
|
4563
4582
|
}
|
|
4564
|
-
function createResolvedConfigFs(
|
|
4583
|
+
function createResolvedConfigFs(fs4, globalPath, globalContent) {
|
|
4565
4584
|
return {
|
|
4566
4585
|
readFile(filePath, _encoding) {
|
|
4567
4586
|
if (filePath === globalPath) {
|
|
4568
4587
|
return Promise.resolve(globalContent);
|
|
4569
4588
|
}
|
|
4570
|
-
return
|
|
4589
|
+
return fs4.readFile(filePath, "utf8");
|
|
4571
4590
|
}
|
|
4572
4591
|
};
|
|
4573
4592
|
}
|
|
4574
|
-
async function recoverInvalidDocument(
|
|
4575
|
-
await
|
|
4593
|
+
async function recoverInvalidDocument(fs4, filePath, content) {
|
|
4594
|
+
await fs4.mkdir(path14.dirname(filePath), { recursive: true });
|
|
4576
4595
|
const backupPath = createInvalidBackupPath(filePath);
|
|
4577
|
-
await
|
|
4578
|
-
await
|
|
4596
|
+
await fs4.writeFile(backupPath, content, { encoding: "utf8" });
|
|
4597
|
+
await fs4.writeFile(filePath, EMPTY_DOCUMENT, { encoding: "utf8" });
|
|
4579
4598
|
}
|
|
4580
4599
|
function createInvalidBackupPath(filePath) {
|
|
4581
4600
|
const directory = path14.dirname(filePath);
|
|
@@ -4699,7 +4718,7 @@ function mergeScope(scope, baseScope, overrideScope) {
|
|
|
4699
4718
|
...Object.fromEntries(scopeEntries)
|
|
4700
4719
|
};
|
|
4701
4720
|
}
|
|
4702
|
-
function mergeRuntimeScope(baseScope, overrideScope,
|
|
4721
|
+
function mergeRuntimeScope(baseScope, overrideScope, path37 = []) {
|
|
4703
4722
|
const merged = {};
|
|
4704
4723
|
const keys = /* @__PURE__ */ new Set([...Object.keys(baseScope), ...Object.keys(overrideScope)]);
|
|
4705
4724
|
for (const key of keys) {
|
|
@@ -4711,20 +4730,20 @@ function mergeRuntimeScope(baseScope, overrideScope, path32 = []) {
|
|
|
4711
4730
|
}
|
|
4712
4731
|
continue;
|
|
4713
4732
|
}
|
|
4714
|
-
if (isRuntimeConcatenativeArray([...
|
|
4733
|
+
if (isRuntimeConcatenativeArray([...path37, key]) && Array.isArray(baseValue) && Array.isArray(overrideValue)) {
|
|
4715
4734
|
merged[key] = [...baseValue, ...overrideValue];
|
|
4716
4735
|
continue;
|
|
4717
4736
|
}
|
|
4718
4737
|
if (isRecord4(baseValue) && isRecord4(overrideValue)) {
|
|
4719
|
-
merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...
|
|
4738
|
+
merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...path37, key]);
|
|
4720
4739
|
continue;
|
|
4721
4740
|
}
|
|
4722
4741
|
merged[key] = overrideValue;
|
|
4723
4742
|
}
|
|
4724
4743
|
return merged;
|
|
4725
4744
|
}
|
|
4726
|
-
function isRuntimeConcatenativeArray(
|
|
4727
|
-
return
|
|
4745
|
+
function isRuntimeConcatenativeArray(path37) {
|
|
4746
|
+
return path37.join(".") === "mounts" || path37.join(".") === "runner.workspace.exclude";
|
|
4728
4747
|
}
|
|
4729
4748
|
function isRecord4(value) {
|
|
4730
4749
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -4912,6 +4931,7 @@ var poeProvider = {
|
|
|
4912
4931
|
label: "Poe",
|
|
4913
4932
|
summary: "Route AI coding agents through Poe's API.",
|
|
4914
4933
|
baseUrl: "https://api.poe.com",
|
|
4934
|
+
agentBaseUrl: "https://api.poe.com",
|
|
4915
4935
|
auth: {
|
|
4916
4936
|
kind: "api-key",
|
|
4917
4937
|
envVar: "POE_API_KEY",
|
|
@@ -4919,6 +4939,12 @@ var poeProvider = {
|
|
|
4919
4939
|
prompt: { title: "Poe API key" },
|
|
4920
4940
|
preferredLogin: "oauth"
|
|
4921
4941
|
},
|
|
4942
|
+
env: {
|
|
4943
|
+
ANTHROPIC_CUSTOM_HEADERS: {
|
|
4944
|
+
kind: "providerCredential",
|
|
4945
|
+
prefix: "Authorization: Bearer "
|
|
4946
|
+
}
|
|
4947
|
+
},
|
|
4922
4948
|
apiShapes: [
|
|
4923
4949
|
{
|
|
4924
4950
|
id: "openai-chat-completions",
|
|
@@ -4947,6 +4973,9 @@ var anthropicProvider = {
|
|
|
4947
4973
|
storageKey: "provider:anthropic",
|
|
4948
4974
|
prompt: { title: "Anthropic API key" }
|
|
4949
4975
|
},
|
|
4976
|
+
env: {
|
|
4977
|
+
ANTHROPIC_API_KEY: { kind: "providerCredential" }
|
|
4978
|
+
},
|
|
4950
4979
|
apiShapes: [
|
|
4951
4980
|
{
|
|
4952
4981
|
id: "anthropic-messages",
|
|
@@ -4969,6 +4998,12 @@ var cloudflareProvider = {
|
|
|
4969
4998
|
storageKey: "provider:cloudflare",
|
|
4970
4999
|
prompt: { title: "Cloudflare AI Gateway token" }
|
|
4971
5000
|
},
|
|
5001
|
+
env: {
|
|
5002
|
+
ANTHROPIC_CUSTOM_HEADERS: {
|
|
5003
|
+
kind: "providerCredential",
|
|
5004
|
+
prefix: "Authorization: Bearer "
|
|
5005
|
+
}
|
|
5006
|
+
},
|
|
4972
5007
|
apiShapes: [
|
|
4973
5008
|
{
|
|
4974
5009
|
id: "openai-chat-completions",
|
|
@@ -5013,7 +5048,7 @@ function isNotFoundError(error2) {
|
|
|
5013
5048
|
}
|
|
5014
5049
|
|
|
5015
5050
|
// packages/poe-code-config/src/state/jobs.ts
|
|
5016
|
-
function createJobRegistry(homeDir,
|
|
5051
|
+
function createJobRegistry(homeDir, fs4 = defaultStateFs) {
|
|
5017
5052
|
const jobsDir = path17.join(homeDir, ".poe-code", "state", "jobs");
|
|
5018
5053
|
function jobPath(id) {
|
|
5019
5054
|
assertSafeJobId(id);
|
|
@@ -5021,7 +5056,7 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5021
5056
|
}
|
|
5022
5057
|
async function get(id) {
|
|
5023
5058
|
try {
|
|
5024
|
-
return parseJobEntry(await
|
|
5059
|
+
return parseJobEntry(await fs4.readFile(jobPath(id), "utf8"));
|
|
5025
5060
|
} catch (error2) {
|
|
5026
5061
|
if (isNotFoundError(error2)) {
|
|
5027
5062
|
return null;
|
|
@@ -5032,8 +5067,8 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5032
5067
|
async function put(entry) {
|
|
5033
5068
|
assertJobEntry(entry);
|
|
5034
5069
|
const filePath = jobPath(entry.id);
|
|
5035
|
-
await
|
|
5036
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5070
|
+
await fs4.mkdir(jobsDir, { recursive: true });
|
|
5071
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5037
5072
|
try {
|
|
5038
5073
|
await writeJobAtomically(filePath, entry);
|
|
5039
5074
|
} finally {
|
|
@@ -5042,8 +5077,8 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5042
5077
|
}
|
|
5043
5078
|
async function update(id, patch) {
|
|
5044
5079
|
const filePath = jobPath(id);
|
|
5045
|
-
await
|
|
5046
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5080
|
+
await fs4.mkdir(jobsDir, { recursive: true });
|
|
5081
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5047
5082
|
try {
|
|
5048
5083
|
const current = await get(id);
|
|
5049
5084
|
if (current === null) {
|
|
@@ -5064,7 +5099,7 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5064
5099
|
async function list(filter = {}) {
|
|
5065
5100
|
let entries;
|
|
5066
5101
|
try {
|
|
5067
|
-
entries = await
|
|
5102
|
+
entries = await fs4.readdir(jobsDir);
|
|
5068
5103
|
} catch (error2) {
|
|
5069
5104
|
if (isNotFoundError(error2)) {
|
|
5070
5105
|
return [];
|
|
@@ -5077,11 +5112,11 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5077
5112
|
continue;
|
|
5078
5113
|
}
|
|
5079
5114
|
const filePath = path17.join(jobsDir, entry);
|
|
5080
|
-
const stat3 = await
|
|
5115
|
+
const stat3 = await fs4.stat(filePath);
|
|
5081
5116
|
if (!stat3.isFile()) {
|
|
5082
5117
|
continue;
|
|
5083
5118
|
}
|
|
5084
|
-
const job = parseJobEntry(await
|
|
5119
|
+
const job = parseJobEntry(await fs4.readFile(filePath, "utf8"));
|
|
5085
5120
|
if (matchesFilter(job, filter)) {
|
|
5086
5121
|
jobs.push(job);
|
|
5087
5122
|
}
|
|
@@ -5091,16 +5126,16 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5091
5126
|
async function remove2(id) {
|
|
5092
5127
|
const filePath = jobPath(id);
|
|
5093
5128
|
try {
|
|
5094
|
-
await
|
|
5129
|
+
await fs4.stat(jobsDir);
|
|
5095
5130
|
} catch (error2) {
|
|
5096
5131
|
if (isNotFoundError(error2)) {
|
|
5097
5132
|
return;
|
|
5098
5133
|
}
|
|
5099
5134
|
throw error2;
|
|
5100
5135
|
}
|
|
5101
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5136
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5102
5137
|
try {
|
|
5103
|
-
await
|
|
5138
|
+
await fs4.unlink(filePath);
|
|
5104
5139
|
} catch (error2) {
|
|
5105
5140
|
if (!isNotFoundError(error2)) {
|
|
5106
5141
|
throw error2;
|
|
@@ -5110,14 +5145,14 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5110
5145
|
}
|
|
5111
5146
|
}
|
|
5112
5147
|
async function writeJobAtomically(filePath, entry) {
|
|
5113
|
-
await
|
|
5148
|
+
await fs4.mkdir(path17.dirname(filePath), { recursive: true });
|
|
5114
5149
|
const tempPath = `${filePath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
5115
5150
|
try {
|
|
5116
|
-
await
|
|
5151
|
+
await fs4.writeFile(tempPath, `${JSON.stringify(entry, null, 2)}
|
|
5117
5152
|
`, {
|
|
5118
5153
|
encoding: "utf8"
|
|
5119
5154
|
});
|
|
5120
|
-
await
|
|
5155
|
+
await fs4.rename(tempPath, filePath);
|
|
5121
5156
|
} catch (error2) {
|
|
5122
5157
|
await removeTempFile(tempPath);
|
|
5123
5158
|
throw error2;
|
|
@@ -5125,7 +5160,7 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5125
5160
|
}
|
|
5126
5161
|
async function removeTempFile(tempPath) {
|
|
5127
5162
|
try {
|
|
5128
|
-
await
|
|
5163
|
+
await fs4.unlink(tempPath);
|
|
5129
5164
|
} catch (error2) {
|
|
5130
5165
|
if (!isNotFoundError(error2)) {
|
|
5131
5166
|
throw error2;
|
|
@@ -5172,11 +5207,11 @@ function isRecord5(value) {
|
|
|
5172
5207
|
|
|
5173
5208
|
// packages/poe-code-config/src/state/templates.ts
|
|
5174
5209
|
import path18 from "node:path";
|
|
5175
|
-
function createTemplateRegistry(homeDir,
|
|
5210
|
+
function createTemplateRegistry(homeDir, fs4 = defaultStateFs) {
|
|
5176
5211
|
const filePath = path18.join(homeDir, ".poe-code", "state", "templates.json");
|
|
5177
5212
|
async function readState() {
|
|
5178
5213
|
try {
|
|
5179
|
-
const raw = await
|
|
5214
|
+
const raw = await fs4.readFile(filePath, "utf8");
|
|
5180
5215
|
return normalizeTemplateState(JSON.parse(raw));
|
|
5181
5216
|
} catch (error2) {
|
|
5182
5217
|
if (isNotFoundError(error2)) {
|
|
@@ -5186,14 +5221,14 @@ function createTemplateRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5186
5221
|
}
|
|
5187
5222
|
}
|
|
5188
5223
|
async function writeState(state) {
|
|
5189
|
-
await
|
|
5224
|
+
await fs4.writeFile(filePath, `${JSON.stringify(state, null, 2)}
|
|
5190
5225
|
`, {
|
|
5191
5226
|
encoding: "utf8"
|
|
5192
5227
|
});
|
|
5193
5228
|
}
|
|
5194
5229
|
async function updateState(mutator) {
|
|
5195
|
-
await
|
|
5196
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5230
|
+
await fs4.mkdir(path18.dirname(filePath), { recursive: true });
|
|
5231
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5197
5232
|
try {
|
|
5198
5233
|
const state = await readState();
|
|
5199
5234
|
mutator(state);
|
|
@@ -5263,10 +5298,10 @@ function isRecord6(value) {
|
|
|
5263
5298
|
}
|
|
5264
5299
|
|
|
5265
5300
|
// packages/poe-code-config/src/state/index.ts
|
|
5266
|
-
function createStateManager(homeDir,
|
|
5301
|
+
function createStateManager(homeDir, fs4) {
|
|
5267
5302
|
return {
|
|
5268
|
-
templates: createTemplateRegistry(homeDir,
|
|
5269
|
-
jobs: createJobRegistry(homeDir,
|
|
5303
|
+
templates: createTemplateRegistry(homeDir, fs4),
|
|
5304
|
+
jobs: createJobRegistry(homeDir, fs4)
|
|
5270
5305
|
};
|
|
5271
5306
|
}
|
|
5272
5307
|
|
|
@@ -5581,7 +5616,7 @@ import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream"
|
|
|
5581
5616
|
import path21 from "node:path";
|
|
5582
5617
|
var JOB_DIR2 = "/tmp/poe-jobs";
|
|
5583
5618
|
function createE2bJobHandle(input) {
|
|
5584
|
-
const
|
|
5619
|
+
const fs4 = createE2bLogStreamFs(input.sandbox);
|
|
5585
5620
|
return {
|
|
5586
5621
|
id: input.jobId,
|
|
5587
5622
|
envId: input.envId,
|
|
@@ -5597,10 +5632,10 @@ function createE2bJobHandle(input) {
|
|
|
5597
5632
|
return isRunning ? "running" : "lost";
|
|
5598
5633
|
},
|
|
5599
5634
|
stream(opts = {}) {
|
|
5600
|
-
return streamLogFile({ fs:
|
|
5635
|
+
return streamLogFile({ fs: fs4 }, input.jobId, opts);
|
|
5601
5636
|
},
|
|
5602
5637
|
async wait() {
|
|
5603
|
-
const result = await waitForExit({ fs:
|
|
5638
|
+
const result = await waitForExit({ fs: fs4 }, input.jobId);
|
|
5604
5639
|
const preserveMs = input.preserveAfterExitHours * 60 * 60 * 1e3;
|
|
5605
5640
|
if (preserveMs > 0) {
|
|
5606
5641
|
await input.sandbox.setTimeout(preserveMs);
|
|
@@ -6097,10 +6132,10 @@ var e2bAuthScope = defineScope("e2b", {
|
|
|
6097
6132
|
});
|
|
6098
6133
|
async function resolveE2bApiKey(input) {
|
|
6099
6134
|
const homeDir = input.homeDir ?? os4.homedir();
|
|
6100
|
-
const
|
|
6135
|
+
const fs4 = input.fs ?? nodeFs4;
|
|
6101
6136
|
const env = input.env ?? process.env;
|
|
6102
6137
|
const document = await readMergedDocument(
|
|
6103
|
-
|
|
6138
|
+
fs4,
|
|
6104
6139
|
resolveConfigPath(homeDir),
|
|
6105
6140
|
resolveProjectConfigPath(input.cwd)
|
|
6106
6141
|
);
|
|
@@ -6607,6 +6642,23 @@ var gooseAcpSpawnConfig = {
|
|
|
6607
6642
|
skipAuth: true
|
|
6608
6643
|
};
|
|
6609
6644
|
|
|
6645
|
+
// packages/agent-spawn/src/configs/gemini-cli.ts
|
|
6646
|
+
var geminiCliAcpSpawnConfig = {
|
|
6647
|
+
kind: "acp",
|
|
6648
|
+
agentId: "gemini-cli",
|
|
6649
|
+
acpArgs: ({ model, mcpServers }) => [
|
|
6650
|
+
"--acp",
|
|
6651
|
+
...model ? ["--model", model] : [],
|
|
6652
|
+
...mcpServers ? ["--allowed-mcp-server-names", Object.keys(mcpServers).join(",")] : [],
|
|
6653
|
+
...mcpServers ? ["--skip-trust"] : [],
|
|
6654
|
+
"--yolo"
|
|
6655
|
+
],
|
|
6656
|
+
env: {
|
|
6657
|
+
GEMINI_SANDBOX: "false"
|
|
6658
|
+
},
|
|
6659
|
+
skipAuth: true
|
|
6660
|
+
};
|
|
6661
|
+
|
|
6610
6662
|
// packages/agent-spawn/src/configs/index.ts
|
|
6611
6663
|
var allSpawnConfigs = [
|
|
6612
6664
|
claudeCodeSpawnConfig,
|
|
@@ -6623,6 +6675,7 @@ var acpLookup = /* @__PURE__ */ new Map();
|
|
|
6623
6675
|
acpLookup.set(openCodeAcpSpawnConfig.agentId, openCodeAcpSpawnConfig);
|
|
6624
6676
|
acpLookup.set(kimiAcpSpawnConfig.agentId, kimiAcpSpawnConfig);
|
|
6625
6677
|
acpLookup.set(gooseAcpSpawnConfig.agentId, gooseAcpSpawnConfig);
|
|
6678
|
+
acpLookup.set(geminiCliAcpSpawnConfig.agentId, geminiCliAcpSpawnConfig);
|
|
6626
6679
|
function getSpawnConfig(input) {
|
|
6627
6680
|
const resolvedId = resolveAgentId(input);
|
|
6628
6681
|
if (!resolvedId) {
|
|
@@ -6642,8 +6695,8 @@ function listMcpSupportedAgents() {
|
|
|
6642
6695
|
}
|
|
6643
6696
|
|
|
6644
6697
|
// packages/agent-spawn/src/spawn.ts
|
|
6645
|
-
import { mkdirSync as
|
|
6646
|
-
import
|
|
6698
|
+
import { mkdirSync as mkdirSync5, openSync as openSync2, writeSync, closeSync as closeSync2 } from "node:fs";
|
|
6699
|
+
import path34 from "node:path";
|
|
6647
6700
|
|
|
6648
6701
|
// packages/agent-spawn/src/configs/resolve-config.ts
|
|
6649
6702
|
function resolveConfig(agentId) {
|
|
@@ -7044,7 +7097,7 @@ function createEventQueue() {
|
|
|
7044
7097
|
|
|
7045
7098
|
// packages/agent-spawn/src/skill-bridge.ts
|
|
7046
7099
|
import crypto from "node:crypto";
|
|
7047
|
-
import
|
|
7100
|
+
import os7 from "node:os";
|
|
7048
7101
|
|
|
7049
7102
|
// packages/agent-skill-config/src/configs.ts
|
|
7050
7103
|
import os5 from "node:os";
|
|
@@ -7058,6 +7111,10 @@ var agentSkillConfigs = {
|
|
|
7058
7111
|
globalSkillDir: "~/.codex/skills",
|
|
7059
7112
|
localSkillDir: ".codex/skills"
|
|
7060
7113
|
},
|
|
7114
|
+
"gemini-cli": {
|
|
7115
|
+
globalSkillDir: "~/.gemini/skills",
|
|
7116
|
+
localSkillDir: ".gemini/skills"
|
|
7117
|
+
},
|
|
7061
7118
|
opencode: {
|
|
7062
7119
|
globalSkillDir: "~/.config/opencode/skills",
|
|
7063
7120
|
localSkillDir: ".opencode/skills"
|
|
@@ -7200,7 +7257,7 @@ function resolveSkillReference(ref, cwd, homeDir) {
|
|
|
7200
7257
|
import { execFileSync } from "node:child_process";
|
|
7201
7258
|
import * as fs from "node:fs";
|
|
7202
7259
|
import path27 from "node:path";
|
|
7203
|
-
var
|
|
7260
|
+
var defaultMarkerPrefix = "poe-code-spawn-skills";
|
|
7204
7261
|
function defaultGitDirRunner(cwd) {
|
|
7205
7262
|
try {
|
|
7206
7263
|
return execFileSync("git", ["rev-parse", "--git-dir"], {
|
|
@@ -7220,10 +7277,10 @@ function resolveExcludePath(cwd) {
|
|
|
7220
7277
|
}
|
|
7221
7278
|
return path27.join(path27.isAbsolute(gitDir) ? gitDir : path27.resolve(cwd, gitDir), "info/exclude");
|
|
7222
7279
|
}
|
|
7223
|
-
function markers(runId) {
|
|
7280
|
+
function markers(runId, markerPrefix) {
|
|
7224
7281
|
return {
|
|
7225
|
-
begin:
|
|
7226
|
-
end:
|
|
7282
|
+
begin: `# ${markerPrefix}:${runId} begin`,
|
|
7283
|
+
end: `# ${markerPrefix}:${runId} end`
|
|
7227
7284
|
};
|
|
7228
7285
|
}
|
|
7229
7286
|
function readExcludeFile(excludePath) {
|
|
@@ -7239,8 +7296,8 @@ function readExcludeFile(excludePath) {
|
|
|
7239
7296
|
function isNodeError2(error2) {
|
|
7240
7297
|
return error2 instanceof Error && "code" in error2;
|
|
7241
7298
|
}
|
|
7242
|
-
function removeBlock(content, runId) {
|
|
7243
|
-
const { begin, end } = markers(runId);
|
|
7299
|
+
function removeBlock(content, runId, markerPrefix) {
|
|
7300
|
+
const { begin, end } = markers(runId, markerPrefix);
|
|
7244
7301
|
const lines = content.split("\n");
|
|
7245
7302
|
const result = [];
|
|
7246
7303
|
for (let index = 0; index < lines.length; index += 1) {
|
|
@@ -7255,23 +7312,27 @@ function removeBlock(content, runId) {
|
|
|
7255
7312
|
}
|
|
7256
7313
|
return result.join("\n");
|
|
7257
7314
|
}
|
|
7258
|
-
function appendBlock(content, runId, entries) {
|
|
7259
|
-
const { begin, end } = markers(runId);
|
|
7315
|
+
function appendBlock(content, runId, entries, markerPrefix) {
|
|
7316
|
+
const { begin, end } = markers(runId, markerPrefix);
|
|
7260
7317
|
const existing = content ?? "";
|
|
7261
7318
|
const prefix = existing.length === 0 || existing.endsWith("\n") ? existing : `${existing}
|
|
7262
7319
|
`;
|
|
7263
7320
|
return `${prefix}${[begin, ...entries, end, ""].join("\n")}`;
|
|
7264
7321
|
}
|
|
7265
|
-
function appendExcludeBlock(cwd, runId, entries) {
|
|
7322
|
+
function appendExcludeBlock(cwd, runId, entries, opts) {
|
|
7266
7323
|
const excludePath = resolveExcludePath(cwd);
|
|
7267
7324
|
if (excludePath === void 0) {
|
|
7268
7325
|
return;
|
|
7269
7326
|
}
|
|
7270
7327
|
fs.mkdirSync(path27.dirname(excludePath), { recursive: true });
|
|
7271
7328
|
const content = readExcludeFile(excludePath);
|
|
7272
|
-
fs.writeFileSync(
|
|
7329
|
+
fs.writeFileSync(
|
|
7330
|
+
excludePath,
|
|
7331
|
+
appendBlock(content, runId, entries, opts?.markerPrefix ?? defaultMarkerPrefix),
|
|
7332
|
+
"utf8"
|
|
7333
|
+
);
|
|
7273
7334
|
}
|
|
7274
|
-
function removeExcludeBlock(cwd, runId) {
|
|
7335
|
+
function removeExcludeBlock(cwd, runId, opts) {
|
|
7275
7336
|
const excludePath = resolveExcludePath(cwd);
|
|
7276
7337
|
if (excludePath === void 0) {
|
|
7277
7338
|
return;
|
|
@@ -7280,7 +7341,11 @@ function removeExcludeBlock(cwd, runId) {
|
|
|
7280
7341
|
if (content === void 0) {
|
|
7281
7342
|
return;
|
|
7282
7343
|
}
|
|
7283
|
-
fs.writeFileSync(
|
|
7344
|
+
fs.writeFileSync(
|
|
7345
|
+
excludePath,
|
|
7346
|
+
removeBlock(content, runId, opts?.markerPrefix ?? defaultMarkerPrefix),
|
|
7347
|
+
"utf8"
|
|
7348
|
+
);
|
|
7284
7349
|
}
|
|
7285
7350
|
|
|
7286
7351
|
// packages/agent-skill-config/src/bridge-active-skills.ts
|
|
@@ -7486,22 +7551,679 @@ function cleanupBridgedSkills(manifest) {
|
|
|
7486
7551
|
removeExcludeBlock(manifest.cwd, manifest.runId);
|
|
7487
7552
|
}
|
|
7488
7553
|
|
|
7554
|
+
// packages/agent-hook-config/src/configs.ts
|
|
7555
|
+
import os6 from "node:os";
|
|
7556
|
+
import path29 from "node:path";
|
|
7557
|
+
var agentHookConfigs = {
|
|
7558
|
+
"claude-code": {
|
|
7559
|
+
globalHookPath: "~/.claude/settings.json",
|
|
7560
|
+
localHookPath: ".claude/settings.json",
|
|
7561
|
+
format: "claude-settings-json",
|
|
7562
|
+
supportedEvents: [
|
|
7563
|
+
"SessionStart",
|
|
7564
|
+
"SessionEnd",
|
|
7565
|
+
"UserPromptSubmit",
|
|
7566
|
+
"PreToolUse",
|
|
7567
|
+
"PostToolUse",
|
|
7568
|
+
"PermissionRequest",
|
|
7569
|
+
"Stop",
|
|
7570
|
+
"StopFailure",
|
|
7571
|
+
"Notification",
|
|
7572
|
+
"PreCompact",
|
|
7573
|
+
"PostCompact",
|
|
7574
|
+
"SubagentStart",
|
|
7575
|
+
"SubagentStop"
|
|
7576
|
+
],
|
|
7577
|
+
supportedHandlerTypes: ["command", "http", "mcp_tool", "prompt", "agent"],
|
|
7578
|
+
placeholders: {
|
|
7579
|
+
projectDir: "${CLAUDE_PROJECT_DIR}",
|
|
7580
|
+
pluginRoot: "${CLAUDE_PLUGIN_ROOT}",
|
|
7581
|
+
pluginData: "${CLAUDE_PLUGIN_DATA}"
|
|
7582
|
+
}
|
|
7583
|
+
},
|
|
7584
|
+
codex: {
|
|
7585
|
+
globalHookPath: "~/.codex/hooks.json",
|
|
7586
|
+
localHookPath: ".codex/hooks.json",
|
|
7587
|
+
format: "codex-hooks-json",
|
|
7588
|
+
supportedEvents: [
|
|
7589
|
+
"SessionStart",
|
|
7590
|
+
"UserPromptSubmit",
|
|
7591
|
+
"PreToolUse",
|
|
7592
|
+
"PostToolUse",
|
|
7593
|
+
"PermissionRequest",
|
|
7594
|
+
"Stop"
|
|
7595
|
+
],
|
|
7596
|
+
supportedHandlerTypes: ["command"],
|
|
7597
|
+
placeholders: {
|
|
7598
|
+
projectDir: "$(git rev-parse --show-toplevel)",
|
|
7599
|
+
pluginRoot: "$PLUGIN_ROOT",
|
|
7600
|
+
pluginData: "$PLUGIN_DATA"
|
|
7601
|
+
}
|
|
7602
|
+
}
|
|
7603
|
+
};
|
|
7604
|
+
var supportedHookAgents = Object.keys(agentHookConfigs);
|
|
7605
|
+
function resolveAgentSupport2(input, registry = agentHookConfigs) {
|
|
7606
|
+
const resolvedId = resolveAgentId(input);
|
|
7607
|
+
if (!resolvedId) {
|
|
7608
|
+
return { status: "unknown", input };
|
|
7609
|
+
}
|
|
7610
|
+
const config = registry[resolvedId];
|
|
7611
|
+
if (!config) {
|
|
7612
|
+
return { status: "unsupported", input, id: resolvedId };
|
|
7613
|
+
}
|
|
7614
|
+
return { status: "supported", input, id: resolvedId, config };
|
|
7615
|
+
}
|
|
7616
|
+
function getAgentConfig2(agentId) {
|
|
7617
|
+
const support = resolveAgentSupport2(agentId);
|
|
7618
|
+
return support.status === "supported" ? support.config : void 0;
|
|
7619
|
+
}
|
|
7620
|
+
function expandHome3(targetPath, homeDir = os6.homedir()) {
|
|
7621
|
+
if (!targetPath?.startsWith("~")) {
|
|
7622
|
+
return targetPath;
|
|
7623
|
+
}
|
|
7624
|
+
if (targetPath === "~") {
|
|
7625
|
+
return homeDir;
|
|
7626
|
+
}
|
|
7627
|
+
if (targetPath.startsWith("~./")) {
|
|
7628
|
+
targetPath = `~/.${targetPath.slice(3)}`;
|
|
7629
|
+
}
|
|
7630
|
+
let remainder = targetPath.slice(1);
|
|
7631
|
+
if (remainder.startsWith("/") || remainder.startsWith("\\")) {
|
|
7632
|
+
remainder = remainder.slice(1);
|
|
7633
|
+
} else if (remainder.startsWith(".")) {
|
|
7634
|
+
remainder = remainder.slice(1);
|
|
7635
|
+
if (remainder.startsWith("/") || remainder.startsWith("\\")) {
|
|
7636
|
+
remainder = remainder.slice(1);
|
|
7637
|
+
}
|
|
7638
|
+
}
|
|
7639
|
+
return remainder.length === 0 ? homeDir : path29.join(homeDir, remainder);
|
|
7640
|
+
}
|
|
7641
|
+
function resolveHookPath(config, scope, cwd, homeDir) {
|
|
7642
|
+
if (scope === "global") {
|
|
7643
|
+
return path29.resolve(expandHome3(config.globalHookPath, homeDir));
|
|
7644
|
+
}
|
|
7645
|
+
return config.localHookPath ? path29.resolve(cwd, config.localHookPath) : void 0;
|
|
7646
|
+
}
|
|
7647
|
+
|
|
7648
|
+
// packages/agent-hook-config/src/read-hooks.ts
|
|
7649
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
7650
|
+
import path30 from "node:path";
|
|
7651
|
+
function readSettingsFile(filePath) {
|
|
7652
|
+
let content;
|
|
7653
|
+
try {
|
|
7654
|
+
content = readFileSync3(filePath, "utf8");
|
|
7655
|
+
} catch (error2) {
|
|
7656
|
+
if (error2.code === "ENOENT") {
|
|
7657
|
+
return void 0;
|
|
7658
|
+
}
|
|
7659
|
+
throw error2;
|
|
7660
|
+
}
|
|
7661
|
+
try {
|
|
7662
|
+
return JSON.parse(content);
|
|
7663
|
+
} catch (error2) {
|
|
7664
|
+
throw new Error(`Malformed JSON in ${filePath}`, { cause: error2 });
|
|
7665
|
+
}
|
|
7666
|
+
}
|
|
7667
|
+
function readClaudeHooks(cwd, homeDir, opts) {
|
|
7668
|
+
const projectPath = path30.resolve(cwd, ".claude/settings.json");
|
|
7669
|
+
const userPath = path30.resolve(homeDir, ".claude/settings.json");
|
|
7670
|
+
const scope = opts?.scope ?? "merged";
|
|
7671
|
+
const sourcePaths = scope === "project" ? [projectPath] : scope === "user" ? [userPath] : [userPath, projectPath];
|
|
7672
|
+
const result = { entries: [], readPaths: [] };
|
|
7673
|
+
for (const sourcePath of sourcePaths) {
|
|
7674
|
+
const settings = readSettingsFile(sourcePath);
|
|
7675
|
+
if (settings === void 0) {
|
|
7676
|
+
continue;
|
|
7677
|
+
}
|
|
7678
|
+
result.readPaths.push(sourcePath);
|
|
7679
|
+
for (const [event, groups] of Object.entries(settings.hooks ?? {})) {
|
|
7680
|
+
for (const group of groups) {
|
|
7681
|
+
for (const handler of group.hooks) {
|
|
7682
|
+
result.entries.push({ event, matcher: group.matcher, handler });
|
|
7683
|
+
}
|
|
7684
|
+
}
|
|
7685
|
+
}
|
|
7686
|
+
}
|
|
7687
|
+
return result;
|
|
7688
|
+
}
|
|
7689
|
+
|
|
7690
|
+
// packages/agent-hook-config/src/event-mapping.ts
|
|
7691
|
+
function requireAgentConfig(agentId) {
|
|
7692
|
+
const config = getAgentConfig2(agentId);
|
|
7693
|
+
if (!config) {
|
|
7694
|
+
throw new Error(`Unknown hook agent "${agentId}"`);
|
|
7695
|
+
}
|
|
7696
|
+
return config;
|
|
7697
|
+
}
|
|
7698
|
+
function getEventMappings(sourceAgentId, targetAgentId) {
|
|
7699
|
+
const source = requireAgentConfig(sourceAgentId);
|
|
7700
|
+
const target = requireAgentConfig(targetAgentId);
|
|
7701
|
+
return source.supportedEvents.map((sourceEvent) => {
|
|
7702
|
+
if (target.supportedEvents.includes(sourceEvent)) {
|
|
7703
|
+
return { sourceEvent, targetEvent: sourceEvent };
|
|
7704
|
+
}
|
|
7705
|
+
return {
|
|
7706
|
+
sourceEvent,
|
|
7707
|
+
targetEvent: null,
|
|
7708
|
+
dropReason: `${targetAgentId} has no ${sourceEvent} hook`
|
|
7709
|
+
};
|
|
7710
|
+
});
|
|
7711
|
+
}
|
|
7712
|
+
function getHandlerTypeRules(targetAgentId) {
|
|
7713
|
+
const target = requireAgentConfig(targetAgentId);
|
|
7714
|
+
const registeredTypes = supportedHookAgents.flatMap(
|
|
7715
|
+
(agentId) => requireAgentConfig(agentId).supportedHandlerTypes
|
|
7716
|
+
);
|
|
7717
|
+
const sourceTypes = [...new Set(registeredTypes)];
|
|
7718
|
+
const supportedTypes = target.supportedHandlerTypes.map((handlerType) => `"${handlerType}"`).join(", ");
|
|
7719
|
+
return sourceTypes.map((sourceType) => {
|
|
7720
|
+
if (target.supportedHandlerTypes.includes(sourceType)) {
|
|
7721
|
+
return { sourceType, allowed: true };
|
|
7722
|
+
}
|
|
7723
|
+
return {
|
|
7724
|
+
sourceType,
|
|
7725
|
+
allowed: false,
|
|
7726
|
+
dropReason: `${targetAgentId} only honors handlers of type ${supportedTypes}`
|
|
7727
|
+
};
|
|
7728
|
+
});
|
|
7729
|
+
}
|
|
7730
|
+
function getPlaceholderRewrites(sourceAgentId, targetAgentId) {
|
|
7731
|
+
const source = requireAgentConfig(sourceAgentId);
|
|
7732
|
+
const target = requireAgentConfig(targetAgentId);
|
|
7733
|
+
return Object.keys(source.placeholders).flatMap((key) => {
|
|
7734
|
+
const from = source.placeholders[key];
|
|
7735
|
+
const to = target.placeholders[key];
|
|
7736
|
+
if (!from || !to || from === to) {
|
|
7737
|
+
return [];
|
|
7738
|
+
}
|
|
7739
|
+
return [{ from, to }];
|
|
7740
|
+
});
|
|
7741
|
+
}
|
|
7742
|
+
|
|
7743
|
+
// packages/agent-hook-config/src/transform-hooks.ts
|
|
7744
|
+
function applyPlaceholderRewrites(value, rewrites) {
|
|
7745
|
+
return rewrites.reduce((rewrittenValue, rewrite) => {
|
|
7746
|
+
return rewrittenValue.replaceAll(rewrite.from, rewrite.to);
|
|
7747
|
+
}, value);
|
|
7748
|
+
}
|
|
7749
|
+
function transformHooks(source, sourceAgentId, targetAgentId, opts) {
|
|
7750
|
+
const eventMappings = getEventMappings(sourceAgentId, targetAgentId);
|
|
7751
|
+
const handlerRules = getHandlerTypeRules(targetAgentId);
|
|
7752
|
+
const placeholderRewrites = getPlaceholderRewrites(sourceAgentId, targetAgentId);
|
|
7753
|
+
const result = { entries: [], drops: [] };
|
|
7754
|
+
for (const sourceEntry of source) {
|
|
7755
|
+
const eventMapping = eventMappings.find((mapping) => mapping.sourceEvent === sourceEntry.event);
|
|
7756
|
+
if (!eventMapping || eventMapping.targetEvent === null) {
|
|
7757
|
+
result.drops.push({
|
|
7758
|
+
reason: "unsupported-event",
|
|
7759
|
+
detail: eventMapping?.dropReason ?? `${targetAgentId} has no ${sourceEntry.event} hook`,
|
|
7760
|
+
source: sourceEntry
|
|
7761
|
+
});
|
|
7762
|
+
continue;
|
|
7763
|
+
}
|
|
7764
|
+
const handlerRule = handlerRules.find((rule) => rule.sourceType === sourceEntry.handler.type);
|
|
7765
|
+
if (!handlerRule?.allowed) {
|
|
7766
|
+
result.drops.push({
|
|
7767
|
+
reason: "unsupported-handler-type",
|
|
7768
|
+
detail: `Unsupported handler type "${sourceEntry.handler.type}": ${handlerRule?.dropReason ?? `${targetAgentId} does not honor it`}`,
|
|
7769
|
+
source: sourceEntry
|
|
7770
|
+
});
|
|
7771
|
+
continue;
|
|
7772
|
+
}
|
|
7773
|
+
const handler = {
|
|
7774
|
+
type: "command",
|
|
7775
|
+
command: applyPlaceholderRewrites(sourceEntry.handler.command ?? "", placeholderRewrites),
|
|
7776
|
+
statusMessage: `[generated:${opts.runId}] ${sourceEntry.handler.statusMessage ?? ""}`
|
|
7777
|
+
};
|
|
7778
|
+
if (sourceEntry.handler.args !== void 0) {
|
|
7779
|
+
handler.args = sourceEntry.handler.args.map(
|
|
7780
|
+
(arg) => applyPlaceholderRewrites(arg, placeholderRewrites)
|
|
7781
|
+
);
|
|
7782
|
+
}
|
|
7783
|
+
if (sourceEntry.handler.timeout !== void 0) {
|
|
7784
|
+
handler.timeout = sourceEntry.handler.timeout;
|
|
7785
|
+
}
|
|
7786
|
+
result.entries.push({
|
|
7787
|
+
event: eventMapping.targetEvent,
|
|
7788
|
+
matcher: sourceEntry.matcher,
|
|
7789
|
+
handler,
|
|
7790
|
+
generatedId: `generated-${opts.runId}-${result.entries.length}`
|
|
7791
|
+
});
|
|
7792
|
+
}
|
|
7793
|
+
return result;
|
|
7794
|
+
}
|
|
7795
|
+
|
|
7796
|
+
// packages/agent-hook-config/src/write-hooks.ts
|
|
7797
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
7798
|
+
import path31 from "node:path";
|
|
7799
|
+
function isGeneratedHandler(handler) {
|
|
7800
|
+
return handler.statusMessage?.startsWith("[generated:") ?? false;
|
|
7801
|
+
}
|
|
7802
|
+
function parseHooksFile(targetPath) {
|
|
7803
|
+
let content;
|
|
7804
|
+
try {
|
|
7805
|
+
content = readFileSync4(targetPath, "utf8");
|
|
7806
|
+
} catch (error2) {
|
|
7807
|
+
if (error2.code === "ENOENT") {
|
|
7808
|
+
return { file: { hooks: {} }, fileCreated: true };
|
|
7809
|
+
}
|
|
7810
|
+
throw error2;
|
|
7811
|
+
}
|
|
7812
|
+
try {
|
|
7813
|
+
return { file: JSON.parse(content), fileCreated: false };
|
|
7814
|
+
} catch (error2) {
|
|
7815
|
+
throw new Error(`Malformed JSON in ${targetPath}`, { cause: error2 });
|
|
7816
|
+
}
|
|
7817
|
+
}
|
|
7818
|
+
function validateEntries(entries) {
|
|
7819
|
+
for (const entry of entries) {
|
|
7820
|
+
if (!isGeneratedHandler(entry.handler)) {
|
|
7821
|
+
throw new Error(
|
|
7822
|
+
`Generated hook entry "${entry.generatedId}" has statusMessage that must start with "[generated:"`
|
|
7823
|
+
);
|
|
7824
|
+
}
|
|
7825
|
+
}
|
|
7826
|
+
}
|
|
7827
|
+
function removeGeneratedHandlers(file) {
|
|
7828
|
+
let removed = 0;
|
|
7829
|
+
const hooks = file.hooks ?? (file.hooks = {});
|
|
7830
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
7831
|
+
hooks[event] = groups.filter((group) => {
|
|
7832
|
+
const initialCount = group.hooks.length;
|
|
7833
|
+
const remainingHandlers = group.hooks.filter((handler) => {
|
|
7834
|
+
if (isGeneratedHandler(handler)) {
|
|
7835
|
+
removed += 1;
|
|
7836
|
+
return false;
|
|
7837
|
+
}
|
|
7838
|
+
return true;
|
|
7839
|
+
});
|
|
7840
|
+
group.hooks = remainingHandlers;
|
|
7841
|
+
return group.hooks.length > 0 || group.hooks.length === initialCount;
|
|
7842
|
+
});
|
|
7843
|
+
}
|
|
7844
|
+
return removed;
|
|
7845
|
+
}
|
|
7846
|
+
function appendEntries(file, entries) {
|
|
7847
|
+
const hooks = file.hooks ?? (file.hooks = {});
|
|
7848
|
+
for (const entry of entries) {
|
|
7849
|
+
const groups = hooks[entry.event] ?? (hooks[entry.event] = []);
|
|
7850
|
+
let group = groups.find((candidate) => candidate.matcher === entry.matcher);
|
|
7851
|
+
if (!group) {
|
|
7852
|
+
group = entry.matcher === void 0 ? { hooks: [] } : { matcher: entry.matcher, hooks: [] };
|
|
7853
|
+
groups.push(group);
|
|
7854
|
+
}
|
|
7855
|
+
group.hooks.push(entry.handler);
|
|
7856
|
+
}
|
|
7857
|
+
}
|
|
7858
|
+
function writeCodexHooks(targetPath, entries, _runId) {
|
|
7859
|
+
const { file, fileCreated } = parseHooksFile(targetPath);
|
|
7860
|
+
validateEntries(entries);
|
|
7861
|
+
const previousGeneratedRemoved = removeGeneratedHandlers(file);
|
|
7862
|
+
appendEntries(file, entries);
|
|
7863
|
+
mkdirSync3(path31.dirname(targetPath), { recursive: true });
|
|
7864
|
+
const temporaryPath = `${targetPath}.tmp`;
|
|
7865
|
+
writeFileSync2(temporaryPath, `${JSON.stringify(file, null, 2)}
|
|
7866
|
+
`);
|
|
7867
|
+
renameSync(temporaryPath, targetPath);
|
|
7868
|
+
return {
|
|
7869
|
+
path: targetPath,
|
|
7870
|
+
fileCreated,
|
|
7871
|
+
previousGeneratedRemoved,
|
|
7872
|
+
generatedWritten: entries.length
|
|
7873
|
+
};
|
|
7874
|
+
}
|
|
7875
|
+
|
|
7876
|
+
// packages/agent-hook-config/src/symlink-hooks.ts
|
|
7877
|
+
import {
|
|
7878
|
+
closeSync,
|
|
7879
|
+
lstatSync,
|
|
7880
|
+
mkdirSync as mkdirSync4,
|
|
7881
|
+
openSync,
|
|
7882
|
+
readlinkSync,
|
|
7883
|
+
readSync,
|
|
7884
|
+
symlinkSync,
|
|
7885
|
+
unlinkSync
|
|
7886
|
+
} from "node:fs";
|
|
7887
|
+
import path32 from "node:path";
|
|
7888
|
+
function requireAgentConfig2(agentId) {
|
|
7889
|
+
const config = getAgentConfig2(agentId);
|
|
7890
|
+
if (!config) {
|
|
7891
|
+
throw new Error(`No hook configuration found for agent "${agentId}"`);
|
|
7892
|
+
}
|
|
7893
|
+
return config;
|
|
7894
|
+
}
|
|
7895
|
+
function resolveScopedPath(config, agentId, cwd, homeDir, scope) {
|
|
7896
|
+
const targetPath = resolveHookPath(
|
|
7897
|
+
config,
|
|
7898
|
+
scope === "project" ? "local" : "global",
|
|
7899
|
+
cwd,
|
|
7900
|
+
homeDir
|
|
7901
|
+
);
|
|
7902
|
+
if (!targetPath) {
|
|
7903
|
+
throw new Error(`Agent "${agentId}" has no ${scope} hook path`);
|
|
7904
|
+
}
|
|
7905
|
+
return targetPath;
|
|
7906
|
+
}
|
|
7907
|
+
function readFirstKilobyte(filePath) {
|
|
7908
|
+
const descriptor = openSync(filePath, "r");
|
|
7909
|
+
const buffer = Buffer.alloc(1024);
|
|
7910
|
+
try {
|
|
7911
|
+
const length = readSync(descriptor, buffer, 0, buffer.length, 0);
|
|
7912
|
+
return buffer.toString("utf8", 0, length);
|
|
7913
|
+
} finally {
|
|
7914
|
+
closeSync(descriptor);
|
|
7915
|
+
}
|
|
7916
|
+
}
|
|
7917
|
+
function isRecord7(value) {
|
|
7918
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7919
|
+
}
|
|
7920
|
+
function isFullyGeneratedFile(filePath) {
|
|
7921
|
+
let parsed;
|
|
7922
|
+
try {
|
|
7923
|
+
parsed = JSON.parse(readFirstKilobyte(filePath));
|
|
7924
|
+
} catch {
|
|
7925
|
+
return false;
|
|
7926
|
+
}
|
|
7927
|
+
if (!isRecord7(parsed)) {
|
|
7928
|
+
return false;
|
|
7929
|
+
}
|
|
7930
|
+
if (Object.keys(parsed).some((key) => key !== "hooks")) {
|
|
7931
|
+
return false;
|
|
7932
|
+
}
|
|
7933
|
+
const hooks = parsed.hooks;
|
|
7934
|
+
if (!isRecord7(hooks)) {
|
|
7935
|
+
return false;
|
|
7936
|
+
}
|
|
7937
|
+
let handlerFound = false;
|
|
7938
|
+
for (const groups of Object.values(hooks)) {
|
|
7939
|
+
if (!Array.isArray(groups)) {
|
|
7940
|
+
return false;
|
|
7941
|
+
}
|
|
7942
|
+
for (const group of groups) {
|
|
7943
|
+
if (!isRecord7(group) || !Array.isArray(group.hooks)) {
|
|
7944
|
+
return false;
|
|
7945
|
+
}
|
|
7946
|
+
for (const handler of group.hooks) {
|
|
7947
|
+
if (!isRecord7(handler)) {
|
|
7948
|
+
return false;
|
|
7949
|
+
}
|
|
7950
|
+
handlerFound = true;
|
|
7951
|
+
const statusMessage = handler.statusMessage;
|
|
7952
|
+
if (typeof statusMessage !== "string" || !statusMessage.startsWith("[generated:")) {
|
|
7953
|
+
return false;
|
|
7954
|
+
}
|
|
7955
|
+
}
|
|
7956
|
+
}
|
|
7957
|
+
}
|
|
7958
|
+
return handlerFound;
|
|
7959
|
+
}
|
|
7960
|
+
function symlinkHooks(sourceAgentId, targetAgentId, cwd, homeDir, scope) {
|
|
7961
|
+
const source = requireAgentConfig2(sourceAgentId);
|
|
7962
|
+
const target = requireAgentConfig2(targetAgentId);
|
|
7963
|
+
if (source.format !== target.format) {
|
|
7964
|
+
throw new Error(
|
|
7965
|
+
`Cannot symlink hook formats "${source.format}" and "${target.format}"; use transformation instead`
|
|
7966
|
+
);
|
|
7967
|
+
}
|
|
7968
|
+
const targetPath = resolveScopedPath(source, sourceAgentId, cwd, homeDir, scope);
|
|
7969
|
+
const symlinkPath = resolveScopedPath(target, targetAgentId, cwd, homeDir, scope);
|
|
7970
|
+
let replaced = "none";
|
|
7971
|
+
try {
|
|
7972
|
+
const existing = lstatSync(symlinkPath);
|
|
7973
|
+
if (existing.isSymbolicLink()) {
|
|
7974
|
+
if (readlinkSync(symlinkPath) === targetPath) {
|
|
7975
|
+
return { symlinkPath, targetPath, replaced };
|
|
7976
|
+
}
|
|
7977
|
+
unlinkSync(symlinkPath);
|
|
7978
|
+
replaced = "stale-symlink";
|
|
7979
|
+
} else if (existing.isFile() && isFullyGeneratedFile(symlinkPath)) {
|
|
7980
|
+
unlinkSync(symlinkPath);
|
|
7981
|
+
replaced = "generated-file";
|
|
7982
|
+
} else {
|
|
7983
|
+
throw new Error(`Refuse to replace user-authored hook file at ${symlinkPath}`);
|
|
7984
|
+
}
|
|
7985
|
+
} catch (error2) {
|
|
7986
|
+
if (error2.code !== "ENOENT") {
|
|
7987
|
+
throw error2;
|
|
7988
|
+
}
|
|
7989
|
+
}
|
|
7990
|
+
mkdirSync4(path32.dirname(symlinkPath), { recursive: true });
|
|
7991
|
+
symlinkSync(targetPath, symlinkPath);
|
|
7992
|
+
return { symlinkPath, targetPath, replaced };
|
|
7993
|
+
}
|
|
7994
|
+
|
|
7995
|
+
// packages/agent-hook-config/src/bridge-hooks.ts
|
|
7996
|
+
import * as fs3 from "node:fs";
|
|
7997
|
+
import path33 from "node:path";
|
|
7998
|
+
var hookExcludeMarkerPrefix = "poe-code-spawn-hooks";
|
|
7999
|
+
function isNodeError4(error2) {
|
|
8000
|
+
return error2 instanceof Error && "code" in error2;
|
|
8001
|
+
}
|
|
8002
|
+
function pathExists3(targetPath) {
|
|
8003
|
+
try {
|
|
8004
|
+
fs3.lstatSync(targetPath);
|
|
8005
|
+
return true;
|
|
8006
|
+
} catch (error2) {
|
|
8007
|
+
if (isNodeError4(error2) && error2.code === "ENOENT") {
|
|
8008
|
+
return false;
|
|
8009
|
+
}
|
|
8010
|
+
throw error2;
|
|
8011
|
+
}
|
|
8012
|
+
}
|
|
8013
|
+
function collectMissingParents2(targetPath) {
|
|
8014
|
+
const parents = [];
|
|
8015
|
+
let current = path33.dirname(targetPath);
|
|
8016
|
+
while (!pathExists3(current)) {
|
|
8017
|
+
parents.push(current);
|
|
8018
|
+
const parent = path33.dirname(current);
|
|
8019
|
+
if (parent === current) {
|
|
8020
|
+
break;
|
|
8021
|
+
}
|
|
8022
|
+
current = parent;
|
|
8023
|
+
}
|
|
8024
|
+
return parents.reverse();
|
|
8025
|
+
}
|
|
8026
|
+
function removeDirectoryIfEmpty2(targetPath) {
|
|
8027
|
+
try {
|
|
8028
|
+
fs3.rmdirSync(targetPath);
|
|
8029
|
+
} catch (error2) {
|
|
8030
|
+
if (isNodeError4(error2) && (error2.code === "ENOENT" || error2.code === "ENOTEMPTY" || error2.code === "EEXIST")) {
|
|
8031
|
+
return;
|
|
8032
|
+
}
|
|
8033
|
+
throw error2;
|
|
8034
|
+
}
|
|
8035
|
+
}
|
|
8036
|
+
function requireSupport(input, role) {
|
|
8037
|
+
const support = resolveAgentSupport2(input);
|
|
8038
|
+
if (support.status !== "supported" || !support.id || !support.config) {
|
|
8039
|
+
throw new Error(
|
|
8040
|
+
`Unsupported ${role} hook agent "${input}". Supported hook agents: ${supportedHookAgents.join(", ")}.`
|
|
8041
|
+
);
|
|
8042
|
+
}
|
|
8043
|
+
return { id: support.id, config: support.config };
|
|
8044
|
+
}
|
|
8045
|
+
function requireTargetPath(targetId, config, cwd, homeDir) {
|
|
8046
|
+
const targetPath = resolveHookPath(config, "local", cwd, homeDir);
|
|
8047
|
+
if (!targetPath) {
|
|
8048
|
+
throw new Error(`Agent "${targetId}" has no project hook path`);
|
|
8049
|
+
}
|
|
8050
|
+
return targetPath;
|
|
8051
|
+
}
|
|
8052
|
+
function readCodexFile(targetPath) {
|
|
8053
|
+
let content;
|
|
8054
|
+
try {
|
|
8055
|
+
content = fs3.readFileSync(targetPath, "utf8");
|
|
8056
|
+
} catch (error2) {
|
|
8057
|
+
if (isNodeError4(error2) && error2.code === "ENOENT") {
|
|
8058
|
+
return void 0;
|
|
8059
|
+
}
|
|
8060
|
+
throw error2;
|
|
8061
|
+
}
|
|
8062
|
+
try {
|
|
8063
|
+
return JSON.parse(content);
|
|
8064
|
+
} catch (error2) {
|
|
8065
|
+
throw new Error(`Malformed JSON in ${targetPath}`, { cause: error2 });
|
|
8066
|
+
}
|
|
8067
|
+
}
|
|
8068
|
+
function writeCodexFile(targetPath, file) {
|
|
8069
|
+
fs3.writeFileSync(targetPath, `${JSON.stringify(file, null, 2)}
|
|
8070
|
+
`, "utf8");
|
|
8071
|
+
}
|
|
8072
|
+
function hasOnlyEmptyHooks(file) {
|
|
8073
|
+
return Object.keys(file).every((key) => key === "hooks") && Object.values(file.hooks ?? {}).every((groups) => groups.length === 0);
|
|
8074
|
+
}
|
|
8075
|
+
function relativeToCwd(cwd, targetPath) {
|
|
8076
|
+
return path33.relative(cwd, targetPath);
|
|
8077
|
+
}
|
|
8078
|
+
function matcherKey(event, matcher) {
|
|
8079
|
+
return `${event}\0${matcher === void 0 ? "<undefined>" : matcher}`;
|
|
8080
|
+
}
|
|
8081
|
+
function bridgeHooks(sourceAgentId, targetAgentId, cwd, homeDir, runId, opts) {
|
|
8082
|
+
const source = requireSupport(sourceAgentId, "source");
|
|
8083
|
+
const target = requireSupport(targetAgentId, "target");
|
|
8084
|
+
const strategy = opts?.strategy ?? (source.config.format === target.config.format ? "symlink" : "transform");
|
|
8085
|
+
const manifest = {
|
|
8086
|
+
sourceAgentId,
|
|
8087
|
+
targetAgentId,
|
|
8088
|
+
cwd,
|
|
8089
|
+
runId,
|
|
8090
|
+
strategy,
|
|
8091
|
+
drops: []
|
|
8092
|
+
};
|
|
8093
|
+
if (strategy === "symlink") {
|
|
8094
|
+
const symlinkPath = requireTargetPath(target.id, target.config, cwd, homeDir);
|
|
8095
|
+
manifest.createdParents = collectMissingParents2(symlinkPath);
|
|
8096
|
+
const result = symlinkHooks(source.id, target.id, cwd, homeDir, "project");
|
|
8097
|
+
manifest.symlinkPath = result.symlinkPath;
|
|
8098
|
+
manifest.symlinkTarget = result.targetPath;
|
|
8099
|
+
manifest.symlinkReplaced = result.replaced;
|
|
8100
|
+
appendExcludeBlock(cwd, runId, [relativeToCwd(cwd, result.symlinkPath)], {
|
|
8101
|
+
markerPrefix: hookExcludeMarkerPrefix
|
|
8102
|
+
});
|
|
8103
|
+
return manifest;
|
|
8104
|
+
}
|
|
8105
|
+
if (source.id !== "claude-code") {
|
|
8106
|
+
throw new Error(`Transforming hooks from "${source.id}" is not supported yet`);
|
|
8107
|
+
}
|
|
8108
|
+
if (target.config.format !== "codex-hooks-json") {
|
|
8109
|
+
throw new Error(
|
|
8110
|
+
`Transforming hooks to "${target.id}" is not supported yet; only codex-hook targets can be written`
|
|
8111
|
+
);
|
|
8112
|
+
}
|
|
8113
|
+
const targetPath = requireTargetPath(target.id, target.config, cwd, homeDir);
|
|
8114
|
+
const priorFile = readCodexFile(targetPath);
|
|
8115
|
+
const sourceHooks = readClaudeHooks(cwd, homeDir, { scope: opts?.scope ?? "merged" });
|
|
8116
|
+
const transformed = transformHooks(sourceHooks.entries, source.id, target.id, { runId });
|
|
8117
|
+
const createdParents = collectMissingParents2(targetPath);
|
|
8118
|
+
const writeResult = writeCodexHooks(targetPath, transformed.entries, runId);
|
|
8119
|
+
manifest.writtenPath = targetPath;
|
|
8120
|
+
manifest.generatedEntryIds = transformed.entries.map((entry) => entry.generatedId);
|
|
8121
|
+
manifest.drops = transformed.drops;
|
|
8122
|
+
manifest.createdParents = createdParents;
|
|
8123
|
+
manifest.fileCreated = writeResult.fileCreated;
|
|
8124
|
+
manifest.preExistingEvents = Object.keys(priorFile?.hooks ?? {});
|
|
8125
|
+
manifest.preExistingMatchers = Object.entries(priorFile?.hooks ?? {}).flatMap(
|
|
8126
|
+
([event, groups]) => groups.map((group) => ({
|
|
8127
|
+
event,
|
|
8128
|
+
...group.matcher === void 0 ? {} : { matcher: group.matcher }
|
|
8129
|
+
}))
|
|
8130
|
+
);
|
|
8131
|
+
appendExcludeBlock(cwd, runId, [relativeToCwd(cwd, targetPath)], {
|
|
8132
|
+
markerPrefix: hookExcludeMarkerPrefix
|
|
8133
|
+
});
|
|
8134
|
+
return manifest;
|
|
8135
|
+
}
|
|
8136
|
+
function cleanupBridgedHooks(manifest) {
|
|
8137
|
+
if (manifest.strategy === "symlink" && manifest.symlinkPath && manifest.symlinkTarget) {
|
|
8138
|
+
try {
|
|
8139
|
+
if (fs3.lstatSync(manifest.symlinkPath).isSymbolicLink() && fs3.readlinkSync(manifest.symlinkPath) === manifest.symlinkTarget) {
|
|
8140
|
+
fs3.unlinkSync(manifest.symlinkPath);
|
|
8141
|
+
}
|
|
8142
|
+
} catch (error2) {
|
|
8143
|
+
if (!isNodeError4(error2) || error2.code !== "ENOENT") {
|
|
8144
|
+
throw error2;
|
|
8145
|
+
}
|
|
8146
|
+
}
|
|
8147
|
+
for (const parent of [...manifest.createdParents ?? []].reverse()) {
|
|
8148
|
+
removeDirectoryIfEmpty2(parent);
|
|
8149
|
+
}
|
|
8150
|
+
}
|
|
8151
|
+
if (manifest.strategy === "transform" && manifest.writtenPath) {
|
|
8152
|
+
const file = readCodexFile(manifest.writtenPath);
|
|
8153
|
+
if (file) {
|
|
8154
|
+
const generatedPrefix = `[generated:${manifest.runId}]`;
|
|
8155
|
+
const preExistingEvents = new Set(manifest.preExistingEvents ?? []);
|
|
8156
|
+
const preExistingMatchers = new Set(
|
|
8157
|
+
(manifest.preExistingMatchers ?? []).map((group) => matcherKey(group.event, group.matcher))
|
|
8158
|
+
);
|
|
8159
|
+
const hooks = file.hooks ?? {};
|
|
8160
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
8161
|
+
hooks[event] = groups.filter((group) => {
|
|
8162
|
+
const priorLength = group.hooks.length;
|
|
8163
|
+
group.hooks = group.hooks.filter(
|
|
8164
|
+
(handler) => !handler.statusMessage?.startsWith(generatedPrefix)
|
|
8165
|
+
);
|
|
8166
|
+
return group.hooks.length > 0 || group.hooks.length === priorLength || preExistingMatchers.has(matcherKey(event, group.matcher));
|
|
8167
|
+
});
|
|
8168
|
+
if (hooks[event].length === 0 && !preExistingEvents.has(event)) {
|
|
8169
|
+
delete hooks[event];
|
|
8170
|
+
}
|
|
8171
|
+
}
|
|
8172
|
+
file.hooks = hooks;
|
|
8173
|
+
if (manifest.fileCreated && hasOnlyEmptyHooks(file)) {
|
|
8174
|
+
fs3.unlinkSync(manifest.writtenPath);
|
|
8175
|
+
} else {
|
|
8176
|
+
writeCodexFile(manifest.writtenPath, file);
|
|
8177
|
+
}
|
|
8178
|
+
}
|
|
8179
|
+
for (const parent of [...manifest.createdParents ?? []].reverse()) {
|
|
8180
|
+
removeDirectoryIfEmpty2(parent);
|
|
8181
|
+
}
|
|
8182
|
+
}
|
|
8183
|
+
removeExcludeBlock(manifest.cwd, manifest.runId, { markerPrefix: hookExcludeMarkerPrefix });
|
|
8184
|
+
}
|
|
8185
|
+
|
|
7489
8186
|
// packages/agent-spawn/src/skill-bridge.ts
|
|
7490
|
-
function
|
|
7491
|
-
if (!skills || skills.length === 0) {
|
|
8187
|
+
function bridgeResourcesForRun(agentId, cwd, skills, hooks) {
|
|
8188
|
+
if ((!skills || skills.length === 0) && !hooks) {
|
|
7492
8189
|
return void 0;
|
|
7493
8190
|
}
|
|
7494
|
-
const
|
|
7495
|
-
|
|
7496
|
-
|
|
8191
|
+
const runId = crypto.randomUUID();
|
|
8192
|
+
const manifests = {};
|
|
8193
|
+
try {
|
|
8194
|
+
if (skills && skills.length > 0) {
|
|
8195
|
+
manifests.skills = bridgeActiveSkills(agentId, cwd, skills, os7.homedir(), runId);
|
|
8196
|
+
for (const warning2 of manifests.skills.warnings) {
|
|
8197
|
+
logger.warn(warning2.message);
|
|
8198
|
+
}
|
|
8199
|
+
}
|
|
8200
|
+
if (hooks) {
|
|
8201
|
+
manifests.hooks = bridgeHooks(hooks.from, agentId, cwd, os7.homedir(), runId, {
|
|
8202
|
+
strategy: hooks.strategy === "auto" ? void 0 : hooks.strategy,
|
|
8203
|
+
scope: hooks.scope
|
|
8204
|
+
});
|
|
8205
|
+
for (const drop of manifests.hooks.drops) {
|
|
8206
|
+
logger.warn(
|
|
8207
|
+
`Dropped bridged hook event "${drop.source.event}" with handler type "${drop.source.handler.type}": ${drop.detail}`
|
|
8208
|
+
);
|
|
8209
|
+
}
|
|
8210
|
+
}
|
|
8211
|
+
} catch (error2) {
|
|
8212
|
+
cleanupResourcesForRun(manifests);
|
|
8213
|
+
throw error2;
|
|
7497
8214
|
}
|
|
7498
|
-
return
|
|
8215
|
+
return manifests;
|
|
7499
8216
|
}
|
|
7500
|
-
function
|
|
8217
|
+
function cleanupResourcesForRun(manifest) {
|
|
7501
8218
|
if (!manifest) {
|
|
7502
8219
|
return;
|
|
7503
8220
|
}
|
|
7504
|
-
|
|
8221
|
+
if (manifest.hooks) {
|
|
8222
|
+
cleanupBridgedHooks(manifest.hooks);
|
|
8223
|
+
}
|
|
8224
|
+
if (manifest.skills) {
|
|
8225
|
+
cleanupBridgedSkills(manifest.skills);
|
|
8226
|
+
}
|
|
7505
8227
|
}
|
|
7506
8228
|
|
|
7507
8229
|
// packages/agent-spawn/src/adapters/utils.ts
|
|
@@ -7627,21 +8349,21 @@ async function* adaptClaude(lines) {
|
|
|
7627
8349
|
if (blockType !== "tool_result") continue;
|
|
7628
8350
|
const kind = toolKindsById.get(item.tool_use_id);
|
|
7629
8351
|
toolKindsById.delete(item.tool_use_id);
|
|
7630
|
-
let
|
|
8352
|
+
let path37;
|
|
7631
8353
|
if (typeof item.content === "string") {
|
|
7632
|
-
|
|
8354
|
+
path37 = item.content;
|
|
7633
8355
|
} else {
|
|
7634
8356
|
try {
|
|
7635
|
-
|
|
8357
|
+
path37 = JSON.stringify(item.content);
|
|
7636
8358
|
} catch {
|
|
7637
|
-
|
|
8359
|
+
path37 = String(item.content);
|
|
7638
8360
|
}
|
|
7639
8361
|
}
|
|
7640
8362
|
yield {
|
|
7641
8363
|
event: "tool_complete",
|
|
7642
8364
|
id: item.tool_use_id,
|
|
7643
8365
|
kind,
|
|
7644
|
-
path:
|
|
8366
|
+
path: path37
|
|
7645
8367
|
};
|
|
7646
8368
|
}
|
|
7647
8369
|
}
|
|
@@ -7737,10 +8459,10 @@ async function* adaptCodex(lines) {
|
|
|
7737
8459
|
const kindFromStart = toolKindById.get(item.id);
|
|
7738
8460
|
const kind = kindFromStart ?? (itemType === "command_execution" ? "exec" : itemType === "file_edit" ? "edit" : "other");
|
|
7739
8461
|
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;
|
|
7740
|
-
const
|
|
8462
|
+
const path37 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
|
|
7741
8463
|
toolTitleById.delete(item.id);
|
|
7742
8464
|
toolKindById.delete(item.id);
|
|
7743
|
-
yield { event: "tool_complete", id: item.id, kind, path:
|
|
8465
|
+
yield { event: "tool_complete", id: item.id, kind, path: path37 };
|
|
7744
8466
|
}
|
|
7745
8467
|
}
|
|
7746
8468
|
}
|
|
@@ -8268,7 +8990,7 @@ function spawnStreaming(options) {
|
|
|
8268
8990
|
};
|
|
8269
8991
|
}
|
|
8270
8992
|
};
|
|
8271
|
-
const manifest =
|
|
8993
|
+
const manifest = bridgeResourcesForRun(options.agentId, cwd, options.skills, options.hooks);
|
|
8272
8994
|
void (async () => {
|
|
8273
8995
|
try {
|
|
8274
8996
|
for await (const output of adapter(queue.lines())) {
|
|
@@ -8319,7 +9041,7 @@ function spawnStreaming(options) {
|
|
|
8319
9041
|
...ctx.logFile && !result.logFile ? { logFile: ctx.logFile } : {}
|
|
8320
9042
|
};
|
|
8321
9043
|
} finally {
|
|
8322
|
-
|
|
9044
|
+
cleanupResourcesForRun(manifest);
|
|
8323
9045
|
}
|
|
8324
9046
|
})();
|
|
8325
9047
|
return {
|
|
@@ -8461,7 +9183,7 @@ async function runSpawn(agentId, options, context) {
|
|
|
8461
9183
|
return { stdout: "", stderr: "", exitCode: 0 };
|
|
8462
9184
|
}
|
|
8463
9185
|
const cwd = options.cwd ?? process.cwd();
|
|
8464
|
-
const manifest =
|
|
9186
|
+
const manifest = bridgeResourcesForRun(agentId, cwd, options.skills, options.hooks);
|
|
8465
9187
|
let logFd;
|
|
8466
9188
|
try {
|
|
8467
9189
|
const logFilePath = resolveSpawnLogPath(options);
|
|
@@ -8529,7 +9251,7 @@ async function runSpawn(agentId, options, context) {
|
|
|
8529
9251
|
};
|
|
8530
9252
|
} finally {
|
|
8531
9253
|
closeSpawnLog(logFd);
|
|
8532
|
-
|
|
9254
|
+
cleanupResourcesForRun(manifest);
|
|
8533
9255
|
}
|
|
8534
9256
|
}
|
|
8535
9257
|
spawn4.retry = createSpawnRetry((service, options) => {
|
|
@@ -8551,12 +9273,12 @@ function resolveSpawnLogPath(options) {
|
|
|
8551
9273
|
if (!options.logDir || !options.logFileName) {
|
|
8552
9274
|
return void 0;
|
|
8553
9275
|
}
|
|
8554
|
-
return
|
|
9276
|
+
return path34.join(options.logDir, options.logFileName);
|
|
8555
9277
|
}
|
|
8556
9278
|
function openSpawnLog(filePath) {
|
|
8557
9279
|
try {
|
|
8558
|
-
|
|
8559
|
-
return
|
|
9280
|
+
mkdirSync5(path34.dirname(filePath), { recursive: true });
|
|
9281
|
+
return openSync2(filePath, "a");
|
|
8560
9282
|
} catch {
|
|
8561
9283
|
return void 0;
|
|
8562
9284
|
}
|
|
@@ -8571,7 +9293,7 @@ function appendSpawnLog(fd, chunk) {
|
|
|
8571
9293
|
function closeSpawnLog(fd) {
|
|
8572
9294
|
if (fd === void 0) return;
|
|
8573
9295
|
try {
|
|
8574
|
-
|
|
9296
|
+
closeSync2(fd);
|
|
8575
9297
|
} catch {
|
|
8576
9298
|
}
|
|
8577
9299
|
}
|
|
@@ -8580,7 +9302,7 @@ function closeSpawnLog(fd) {
|
|
|
8580
9302
|
var DEFAULT_ACTIVITY_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
8581
9303
|
|
|
8582
9304
|
// packages/agent-spawn/src/acp/replay.ts
|
|
8583
|
-
import
|
|
9305
|
+
import path35 from "node:path";
|
|
8584
9306
|
import { homedir as homedir2 } from "node:os";
|
|
8585
9307
|
import { open as open2, readdir as readdir2 } from "node:fs/promises";
|
|
8586
9308
|
import { createInterface } from "node:readline";
|
|
@@ -8599,7 +9321,7 @@ import { homedir } from "node:os";
|
|
|
8599
9321
|
import { join } from "node:path";
|
|
8600
9322
|
|
|
8601
9323
|
// packages/agent-spawn/src/acp/middlewares/spawn-log.ts
|
|
8602
|
-
import
|
|
9324
|
+
import path36 from "node:path";
|
|
8603
9325
|
import { homedir as homedir3 } from "node:os";
|
|
8604
9326
|
import { mkdir, open as open3 } from "node:fs/promises";
|
|
8605
9327
|
|
|
@@ -8613,9 +9335,30 @@ stderr:
|
|
|
8613
9335
|
${stderr}`;
|
|
8614
9336
|
}
|
|
8615
9337
|
function createSpawnHealthCheck(agentId, options) {
|
|
8616
|
-
const
|
|
8617
|
-
|
|
8618
|
-
|
|
9338
|
+
const {
|
|
9339
|
+
binaryName,
|
|
9340
|
+
args,
|
|
9341
|
+
env: modeEnv
|
|
9342
|
+
} = options.hooks ? {
|
|
9343
|
+
binaryName: "poe-code",
|
|
9344
|
+
args: [
|
|
9345
|
+
"spawn",
|
|
9346
|
+
"--hooks-from",
|
|
9347
|
+
options.hooks.from,
|
|
9348
|
+
...options.hooks.strategy ? ["--hooks-strategy", options.hooks.strategy] : [],
|
|
9349
|
+
...options.model ? ["--model", options.model] : [],
|
|
9350
|
+
"--mode",
|
|
9351
|
+
"yolo",
|
|
9352
|
+
agentId,
|
|
9353
|
+
`Output exactly: ${options.expectedOutput}`
|
|
9354
|
+
],
|
|
9355
|
+
env: void 0
|
|
9356
|
+
} : options.invocation ? {
|
|
9357
|
+
binaryName: options.invocation.command,
|
|
9358
|
+
args: options.invocation.args,
|
|
9359
|
+
env: options.invocation.env
|
|
9360
|
+
} : buildSpawnArgs(agentId, {
|
|
9361
|
+
prompt: `Output exactly: ${options.expectedOutput}`,
|
|
8619
9362
|
model: options.model,
|
|
8620
9363
|
mode: "yolo"
|
|
8621
9364
|
});
|
|
@@ -8630,6 +9373,13 @@ function createSpawnHealthCheck(agentId, options) {
|
|
|
8630
9373
|
return;
|
|
8631
9374
|
}
|
|
8632
9375
|
const result = modeEnv ? await context.runCommand(binaryName, args, { env: modeEnv }) : await context.runCommand(binaryName, args);
|
|
9376
|
+
if (options.hooks) {
|
|
9377
|
+
for (const line of result.stdout.split("\n")) {
|
|
9378
|
+
if (line.includes("Dropped bridged hook event")) {
|
|
9379
|
+
context.logWarning?.(line);
|
|
9380
|
+
}
|
|
9381
|
+
}
|
|
9382
|
+
}
|
|
8633
9383
|
if (result.exitCode !== 0) {
|
|
8634
9384
|
throw new Error(
|
|
8635
9385
|
`spawn ${agentId} failed with exit code ${result.exitCode}.
|
|
@@ -8767,6 +9517,7 @@ function createProvider(opts) {
|
|
|
8767
9517
|
configurePrompts: opts.configurePrompts,
|
|
8768
9518
|
postConfigureMessages: opts.postConfigureMessages,
|
|
8769
9519
|
extendConfigurePayload: opts.extendConfigurePayload,
|
|
9520
|
+
runtimeEnv: opts.runtimeEnv,
|
|
8770
9521
|
isolatedEnv: opts.isolatedEnv,
|
|
8771
9522
|
async configure(context, runOptions) {
|
|
8772
9523
|
await runMutations(opts.manifest.configure, {
|