poe-code 3.0.224 → 3.0.225
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/poe-gemini.js +23 -0
- package/dist/cli/commands/configure-payload.js +50 -3
- package/dist/cli/commands/configure-payload.js.map +1 -1
- package/dist/cli/commands/pipeline.js +4 -2
- package/dist/cli/commands/pipeline.js.map +1 -1
- package/dist/cli/commands/ralph.js +1 -0
- package/dist/cli/commands/ralph.js.map +1 -1
- package/dist/cli/commands/shared.d.ts +4 -0
- package/dist/cli/commands/shared.js +33 -2
- package/dist/cli/commands/shared.js.map +1 -1
- package/dist/cli/commands/spawn.js +20 -0
- package/dist/cli/commands/spawn.js.map +1 -1
- package/dist/cli/commands/test.d.ts +5 -1
- package/dist/cli/commands/test.js +58 -6
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/constants.d.ts +1 -0
- package/dist/cli/constants.js +2 -1
- package/dist/cli/constants.js.map +1 -1
- package/dist/cli/isolated-env.d.ts +2 -1
- package/dist/cli/isolated-env.js +20 -2
- package/dist/cli/isolated-env.js.map +1 -1
- package/dist/cli/options.d.ts +2 -5
- package/dist/cli/poe-code-command-runner.js +7 -2
- package/dist/cli/poe-code-command-runner.js.map +1 -1
- package/dist/cli/prompts.d.ts +21 -13
- package/dist/cli/prompts.js.map +1 -1
- package/dist/cli/service-registry.d.ts +12 -3
- package/dist/cli/service-registry.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +4694 -2378
- package/dist/index.js.map +4 -4
- package/dist/providers/claude-code.js +913 -152
- package/dist/providers/claude-code.js.map +4 -4
- package/dist/providers/codex.js +897 -149
- package/dist/providers/codex.js.map +4 -4
- package/dist/providers/create-provider.d.ts +1 -0
- package/dist/providers/create-provider.js +1 -0
- package/dist/providers/create-provider.js.map +1 -1
- package/dist/providers/gemini-cli.d.ts +16 -0
- package/dist/providers/gemini-cli.js +11349 -0
- package/dist/providers/gemini-cli.js.map +7 -0
- package/dist/providers/goose.js +870 -161
- package/dist/providers/goose.js.map +4 -4
- package/dist/providers/kimi.js +894 -143
- package/dist/providers/kimi.js.map +4 -4
- package/dist/providers/opencode.js +894 -143
- package/dist/providers/opencode.js.map +4 -4
- package/dist/providers/poe-agent.js +1144 -335
- package/dist/providers/poe-agent.js.map +4 -4
- package/dist/providers/spawn-options.d.ts +3 -0
- package/dist/sdk/pipeline.d.ts +1 -1
- package/dist/sdk/pipeline.js +22 -19
- package/dist/sdk/pipeline.js.map +1 -1
- package/dist/sdk/ralph.js +5 -0
- package/dist/sdk/ralph.js.map +1 -1
- package/dist/sdk/spawn-core.d.ts +3 -0
- package/dist/sdk/spawn-core.js +6 -8
- package/dist/sdk/spawn-core.js.map +1 -1
- package/dist/sdk/spawn.d.ts +8 -8
- package/dist/sdk/spawn.js +26 -3
- package/dist/sdk/spawn.js.map +1 -1
- package/dist/sdk/types.d.ts +7 -0
- package/dist/utils/command-checks.d.ts +8 -0
- package/dist/utils/command-checks.js +35 -9
- package/dist/utils/command-checks.js.map +1 -1
- package/dist/utils/dry-run.js +7 -1
- package/dist/utils/dry-run.js.map +1 -1
- package/dist/workflow-templates/github-issue-opened.caller.yml +2 -1
- package/dist/workflow-templates/github-issue-opened.ejected.yml +2 -1
- package/package.json +2 -1
- package/packages/agent-skill-config/dist/configs.js +4 -0
- package/packages/agent-skill-config/dist/git-exclude.d.ts +6 -2
- package/packages/agent-skill-config/dist/git-exclude.js +12 -12
- package/packages/memory/dist/index.js +914 -192
- package/packages/memory/dist/index.js.map +4 -4
- package/packages/superintendent/dist/index.d.ts +2 -1
- package/packages/superintendent/dist/runtime/loop.d.ts +1 -0
- package/packages/superintendent/dist/runtime/loop.js +14 -2
|
@@ -523,7 +523,7 @@ import path7 from "node:path";
|
|
|
523
523
|
|
|
524
524
|
// packages/config-extends/src/discover.ts
|
|
525
525
|
import path3 from "node:path";
|
|
526
|
-
async function findBase(name, bases,
|
|
526
|
+
async function findBase(name, bases, fs17) {
|
|
527
527
|
const checkedPaths = [];
|
|
528
528
|
for (const basePath of bases) {
|
|
529
529
|
for (const extension of [".md", ".yaml", ".yml", ".json"]) {
|
|
@@ -531,7 +531,7 @@ async function findBase(name, bases, fs16) {
|
|
|
531
531
|
checkedPaths.push(filePath);
|
|
532
532
|
try {
|
|
533
533
|
return {
|
|
534
|
-
content: await
|
|
534
|
+
content: await fs17.readFile(filePath, "utf8"),
|
|
535
535
|
filePath
|
|
536
536
|
};
|
|
537
537
|
} catch (error2) {
|
|
@@ -611,11 +611,11 @@ function stripBom(content) {
|
|
|
611
611
|
function mergeLayers(layers) {
|
|
612
612
|
return mergeObjectLayers(layers, []);
|
|
613
613
|
}
|
|
614
|
-
function mergeObjectLayers(layers,
|
|
614
|
+
function mergeObjectLayers(layers, path55) {
|
|
615
615
|
const data = {};
|
|
616
616
|
const sources = {};
|
|
617
617
|
for (const key of collectKeys(layers)) {
|
|
618
|
-
const resolved = resolveKey(layers, key,
|
|
618
|
+
const resolved = resolveKey(layers, key, path55);
|
|
619
619
|
if (resolved === void 0) {
|
|
620
620
|
continue;
|
|
621
621
|
}
|
|
@@ -633,7 +633,7 @@ function collectKeys(layers) {
|
|
|
633
633
|
}
|
|
634
634
|
return [...keys];
|
|
635
635
|
}
|
|
636
|
-
function resolveKey(layers, key,
|
|
636
|
+
function resolveKey(layers, key, path55) {
|
|
637
637
|
let winningSource;
|
|
638
638
|
let winningValue;
|
|
639
639
|
const objectLayers = [];
|
|
@@ -663,9 +663,9 @@ function resolveKey(layers, key, path50) {
|
|
|
663
663
|
if (winningSource === void 0) {
|
|
664
664
|
return void 0;
|
|
665
665
|
}
|
|
666
|
-
const fullPath = buildPath(
|
|
666
|
+
const fullPath = buildPath(path55, key);
|
|
667
667
|
if (isPlainObject(winningValue)) {
|
|
668
|
-
const merged = mergeObjectLayers(objectLayers, [...
|
|
668
|
+
const merged = mergeObjectLayers(objectLayers, [...path55, key]);
|
|
669
669
|
return {
|
|
670
670
|
value: merged.data,
|
|
671
671
|
sources: {
|
|
@@ -690,8 +690,8 @@ function isWinningCandidate(key, value) {
|
|
|
690
690
|
}
|
|
691
691
|
return true;
|
|
692
692
|
}
|
|
693
|
-
function buildPath(
|
|
694
|
-
return [...
|
|
693
|
+
function buildPath(path55, key) {
|
|
694
|
+
return [...path55, key].join(".");
|
|
695
695
|
}
|
|
696
696
|
function isPlainObject(value) {
|
|
697
697
|
if (value === null || Array.isArray(value) || typeof value !== "object") {
|
|
@@ -2079,16 +2079,16 @@ function getConfigFormat(pathOrFormat) {
|
|
|
2079
2079
|
}
|
|
2080
2080
|
return formatRegistry[formatName];
|
|
2081
2081
|
}
|
|
2082
|
-
function detectFormat2(
|
|
2083
|
-
const ext = getExtension(
|
|
2082
|
+
function detectFormat2(path55) {
|
|
2083
|
+
const ext = getExtension(path55);
|
|
2084
2084
|
return extensionMap[ext];
|
|
2085
2085
|
}
|
|
2086
|
-
function getExtension(
|
|
2087
|
-
const lastDot =
|
|
2086
|
+
function getExtension(path55) {
|
|
2087
|
+
const lastDot = path55.lastIndexOf(".");
|
|
2088
2088
|
if (lastDot === -1) {
|
|
2089
2089
|
return "";
|
|
2090
2090
|
}
|
|
2091
|
-
return
|
|
2091
|
+
return path55.slice(lastDot).toLowerCase();
|
|
2092
2092
|
}
|
|
2093
2093
|
|
|
2094
2094
|
// packages/config-mutations/src/execution/path-utils.ts
|
|
@@ -2139,9 +2139,9 @@ function resolvePath(rawPath, homeDir, pathMapper) {
|
|
|
2139
2139
|
function isNotFound(error2) {
|
|
2140
2140
|
return typeof error2 === "object" && error2 !== null && "code" in error2 && error2.code === "ENOENT";
|
|
2141
2141
|
}
|
|
2142
|
-
async function readFileIfExists(
|
|
2142
|
+
async function readFileIfExists(fs17, target) {
|
|
2143
2143
|
try {
|
|
2144
|
-
return await
|
|
2144
|
+
return await fs17.readFile(target, "utf8");
|
|
2145
2145
|
} catch (error2) {
|
|
2146
2146
|
if (isNotFound(error2)) {
|
|
2147
2147
|
return null;
|
|
@@ -2149,9 +2149,9 @@ async function readFileIfExists(fs16, target) {
|
|
|
2149
2149
|
throw error2;
|
|
2150
2150
|
}
|
|
2151
2151
|
}
|
|
2152
|
-
async function pathExists(
|
|
2152
|
+
async function pathExists(fs17, target) {
|
|
2153
2153
|
try {
|
|
2154
|
-
await
|
|
2154
|
+
await fs17.stat(target);
|
|
2155
2155
|
return true;
|
|
2156
2156
|
} catch (error2) {
|
|
2157
2157
|
if (isNotFound(error2)) {
|
|
@@ -2175,9 +2175,9 @@ function createInvalidDocumentBackupPath(targetPath) {
|
|
|
2175
2175
|
const ext = targetPath.includes(".") ? targetPath.split(".").pop() : "bak";
|
|
2176
2176
|
return `${targetPath}.invalid-${createTimestamp()}.${ext}`;
|
|
2177
2177
|
}
|
|
2178
|
-
async function backupInvalidDocument(
|
|
2178
|
+
async function backupInvalidDocument(fs17, targetPath, content) {
|
|
2179
2179
|
const backupPath = createInvalidDocumentBackupPath(targetPath);
|
|
2180
|
-
await
|
|
2180
|
+
await fs17.writeFile(backupPath, content, { encoding: "utf8" });
|
|
2181
2181
|
}
|
|
2182
2182
|
function describeMutation(kind, targetPath) {
|
|
2183
2183
|
const displayPath = targetPath ?? "target";
|
|
@@ -2735,12 +2735,12 @@ async function executeMutation(mutation, context, options) {
|
|
|
2735
2735
|
}
|
|
2736
2736
|
|
|
2737
2737
|
// packages/poe-code-config/src/store.ts
|
|
2738
|
-
async function readMergedDocument(
|
|
2739
|
-
const globalDocument = await readStoredDocument(
|
|
2738
|
+
async function readMergedDocument(fs17, globalPath, projectPath) {
|
|
2739
|
+
const globalDocument = await readStoredDocument(fs17, globalPath);
|
|
2740
2740
|
if (!projectPath || projectPath === globalPath) {
|
|
2741
2741
|
return globalDocument.data;
|
|
2742
2742
|
}
|
|
2743
|
-
const projectDocument = await readStoredDocument(
|
|
2743
|
+
const projectDocument = await readStoredDocument(fs17, projectPath);
|
|
2744
2744
|
const resolved = await resolve(
|
|
2745
2745
|
[
|
|
2746
2746
|
{
|
|
@@ -2754,16 +2754,16 @@ async function readMergedDocument(fs16, globalPath, projectPath) {
|
|
|
2754
2754
|
}
|
|
2755
2755
|
],
|
|
2756
2756
|
{
|
|
2757
|
-
fs: createResolvedConfigFs(
|
|
2757
|
+
fs: createResolvedConfigFs(fs17, globalPath, globalDocument.content),
|
|
2758
2758
|
autoExtend: true
|
|
2759
2759
|
}
|
|
2760
2760
|
);
|
|
2761
2761
|
return normalizeDocument(resolved.data);
|
|
2762
2762
|
}
|
|
2763
|
-
async function readStoredDocument(
|
|
2763
|
+
async function readStoredDocument(fs17, filePath) {
|
|
2764
2764
|
try {
|
|
2765
|
-
const raw = await
|
|
2766
|
-
return await parseStoredDocument(
|
|
2765
|
+
const raw = await fs17.readFile(filePath, "utf8");
|
|
2766
|
+
return await parseStoredDocument(fs17, filePath, raw);
|
|
2767
2767
|
} catch (error2) {
|
|
2768
2768
|
if (isNotFound(error2)) {
|
|
2769
2769
|
return {
|
|
@@ -2774,7 +2774,7 @@ async function readStoredDocument(fs16, filePath) {
|
|
|
2774
2774
|
throw error2;
|
|
2775
2775
|
}
|
|
2776
2776
|
}
|
|
2777
|
-
async function parseStoredDocument(
|
|
2777
|
+
async function parseStoredDocument(fs17, filePath, raw) {
|
|
2778
2778
|
try {
|
|
2779
2779
|
return {
|
|
2780
2780
|
content: raw,
|
|
@@ -2782,7 +2782,7 @@ async function parseStoredDocument(fs16, filePath, raw) {
|
|
|
2782
2782
|
};
|
|
2783
2783
|
} catch (error2) {
|
|
2784
2784
|
if (error2 instanceof SyntaxError) {
|
|
2785
|
-
await recoverInvalidDocument(
|
|
2785
|
+
await recoverInvalidDocument(fs17, filePath, raw);
|
|
2786
2786
|
return {
|
|
2787
2787
|
content: EMPTY_DOCUMENT,
|
|
2788
2788
|
data: {}
|
|
@@ -2816,21 +2816,21 @@ function normalizeScopeValues(value) {
|
|
|
2816
2816
|
}
|
|
2817
2817
|
return normalized;
|
|
2818
2818
|
}
|
|
2819
|
-
function createResolvedConfigFs(
|
|
2819
|
+
function createResolvedConfigFs(fs17, globalPath, globalContent) {
|
|
2820
2820
|
return {
|
|
2821
2821
|
readFile(filePath, _encoding) {
|
|
2822
2822
|
if (filePath === globalPath) {
|
|
2823
2823
|
return Promise.resolve(globalContent);
|
|
2824
2824
|
}
|
|
2825
|
-
return
|
|
2825
|
+
return fs17.readFile(filePath, "utf8");
|
|
2826
2826
|
}
|
|
2827
2827
|
};
|
|
2828
2828
|
}
|
|
2829
|
-
async function recoverInvalidDocument(
|
|
2830
|
-
await
|
|
2829
|
+
async function recoverInvalidDocument(fs17, filePath, content) {
|
|
2830
|
+
await fs17.mkdir(path7.dirname(filePath), { recursive: true });
|
|
2831
2831
|
const backupPath = createInvalidBackupPath(filePath);
|
|
2832
|
-
await
|
|
2833
|
-
await
|
|
2832
|
+
await fs17.writeFile(backupPath, content, { encoding: "utf8" });
|
|
2833
|
+
await fs17.writeFile(filePath, EMPTY_DOCUMENT, { encoding: "utf8" });
|
|
2834
2834
|
}
|
|
2835
2835
|
function createInvalidBackupPath(filePath) {
|
|
2836
2836
|
const directory = path7.dirname(filePath);
|
|
@@ -2954,7 +2954,7 @@ function mergeScope(scope, baseScope, overrideScope) {
|
|
|
2954
2954
|
...Object.fromEntries(scopeEntries)
|
|
2955
2955
|
};
|
|
2956
2956
|
}
|
|
2957
|
-
function mergeRuntimeScope(baseScope, overrideScope,
|
|
2957
|
+
function mergeRuntimeScope(baseScope, overrideScope, path55 = []) {
|
|
2958
2958
|
const merged = {};
|
|
2959
2959
|
const keys = /* @__PURE__ */ new Set([...Object.keys(baseScope), ...Object.keys(overrideScope)]);
|
|
2960
2960
|
for (const key of keys) {
|
|
@@ -2966,20 +2966,20 @@ function mergeRuntimeScope(baseScope, overrideScope, path50 = []) {
|
|
|
2966
2966
|
}
|
|
2967
2967
|
continue;
|
|
2968
2968
|
}
|
|
2969
|
-
if (isRuntimeConcatenativeArray([...
|
|
2969
|
+
if (isRuntimeConcatenativeArray([...path55, key]) && Array.isArray(baseValue) && Array.isArray(overrideValue)) {
|
|
2970
2970
|
merged[key] = [...baseValue, ...overrideValue];
|
|
2971
2971
|
continue;
|
|
2972
2972
|
}
|
|
2973
2973
|
if (isRecord3(baseValue) && isRecord3(overrideValue)) {
|
|
2974
|
-
merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...
|
|
2974
|
+
merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...path55, key]);
|
|
2975
2975
|
continue;
|
|
2976
2976
|
}
|
|
2977
2977
|
merged[key] = overrideValue;
|
|
2978
2978
|
}
|
|
2979
2979
|
return merged;
|
|
2980
2980
|
}
|
|
2981
|
-
function isRuntimeConcatenativeArray(
|
|
2982
|
-
return
|
|
2981
|
+
function isRuntimeConcatenativeArray(path55) {
|
|
2982
|
+
return path55.join(".") === "mounts" || path55.join(".") === "runner.workspace.exclude";
|
|
2983
2983
|
}
|
|
2984
2984
|
function isRecord3(value) {
|
|
2985
2985
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -3088,6 +3088,24 @@ var codexAgent = {
|
|
|
3088
3088
|
}
|
|
3089
3089
|
};
|
|
3090
3090
|
|
|
3091
|
+
// packages/agent-defs/src/agents/gemini-cli.ts
|
|
3092
|
+
var geminiCliAgent = {
|
|
3093
|
+
id: "gemini-cli",
|
|
3094
|
+
name: "gemini-cli",
|
|
3095
|
+
aliases: ["gemini"],
|
|
3096
|
+
label: "Gemini CLI",
|
|
3097
|
+
summary: "Configure Google's Gemini CLI to use a compatible Google generations API.",
|
|
3098
|
+
binaryName: "gemini",
|
|
3099
|
+
configPath: "~/.gemini/settings.json",
|
|
3100
|
+
apiShapes: ["google-generations"],
|
|
3101
|
+
branding: {
|
|
3102
|
+
colors: {
|
|
3103
|
+
dark: "#8AB4F8",
|
|
3104
|
+
light: "#1A73E8"
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
};
|
|
3108
|
+
|
|
3091
3109
|
// packages/agent-defs/src/agents/opencode.ts
|
|
3092
3110
|
var openCodeAgent = {
|
|
3093
3111
|
id: "opencode",
|
|
@@ -3161,6 +3179,7 @@ var allAgents = [
|
|
|
3161
3179
|
claudeCodeAgent,
|
|
3162
3180
|
claudeDesktopAgent,
|
|
3163
3181
|
codexAgent,
|
|
3182
|
+
geminiCliAgent,
|
|
3164
3183
|
openCodeAgent,
|
|
3165
3184
|
kimiAgent,
|
|
3166
3185
|
gooseAgent,
|
|
@@ -3357,6 +3376,7 @@ var poeProvider = {
|
|
|
3357
3376
|
label: "Poe",
|
|
3358
3377
|
summary: "Route AI coding agents through Poe's API.",
|
|
3359
3378
|
baseUrl: "https://api.poe.com",
|
|
3379
|
+
agentBaseUrl: "https://api.poe.com",
|
|
3360
3380
|
auth: {
|
|
3361
3381
|
kind: "api-key",
|
|
3362
3382
|
envVar: "POE_API_KEY",
|
|
@@ -3364,6 +3384,12 @@ var poeProvider = {
|
|
|
3364
3384
|
prompt: { title: "Poe API key" },
|
|
3365
3385
|
preferredLogin: "oauth"
|
|
3366
3386
|
},
|
|
3387
|
+
env: {
|
|
3388
|
+
ANTHROPIC_CUSTOM_HEADERS: {
|
|
3389
|
+
kind: "providerCredential",
|
|
3390
|
+
prefix: "Authorization: Bearer "
|
|
3391
|
+
}
|
|
3392
|
+
},
|
|
3367
3393
|
apiShapes: [
|
|
3368
3394
|
{
|
|
3369
3395
|
id: "openai-chat-completions",
|
|
@@ -3392,6 +3418,9 @@ var anthropicProvider = {
|
|
|
3392
3418
|
storageKey: "provider:anthropic",
|
|
3393
3419
|
prompt: { title: "Anthropic API key" }
|
|
3394
3420
|
},
|
|
3421
|
+
env: {
|
|
3422
|
+
ANTHROPIC_API_KEY: { kind: "providerCredential" }
|
|
3423
|
+
},
|
|
3395
3424
|
apiShapes: [
|
|
3396
3425
|
{
|
|
3397
3426
|
id: "anthropic-messages",
|
|
@@ -3414,6 +3443,12 @@ var cloudflareProvider = {
|
|
|
3414
3443
|
storageKey: "provider:cloudflare",
|
|
3415
3444
|
prompt: { title: "Cloudflare AI Gateway token" }
|
|
3416
3445
|
},
|
|
3446
|
+
env: {
|
|
3447
|
+
ANTHROPIC_CUSTOM_HEADERS: {
|
|
3448
|
+
kind: "providerCredential",
|
|
3449
|
+
prefix: "Authorization: Bearer "
|
|
3450
|
+
}
|
|
3451
|
+
},
|
|
3417
3452
|
apiShapes: [
|
|
3418
3453
|
{
|
|
3419
3454
|
id: "openai-chat-completions",
|
|
@@ -3509,17 +3544,17 @@ function isPidRunning(pid) {
|
|
|
3509
3544
|
}
|
|
3510
3545
|
function createDefaultFs() {
|
|
3511
3546
|
return {
|
|
3512
|
-
open: (
|
|
3513
|
-
readFile: (
|
|
3547
|
+
open: (path55, flags) => fsPromises.open(path55, flags),
|
|
3548
|
+
readFile: (path55, encoding) => fsPromises.readFile(path55, encoding),
|
|
3514
3549
|
stat: fsPromises.stat,
|
|
3515
3550
|
unlink: fsPromises.unlink
|
|
3516
3551
|
};
|
|
3517
3552
|
}
|
|
3518
|
-
async function removeLockFile(
|
|
3553
|
+
async function removeLockFile(fs17, lockPath, signal) {
|
|
3519
3554
|
for (let attempt = 0; attempt <= 4; attempt += 1) {
|
|
3520
3555
|
throwIfAborted(signal);
|
|
3521
3556
|
try {
|
|
3522
|
-
await
|
|
3557
|
+
await fs17.unlink(lockPath);
|
|
3523
3558
|
return;
|
|
3524
3559
|
} catch (error2) {
|
|
3525
3560
|
if (hasErrorCode(error2, "ENOENT")) {
|
|
@@ -3550,12 +3585,12 @@ function parseLockMetadata(content) {
|
|
|
3550
3585
|
}
|
|
3551
3586
|
return void 0;
|
|
3552
3587
|
}
|
|
3553
|
-
async function readLockMetadata(
|
|
3554
|
-
if (!
|
|
3588
|
+
async function readLockMetadata(fs17, lockPath) {
|
|
3589
|
+
if (!fs17.readFile) {
|
|
3555
3590
|
return void 0;
|
|
3556
3591
|
}
|
|
3557
3592
|
try {
|
|
3558
|
-
return parseLockMetadata(await
|
|
3593
|
+
return parseLockMetadata(await fs17.readFile(lockPath, "utf8"));
|
|
3559
3594
|
} catch (error2) {
|
|
3560
3595
|
if (hasErrorCode(error2, "ENOENT")) {
|
|
3561
3596
|
return null;
|
|
@@ -3589,7 +3624,7 @@ async function writeLockMetadata(handle) {
|
|
|
3589
3624
|
}
|
|
3590
3625
|
}
|
|
3591
3626
|
async function acquireFileLock(filePath, options = {}) {
|
|
3592
|
-
const
|
|
3627
|
+
const fs17 = options.fs ?? createDefaultFs();
|
|
3593
3628
|
const retries = options.retries ?? 20;
|
|
3594
3629
|
const minTimeout = options.minTimeout ?? 25;
|
|
3595
3630
|
const maxTimeout = options.maxTimeout ?? 250;
|
|
@@ -3600,7 +3635,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
3600
3635
|
while (attempt <= retries) {
|
|
3601
3636
|
throwIfAborted(options.signal);
|
|
3602
3637
|
try {
|
|
3603
|
-
const handle = await
|
|
3638
|
+
const handle = await fs17.open(lockPath, "wx");
|
|
3604
3639
|
await writeLockMetadata(handle);
|
|
3605
3640
|
let released = false;
|
|
3606
3641
|
return async () => {
|
|
@@ -3608,7 +3643,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
3608
3643
|
return;
|
|
3609
3644
|
}
|
|
3610
3645
|
released = true;
|
|
3611
|
-
await removeLockFile(
|
|
3646
|
+
await removeLockFile(fs17, lockPath, options.signal);
|
|
3612
3647
|
};
|
|
3613
3648
|
} catch (error2) {
|
|
3614
3649
|
if (!hasErrorCode(error2, "EEXIST")) {
|
|
@@ -3617,7 +3652,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
3617
3652
|
}
|
|
3618
3653
|
let stat7;
|
|
3619
3654
|
try {
|
|
3620
|
-
stat7 = await
|
|
3655
|
+
stat7 = await fs17.stat(lockPath);
|
|
3621
3656
|
} catch (statError) {
|
|
3622
3657
|
if (hasErrorCode(statError, "ENOENT")) {
|
|
3623
3658
|
continue;
|
|
@@ -3625,7 +3660,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
3625
3660
|
throw statError;
|
|
3626
3661
|
}
|
|
3627
3662
|
const reclaimLock = await shouldReclaimLock({
|
|
3628
|
-
fs:
|
|
3663
|
+
fs: fs17,
|
|
3629
3664
|
isPidRunning: pidIsRunning,
|
|
3630
3665
|
lockPath,
|
|
3631
3666
|
staleMs,
|
|
@@ -3635,7 +3670,7 @@ async function acquireFileLock(filePath, options = {}) {
|
|
|
3635
3670
|
continue;
|
|
3636
3671
|
}
|
|
3637
3672
|
if (reclaimLock) {
|
|
3638
|
-
await removeLockFile(
|
|
3673
|
+
await removeLockFile(fs17, lockPath, options.signal);
|
|
3639
3674
|
continue;
|
|
3640
3675
|
}
|
|
3641
3676
|
if (attempt >= retries) {
|
|
@@ -3655,7 +3690,7 @@ function isNotFoundError(error2) {
|
|
|
3655
3690
|
}
|
|
3656
3691
|
|
|
3657
3692
|
// packages/poe-code-config/src/state/jobs.ts
|
|
3658
|
-
function createJobRegistry(homeDir,
|
|
3693
|
+
function createJobRegistry(homeDir, fs17 = defaultStateFs) {
|
|
3659
3694
|
const jobsDir = path10.join(homeDir, ".poe-code", "state", "jobs");
|
|
3660
3695
|
function jobPath(id) {
|
|
3661
3696
|
assertSafeJobId(id);
|
|
@@ -3663,7 +3698,7 @@ function createJobRegistry(homeDir, fs16 = defaultStateFs) {
|
|
|
3663
3698
|
}
|
|
3664
3699
|
async function get(id) {
|
|
3665
3700
|
try {
|
|
3666
|
-
return parseJobEntry(await
|
|
3701
|
+
return parseJobEntry(await fs17.readFile(jobPath(id), "utf8"));
|
|
3667
3702
|
} catch (error2) {
|
|
3668
3703
|
if (isNotFoundError(error2)) {
|
|
3669
3704
|
return null;
|
|
@@ -3674,8 +3709,8 @@ function createJobRegistry(homeDir, fs16 = defaultStateFs) {
|
|
|
3674
3709
|
async function put(entry) {
|
|
3675
3710
|
assertJobEntry(entry);
|
|
3676
3711
|
const filePath = jobPath(entry.id);
|
|
3677
|
-
await
|
|
3678
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
3712
|
+
await fs17.mkdir(jobsDir, { recursive: true });
|
|
3713
|
+
const release = await acquireFileLock(filePath, { fs: fs17 });
|
|
3679
3714
|
try {
|
|
3680
3715
|
await writeJobAtomically(filePath, entry);
|
|
3681
3716
|
} finally {
|
|
@@ -3684,8 +3719,8 @@ function createJobRegistry(homeDir, fs16 = defaultStateFs) {
|
|
|
3684
3719
|
}
|
|
3685
3720
|
async function update(id, patch) {
|
|
3686
3721
|
const filePath = jobPath(id);
|
|
3687
|
-
await
|
|
3688
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
3722
|
+
await fs17.mkdir(jobsDir, { recursive: true });
|
|
3723
|
+
const release = await acquireFileLock(filePath, { fs: fs17 });
|
|
3689
3724
|
try {
|
|
3690
3725
|
const current = await get(id);
|
|
3691
3726
|
if (current === null) {
|
|
@@ -3706,7 +3741,7 @@ function createJobRegistry(homeDir, fs16 = defaultStateFs) {
|
|
|
3706
3741
|
async function list(filter = {}) {
|
|
3707
3742
|
let entries;
|
|
3708
3743
|
try {
|
|
3709
|
-
entries = await
|
|
3744
|
+
entries = await fs17.readdir(jobsDir);
|
|
3710
3745
|
} catch (error2) {
|
|
3711
3746
|
if (isNotFoundError(error2)) {
|
|
3712
3747
|
return [];
|
|
@@ -3719,11 +3754,11 @@ function createJobRegistry(homeDir, fs16 = defaultStateFs) {
|
|
|
3719
3754
|
continue;
|
|
3720
3755
|
}
|
|
3721
3756
|
const filePath = path10.join(jobsDir, entry);
|
|
3722
|
-
const stat7 = await
|
|
3757
|
+
const stat7 = await fs17.stat(filePath);
|
|
3723
3758
|
if (!stat7.isFile()) {
|
|
3724
3759
|
continue;
|
|
3725
3760
|
}
|
|
3726
|
-
const job = parseJobEntry(await
|
|
3761
|
+
const job = parseJobEntry(await fs17.readFile(filePath, "utf8"));
|
|
3727
3762
|
if (matchesFilter(job, filter)) {
|
|
3728
3763
|
jobs.push(job);
|
|
3729
3764
|
}
|
|
@@ -3733,16 +3768,16 @@ function createJobRegistry(homeDir, fs16 = defaultStateFs) {
|
|
|
3733
3768
|
async function remove2(id) {
|
|
3734
3769
|
const filePath = jobPath(id);
|
|
3735
3770
|
try {
|
|
3736
|
-
await
|
|
3771
|
+
await fs17.stat(jobsDir);
|
|
3737
3772
|
} catch (error2) {
|
|
3738
3773
|
if (isNotFoundError(error2)) {
|
|
3739
3774
|
return;
|
|
3740
3775
|
}
|
|
3741
3776
|
throw error2;
|
|
3742
3777
|
}
|
|
3743
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
3778
|
+
const release = await acquireFileLock(filePath, { fs: fs17 });
|
|
3744
3779
|
try {
|
|
3745
|
-
await
|
|
3780
|
+
await fs17.unlink(filePath);
|
|
3746
3781
|
} catch (error2) {
|
|
3747
3782
|
if (!isNotFoundError(error2)) {
|
|
3748
3783
|
throw error2;
|
|
@@ -3752,14 +3787,14 @@ function createJobRegistry(homeDir, fs16 = defaultStateFs) {
|
|
|
3752
3787
|
}
|
|
3753
3788
|
}
|
|
3754
3789
|
async function writeJobAtomically(filePath, entry) {
|
|
3755
|
-
await
|
|
3790
|
+
await fs17.mkdir(path10.dirname(filePath), { recursive: true });
|
|
3756
3791
|
const tempPath = `${filePath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
3757
3792
|
try {
|
|
3758
|
-
await
|
|
3793
|
+
await fs17.writeFile(tempPath, `${JSON.stringify(entry, null, 2)}
|
|
3759
3794
|
`, {
|
|
3760
3795
|
encoding: "utf8"
|
|
3761
3796
|
});
|
|
3762
|
-
await
|
|
3797
|
+
await fs17.rename(tempPath, filePath);
|
|
3763
3798
|
} catch (error2) {
|
|
3764
3799
|
await removeTempFile(tempPath);
|
|
3765
3800
|
throw error2;
|
|
@@ -3767,7 +3802,7 @@ function createJobRegistry(homeDir, fs16 = defaultStateFs) {
|
|
|
3767
3802
|
}
|
|
3768
3803
|
async function removeTempFile(tempPath) {
|
|
3769
3804
|
try {
|
|
3770
|
-
await
|
|
3805
|
+
await fs17.unlink(tempPath);
|
|
3771
3806
|
} catch (error2) {
|
|
3772
3807
|
if (!isNotFoundError(error2)) {
|
|
3773
3808
|
throw error2;
|
|
@@ -3814,11 +3849,11 @@ function isRecord4(value) {
|
|
|
3814
3849
|
|
|
3815
3850
|
// packages/poe-code-config/src/state/templates.ts
|
|
3816
3851
|
import path11 from "node:path";
|
|
3817
|
-
function createTemplateRegistry(homeDir,
|
|
3852
|
+
function createTemplateRegistry(homeDir, fs17 = defaultStateFs) {
|
|
3818
3853
|
const filePath = path11.join(homeDir, ".poe-code", "state", "templates.json");
|
|
3819
3854
|
async function readState() {
|
|
3820
3855
|
try {
|
|
3821
|
-
const raw = await
|
|
3856
|
+
const raw = await fs17.readFile(filePath, "utf8");
|
|
3822
3857
|
return normalizeTemplateState(JSON.parse(raw));
|
|
3823
3858
|
} catch (error2) {
|
|
3824
3859
|
if (isNotFoundError(error2)) {
|
|
@@ -3828,14 +3863,14 @@ function createTemplateRegistry(homeDir, fs16 = defaultStateFs) {
|
|
|
3828
3863
|
}
|
|
3829
3864
|
}
|
|
3830
3865
|
async function writeState(state) {
|
|
3831
|
-
await
|
|
3866
|
+
await fs17.writeFile(filePath, `${JSON.stringify(state, null, 2)}
|
|
3832
3867
|
`, {
|
|
3833
3868
|
encoding: "utf8"
|
|
3834
3869
|
});
|
|
3835
3870
|
}
|
|
3836
3871
|
async function updateState(mutator) {
|
|
3837
|
-
await
|
|
3838
|
-
const release = await acquireFileLock(filePath, { fs:
|
|
3872
|
+
await fs17.mkdir(path11.dirname(filePath), { recursive: true });
|
|
3873
|
+
const release = await acquireFileLock(filePath, { fs: fs17 });
|
|
3839
3874
|
try {
|
|
3840
3875
|
const state = await readState();
|
|
3841
3876
|
mutator(state);
|
|
@@ -3905,10 +3940,10 @@ function isRecord5(value) {
|
|
|
3905
3940
|
}
|
|
3906
3941
|
|
|
3907
3942
|
// packages/poe-code-config/src/state/index.ts
|
|
3908
|
-
function createStateManager(homeDir,
|
|
3943
|
+
function createStateManager(homeDir, fs17) {
|
|
3909
3944
|
return {
|
|
3910
|
-
templates: createTemplateRegistry(homeDir,
|
|
3911
|
-
jobs: createJobRegistry(homeDir,
|
|
3945
|
+
templates: createTemplateRegistry(homeDir, fs17),
|
|
3946
|
+
jobs: createJobRegistry(homeDir, fs17)
|
|
3912
3947
|
};
|
|
3913
3948
|
}
|
|
3914
3949
|
|
|
@@ -4136,10 +4171,10 @@ function parseSources(value) {
|
|
|
4136
4171
|
if (!isRecord6(item)) {
|
|
4137
4172
|
throw new Error('Invalid "sources" frontmatter. Expected each source to be a string or object.');
|
|
4138
4173
|
}
|
|
4139
|
-
const
|
|
4174
|
+
const path55 = readRequiredString(item.path, "sources[].path");
|
|
4140
4175
|
const startLine = readOptionalPositiveInteger(item.startLine, "sources[].startLine");
|
|
4141
4176
|
const endLine = readOptionalPositiveInteger(item.endLine, "sources[].endLine");
|
|
4142
|
-
return parseSourceRef(serializeSourceRef({ path:
|
|
4177
|
+
return parseSourceRef(serializeSourceRef({ path: path55, ...startLine === void 0 ? {} : { startLine }, ...endLine === void 0 ? {} : { endLine } }));
|
|
4143
4178
|
});
|
|
4144
4179
|
}
|
|
4145
4180
|
function readOptionalString(value, field) {
|
|
@@ -4381,18 +4416,18 @@ function isPidRunning2(pid) {
|
|
|
4381
4416
|
return !hasErrorCode3(error2, "ESRCH");
|
|
4382
4417
|
}
|
|
4383
4418
|
}
|
|
4384
|
-
async function removeLockFile2(
|
|
4419
|
+
async function removeLockFile2(fs17, lockPath) {
|
|
4385
4420
|
try {
|
|
4386
|
-
await
|
|
4421
|
+
await fs17.unlink(lockPath);
|
|
4387
4422
|
} catch (error2) {
|
|
4388
4423
|
if (!hasErrorCode3(error2, "ENOENT")) {
|
|
4389
4424
|
throw error2;
|
|
4390
4425
|
}
|
|
4391
4426
|
}
|
|
4392
4427
|
}
|
|
4393
|
-
async function readLockPid(
|
|
4428
|
+
async function readLockPid(fs17, lockPath) {
|
|
4394
4429
|
try {
|
|
4395
|
-
return parsePid(await
|
|
4430
|
+
return parsePid(await fs17.readFile(lockPath, "utf8"));
|
|
4396
4431
|
} catch (error2) {
|
|
4397
4432
|
if (hasErrorCode3(error2, "ENOENT")) {
|
|
4398
4433
|
return null;
|
|
@@ -4401,7 +4436,7 @@ async function readLockPid(fs16, lockPath) {
|
|
|
4401
4436
|
}
|
|
4402
4437
|
}
|
|
4403
4438
|
async function withLock(root, run, options = {}) {
|
|
4404
|
-
const
|
|
4439
|
+
const fs17 = options.fs ?? createDefaultFs2();
|
|
4405
4440
|
const lockPath = path17.join(root, MEMORY_LOCK_RELPATH);
|
|
4406
4441
|
const pid = options.pid ?? process.pid;
|
|
4407
4442
|
const retries = options.retries ?? 20;
|
|
@@ -4410,24 +4445,24 @@ async function withLock(root, run, options = {}) {
|
|
|
4410
4445
|
const pidIsRunning = options.isPidRunning ?? isPidRunning2;
|
|
4411
4446
|
for (let attempt = 0; attempt <= retries; attempt += 1) {
|
|
4412
4447
|
try {
|
|
4413
|
-
await
|
|
4448
|
+
await fs17.writeFile(lockPath, `${pid}
|
|
4414
4449
|
`, { encoding: "utf8", flag: "wx" });
|
|
4415
4450
|
try {
|
|
4416
4451
|
return await run();
|
|
4417
4452
|
} finally {
|
|
4418
|
-
await removeLockFile2(
|
|
4453
|
+
await removeLockFile2(fs17, lockPath);
|
|
4419
4454
|
}
|
|
4420
4455
|
} catch (error2) {
|
|
4421
4456
|
if (!hasErrorCode3(error2, "EEXIST")) {
|
|
4422
4457
|
throw error2;
|
|
4423
4458
|
}
|
|
4424
4459
|
}
|
|
4425
|
-
const existingPid = await readLockPid(
|
|
4460
|
+
const existingPid = await readLockPid(fs17, lockPath);
|
|
4426
4461
|
if (existingPid === null) {
|
|
4427
4462
|
continue;
|
|
4428
4463
|
}
|
|
4429
4464
|
if (existingPid === void 0 || !pidIsRunning(existingPid)) {
|
|
4430
|
-
await removeLockFile2(
|
|
4465
|
+
await removeLockFile2(fs17, lockPath);
|
|
4431
4466
|
continue;
|
|
4432
4467
|
}
|
|
4433
4468
|
if (attempt < retries) {
|
|
@@ -5194,8 +5229,8 @@ function parseOlderThan(value) {
|
|
|
5194
5229
|
}
|
|
5195
5230
|
|
|
5196
5231
|
// packages/memory/src/ingest.ts
|
|
5197
|
-
import * as
|
|
5198
|
-
import
|
|
5232
|
+
import * as fs14 from "node:fs/promises";
|
|
5233
|
+
import path50 from "node:path";
|
|
5199
5234
|
|
|
5200
5235
|
// packages/agent-spawn/src/register-factories.ts
|
|
5201
5236
|
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
@@ -6031,29 +6066,29 @@ function wrapForLogTee(argv, jobId) {
|
|
|
6031
6066
|
return ["sh", "-c", script];
|
|
6032
6067
|
}
|
|
6033
6068
|
async function* streamLogFile(env, jobId, opts) {
|
|
6034
|
-
const
|
|
6069
|
+
const fs17 = env.fs ?? nodeFs2;
|
|
6035
6070
|
const file = jobLogPath(jobId);
|
|
6036
6071
|
let byteOffset = opts.sinceByte ?? 0;
|
|
6037
6072
|
while (true) {
|
|
6038
|
-
if (opts.since !== void 0 && !await wasModifiedSince(
|
|
6039
|
-
await waitForLogChange(
|
|
6073
|
+
if (opts.since !== void 0 && !await wasModifiedSince(fs17, file, opts.since)) {
|
|
6074
|
+
await waitForLogChange(fs17, file);
|
|
6040
6075
|
continue;
|
|
6041
6076
|
}
|
|
6042
|
-
const result = await readLogChunk(
|
|
6077
|
+
const result = await readLogChunk(fs17, file, byteOffset);
|
|
6043
6078
|
if (result !== null) {
|
|
6044
6079
|
byteOffset = result.nextByteOffset;
|
|
6045
6080
|
yield result.chunk;
|
|
6046
6081
|
continue;
|
|
6047
6082
|
}
|
|
6048
|
-
await waitForLogChange(
|
|
6083
|
+
await waitForLogChange(fs17, file);
|
|
6049
6084
|
}
|
|
6050
6085
|
}
|
|
6051
|
-
async function wasModifiedSince(
|
|
6052
|
-
if (
|
|
6086
|
+
async function wasModifiedSince(fs17, file, since) {
|
|
6087
|
+
if (fs17.promises.stat === void 0) {
|
|
6053
6088
|
return true;
|
|
6054
6089
|
}
|
|
6055
6090
|
try {
|
|
6056
|
-
const stat7 = await
|
|
6091
|
+
const stat7 = await fs17.promises.stat(file);
|
|
6057
6092
|
return stat7.mtimeMs >= since.getTime();
|
|
6058
6093
|
} catch (error2) {
|
|
6059
6094
|
if (isNodeError(error2) && error2.code === "ENOENT") {
|
|
@@ -6063,11 +6098,11 @@ async function wasModifiedSince(fs16, file, since) {
|
|
|
6063
6098
|
}
|
|
6064
6099
|
}
|
|
6065
6100
|
async function waitForExit(env, jobId, opts = {}) {
|
|
6066
|
-
const
|
|
6101
|
+
const fs17 = env.fs ?? nodeFs2;
|
|
6067
6102
|
const file = jobExitPath(jobId);
|
|
6068
6103
|
while (true) {
|
|
6069
6104
|
throwIfAborted2(opts.signal);
|
|
6070
|
-
const contents = await readTextFileIfExists(
|
|
6105
|
+
const contents = await readTextFileIfExists(fs17, file);
|
|
6071
6106
|
if (contents !== null) {
|
|
6072
6107
|
const text5 = contents.trim();
|
|
6073
6108
|
const exitCode = Number(text5);
|
|
@@ -6085,8 +6120,8 @@ function jobLogPath(jobId) {
|
|
|
6085
6120
|
function jobExitPath(jobId) {
|
|
6086
6121
|
return `${JOB_DIR}/${jobId}.exit`;
|
|
6087
6122
|
}
|
|
6088
|
-
async function readLogChunk(
|
|
6089
|
-
const contents = await readFileIfExists2(
|
|
6123
|
+
async function readLogChunk(fs17, file, byteOffset) {
|
|
6124
|
+
const contents = await readFileIfExists2(fs17, file);
|
|
6090
6125
|
if (contents === null || byteOffset >= contents.byteLength) {
|
|
6091
6126
|
return null;
|
|
6092
6127
|
}
|
|
@@ -6098,13 +6133,13 @@ async function readLogChunk(fs16, file, byteOffset) {
|
|
|
6098
6133
|
nextByteOffset: contents.byteLength
|
|
6099
6134
|
};
|
|
6100
6135
|
}
|
|
6101
|
-
async function readTextFileIfExists(
|
|
6102
|
-
const contents = await readFileIfExists2(
|
|
6136
|
+
async function readTextFileIfExists(fs17, file) {
|
|
6137
|
+
const contents = await readFileIfExists2(fs17, file);
|
|
6103
6138
|
return contents?.toString("utf8") ?? null;
|
|
6104
6139
|
}
|
|
6105
|
-
async function readFileIfExists2(
|
|
6140
|
+
async function readFileIfExists2(fs17, file) {
|
|
6106
6141
|
try {
|
|
6107
|
-
const contents = await
|
|
6142
|
+
const contents = await fs17.promises.readFile(file);
|
|
6108
6143
|
return Buffer.isBuffer(contents) ? contents : Buffer.from(contents);
|
|
6109
6144
|
} catch (error2) {
|
|
6110
6145
|
if (isNodeError(error2) && error2.code === "ENOENT") {
|
|
@@ -6113,8 +6148,8 @@ async function readFileIfExists2(fs16, file) {
|
|
|
6113
6148
|
throw error2;
|
|
6114
6149
|
}
|
|
6115
6150
|
}
|
|
6116
|
-
async function waitForLogChange(
|
|
6117
|
-
const watch =
|
|
6151
|
+
async function waitForLogChange(fs17, file) {
|
|
6152
|
+
const watch = fs17.watch;
|
|
6118
6153
|
if (typeof watch !== "function") {
|
|
6119
6154
|
await sleep3(POLL_INTERVAL_MS);
|
|
6120
6155
|
return;
|
|
@@ -6905,7 +6940,7 @@ import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream"
|
|
|
6905
6940
|
import path33 from "node:path";
|
|
6906
6941
|
var JOB_DIR2 = "/tmp/poe-jobs";
|
|
6907
6942
|
function createE2bJobHandle(input) {
|
|
6908
|
-
const
|
|
6943
|
+
const fs17 = createE2bLogStreamFs(input.sandbox);
|
|
6909
6944
|
return {
|
|
6910
6945
|
id: input.jobId,
|
|
6911
6946
|
envId: input.envId,
|
|
@@ -6921,10 +6956,10 @@ function createE2bJobHandle(input) {
|
|
|
6921
6956
|
return isRunning ? "running" : "lost";
|
|
6922
6957
|
},
|
|
6923
6958
|
stream(opts = {}) {
|
|
6924
|
-
return streamLogFile({ fs:
|
|
6959
|
+
return streamLogFile({ fs: fs17 }, input.jobId, opts);
|
|
6925
6960
|
},
|
|
6926
6961
|
async wait() {
|
|
6927
|
-
const result = await waitForExit({ fs:
|
|
6962
|
+
const result = await waitForExit({ fs: fs17 }, input.jobId);
|
|
6928
6963
|
const preserveMs = input.preserveAfterExitHours * 60 * 60 * 1e3;
|
|
6929
6964
|
if (preserveMs > 0) {
|
|
6930
6965
|
await input.sandbox.setTimeout(preserveMs);
|
|
@@ -7421,10 +7456,10 @@ var e2bAuthScope = defineScope("e2b", {
|
|
|
7421
7456
|
});
|
|
7422
7457
|
async function resolveE2bApiKey(input) {
|
|
7423
7458
|
const homeDir = input.homeDir ?? os4.homedir();
|
|
7424
|
-
const
|
|
7459
|
+
const fs17 = input.fs ?? nodeFs4;
|
|
7425
7460
|
const env = input.env ?? process.env;
|
|
7426
7461
|
const document = await readMergedDocument(
|
|
7427
|
-
|
|
7462
|
+
fs17,
|
|
7428
7463
|
resolveConfigPath(homeDir),
|
|
7429
7464
|
resolveProjectConfigPath(input.cwd)
|
|
7430
7465
|
);
|
|
@@ -7931,6 +7966,23 @@ var gooseAcpSpawnConfig = {
|
|
|
7931
7966
|
skipAuth: true
|
|
7932
7967
|
};
|
|
7933
7968
|
|
|
7969
|
+
// packages/agent-spawn/src/configs/gemini-cli.ts
|
|
7970
|
+
var geminiCliAcpSpawnConfig = {
|
|
7971
|
+
kind: "acp",
|
|
7972
|
+
agentId: "gemini-cli",
|
|
7973
|
+
acpArgs: ({ model, mcpServers }) => [
|
|
7974
|
+
"--acp",
|
|
7975
|
+
...model ? ["--model", model] : [],
|
|
7976
|
+
...mcpServers ? ["--allowed-mcp-server-names", Object.keys(mcpServers).join(",")] : [],
|
|
7977
|
+
...mcpServers ? ["--skip-trust"] : [],
|
|
7978
|
+
"--yolo"
|
|
7979
|
+
],
|
|
7980
|
+
env: {
|
|
7981
|
+
GEMINI_SANDBOX: "false"
|
|
7982
|
+
},
|
|
7983
|
+
skipAuth: true
|
|
7984
|
+
};
|
|
7985
|
+
|
|
7934
7986
|
// packages/agent-spawn/src/configs/index.ts
|
|
7935
7987
|
var allSpawnConfigs = [
|
|
7936
7988
|
claudeCodeSpawnConfig,
|
|
@@ -7947,6 +7999,7 @@ var acpLookup = /* @__PURE__ */ new Map();
|
|
|
7947
7999
|
acpLookup.set(openCodeAcpSpawnConfig.agentId, openCodeAcpSpawnConfig);
|
|
7948
8000
|
acpLookup.set(kimiAcpSpawnConfig.agentId, kimiAcpSpawnConfig);
|
|
7949
8001
|
acpLookup.set(gooseAcpSpawnConfig.agentId, gooseAcpSpawnConfig);
|
|
8002
|
+
acpLookup.set(geminiCliAcpSpawnConfig.agentId, geminiCliAcpSpawnConfig);
|
|
7950
8003
|
function getSpawnConfig(input) {
|
|
7951
8004
|
const resolvedId = resolveAgentId(input);
|
|
7952
8005
|
if (!resolvedId) {
|
|
@@ -7966,8 +8019,8 @@ function listMcpSupportedAgents() {
|
|
|
7966
8019
|
}
|
|
7967
8020
|
|
|
7968
8021
|
// packages/agent-spawn/src/spawn.ts
|
|
7969
|
-
import { mkdirSync as
|
|
7970
|
-
import
|
|
8022
|
+
import { mkdirSync as mkdirSync5, openSync as openSync2, writeSync, closeSync as closeSync2 } from "node:fs";
|
|
8023
|
+
import path46 from "node:path";
|
|
7971
8024
|
|
|
7972
8025
|
// packages/agent-spawn/src/configs/resolve-config.ts
|
|
7973
8026
|
function resolveConfig(agentId) {
|
|
@@ -8368,7 +8421,7 @@ function createEventQueue() {
|
|
|
8368
8421
|
|
|
8369
8422
|
// packages/agent-spawn/src/skill-bridge.ts
|
|
8370
8423
|
import crypto from "node:crypto";
|
|
8371
|
-
import
|
|
8424
|
+
import os7 from "node:os";
|
|
8372
8425
|
|
|
8373
8426
|
// packages/agent-skill-config/src/configs.ts
|
|
8374
8427
|
import os5 from "node:os";
|
|
@@ -8382,6 +8435,10 @@ var agentSkillConfigs = {
|
|
|
8382
8435
|
globalSkillDir: "~/.codex/skills",
|
|
8383
8436
|
localSkillDir: ".codex/skills"
|
|
8384
8437
|
},
|
|
8438
|
+
"gemini-cli": {
|
|
8439
|
+
globalSkillDir: "~/.gemini/skills",
|
|
8440
|
+
localSkillDir: ".gemini/skills"
|
|
8441
|
+
},
|
|
8385
8442
|
opencode: {
|
|
8386
8443
|
globalSkillDir: "~/.config/opencode/skills",
|
|
8387
8444
|
localSkillDir: ".opencode/skills"
|
|
@@ -8578,7 +8635,7 @@ function resolveSkillReference(ref, cwd, homeDir) {
|
|
|
8578
8635
|
import { execFileSync } from "node:child_process";
|
|
8579
8636
|
import * as fs10 from "node:fs";
|
|
8580
8637
|
import path39 from "node:path";
|
|
8581
|
-
var
|
|
8638
|
+
var defaultMarkerPrefix = "poe-code-spawn-skills";
|
|
8582
8639
|
function defaultGitDirRunner(cwd) {
|
|
8583
8640
|
try {
|
|
8584
8641
|
return execFileSync("git", ["rev-parse", "--git-dir"], {
|
|
@@ -8598,10 +8655,10 @@ function resolveExcludePath(cwd) {
|
|
|
8598
8655
|
}
|
|
8599
8656
|
return path39.join(path39.isAbsolute(gitDir) ? gitDir : path39.resolve(cwd, gitDir), "info/exclude");
|
|
8600
8657
|
}
|
|
8601
|
-
function markers(runId) {
|
|
8658
|
+
function markers(runId, markerPrefix) {
|
|
8602
8659
|
return {
|
|
8603
|
-
begin:
|
|
8604
|
-
end:
|
|
8660
|
+
begin: `# ${markerPrefix}:${runId} begin`,
|
|
8661
|
+
end: `# ${markerPrefix}:${runId} end`
|
|
8605
8662
|
};
|
|
8606
8663
|
}
|
|
8607
8664
|
function readExcludeFile(excludePath) {
|
|
@@ -8617,8 +8674,8 @@ function readExcludeFile(excludePath) {
|
|
|
8617
8674
|
function isNodeError2(error2) {
|
|
8618
8675
|
return error2 instanceof Error && "code" in error2;
|
|
8619
8676
|
}
|
|
8620
|
-
function removeBlock(content, runId) {
|
|
8621
|
-
const { begin, end } = markers(runId);
|
|
8677
|
+
function removeBlock(content, runId, markerPrefix) {
|
|
8678
|
+
const { begin, end } = markers(runId, markerPrefix);
|
|
8622
8679
|
const lines = content.split("\n");
|
|
8623
8680
|
const result = [];
|
|
8624
8681
|
for (let index = 0; index < lines.length; index += 1) {
|
|
@@ -8633,23 +8690,27 @@ function removeBlock(content, runId) {
|
|
|
8633
8690
|
}
|
|
8634
8691
|
return result.join("\n");
|
|
8635
8692
|
}
|
|
8636
|
-
function appendBlock(content, runId, entries) {
|
|
8637
|
-
const { begin, end } = markers(runId);
|
|
8693
|
+
function appendBlock(content, runId, entries, markerPrefix) {
|
|
8694
|
+
const { begin, end } = markers(runId, markerPrefix);
|
|
8638
8695
|
const existing = content ?? "";
|
|
8639
8696
|
const prefix = existing.length === 0 || existing.endsWith("\n") ? existing : `${existing}
|
|
8640
8697
|
`;
|
|
8641
8698
|
return `${prefix}${[begin, ...entries, end, ""].join("\n")}`;
|
|
8642
8699
|
}
|
|
8643
|
-
function appendExcludeBlock(cwd, runId, entries) {
|
|
8700
|
+
function appendExcludeBlock(cwd, runId, entries, opts) {
|
|
8644
8701
|
const excludePath = resolveExcludePath(cwd);
|
|
8645
8702
|
if (excludePath === void 0) {
|
|
8646
8703
|
return;
|
|
8647
8704
|
}
|
|
8648
8705
|
fs10.mkdirSync(path39.dirname(excludePath), { recursive: true });
|
|
8649
8706
|
const content = readExcludeFile(excludePath);
|
|
8650
|
-
fs10.writeFileSync(
|
|
8707
|
+
fs10.writeFileSync(
|
|
8708
|
+
excludePath,
|
|
8709
|
+
appendBlock(content, runId, entries, opts?.markerPrefix ?? defaultMarkerPrefix),
|
|
8710
|
+
"utf8"
|
|
8711
|
+
);
|
|
8651
8712
|
}
|
|
8652
|
-
function removeExcludeBlock(cwd, runId) {
|
|
8713
|
+
function removeExcludeBlock(cwd, runId, opts) {
|
|
8653
8714
|
const excludePath = resolveExcludePath(cwd);
|
|
8654
8715
|
if (excludePath === void 0) {
|
|
8655
8716
|
return;
|
|
@@ -8658,7 +8719,11 @@ function removeExcludeBlock(cwd, runId) {
|
|
|
8658
8719
|
if (content === void 0) {
|
|
8659
8720
|
return;
|
|
8660
8721
|
}
|
|
8661
|
-
fs10.writeFileSync(
|
|
8722
|
+
fs10.writeFileSync(
|
|
8723
|
+
excludePath,
|
|
8724
|
+
removeBlock(content, runId, opts?.markerPrefix ?? defaultMarkerPrefix),
|
|
8725
|
+
"utf8"
|
|
8726
|
+
);
|
|
8662
8727
|
}
|
|
8663
8728
|
|
|
8664
8729
|
// packages/agent-skill-config/src/bridge-active-skills.ts
|
|
@@ -8864,22 +8929,679 @@ function cleanupBridgedSkills(manifest) {
|
|
|
8864
8929
|
removeExcludeBlock(manifest.cwd, manifest.runId);
|
|
8865
8930
|
}
|
|
8866
8931
|
|
|
8932
|
+
// packages/agent-hook-config/src/configs.ts
|
|
8933
|
+
import os6 from "node:os";
|
|
8934
|
+
import path41 from "node:path";
|
|
8935
|
+
var agentHookConfigs = {
|
|
8936
|
+
"claude-code": {
|
|
8937
|
+
globalHookPath: "~/.claude/settings.json",
|
|
8938
|
+
localHookPath: ".claude/settings.json",
|
|
8939
|
+
format: "claude-settings-json",
|
|
8940
|
+
supportedEvents: [
|
|
8941
|
+
"SessionStart",
|
|
8942
|
+
"SessionEnd",
|
|
8943
|
+
"UserPromptSubmit",
|
|
8944
|
+
"PreToolUse",
|
|
8945
|
+
"PostToolUse",
|
|
8946
|
+
"PermissionRequest",
|
|
8947
|
+
"Stop",
|
|
8948
|
+
"StopFailure",
|
|
8949
|
+
"Notification",
|
|
8950
|
+
"PreCompact",
|
|
8951
|
+
"PostCompact",
|
|
8952
|
+
"SubagentStart",
|
|
8953
|
+
"SubagentStop"
|
|
8954
|
+
],
|
|
8955
|
+
supportedHandlerTypes: ["command", "http", "mcp_tool", "prompt", "agent"],
|
|
8956
|
+
placeholders: {
|
|
8957
|
+
projectDir: "${CLAUDE_PROJECT_DIR}",
|
|
8958
|
+
pluginRoot: "${CLAUDE_PLUGIN_ROOT}",
|
|
8959
|
+
pluginData: "${CLAUDE_PLUGIN_DATA}"
|
|
8960
|
+
}
|
|
8961
|
+
},
|
|
8962
|
+
codex: {
|
|
8963
|
+
globalHookPath: "~/.codex/hooks.json",
|
|
8964
|
+
localHookPath: ".codex/hooks.json",
|
|
8965
|
+
format: "codex-hooks-json",
|
|
8966
|
+
supportedEvents: [
|
|
8967
|
+
"SessionStart",
|
|
8968
|
+
"UserPromptSubmit",
|
|
8969
|
+
"PreToolUse",
|
|
8970
|
+
"PostToolUse",
|
|
8971
|
+
"PermissionRequest",
|
|
8972
|
+
"Stop"
|
|
8973
|
+
],
|
|
8974
|
+
supportedHandlerTypes: ["command"],
|
|
8975
|
+
placeholders: {
|
|
8976
|
+
projectDir: "$(git rev-parse --show-toplevel)",
|
|
8977
|
+
pluginRoot: "$PLUGIN_ROOT",
|
|
8978
|
+
pluginData: "$PLUGIN_DATA"
|
|
8979
|
+
}
|
|
8980
|
+
}
|
|
8981
|
+
};
|
|
8982
|
+
var supportedHookAgents = Object.keys(agentHookConfigs);
|
|
8983
|
+
function resolveAgentSupport2(input, registry = agentHookConfigs) {
|
|
8984
|
+
const resolvedId = resolveAgentId(input);
|
|
8985
|
+
if (!resolvedId) {
|
|
8986
|
+
return { status: "unknown", input };
|
|
8987
|
+
}
|
|
8988
|
+
const config = registry[resolvedId];
|
|
8989
|
+
if (!config) {
|
|
8990
|
+
return { status: "unsupported", input, id: resolvedId };
|
|
8991
|
+
}
|
|
8992
|
+
return { status: "supported", input, id: resolvedId, config };
|
|
8993
|
+
}
|
|
8994
|
+
function getAgentConfig2(agentId) {
|
|
8995
|
+
const support = resolveAgentSupport2(agentId);
|
|
8996
|
+
return support.status === "supported" ? support.config : void 0;
|
|
8997
|
+
}
|
|
8998
|
+
function expandHome3(targetPath, homeDir = os6.homedir()) {
|
|
8999
|
+
if (!targetPath?.startsWith("~")) {
|
|
9000
|
+
return targetPath;
|
|
9001
|
+
}
|
|
9002
|
+
if (targetPath === "~") {
|
|
9003
|
+
return homeDir;
|
|
9004
|
+
}
|
|
9005
|
+
if (targetPath.startsWith("~./")) {
|
|
9006
|
+
targetPath = `~/.${targetPath.slice(3)}`;
|
|
9007
|
+
}
|
|
9008
|
+
let remainder = targetPath.slice(1);
|
|
9009
|
+
if (remainder.startsWith("/") || remainder.startsWith("\\")) {
|
|
9010
|
+
remainder = remainder.slice(1);
|
|
9011
|
+
} else if (remainder.startsWith(".")) {
|
|
9012
|
+
remainder = remainder.slice(1);
|
|
9013
|
+
if (remainder.startsWith("/") || remainder.startsWith("\\")) {
|
|
9014
|
+
remainder = remainder.slice(1);
|
|
9015
|
+
}
|
|
9016
|
+
}
|
|
9017
|
+
return remainder.length === 0 ? homeDir : path41.join(homeDir, remainder);
|
|
9018
|
+
}
|
|
9019
|
+
function resolveHookPath(config, scope, cwd, homeDir) {
|
|
9020
|
+
if (scope === "global") {
|
|
9021
|
+
return path41.resolve(expandHome3(config.globalHookPath, homeDir));
|
|
9022
|
+
}
|
|
9023
|
+
return config.localHookPath ? path41.resolve(cwd, config.localHookPath) : void 0;
|
|
9024
|
+
}
|
|
9025
|
+
|
|
9026
|
+
// packages/agent-hook-config/src/read-hooks.ts
|
|
9027
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
9028
|
+
import path42 from "node:path";
|
|
9029
|
+
function readSettingsFile(filePath) {
|
|
9030
|
+
let content;
|
|
9031
|
+
try {
|
|
9032
|
+
content = readFileSync3(filePath, "utf8");
|
|
9033
|
+
} catch (error2) {
|
|
9034
|
+
if (error2.code === "ENOENT") {
|
|
9035
|
+
return void 0;
|
|
9036
|
+
}
|
|
9037
|
+
throw error2;
|
|
9038
|
+
}
|
|
9039
|
+
try {
|
|
9040
|
+
return JSON.parse(content);
|
|
9041
|
+
} catch (error2) {
|
|
9042
|
+
throw new Error(`Malformed JSON in ${filePath}`, { cause: error2 });
|
|
9043
|
+
}
|
|
9044
|
+
}
|
|
9045
|
+
function readClaudeHooks(cwd, homeDir, opts) {
|
|
9046
|
+
const projectPath = path42.resolve(cwd, ".claude/settings.json");
|
|
9047
|
+
const userPath = path42.resolve(homeDir, ".claude/settings.json");
|
|
9048
|
+
const scope = opts?.scope ?? "merged";
|
|
9049
|
+
const sourcePaths = scope === "project" ? [projectPath] : scope === "user" ? [userPath] : [userPath, projectPath];
|
|
9050
|
+
const result = { entries: [], readPaths: [] };
|
|
9051
|
+
for (const sourcePath of sourcePaths) {
|
|
9052
|
+
const settings = readSettingsFile(sourcePath);
|
|
9053
|
+
if (settings === void 0) {
|
|
9054
|
+
continue;
|
|
9055
|
+
}
|
|
9056
|
+
result.readPaths.push(sourcePath);
|
|
9057
|
+
for (const [event, groups] of Object.entries(settings.hooks ?? {})) {
|
|
9058
|
+
for (const group of groups) {
|
|
9059
|
+
for (const handler of group.hooks) {
|
|
9060
|
+
result.entries.push({ event, matcher: group.matcher, handler });
|
|
9061
|
+
}
|
|
9062
|
+
}
|
|
9063
|
+
}
|
|
9064
|
+
}
|
|
9065
|
+
return result;
|
|
9066
|
+
}
|
|
9067
|
+
|
|
9068
|
+
// packages/agent-hook-config/src/event-mapping.ts
|
|
9069
|
+
function requireAgentConfig(agentId) {
|
|
9070
|
+
const config = getAgentConfig2(agentId);
|
|
9071
|
+
if (!config) {
|
|
9072
|
+
throw new Error(`Unknown hook agent "${agentId}"`);
|
|
9073
|
+
}
|
|
9074
|
+
return config;
|
|
9075
|
+
}
|
|
9076
|
+
function getEventMappings(sourceAgentId, targetAgentId) {
|
|
9077
|
+
const source = requireAgentConfig(sourceAgentId);
|
|
9078
|
+
const target = requireAgentConfig(targetAgentId);
|
|
9079
|
+
return source.supportedEvents.map((sourceEvent) => {
|
|
9080
|
+
if (target.supportedEvents.includes(sourceEvent)) {
|
|
9081
|
+
return { sourceEvent, targetEvent: sourceEvent };
|
|
9082
|
+
}
|
|
9083
|
+
return {
|
|
9084
|
+
sourceEvent,
|
|
9085
|
+
targetEvent: null,
|
|
9086
|
+
dropReason: `${targetAgentId} has no ${sourceEvent} hook`
|
|
9087
|
+
};
|
|
9088
|
+
});
|
|
9089
|
+
}
|
|
9090
|
+
function getHandlerTypeRules(targetAgentId) {
|
|
9091
|
+
const target = requireAgentConfig(targetAgentId);
|
|
9092
|
+
const registeredTypes = supportedHookAgents.flatMap(
|
|
9093
|
+
(agentId) => requireAgentConfig(agentId).supportedHandlerTypes
|
|
9094
|
+
);
|
|
9095
|
+
const sourceTypes = [...new Set(registeredTypes)];
|
|
9096
|
+
const supportedTypes = target.supportedHandlerTypes.map((handlerType) => `"${handlerType}"`).join(", ");
|
|
9097
|
+
return sourceTypes.map((sourceType) => {
|
|
9098
|
+
if (target.supportedHandlerTypes.includes(sourceType)) {
|
|
9099
|
+
return { sourceType, allowed: true };
|
|
9100
|
+
}
|
|
9101
|
+
return {
|
|
9102
|
+
sourceType,
|
|
9103
|
+
allowed: false,
|
|
9104
|
+
dropReason: `${targetAgentId} only honors handlers of type ${supportedTypes}`
|
|
9105
|
+
};
|
|
9106
|
+
});
|
|
9107
|
+
}
|
|
9108
|
+
function getPlaceholderRewrites(sourceAgentId, targetAgentId) {
|
|
9109
|
+
const source = requireAgentConfig(sourceAgentId);
|
|
9110
|
+
const target = requireAgentConfig(targetAgentId);
|
|
9111
|
+
return Object.keys(source.placeholders).flatMap((key) => {
|
|
9112
|
+
const from = source.placeholders[key];
|
|
9113
|
+
const to = target.placeholders[key];
|
|
9114
|
+
if (!from || !to || from === to) {
|
|
9115
|
+
return [];
|
|
9116
|
+
}
|
|
9117
|
+
return [{ from, to }];
|
|
9118
|
+
});
|
|
9119
|
+
}
|
|
9120
|
+
|
|
9121
|
+
// packages/agent-hook-config/src/transform-hooks.ts
|
|
9122
|
+
function applyPlaceholderRewrites(value, rewrites) {
|
|
9123
|
+
return rewrites.reduce((rewrittenValue, rewrite) => {
|
|
9124
|
+
return rewrittenValue.replaceAll(rewrite.from, rewrite.to);
|
|
9125
|
+
}, value);
|
|
9126
|
+
}
|
|
9127
|
+
function transformHooks(source, sourceAgentId, targetAgentId, opts) {
|
|
9128
|
+
const eventMappings = getEventMappings(sourceAgentId, targetAgentId);
|
|
9129
|
+
const handlerRules = getHandlerTypeRules(targetAgentId);
|
|
9130
|
+
const placeholderRewrites = getPlaceholderRewrites(sourceAgentId, targetAgentId);
|
|
9131
|
+
const result = { entries: [], drops: [] };
|
|
9132
|
+
for (const sourceEntry of source) {
|
|
9133
|
+
const eventMapping = eventMappings.find((mapping) => mapping.sourceEvent === sourceEntry.event);
|
|
9134
|
+
if (!eventMapping || eventMapping.targetEvent === null) {
|
|
9135
|
+
result.drops.push({
|
|
9136
|
+
reason: "unsupported-event",
|
|
9137
|
+
detail: eventMapping?.dropReason ?? `${targetAgentId} has no ${sourceEntry.event} hook`,
|
|
9138
|
+
source: sourceEntry
|
|
9139
|
+
});
|
|
9140
|
+
continue;
|
|
9141
|
+
}
|
|
9142
|
+
const handlerRule = handlerRules.find((rule) => rule.sourceType === sourceEntry.handler.type);
|
|
9143
|
+
if (!handlerRule?.allowed) {
|
|
9144
|
+
result.drops.push({
|
|
9145
|
+
reason: "unsupported-handler-type",
|
|
9146
|
+
detail: `Unsupported handler type "${sourceEntry.handler.type}": ${handlerRule?.dropReason ?? `${targetAgentId} does not honor it`}`,
|
|
9147
|
+
source: sourceEntry
|
|
9148
|
+
});
|
|
9149
|
+
continue;
|
|
9150
|
+
}
|
|
9151
|
+
const handler = {
|
|
9152
|
+
type: "command",
|
|
9153
|
+
command: applyPlaceholderRewrites(sourceEntry.handler.command ?? "", placeholderRewrites),
|
|
9154
|
+
statusMessage: `[generated:${opts.runId}] ${sourceEntry.handler.statusMessage ?? ""}`
|
|
9155
|
+
};
|
|
9156
|
+
if (sourceEntry.handler.args !== void 0) {
|
|
9157
|
+
handler.args = sourceEntry.handler.args.map(
|
|
9158
|
+
(arg) => applyPlaceholderRewrites(arg, placeholderRewrites)
|
|
9159
|
+
);
|
|
9160
|
+
}
|
|
9161
|
+
if (sourceEntry.handler.timeout !== void 0) {
|
|
9162
|
+
handler.timeout = sourceEntry.handler.timeout;
|
|
9163
|
+
}
|
|
9164
|
+
result.entries.push({
|
|
9165
|
+
event: eventMapping.targetEvent,
|
|
9166
|
+
matcher: sourceEntry.matcher,
|
|
9167
|
+
handler,
|
|
9168
|
+
generatedId: `generated-${opts.runId}-${result.entries.length}`
|
|
9169
|
+
});
|
|
9170
|
+
}
|
|
9171
|
+
return result;
|
|
9172
|
+
}
|
|
9173
|
+
|
|
9174
|
+
// packages/agent-hook-config/src/write-hooks.ts
|
|
9175
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
9176
|
+
import path43 from "node:path";
|
|
9177
|
+
function isGeneratedHandler(handler) {
|
|
9178
|
+
return handler.statusMessage?.startsWith("[generated:") ?? false;
|
|
9179
|
+
}
|
|
9180
|
+
function parseHooksFile(targetPath) {
|
|
9181
|
+
let content;
|
|
9182
|
+
try {
|
|
9183
|
+
content = readFileSync4(targetPath, "utf8");
|
|
9184
|
+
} catch (error2) {
|
|
9185
|
+
if (error2.code === "ENOENT") {
|
|
9186
|
+
return { file: { hooks: {} }, fileCreated: true };
|
|
9187
|
+
}
|
|
9188
|
+
throw error2;
|
|
9189
|
+
}
|
|
9190
|
+
try {
|
|
9191
|
+
return { file: JSON.parse(content), fileCreated: false };
|
|
9192
|
+
} catch (error2) {
|
|
9193
|
+
throw new Error(`Malformed JSON in ${targetPath}`, { cause: error2 });
|
|
9194
|
+
}
|
|
9195
|
+
}
|
|
9196
|
+
function validateEntries(entries) {
|
|
9197
|
+
for (const entry of entries) {
|
|
9198
|
+
if (!isGeneratedHandler(entry.handler)) {
|
|
9199
|
+
throw new Error(
|
|
9200
|
+
`Generated hook entry "${entry.generatedId}" has statusMessage that must start with "[generated:"`
|
|
9201
|
+
);
|
|
9202
|
+
}
|
|
9203
|
+
}
|
|
9204
|
+
}
|
|
9205
|
+
function removeGeneratedHandlers(file) {
|
|
9206
|
+
let removed = 0;
|
|
9207
|
+
const hooks = file.hooks ?? (file.hooks = {});
|
|
9208
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
9209
|
+
hooks[event] = groups.filter((group) => {
|
|
9210
|
+
const initialCount = group.hooks.length;
|
|
9211
|
+
const remainingHandlers = group.hooks.filter((handler) => {
|
|
9212
|
+
if (isGeneratedHandler(handler)) {
|
|
9213
|
+
removed += 1;
|
|
9214
|
+
return false;
|
|
9215
|
+
}
|
|
9216
|
+
return true;
|
|
9217
|
+
});
|
|
9218
|
+
group.hooks = remainingHandlers;
|
|
9219
|
+
return group.hooks.length > 0 || group.hooks.length === initialCount;
|
|
9220
|
+
});
|
|
9221
|
+
}
|
|
9222
|
+
return removed;
|
|
9223
|
+
}
|
|
9224
|
+
function appendEntries(file, entries) {
|
|
9225
|
+
const hooks = file.hooks ?? (file.hooks = {});
|
|
9226
|
+
for (const entry of entries) {
|
|
9227
|
+
const groups = hooks[entry.event] ?? (hooks[entry.event] = []);
|
|
9228
|
+
let group = groups.find((candidate) => candidate.matcher === entry.matcher);
|
|
9229
|
+
if (!group) {
|
|
9230
|
+
group = entry.matcher === void 0 ? { hooks: [] } : { matcher: entry.matcher, hooks: [] };
|
|
9231
|
+
groups.push(group);
|
|
9232
|
+
}
|
|
9233
|
+
group.hooks.push(entry.handler);
|
|
9234
|
+
}
|
|
9235
|
+
}
|
|
9236
|
+
function writeCodexHooks(targetPath, entries, _runId) {
|
|
9237
|
+
const { file, fileCreated } = parseHooksFile(targetPath);
|
|
9238
|
+
validateEntries(entries);
|
|
9239
|
+
const previousGeneratedRemoved = removeGeneratedHandlers(file);
|
|
9240
|
+
appendEntries(file, entries);
|
|
9241
|
+
mkdirSync3(path43.dirname(targetPath), { recursive: true });
|
|
9242
|
+
const temporaryPath = `${targetPath}.tmp`;
|
|
9243
|
+
writeFileSync2(temporaryPath, `${JSON.stringify(file, null, 2)}
|
|
9244
|
+
`);
|
|
9245
|
+
renameSync(temporaryPath, targetPath);
|
|
9246
|
+
return {
|
|
9247
|
+
path: targetPath,
|
|
9248
|
+
fileCreated,
|
|
9249
|
+
previousGeneratedRemoved,
|
|
9250
|
+
generatedWritten: entries.length
|
|
9251
|
+
};
|
|
9252
|
+
}
|
|
9253
|
+
|
|
9254
|
+
// packages/agent-hook-config/src/symlink-hooks.ts
|
|
9255
|
+
import {
|
|
9256
|
+
closeSync,
|
|
9257
|
+
lstatSync,
|
|
9258
|
+
mkdirSync as mkdirSync4,
|
|
9259
|
+
openSync,
|
|
9260
|
+
readlinkSync,
|
|
9261
|
+
readSync,
|
|
9262
|
+
symlinkSync,
|
|
9263
|
+
unlinkSync
|
|
9264
|
+
} from "node:fs";
|
|
9265
|
+
import path44 from "node:path";
|
|
9266
|
+
function requireAgentConfig2(agentId) {
|
|
9267
|
+
const config = getAgentConfig2(agentId);
|
|
9268
|
+
if (!config) {
|
|
9269
|
+
throw new Error(`No hook configuration found for agent "${agentId}"`);
|
|
9270
|
+
}
|
|
9271
|
+
return config;
|
|
9272
|
+
}
|
|
9273
|
+
function resolveScopedPath(config, agentId, cwd, homeDir, scope) {
|
|
9274
|
+
const targetPath = resolveHookPath(
|
|
9275
|
+
config,
|
|
9276
|
+
scope === "project" ? "local" : "global",
|
|
9277
|
+
cwd,
|
|
9278
|
+
homeDir
|
|
9279
|
+
);
|
|
9280
|
+
if (!targetPath) {
|
|
9281
|
+
throw new Error(`Agent "${agentId}" has no ${scope} hook path`);
|
|
9282
|
+
}
|
|
9283
|
+
return targetPath;
|
|
9284
|
+
}
|
|
9285
|
+
function readFirstKilobyte(filePath) {
|
|
9286
|
+
const descriptor = openSync(filePath, "r");
|
|
9287
|
+
const buffer = Buffer.alloc(1024);
|
|
9288
|
+
try {
|
|
9289
|
+
const length = readSync(descriptor, buffer, 0, buffer.length, 0);
|
|
9290
|
+
return buffer.toString("utf8", 0, length);
|
|
9291
|
+
} finally {
|
|
9292
|
+
closeSync(descriptor);
|
|
9293
|
+
}
|
|
9294
|
+
}
|
|
9295
|
+
function isRecord8(value) {
|
|
9296
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9297
|
+
}
|
|
9298
|
+
function isFullyGeneratedFile(filePath) {
|
|
9299
|
+
let parsed;
|
|
9300
|
+
try {
|
|
9301
|
+
parsed = JSON.parse(readFirstKilobyte(filePath));
|
|
9302
|
+
} catch {
|
|
9303
|
+
return false;
|
|
9304
|
+
}
|
|
9305
|
+
if (!isRecord8(parsed)) {
|
|
9306
|
+
return false;
|
|
9307
|
+
}
|
|
9308
|
+
if (Object.keys(parsed).some((key) => key !== "hooks")) {
|
|
9309
|
+
return false;
|
|
9310
|
+
}
|
|
9311
|
+
const hooks = parsed.hooks;
|
|
9312
|
+
if (!isRecord8(hooks)) {
|
|
9313
|
+
return false;
|
|
9314
|
+
}
|
|
9315
|
+
let handlerFound = false;
|
|
9316
|
+
for (const groups of Object.values(hooks)) {
|
|
9317
|
+
if (!Array.isArray(groups)) {
|
|
9318
|
+
return false;
|
|
9319
|
+
}
|
|
9320
|
+
for (const group of groups) {
|
|
9321
|
+
if (!isRecord8(group) || !Array.isArray(group.hooks)) {
|
|
9322
|
+
return false;
|
|
9323
|
+
}
|
|
9324
|
+
for (const handler of group.hooks) {
|
|
9325
|
+
if (!isRecord8(handler)) {
|
|
9326
|
+
return false;
|
|
9327
|
+
}
|
|
9328
|
+
handlerFound = true;
|
|
9329
|
+
const statusMessage = handler.statusMessage;
|
|
9330
|
+
if (typeof statusMessage !== "string" || !statusMessage.startsWith("[generated:")) {
|
|
9331
|
+
return false;
|
|
9332
|
+
}
|
|
9333
|
+
}
|
|
9334
|
+
}
|
|
9335
|
+
}
|
|
9336
|
+
return handlerFound;
|
|
9337
|
+
}
|
|
9338
|
+
function symlinkHooks(sourceAgentId, targetAgentId, cwd, homeDir, scope) {
|
|
9339
|
+
const source = requireAgentConfig2(sourceAgentId);
|
|
9340
|
+
const target = requireAgentConfig2(targetAgentId);
|
|
9341
|
+
if (source.format !== target.format) {
|
|
9342
|
+
throw new Error(
|
|
9343
|
+
`Cannot symlink hook formats "${source.format}" and "${target.format}"; use transformation instead`
|
|
9344
|
+
);
|
|
9345
|
+
}
|
|
9346
|
+
const targetPath = resolveScopedPath(source, sourceAgentId, cwd, homeDir, scope);
|
|
9347
|
+
const symlinkPath = resolveScopedPath(target, targetAgentId, cwd, homeDir, scope);
|
|
9348
|
+
let replaced = "none";
|
|
9349
|
+
try {
|
|
9350
|
+
const existing = lstatSync(symlinkPath);
|
|
9351
|
+
if (existing.isSymbolicLink()) {
|
|
9352
|
+
if (readlinkSync(symlinkPath) === targetPath) {
|
|
9353
|
+
return { symlinkPath, targetPath, replaced };
|
|
9354
|
+
}
|
|
9355
|
+
unlinkSync(symlinkPath);
|
|
9356
|
+
replaced = "stale-symlink";
|
|
9357
|
+
} else if (existing.isFile() && isFullyGeneratedFile(symlinkPath)) {
|
|
9358
|
+
unlinkSync(symlinkPath);
|
|
9359
|
+
replaced = "generated-file";
|
|
9360
|
+
} else {
|
|
9361
|
+
throw new Error(`Refuse to replace user-authored hook file at ${symlinkPath}`);
|
|
9362
|
+
}
|
|
9363
|
+
} catch (error2) {
|
|
9364
|
+
if (error2.code !== "ENOENT") {
|
|
9365
|
+
throw error2;
|
|
9366
|
+
}
|
|
9367
|
+
}
|
|
9368
|
+
mkdirSync4(path44.dirname(symlinkPath), { recursive: true });
|
|
9369
|
+
symlinkSync(targetPath, symlinkPath);
|
|
9370
|
+
return { symlinkPath, targetPath, replaced };
|
|
9371
|
+
}
|
|
9372
|
+
|
|
9373
|
+
// packages/agent-hook-config/src/bridge-hooks.ts
|
|
9374
|
+
import * as fs12 from "node:fs";
|
|
9375
|
+
import path45 from "node:path";
|
|
9376
|
+
var hookExcludeMarkerPrefix = "poe-code-spawn-hooks";
|
|
9377
|
+
function isNodeError4(error2) {
|
|
9378
|
+
return error2 instanceof Error && "code" in error2;
|
|
9379
|
+
}
|
|
9380
|
+
function pathExists4(targetPath) {
|
|
9381
|
+
try {
|
|
9382
|
+
fs12.lstatSync(targetPath);
|
|
9383
|
+
return true;
|
|
9384
|
+
} catch (error2) {
|
|
9385
|
+
if (isNodeError4(error2) && error2.code === "ENOENT") {
|
|
9386
|
+
return false;
|
|
9387
|
+
}
|
|
9388
|
+
throw error2;
|
|
9389
|
+
}
|
|
9390
|
+
}
|
|
9391
|
+
function collectMissingParents2(targetPath) {
|
|
9392
|
+
const parents = [];
|
|
9393
|
+
let current = path45.dirname(targetPath);
|
|
9394
|
+
while (!pathExists4(current)) {
|
|
9395
|
+
parents.push(current);
|
|
9396
|
+
const parent = path45.dirname(current);
|
|
9397
|
+
if (parent === current) {
|
|
9398
|
+
break;
|
|
9399
|
+
}
|
|
9400
|
+
current = parent;
|
|
9401
|
+
}
|
|
9402
|
+
return parents.reverse();
|
|
9403
|
+
}
|
|
9404
|
+
function removeDirectoryIfEmpty2(targetPath) {
|
|
9405
|
+
try {
|
|
9406
|
+
fs12.rmdirSync(targetPath);
|
|
9407
|
+
} catch (error2) {
|
|
9408
|
+
if (isNodeError4(error2) && (error2.code === "ENOENT" || error2.code === "ENOTEMPTY" || error2.code === "EEXIST")) {
|
|
9409
|
+
return;
|
|
9410
|
+
}
|
|
9411
|
+
throw error2;
|
|
9412
|
+
}
|
|
9413
|
+
}
|
|
9414
|
+
function requireSupport(input, role) {
|
|
9415
|
+
const support = resolveAgentSupport2(input);
|
|
9416
|
+
if (support.status !== "supported" || !support.id || !support.config) {
|
|
9417
|
+
throw new Error(
|
|
9418
|
+
`Unsupported ${role} hook agent "${input}". Supported hook agents: ${supportedHookAgents.join(", ")}.`
|
|
9419
|
+
);
|
|
9420
|
+
}
|
|
9421
|
+
return { id: support.id, config: support.config };
|
|
9422
|
+
}
|
|
9423
|
+
function requireTargetPath(targetId, config, cwd, homeDir) {
|
|
9424
|
+
const targetPath = resolveHookPath(config, "local", cwd, homeDir);
|
|
9425
|
+
if (!targetPath) {
|
|
9426
|
+
throw new Error(`Agent "${targetId}" has no project hook path`);
|
|
9427
|
+
}
|
|
9428
|
+
return targetPath;
|
|
9429
|
+
}
|
|
9430
|
+
function readCodexFile(targetPath) {
|
|
9431
|
+
let content;
|
|
9432
|
+
try {
|
|
9433
|
+
content = fs12.readFileSync(targetPath, "utf8");
|
|
9434
|
+
} catch (error2) {
|
|
9435
|
+
if (isNodeError4(error2) && error2.code === "ENOENT") {
|
|
9436
|
+
return void 0;
|
|
9437
|
+
}
|
|
9438
|
+
throw error2;
|
|
9439
|
+
}
|
|
9440
|
+
try {
|
|
9441
|
+
return JSON.parse(content);
|
|
9442
|
+
} catch (error2) {
|
|
9443
|
+
throw new Error(`Malformed JSON in ${targetPath}`, { cause: error2 });
|
|
9444
|
+
}
|
|
9445
|
+
}
|
|
9446
|
+
function writeCodexFile(targetPath, file) {
|
|
9447
|
+
fs12.writeFileSync(targetPath, `${JSON.stringify(file, null, 2)}
|
|
9448
|
+
`, "utf8");
|
|
9449
|
+
}
|
|
9450
|
+
function hasOnlyEmptyHooks(file) {
|
|
9451
|
+
return Object.keys(file).every((key) => key === "hooks") && Object.values(file.hooks ?? {}).every((groups) => groups.length === 0);
|
|
9452
|
+
}
|
|
9453
|
+
function relativeToCwd(cwd, targetPath) {
|
|
9454
|
+
return path45.relative(cwd, targetPath);
|
|
9455
|
+
}
|
|
9456
|
+
function matcherKey(event, matcher) {
|
|
9457
|
+
return `${event}\0${matcher === void 0 ? "<undefined>" : matcher}`;
|
|
9458
|
+
}
|
|
9459
|
+
function bridgeHooks(sourceAgentId, targetAgentId, cwd, homeDir, runId, opts) {
|
|
9460
|
+
const source = requireSupport(sourceAgentId, "source");
|
|
9461
|
+
const target = requireSupport(targetAgentId, "target");
|
|
9462
|
+
const strategy = opts?.strategy ?? (source.config.format === target.config.format ? "symlink" : "transform");
|
|
9463
|
+
const manifest = {
|
|
9464
|
+
sourceAgentId,
|
|
9465
|
+
targetAgentId,
|
|
9466
|
+
cwd,
|
|
9467
|
+
runId,
|
|
9468
|
+
strategy,
|
|
9469
|
+
drops: []
|
|
9470
|
+
};
|
|
9471
|
+
if (strategy === "symlink") {
|
|
9472
|
+
const symlinkPath = requireTargetPath(target.id, target.config, cwd, homeDir);
|
|
9473
|
+
manifest.createdParents = collectMissingParents2(symlinkPath);
|
|
9474
|
+
const result = symlinkHooks(source.id, target.id, cwd, homeDir, "project");
|
|
9475
|
+
manifest.symlinkPath = result.symlinkPath;
|
|
9476
|
+
manifest.symlinkTarget = result.targetPath;
|
|
9477
|
+
manifest.symlinkReplaced = result.replaced;
|
|
9478
|
+
appendExcludeBlock(cwd, runId, [relativeToCwd(cwd, result.symlinkPath)], {
|
|
9479
|
+
markerPrefix: hookExcludeMarkerPrefix
|
|
9480
|
+
});
|
|
9481
|
+
return manifest;
|
|
9482
|
+
}
|
|
9483
|
+
if (source.id !== "claude-code") {
|
|
9484
|
+
throw new Error(`Transforming hooks from "${source.id}" is not supported yet`);
|
|
9485
|
+
}
|
|
9486
|
+
if (target.config.format !== "codex-hooks-json") {
|
|
9487
|
+
throw new Error(
|
|
9488
|
+
`Transforming hooks to "${target.id}" is not supported yet; only codex-hook targets can be written`
|
|
9489
|
+
);
|
|
9490
|
+
}
|
|
9491
|
+
const targetPath = requireTargetPath(target.id, target.config, cwd, homeDir);
|
|
9492
|
+
const priorFile = readCodexFile(targetPath);
|
|
9493
|
+
const sourceHooks = readClaudeHooks(cwd, homeDir, { scope: opts?.scope ?? "merged" });
|
|
9494
|
+
const transformed = transformHooks(sourceHooks.entries, source.id, target.id, { runId });
|
|
9495
|
+
const createdParents = collectMissingParents2(targetPath);
|
|
9496
|
+
const writeResult = writeCodexHooks(targetPath, transformed.entries, runId);
|
|
9497
|
+
manifest.writtenPath = targetPath;
|
|
9498
|
+
manifest.generatedEntryIds = transformed.entries.map((entry) => entry.generatedId);
|
|
9499
|
+
manifest.drops = transformed.drops;
|
|
9500
|
+
manifest.createdParents = createdParents;
|
|
9501
|
+
manifest.fileCreated = writeResult.fileCreated;
|
|
9502
|
+
manifest.preExistingEvents = Object.keys(priorFile?.hooks ?? {});
|
|
9503
|
+
manifest.preExistingMatchers = Object.entries(priorFile?.hooks ?? {}).flatMap(
|
|
9504
|
+
([event, groups]) => groups.map((group) => ({
|
|
9505
|
+
event,
|
|
9506
|
+
...group.matcher === void 0 ? {} : { matcher: group.matcher }
|
|
9507
|
+
}))
|
|
9508
|
+
);
|
|
9509
|
+
appendExcludeBlock(cwd, runId, [relativeToCwd(cwd, targetPath)], {
|
|
9510
|
+
markerPrefix: hookExcludeMarkerPrefix
|
|
9511
|
+
});
|
|
9512
|
+
return manifest;
|
|
9513
|
+
}
|
|
9514
|
+
function cleanupBridgedHooks(manifest) {
|
|
9515
|
+
if (manifest.strategy === "symlink" && manifest.symlinkPath && manifest.symlinkTarget) {
|
|
9516
|
+
try {
|
|
9517
|
+
if (fs12.lstatSync(manifest.symlinkPath).isSymbolicLink() && fs12.readlinkSync(manifest.symlinkPath) === manifest.symlinkTarget) {
|
|
9518
|
+
fs12.unlinkSync(manifest.symlinkPath);
|
|
9519
|
+
}
|
|
9520
|
+
} catch (error2) {
|
|
9521
|
+
if (!isNodeError4(error2) || error2.code !== "ENOENT") {
|
|
9522
|
+
throw error2;
|
|
9523
|
+
}
|
|
9524
|
+
}
|
|
9525
|
+
for (const parent of [...manifest.createdParents ?? []].reverse()) {
|
|
9526
|
+
removeDirectoryIfEmpty2(parent);
|
|
9527
|
+
}
|
|
9528
|
+
}
|
|
9529
|
+
if (manifest.strategy === "transform" && manifest.writtenPath) {
|
|
9530
|
+
const file = readCodexFile(manifest.writtenPath);
|
|
9531
|
+
if (file) {
|
|
9532
|
+
const generatedPrefix = `[generated:${manifest.runId}]`;
|
|
9533
|
+
const preExistingEvents = new Set(manifest.preExistingEvents ?? []);
|
|
9534
|
+
const preExistingMatchers = new Set(
|
|
9535
|
+
(manifest.preExistingMatchers ?? []).map((group) => matcherKey(group.event, group.matcher))
|
|
9536
|
+
);
|
|
9537
|
+
const hooks = file.hooks ?? {};
|
|
9538
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
9539
|
+
hooks[event] = groups.filter((group) => {
|
|
9540
|
+
const priorLength = group.hooks.length;
|
|
9541
|
+
group.hooks = group.hooks.filter(
|
|
9542
|
+
(handler) => !handler.statusMessage?.startsWith(generatedPrefix)
|
|
9543
|
+
);
|
|
9544
|
+
return group.hooks.length > 0 || group.hooks.length === priorLength || preExistingMatchers.has(matcherKey(event, group.matcher));
|
|
9545
|
+
});
|
|
9546
|
+
if (hooks[event].length === 0 && !preExistingEvents.has(event)) {
|
|
9547
|
+
delete hooks[event];
|
|
9548
|
+
}
|
|
9549
|
+
}
|
|
9550
|
+
file.hooks = hooks;
|
|
9551
|
+
if (manifest.fileCreated && hasOnlyEmptyHooks(file)) {
|
|
9552
|
+
fs12.unlinkSync(manifest.writtenPath);
|
|
9553
|
+
} else {
|
|
9554
|
+
writeCodexFile(manifest.writtenPath, file);
|
|
9555
|
+
}
|
|
9556
|
+
}
|
|
9557
|
+
for (const parent of [...manifest.createdParents ?? []].reverse()) {
|
|
9558
|
+
removeDirectoryIfEmpty2(parent);
|
|
9559
|
+
}
|
|
9560
|
+
}
|
|
9561
|
+
removeExcludeBlock(manifest.cwd, manifest.runId, { markerPrefix: hookExcludeMarkerPrefix });
|
|
9562
|
+
}
|
|
9563
|
+
|
|
8867
9564
|
// packages/agent-spawn/src/skill-bridge.ts
|
|
8868
|
-
function
|
|
8869
|
-
if (!skills || skills.length === 0) {
|
|
9565
|
+
function bridgeResourcesForRun(agentId, cwd, skills, hooks) {
|
|
9566
|
+
if ((!skills || skills.length === 0) && !hooks) {
|
|
8870
9567
|
return void 0;
|
|
8871
9568
|
}
|
|
8872
|
-
const
|
|
8873
|
-
|
|
8874
|
-
|
|
9569
|
+
const runId = crypto.randomUUID();
|
|
9570
|
+
const manifests = {};
|
|
9571
|
+
try {
|
|
9572
|
+
if (skills && skills.length > 0) {
|
|
9573
|
+
manifests.skills = bridgeActiveSkills(agentId, cwd, skills, os7.homedir(), runId);
|
|
9574
|
+
for (const warning2 of manifests.skills.warnings) {
|
|
9575
|
+
logger.warn(warning2.message);
|
|
9576
|
+
}
|
|
9577
|
+
}
|
|
9578
|
+
if (hooks) {
|
|
9579
|
+
manifests.hooks = bridgeHooks(hooks.from, agentId, cwd, os7.homedir(), runId, {
|
|
9580
|
+
strategy: hooks.strategy === "auto" ? void 0 : hooks.strategy,
|
|
9581
|
+
scope: hooks.scope
|
|
9582
|
+
});
|
|
9583
|
+
for (const drop of manifests.hooks.drops) {
|
|
9584
|
+
logger.warn(
|
|
9585
|
+
`Dropped bridged hook event "${drop.source.event}" with handler type "${drop.source.handler.type}": ${drop.detail}`
|
|
9586
|
+
);
|
|
9587
|
+
}
|
|
9588
|
+
}
|
|
9589
|
+
} catch (error2) {
|
|
9590
|
+
cleanupResourcesForRun(manifests);
|
|
9591
|
+
throw error2;
|
|
8875
9592
|
}
|
|
8876
|
-
return
|
|
9593
|
+
return manifests;
|
|
8877
9594
|
}
|
|
8878
|
-
function
|
|
9595
|
+
function cleanupResourcesForRun(manifest) {
|
|
8879
9596
|
if (!manifest) {
|
|
8880
9597
|
return;
|
|
8881
9598
|
}
|
|
8882
|
-
|
|
9599
|
+
if (manifest.hooks) {
|
|
9600
|
+
cleanupBridgedHooks(manifest.hooks);
|
|
9601
|
+
}
|
|
9602
|
+
if (manifest.skills) {
|
|
9603
|
+
cleanupBridgedSkills(manifest.skills);
|
|
9604
|
+
}
|
|
8883
9605
|
}
|
|
8884
9606
|
|
|
8885
9607
|
// packages/agent-spawn/src/adapters/utils.ts
|
|
@@ -9005,21 +9727,21 @@ async function* adaptClaude(lines) {
|
|
|
9005
9727
|
if (blockType !== "tool_result") continue;
|
|
9006
9728
|
const kind = toolKindsById.get(item.tool_use_id);
|
|
9007
9729
|
toolKindsById.delete(item.tool_use_id);
|
|
9008
|
-
let
|
|
9730
|
+
let path55;
|
|
9009
9731
|
if (typeof item.content === "string") {
|
|
9010
|
-
|
|
9732
|
+
path55 = item.content;
|
|
9011
9733
|
} else {
|
|
9012
9734
|
try {
|
|
9013
|
-
|
|
9735
|
+
path55 = JSON.stringify(item.content);
|
|
9014
9736
|
} catch {
|
|
9015
|
-
|
|
9737
|
+
path55 = String(item.content);
|
|
9016
9738
|
}
|
|
9017
9739
|
}
|
|
9018
9740
|
yield {
|
|
9019
9741
|
event: "tool_complete",
|
|
9020
9742
|
id: item.tool_use_id,
|
|
9021
9743
|
kind,
|
|
9022
|
-
path:
|
|
9744
|
+
path: path55
|
|
9023
9745
|
};
|
|
9024
9746
|
}
|
|
9025
9747
|
}
|
|
@@ -9115,10 +9837,10 @@ async function* adaptCodex(lines) {
|
|
|
9115
9837
|
const kindFromStart = toolKindById.get(item.id);
|
|
9116
9838
|
const kind = kindFromStart ?? (itemType === "command_execution" ? "exec" : itemType === "file_edit" ? "edit" : "other");
|
|
9117
9839
|
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;
|
|
9118
|
-
const
|
|
9840
|
+
const path55 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
|
|
9119
9841
|
toolTitleById.delete(item.id);
|
|
9120
9842
|
toolKindById.delete(item.id);
|
|
9121
|
-
yield { event: "tool_complete", id: item.id, kind, path:
|
|
9843
|
+
yield { event: "tool_complete", id: item.id, kind, path: path55 };
|
|
9122
9844
|
}
|
|
9123
9845
|
}
|
|
9124
9846
|
}
|
|
@@ -9646,7 +10368,7 @@ function spawnStreaming(options) {
|
|
|
9646
10368
|
};
|
|
9647
10369
|
}
|
|
9648
10370
|
};
|
|
9649
|
-
const manifest =
|
|
10371
|
+
const manifest = bridgeResourcesForRun(options.agentId, cwd, options.skills, options.hooks);
|
|
9650
10372
|
void (async () => {
|
|
9651
10373
|
try {
|
|
9652
10374
|
for await (const output of adapter(queue.lines())) {
|
|
@@ -9697,7 +10419,7 @@ function spawnStreaming(options) {
|
|
|
9697
10419
|
...ctx.logFile && !result.logFile ? { logFile: ctx.logFile } : {}
|
|
9698
10420
|
};
|
|
9699
10421
|
} finally {
|
|
9700
|
-
|
|
10422
|
+
cleanupResourcesForRun(manifest);
|
|
9701
10423
|
}
|
|
9702
10424
|
})();
|
|
9703
10425
|
return {
|
|
@@ -9833,7 +10555,7 @@ async function runSpawn(agentId, options, context) {
|
|
|
9833
10555
|
return { stdout: "", stderr: "", exitCode: 0 };
|
|
9834
10556
|
}
|
|
9835
10557
|
const cwd = options.cwd ?? process.cwd();
|
|
9836
|
-
const manifest =
|
|
10558
|
+
const manifest = bridgeResourcesForRun(agentId, cwd, options.skills, options.hooks);
|
|
9837
10559
|
let logFd;
|
|
9838
10560
|
try {
|
|
9839
10561
|
const logFilePath = resolveSpawnLogPath(options);
|
|
@@ -9901,7 +10623,7 @@ async function runSpawn(agentId, options, context) {
|
|
|
9901
10623
|
};
|
|
9902
10624
|
} finally {
|
|
9903
10625
|
closeSpawnLog(logFd);
|
|
9904
|
-
|
|
10626
|
+
cleanupResourcesForRun(manifest);
|
|
9905
10627
|
}
|
|
9906
10628
|
}
|
|
9907
10629
|
spawn4.retry = createSpawnRetry((service, options) => {
|
|
@@ -9923,12 +10645,12 @@ function resolveSpawnLogPath(options) {
|
|
|
9923
10645
|
if (!options.logDir || !options.logFileName) {
|
|
9924
10646
|
return void 0;
|
|
9925
10647
|
}
|
|
9926
|
-
return
|
|
10648
|
+
return path46.join(options.logDir, options.logFileName);
|
|
9927
10649
|
}
|
|
9928
10650
|
function openSpawnLog(filePath) {
|
|
9929
10651
|
try {
|
|
9930
|
-
|
|
9931
|
-
return
|
|
10652
|
+
mkdirSync5(path46.dirname(filePath), { recursive: true });
|
|
10653
|
+
return openSync2(filePath, "a");
|
|
9932
10654
|
} catch {
|
|
9933
10655
|
return void 0;
|
|
9934
10656
|
}
|
|
@@ -9943,7 +10665,7 @@ function appendSpawnLog(fd, chunk) {
|
|
|
9943
10665
|
function closeSpawnLog(fd) {
|
|
9944
10666
|
if (fd === void 0) return;
|
|
9945
10667
|
try {
|
|
9946
|
-
|
|
10668
|
+
closeSync2(fd);
|
|
9947
10669
|
} catch {
|
|
9948
10670
|
}
|
|
9949
10671
|
}
|
|
@@ -9952,7 +10674,7 @@ function closeSpawnLog(fd) {
|
|
|
9952
10674
|
var DEFAULT_ACTIVITY_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
9953
10675
|
|
|
9954
10676
|
// packages/agent-spawn/src/acp/replay.ts
|
|
9955
|
-
import
|
|
10677
|
+
import path47 from "node:path";
|
|
9956
10678
|
import { homedir as homedir2 } from "node:os";
|
|
9957
10679
|
import { open as open2, readdir as readdir5 } from "node:fs/promises";
|
|
9958
10680
|
import { createInterface } from "node:readline";
|
|
@@ -9971,13 +10693,13 @@ import { homedir } from "node:os";
|
|
|
9971
10693
|
import { join } from "node:path";
|
|
9972
10694
|
|
|
9973
10695
|
// packages/agent-spawn/src/acp/middlewares/spawn-log.ts
|
|
9974
|
-
import
|
|
10696
|
+
import path48 from "node:path";
|
|
9975
10697
|
import { homedir as homedir3 } from "node:os";
|
|
9976
10698
|
import { mkdir as mkdir5, open as open3 } from "node:fs/promises";
|
|
9977
10699
|
|
|
9978
10700
|
// packages/memory/src/tokens.ts
|
|
9979
|
-
import * as
|
|
9980
|
-
import
|
|
10701
|
+
import * as fs13 from "node:fs/promises";
|
|
10702
|
+
import path49 from "node:path";
|
|
9981
10703
|
|
|
9982
10704
|
// packages/tokenfill/dist/tokenizer.js
|
|
9983
10705
|
import { get_encoding } from "tiktoken";
|
|
@@ -10018,7 +10740,7 @@ function countTokens(text5) {
|
|
|
10018
10740
|
}
|
|
10019
10741
|
|
|
10020
10742
|
// packages/tokenfill/dist/corpus.js
|
|
10021
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
10743
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync6 } from "node:fs";
|
|
10022
10744
|
import { dirname, join as join2 } from "node:path";
|
|
10023
10745
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
10024
10746
|
var CORPUS_ARTICLE_SEPARATOR = "\n\n";
|
|
@@ -10031,7 +10753,7 @@ function loadBuiltInCorpusArticles() {
|
|
|
10031
10753
|
if (corpusFileNames.length === 0) {
|
|
10032
10754
|
throw new Error(`No built-in corpus markdown files found in ${corpusDirectoryPath}`);
|
|
10033
10755
|
}
|
|
10034
|
-
return corpusFileNames.map((fileName) =>
|
|
10756
|
+
return corpusFileNames.map((fileName) => readFileSync6(join2(corpusDirectoryPath, fileName), "utf8").trim());
|
|
10035
10757
|
}
|
|
10036
10758
|
var BUILT_IN_CORPUS_ARTICLES = loadBuiltInCorpusArticles();
|
|
10037
10759
|
|
|
@@ -10041,7 +10763,7 @@ var builtInCorpusByteLength = Buffer.byteLength(builtInCorpusText, "utf8");
|
|
|
10041
10763
|
|
|
10042
10764
|
// packages/memory/src/tokens.ts
|
|
10043
10765
|
async function computeTokenStats(root) {
|
|
10044
|
-
if (!await
|
|
10766
|
+
if (!await pathExists5(root)) {
|
|
10045
10767
|
return {
|
|
10046
10768
|
memoryTokens: 0,
|
|
10047
10769
|
sourceTokens: 0,
|
|
@@ -10061,13 +10783,13 @@ async function computeTokenStats(root) {
|
|
|
10061
10783
|
}
|
|
10062
10784
|
}
|
|
10063
10785
|
}
|
|
10064
|
-
const repoRoot =
|
|
10786
|
+
const repoRoot = path49.resolve(root, "..", "..");
|
|
10065
10787
|
let sourceTokens = 0;
|
|
10066
10788
|
const missingSources = [];
|
|
10067
10789
|
for (const sourcePath of sourcePaths) {
|
|
10068
|
-
const absPath =
|
|
10790
|
+
const absPath = path49.isAbsolute(sourcePath) ? sourcePath : path49.resolve(repoRoot, sourcePath);
|
|
10069
10791
|
try {
|
|
10070
|
-
const content = await
|
|
10792
|
+
const content = await fs13.readFile(absPath, "utf8");
|
|
10071
10793
|
sourceTokens += countTokens(content);
|
|
10072
10794
|
} catch (error2) {
|
|
10073
10795
|
if (isMissing4(error2)) {
|
|
@@ -10086,9 +10808,9 @@ async function computeTokenStats(root) {
|
|
|
10086
10808
|
missingSources
|
|
10087
10809
|
};
|
|
10088
10810
|
}
|
|
10089
|
-
async function
|
|
10811
|
+
async function pathExists5(targetPath) {
|
|
10090
10812
|
try {
|
|
10091
|
-
await
|
|
10813
|
+
await fs13.stat(targetPath);
|
|
10092
10814
|
return true;
|
|
10093
10815
|
} catch (error2) {
|
|
10094
10816
|
if (isMissing4(error2)) {
|
|
@@ -10116,10 +10838,10 @@ function resolveRunners(overrides) {
|
|
|
10116
10838
|
async function ingest(root, opts, runners) {
|
|
10117
10839
|
const resolved = resolveRunners(runners);
|
|
10118
10840
|
const source = await materializeSource(opts.source);
|
|
10119
|
-
const indexMdBytes = await
|
|
10841
|
+
const indexMdBytes = await fs14.readFile(path50.join(root, MEMORY_INDEX_RELPATH));
|
|
10120
10842
|
const configOptions = {
|
|
10121
|
-
fs:
|
|
10122
|
-
filePath:
|
|
10843
|
+
fs: fs14,
|
|
10844
|
+
filePath: path50.join(inferRepoRoot(root), "poe-code.json")
|
|
10123
10845
|
};
|
|
10124
10846
|
const agentId = await resolveAgent(configOptions, opts.agent ?? null) ?? opts.agent ?? "claude-code";
|
|
10125
10847
|
const key = resolved.computeIngestKey({
|
|
@@ -10199,7 +10921,7 @@ function buildIngestPrompt(root, sourceLabel, sourceText) {
|
|
|
10199
10921
|
}
|
|
10200
10922
|
async function materializeSource(source) {
|
|
10201
10923
|
if (source.kind === "file") {
|
|
10202
|
-
const bytes = await
|
|
10924
|
+
const bytes = await fs14.readFile(source.absPath);
|
|
10203
10925
|
return {
|
|
10204
10926
|
label: source.absPath,
|
|
10205
10927
|
bytes,
|
|
@@ -10209,7 +10931,7 @@ async function materializeSource(source) {
|
|
|
10209
10931
|
throw new Error("URL ingest not implemented yet.");
|
|
10210
10932
|
}
|
|
10211
10933
|
function inferRepoRoot(root) {
|
|
10212
|
-
return
|
|
10934
|
+
return path50.resolve(root, "..", "..");
|
|
10213
10935
|
}
|
|
10214
10936
|
async function runWithTimeout(promise, timeoutMs) {
|
|
10215
10937
|
return await new Promise((resolve2, reject) => {
|
|
@@ -11016,7 +11738,7 @@ var agentMcpConfigs = {
|
|
|
11016
11738
|
}
|
|
11017
11739
|
};
|
|
11018
11740
|
var supportedAgents3 = Object.keys(agentMcpConfigs);
|
|
11019
|
-
function
|
|
11741
|
+
function resolveAgentSupport3(input, registry = agentMcpConfigs) {
|
|
11020
11742
|
const resolvedId = resolveAgentId(input);
|
|
11021
11743
|
if (!resolvedId) {
|
|
11022
11744
|
return { status: "unknown", input };
|
|
@@ -11028,10 +11750,10 @@ function resolveAgentSupport2(input, registry = agentMcpConfigs) {
|
|
|
11028
11750
|
return { status: "supported", input, id: resolvedId, config };
|
|
11029
11751
|
}
|
|
11030
11752
|
function isSupported(agentId) {
|
|
11031
|
-
return
|
|
11753
|
+
return resolveAgentSupport3(agentId).status === "supported";
|
|
11032
11754
|
}
|
|
11033
|
-
function
|
|
11034
|
-
const support =
|
|
11755
|
+
function getAgentConfig3(agentId) {
|
|
11756
|
+
const support = resolveAgentSupport3(agentId);
|
|
11035
11757
|
return support.status === "supported" ? support.config : void 0;
|
|
11036
11758
|
}
|
|
11037
11759
|
function resolveConfigPath2(config, platform) {
|
|
@@ -11042,7 +11764,7 @@ function resolveConfigPath2(config, platform) {
|
|
|
11042
11764
|
}
|
|
11043
11765
|
|
|
11044
11766
|
// packages/agent-mcp-config/src/apply.ts
|
|
11045
|
-
import
|
|
11767
|
+
import path51 from "node:path";
|
|
11046
11768
|
import { parse as parseYaml3, stringify as stringifyYaml2 } from "yaml";
|
|
11047
11769
|
|
|
11048
11770
|
// packages/agent-mcp-config/src/shapes.ts
|
|
@@ -11134,7 +11856,7 @@ function getShapeTransformer(shape) {
|
|
|
11134
11856
|
|
|
11135
11857
|
// packages/agent-mcp-config/src/apply.ts
|
|
11136
11858
|
function getConfigDirectory(configPath) {
|
|
11137
|
-
return
|
|
11859
|
+
return path51.dirname(configPath);
|
|
11138
11860
|
}
|
|
11139
11861
|
var UnsupportedAgentError2 = class extends Error {
|
|
11140
11862
|
constructor(agentId) {
|
|
@@ -11160,9 +11882,9 @@ function expandHomePath(configPath, homeDir) {
|
|
|
11160
11882
|
return homeDir;
|
|
11161
11883
|
}
|
|
11162
11884
|
if (configPath.startsWith("~/")) {
|
|
11163
|
-
return
|
|
11885
|
+
return path51.join(homeDir, configPath.slice(2));
|
|
11164
11886
|
}
|
|
11165
|
-
return
|
|
11887
|
+
return path51.join(homeDir, configPath.slice(1));
|
|
11166
11888
|
}
|
|
11167
11889
|
function parseYamlDocument(content) {
|
|
11168
11890
|
if (content.trim() === "") {
|
|
@@ -11195,7 +11917,7 @@ async function writeYamlConfig(configPath, document, options) {
|
|
|
11195
11917
|
return;
|
|
11196
11918
|
}
|
|
11197
11919
|
const absolutePath = expandHomePath(configPath, options.homeDir);
|
|
11198
|
-
const configDir =
|
|
11920
|
+
const configDir = path51.dirname(absolutePath);
|
|
11199
11921
|
await options.fs.mkdir(configDir, { recursive: true });
|
|
11200
11922
|
await options.fs.writeFile(absolutePath, serializeYamlDocument(document), {
|
|
11201
11923
|
encoding: "utf8"
|
|
@@ -11222,7 +11944,7 @@ async function configure2(agentId, server, options) {
|
|
|
11222
11944
|
if (!isSupported(agentId)) {
|
|
11223
11945
|
throw new UnsupportedAgentError2(agentId);
|
|
11224
11946
|
}
|
|
11225
|
-
const config =
|
|
11947
|
+
const config = getAgentConfig3(agentId);
|
|
11226
11948
|
const configPath = resolveConfigPath2(config, options.platform);
|
|
11227
11949
|
const shapeTransformer = getShapeTransformer(config.shape);
|
|
11228
11950
|
const shaped = shapeTransformer(server);
|
|
@@ -11278,7 +12000,7 @@ async function unconfigure2(agentId, serverName, options) {
|
|
|
11278
12000
|
if (!isSupported(agentId)) {
|
|
11279
12001
|
throw new UnsupportedAgentError2(agentId);
|
|
11280
12002
|
}
|
|
11281
|
-
const config =
|
|
12003
|
+
const config = getAgentConfig3(agentId);
|
|
11282
12004
|
const configPath = resolveConfigPath2(config, options.platform);
|
|
11283
12005
|
if (config.format === "yaml") {
|
|
11284
12006
|
const document = await readYamlConfig(configPath, options);
|
|
@@ -11372,8 +12094,8 @@ async function installMemory(options) {
|
|
|
11372
12094
|
}
|
|
11373
12095
|
|
|
11374
12096
|
// packages/memory/src/query.ts
|
|
11375
|
-
import * as
|
|
11376
|
-
import
|
|
12097
|
+
import * as fs15 from "node:fs/promises";
|
|
12098
|
+
import path52 from "node:path";
|
|
11377
12099
|
async function queryMemory(root, options) {
|
|
11378
12100
|
const pages = await listPages(root);
|
|
11379
12101
|
if (pages.length === 0) {
|
|
@@ -11386,8 +12108,8 @@ async function queryMemory(root, options) {
|
|
|
11386
12108
|
};
|
|
11387
12109
|
}
|
|
11388
12110
|
const configOptions = {
|
|
11389
|
-
fs:
|
|
11390
|
-
filePath:
|
|
12111
|
+
fs: fs15,
|
|
12112
|
+
filePath: path52.join(inferRepoRoot2(root), "poe-code.json")
|
|
11391
12113
|
};
|
|
11392
12114
|
const agentId = await resolveAgent(configOptions, options.agent ?? null) ?? options.agent ?? "claude-code";
|
|
11393
12115
|
const context = await selectQueryContext(root, options.question, options.budget);
|
|
@@ -11402,7 +12124,7 @@ async function queryMemory(root, options) {
|
|
|
11402
12124
|
}
|
|
11403
12125
|
async function selectQueryContext(root, question, budget) {
|
|
11404
12126
|
const [indexText, pages] = await Promise.all([
|
|
11405
|
-
|
|
12127
|
+
fs15.readFile(path52.join(root, MEMORY_INDEX_RELPATH), "utf8"),
|
|
11406
12128
|
listPages(root)
|
|
11407
12129
|
]);
|
|
11408
12130
|
const indexTokens = countTokens(indexText);
|
|
@@ -11481,12 +12203,12 @@ function tokenize(text5) {
|
|
|
11481
12203
|
return text5.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length > 0);
|
|
11482
12204
|
}
|
|
11483
12205
|
function inferRepoRoot2(root) {
|
|
11484
|
-
return
|
|
12206
|
+
return path52.resolve(root, "..", "..");
|
|
11485
12207
|
}
|
|
11486
12208
|
|
|
11487
12209
|
// packages/memory/src/explain.ts
|
|
11488
|
-
import * as
|
|
11489
|
-
import
|
|
12210
|
+
import * as fs16 from "node:fs/promises";
|
|
12211
|
+
import path53 from "node:path";
|
|
11490
12212
|
async function explainPage(root, options) {
|
|
11491
12213
|
const targetPage = await readPageIfPresent(root, options.relPath);
|
|
11492
12214
|
if (targetPage === void 0) {
|
|
@@ -11508,8 +12230,8 @@ async function explainPage(root, options) {
|
|
|
11508
12230
|
throw new Error(`budget too small; needs at least ${tokensUsed} tokens`);
|
|
11509
12231
|
}
|
|
11510
12232
|
const configOptions = {
|
|
11511
|
-
fs:
|
|
11512
|
-
filePath:
|
|
12233
|
+
fs: fs16,
|
|
12234
|
+
filePath: path53.join(inferRepoRoot3(root), "poe-code.json")
|
|
11513
12235
|
};
|
|
11514
12236
|
const agentId = await resolveAgent(configOptions, options.agent ?? null) ?? options.agent ?? "claude-code";
|
|
11515
12237
|
const response = await spawn4(agentId, { prompt });
|
|
@@ -11558,7 +12280,7 @@ async function readPageIfPresent(root, relPath) {
|
|
|
11558
12280
|
}
|
|
11559
12281
|
}
|
|
11560
12282
|
function inferRepoRoot3(root) {
|
|
11561
|
-
return
|
|
12283
|
+
return path53.resolve(root, "..", "..");
|
|
11562
12284
|
}
|
|
11563
12285
|
|
|
11564
12286
|
// packages/memory/src/explain.cli.ts
|
|
@@ -11571,9 +12293,9 @@ async function runMemoryExplain(input) {
|
|
|
11571
12293
|
}
|
|
11572
12294
|
|
|
11573
12295
|
// packages/memory/src/handle.ts
|
|
11574
|
-
import
|
|
12296
|
+
import path54 from "node:path";
|
|
11575
12297
|
function openMemory(opts) {
|
|
11576
|
-
if (!
|
|
12298
|
+
if (!path54.isAbsolute(opts.root)) {
|
|
11577
12299
|
throw new Error(`openMemory: root must be absolute, got ${opts.root}`);
|
|
11578
12300
|
}
|
|
11579
12301
|
const root = opts.root;
|