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
|
@@ -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
|
|
|
@@ -67,19 +67,6 @@ var CLAUDE_CODE_VARIANTS = {
|
|
|
67
67
|
opus: "anthropic/claude-opus-4.7"
|
|
68
68
|
};
|
|
69
69
|
var DEFAULT_CLAUDE_CODE_MODEL = CLAUDE_CODE_VARIANTS.sonnet;
|
|
70
|
-
var CODEX_MODELS = [
|
|
71
|
-
"openai/gpt-5.5",
|
|
72
|
-
"openai/gpt-5.4",
|
|
73
|
-
"openai/gpt-5.3-codex",
|
|
74
|
-
"openai/gpt-5.2-codex",
|
|
75
|
-
"openai/gpt-5.2",
|
|
76
|
-
"openai/gpt-5.2-chat",
|
|
77
|
-
"openai/gpt-5.2-pro",
|
|
78
|
-
"openai/gpt-5.1",
|
|
79
|
-
"openai/gpt-5.1-codex-mini",
|
|
80
|
-
"anthropic/claude-opus-4.7"
|
|
81
|
-
];
|
|
82
|
-
var DEFAULT_CODEX_MODEL = CODEX_MODELS[0];
|
|
83
70
|
var KIMI_MODELS = [
|
|
84
71
|
"novitaai/kimi-k2.5",
|
|
85
72
|
"novitaai/kimi-k2-thinking",
|
|
@@ -840,17 +827,17 @@ function isPidRunning(pid) {
|
|
|
840
827
|
}
|
|
841
828
|
function createDefaultFs() {
|
|
842
829
|
return {
|
|
843
|
-
open: (
|
|
844
|
-
readFile: (
|
|
830
|
+
open: (path37, flags) => fsPromises.open(path37, flags),
|
|
831
|
+
readFile: (path37, encoding) => fsPromises.readFile(path37, encoding),
|
|
845
832
|
stat: fsPromises.stat,
|
|
846
833
|
unlink: fsPromises.unlink
|
|
847
834
|
};
|
|
848
835
|
}
|
|
849
|
-
async function removeLockFile(
|
|
836
|
+
async function removeLockFile(fs4, lockPath, signal) {
|
|
850
837
|
for (let attempt = 0; attempt <= 4; attempt += 1) {
|
|
851
838
|
throwIfAborted(signal);
|
|
852
839
|
try {
|
|
853
|
-
await
|
|
840
|
+
await fs4.unlink(lockPath);
|
|
854
841
|
return;
|
|
855
842
|
} catch (error2) {
|
|
856
843
|
if (hasErrorCode(error2, "ENOENT")) {
|
|
@@ -881,12 +868,12 @@ function parseLockMetadata(content) {
|
|
|
881
868
|
}
|
|
882
869
|
return void 0;
|
|
883
870
|
}
|
|
884
|
-
async function readLockMetadata(
|
|
885
|
-
if (!
|
|
871
|
+
async function readLockMetadata(fs4, lockPath) {
|
|
872
|
+
if (!fs4.readFile) {
|
|
886
873
|
return void 0;
|
|
887
874
|
}
|
|
888
875
|
try {
|
|
889
|
-
return parseLockMetadata(await
|
|
876
|
+
return parseLockMetadata(await fs4.readFile(lockPath, "utf8"));
|
|
890
877
|
} catch (error2) {
|
|
891
878
|
if (hasErrorCode(error2, "ENOENT")) {
|
|
892
879
|
return null;
|
|
@@ -920,7 +907,7 @@ async function writeLockMetadata(handle) {
|
|
|
920
907
|
}
|
|
921
908
|
}
|
|
922
909
|
async function acquireFileLock(filePath, options = {}) {
|
|
923
|
-
const
|
|
910
|
+
const fs4 = options.fs ?? createDefaultFs();
|
|
924
911
|
const retries = options.retries ?? 20;
|
|
925
912
|
const minTimeout = options.minTimeout ?? 25;
|
|
926
913
|
const maxTimeout = options.maxTimeout ?? 250;
|
|
@@ -931,7 +918,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
931
918
|
while (attempt <= retries) {
|
|
932
919
|
throwIfAborted(options.signal);
|
|
933
920
|
try {
|
|
934
|
-
const handle = await
|
|
921
|
+
const handle = await fs4.open(lockPath, "wx");
|
|
935
922
|
await writeLockMetadata(handle);
|
|
936
923
|
let released = false;
|
|
937
924
|
return async () => {
|
|
@@ -939,7 +926,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
939
926
|
return;
|
|
940
927
|
}
|
|
941
928
|
released = true;
|
|
942
|
-
await removeLockFile(
|
|
929
|
+
await removeLockFile(fs4, lockPath, options.signal);
|
|
943
930
|
};
|
|
944
931
|
} catch (error2) {
|
|
945
932
|
if (!hasErrorCode(error2, "EEXIST")) {
|
|
@@ -948,7 +935,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
948
935
|
}
|
|
949
936
|
let stat3;
|
|
950
937
|
try {
|
|
951
|
-
stat3 = await
|
|
938
|
+
stat3 = await fs4.stat(lockPath);
|
|
952
939
|
} catch (statError) {
|
|
953
940
|
if (hasErrorCode(statError, "ENOENT")) {
|
|
954
941
|
continue;
|
|
@@ -956,7 +943,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
956
943
|
throw statError;
|
|
957
944
|
}
|
|
958
945
|
const reclaimLock = await shouldReclaimLock({
|
|
959
|
-
fs:
|
|
946
|
+
fs: fs4,
|
|
960
947
|
isPidRunning: pidIsRunning,
|
|
961
948
|
lockPath,
|
|
962
949
|
staleMs,
|
|
@@ -966,7 +953,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
966
953
|
continue;
|
|
967
954
|
}
|
|
968
955
|
if (reclaimLock) {
|
|
969
|
-
await removeLockFile(
|
|
956
|
+
await removeLockFile(fs4, lockPath, options.signal);
|
|
970
957
|
continue;
|
|
971
958
|
}
|
|
972
959
|
if (attempt >= retries) {
|
|
@@ -1143,6 +1130,24 @@ var codexAgent = {
|
|
|
1143
1130
|
}
|
|
1144
1131
|
};
|
|
1145
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
|
+
|
|
1146
1151
|
// packages/agent-defs/src/agents/opencode.ts
|
|
1147
1152
|
var openCodeAgent = {
|
|
1148
1153
|
id: "opencode",
|
|
@@ -1216,6 +1221,7 @@ var allAgents = [
|
|
|
1216
1221
|
claudeCodeAgent,
|
|
1217
1222
|
claudeDesktopAgent,
|
|
1218
1223
|
codexAgent,
|
|
1224
|
+
geminiCliAgent,
|
|
1219
1225
|
openCodeAgent,
|
|
1220
1226
|
kimiAgent,
|
|
1221
1227
|
gooseAgent,
|
|
@@ -1266,29 +1272,29 @@ function wrapForLogTee(argv, jobId) {
|
|
|
1266
1272
|
return ["sh", "-c", script];
|
|
1267
1273
|
}
|
|
1268
1274
|
async function* streamLogFile(env, jobId, opts) {
|
|
1269
|
-
const
|
|
1275
|
+
const fs4 = env.fs ?? nodeFs;
|
|
1270
1276
|
const file = jobLogPath(jobId);
|
|
1271
1277
|
let byteOffset = opts.sinceByte ?? 0;
|
|
1272
1278
|
while (true) {
|
|
1273
|
-
if (opts.since !== void 0 && !await wasModifiedSince(
|
|
1274
|
-
await waitForLogChange(
|
|
1279
|
+
if (opts.since !== void 0 && !await wasModifiedSince(fs4, file, opts.since)) {
|
|
1280
|
+
await waitForLogChange(fs4, file);
|
|
1275
1281
|
continue;
|
|
1276
1282
|
}
|
|
1277
|
-
const result = await readLogChunk(
|
|
1283
|
+
const result = await readLogChunk(fs4, file, byteOffset);
|
|
1278
1284
|
if (result !== null) {
|
|
1279
1285
|
byteOffset = result.nextByteOffset;
|
|
1280
1286
|
yield result.chunk;
|
|
1281
1287
|
continue;
|
|
1282
1288
|
}
|
|
1283
|
-
await waitForLogChange(
|
|
1289
|
+
await waitForLogChange(fs4, file);
|
|
1284
1290
|
}
|
|
1285
1291
|
}
|
|
1286
|
-
async function wasModifiedSince(
|
|
1287
|
-
if (
|
|
1292
|
+
async function wasModifiedSince(fs4, file, since) {
|
|
1293
|
+
if (fs4.promises.stat === void 0) {
|
|
1288
1294
|
return true;
|
|
1289
1295
|
}
|
|
1290
1296
|
try {
|
|
1291
|
-
const stat3 = await
|
|
1297
|
+
const stat3 = await fs4.promises.stat(file);
|
|
1292
1298
|
return stat3.mtimeMs >= since.getTime();
|
|
1293
1299
|
} catch (error2) {
|
|
1294
1300
|
if (isNodeError(error2) && error2.code === "ENOENT") {
|
|
@@ -1298,11 +1304,11 @@ async function wasModifiedSince(fs3, file, since) {
|
|
|
1298
1304
|
}
|
|
1299
1305
|
}
|
|
1300
1306
|
async function waitForExit(env, jobId, opts = {}) {
|
|
1301
|
-
const
|
|
1307
|
+
const fs4 = env.fs ?? nodeFs;
|
|
1302
1308
|
const file = jobExitPath(jobId);
|
|
1303
1309
|
while (true) {
|
|
1304
1310
|
throwIfAborted2(opts.signal);
|
|
1305
|
-
const contents = await readTextFileIfExists(
|
|
1311
|
+
const contents = await readTextFileIfExists(fs4, file);
|
|
1306
1312
|
if (contents !== null) {
|
|
1307
1313
|
const text5 = contents.trim();
|
|
1308
1314
|
const exitCode = Number(text5);
|
|
@@ -1320,8 +1326,8 @@ function jobLogPath(jobId) {
|
|
|
1320
1326
|
function jobExitPath(jobId) {
|
|
1321
1327
|
return `${JOB_DIR}/${jobId}.exit`;
|
|
1322
1328
|
}
|
|
1323
|
-
async function readLogChunk(
|
|
1324
|
-
const contents = await readFileIfExists(
|
|
1329
|
+
async function readLogChunk(fs4, file, byteOffset) {
|
|
1330
|
+
const contents = await readFileIfExists(fs4, file);
|
|
1325
1331
|
if (contents === null || byteOffset >= contents.byteLength) {
|
|
1326
1332
|
return null;
|
|
1327
1333
|
}
|
|
@@ -1333,13 +1339,13 @@ async function readLogChunk(fs3, file, byteOffset) {
|
|
|
1333
1339
|
nextByteOffset: contents.byteLength
|
|
1334
1340
|
};
|
|
1335
1341
|
}
|
|
1336
|
-
async function readTextFileIfExists(
|
|
1337
|
-
const contents = await readFileIfExists(
|
|
1342
|
+
async function readTextFileIfExists(fs4, file) {
|
|
1343
|
+
const contents = await readFileIfExists(fs4, file);
|
|
1338
1344
|
return contents?.toString("utf8") ?? null;
|
|
1339
1345
|
}
|
|
1340
|
-
async function readFileIfExists(
|
|
1346
|
+
async function readFileIfExists(fs4, file) {
|
|
1341
1347
|
try {
|
|
1342
|
-
const contents = await
|
|
1348
|
+
const contents = await fs4.promises.readFile(file);
|
|
1343
1349
|
return Buffer.isBuffer(contents) ? contents : Buffer.from(contents);
|
|
1344
1350
|
} catch (error2) {
|
|
1345
1351
|
if (isNodeError(error2) && error2.code === "ENOENT") {
|
|
@@ -1348,8 +1354,8 @@ async function readFileIfExists(fs3, file) {
|
|
|
1348
1354
|
throw error2;
|
|
1349
1355
|
}
|
|
1350
1356
|
}
|
|
1351
|
-
async function waitForLogChange(
|
|
1352
|
-
const watch =
|
|
1357
|
+
async function waitForLogChange(fs4, file) {
|
|
1358
|
+
const watch = fs4.watch;
|
|
1353
1359
|
if (typeof watch !== "function") {
|
|
1354
1360
|
await sleep2(POLL_INTERVAL_MS);
|
|
1355
1361
|
return;
|
|
@@ -2315,7 +2321,7 @@ import path14 from "node:path";
|
|
|
2315
2321
|
|
|
2316
2322
|
// packages/config-extends/src/discover.ts
|
|
2317
2323
|
import path10 from "node:path";
|
|
2318
|
-
async function findBase(name, bases,
|
|
2324
|
+
async function findBase(name, bases, fs4) {
|
|
2319
2325
|
const checkedPaths = [];
|
|
2320
2326
|
for (const basePath of bases) {
|
|
2321
2327
|
for (const extension of [".md", ".yaml", ".yml", ".json"]) {
|
|
@@ -2323,7 +2329,7 @@ async function findBase(name, bases, fs3) {
|
|
|
2323
2329
|
checkedPaths.push(filePath);
|
|
2324
2330
|
try {
|
|
2325
2331
|
return {
|
|
2326
|
-
content: await
|
|
2332
|
+
content: await fs4.readFile(filePath, "utf8"),
|
|
2327
2333
|
filePath
|
|
2328
2334
|
};
|
|
2329
2335
|
} catch (error2) {
|
|
@@ -2403,11 +2409,11 @@ function stripBom(content) {
|
|
|
2403
2409
|
function mergeLayers(layers) {
|
|
2404
2410
|
return mergeObjectLayers(layers, []);
|
|
2405
2411
|
}
|
|
2406
|
-
function mergeObjectLayers(layers,
|
|
2412
|
+
function mergeObjectLayers(layers, path37) {
|
|
2407
2413
|
const data = {};
|
|
2408
2414
|
const sources = {};
|
|
2409
2415
|
for (const key of collectKeys(layers)) {
|
|
2410
|
-
const resolved = resolveKey(layers, key,
|
|
2416
|
+
const resolved = resolveKey(layers, key, path37);
|
|
2411
2417
|
if (resolved === void 0) {
|
|
2412
2418
|
continue;
|
|
2413
2419
|
}
|
|
@@ -2425,7 +2431,7 @@ function collectKeys(layers) {
|
|
|
2425
2431
|
}
|
|
2426
2432
|
return [...keys];
|
|
2427
2433
|
}
|
|
2428
|
-
function resolveKey(layers, key,
|
|
2434
|
+
function resolveKey(layers, key, path37) {
|
|
2429
2435
|
let winningSource;
|
|
2430
2436
|
let winningValue;
|
|
2431
2437
|
const objectLayers = [];
|
|
@@ -2455,9 +2461,9 @@ function resolveKey(layers, key, path32) {
|
|
|
2455
2461
|
if (winningSource === void 0) {
|
|
2456
2462
|
return void 0;
|
|
2457
2463
|
}
|
|
2458
|
-
const fullPath = buildPath(
|
|
2464
|
+
const fullPath = buildPath(path37, key);
|
|
2459
2465
|
if (isPlainObject(winningValue)) {
|
|
2460
|
-
const merged = mergeObjectLayers(objectLayers, [...
|
|
2466
|
+
const merged = mergeObjectLayers(objectLayers, [...path37, key]);
|
|
2461
2467
|
return {
|
|
2462
2468
|
value: merged.data,
|
|
2463
2469
|
sources: {
|
|
@@ -2482,8 +2488,8 @@ function isWinningCandidate(key, value) {
|
|
|
2482
2488
|
}
|
|
2483
2489
|
return true;
|
|
2484
2490
|
}
|
|
2485
|
-
function buildPath(
|
|
2486
|
-
return [...
|
|
2491
|
+
function buildPath(path37, key) {
|
|
2492
|
+
return [...path37, key].join(".");
|
|
2487
2493
|
}
|
|
2488
2494
|
function isPlainObject(value) {
|
|
2489
2495
|
if (value === null || Array.isArray(value) || typeof value !== "object") {
|
|
@@ -3837,16 +3843,16 @@ function getConfigFormat(pathOrFormat) {
|
|
|
3837
3843
|
}
|
|
3838
3844
|
return formatRegistry[formatName];
|
|
3839
3845
|
}
|
|
3840
|
-
function detectFormat2(
|
|
3841
|
-
const ext = getExtension(
|
|
3846
|
+
function detectFormat2(path37) {
|
|
3847
|
+
const ext = getExtension(path37);
|
|
3842
3848
|
return extensionMap[ext];
|
|
3843
3849
|
}
|
|
3844
|
-
function getExtension(
|
|
3845
|
-
const lastDot =
|
|
3850
|
+
function getExtension(path37) {
|
|
3851
|
+
const lastDot = path37.lastIndexOf(".");
|
|
3846
3852
|
if (lastDot === -1) {
|
|
3847
3853
|
return "";
|
|
3848
3854
|
}
|
|
3849
|
-
return
|
|
3855
|
+
return path37.slice(lastDot).toLowerCase();
|
|
3850
3856
|
}
|
|
3851
3857
|
|
|
3852
3858
|
// packages/config-mutations/src/execution/path-utils.ts
|
|
@@ -3897,9 +3903,9 @@ function resolvePath(rawPath, homeDir, pathMapper) {
|
|
|
3897
3903
|
function isNotFound(error2) {
|
|
3898
3904
|
return typeof error2 === "object" && error2 !== null && "code" in error2 && error2.code === "ENOENT";
|
|
3899
3905
|
}
|
|
3900
|
-
async function readFileIfExists2(
|
|
3906
|
+
async function readFileIfExists2(fs4, target) {
|
|
3901
3907
|
try {
|
|
3902
|
-
return await
|
|
3908
|
+
return await fs4.readFile(target, "utf8");
|
|
3903
3909
|
} catch (error2) {
|
|
3904
3910
|
if (isNotFound(error2)) {
|
|
3905
3911
|
return null;
|
|
@@ -3907,9 +3913,9 @@ async function readFileIfExists2(fs3, target) {
|
|
|
3907
3913
|
throw error2;
|
|
3908
3914
|
}
|
|
3909
3915
|
}
|
|
3910
|
-
async function pathExists(
|
|
3916
|
+
async function pathExists(fs4, target) {
|
|
3911
3917
|
try {
|
|
3912
|
-
await
|
|
3918
|
+
await fs4.stat(target);
|
|
3913
3919
|
return true;
|
|
3914
3920
|
} catch (error2) {
|
|
3915
3921
|
if (isNotFound(error2)) {
|
|
@@ -3933,9 +3939,9 @@ function createInvalidDocumentBackupPath(targetPath) {
|
|
|
3933
3939
|
const ext = targetPath.includes(".") ? targetPath.split(".").pop() : "bak";
|
|
3934
3940
|
return `${targetPath}.invalid-${createTimestamp()}.${ext}`;
|
|
3935
3941
|
}
|
|
3936
|
-
async function backupInvalidDocument(
|
|
3942
|
+
async function backupInvalidDocument(fs4, targetPath, content) {
|
|
3937
3943
|
const backupPath = createInvalidDocumentBackupPath(targetPath);
|
|
3938
|
-
await
|
|
3944
|
+
await fs4.writeFile(backupPath, content, { encoding: "utf8" });
|
|
3939
3945
|
}
|
|
3940
3946
|
function describeMutation(kind, targetPath) {
|
|
3941
3947
|
const displayPath = targetPath ?? "target";
|
|
@@ -4493,12 +4499,12 @@ async function executeMutation(mutation, context, options) {
|
|
|
4493
4499
|
}
|
|
4494
4500
|
|
|
4495
4501
|
// packages/poe-code-config/src/store.ts
|
|
4496
|
-
async function readMergedDocument(
|
|
4497
|
-
const globalDocument = await readStoredDocument(
|
|
4502
|
+
async function readMergedDocument(fs4, globalPath, projectPath) {
|
|
4503
|
+
const globalDocument = await readStoredDocument(fs4, globalPath);
|
|
4498
4504
|
if (!projectPath || projectPath === globalPath) {
|
|
4499
4505
|
return globalDocument.data;
|
|
4500
4506
|
}
|
|
4501
|
-
const projectDocument = await readStoredDocument(
|
|
4507
|
+
const projectDocument = await readStoredDocument(fs4, projectPath);
|
|
4502
4508
|
const resolved = await resolve(
|
|
4503
4509
|
[
|
|
4504
4510
|
{
|
|
@@ -4512,16 +4518,16 @@ async function readMergedDocument(fs3, globalPath, projectPath) {
|
|
|
4512
4518
|
}
|
|
4513
4519
|
],
|
|
4514
4520
|
{
|
|
4515
|
-
fs: createResolvedConfigFs(
|
|
4521
|
+
fs: createResolvedConfigFs(fs4, globalPath, globalDocument.content),
|
|
4516
4522
|
autoExtend: true
|
|
4517
4523
|
}
|
|
4518
4524
|
);
|
|
4519
4525
|
return normalizeDocument(resolved.data);
|
|
4520
4526
|
}
|
|
4521
|
-
async function readStoredDocument(
|
|
4527
|
+
async function readStoredDocument(fs4, filePath) {
|
|
4522
4528
|
try {
|
|
4523
|
-
const raw = await
|
|
4524
|
-
return await parseStoredDocument(
|
|
4529
|
+
const raw = await fs4.readFile(filePath, "utf8");
|
|
4530
|
+
return await parseStoredDocument(fs4, filePath, raw);
|
|
4525
4531
|
} catch (error2) {
|
|
4526
4532
|
if (isNotFound(error2)) {
|
|
4527
4533
|
return {
|
|
@@ -4532,7 +4538,7 @@ async function readStoredDocument(fs3, filePath) {
|
|
|
4532
4538
|
throw error2;
|
|
4533
4539
|
}
|
|
4534
4540
|
}
|
|
4535
|
-
async function parseStoredDocument(
|
|
4541
|
+
async function parseStoredDocument(fs4, filePath, raw) {
|
|
4536
4542
|
try {
|
|
4537
4543
|
return {
|
|
4538
4544
|
content: raw,
|
|
@@ -4540,7 +4546,7 @@ async function parseStoredDocument(fs3, filePath, raw) {
|
|
|
4540
4546
|
};
|
|
4541
4547
|
} catch (error2) {
|
|
4542
4548
|
if (error2 instanceof SyntaxError) {
|
|
4543
|
-
await recoverInvalidDocument(
|
|
4549
|
+
await recoverInvalidDocument(fs4, filePath, raw);
|
|
4544
4550
|
return {
|
|
4545
4551
|
content: EMPTY_DOCUMENT,
|
|
4546
4552
|
data: {}
|
|
@@ -4574,21 +4580,21 @@ function normalizeScopeValues(value) {
|
|
|
4574
4580
|
}
|
|
4575
4581
|
return normalized;
|
|
4576
4582
|
}
|
|
4577
|
-
function createResolvedConfigFs(
|
|
4583
|
+
function createResolvedConfigFs(fs4, globalPath, globalContent) {
|
|
4578
4584
|
return {
|
|
4579
4585
|
readFile(filePath, _encoding) {
|
|
4580
4586
|
if (filePath === globalPath) {
|
|
4581
4587
|
return Promise.resolve(globalContent);
|
|
4582
4588
|
}
|
|
4583
|
-
return
|
|
4589
|
+
return fs4.readFile(filePath, "utf8");
|
|
4584
4590
|
}
|
|
4585
4591
|
};
|
|
4586
4592
|
}
|
|
4587
|
-
async function recoverInvalidDocument(
|
|
4588
|
-
await
|
|
4593
|
+
async function recoverInvalidDocument(fs4, filePath, content) {
|
|
4594
|
+
await fs4.mkdir(path14.dirname(filePath), { recursive: true });
|
|
4589
4595
|
const backupPath = createInvalidBackupPath(filePath);
|
|
4590
|
-
await
|
|
4591
|
-
await
|
|
4596
|
+
await fs4.writeFile(backupPath, content, { encoding: "utf8" });
|
|
4597
|
+
await fs4.writeFile(filePath, EMPTY_DOCUMENT, { encoding: "utf8" });
|
|
4592
4598
|
}
|
|
4593
4599
|
function createInvalidBackupPath(filePath) {
|
|
4594
4600
|
const directory = path14.dirname(filePath);
|
|
@@ -4712,7 +4718,7 @@ function mergeScope(scope, baseScope, overrideScope) {
|
|
|
4712
4718
|
...Object.fromEntries(scopeEntries)
|
|
4713
4719
|
};
|
|
4714
4720
|
}
|
|
4715
|
-
function mergeRuntimeScope(baseScope, overrideScope,
|
|
4721
|
+
function mergeRuntimeScope(baseScope, overrideScope, path37 = []) {
|
|
4716
4722
|
const merged = {};
|
|
4717
4723
|
const keys = /* @__PURE__ */ new Set([...Object.keys(baseScope), ...Object.keys(overrideScope)]);
|
|
4718
4724
|
for (const key of keys) {
|
|
@@ -4724,20 +4730,20 @@ function mergeRuntimeScope(baseScope, overrideScope, path32 = []) {
|
|
|
4724
4730
|
}
|
|
4725
4731
|
continue;
|
|
4726
4732
|
}
|
|
4727
|
-
if (isRuntimeConcatenativeArray([...
|
|
4733
|
+
if (isRuntimeConcatenativeArray([...path37, key]) && Array.isArray(baseValue) && Array.isArray(overrideValue)) {
|
|
4728
4734
|
merged[key] = [...baseValue, ...overrideValue];
|
|
4729
4735
|
continue;
|
|
4730
4736
|
}
|
|
4731
4737
|
if (isRecord4(baseValue) && isRecord4(overrideValue)) {
|
|
4732
|
-
merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...
|
|
4738
|
+
merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...path37, key]);
|
|
4733
4739
|
continue;
|
|
4734
4740
|
}
|
|
4735
4741
|
merged[key] = overrideValue;
|
|
4736
4742
|
}
|
|
4737
4743
|
return merged;
|
|
4738
4744
|
}
|
|
4739
|
-
function isRuntimeConcatenativeArray(
|
|
4740
|
-
return
|
|
4745
|
+
function isRuntimeConcatenativeArray(path37) {
|
|
4746
|
+
return path37.join(".") === "mounts" || path37.join(".") === "runner.workspace.exclude";
|
|
4741
4747
|
}
|
|
4742
4748
|
function isRecord4(value) {
|
|
4743
4749
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -4925,6 +4931,7 @@ var poeProvider = {
|
|
|
4925
4931
|
label: "Poe",
|
|
4926
4932
|
summary: "Route AI coding agents through Poe's API.",
|
|
4927
4933
|
baseUrl: "https://api.poe.com",
|
|
4934
|
+
agentBaseUrl: "https://api.poe.com",
|
|
4928
4935
|
auth: {
|
|
4929
4936
|
kind: "api-key",
|
|
4930
4937
|
envVar: "POE_API_KEY",
|
|
@@ -4932,6 +4939,12 @@ var poeProvider = {
|
|
|
4932
4939
|
prompt: { title: "Poe API key" },
|
|
4933
4940
|
preferredLogin: "oauth"
|
|
4934
4941
|
},
|
|
4942
|
+
env: {
|
|
4943
|
+
ANTHROPIC_CUSTOM_HEADERS: {
|
|
4944
|
+
kind: "providerCredential",
|
|
4945
|
+
prefix: "Authorization: Bearer "
|
|
4946
|
+
}
|
|
4947
|
+
},
|
|
4935
4948
|
apiShapes: [
|
|
4936
4949
|
{
|
|
4937
4950
|
id: "openai-chat-completions",
|
|
@@ -4960,6 +4973,9 @@ var anthropicProvider = {
|
|
|
4960
4973
|
storageKey: "provider:anthropic",
|
|
4961
4974
|
prompt: { title: "Anthropic API key" }
|
|
4962
4975
|
},
|
|
4976
|
+
env: {
|
|
4977
|
+
ANTHROPIC_API_KEY: { kind: "providerCredential" }
|
|
4978
|
+
},
|
|
4963
4979
|
apiShapes: [
|
|
4964
4980
|
{
|
|
4965
4981
|
id: "anthropic-messages",
|
|
@@ -4972,30 +4988,38 @@ var anthropicProvider = {
|
|
|
4972
4988
|
var cloudflareProvider = {
|
|
4973
4989
|
id: "cloudflare",
|
|
4974
4990
|
label: "Cloudflare AI Gateway",
|
|
4975
|
-
summary: "Route
|
|
4976
|
-
|
|
4991
|
+
summary: "Route coding agents through Cloudflare AI Gateway.",
|
|
4992
|
+
baseUrlEnvVar: "CF_AIG_BASE_URL",
|
|
4993
|
+
requiresBaseUrl: true,
|
|
4994
|
+
modelInput: { kind: "freeform" },
|
|
4977
4995
|
auth: {
|
|
4978
4996
|
kind: "api-key",
|
|
4979
|
-
envVar: "
|
|
4997
|
+
envVar: "CF_AIG_TOKEN",
|
|
4980
4998
|
storageKey: "provider:cloudflare",
|
|
4981
|
-
prompt: { title: "Cloudflare
|
|
4999
|
+
prompt: { title: "Cloudflare AI Gateway token" }
|
|
5000
|
+
},
|
|
5001
|
+
env: {
|
|
5002
|
+
ANTHROPIC_CUSTOM_HEADERS: {
|
|
5003
|
+
kind: "providerCredential",
|
|
5004
|
+
prefix: "Authorization: Bearer "
|
|
5005
|
+
}
|
|
4982
5006
|
},
|
|
4983
5007
|
apiShapes: [
|
|
4984
5008
|
{
|
|
4985
5009
|
id: "openai-chat-completions",
|
|
4986
|
-
|
|
5010
|
+
baseUrlPath: "compat"
|
|
4987
5011
|
},
|
|
4988
5012
|
{
|
|
4989
5013
|
id: "openai-responses",
|
|
4990
|
-
|
|
5014
|
+
baseUrlPath: "openai"
|
|
4991
5015
|
},
|
|
4992
5016
|
{
|
|
4993
5017
|
id: "anthropic-messages",
|
|
4994
|
-
|
|
5018
|
+
baseUrlPath: "anthropic"
|
|
4995
5019
|
},
|
|
4996
5020
|
{
|
|
4997
5021
|
id: "google-generations",
|
|
4998
|
-
|
|
5022
|
+
baseUrlPath: "google-ai-studio"
|
|
4999
5023
|
}
|
|
5000
5024
|
]
|
|
5001
5025
|
};
|
|
@@ -5024,7 +5048,7 @@ function isNotFoundError(error2) {
|
|
|
5024
5048
|
}
|
|
5025
5049
|
|
|
5026
5050
|
// packages/poe-code-config/src/state/jobs.ts
|
|
5027
|
-
function createJobRegistry(homeDir,
|
|
5051
|
+
function createJobRegistry(homeDir, fs4 = defaultStateFs) {
|
|
5028
5052
|
const jobsDir = path17.join(homeDir, ".poe-code", "state", "jobs");
|
|
5029
5053
|
function jobPath(id) {
|
|
5030
5054
|
assertSafeJobId(id);
|
|
@@ -5032,7 +5056,7 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5032
5056
|
}
|
|
5033
5057
|
async function get(id) {
|
|
5034
5058
|
try {
|
|
5035
|
-
return parseJobEntry(await
|
|
5059
|
+
return parseJobEntry(await fs4.readFile(jobPath(id), "utf8"));
|
|
5036
5060
|
} catch (error2) {
|
|
5037
5061
|
if (isNotFoundError(error2)) {
|
|
5038
5062
|
return null;
|
|
@@ -5043,8 +5067,8 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5043
5067
|
async function put(entry) {
|
|
5044
5068
|
assertJobEntry(entry);
|
|
5045
5069
|
const filePath = jobPath(entry.id);
|
|
5046
|
-
await
|
|
5047
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5070
|
+
await fs4.mkdir(jobsDir, { recursive: true });
|
|
5071
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5048
5072
|
try {
|
|
5049
5073
|
await writeJobAtomically(filePath, entry);
|
|
5050
5074
|
} finally {
|
|
@@ -5053,8 +5077,8 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5053
5077
|
}
|
|
5054
5078
|
async function update(id, patch) {
|
|
5055
5079
|
const filePath = jobPath(id);
|
|
5056
|
-
await
|
|
5057
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5080
|
+
await fs4.mkdir(jobsDir, { recursive: true });
|
|
5081
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5058
5082
|
try {
|
|
5059
5083
|
const current = await get(id);
|
|
5060
5084
|
if (current === null) {
|
|
@@ -5075,7 +5099,7 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5075
5099
|
async function list(filter = {}) {
|
|
5076
5100
|
let entries;
|
|
5077
5101
|
try {
|
|
5078
|
-
entries = await
|
|
5102
|
+
entries = await fs4.readdir(jobsDir);
|
|
5079
5103
|
} catch (error2) {
|
|
5080
5104
|
if (isNotFoundError(error2)) {
|
|
5081
5105
|
return [];
|
|
@@ -5088,11 +5112,11 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5088
5112
|
continue;
|
|
5089
5113
|
}
|
|
5090
5114
|
const filePath = path17.join(jobsDir, entry);
|
|
5091
|
-
const stat3 = await
|
|
5115
|
+
const stat3 = await fs4.stat(filePath);
|
|
5092
5116
|
if (!stat3.isFile()) {
|
|
5093
5117
|
continue;
|
|
5094
5118
|
}
|
|
5095
|
-
const job = parseJobEntry(await
|
|
5119
|
+
const job = parseJobEntry(await fs4.readFile(filePath, "utf8"));
|
|
5096
5120
|
if (matchesFilter(job, filter)) {
|
|
5097
5121
|
jobs.push(job);
|
|
5098
5122
|
}
|
|
@@ -5102,16 +5126,16 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5102
5126
|
async function remove2(id) {
|
|
5103
5127
|
const filePath = jobPath(id);
|
|
5104
5128
|
try {
|
|
5105
|
-
await
|
|
5129
|
+
await fs4.stat(jobsDir);
|
|
5106
5130
|
} catch (error2) {
|
|
5107
5131
|
if (isNotFoundError(error2)) {
|
|
5108
5132
|
return;
|
|
5109
5133
|
}
|
|
5110
5134
|
throw error2;
|
|
5111
5135
|
}
|
|
5112
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5136
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5113
5137
|
try {
|
|
5114
|
-
await
|
|
5138
|
+
await fs4.unlink(filePath);
|
|
5115
5139
|
} catch (error2) {
|
|
5116
5140
|
if (!isNotFoundError(error2)) {
|
|
5117
5141
|
throw error2;
|
|
@@ -5121,14 +5145,14 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5121
5145
|
}
|
|
5122
5146
|
}
|
|
5123
5147
|
async function writeJobAtomically(filePath, entry) {
|
|
5124
|
-
await
|
|
5148
|
+
await fs4.mkdir(path17.dirname(filePath), { recursive: true });
|
|
5125
5149
|
const tempPath = `${filePath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
5126
5150
|
try {
|
|
5127
|
-
await
|
|
5151
|
+
await fs4.writeFile(tempPath, `${JSON.stringify(entry, null, 2)}
|
|
5128
5152
|
`, {
|
|
5129
5153
|
encoding: "utf8"
|
|
5130
5154
|
});
|
|
5131
|
-
await
|
|
5155
|
+
await fs4.rename(tempPath, filePath);
|
|
5132
5156
|
} catch (error2) {
|
|
5133
5157
|
await removeTempFile(tempPath);
|
|
5134
5158
|
throw error2;
|
|
@@ -5136,7 +5160,7 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5136
5160
|
}
|
|
5137
5161
|
async function removeTempFile(tempPath) {
|
|
5138
5162
|
try {
|
|
5139
|
-
await
|
|
5163
|
+
await fs4.unlink(tempPath);
|
|
5140
5164
|
} catch (error2) {
|
|
5141
5165
|
if (!isNotFoundError(error2)) {
|
|
5142
5166
|
throw error2;
|
|
@@ -5183,11 +5207,11 @@ function isRecord5(value) {
|
|
|
5183
5207
|
|
|
5184
5208
|
// packages/poe-code-config/src/state/templates.ts
|
|
5185
5209
|
import path18 from "node:path";
|
|
5186
|
-
function createTemplateRegistry(homeDir,
|
|
5210
|
+
function createTemplateRegistry(homeDir, fs4 = defaultStateFs) {
|
|
5187
5211
|
const filePath = path18.join(homeDir, ".poe-code", "state", "templates.json");
|
|
5188
5212
|
async function readState() {
|
|
5189
5213
|
try {
|
|
5190
|
-
const raw = await
|
|
5214
|
+
const raw = await fs4.readFile(filePath, "utf8");
|
|
5191
5215
|
return normalizeTemplateState(JSON.parse(raw));
|
|
5192
5216
|
} catch (error2) {
|
|
5193
5217
|
if (isNotFoundError(error2)) {
|
|
@@ -5197,14 +5221,14 @@ function createTemplateRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5197
5221
|
}
|
|
5198
5222
|
}
|
|
5199
5223
|
async function writeState(state) {
|
|
5200
|
-
await
|
|
5224
|
+
await fs4.writeFile(filePath, `${JSON.stringify(state, null, 2)}
|
|
5201
5225
|
`, {
|
|
5202
5226
|
encoding: "utf8"
|
|
5203
5227
|
});
|
|
5204
5228
|
}
|
|
5205
5229
|
async function updateState(mutator) {
|
|
5206
|
-
await
|
|
5207
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5230
|
+
await fs4.mkdir(path18.dirname(filePath), { recursive: true });
|
|
5231
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5208
5232
|
try {
|
|
5209
5233
|
const state = await readState();
|
|
5210
5234
|
mutator(state);
|
|
@@ -5274,10 +5298,10 @@ function isRecord6(value) {
|
|
|
5274
5298
|
}
|
|
5275
5299
|
|
|
5276
5300
|
// packages/poe-code-config/src/state/index.ts
|
|
5277
|
-
function createStateManager(homeDir,
|
|
5301
|
+
function createStateManager(homeDir, fs4) {
|
|
5278
5302
|
return {
|
|
5279
|
-
templates: createTemplateRegistry(homeDir,
|
|
5280
|
-
jobs: createJobRegistry(homeDir,
|
|
5303
|
+
templates: createTemplateRegistry(homeDir, fs4),
|
|
5304
|
+
jobs: createJobRegistry(homeDir, fs4)
|
|
5281
5305
|
};
|
|
5282
5306
|
}
|
|
5283
5307
|
|
|
@@ -5592,7 +5616,7 @@ import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream"
|
|
|
5592
5616
|
import path21 from "node:path";
|
|
5593
5617
|
var JOB_DIR2 = "/tmp/poe-jobs";
|
|
5594
5618
|
function createE2bJobHandle(input) {
|
|
5595
|
-
const
|
|
5619
|
+
const fs4 = createE2bLogStreamFs(input.sandbox);
|
|
5596
5620
|
return {
|
|
5597
5621
|
id: input.jobId,
|
|
5598
5622
|
envId: input.envId,
|
|
@@ -5608,10 +5632,10 @@ function createE2bJobHandle(input) {
|
|
|
5608
5632
|
return isRunning ? "running" : "lost";
|
|
5609
5633
|
},
|
|
5610
5634
|
stream(opts = {}) {
|
|
5611
|
-
return streamLogFile({ fs:
|
|
5635
|
+
return streamLogFile({ fs: fs4 }, input.jobId, opts);
|
|
5612
5636
|
},
|
|
5613
5637
|
async wait() {
|
|
5614
|
-
const result = await waitForExit({ fs:
|
|
5638
|
+
const result = await waitForExit({ fs: fs4 }, input.jobId);
|
|
5615
5639
|
const preserveMs = input.preserveAfterExitHours * 60 * 60 * 1e3;
|
|
5616
5640
|
if (preserveMs > 0) {
|
|
5617
5641
|
await input.sandbox.setTimeout(preserveMs);
|
|
@@ -6108,10 +6132,10 @@ var e2bAuthScope = defineScope("e2b", {
|
|
|
6108
6132
|
});
|
|
6109
6133
|
async function resolveE2bApiKey(input) {
|
|
6110
6134
|
const homeDir = input.homeDir ?? os4.homedir();
|
|
6111
|
-
const
|
|
6135
|
+
const fs4 = input.fs ?? nodeFs4;
|
|
6112
6136
|
const env = input.env ?? process.env;
|
|
6113
6137
|
const document = await readMergedDocument(
|
|
6114
|
-
|
|
6138
|
+
fs4,
|
|
6115
6139
|
resolveConfigPath(homeDir),
|
|
6116
6140
|
resolveProjectConfigPath(input.cwd)
|
|
6117
6141
|
);
|
|
@@ -6618,6 +6642,23 @@ var gooseAcpSpawnConfig = {
|
|
|
6618
6642
|
skipAuth: true
|
|
6619
6643
|
};
|
|
6620
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
|
+
|
|
6621
6662
|
// packages/agent-spawn/src/configs/index.ts
|
|
6622
6663
|
var allSpawnConfigs = [
|
|
6623
6664
|
claudeCodeSpawnConfig,
|
|
@@ -6634,6 +6675,7 @@ var acpLookup = /* @__PURE__ */ new Map();
|
|
|
6634
6675
|
acpLookup.set(openCodeAcpSpawnConfig.agentId, openCodeAcpSpawnConfig);
|
|
6635
6676
|
acpLookup.set(kimiAcpSpawnConfig.agentId, kimiAcpSpawnConfig);
|
|
6636
6677
|
acpLookup.set(gooseAcpSpawnConfig.agentId, gooseAcpSpawnConfig);
|
|
6678
|
+
acpLookup.set(geminiCliAcpSpawnConfig.agentId, geminiCliAcpSpawnConfig);
|
|
6637
6679
|
function getSpawnConfig(input) {
|
|
6638
6680
|
const resolvedId = resolveAgentId(input);
|
|
6639
6681
|
if (!resolvedId) {
|
|
@@ -6653,8 +6695,8 @@ function listMcpSupportedAgents() {
|
|
|
6653
6695
|
}
|
|
6654
6696
|
|
|
6655
6697
|
// packages/agent-spawn/src/spawn.ts
|
|
6656
|
-
import { mkdirSync as
|
|
6657
|
-
import
|
|
6698
|
+
import { mkdirSync as mkdirSync5, openSync as openSync2, writeSync, closeSync as closeSync2 } from "node:fs";
|
|
6699
|
+
import path34 from "node:path";
|
|
6658
6700
|
|
|
6659
6701
|
// packages/agent-spawn/src/configs/resolve-config.ts
|
|
6660
6702
|
function resolveConfig(agentId) {
|
|
@@ -7055,7 +7097,7 @@ function createEventQueue() {
|
|
|
7055
7097
|
|
|
7056
7098
|
// packages/agent-spawn/src/skill-bridge.ts
|
|
7057
7099
|
import crypto from "node:crypto";
|
|
7058
|
-
import
|
|
7100
|
+
import os7 from "node:os";
|
|
7059
7101
|
|
|
7060
7102
|
// packages/agent-skill-config/src/configs.ts
|
|
7061
7103
|
import os5 from "node:os";
|
|
@@ -7069,6 +7111,10 @@ var agentSkillConfigs = {
|
|
|
7069
7111
|
globalSkillDir: "~/.codex/skills",
|
|
7070
7112
|
localSkillDir: ".codex/skills"
|
|
7071
7113
|
},
|
|
7114
|
+
"gemini-cli": {
|
|
7115
|
+
globalSkillDir: "~/.gemini/skills",
|
|
7116
|
+
localSkillDir: ".gemini/skills"
|
|
7117
|
+
},
|
|
7072
7118
|
opencode: {
|
|
7073
7119
|
globalSkillDir: "~/.config/opencode/skills",
|
|
7074
7120
|
localSkillDir: ".opencode/skills"
|
|
@@ -7211,7 +7257,7 @@ function resolveSkillReference(ref, cwd, homeDir) {
|
|
|
7211
7257
|
import { execFileSync } from "node:child_process";
|
|
7212
7258
|
import * as fs from "node:fs";
|
|
7213
7259
|
import path27 from "node:path";
|
|
7214
|
-
var
|
|
7260
|
+
var defaultMarkerPrefix = "poe-code-spawn-skills";
|
|
7215
7261
|
function defaultGitDirRunner(cwd) {
|
|
7216
7262
|
try {
|
|
7217
7263
|
return execFileSync("git", ["rev-parse", "--git-dir"], {
|
|
@@ -7231,10 +7277,10 @@ function resolveExcludePath(cwd) {
|
|
|
7231
7277
|
}
|
|
7232
7278
|
return path27.join(path27.isAbsolute(gitDir) ? gitDir : path27.resolve(cwd, gitDir), "info/exclude");
|
|
7233
7279
|
}
|
|
7234
|
-
function markers(runId) {
|
|
7280
|
+
function markers(runId, markerPrefix) {
|
|
7235
7281
|
return {
|
|
7236
|
-
begin:
|
|
7237
|
-
end:
|
|
7282
|
+
begin: `# ${markerPrefix}:${runId} begin`,
|
|
7283
|
+
end: `# ${markerPrefix}:${runId} end`
|
|
7238
7284
|
};
|
|
7239
7285
|
}
|
|
7240
7286
|
function readExcludeFile(excludePath) {
|
|
@@ -7250,8 +7296,8 @@ function readExcludeFile(excludePath) {
|
|
|
7250
7296
|
function isNodeError2(error2) {
|
|
7251
7297
|
return error2 instanceof Error && "code" in error2;
|
|
7252
7298
|
}
|
|
7253
|
-
function removeBlock(content, runId) {
|
|
7254
|
-
const { begin, end } = markers(runId);
|
|
7299
|
+
function removeBlock(content, runId, markerPrefix) {
|
|
7300
|
+
const { begin, end } = markers(runId, markerPrefix);
|
|
7255
7301
|
const lines = content.split("\n");
|
|
7256
7302
|
const result = [];
|
|
7257
7303
|
for (let index = 0; index < lines.length; index += 1) {
|
|
@@ -7266,23 +7312,27 @@ function removeBlock(content, runId) {
|
|
|
7266
7312
|
}
|
|
7267
7313
|
return result.join("\n");
|
|
7268
7314
|
}
|
|
7269
|
-
function appendBlock(content, runId, entries) {
|
|
7270
|
-
const { begin, end } = markers(runId);
|
|
7315
|
+
function appendBlock(content, runId, entries, markerPrefix) {
|
|
7316
|
+
const { begin, end } = markers(runId, markerPrefix);
|
|
7271
7317
|
const existing = content ?? "";
|
|
7272
7318
|
const prefix = existing.length === 0 || existing.endsWith("\n") ? existing : `${existing}
|
|
7273
7319
|
`;
|
|
7274
7320
|
return `${prefix}${[begin, ...entries, end, ""].join("\n")}`;
|
|
7275
7321
|
}
|
|
7276
|
-
function appendExcludeBlock(cwd, runId, entries) {
|
|
7322
|
+
function appendExcludeBlock(cwd, runId, entries, opts) {
|
|
7277
7323
|
const excludePath = resolveExcludePath(cwd);
|
|
7278
7324
|
if (excludePath === void 0) {
|
|
7279
7325
|
return;
|
|
7280
7326
|
}
|
|
7281
7327
|
fs.mkdirSync(path27.dirname(excludePath), { recursive: true });
|
|
7282
7328
|
const content = readExcludeFile(excludePath);
|
|
7283
|
-
fs.writeFileSync(
|
|
7329
|
+
fs.writeFileSync(
|
|
7330
|
+
excludePath,
|
|
7331
|
+
appendBlock(content, runId, entries, opts?.markerPrefix ?? defaultMarkerPrefix),
|
|
7332
|
+
"utf8"
|
|
7333
|
+
);
|
|
7284
7334
|
}
|
|
7285
|
-
function removeExcludeBlock(cwd, runId) {
|
|
7335
|
+
function removeExcludeBlock(cwd, runId, opts) {
|
|
7286
7336
|
const excludePath = resolveExcludePath(cwd);
|
|
7287
7337
|
if (excludePath === void 0) {
|
|
7288
7338
|
return;
|
|
@@ -7291,7 +7341,11 @@ function removeExcludeBlock(cwd, runId) {
|
|
|
7291
7341
|
if (content === void 0) {
|
|
7292
7342
|
return;
|
|
7293
7343
|
}
|
|
7294
|
-
fs.writeFileSync(
|
|
7344
|
+
fs.writeFileSync(
|
|
7345
|
+
excludePath,
|
|
7346
|
+
removeBlock(content, runId, opts?.markerPrefix ?? defaultMarkerPrefix),
|
|
7347
|
+
"utf8"
|
|
7348
|
+
);
|
|
7295
7349
|
}
|
|
7296
7350
|
|
|
7297
7351
|
// packages/agent-skill-config/src/bridge-active-skills.ts
|
|
@@ -7497,22 +7551,679 @@ function cleanupBridgedSkills(manifest) {
|
|
|
7497
7551
|
removeExcludeBlock(manifest.cwd, manifest.runId);
|
|
7498
7552
|
}
|
|
7499
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
|
+
|
|
7500
8186
|
// packages/agent-spawn/src/skill-bridge.ts
|
|
7501
|
-
function
|
|
7502
|
-
if (!skills || skills.length === 0) {
|
|
8187
|
+
function bridgeResourcesForRun(agentId, cwd, skills, hooks) {
|
|
8188
|
+
if ((!skills || skills.length === 0) && !hooks) {
|
|
7503
8189
|
return void 0;
|
|
7504
8190
|
}
|
|
7505
|
-
const
|
|
7506
|
-
|
|
7507
|
-
|
|
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;
|
|
7508
8214
|
}
|
|
7509
|
-
return
|
|
8215
|
+
return manifests;
|
|
7510
8216
|
}
|
|
7511
|
-
function
|
|
8217
|
+
function cleanupResourcesForRun(manifest) {
|
|
7512
8218
|
if (!manifest) {
|
|
7513
8219
|
return;
|
|
7514
8220
|
}
|
|
7515
|
-
|
|
8221
|
+
if (manifest.hooks) {
|
|
8222
|
+
cleanupBridgedHooks(manifest.hooks);
|
|
8223
|
+
}
|
|
8224
|
+
if (manifest.skills) {
|
|
8225
|
+
cleanupBridgedSkills(manifest.skills);
|
|
8226
|
+
}
|
|
7516
8227
|
}
|
|
7517
8228
|
|
|
7518
8229
|
// packages/agent-spawn/src/adapters/utils.ts
|
|
@@ -7638,21 +8349,21 @@ async function* adaptClaude(lines) {
|
|
|
7638
8349
|
if (blockType !== "tool_result") continue;
|
|
7639
8350
|
const kind = toolKindsById.get(item.tool_use_id);
|
|
7640
8351
|
toolKindsById.delete(item.tool_use_id);
|
|
7641
|
-
let
|
|
8352
|
+
let path37;
|
|
7642
8353
|
if (typeof item.content === "string") {
|
|
7643
|
-
|
|
8354
|
+
path37 = item.content;
|
|
7644
8355
|
} else {
|
|
7645
8356
|
try {
|
|
7646
|
-
|
|
8357
|
+
path37 = JSON.stringify(item.content);
|
|
7647
8358
|
} catch {
|
|
7648
|
-
|
|
8359
|
+
path37 = String(item.content);
|
|
7649
8360
|
}
|
|
7650
8361
|
}
|
|
7651
8362
|
yield {
|
|
7652
8363
|
event: "tool_complete",
|
|
7653
8364
|
id: item.tool_use_id,
|
|
7654
8365
|
kind,
|
|
7655
|
-
path:
|
|
8366
|
+
path: path37
|
|
7656
8367
|
};
|
|
7657
8368
|
}
|
|
7658
8369
|
}
|
|
@@ -7748,10 +8459,10 @@ async function* adaptCodex(lines) {
|
|
|
7748
8459
|
const kindFromStart = toolKindById.get(item.id);
|
|
7749
8460
|
const kind = kindFromStart ?? (itemType === "command_execution" ? "exec" : itemType === "file_edit" ? "edit" : "other");
|
|
7750
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;
|
|
7751
|
-
const
|
|
8462
|
+
const path37 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
|
|
7752
8463
|
toolTitleById.delete(item.id);
|
|
7753
8464
|
toolKindById.delete(item.id);
|
|
7754
|
-
yield { event: "tool_complete", id: item.id, kind, path:
|
|
8465
|
+
yield { event: "tool_complete", id: item.id, kind, path: path37 };
|
|
7755
8466
|
}
|
|
7756
8467
|
}
|
|
7757
8468
|
}
|
|
@@ -8279,7 +8990,7 @@ function spawnStreaming(options) {
|
|
|
8279
8990
|
};
|
|
8280
8991
|
}
|
|
8281
8992
|
};
|
|
8282
|
-
const manifest =
|
|
8993
|
+
const manifest = bridgeResourcesForRun(options.agentId, cwd, options.skills, options.hooks);
|
|
8283
8994
|
void (async () => {
|
|
8284
8995
|
try {
|
|
8285
8996
|
for await (const output of adapter(queue.lines())) {
|
|
@@ -8330,7 +9041,7 @@ function spawnStreaming(options) {
|
|
|
8330
9041
|
...ctx.logFile && !result.logFile ? { logFile: ctx.logFile } : {}
|
|
8331
9042
|
};
|
|
8332
9043
|
} finally {
|
|
8333
|
-
|
|
9044
|
+
cleanupResourcesForRun(manifest);
|
|
8334
9045
|
}
|
|
8335
9046
|
})();
|
|
8336
9047
|
return {
|
|
@@ -8472,7 +9183,7 @@ async function runSpawn(agentId, options, context) {
|
|
|
8472
9183
|
return { stdout: "", stderr: "", exitCode: 0 };
|
|
8473
9184
|
}
|
|
8474
9185
|
const cwd = options.cwd ?? process.cwd();
|
|
8475
|
-
const manifest =
|
|
9186
|
+
const manifest = bridgeResourcesForRun(agentId, cwd, options.skills, options.hooks);
|
|
8476
9187
|
let logFd;
|
|
8477
9188
|
try {
|
|
8478
9189
|
const logFilePath = resolveSpawnLogPath(options);
|
|
@@ -8540,7 +9251,7 @@ async function runSpawn(agentId, options, context) {
|
|
|
8540
9251
|
};
|
|
8541
9252
|
} finally {
|
|
8542
9253
|
closeSpawnLog(logFd);
|
|
8543
|
-
|
|
9254
|
+
cleanupResourcesForRun(manifest);
|
|
8544
9255
|
}
|
|
8545
9256
|
}
|
|
8546
9257
|
spawn4.retry = createSpawnRetry((service, options) => {
|
|
@@ -8562,12 +9273,12 @@ function resolveSpawnLogPath(options) {
|
|
|
8562
9273
|
if (!options.logDir || !options.logFileName) {
|
|
8563
9274
|
return void 0;
|
|
8564
9275
|
}
|
|
8565
|
-
return
|
|
9276
|
+
return path34.join(options.logDir, options.logFileName);
|
|
8566
9277
|
}
|
|
8567
9278
|
function openSpawnLog(filePath) {
|
|
8568
9279
|
try {
|
|
8569
|
-
|
|
8570
|
-
return
|
|
9280
|
+
mkdirSync5(path34.dirname(filePath), { recursive: true });
|
|
9281
|
+
return openSync2(filePath, "a");
|
|
8571
9282
|
} catch {
|
|
8572
9283
|
return void 0;
|
|
8573
9284
|
}
|
|
@@ -8582,7 +9293,7 @@ function appendSpawnLog(fd, chunk) {
|
|
|
8582
9293
|
function closeSpawnLog(fd) {
|
|
8583
9294
|
if (fd === void 0) return;
|
|
8584
9295
|
try {
|
|
8585
|
-
|
|
9296
|
+
closeSync2(fd);
|
|
8586
9297
|
} catch {
|
|
8587
9298
|
}
|
|
8588
9299
|
}
|
|
@@ -8591,7 +9302,7 @@ function closeSpawnLog(fd) {
|
|
|
8591
9302
|
var DEFAULT_ACTIVITY_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
8592
9303
|
|
|
8593
9304
|
// packages/agent-spawn/src/acp/replay.ts
|
|
8594
|
-
import
|
|
9305
|
+
import path35 from "node:path";
|
|
8595
9306
|
import { homedir as homedir2 } from "node:os";
|
|
8596
9307
|
import { open as open2, readdir as readdir2 } from "node:fs/promises";
|
|
8597
9308
|
import { createInterface } from "node:readline";
|
|
@@ -8610,7 +9321,7 @@ import { homedir } from "node:os";
|
|
|
8610
9321
|
import { join } from "node:path";
|
|
8611
9322
|
|
|
8612
9323
|
// packages/agent-spawn/src/acp/middlewares/spawn-log.ts
|
|
8613
|
-
import
|
|
9324
|
+
import path36 from "node:path";
|
|
8614
9325
|
import { homedir as homedir3 } from "node:os";
|
|
8615
9326
|
import { mkdir, open as open3 } from "node:fs/promises";
|
|
8616
9327
|
|
|
@@ -8624,9 +9335,30 @@ stderr:
|
|
|
8624
9335
|
${stderr}`;
|
|
8625
9336
|
}
|
|
8626
9337
|
function createSpawnHealthCheck(agentId, options) {
|
|
8627
|
-
const
|
|
8628
|
-
|
|
8629
|
-
|
|
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}`,
|
|
8630
9362
|
model: options.model,
|
|
8631
9363
|
mode: "yolo"
|
|
8632
9364
|
});
|
|
@@ -8641,6 +9373,13 @@ function createSpawnHealthCheck(agentId, options) {
|
|
|
8641
9373
|
return;
|
|
8642
9374
|
}
|
|
8643
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
|
+
}
|
|
8644
9383
|
if (result.exitCode !== 0) {
|
|
8645
9384
|
throw new Error(
|
|
8646
9385
|
`spawn ${agentId} failed with exit code ${result.exitCode}.
|
|
@@ -8778,6 +9517,7 @@ function createProvider(opts) {
|
|
|
8778
9517
|
configurePrompts: opts.configurePrompts,
|
|
8779
9518
|
postConfigureMessages: opts.postConfigureMessages,
|
|
8780
9519
|
extendConfigurePayload: opts.extendConfigurePayload,
|
|
9520
|
+
runtimeEnv: opts.runtimeEnv,
|
|
8781
9521
|
isolatedEnv: opts.isolatedEnv,
|
|
8782
9522
|
async configure(context, runOptions) {
|
|
8783
9523
|
await runMutations(opts.manifest.configure, {
|