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
|
|
|
@@ -804,17 +804,17 @@ function isPidRunning(pid) {
|
|
|
804
804
|
}
|
|
805
805
|
function createDefaultFs() {
|
|
806
806
|
return {
|
|
807
|
-
open: (
|
|
808
|
-
readFile: (
|
|
807
|
+
open: (path37, flags) => fsPromises.open(path37, flags),
|
|
808
|
+
readFile: (path37, encoding) => fsPromises.readFile(path37, encoding),
|
|
809
809
|
stat: fsPromises.stat,
|
|
810
810
|
unlink: fsPromises.unlink
|
|
811
811
|
};
|
|
812
812
|
}
|
|
813
|
-
async function removeLockFile(
|
|
813
|
+
async function removeLockFile(fs4, lockPath, signal) {
|
|
814
814
|
for (let attempt = 0; attempt <= 4; attempt += 1) {
|
|
815
815
|
throwIfAborted(signal);
|
|
816
816
|
try {
|
|
817
|
-
await
|
|
817
|
+
await fs4.unlink(lockPath);
|
|
818
818
|
return;
|
|
819
819
|
} catch (error2) {
|
|
820
820
|
if (hasErrorCode(error2, "ENOENT")) {
|
|
@@ -845,12 +845,12 @@ function parseLockMetadata(content) {
|
|
|
845
845
|
}
|
|
846
846
|
return void 0;
|
|
847
847
|
}
|
|
848
|
-
async function readLockMetadata(
|
|
849
|
-
if (!
|
|
848
|
+
async function readLockMetadata(fs4, lockPath) {
|
|
849
|
+
if (!fs4.readFile) {
|
|
850
850
|
return void 0;
|
|
851
851
|
}
|
|
852
852
|
try {
|
|
853
|
-
return parseLockMetadata(await
|
|
853
|
+
return parseLockMetadata(await fs4.readFile(lockPath, "utf8"));
|
|
854
854
|
} catch (error2) {
|
|
855
855
|
if (hasErrorCode(error2, "ENOENT")) {
|
|
856
856
|
return null;
|
|
@@ -884,7 +884,7 @@ async function writeLockMetadata(handle) {
|
|
|
884
884
|
}
|
|
885
885
|
}
|
|
886
886
|
async function acquireFileLock(filePath, options = {}) {
|
|
887
|
-
const
|
|
887
|
+
const fs4 = options.fs ?? createDefaultFs();
|
|
888
888
|
const retries = options.retries ?? 20;
|
|
889
889
|
const minTimeout = options.minTimeout ?? 25;
|
|
890
890
|
const maxTimeout = options.maxTimeout ?? 250;
|
|
@@ -895,7 +895,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
895
895
|
while (attempt <= retries) {
|
|
896
896
|
throwIfAborted(options.signal);
|
|
897
897
|
try {
|
|
898
|
-
const handle = await
|
|
898
|
+
const handle = await fs4.open(lockPath, "wx");
|
|
899
899
|
await writeLockMetadata(handle);
|
|
900
900
|
let released = false;
|
|
901
901
|
return async () => {
|
|
@@ -903,7 +903,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
903
903
|
return;
|
|
904
904
|
}
|
|
905
905
|
released = true;
|
|
906
|
-
await removeLockFile(
|
|
906
|
+
await removeLockFile(fs4, lockPath, options.signal);
|
|
907
907
|
};
|
|
908
908
|
} catch (error2) {
|
|
909
909
|
if (!hasErrorCode(error2, "EEXIST")) {
|
|
@@ -912,7 +912,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
912
912
|
}
|
|
913
913
|
let stat3;
|
|
914
914
|
try {
|
|
915
|
-
stat3 = await
|
|
915
|
+
stat3 = await fs4.stat(lockPath);
|
|
916
916
|
} catch (statError) {
|
|
917
917
|
if (hasErrorCode(statError, "ENOENT")) {
|
|
918
918
|
continue;
|
|
@@ -920,7 +920,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
920
920
|
throw statError;
|
|
921
921
|
}
|
|
922
922
|
const reclaimLock = await shouldReclaimLock({
|
|
923
|
-
fs:
|
|
923
|
+
fs: fs4,
|
|
924
924
|
isPidRunning: pidIsRunning,
|
|
925
925
|
lockPath,
|
|
926
926
|
staleMs,
|
|
@@ -930,7 +930,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
930
930
|
continue;
|
|
931
931
|
}
|
|
932
932
|
if (reclaimLock) {
|
|
933
|
-
await removeLockFile(
|
|
933
|
+
await removeLockFile(fs4, lockPath, options.signal);
|
|
934
934
|
continue;
|
|
935
935
|
}
|
|
936
936
|
if (attempt >= retries) {
|
|
@@ -1107,6 +1107,24 @@ var codexAgent = {
|
|
|
1107
1107
|
}
|
|
1108
1108
|
};
|
|
1109
1109
|
|
|
1110
|
+
// packages/agent-defs/src/agents/gemini-cli.ts
|
|
1111
|
+
var geminiCliAgent = {
|
|
1112
|
+
id: "gemini-cli",
|
|
1113
|
+
name: "gemini-cli",
|
|
1114
|
+
aliases: ["gemini"],
|
|
1115
|
+
label: "Gemini CLI",
|
|
1116
|
+
summary: "Configure Google's Gemini CLI to use a compatible Google generations API.",
|
|
1117
|
+
binaryName: "gemini",
|
|
1118
|
+
configPath: "~/.gemini/settings.json",
|
|
1119
|
+
apiShapes: ["google-generations"],
|
|
1120
|
+
branding: {
|
|
1121
|
+
colors: {
|
|
1122
|
+
dark: "#8AB4F8",
|
|
1123
|
+
light: "#1A73E8"
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
|
|
1110
1128
|
// packages/agent-defs/src/agents/opencode.ts
|
|
1111
1129
|
var openCodeAgent = {
|
|
1112
1130
|
id: "opencode",
|
|
@@ -1180,6 +1198,7 @@ var allAgents = [
|
|
|
1180
1198
|
claudeCodeAgent,
|
|
1181
1199
|
claudeDesktopAgent,
|
|
1182
1200
|
codexAgent,
|
|
1201
|
+
geminiCliAgent,
|
|
1183
1202
|
openCodeAgent,
|
|
1184
1203
|
kimiAgent,
|
|
1185
1204
|
gooseAgent,
|
|
@@ -1230,29 +1249,29 @@ function wrapForLogTee(argv, jobId) {
|
|
|
1230
1249
|
return ["sh", "-c", script];
|
|
1231
1250
|
}
|
|
1232
1251
|
async function* streamLogFile(env, jobId, opts) {
|
|
1233
|
-
const
|
|
1252
|
+
const fs4 = env.fs ?? nodeFs;
|
|
1234
1253
|
const file = jobLogPath(jobId);
|
|
1235
1254
|
let byteOffset = opts.sinceByte ?? 0;
|
|
1236
1255
|
while (true) {
|
|
1237
|
-
if (opts.since !== void 0 && !await wasModifiedSince(
|
|
1238
|
-
await waitForLogChange(
|
|
1256
|
+
if (opts.since !== void 0 && !await wasModifiedSince(fs4, file, opts.since)) {
|
|
1257
|
+
await waitForLogChange(fs4, file);
|
|
1239
1258
|
continue;
|
|
1240
1259
|
}
|
|
1241
|
-
const result = await readLogChunk(
|
|
1260
|
+
const result = await readLogChunk(fs4, file, byteOffset);
|
|
1242
1261
|
if (result !== null) {
|
|
1243
1262
|
byteOffset = result.nextByteOffset;
|
|
1244
1263
|
yield result.chunk;
|
|
1245
1264
|
continue;
|
|
1246
1265
|
}
|
|
1247
|
-
await waitForLogChange(
|
|
1266
|
+
await waitForLogChange(fs4, file);
|
|
1248
1267
|
}
|
|
1249
1268
|
}
|
|
1250
|
-
async function wasModifiedSince(
|
|
1251
|
-
if (
|
|
1269
|
+
async function wasModifiedSince(fs4, file, since) {
|
|
1270
|
+
if (fs4.promises.stat === void 0) {
|
|
1252
1271
|
return true;
|
|
1253
1272
|
}
|
|
1254
1273
|
try {
|
|
1255
|
-
const stat3 = await
|
|
1274
|
+
const stat3 = await fs4.promises.stat(file);
|
|
1256
1275
|
return stat3.mtimeMs >= since.getTime();
|
|
1257
1276
|
} catch (error2) {
|
|
1258
1277
|
if (isNodeError(error2) && error2.code === "ENOENT") {
|
|
@@ -1262,11 +1281,11 @@ async function wasModifiedSince(fs3, file, since) {
|
|
|
1262
1281
|
}
|
|
1263
1282
|
}
|
|
1264
1283
|
async function waitForExit(env, jobId, opts = {}) {
|
|
1265
|
-
const
|
|
1284
|
+
const fs4 = env.fs ?? nodeFs;
|
|
1266
1285
|
const file = jobExitPath(jobId);
|
|
1267
1286
|
while (true) {
|
|
1268
1287
|
throwIfAborted2(opts.signal);
|
|
1269
|
-
const contents = await readTextFileIfExists(
|
|
1288
|
+
const contents = await readTextFileIfExists(fs4, file);
|
|
1270
1289
|
if (contents !== null) {
|
|
1271
1290
|
const text5 = contents.trim();
|
|
1272
1291
|
const exitCode = Number(text5);
|
|
@@ -1284,8 +1303,8 @@ function jobLogPath(jobId) {
|
|
|
1284
1303
|
function jobExitPath(jobId) {
|
|
1285
1304
|
return `${JOB_DIR}/${jobId}.exit`;
|
|
1286
1305
|
}
|
|
1287
|
-
async function readLogChunk(
|
|
1288
|
-
const contents = await readFileIfExists(
|
|
1306
|
+
async function readLogChunk(fs4, file, byteOffset) {
|
|
1307
|
+
const contents = await readFileIfExists(fs4, file);
|
|
1289
1308
|
if (contents === null || byteOffset >= contents.byteLength) {
|
|
1290
1309
|
return null;
|
|
1291
1310
|
}
|
|
@@ -1297,13 +1316,13 @@ async function readLogChunk(fs3, file, byteOffset) {
|
|
|
1297
1316
|
nextByteOffset: contents.byteLength
|
|
1298
1317
|
};
|
|
1299
1318
|
}
|
|
1300
|
-
async function readTextFileIfExists(
|
|
1301
|
-
const contents = await readFileIfExists(
|
|
1319
|
+
async function readTextFileIfExists(fs4, file) {
|
|
1320
|
+
const contents = await readFileIfExists(fs4, file);
|
|
1302
1321
|
return contents?.toString("utf8") ?? null;
|
|
1303
1322
|
}
|
|
1304
|
-
async function readFileIfExists(
|
|
1323
|
+
async function readFileIfExists(fs4, file) {
|
|
1305
1324
|
try {
|
|
1306
|
-
const contents = await
|
|
1325
|
+
const contents = await fs4.promises.readFile(file);
|
|
1307
1326
|
return Buffer.isBuffer(contents) ? contents : Buffer.from(contents);
|
|
1308
1327
|
} catch (error2) {
|
|
1309
1328
|
if (isNodeError(error2) && error2.code === "ENOENT") {
|
|
@@ -1312,8 +1331,8 @@ async function readFileIfExists(fs3, file) {
|
|
|
1312
1331
|
throw error2;
|
|
1313
1332
|
}
|
|
1314
1333
|
}
|
|
1315
|
-
async function waitForLogChange(
|
|
1316
|
-
const watch =
|
|
1334
|
+
async function waitForLogChange(fs4, file) {
|
|
1335
|
+
const watch = fs4.watch;
|
|
1317
1336
|
if (typeof watch !== "function") {
|
|
1318
1337
|
await sleep2(POLL_INTERVAL_MS);
|
|
1319
1338
|
return;
|
|
@@ -2279,7 +2298,7 @@ import path14 from "node:path";
|
|
|
2279
2298
|
|
|
2280
2299
|
// packages/config-extends/src/discover.ts
|
|
2281
2300
|
import path10 from "node:path";
|
|
2282
|
-
async function findBase(name, bases,
|
|
2301
|
+
async function findBase(name, bases, fs4) {
|
|
2283
2302
|
const checkedPaths = [];
|
|
2284
2303
|
for (const basePath of bases) {
|
|
2285
2304
|
for (const extension of [".md", ".yaml", ".yml", ".json"]) {
|
|
@@ -2287,7 +2306,7 @@ async function findBase(name, bases, fs3) {
|
|
|
2287
2306
|
checkedPaths.push(filePath);
|
|
2288
2307
|
try {
|
|
2289
2308
|
return {
|
|
2290
|
-
content: await
|
|
2309
|
+
content: await fs4.readFile(filePath, "utf8"),
|
|
2291
2310
|
filePath
|
|
2292
2311
|
};
|
|
2293
2312
|
} catch (error2) {
|
|
@@ -2367,11 +2386,11 @@ function stripBom(content) {
|
|
|
2367
2386
|
function mergeLayers(layers) {
|
|
2368
2387
|
return mergeObjectLayers(layers, []);
|
|
2369
2388
|
}
|
|
2370
|
-
function mergeObjectLayers(layers,
|
|
2389
|
+
function mergeObjectLayers(layers, path37) {
|
|
2371
2390
|
const data = {};
|
|
2372
2391
|
const sources = {};
|
|
2373
2392
|
for (const key of collectKeys(layers)) {
|
|
2374
|
-
const resolved = resolveKey(layers, key,
|
|
2393
|
+
const resolved = resolveKey(layers, key, path37);
|
|
2375
2394
|
if (resolved === void 0) {
|
|
2376
2395
|
continue;
|
|
2377
2396
|
}
|
|
@@ -2389,7 +2408,7 @@ function collectKeys(layers) {
|
|
|
2389
2408
|
}
|
|
2390
2409
|
return [...keys];
|
|
2391
2410
|
}
|
|
2392
|
-
function resolveKey(layers, key,
|
|
2411
|
+
function resolveKey(layers, key, path37) {
|
|
2393
2412
|
let winningSource;
|
|
2394
2413
|
let winningValue;
|
|
2395
2414
|
const objectLayers = [];
|
|
@@ -2419,9 +2438,9 @@ function resolveKey(layers, key, path32) {
|
|
|
2419
2438
|
if (winningSource === void 0) {
|
|
2420
2439
|
return void 0;
|
|
2421
2440
|
}
|
|
2422
|
-
const fullPath = buildPath(
|
|
2441
|
+
const fullPath = buildPath(path37, key);
|
|
2423
2442
|
if (isPlainObject(winningValue)) {
|
|
2424
|
-
const merged = mergeObjectLayers(objectLayers, [...
|
|
2443
|
+
const merged = mergeObjectLayers(objectLayers, [...path37, key]);
|
|
2425
2444
|
return {
|
|
2426
2445
|
value: merged.data,
|
|
2427
2446
|
sources: {
|
|
@@ -2446,8 +2465,8 @@ function isWinningCandidate(key, value) {
|
|
|
2446
2465
|
}
|
|
2447
2466
|
return true;
|
|
2448
2467
|
}
|
|
2449
|
-
function buildPath(
|
|
2450
|
-
return [...
|
|
2468
|
+
function buildPath(path37, key) {
|
|
2469
|
+
return [...path37, key].join(".");
|
|
2451
2470
|
}
|
|
2452
2471
|
function isPlainObject(value) {
|
|
2453
2472
|
if (value === null || Array.isArray(value) || typeof value !== "object") {
|
|
@@ -3801,16 +3820,16 @@ function getConfigFormat(pathOrFormat) {
|
|
|
3801
3820
|
}
|
|
3802
3821
|
return formatRegistry[formatName];
|
|
3803
3822
|
}
|
|
3804
|
-
function detectFormat2(
|
|
3805
|
-
const ext = getExtension(
|
|
3823
|
+
function detectFormat2(path37) {
|
|
3824
|
+
const ext = getExtension(path37);
|
|
3806
3825
|
return extensionMap[ext];
|
|
3807
3826
|
}
|
|
3808
|
-
function getExtension(
|
|
3809
|
-
const lastDot =
|
|
3827
|
+
function getExtension(path37) {
|
|
3828
|
+
const lastDot = path37.lastIndexOf(".");
|
|
3810
3829
|
if (lastDot === -1) {
|
|
3811
3830
|
return "";
|
|
3812
3831
|
}
|
|
3813
|
-
return
|
|
3832
|
+
return path37.slice(lastDot).toLowerCase();
|
|
3814
3833
|
}
|
|
3815
3834
|
|
|
3816
3835
|
// packages/config-mutations/src/execution/path-utils.ts
|
|
@@ -3861,9 +3880,9 @@ function resolvePath(rawPath, homeDir, pathMapper) {
|
|
|
3861
3880
|
function isNotFound(error2) {
|
|
3862
3881
|
return typeof error2 === "object" && error2 !== null && "code" in error2 && error2.code === "ENOENT";
|
|
3863
3882
|
}
|
|
3864
|
-
async function readFileIfExists2(
|
|
3883
|
+
async function readFileIfExists2(fs4, target) {
|
|
3865
3884
|
try {
|
|
3866
|
-
return await
|
|
3885
|
+
return await fs4.readFile(target, "utf8");
|
|
3867
3886
|
} catch (error2) {
|
|
3868
3887
|
if (isNotFound(error2)) {
|
|
3869
3888
|
return null;
|
|
@@ -3871,9 +3890,9 @@ async function readFileIfExists2(fs3, target) {
|
|
|
3871
3890
|
throw error2;
|
|
3872
3891
|
}
|
|
3873
3892
|
}
|
|
3874
|
-
async function pathExists(
|
|
3893
|
+
async function pathExists(fs4, target) {
|
|
3875
3894
|
try {
|
|
3876
|
-
await
|
|
3895
|
+
await fs4.stat(target);
|
|
3877
3896
|
return true;
|
|
3878
3897
|
} catch (error2) {
|
|
3879
3898
|
if (isNotFound(error2)) {
|
|
@@ -3897,9 +3916,9 @@ function createInvalidDocumentBackupPath(targetPath) {
|
|
|
3897
3916
|
const ext = targetPath.includes(".") ? targetPath.split(".").pop() : "bak";
|
|
3898
3917
|
return `${targetPath}.invalid-${createTimestamp()}.${ext}`;
|
|
3899
3918
|
}
|
|
3900
|
-
async function backupInvalidDocument(
|
|
3919
|
+
async function backupInvalidDocument(fs4, targetPath, content) {
|
|
3901
3920
|
const backupPath = createInvalidDocumentBackupPath(targetPath);
|
|
3902
|
-
await
|
|
3921
|
+
await fs4.writeFile(backupPath, content, { encoding: "utf8" });
|
|
3903
3922
|
}
|
|
3904
3923
|
function describeMutation(kind, targetPath) {
|
|
3905
3924
|
const displayPath = targetPath ?? "target";
|
|
@@ -4457,12 +4476,12 @@ async function executeMutation(mutation, context, options) {
|
|
|
4457
4476
|
}
|
|
4458
4477
|
|
|
4459
4478
|
// packages/poe-code-config/src/store.ts
|
|
4460
|
-
async function readMergedDocument(
|
|
4461
|
-
const globalDocument = await readStoredDocument(
|
|
4479
|
+
async function readMergedDocument(fs4, globalPath, projectPath) {
|
|
4480
|
+
const globalDocument = await readStoredDocument(fs4, globalPath);
|
|
4462
4481
|
if (!projectPath || projectPath === globalPath) {
|
|
4463
4482
|
return globalDocument.data;
|
|
4464
4483
|
}
|
|
4465
|
-
const projectDocument = await readStoredDocument(
|
|
4484
|
+
const projectDocument = await readStoredDocument(fs4, projectPath);
|
|
4466
4485
|
const resolved = await resolve(
|
|
4467
4486
|
[
|
|
4468
4487
|
{
|
|
@@ -4476,16 +4495,16 @@ async function readMergedDocument(fs3, globalPath, projectPath) {
|
|
|
4476
4495
|
}
|
|
4477
4496
|
],
|
|
4478
4497
|
{
|
|
4479
|
-
fs: createResolvedConfigFs(
|
|
4498
|
+
fs: createResolvedConfigFs(fs4, globalPath, globalDocument.content),
|
|
4480
4499
|
autoExtend: true
|
|
4481
4500
|
}
|
|
4482
4501
|
);
|
|
4483
4502
|
return normalizeDocument(resolved.data);
|
|
4484
4503
|
}
|
|
4485
|
-
async function readStoredDocument(
|
|
4504
|
+
async function readStoredDocument(fs4, filePath) {
|
|
4486
4505
|
try {
|
|
4487
|
-
const raw = await
|
|
4488
|
-
return await parseStoredDocument(
|
|
4506
|
+
const raw = await fs4.readFile(filePath, "utf8");
|
|
4507
|
+
return await parseStoredDocument(fs4, filePath, raw);
|
|
4489
4508
|
} catch (error2) {
|
|
4490
4509
|
if (isNotFound(error2)) {
|
|
4491
4510
|
return {
|
|
@@ -4496,7 +4515,7 @@ async function readStoredDocument(fs3, filePath) {
|
|
|
4496
4515
|
throw error2;
|
|
4497
4516
|
}
|
|
4498
4517
|
}
|
|
4499
|
-
async function parseStoredDocument(
|
|
4518
|
+
async function parseStoredDocument(fs4, filePath, raw) {
|
|
4500
4519
|
try {
|
|
4501
4520
|
return {
|
|
4502
4521
|
content: raw,
|
|
@@ -4504,7 +4523,7 @@ async function parseStoredDocument(fs3, filePath, raw) {
|
|
|
4504
4523
|
};
|
|
4505
4524
|
} catch (error2) {
|
|
4506
4525
|
if (error2 instanceof SyntaxError) {
|
|
4507
|
-
await recoverInvalidDocument(
|
|
4526
|
+
await recoverInvalidDocument(fs4, filePath, raw);
|
|
4508
4527
|
return {
|
|
4509
4528
|
content: EMPTY_DOCUMENT,
|
|
4510
4529
|
data: {}
|
|
@@ -4538,21 +4557,21 @@ function normalizeScopeValues(value) {
|
|
|
4538
4557
|
}
|
|
4539
4558
|
return normalized;
|
|
4540
4559
|
}
|
|
4541
|
-
function createResolvedConfigFs(
|
|
4560
|
+
function createResolvedConfigFs(fs4, globalPath, globalContent) {
|
|
4542
4561
|
return {
|
|
4543
4562
|
readFile(filePath, _encoding) {
|
|
4544
4563
|
if (filePath === globalPath) {
|
|
4545
4564
|
return Promise.resolve(globalContent);
|
|
4546
4565
|
}
|
|
4547
|
-
return
|
|
4566
|
+
return fs4.readFile(filePath, "utf8");
|
|
4548
4567
|
}
|
|
4549
4568
|
};
|
|
4550
4569
|
}
|
|
4551
|
-
async function recoverInvalidDocument(
|
|
4552
|
-
await
|
|
4570
|
+
async function recoverInvalidDocument(fs4, filePath, content) {
|
|
4571
|
+
await fs4.mkdir(path14.dirname(filePath), { recursive: true });
|
|
4553
4572
|
const backupPath = createInvalidBackupPath(filePath);
|
|
4554
|
-
await
|
|
4555
|
-
await
|
|
4573
|
+
await fs4.writeFile(backupPath, content, { encoding: "utf8" });
|
|
4574
|
+
await fs4.writeFile(filePath, EMPTY_DOCUMENT, { encoding: "utf8" });
|
|
4556
4575
|
}
|
|
4557
4576
|
function createInvalidBackupPath(filePath) {
|
|
4558
4577
|
const directory = path14.dirname(filePath);
|
|
@@ -4676,7 +4695,7 @@ function mergeScope(scope, baseScope, overrideScope) {
|
|
|
4676
4695
|
...Object.fromEntries(scopeEntries)
|
|
4677
4696
|
};
|
|
4678
4697
|
}
|
|
4679
|
-
function mergeRuntimeScope(baseScope, overrideScope,
|
|
4698
|
+
function mergeRuntimeScope(baseScope, overrideScope, path37 = []) {
|
|
4680
4699
|
const merged = {};
|
|
4681
4700
|
const keys = /* @__PURE__ */ new Set([...Object.keys(baseScope), ...Object.keys(overrideScope)]);
|
|
4682
4701
|
for (const key of keys) {
|
|
@@ -4688,20 +4707,20 @@ function mergeRuntimeScope(baseScope, overrideScope, path32 = []) {
|
|
|
4688
4707
|
}
|
|
4689
4708
|
continue;
|
|
4690
4709
|
}
|
|
4691
|
-
if (isRuntimeConcatenativeArray([...
|
|
4710
|
+
if (isRuntimeConcatenativeArray([...path37, key]) && Array.isArray(baseValue) && Array.isArray(overrideValue)) {
|
|
4692
4711
|
merged[key] = [...baseValue, ...overrideValue];
|
|
4693
4712
|
continue;
|
|
4694
4713
|
}
|
|
4695
4714
|
if (isRecord4(baseValue) && isRecord4(overrideValue)) {
|
|
4696
|
-
merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...
|
|
4715
|
+
merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...path37, key]);
|
|
4697
4716
|
continue;
|
|
4698
4717
|
}
|
|
4699
4718
|
merged[key] = overrideValue;
|
|
4700
4719
|
}
|
|
4701
4720
|
return merged;
|
|
4702
4721
|
}
|
|
4703
|
-
function isRuntimeConcatenativeArray(
|
|
4704
|
-
return
|
|
4722
|
+
function isRuntimeConcatenativeArray(path37) {
|
|
4723
|
+
return path37.join(".") === "mounts" || path37.join(".") === "runner.workspace.exclude";
|
|
4705
4724
|
}
|
|
4706
4725
|
function isRecord4(value) {
|
|
4707
4726
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -4889,6 +4908,7 @@ var poeProvider = {
|
|
|
4889
4908
|
label: "Poe",
|
|
4890
4909
|
summary: "Route AI coding agents through Poe's API.",
|
|
4891
4910
|
baseUrl: "https://api.poe.com",
|
|
4911
|
+
agentBaseUrl: "https://api.poe.com",
|
|
4892
4912
|
auth: {
|
|
4893
4913
|
kind: "api-key",
|
|
4894
4914
|
envVar: "POE_API_KEY",
|
|
@@ -4896,6 +4916,12 @@ var poeProvider = {
|
|
|
4896
4916
|
prompt: { title: "Poe API key" },
|
|
4897
4917
|
preferredLogin: "oauth"
|
|
4898
4918
|
},
|
|
4919
|
+
env: {
|
|
4920
|
+
ANTHROPIC_CUSTOM_HEADERS: {
|
|
4921
|
+
kind: "providerCredential",
|
|
4922
|
+
prefix: "Authorization: Bearer "
|
|
4923
|
+
}
|
|
4924
|
+
},
|
|
4899
4925
|
apiShapes: [
|
|
4900
4926
|
{
|
|
4901
4927
|
id: "openai-chat-completions",
|
|
@@ -4924,6 +4950,9 @@ var anthropicProvider = {
|
|
|
4924
4950
|
storageKey: "provider:anthropic",
|
|
4925
4951
|
prompt: { title: "Anthropic API key" }
|
|
4926
4952
|
},
|
|
4953
|
+
env: {
|
|
4954
|
+
ANTHROPIC_API_KEY: { kind: "providerCredential" }
|
|
4955
|
+
},
|
|
4927
4956
|
apiShapes: [
|
|
4928
4957
|
{
|
|
4929
4958
|
id: "anthropic-messages",
|
|
@@ -4936,30 +4965,38 @@ var anthropicProvider = {
|
|
|
4936
4965
|
var cloudflareProvider = {
|
|
4937
4966
|
id: "cloudflare",
|
|
4938
4967
|
label: "Cloudflare AI Gateway",
|
|
4939
|
-
summary: "Route
|
|
4940
|
-
|
|
4968
|
+
summary: "Route coding agents through Cloudflare AI Gateway.",
|
|
4969
|
+
baseUrlEnvVar: "CF_AIG_BASE_URL",
|
|
4970
|
+
requiresBaseUrl: true,
|
|
4971
|
+
modelInput: { kind: "freeform" },
|
|
4941
4972
|
auth: {
|
|
4942
4973
|
kind: "api-key",
|
|
4943
|
-
envVar: "
|
|
4974
|
+
envVar: "CF_AIG_TOKEN",
|
|
4944
4975
|
storageKey: "provider:cloudflare",
|
|
4945
|
-
prompt: { title: "Cloudflare
|
|
4976
|
+
prompt: { title: "Cloudflare AI Gateway token" }
|
|
4977
|
+
},
|
|
4978
|
+
env: {
|
|
4979
|
+
ANTHROPIC_CUSTOM_HEADERS: {
|
|
4980
|
+
kind: "providerCredential",
|
|
4981
|
+
prefix: "Authorization: Bearer "
|
|
4982
|
+
}
|
|
4946
4983
|
},
|
|
4947
4984
|
apiShapes: [
|
|
4948
4985
|
{
|
|
4949
4986
|
id: "openai-chat-completions",
|
|
4950
|
-
|
|
4987
|
+
baseUrlPath: "compat"
|
|
4951
4988
|
},
|
|
4952
4989
|
{
|
|
4953
4990
|
id: "openai-responses",
|
|
4954
|
-
|
|
4991
|
+
baseUrlPath: "openai"
|
|
4955
4992
|
},
|
|
4956
4993
|
{
|
|
4957
4994
|
id: "anthropic-messages",
|
|
4958
|
-
|
|
4995
|
+
baseUrlPath: "anthropic"
|
|
4959
4996
|
},
|
|
4960
4997
|
{
|
|
4961
4998
|
id: "google-generations",
|
|
4962
|
-
|
|
4999
|
+
baseUrlPath: "google-ai-studio"
|
|
4963
5000
|
}
|
|
4964
5001
|
]
|
|
4965
5002
|
};
|
|
@@ -4988,7 +5025,7 @@ function isNotFoundError(error2) {
|
|
|
4988
5025
|
}
|
|
4989
5026
|
|
|
4990
5027
|
// packages/poe-code-config/src/state/jobs.ts
|
|
4991
|
-
function createJobRegistry(homeDir,
|
|
5028
|
+
function createJobRegistry(homeDir, fs4 = defaultStateFs) {
|
|
4992
5029
|
const jobsDir = path17.join(homeDir, ".poe-code", "state", "jobs");
|
|
4993
5030
|
function jobPath(id) {
|
|
4994
5031
|
assertSafeJobId(id);
|
|
@@ -4996,7 +5033,7 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
4996
5033
|
}
|
|
4997
5034
|
async function get(id) {
|
|
4998
5035
|
try {
|
|
4999
|
-
return parseJobEntry(await
|
|
5036
|
+
return parseJobEntry(await fs4.readFile(jobPath(id), "utf8"));
|
|
5000
5037
|
} catch (error2) {
|
|
5001
5038
|
if (isNotFoundError(error2)) {
|
|
5002
5039
|
return null;
|
|
@@ -5007,8 +5044,8 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5007
5044
|
async function put(entry) {
|
|
5008
5045
|
assertJobEntry(entry);
|
|
5009
5046
|
const filePath = jobPath(entry.id);
|
|
5010
|
-
await
|
|
5011
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5047
|
+
await fs4.mkdir(jobsDir, { recursive: true });
|
|
5048
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5012
5049
|
try {
|
|
5013
5050
|
await writeJobAtomically(filePath, entry);
|
|
5014
5051
|
} finally {
|
|
@@ -5017,8 +5054,8 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5017
5054
|
}
|
|
5018
5055
|
async function update(id, patch) {
|
|
5019
5056
|
const filePath = jobPath(id);
|
|
5020
|
-
await
|
|
5021
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5057
|
+
await fs4.mkdir(jobsDir, { recursive: true });
|
|
5058
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5022
5059
|
try {
|
|
5023
5060
|
const current = await get(id);
|
|
5024
5061
|
if (current === null) {
|
|
@@ -5039,7 +5076,7 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5039
5076
|
async function list(filter = {}) {
|
|
5040
5077
|
let entries;
|
|
5041
5078
|
try {
|
|
5042
|
-
entries = await
|
|
5079
|
+
entries = await fs4.readdir(jobsDir);
|
|
5043
5080
|
} catch (error2) {
|
|
5044
5081
|
if (isNotFoundError(error2)) {
|
|
5045
5082
|
return [];
|
|
@@ -5052,11 +5089,11 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5052
5089
|
continue;
|
|
5053
5090
|
}
|
|
5054
5091
|
const filePath = path17.join(jobsDir, entry);
|
|
5055
|
-
const stat3 = await
|
|
5092
|
+
const stat3 = await fs4.stat(filePath);
|
|
5056
5093
|
if (!stat3.isFile()) {
|
|
5057
5094
|
continue;
|
|
5058
5095
|
}
|
|
5059
|
-
const job = parseJobEntry(await
|
|
5096
|
+
const job = parseJobEntry(await fs4.readFile(filePath, "utf8"));
|
|
5060
5097
|
if (matchesFilter(job, filter)) {
|
|
5061
5098
|
jobs.push(job);
|
|
5062
5099
|
}
|
|
@@ -5066,16 +5103,16 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5066
5103
|
async function remove2(id) {
|
|
5067
5104
|
const filePath = jobPath(id);
|
|
5068
5105
|
try {
|
|
5069
|
-
await
|
|
5106
|
+
await fs4.stat(jobsDir);
|
|
5070
5107
|
} catch (error2) {
|
|
5071
5108
|
if (isNotFoundError(error2)) {
|
|
5072
5109
|
return;
|
|
5073
5110
|
}
|
|
5074
5111
|
throw error2;
|
|
5075
5112
|
}
|
|
5076
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5113
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5077
5114
|
try {
|
|
5078
|
-
await
|
|
5115
|
+
await fs4.unlink(filePath);
|
|
5079
5116
|
} catch (error2) {
|
|
5080
5117
|
if (!isNotFoundError(error2)) {
|
|
5081
5118
|
throw error2;
|
|
@@ -5085,14 +5122,14 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5085
5122
|
}
|
|
5086
5123
|
}
|
|
5087
5124
|
async function writeJobAtomically(filePath, entry) {
|
|
5088
|
-
await
|
|
5125
|
+
await fs4.mkdir(path17.dirname(filePath), { recursive: true });
|
|
5089
5126
|
const tempPath = `${filePath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
5090
5127
|
try {
|
|
5091
|
-
await
|
|
5128
|
+
await fs4.writeFile(tempPath, `${JSON.stringify(entry, null, 2)}
|
|
5092
5129
|
`, {
|
|
5093
5130
|
encoding: "utf8"
|
|
5094
5131
|
});
|
|
5095
|
-
await
|
|
5132
|
+
await fs4.rename(tempPath, filePath);
|
|
5096
5133
|
} catch (error2) {
|
|
5097
5134
|
await removeTempFile(tempPath);
|
|
5098
5135
|
throw error2;
|
|
@@ -5100,7 +5137,7 @@ function createJobRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5100
5137
|
}
|
|
5101
5138
|
async function removeTempFile(tempPath) {
|
|
5102
5139
|
try {
|
|
5103
|
-
await
|
|
5140
|
+
await fs4.unlink(tempPath);
|
|
5104
5141
|
} catch (error2) {
|
|
5105
5142
|
if (!isNotFoundError(error2)) {
|
|
5106
5143
|
throw error2;
|
|
@@ -5147,11 +5184,11 @@ function isRecord5(value) {
|
|
|
5147
5184
|
|
|
5148
5185
|
// packages/poe-code-config/src/state/templates.ts
|
|
5149
5186
|
import path18 from "node:path";
|
|
5150
|
-
function createTemplateRegistry(homeDir,
|
|
5187
|
+
function createTemplateRegistry(homeDir, fs4 = defaultStateFs) {
|
|
5151
5188
|
const filePath = path18.join(homeDir, ".poe-code", "state", "templates.json");
|
|
5152
5189
|
async function readState() {
|
|
5153
5190
|
try {
|
|
5154
|
-
const raw = await
|
|
5191
|
+
const raw = await fs4.readFile(filePath, "utf8");
|
|
5155
5192
|
return normalizeTemplateState(JSON.parse(raw));
|
|
5156
5193
|
} catch (error2) {
|
|
5157
5194
|
if (isNotFoundError(error2)) {
|
|
@@ -5161,14 +5198,14 @@ function createTemplateRegistry(homeDir, fs3 = defaultStateFs) {
|
|
|
5161
5198
|
}
|
|
5162
5199
|
}
|
|
5163
5200
|
async function writeState(state) {
|
|
5164
|
-
await
|
|
5201
|
+
await fs4.writeFile(filePath, `${JSON.stringify(state, null, 2)}
|
|
5165
5202
|
`, {
|
|
5166
5203
|
encoding: "utf8"
|
|
5167
5204
|
});
|
|
5168
5205
|
}
|
|
5169
5206
|
async function updateState(mutator) {
|
|
5170
|
-
await
|
|
5171
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
5207
|
+
await fs4.mkdir(path18.dirname(filePath), { recursive: true });
|
|
5208
|
+
const release = await acquireFileLock(filePath, { fs: fs4 });
|
|
5172
5209
|
try {
|
|
5173
5210
|
const state = await readState();
|
|
5174
5211
|
mutator(state);
|
|
@@ -5238,10 +5275,10 @@ function isRecord6(value) {
|
|
|
5238
5275
|
}
|
|
5239
5276
|
|
|
5240
5277
|
// packages/poe-code-config/src/state/index.ts
|
|
5241
|
-
function createStateManager(homeDir,
|
|
5278
|
+
function createStateManager(homeDir, fs4) {
|
|
5242
5279
|
return {
|
|
5243
|
-
templates: createTemplateRegistry(homeDir,
|
|
5244
|
-
jobs: createJobRegistry(homeDir,
|
|
5280
|
+
templates: createTemplateRegistry(homeDir, fs4),
|
|
5281
|
+
jobs: createJobRegistry(homeDir, fs4)
|
|
5245
5282
|
};
|
|
5246
5283
|
}
|
|
5247
5284
|
|
|
@@ -5556,7 +5593,7 @@ import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream"
|
|
|
5556
5593
|
import path21 from "node:path";
|
|
5557
5594
|
var JOB_DIR2 = "/tmp/poe-jobs";
|
|
5558
5595
|
function createE2bJobHandle(input) {
|
|
5559
|
-
const
|
|
5596
|
+
const fs4 = createE2bLogStreamFs(input.sandbox);
|
|
5560
5597
|
return {
|
|
5561
5598
|
id: input.jobId,
|
|
5562
5599
|
envId: input.envId,
|
|
@@ -5572,10 +5609,10 @@ function createE2bJobHandle(input) {
|
|
|
5572
5609
|
return isRunning ? "running" : "lost";
|
|
5573
5610
|
},
|
|
5574
5611
|
stream(opts = {}) {
|
|
5575
|
-
return streamLogFile({ fs:
|
|
5612
|
+
return streamLogFile({ fs: fs4 }, input.jobId, opts);
|
|
5576
5613
|
},
|
|
5577
5614
|
async wait() {
|
|
5578
|
-
const result = await waitForExit({ fs:
|
|
5615
|
+
const result = await waitForExit({ fs: fs4 }, input.jobId);
|
|
5579
5616
|
const preserveMs = input.preserveAfterExitHours * 60 * 60 * 1e3;
|
|
5580
5617
|
if (preserveMs > 0) {
|
|
5581
5618
|
await input.sandbox.setTimeout(preserveMs);
|
|
@@ -6072,10 +6109,10 @@ var e2bAuthScope = defineScope("e2b", {
|
|
|
6072
6109
|
});
|
|
6073
6110
|
async function resolveE2bApiKey(input) {
|
|
6074
6111
|
const homeDir = input.homeDir ?? os4.homedir();
|
|
6075
|
-
const
|
|
6112
|
+
const fs4 = input.fs ?? nodeFs4;
|
|
6076
6113
|
const env = input.env ?? process.env;
|
|
6077
6114
|
const document = await readMergedDocument(
|
|
6078
|
-
|
|
6115
|
+
fs4,
|
|
6079
6116
|
resolveConfigPath(homeDir),
|
|
6080
6117
|
resolveProjectConfigPath(input.cwd)
|
|
6081
6118
|
);
|
|
@@ -6582,6 +6619,23 @@ var gooseAcpSpawnConfig = {
|
|
|
6582
6619
|
skipAuth: true
|
|
6583
6620
|
};
|
|
6584
6621
|
|
|
6622
|
+
// packages/agent-spawn/src/configs/gemini-cli.ts
|
|
6623
|
+
var geminiCliAcpSpawnConfig = {
|
|
6624
|
+
kind: "acp",
|
|
6625
|
+
agentId: "gemini-cli",
|
|
6626
|
+
acpArgs: ({ model, mcpServers }) => [
|
|
6627
|
+
"--acp",
|
|
6628
|
+
...model ? ["--model", model] : [],
|
|
6629
|
+
...mcpServers ? ["--allowed-mcp-server-names", Object.keys(mcpServers).join(",")] : [],
|
|
6630
|
+
...mcpServers ? ["--skip-trust"] : [],
|
|
6631
|
+
"--yolo"
|
|
6632
|
+
],
|
|
6633
|
+
env: {
|
|
6634
|
+
GEMINI_SANDBOX: "false"
|
|
6635
|
+
},
|
|
6636
|
+
skipAuth: true
|
|
6637
|
+
};
|
|
6638
|
+
|
|
6585
6639
|
// packages/agent-spawn/src/configs/index.ts
|
|
6586
6640
|
var allSpawnConfigs = [
|
|
6587
6641
|
claudeCodeSpawnConfig,
|
|
@@ -6598,6 +6652,7 @@ var acpLookup = /* @__PURE__ */ new Map();
|
|
|
6598
6652
|
acpLookup.set(openCodeAcpSpawnConfig.agentId, openCodeAcpSpawnConfig);
|
|
6599
6653
|
acpLookup.set(kimiAcpSpawnConfig.agentId, kimiAcpSpawnConfig);
|
|
6600
6654
|
acpLookup.set(gooseAcpSpawnConfig.agentId, gooseAcpSpawnConfig);
|
|
6655
|
+
acpLookup.set(geminiCliAcpSpawnConfig.agentId, geminiCliAcpSpawnConfig);
|
|
6601
6656
|
function getSpawnConfig(input) {
|
|
6602
6657
|
const resolvedId = resolveAgentId(input);
|
|
6603
6658
|
if (!resolvedId) {
|
|
@@ -6617,8 +6672,8 @@ function listMcpSupportedAgents() {
|
|
|
6617
6672
|
}
|
|
6618
6673
|
|
|
6619
6674
|
// packages/agent-spawn/src/spawn.ts
|
|
6620
|
-
import { mkdirSync as
|
|
6621
|
-
import
|
|
6675
|
+
import { mkdirSync as mkdirSync5, openSync as openSync2, writeSync, closeSync as closeSync2 } from "node:fs";
|
|
6676
|
+
import path34 from "node:path";
|
|
6622
6677
|
|
|
6623
6678
|
// packages/agent-spawn/src/configs/resolve-config.ts
|
|
6624
6679
|
function resolveConfig(agentId) {
|
|
@@ -7019,7 +7074,7 @@ function createEventQueue() {
|
|
|
7019
7074
|
|
|
7020
7075
|
// packages/agent-spawn/src/skill-bridge.ts
|
|
7021
7076
|
import crypto from "node:crypto";
|
|
7022
|
-
import
|
|
7077
|
+
import os7 from "node:os";
|
|
7023
7078
|
|
|
7024
7079
|
// packages/agent-skill-config/src/configs.ts
|
|
7025
7080
|
import os5 from "node:os";
|
|
@@ -7033,6 +7088,10 @@ var agentSkillConfigs = {
|
|
|
7033
7088
|
globalSkillDir: "~/.codex/skills",
|
|
7034
7089
|
localSkillDir: ".codex/skills"
|
|
7035
7090
|
},
|
|
7091
|
+
"gemini-cli": {
|
|
7092
|
+
globalSkillDir: "~/.gemini/skills",
|
|
7093
|
+
localSkillDir: ".gemini/skills"
|
|
7094
|
+
},
|
|
7036
7095
|
opencode: {
|
|
7037
7096
|
globalSkillDir: "~/.config/opencode/skills",
|
|
7038
7097
|
localSkillDir: ".opencode/skills"
|
|
@@ -7175,7 +7234,7 @@ function resolveSkillReference(ref, cwd, homeDir) {
|
|
|
7175
7234
|
import { execFileSync } from "node:child_process";
|
|
7176
7235
|
import * as fs from "node:fs";
|
|
7177
7236
|
import path27 from "node:path";
|
|
7178
|
-
var
|
|
7237
|
+
var defaultMarkerPrefix = "poe-code-spawn-skills";
|
|
7179
7238
|
function defaultGitDirRunner(cwd) {
|
|
7180
7239
|
try {
|
|
7181
7240
|
return execFileSync("git", ["rev-parse", "--git-dir"], {
|
|
@@ -7195,10 +7254,10 @@ function resolveExcludePath(cwd) {
|
|
|
7195
7254
|
}
|
|
7196
7255
|
return path27.join(path27.isAbsolute(gitDir) ? gitDir : path27.resolve(cwd, gitDir), "info/exclude");
|
|
7197
7256
|
}
|
|
7198
|
-
function markers(runId) {
|
|
7257
|
+
function markers(runId, markerPrefix) {
|
|
7199
7258
|
return {
|
|
7200
|
-
begin:
|
|
7201
|
-
end:
|
|
7259
|
+
begin: `# ${markerPrefix}:${runId} begin`,
|
|
7260
|
+
end: `# ${markerPrefix}:${runId} end`
|
|
7202
7261
|
};
|
|
7203
7262
|
}
|
|
7204
7263
|
function readExcludeFile(excludePath) {
|
|
@@ -7214,8 +7273,8 @@ function readExcludeFile(excludePath) {
|
|
|
7214
7273
|
function isNodeError2(error2) {
|
|
7215
7274
|
return error2 instanceof Error && "code" in error2;
|
|
7216
7275
|
}
|
|
7217
|
-
function removeBlock(content, runId) {
|
|
7218
|
-
const { begin, end } = markers(runId);
|
|
7276
|
+
function removeBlock(content, runId, markerPrefix) {
|
|
7277
|
+
const { begin, end } = markers(runId, markerPrefix);
|
|
7219
7278
|
const lines = content.split("\n");
|
|
7220
7279
|
const result = [];
|
|
7221
7280
|
for (let index = 0; index < lines.length; index += 1) {
|
|
@@ -7230,23 +7289,27 @@ function removeBlock(content, runId) {
|
|
|
7230
7289
|
}
|
|
7231
7290
|
return result.join("\n");
|
|
7232
7291
|
}
|
|
7233
|
-
function appendBlock(content, runId, entries) {
|
|
7234
|
-
const { begin, end } = markers(runId);
|
|
7292
|
+
function appendBlock(content, runId, entries, markerPrefix) {
|
|
7293
|
+
const { begin, end } = markers(runId, markerPrefix);
|
|
7235
7294
|
const existing = content ?? "";
|
|
7236
7295
|
const prefix = existing.length === 0 || existing.endsWith("\n") ? existing : `${existing}
|
|
7237
7296
|
`;
|
|
7238
7297
|
return `${prefix}${[begin, ...entries, end, ""].join("\n")}`;
|
|
7239
7298
|
}
|
|
7240
|
-
function appendExcludeBlock(cwd, runId, entries) {
|
|
7299
|
+
function appendExcludeBlock(cwd, runId, entries, opts) {
|
|
7241
7300
|
const excludePath = resolveExcludePath(cwd);
|
|
7242
7301
|
if (excludePath === void 0) {
|
|
7243
7302
|
return;
|
|
7244
7303
|
}
|
|
7245
7304
|
fs.mkdirSync(path27.dirname(excludePath), { recursive: true });
|
|
7246
7305
|
const content = readExcludeFile(excludePath);
|
|
7247
|
-
fs.writeFileSync(
|
|
7306
|
+
fs.writeFileSync(
|
|
7307
|
+
excludePath,
|
|
7308
|
+
appendBlock(content, runId, entries, opts?.markerPrefix ?? defaultMarkerPrefix),
|
|
7309
|
+
"utf8"
|
|
7310
|
+
);
|
|
7248
7311
|
}
|
|
7249
|
-
function removeExcludeBlock(cwd, runId) {
|
|
7312
|
+
function removeExcludeBlock(cwd, runId, opts) {
|
|
7250
7313
|
const excludePath = resolveExcludePath(cwd);
|
|
7251
7314
|
if (excludePath === void 0) {
|
|
7252
7315
|
return;
|
|
@@ -7255,7 +7318,11 @@ function removeExcludeBlock(cwd, runId) {
|
|
|
7255
7318
|
if (content === void 0) {
|
|
7256
7319
|
return;
|
|
7257
7320
|
}
|
|
7258
|
-
fs.writeFileSync(
|
|
7321
|
+
fs.writeFileSync(
|
|
7322
|
+
excludePath,
|
|
7323
|
+
removeBlock(content, runId, opts?.markerPrefix ?? defaultMarkerPrefix),
|
|
7324
|
+
"utf8"
|
|
7325
|
+
);
|
|
7259
7326
|
}
|
|
7260
7327
|
|
|
7261
7328
|
// packages/agent-skill-config/src/bridge-active-skills.ts
|
|
@@ -7461,22 +7528,679 @@ function cleanupBridgedSkills(manifest) {
|
|
|
7461
7528
|
removeExcludeBlock(manifest.cwd, manifest.runId);
|
|
7462
7529
|
}
|
|
7463
7530
|
|
|
7531
|
+
// packages/agent-hook-config/src/configs.ts
|
|
7532
|
+
import os6 from "node:os";
|
|
7533
|
+
import path29 from "node:path";
|
|
7534
|
+
var agentHookConfigs = {
|
|
7535
|
+
"claude-code": {
|
|
7536
|
+
globalHookPath: "~/.claude/settings.json",
|
|
7537
|
+
localHookPath: ".claude/settings.json",
|
|
7538
|
+
format: "claude-settings-json",
|
|
7539
|
+
supportedEvents: [
|
|
7540
|
+
"SessionStart",
|
|
7541
|
+
"SessionEnd",
|
|
7542
|
+
"UserPromptSubmit",
|
|
7543
|
+
"PreToolUse",
|
|
7544
|
+
"PostToolUse",
|
|
7545
|
+
"PermissionRequest",
|
|
7546
|
+
"Stop",
|
|
7547
|
+
"StopFailure",
|
|
7548
|
+
"Notification",
|
|
7549
|
+
"PreCompact",
|
|
7550
|
+
"PostCompact",
|
|
7551
|
+
"SubagentStart",
|
|
7552
|
+
"SubagentStop"
|
|
7553
|
+
],
|
|
7554
|
+
supportedHandlerTypes: ["command", "http", "mcp_tool", "prompt", "agent"],
|
|
7555
|
+
placeholders: {
|
|
7556
|
+
projectDir: "${CLAUDE_PROJECT_DIR}",
|
|
7557
|
+
pluginRoot: "${CLAUDE_PLUGIN_ROOT}",
|
|
7558
|
+
pluginData: "${CLAUDE_PLUGIN_DATA}"
|
|
7559
|
+
}
|
|
7560
|
+
},
|
|
7561
|
+
codex: {
|
|
7562
|
+
globalHookPath: "~/.codex/hooks.json",
|
|
7563
|
+
localHookPath: ".codex/hooks.json",
|
|
7564
|
+
format: "codex-hooks-json",
|
|
7565
|
+
supportedEvents: [
|
|
7566
|
+
"SessionStart",
|
|
7567
|
+
"UserPromptSubmit",
|
|
7568
|
+
"PreToolUse",
|
|
7569
|
+
"PostToolUse",
|
|
7570
|
+
"PermissionRequest",
|
|
7571
|
+
"Stop"
|
|
7572
|
+
],
|
|
7573
|
+
supportedHandlerTypes: ["command"],
|
|
7574
|
+
placeholders: {
|
|
7575
|
+
projectDir: "$(git rev-parse --show-toplevel)",
|
|
7576
|
+
pluginRoot: "$PLUGIN_ROOT",
|
|
7577
|
+
pluginData: "$PLUGIN_DATA"
|
|
7578
|
+
}
|
|
7579
|
+
}
|
|
7580
|
+
};
|
|
7581
|
+
var supportedHookAgents = Object.keys(agentHookConfigs);
|
|
7582
|
+
function resolveAgentSupport2(input, registry = agentHookConfigs) {
|
|
7583
|
+
const resolvedId = resolveAgentId(input);
|
|
7584
|
+
if (!resolvedId) {
|
|
7585
|
+
return { status: "unknown", input };
|
|
7586
|
+
}
|
|
7587
|
+
const config = registry[resolvedId];
|
|
7588
|
+
if (!config) {
|
|
7589
|
+
return { status: "unsupported", input, id: resolvedId };
|
|
7590
|
+
}
|
|
7591
|
+
return { status: "supported", input, id: resolvedId, config };
|
|
7592
|
+
}
|
|
7593
|
+
function getAgentConfig2(agentId) {
|
|
7594
|
+
const support = resolveAgentSupport2(agentId);
|
|
7595
|
+
return support.status === "supported" ? support.config : void 0;
|
|
7596
|
+
}
|
|
7597
|
+
function expandHome3(targetPath, homeDir = os6.homedir()) {
|
|
7598
|
+
if (!targetPath?.startsWith("~")) {
|
|
7599
|
+
return targetPath;
|
|
7600
|
+
}
|
|
7601
|
+
if (targetPath === "~") {
|
|
7602
|
+
return homeDir;
|
|
7603
|
+
}
|
|
7604
|
+
if (targetPath.startsWith("~./")) {
|
|
7605
|
+
targetPath = `~/.${targetPath.slice(3)}`;
|
|
7606
|
+
}
|
|
7607
|
+
let remainder = targetPath.slice(1);
|
|
7608
|
+
if (remainder.startsWith("/") || remainder.startsWith("\\")) {
|
|
7609
|
+
remainder = remainder.slice(1);
|
|
7610
|
+
} else if (remainder.startsWith(".")) {
|
|
7611
|
+
remainder = remainder.slice(1);
|
|
7612
|
+
if (remainder.startsWith("/") || remainder.startsWith("\\")) {
|
|
7613
|
+
remainder = remainder.slice(1);
|
|
7614
|
+
}
|
|
7615
|
+
}
|
|
7616
|
+
return remainder.length === 0 ? homeDir : path29.join(homeDir, remainder);
|
|
7617
|
+
}
|
|
7618
|
+
function resolveHookPath(config, scope, cwd, homeDir) {
|
|
7619
|
+
if (scope === "global") {
|
|
7620
|
+
return path29.resolve(expandHome3(config.globalHookPath, homeDir));
|
|
7621
|
+
}
|
|
7622
|
+
return config.localHookPath ? path29.resolve(cwd, config.localHookPath) : void 0;
|
|
7623
|
+
}
|
|
7624
|
+
|
|
7625
|
+
// packages/agent-hook-config/src/read-hooks.ts
|
|
7626
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
7627
|
+
import path30 from "node:path";
|
|
7628
|
+
function readSettingsFile(filePath) {
|
|
7629
|
+
let content;
|
|
7630
|
+
try {
|
|
7631
|
+
content = readFileSync3(filePath, "utf8");
|
|
7632
|
+
} catch (error2) {
|
|
7633
|
+
if (error2.code === "ENOENT") {
|
|
7634
|
+
return void 0;
|
|
7635
|
+
}
|
|
7636
|
+
throw error2;
|
|
7637
|
+
}
|
|
7638
|
+
try {
|
|
7639
|
+
return JSON.parse(content);
|
|
7640
|
+
} catch (error2) {
|
|
7641
|
+
throw new Error(`Malformed JSON in ${filePath}`, { cause: error2 });
|
|
7642
|
+
}
|
|
7643
|
+
}
|
|
7644
|
+
function readClaudeHooks(cwd, homeDir, opts) {
|
|
7645
|
+
const projectPath = path30.resolve(cwd, ".claude/settings.json");
|
|
7646
|
+
const userPath = path30.resolve(homeDir, ".claude/settings.json");
|
|
7647
|
+
const scope = opts?.scope ?? "merged";
|
|
7648
|
+
const sourcePaths = scope === "project" ? [projectPath] : scope === "user" ? [userPath] : [userPath, projectPath];
|
|
7649
|
+
const result = { entries: [], readPaths: [] };
|
|
7650
|
+
for (const sourcePath of sourcePaths) {
|
|
7651
|
+
const settings = readSettingsFile(sourcePath);
|
|
7652
|
+
if (settings === void 0) {
|
|
7653
|
+
continue;
|
|
7654
|
+
}
|
|
7655
|
+
result.readPaths.push(sourcePath);
|
|
7656
|
+
for (const [event, groups] of Object.entries(settings.hooks ?? {})) {
|
|
7657
|
+
for (const group of groups) {
|
|
7658
|
+
for (const handler of group.hooks) {
|
|
7659
|
+
result.entries.push({ event, matcher: group.matcher, handler });
|
|
7660
|
+
}
|
|
7661
|
+
}
|
|
7662
|
+
}
|
|
7663
|
+
}
|
|
7664
|
+
return result;
|
|
7665
|
+
}
|
|
7666
|
+
|
|
7667
|
+
// packages/agent-hook-config/src/event-mapping.ts
|
|
7668
|
+
function requireAgentConfig(agentId) {
|
|
7669
|
+
const config = getAgentConfig2(agentId);
|
|
7670
|
+
if (!config) {
|
|
7671
|
+
throw new Error(`Unknown hook agent "${agentId}"`);
|
|
7672
|
+
}
|
|
7673
|
+
return config;
|
|
7674
|
+
}
|
|
7675
|
+
function getEventMappings(sourceAgentId, targetAgentId) {
|
|
7676
|
+
const source = requireAgentConfig(sourceAgentId);
|
|
7677
|
+
const target = requireAgentConfig(targetAgentId);
|
|
7678
|
+
return source.supportedEvents.map((sourceEvent) => {
|
|
7679
|
+
if (target.supportedEvents.includes(sourceEvent)) {
|
|
7680
|
+
return { sourceEvent, targetEvent: sourceEvent };
|
|
7681
|
+
}
|
|
7682
|
+
return {
|
|
7683
|
+
sourceEvent,
|
|
7684
|
+
targetEvent: null,
|
|
7685
|
+
dropReason: `${targetAgentId} has no ${sourceEvent} hook`
|
|
7686
|
+
};
|
|
7687
|
+
});
|
|
7688
|
+
}
|
|
7689
|
+
function getHandlerTypeRules(targetAgentId) {
|
|
7690
|
+
const target = requireAgentConfig(targetAgentId);
|
|
7691
|
+
const registeredTypes = supportedHookAgents.flatMap(
|
|
7692
|
+
(agentId) => requireAgentConfig(agentId).supportedHandlerTypes
|
|
7693
|
+
);
|
|
7694
|
+
const sourceTypes = [...new Set(registeredTypes)];
|
|
7695
|
+
const supportedTypes = target.supportedHandlerTypes.map((handlerType) => `"${handlerType}"`).join(", ");
|
|
7696
|
+
return sourceTypes.map((sourceType) => {
|
|
7697
|
+
if (target.supportedHandlerTypes.includes(sourceType)) {
|
|
7698
|
+
return { sourceType, allowed: true };
|
|
7699
|
+
}
|
|
7700
|
+
return {
|
|
7701
|
+
sourceType,
|
|
7702
|
+
allowed: false,
|
|
7703
|
+
dropReason: `${targetAgentId} only honors handlers of type ${supportedTypes}`
|
|
7704
|
+
};
|
|
7705
|
+
});
|
|
7706
|
+
}
|
|
7707
|
+
function getPlaceholderRewrites(sourceAgentId, targetAgentId) {
|
|
7708
|
+
const source = requireAgentConfig(sourceAgentId);
|
|
7709
|
+
const target = requireAgentConfig(targetAgentId);
|
|
7710
|
+
return Object.keys(source.placeholders).flatMap((key) => {
|
|
7711
|
+
const from = source.placeholders[key];
|
|
7712
|
+
const to = target.placeholders[key];
|
|
7713
|
+
if (!from || !to || from === to) {
|
|
7714
|
+
return [];
|
|
7715
|
+
}
|
|
7716
|
+
return [{ from, to }];
|
|
7717
|
+
});
|
|
7718
|
+
}
|
|
7719
|
+
|
|
7720
|
+
// packages/agent-hook-config/src/transform-hooks.ts
|
|
7721
|
+
function applyPlaceholderRewrites(value, rewrites) {
|
|
7722
|
+
return rewrites.reduce((rewrittenValue, rewrite) => {
|
|
7723
|
+
return rewrittenValue.replaceAll(rewrite.from, rewrite.to);
|
|
7724
|
+
}, value);
|
|
7725
|
+
}
|
|
7726
|
+
function transformHooks(source, sourceAgentId, targetAgentId, opts) {
|
|
7727
|
+
const eventMappings = getEventMappings(sourceAgentId, targetAgentId);
|
|
7728
|
+
const handlerRules = getHandlerTypeRules(targetAgentId);
|
|
7729
|
+
const placeholderRewrites = getPlaceholderRewrites(sourceAgentId, targetAgentId);
|
|
7730
|
+
const result = { entries: [], drops: [] };
|
|
7731
|
+
for (const sourceEntry of source) {
|
|
7732
|
+
const eventMapping = eventMappings.find((mapping) => mapping.sourceEvent === sourceEntry.event);
|
|
7733
|
+
if (!eventMapping || eventMapping.targetEvent === null) {
|
|
7734
|
+
result.drops.push({
|
|
7735
|
+
reason: "unsupported-event",
|
|
7736
|
+
detail: eventMapping?.dropReason ?? `${targetAgentId} has no ${sourceEntry.event} hook`,
|
|
7737
|
+
source: sourceEntry
|
|
7738
|
+
});
|
|
7739
|
+
continue;
|
|
7740
|
+
}
|
|
7741
|
+
const handlerRule = handlerRules.find((rule) => rule.sourceType === sourceEntry.handler.type);
|
|
7742
|
+
if (!handlerRule?.allowed) {
|
|
7743
|
+
result.drops.push({
|
|
7744
|
+
reason: "unsupported-handler-type",
|
|
7745
|
+
detail: `Unsupported handler type "${sourceEntry.handler.type}": ${handlerRule?.dropReason ?? `${targetAgentId} does not honor it`}`,
|
|
7746
|
+
source: sourceEntry
|
|
7747
|
+
});
|
|
7748
|
+
continue;
|
|
7749
|
+
}
|
|
7750
|
+
const handler = {
|
|
7751
|
+
type: "command",
|
|
7752
|
+
command: applyPlaceholderRewrites(sourceEntry.handler.command ?? "", placeholderRewrites),
|
|
7753
|
+
statusMessage: `[generated:${opts.runId}] ${sourceEntry.handler.statusMessage ?? ""}`
|
|
7754
|
+
};
|
|
7755
|
+
if (sourceEntry.handler.args !== void 0) {
|
|
7756
|
+
handler.args = sourceEntry.handler.args.map(
|
|
7757
|
+
(arg) => applyPlaceholderRewrites(arg, placeholderRewrites)
|
|
7758
|
+
);
|
|
7759
|
+
}
|
|
7760
|
+
if (sourceEntry.handler.timeout !== void 0) {
|
|
7761
|
+
handler.timeout = sourceEntry.handler.timeout;
|
|
7762
|
+
}
|
|
7763
|
+
result.entries.push({
|
|
7764
|
+
event: eventMapping.targetEvent,
|
|
7765
|
+
matcher: sourceEntry.matcher,
|
|
7766
|
+
handler,
|
|
7767
|
+
generatedId: `generated-${opts.runId}-${result.entries.length}`
|
|
7768
|
+
});
|
|
7769
|
+
}
|
|
7770
|
+
return result;
|
|
7771
|
+
}
|
|
7772
|
+
|
|
7773
|
+
// packages/agent-hook-config/src/write-hooks.ts
|
|
7774
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
7775
|
+
import path31 from "node:path";
|
|
7776
|
+
function isGeneratedHandler(handler) {
|
|
7777
|
+
return handler.statusMessage?.startsWith("[generated:") ?? false;
|
|
7778
|
+
}
|
|
7779
|
+
function parseHooksFile(targetPath) {
|
|
7780
|
+
let content;
|
|
7781
|
+
try {
|
|
7782
|
+
content = readFileSync4(targetPath, "utf8");
|
|
7783
|
+
} catch (error2) {
|
|
7784
|
+
if (error2.code === "ENOENT") {
|
|
7785
|
+
return { file: { hooks: {} }, fileCreated: true };
|
|
7786
|
+
}
|
|
7787
|
+
throw error2;
|
|
7788
|
+
}
|
|
7789
|
+
try {
|
|
7790
|
+
return { file: JSON.parse(content), fileCreated: false };
|
|
7791
|
+
} catch (error2) {
|
|
7792
|
+
throw new Error(`Malformed JSON in ${targetPath}`, { cause: error2 });
|
|
7793
|
+
}
|
|
7794
|
+
}
|
|
7795
|
+
function validateEntries(entries) {
|
|
7796
|
+
for (const entry of entries) {
|
|
7797
|
+
if (!isGeneratedHandler(entry.handler)) {
|
|
7798
|
+
throw new Error(
|
|
7799
|
+
`Generated hook entry "${entry.generatedId}" has statusMessage that must start with "[generated:"`
|
|
7800
|
+
);
|
|
7801
|
+
}
|
|
7802
|
+
}
|
|
7803
|
+
}
|
|
7804
|
+
function removeGeneratedHandlers(file) {
|
|
7805
|
+
let removed = 0;
|
|
7806
|
+
const hooks = file.hooks ?? (file.hooks = {});
|
|
7807
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
7808
|
+
hooks[event] = groups.filter((group) => {
|
|
7809
|
+
const initialCount = group.hooks.length;
|
|
7810
|
+
const remainingHandlers = group.hooks.filter((handler) => {
|
|
7811
|
+
if (isGeneratedHandler(handler)) {
|
|
7812
|
+
removed += 1;
|
|
7813
|
+
return false;
|
|
7814
|
+
}
|
|
7815
|
+
return true;
|
|
7816
|
+
});
|
|
7817
|
+
group.hooks = remainingHandlers;
|
|
7818
|
+
return group.hooks.length > 0 || group.hooks.length === initialCount;
|
|
7819
|
+
});
|
|
7820
|
+
}
|
|
7821
|
+
return removed;
|
|
7822
|
+
}
|
|
7823
|
+
function appendEntries(file, entries) {
|
|
7824
|
+
const hooks = file.hooks ?? (file.hooks = {});
|
|
7825
|
+
for (const entry of entries) {
|
|
7826
|
+
const groups = hooks[entry.event] ?? (hooks[entry.event] = []);
|
|
7827
|
+
let group = groups.find((candidate) => candidate.matcher === entry.matcher);
|
|
7828
|
+
if (!group) {
|
|
7829
|
+
group = entry.matcher === void 0 ? { hooks: [] } : { matcher: entry.matcher, hooks: [] };
|
|
7830
|
+
groups.push(group);
|
|
7831
|
+
}
|
|
7832
|
+
group.hooks.push(entry.handler);
|
|
7833
|
+
}
|
|
7834
|
+
}
|
|
7835
|
+
function writeCodexHooks(targetPath, entries, _runId) {
|
|
7836
|
+
const { file, fileCreated } = parseHooksFile(targetPath);
|
|
7837
|
+
validateEntries(entries);
|
|
7838
|
+
const previousGeneratedRemoved = removeGeneratedHandlers(file);
|
|
7839
|
+
appendEntries(file, entries);
|
|
7840
|
+
mkdirSync3(path31.dirname(targetPath), { recursive: true });
|
|
7841
|
+
const temporaryPath = `${targetPath}.tmp`;
|
|
7842
|
+
writeFileSync2(temporaryPath, `${JSON.stringify(file, null, 2)}
|
|
7843
|
+
`);
|
|
7844
|
+
renameSync(temporaryPath, targetPath);
|
|
7845
|
+
return {
|
|
7846
|
+
path: targetPath,
|
|
7847
|
+
fileCreated,
|
|
7848
|
+
previousGeneratedRemoved,
|
|
7849
|
+
generatedWritten: entries.length
|
|
7850
|
+
};
|
|
7851
|
+
}
|
|
7852
|
+
|
|
7853
|
+
// packages/agent-hook-config/src/symlink-hooks.ts
|
|
7854
|
+
import {
|
|
7855
|
+
closeSync,
|
|
7856
|
+
lstatSync,
|
|
7857
|
+
mkdirSync as mkdirSync4,
|
|
7858
|
+
openSync,
|
|
7859
|
+
readlinkSync,
|
|
7860
|
+
readSync,
|
|
7861
|
+
symlinkSync,
|
|
7862
|
+
unlinkSync
|
|
7863
|
+
} from "node:fs";
|
|
7864
|
+
import path32 from "node:path";
|
|
7865
|
+
function requireAgentConfig2(agentId) {
|
|
7866
|
+
const config = getAgentConfig2(agentId);
|
|
7867
|
+
if (!config) {
|
|
7868
|
+
throw new Error(`No hook configuration found for agent "${agentId}"`);
|
|
7869
|
+
}
|
|
7870
|
+
return config;
|
|
7871
|
+
}
|
|
7872
|
+
function resolveScopedPath(config, agentId, cwd, homeDir, scope) {
|
|
7873
|
+
const targetPath = resolveHookPath(
|
|
7874
|
+
config,
|
|
7875
|
+
scope === "project" ? "local" : "global",
|
|
7876
|
+
cwd,
|
|
7877
|
+
homeDir
|
|
7878
|
+
);
|
|
7879
|
+
if (!targetPath) {
|
|
7880
|
+
throw new Error(`Agent "${agentId}" has no ${scope} hook path`);
|
|
7881
|
+
}
|
|
7882
|
+
return targetPath;
|
|
7883
|
+
}
|
|
7884
|
+
function readFirstKilobyte(filePath) {
|
|
7885
|
+
const descriptor = openSync(filePath, "r");
|
|
7886
|
+
const buffer = Buffer.alloc(1024);
|
|
7887
|
+
try {
|
|
7888
|
+
const length = readSync(descriptor, buffer, 0, buffer.length, 0);
|
|
7889
|
+
return buffer.toString("utf8", 0, length);
|
|
7890
|
+
} finally {
|
|
7891
|
+
closeSync(descriptor);
|
|
7892
|
+
}
|
|
7893
|
+
}
|
|
7894
|
+
function isRecord7(value) {
|
|
7895
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7896
|
+
}
|
|
7897
|
+
function isFullyGeneratedFile(filePath) {
|
|
7898
|
+
let parsed;
|
|
7899
|
+
try {
|
|
7900
|
+
parsed = JSON.parse(readFirstKilobyte(filePath));
|
|
7901
|
+
} catch {
|
|
7902
|
+
return false;
|
|
7903
|
+
}
|
|
7904
|
+
if (!isRecord7(parsed)) {
|
|
7905
|
+
return false;
|
|
7906
|
+
}
|
|
7907
|
+
if (Object.keys(parsed).some((key) => key !== "hooks")) {
|
|
7908
|
+
return false;
|
|
7909
|
+
}
|
|
7910
|
+
const hooks = parsed.hooks;
|
|
7911
|
+
if (!isRecord7(hooks)) {
|
|
7912
|
+
return false;
|
|
7913
|
+
}
|
|
7914
|
+
let handlerFound = false;
|
|
7915
|
+
for (const groups of Object.values(hooks)) {
|
|
7916
|
+
if (!Array.isArray(groups)) {
|
|
7917
|
+
return false;
|
|
7918
|
+
}
|
|
7919
|
+
for (const group of groups) {
|
|
7920
|
+
if (!isRecord7(group) || !Array.isArray(group.hooks)) {
|
|
7921
|
+
return false;
|
|
7922
|
+
}
|
|
7923
|
+
for (const handler of group.hooks) {
|
|
7924
|
+
if (!isRecord7(handler)) {
|
|
7925
|
+
return false;
|
|
7926
|
+
}
|
|
7927
|
+
handlerFound = true;
|
|
7928
|
+
const statusMessage = handler.statusMessage;
|
|
7929
|
+
if (typeof statusMessage !== "string" || !statusMessage.startsWith("[generated:")) {
|
|
7930
|
+
return false;
|
|
7931
|
+
}
|
|
7932
|
+
}
|
|
7933
|
+
}
|
|
7934
|
+
}
|
|
7935
|
+
return handlerFound;
|
|
7936
|
+
}
|
|
7937
|
+
function symlinkHooks(sourceAgentId, targetAgentId, cwd, homeDir, scope) {
|
|
7938
|
+
const source = requireAgentConfig2(sourceAgentId);
|
|
7939
|
+
const target = requireAgentConfig2(targetAgentId);
|
|
7940
|
+
if (source.format !== target.format) {
|
|
7941
|
+
throw new Error(
|
|
7942
|
+
`Cannot symlink hook formats "${source.format}" and "${target.format}"; use transformation instead`
|
|
7943
|
+
);
|
|
7944
|
+
}
|
|
7945
|
+
const targetPath = resolveScopedPath(source, sourceAgentId, cwd, homeDir, scope);
|
|
7946
|
+
const symlinkPath = resolveScopedPath(target, targetAgentId, cwd, homeDir, scope);
|
|
7947
|
+
let replaced = "none";
|
|
7948
|
+
try {
|
|
7949
|
+
const existing = lstatSync(symlinkPath);
|
|
7950
|
+
if (existing.isSymbolicLink()) {
|
|
7951
|
+
if (readlinkSync(symlinkPath) === targetPath) {
|
|
7952
|
+
return { symlinkPath, targetPath, replaced };
|
|
7953
|
+
}
|
|
7954
|
+
unlinkSync(symlinkPath);
|
|
7955
|
+
replaced = "stale-symlink";
|
|
7956
|
+
} else if (existing.isFile() && isFullyGeneratedFile(symlinkPath)) {
|
|
7957
|
+
unlinkSync(symlinkPath);
|
|
7958
|
+
replaced = "generated-file";
|
|
7959
|
+
} else {
|
|
7960
|
+
throw new Error(`Refuse to replace user-authored hook file at ${symlinkPath}`);
|
|
7961
|
+
}
|
|
7962
|
+
} catch (error2) {
|
|
7963
|
+
if (error2.code !== "ENOENT") {
|
|
7964
|
+
throw error2;
|
|
7965
|
+
}
|
|
7966
|
+
}
|
|
7967
|
+
mkdirSync4(path32.dirname(symlinkPath), { recursive: true });
|
|
7968
|
+
symlinkSync(targetPath, symlinkPath);
|
|
7969
|
+
return { symlinkPath, targetPath, replaced };
|
|
7970
|
+
}
|
|
7971
|
+
|
|
7972
|
+
// packages/agent-hook-config/src/bridge-hooks.ts
|
|
7973
|
+
import * as fs3 from "node:fs";
|
|
7974
|
+
import path33 from "node:path";
|
|
7975
|
+
var hookExcludeMarkerPrefix = "poe-code-spawn-hooks";
|
|
7976
|
+
function isNodeError4(error2) {
|
|
7977
|
+
return error2 instanceof Error && "code" in error2;
|
|
7978
|
+
}
|
|
7979
|
+
function pathExists3(targetPath) {
|
|
7980
|
+
try {
|
|
7981
|
+
fs3.lstatSync(targetPath);
|
|
7982
|
+
return true;
|
|
7983
|
+
} catch (error2) {
|
|
7984
|
+
if (isNodeError4(error2) && error2.code === "ENOENT") {
|
|
7985
|
+
return false;
|
|
7986
|
+
}
|
|
7987
|
+
throw error2;
|
|
7988
|
+
}
|
|
7989
|
+
}
|
|
7990
|
+
function collectMissingParents2(targetPath) {
|
|
7991
|
+
const parents = [];
|
|
7992
|
+
let current = path33.dirname(targetPath);
|
|
7993
|
+
while (!pathExists3(current)) {
|
|
7994
|
+
parents.push(current);
|
|
7995
|
+
const parent = path33.dirname(current);
|
|
7996
|
+
if (parent === current) {
|
|
7997
|
+
break;
|
|
7998
|
+
}
|
|
7999
|
+
current = parent;
|
|
8000
|
+
}
|
|
8001
|
+
return parents.reverse();
|
|
8002
|
+
}
|
|
8003
|
+
function removeDirectoryIfEmpty2(targetPath) {
|
|
8004
|
+
try {
|
|
8005
|
+
fs3.rmdirSync(targetPath);
|
|
8006
|
+
} catch (error2) {
|
|
8007
|
+
if (isNodeError4(error2) && (error2.code === "ENOENT" || error2.code === "ENOTEMPTY" || error2.code === "EEXIST")) {
|
|
8008
|
+
return;
|
|
8009
|
+
}
|
|
8010
|
+
throw error2;
|
|
8011
|
+
}
|
|
8012
|
+
}
|
|
8013
|
+
function requireSupport(input, role) {
|
|
8014
|
+
const support = resolveAgentSupport2(input);
|
|
8015
|
+
if (support.status !== "supported" || !support.id || !support.config) {
|
|
8016
|
+
throw new Error(
|
|
8017
|
+
`Unsupported ${role} hook agent "${input}". Supported hook agents: ${supportedHookAgents.join(", ")}.`
|
|
8018
|
+
);
|
|
8019
|
+
}
|
|
8020
|
+
return { id: support.id, config: support.config };
|
|
8021
|
+
}
|
|
8022
|
+
function requireTargetPath(targetId, config, cwd, homeDir) {
|
|
8023
|
+
const targetPath = resolveHookPath(config, "local", cwd, homeDir);
|
|
8024
|
+
if (!targetPath) {
|
|
8025
|
+
throw new Error(`Agent "${targetId}" has no project hook path`);
|
|
8026
|
+
}
|
|
8027
|
+
return targetPath;
|
|
8028
|
+
}
|
|
8029
|
+
function readCodexFile(targetPath) {
|
|
8030
|
+
let content;
|
|
8031
|
+
try {
|
|
8032
|
+
content = fs3.readFileSync(targetPath, "utf8");
|
|
8033
|
+
} catch (error2) {
|
|
8034
|
+
if (isNodeError4(error2) && error2.code === "ENOENT") {
|
|
8035
|
+
return void 0;
|
|
8036
|
+
}
|
|
8037
|
+
throw error2;
|
|
8038
|
+
}
|
|
8039
|
+
try {
|
|
8040
|
+
return JSON.parse(content);
|
|
8041
|
+
} catch (error2) {
|
|
8042
|
+
throw new Error(`Malformed JSON in ${targetPath}`, { cause: error2 });
|
|
8043
|
+
}
|
|
8044
|
+
}
|
|
8045
|
+
function writeCodexFile(targetPath, file) {
|
|
8046
|
+
fs3.writeFileSync(targetPath, `${JSON.stringify(file, null, 2)}
|
|
8047
|
+
`, "utf8");
|
|
8048
|
+
}
|
|
8049
|
+
function hasOnlyEmptyHooks(file) {
|
|
8050
|
+
return Object.keys(file).every((key) => key === "hooks") && Object.values(file.hooks ?? {}).every((groups) => groups.length === 0);
|
|
8051
|
+
}
|
|
8052
|
+
function relativeToCwd(cwd, targetPath) {
|
|
8053
|
+
return path33.relative(cwd, targetPath);
|
|
8054
|
+
}
|
|
8055
|
+
function matcherKey(event, matcher) {
|
|
8056
|
+
return `${event}\0${matcher === void 0 ? "<undefined>" : matcher}`;
|
|
8057
|
+
}
|
|
8058
|
+
function bridgeHooks(sourceAgentId, targetAgentId, cwd, homeDir, runId, opts) {
|
|
8059
|
+
const source = requireSupport(sourceAgentId, "source");
|
|
8060
|
+
const target = requireSupport(targetAgentId, "target");
|
|
8061
|
+
const strategy = opts?.strategy ?? (source.config.format === target.config.format ? "symlink" : "transform");
|
|
8062
|
+
const manifest = {
|
|
8063
|
+
sourceAgentId,
|
|
8064
|
+
targetAgentId,
|
|
8065
|
+
cwd,
|
|
8066
|
+
runId,
|
|
8067
|
+
strategy,
|
|
8068
|
+
drops: []
|
|
8069
|
+
};
|
|
8070
|
+
if (strategy === "symlink") {
|
|
8071
|
+
const symlinkPath = requireTargetPath(target.id, target.config, cwd, homeDir);
|
|
8072
|
+
manifest.createdParents = collectMissingParents2(symlinkPath);
|
|
8073
|
+
const result = symlinkHooks(source.id, target.id, cwd, homeDir, "project");
|
|
8074
|
+
manifest.symlinkPath = result.symlinkPath;
|
|
8075
|
+
manifest.symlinkTarget = result.targetPath;
|
|
8076
|
+
manifest.symlinkReplaced = result.replaced;
|
|
8077
|
+
appendExcludeBlock(cwd, runId, [relativeToCwd(cwd, result.symlinkPath)], {
|
|
8078
|
+
markerPrefix: hookExcludeMarkerPrefix
|
|
8079
|
+
});
|
|
8080
|
+
return manifest;
|
|
8081
|
+
}
|
|
8082
|
+
if (source.id !== "claude-code") {
|
|
8083
|
+
throw new Error(`Transforming hooks from "${source.id}" is not supported yet`);
|
|
8084
|
+
}
|
|
8085
|
+
if (target.config.format !== "codex-hooks-json") {
|
|
8086
|
+
throw new Error(
|
|
8087
|
+
`Transforming hooks to "${target.id}" is not supported yet; only codex-hook targets can be written`
|
|
8088
|
+
);
|
|
8089
|
+
}
|
|
8090
|
+
const targetPath = requireTargetPath(target.id, target.config, cwd, homeDir);
|
|
8091
|
+
const priorFile = readCodexFile(targetPath);
|
|
8092
|
+
const sourceHooks = readClaudeHooks(cwd, homeDir, { scope: opts?.scope ?? "merged" });
|
|
8093
|
+
const transformed = transformHooks(sourceHooks.entries, source.id, target.id, { runId });
|
|
8094
|
+
const createdParents = collectMissingParents2(targetPath);
|
|
8095
|
+
const writeResult = writeCodexHooks(targetPath, transformed.entries, runId);
|
|
8096
|
+
manifest.writtenPath = targetPath;
|
|
8097
|
+
manifest.generatedEntryIds = transformed.entries.map((entry) => entry.generatedId);
|
|
8098
|
+
manifest.drops = transformed.drops;
|
|
8099
|
+
manifest.createdParents = createdParents;
|
|
8100
|
+
manifest.fileCreated = writeResult.fileCreated;
|
|
8101
|
+
manifest.preExistingEvents = Object.keys(priorFile?.hooks ?? {});
|
|
8102
|
+
manifest.preExistingMatchers = Object.entries(priorFile?.hooks ?? {}).flatMap(
|
|
8103
|
+
([event, groups]) => groups.map((group) => ({
|
|
8104
|
+
event,
|
|
8105
|
+
...group.matcher === void 0 ? {} : { matcher: group.matcher }
|
|
8106
|
+
}))
|
|
8107
|
+
);
|
|
8108
|
+
appendExcludeBlock(cwd, runId, [relativeToCwd(cwd, targetPath)], {
|
|
8109
|
+
markerPrefix: hookExcludeMarkerPrefix
|
|
8110
|
+
});
|
|
8111
|
+
return manifest;
|
|
8112
|
+
}
|
|
8113
|
+
function cleanupBridgedHooks(manifest) {
|
|
8114
|
+
if (manifest.strategy === "symlink" && manifest.symlinkPath && manifest.symlinkTarget) {
|
|
8115
|
+
try {
|
|
8116
|
+
if (fs3.lstatSync(manifest.symlinkPath).isSymbolicLink() && fs3.readlinkSync(manifest.symlinkPath) === manifest.symlinkTarget) {
|
|
8117
|
+
fs3.unlinkSync(manifest.symlinkPath);
|
|
8118
|
+
}
|
|
8119
|
+
} catch (error2) {
|
|
8120
|
+
if (!isNodeError4(error2) || error2.code !== "ENOENT") {
|
|
8121
|
+
throw error2;
|
|
8122
|
+
}
|
|
8123
|
+
}
|
|
8124
|
+
for (const parent of [...manifest.createdParents ?? []].reverse()) {
|
|
8125
|
+
removeDirectoryIfEmpty2(parent);
|
|
8126
|
+
}
|
|
8127
|
+
}
|
|
8128
|
+
if (manifest.strategy === "transform" && manifest.writtenPath) {
|
|
8129
|
+
const file = readCodexFile(manifest.writtenPath);
|
|
8130
|
+
if (file) {
|
|
8131
|
+
const generatedPrefix = `[generated:${manifest.runId}]`;
|
|
8132
|
+
const preExistingEvents = new Set(manifest.preExistingEvents ?? []);
|
|
8133
|
+
const preExistingMatchers = new Set(
|
|
8134
|
+
(manifest.preExistingMatchers ?? []).map((group) => matcherKey(group.event, group.matcher))
|
|
8135
|
+
);
|
|
8136
|
+
const hooks = file.hooks ?? {};
|
|
8137
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
8138
|
+
hooks[event] = groups.filter((group) => {
|
|
8139
|
+
const priorLength = group.hooks.length;
|
|
8140
|
+
group.hooks = group.hooks.filter(
|
|
8141
|
+
(handler) => !handler.statusMessage?.startsWith(generatedPrefix)
|
|
8142
|
+
);
|
|
8143
|
+
return group.hooks.length > 0 || group.hooks.length === priorLength || preExistingMatchers.has(matcherKey(event, group.matcher));
|
|
8144
|
+
});
|
|
8145
|
+
if (hooks[event].length === 0 && !preExistingEvents.has(event)) {
|
|
8146
|
+
delete hooks[event];
|
|
8147
|
+
}
|
|
8148
|
+
}
|
|
8149
|
+
file.hooks = hooks;
|
|
8150
|
+
if (manifest.fileCreated && hasOnlyEmptyHooks(file)) {
|
|
8151
|
+
fs3.unlinkSync(manifest.writtenPath);
|
|
8152
|
+
} else {
|
|
8153
|
+
writeCodexFile(manifest.writtenPath, file);
|
|
8154
|
+
}
|
|
8155
|
+
}
|
|
8156
|
+
for (const parent of [...manifest.createdParents ?? []].reverse()) {
|
|
8157
|
+
removeDirectoryIfEmpty2(parent);
|
|
8158
|
+
}
|
|
8159
|
+
}
|
|
8160
|
+
removeExcludeBlock(manifest.cwd, manifest.runId, { markerPrefix: hookExcludeMarkerPrefix });
|
|
8161
|
+
}
|
|
8162
|
+
|
|
7464
8163
|
// packages/agent-spawn/src/skill-bridge.ts
|
|
7465
|
-
function
|
|
7466
|
-
if (!skills || skills.length === 0) {
|
|
8164
|
+
function bridgeResourcesForRun(agentId, cwd, skills, hooks) {
|
|
8165
|
+
if ((!skills || skills.length === 0) && !hooks) {
|
|
7467
8166
|
return void 0;
|
|
7468
8167
|
}
|
|
7469
|
-
const
|
|
7470
|
-
|
|
7471
|
-
|
|
8168
|
+
const runId = crypto.randomUUID();
|
|
8169
|
+
const manifests = {};
|
|
8170
|
+
try {
|
|
8171
|
+
if (skills && skills.length > 0) {
|
|
8172
|
+
manifests.skills = bridgeActiveSkills(agentId, cwd, skills, os7.homedir(), runId);
|
|
8173
|
+
for (const warning2 of manifests.skills.warnings) {
|
|
8174
|
+
logger.warn(warning2.message);
|
|
8175
|
+
}
|
|
8176
|
+
}
|
|
8177
|
+
if (hooks) {
|
|
8178
|
+
manifests.hooks = bridgeHooks(hooks.from, agentId, cwd, os7.homedir(), runId, {
|
|
8179
|
+
strategy: hooks.strategy === "auto" ? void 0 : hooks.strategy,
|
|
8180
|
+
scope: hooks.scope
|
|
8181
|
+
});
|
|
8182
|
+
for (const drop of manifests.hooks.drops) {
|
|
8183
|
+
logger.warn(
|
|
8184
|
+
`Dropped bridged hook event "${drop.source.event}" with handler type "${drop.source.handler.type}": ${drop.detail}`
|
|
8185
|
+
);
|
|
8186
|
+
}
|
|
8187
|
+
}
|
|
8188
|
+
} catch (error2) {
|
|
8189
|
+
cleanupResourcesForRun(manifests);
|
|
8190
|
+
throw error2;
|
|
7472
8191
|
}
|
|
7473
|
-
return
|
|
8192
|
+
return manifests;
|
|
7474
8193
|
}
|
|
7475
|
-
function
|
|
8194
|
+
function cleanupResourcesForRun(manifest) {
|
|
7476
8195
|
if (!manifest) {
|
|
7477
8196
|
return;
|
|
7478
8197
|
}
|
|
7479
|
-
|
|
8198
|
+
if (manifest.hooks) {
|
|
8199
|
+
cleanupBridgedHooks(manifest.hooks);
|
|
8200
|
+
}
|
|
8201
|
+
if (manifest.skills) {
|
|
8202
|
+
cleanupBridgedSkills(manifest.skills);
|
|
8203
|
+
}
|
|
7480
8204
|
}
|
|
7481
8205
|
|
|
7482
8206
|
// packages/agent-spawn/src/adapters/utils.ts
|
|
@@ -7602,21 +8326,21 @@ async function* adaptClaude(lines) {
|
|
|
7602
8326
|
if (blockType !== "tool_result") continue;
|
|
7603
8327
|
const kind = toolKindsById.get(item.tool_use_id);
|
|
7604
8328
|
toolKindsById.delete(item.tool_use_id);
|
|
7605
|
-
let
|
|
8329
|
+
let path37;
|
|
7606
8330
|
if (typeof item.content === "string") {
|
|
7607
|
-
|
|
8331
|
+
path37 = item.content;
|
|
7608
8332
|
} else {
|
|
7609
8333
|
try {
|
|
7610
|
-
|
|
8334
|
+
path37 = JSON.stringify(item.content);
|
|
7611
8335
|
} catch {
|
|
7612
|
-
|
|
8336
|
+
path37 = String(item.content);
|
|
7613
8337
|
}
|
|
7614
8338
|
}
|
|
7615
8339
|
yield {
|
|
7616
8340
|
event: "tool_complete",
|
|
7617
8341
|
id: item.tool_use_id,
|
|
7618
8342
|
kind,
|
|
7619
|
-
path:
|
|
8343
|
+
path: path37
|
|
7620
8344
|
};
|
|
7621
8345
|
}
|
|
7622
8346
|
}
|
|
@@ -7712,10 +8436,10 @@ async function* adaptCodex(lines) {
|
|
|
7712
8436
|
const kindFromStart = toolKindById.get(item.id);
|
|
7713
8437
|
const kind = kindFromStart ?? (itemType === "command_execution" ? "exec" : itemType === "file_edit" ? "edit" : "other");
|
|
7714
8438
|
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;
|
|
7715
|
-
const
|
|
8439
|
+
const path37 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
|
|
7716
8440
|
toolTitleById.delete(item.id);
|
|
7717
8441
|
toolKindById.delete(item.id);
|
|
7718
|
-
yield { event: "tool_complete", id: item.id, kind, path:
|
|
8442
|
+
yield { event: "tool_complete", id: item.id, kind, path: path37 };
|
|
7719
8443
|
}
|
|
7720
8444
|
}
|
|
7721
8445
|
}
|
|
@@ -8243,7 +8967,7 @@ function spawnStreaming(options) {
|
|
|
8243
8967
|
};
|
|
8244
8968
|
}
|
|
8245
8969
|
};
|
|
8246
|
-
const manifest =
|
|
8970
|
+
const manifest = bridgeResourcesForRun(options.agentId, cwd, options.skills, options.hooks);
|
|
8247
8971
|
void (async () => {
|
|
8248
8972
|
try {
|
|
8249
8973
|
for await (const output of adapter(queue.lines())) {
|
|
@@ -8294,7 +9018,7 @@ function spawnStreaming(options) {
|
|
|
8294
9018
|
...ctx.logFile && !result.logFile ? { logFile: ctx.logFile } : {}
|
|
8295
9019
|
};
|
|
8296
9020
|
} finally {
|
|
8297
|
-
|
|
9021
|
+
cleanupResourcesForRun(manifest);
|
|
8298
9022
|
}
|
|
8299
9023
|
})();
|
|
8300
9024
|
return {
|
|
@@ -8436,7 +9160,7 @@ async function runSpawn(agentId, options, context) {
|
|
|
8436
9160
|
return { stdout: "", stderr: "", exitCode: 0 };
|
|
8437
9161
|
}
|
|
8438
9162
|
const cwd = options.cwd ?? process.cwd();
|
|
8439
|
-
const manifest =
|
|
9163
|
+
const manifest = bridgeResourcesForRun(agentId, cwd, options.skills, options.hooks);
|
|
8440
9164
|
let logFd;
|
|
8441
9165
|
try {
|
|
8442
9166
|
const logFilePath = resolveSpawnLogPath(options);
|
|
@@ -8504,7 +9228,7 @@ async function runSpawn(agentId, options, context) {
|
|
|
8504
9228
|
};
|
|
8505
9229
|
} finally {
|
|
8506
9230
|
closeSpawnLog(logFd);
|
|
8507
|
-
|
|
9231
|
+
cleanupResourcesForRun(manifest);
|
|
8508
9232
|
}
|
|
8509
9233
|
}
|
|
8510
9234
|
spawn4.retry = createSpawnRetry((service, options) => {
|
|
@@ -8526,12 +9250,12 @@ function resolveSpawnLogPath(options) {
|
|
|
8526
9250
|
if (!options.logDir || !options.logFileName) {
|
|
8527
9251
|
return void 0;
|
|
8528
9252
|
}
|
|
8529
|
-
return
|
|
9253
|
+
return path34.join(options.logDir, options.logFileName);
|
|
8530
9254
|
}
|
|
8531
9255
|
function openSpawnLog(filePath) {
|
|
8532
9256
|
try {
|
|
8533
|
-
|
|
8534
|
-
return
|
|
9257
|
+
mkdirSync5(path34.dirname(filePath), { recursive: true });
|
|
9258
|
+
return openSync2(filePath, "a");
|
|
8535
9259
|
} catch {
|
|
8536
9260
|
return void 0;
|
|
8537
9261
|
}
|
|
@@ -8546,7 +9270,7 @@ function appendSpawnLog(fd, chunk) {
|
|
|
8546
9270
|
function closeSpawnLog(fd) {
|
|
8547
9271
|
if (fd === void 0) return;
|
|
8548
9272
|
try {
|
|
8549
|
-
|
|
9273
|
+
closeSync2(fd);
|
|
8550
9274
|
} catch {
|
|
8551
9275
|
}
|
|
8552
9276
|
}
|
|
@@ -8555,7 +9279,7 @@ function closeSpawnLog(fd) {
|
|
|
8555
9279
|
var DEFAULT_ACTIVITY_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
8556
9280
|
|
|
8557
9281
|
// packages/agent-spawn/src/acp/replay.ts
|
|
8558
|
-
import
|
|
9282
|
+
import path35 from "node:path";
|
|
8559
9283
|
import { homedir as homedir2 } from "node:os";
|
|
8560
9284
|
import { open as open2, readdir as readdir2 } from "node:fs/promises";
|
|
8561
9285
|
import { createInterface } from "node:readline";
|
|
@@ -8574,7 +9298,7 @@ import { homedir } from "node:os";
|
|
|
8574
9298
|
import { join } from "node:path";
|
|
8575
9299
|
|
|
8576
9300
|
// packages/agent-spawn/src/acp/middlewares/spawn-log.ts
|
|
8577
|
-
import
|
|
9301
|
+
import path36 from "node:path";
|
|
8578
9302
|
import { homedir as homedir3 } from "node:os";
|
|
8579
9303
|
import { mkdir, open as open3 } from "node:fs/promises";
|
|
8580
9304
|
|
|
@@ -8588,9 +9312,30 @@ stderr:
|
|
|
8588
9312
|
${stderr}`;
|
|
8589
9313
|
}
|
|
8590
9314
|
function createSpawnHealthCheck(agentId, options) {
|
|
8591
|
-
const
|
|
8592
|
-
|
|
8593
|
-
|
|
9315
|
+
const {
|
|
9316
|
+
binaryName,
|
|
9317
|
+
args,
|
|
9318
|
+
env: modeEnv
|
|
9319
|
+
} = options.hooks ? {
|
|
9320
|
+
binaryName: "poe-code",
|
|
9321
|
+
args: [
|
|
9322
|
+
"spawn",
|
|
9323
|
+
"--hooks-from",
|
|
9324
|
+
options.hooks.from,
|
|
9325
|
+
...options.hooks.strategy ? ["--hooks-strategy", options.hooks.strategy] : [],
|
|
9326
|
+
...options.model ? ["--model", options.model] : [],
|
|
9327
|
+
"--mode",
|
|
9328
|
+
"yolo",
|
|
9329
|
+
agentId,
|
|
9330
|
+
`Output exactly: ${options.expectedOutput}`
|
|
9331
|
+
],
|
|
9332
|
+
env: void 0
|
|
9333
|
+
} : options.invocation ? {
|
|
9334
|
+
binaryName: options.invocation.command,
|
|
9335
|
+
args: options.invocation.args,
|
|
9336
|
+
env: options.invocation.env
|
|
9337
|
+
} : buildSpawnArgs(agentId, {
|
|
9338
|
+
prompt: `Output exactly: ${options.expectedOutput}`,
|
|
8594
9339
|
model: options.model,
|
|
8595
9340
|
mode: "yolo"
|
|
8596
9341
|
});
|
|
@@ -8605,6 +9350,13 @@ function createSpawnHealthCheck(agentId, options) {
|
|
|
8605
9350
|
return;
|
|
8606
9351
|
}
|
|
8607
9352
|
const result = modeEnv ? await context.runCommand(binaryName, args, { env: modeEnv }) : await context.runCommand(binaryName, args);
|
|
9353
|
+
if (options.hooks) {
|
|
9354
|
+
for (const line of result.stdout.split("\n")) {
|
|
9355
|
+
if (line.includes("Dropped bridged hook event")) {
|
|
9356
|
+
context.logWarning?.(line);
|
|
9357
|
+
}
|
|
9358
|
+
}
|
|
9359
|
+
}
|
|
8608
9360
|
if (result.exitCode !== 0) {
|
|
8609
9361
|
throw new Error(
|
|
8610
9362
|
`spawn ${agentId} failed with exit code ${result.exitCode}.
|
|
@@ -8648,19 +9400,6 @@ function stripModelNamespace2(model) {
|
|
|
8648
9400
|
const id = slashIndex === -1 ? model : model.slice(slashIndex + 1);
|
|
8649
9401
|
return id.toLowerCase();
|
|
8650
9402
|
}
|
|
8651
|
-
var CODEX_MODELS = [
|
|
8652
|
-
"openai/gpt-5.5",
|
|
8653
|
-
"openai/gpt-5.4",
|
|
8654
|
-
"openai/gpt-5.3-codex",
|
|
8655
|
-
"openai/gpt-5.2-codex",
|
|
8656
|
-
"openai/gpt-5.2",
|
|
8657
|
-
"openai/gpt-5.2-chat",
|
|
8658
|
-
"openai/gpt-5.2-pro",
|
|
8659
|
-
"openai/gpt-5.1",
|
|
8660
|
-
"openai/gpt-5.1-codex-mini",
|
|
8661
|
-
"anthropic/claude-opus-4.7"
|
|
8662
|
-
];
|
|
8663
|
-
var DEFAULT_CODEX_MODEL = CODEX_MODELS[0];
|
|
8664
9403
|
var KIMI_MODELS = [
|
|
8665
9404
|
"novitaai/kimi-k2.5",
|
|
8666
9405
|
"novitaai/kimi-k2-thinking",
|
|
@@ -8774,6 +9513,7 @@ function createProvider(opts) {
|
|
|
8774
9513
|
configurePrompts: opts.configurePrompts,
|
|
8775
9514
|
postConfigureMessages: opts.postConfigureMessages,
|
|
8776
9515
|
extendConfigurePayload: opts.extendConfigurePayload,
|
|
9516
|
+
runtimeEnv: opts.runtimeEnv,
|
|
8777
9517
|
isolatedEnv: opts.isolatedEnv,
|
|
8778
9518
|
async configure(context, runOptions) {
|
|
8779
9519
|
await runMutations(opts.manifest.configure, {
|
|
@@ -8863,18 +9603,17 @@ var claudeCodeService = createProvider({
|
|
|
8863
9603
|
postConfigureMessages: [
|
|
8864
9604
|
"If using VSCode - Open the Disable Login Prompt setting and check the box. vscode://settings/claudeCode.disableLoginPrompt"
|
|
8865
9605
|
],
|
|
9606
|
+
runtimeEnv: {
|
|
9607
|
+
ANTHROPIC_BASE_URL: { kind: "agentBaseUrl" }
|
|
9608
|
+
},
|
|
8866
9609
|
isolatedEnv: {
|
|
8867
9610
|
agentBinary: claudeCodeAgent.binaryName,
|
|
8868
|
-
env: {
|
|
8869
|
-
POE_CODE_API_KEY: { kind: "providerCredential" }
|
|
8870
|
-
},
|
|
9611
|
+
env: {},
|
|
8871
9612
|
requiresConfig: false,
|
|
8872
9613
|
cliSettings: {
|
|
8873
|
-
values: {
|
|
8874
|
-
apiKeyHelper: "echo $POE_CODE_API_KEY"
|
|
8875
|
-
},
|
|
9614
|
+
values: {},
|
|
8876
9615
|
env: {
|
|
8877
|
-
ANTHROPIC_BASE_URL: { kind: "
|
|
9616
|
+
ANTHROPIC_BASE_URL: { kind: "agentBaseUrl" }
|
|
8878
9617
|
}
|
|
8879
9618
|
}
|
|
8880
9619
|
},
|
|
@@ -8889,14 +9628,23 @@ var claudeCodeService = createProvider({
|
|
|
8889
9628
|
manifest: {
|
|
8890
9629
|
configure: [
|
|
8891
9630
|
fileMutation.ensureDirectory({ path: "~/.claude" }),
|
|
9631
|
+
configMutation.prune({
|
|
9632
|
+
target: "~/.claude/settings.json",
|
|
9633
|
+
shape: {
|
|
9634
|
+
apiKeyHelper: true,
|
|
9635
|
+
env: {
|
|
9636
|
+
ANTHROPIC_API_KEY: true
|
|
9637
|
+
}
|
|
9638
|
+
}
|
|
9639
|
+
}),
|
|
8892
9640
|
configMutation.merge({
|
|
8893
9641
|
target: "~/.claude/settings.json",
|
|
8894
9642
|
value: (ctx) => {
|
|
8895
9643
|
const options = ctx;
|
|
8896
9644
|
return {
|
|
8897
|
-
apiKeyHelper: `echo ${options.provider?.credential}`,
|
|
8898
9645
|
env: {
|
|
8899
|
-
|
|
9646
|
+
...options.provider?.extraEnv,
|
|
9647
|
+
ANTHROPIC_BASE_URL: options.provider?.agentBaseUrl ?? options.provider?.baseUrl
|
|
8900
9648
|
},
|
|
8901
9649
|
model: stripModelNamespace2(options.model ?? DEFAULT_CLAUDE_CODE_MODEL).replaceAll(".", "-")
|
|
8902
9650
|
};
|
|
@@ -8909,6 +9657,8 @@ var claudeCodeService = createProvider({
|
|
|
8909
9657
|
shape: {
|
|
8910
9658
|
apiKeyHelper: true,
|
|
8911
9659
|
env: {
|
|
9660
|
+
ANTHROPIC_API_KEY: true,
|
|
9661
|
+
ANTHROPIC_CUSTOM_HEADERS: true,
|
|
8912
9662
|
ANTHROPIC_BASE_URL: true,
|
|
8913
9663
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: true,
|
|
8914
9664
|
ANTHROPIC_DEFAULT_SONNET_MODEL: true,
|