poe-code 3.0.203 → 3.0.204
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/cli/commands/braintrust.d.ts +3 -0
- package/dist/cli/commands/braintrust.js +77 -0
- package/dist/cli/commands/braintrust.js.map +1 -0
- package/dist/cli/commands/configure.d.ts +1 -0
- package/dist/cli/commands/configure.js +197 -0
- package/dist/cli/commands/configure.js.map +1 -1
- package/dist/cli/commands/experiment.js +42 -5
- package/dist/cli/commands/experiment.js.map +1 -1
- package/dist/cli/commands/harness.d.ts +3 -0
- package/dist/cli/commands/harness.js +260 -0
- package/dist/cli/commands/harness.js.map +1 -0
- package/dist/cli/commands/pipeline.js +58 -24
- package/dist/cli/commands/pipeline.js.map +1 -1
- package/dist/cli/commands/ralph.js +8 -3
- package/dist/cli/commands/ralph.js.map +1 -1
- package/dist/cli/commands/runtime/build.d.ts +7 -0
- package/dist/cli/commands/runtime/build.js +128 -0
- package/dist/cli/commands/runtime/build.js.map +1 -0
- package/dist/cli/commands/runtime/index.d.ts +3 -0
- package/dist/cli/commands/runtime/index.js +14 -0
- package/dist/cli/commands/runtime/index.js.map +1 -0
- package/dist/cli/commands/runtime/init.d.ts +7 -0
- package/dist/cli/commands/runtime/init.js +39 -0
- package/dist/cli/commands/runtime/init.js.map +1 -0
- package/dist/cli/commands/runtime/jobs/attach.d.ts +3 -0
- package/dist/cli/commands/runtime/jobs/attach.js +35 -0
- package/dist/cli/commands/runtime/jobs/attach.js.map +1 -0
- package/dist/cli/commands/runtime/jobs/index.d.ts +3 -0
- package/dist/cli/commands/runtime/jobs/index.js +16 -0
- package/dist/cli/commands/runtime/jobs/index.js.map +1 -0
- package/dist/cli/commands/runtime/jobs/logs.d.ts +3 -0
- package/dist/cli/commands/runtime/jobs/logs.js +27 -0
- package/dist/cli/commands/runtime/jobs/logs.js.map +1 -0
- package/dist/cli/commands/runtime/jobs/ls.d.ts +3 -0
- package/dist/cli/commands/runtime/jobs/ls.js +60 -0
- package/dist/cli/commands/runtime/jobs/ls.js.map +1 -0
- package/dist/cli/commands/runtime/jobs/sandbox.d.ts +3 -0
- package/dist/cli/commands/runtime/jobs/sandbox.js +15 -0
- package/dist/cli/commands/runtime/jobs/sandbox.js.map +1 -0
- package/dist/cli/commands/runtime/jobs/shared.d.ts +22 -0
- package/dist/cli/commands/runtime/jobs/shared.js +124 -0
- package/dist/cli/commands/runtime/jobs/shared.js.map +1 -0
- package/dist/cli/commands/runtime/jobs/stop.d.ts +3 -0
- package/dist/cli/commands/runtime/jobs/stop.js +31 -0
- package/dist/cli/commands/runtime/jobs/stop.js.map +1 -0
- package/dist/cli/commands/runtime/jobs/sync.d.ts +3 -0
- package/dist/cli/commands/runtime/jobs/sync.js +25 -0
- package/dist/cli/commands/runtime/jobs/sync.js.map +1 -0
- package/dist/cli/commands/runtime/shared.d.ts +20 -0
- package/dist/cli/commands/runtime/shared.js +69 -0
- package/dist/cli/commands/runtime/shared.js.map +1 -0
- package/dist/cli/commands/runtime/templates/clear.d.ts +3 -0
- package/dist/cli/commands/runtime/templates/clear.js +53 -0
- package/dist/cli/commands/runtime/templates/clear.js.map +1 -0
- package/dist/cli/commands/runtime/templates/index.d.ts +3 -0
- package/dist/cli/commands/runtime/templates/index.js +10 -0
- package/dist/cli/commands/runtime/templates/index.js.map +1 -0
- package/dist/cli/commands/runtime/templates/ls.d.ts +3 -0
- package/dist/cli/commands/runtime/templates/ls.js +52 -0
- package/dist/cli/commands/runtime/templates/ls.js.map +1 -0
- package/dist/cli/commands/runtime-options.d.ts +1 -0
- package/dist/cli/commands/runtime-options.js +5 -2
- package/dist/cli/commands/runtime-options.js.map +1 -1
- package/dist/cli/commands/spawn.js +27 -4
- package/dist/cli/commands/spawn.js.map +1 -1
- package/dist/cli/program.js +17 -1
- package/dist/cli/program.js.map +1 -1
- package/dist/index.js +24192 -2429
- package/dist/index.js.map +4 -4
- package/dist/providers/claude-code.js +1692 -93
- package/dist/providers/claude-code.js.map +4 -4
- package/dist/providers/codex.js +1692 -93
- package/dist/providers/codex.js.map +4 -4
- package/dist/providers/goose.js +1687 -88
- package/dist/providers/goose.js.map +4 -4
- package/dist/providers/kimi.js +1692 -93
- package/dist/providers/kimi.js.map +4 -4
- package/dist/providers/opencode.js +1692 -93
- package/dist/providers/opencode.js.map +4 -4
- package/dist/providers/poe-agent.js +1580 -308
- package/dist/providers/poe-agent.js.map +4 -4
- package/dist/providers/spawn-options.d.ts +4 -1
- package/dist/sdk/experiment.js +1 -0
- package/dist/sdk/experiment.js.map +1 -1
- package/dist/sdk/ralph.js +108 -16
- package/dist/sdk/ralph.js.map +1 -1
- package/dist/sdk/spawn.js +11 -4
- package/dist/sdk/spawn.js.map +1 -1
- package/dist/sdk/types.d.ts +12 -1
- package/dist/utils/command-checks.js +2 -29
- package/dist/utils/command-checks.js.map +1 -1
- package/package.json +12 -7
- package/packages/design-system/dist/components/help-formatter-plain.d.ts +4 -0
- package/packages/design-system/dist/components/help-formatter-plain.js +132 -0
- package/packages/design-system/dist/components/help-formatter.d.ts +13 -0
- package/packages/design-system/dist/components/help-formatter.js +116 -7
- package/packages/design-system/dist/components/index.d.ts +2 -2
- package/packages/design-system/dist/components/index.js +1 -1
- package/packages/design-system/dist/components/text.d.ts +1 -0
- package/packages/design-system/dist/components/text.js +8 -0
- package/packages/design-system/dist/index.d.ts +3 -2
- package/packages/design-system/dist/index.js +2 -1
- package/packages/memory/dist/index.js +1201 -115
- package/packages/memory/dist/index.js.map +4 -4
- package/packages/superintendent/dist/commands/run.d.ts +10 -0
- package/packages/superintendent/dist/commands/run.js +96 -49
- package/packages/superintendent/dist/commands/superintendent-group.d.ts +6 -0
- package/packages/superintendent/dist/runtime/agent-runner.d.ts +1 -0
- package/packages/superintendent/dist/runtime/agent-runner.js +4 -2
- package/packages/superintendent/dist/runtime/loop.d.ts +1 -0
|
@@ -94,6 +94,11 @@ var runtimeConfigScope = {
|
|
|
94
94
|
default: "",
|
|
95
95
|
doc: "Path to the Docker build context"
|
|
96
96
|
},
|
|
97
|
+
workspace_dir: {
|
|
98
|
+
type: "string",
|
|
99
|
+
default: "/workspace",
|
|
100
|
+
doc: "Sandbox-local workspace directory for E2B runtime upload, execution, and download"
|
|
101
|
+
},
|
|
97
102
|
engine: {
|
|
98
103
|
type: "string",
|
|
99
104
|
default: "",
|
|
@@ -115,6 +120,11 @@ var runtimeConfigScope = {
|
|
|
115
120
|
default: "",
|
|
116
121
|
doc: "Prebuilt E2B template id"
|
|
117
122
|
},
|
|
123
|
+
from_template: {
|
|
124
|
+
type: "string",
|
|
125
|
+
default: "",
|
|
126
|
+
doc: "Existing E2B template alias to extend instead of using the Dockerfile FROM image"
|
|
127
|
+
},
|
|
118
128
|
cpu: {
|
|
119
129
|
type: "json",
|
|
120
130
|
default: void 0,
|
|
@@ -138,11 +148,6 @@ var runtimeConfigScope = {
|
|
|
138
148
|
default: void 0,
|
|
139
149
|
parse: parseOptionalNumber,
|
|
140
150
|
doc: "Hours to keep an E2B sandbox alive after job exit"
|
|
141
|
-
},
|
|
142
|
-
api_key_env: {
|
|
143
|
-
type: "string",
|
|
144
|
-
default: "",
|
|
145
|
-
doc: "Environment variable name containing the E2B API key"
|
|
146
151
|
}
|
|
147
152
|
}
|
|
148
153
|
};
|
|
@@ -162,6 +167,7 @@ function parseRunner(raw) {
|
|
|
162
167
|
detach: parseOptionalBoolean(record.detach, "runner.detach") ?? false,
|
|
163
168
|
upload_max_file_mb: uploadMaxFileMb,
|
|
164
169
|
download_conflict: parseDownloadConflict(record.download_conflict),
|
|
170
|
+
sync: parseRunnerSync(record.sync),
|
|
165
171
|
workspace: parseRunnerWorkspace(record.workspace)
|
|
166
172
|
});
|
|
167
173
|
}
|
|
@@ -200,13 +206,14 @@ function parseRuntime(raw) {
|
|
|
200
206
|
...shared,
|
|
201
207
|
type,
|
|
202
208
|
template_id: parseOptionalString(record.template_id),
|
|
209
|
+
from_template: parseOptionalString(record.from_template),
|
|
203
210
|
dockerfile: parseOptionalString(record.dockerfile),
|
|
204
211
|
build_context: parseOptionalString(record.build_context),
|
|
212
|
+
workspace_dir: parseWorkspaceDir(record.workspace_dir),
|
|
205
213
|
cpu: parseOptionalNumber(record.cpu),
|
|
206
214
|
memory_mb: parseOptionalNumber(record.memory_mb),
|
|
207
215
|
timeout_minutes: parseOptionalNumber(record.timeout_minutes),
|
|
208
|
-
preserve_after_exit_hours: preserveAfterExitHours
|
|
209
|
-
api_key_env: parseOptionalString(record.api_key_env) ?? "E2B_API_KEY"
|
|
216
|
+
preserve_after_exit_hours: preserveAfterExitHours
|
|
210
217
|
});
|
|
211
218
|
}
|
|
212
219
|
return {
|
|
@@ -295,11 +302,23 @@ function parseRuntimeType(value) {
|
|
|
295
302
|
}
|
|
296
303
|
throw new Error('type: expected "host", "docker", or "e2b".');
|
|
297
304
|
}
|
|
305
|
+
function parseWorkspaceDir(value) {
|
|
306
|
+
const workspaceDir = parseOptionalString(value) ?? "/workspace";
|
|
307
|
+
if (!path2.posix.isAbsolute(workspaceDir)) {
|
|
308
|
+
throw new Error("workspace_dir: expected an absolute sandbox path.");
|
|
309
|
+
}
|
|
310
|
+
let normalized = path2.posix.normalize(workspaceDir);
|
|
311
|
+
while (normalized.length > 1 && normalized.endsWith("/")) {
|
|
312
|
+
normalized = normalized.slice(0, -1);
|
|
313
|
+
}
|
|
314
|
+
return normalized;
|
|
315
|
+
}
|
|
298
316
|
function createDefaultRunnerScope() {
|
|
299
317
|
return {
|
|
300
318
|
detach: false,
|
|
301
319
|
upload_max_file_mb: 100,
|
|
302
320
|
download_conflict: "refuse",
|
|
321
|
+
sync: "both",
|
|
303
322
|
workspace: {
|
|
304
323
|
exclude: [...defaultWorkspaceExclude]
|
|
305
324
|
}
|
|
@@ -330,6 +349,15 @@ function parseDownloadConflict(value) {
|
|
|
330
349
|
}
|
|
331
350
|
throw new Error('runner.download_conflict: expected "refuse" or "overwrite".');
|
|
332
351
|
}
|
|
352
|
+
function parseRunnerSync(value) {
|
|
353
|
+
if (value === void 0) {
|
|
354
|
+
return "both";
|
|
355
|
+
}
|
|
356
|
+
if (value === "both" || value === "upload" || value === "none") {
|
|
357
|
+
return value;
|
|
358
|
+
}
|
|
359
|
+
throw new Error('runner.sync: expected "both", "upload", or "none".');
|
|
360
|
+
}
|
|
333
361
|
function parseBuildArgs(value) {
|
|
334
362
|
if (value === void 0) {
|
|
335
363
|
return {};
|
|
@@ -442,6 +470,43 @@ function defineScope(scope, schema) {
|
|
|
442
470
|
schema
|
|
443
471
|
};
|
|
444
472
|
}
|
|
473
|
+
var integrationsConfigScope = defineScope("integrations", {
|
|
474
|
+
braintrust: {
|
|
475
|
+
type: "json",
|
|
476
|
+
default: {
|
|
477
|
+
enabled: false
|
|
478
|
+
},
|
|
479
|
+
parse: parseBraintrustIntegrationConfig,
|
|
480
|
+
doc: "Braintrust integration configuration"
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
function parseBraintrustIntegrationConfig(value) {
|
|
484
|
+
if (!isRecord(value)) {
|
|
485
|
+
throw new Error("expected an object");
|
|
486
|
+
}
|
|
487
|
+
const enabled = value.enabled === void 0 ? false : value.enabled;
|
|
488
|
+
if (typeof enabled !== "boolean") {
|
|
489
|
+
throw new Error("enabled must be a boolean");
|
|
490
|
+
}
|
|
491
|
+
return {
|
|
492
|
+
enabled,
|
|
493
|
+
...optionalStringEntry("apiKey", value.apiKey),
|
|
494
|
+
...optionalStringEntry("apiUrl", value.apiUrl),
|
|
495
|
+
...optionalStringEntry("project", value.project)
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
function optionalStringEntry(key, value) {
|
|
499
|
+
if (value === void 0) {
|
|
500
|
+
return {};
|
|
501
|
+
}
|
|
502
|
+
if (typeof value !== "string") {
|
|
503
|
+
throw new Error(`${key} must be a string`);
|
|
504
|
+
}
|
|
505
|
+
return { [key]: value };
|
|
506
|
+
}
|
|
507
|
+
function isRecord(value) {
|
|
508
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
509
|
+
}
|
|
445
510
|
|
|
446
511
|
// packages/poe-code-config/src/plan-scope.ts
|
|
447
512
|
var planConfigScope = defineScope("plan", {
|
|
@@ -546,11 +611,11 @@ function stripBom(content) {
|
|
|
546
611
|
function mergeLayers(layers) {
|
|
547
612
|
return mergeObjectLayers(layers, []);
|
|
548
613
|
}
|
|
549
|
-
function mergeObjectLayers(layers,
|
|
614
|
+
function mergeObjectLayers(layers, path42) {
|
|
550
615
|
const data = {};
|
|
551
616
|
const sources = {};
|
|
552
617
|
for (const key of collectKeys(layers)) {
|
|
553
|
-
const resolved = resolveKey(layers, key,
|
|
618
|
+
const resolved = resolveKey(layers, key, path42);
|
|
554
619
|
if (resolved === void 0) {
|
|
555
620
|
continue;
|
|
556
621
|
}
|
|
@@ -568,7 +633,7 @@ function collectKeys(layers) {
|
|
|
568
633
|
}
|
|
569
634
|
return [...keys];
|
|
570
635
|
}
|
|
571
|
-
function resolveKey(layers, key,
|
|
636
|
+
function resolveKey(layers, key, path42) {
|
|
572
637
|
let winningSource;
|
|
573
638
|
let winningValue;
|
|
574
639
|
const objectLayers = [];
|
|
@@ -598,9 +663,9 @@ function resolveKey(layers, key, path38) {
|
|
|
598
663
|
if (winningSource === void 0) {
|
|
599
664
|
return void 0;
|
|
600
665
|
}
|
|
601
|
-
const fullPath = buildPath(
|
|
666
|
+
const fullPath = buildPath(path42, key);
|
|
602
667
|
if (isPlainObject(winningValue)) {
|
|
603
|
-
const merged = mergeObjectLayers(objectLayers, [...
|
|
668
|
+
const merged = mergeObjectLayers(objectLayers, [...path42, key]);
|
|
604
669
|
return {
|
|
605
670
|
value: merged.data,
|
|
606
671
|
sources: {
|
|
@@ -625,8 +690,8 @@ function isWinningCandidate(key, value) {
|
|
|
625
690
|
}
|
|
626
691
|
return true;
|
|
627
692
|
}
|
|
628
|
-
function buildPath(
|
|
629
|
-
return [...
|
|
693
|
+
function buildPath(path42, key) {
|
|
694
|
+
return [...path42, key].join(".");
|
|
630
695
|
}
|
|
631
696
|
function isPlainObject(value) {
|
|
632
697
|
if (value === null || Array.isArray(value) || typeof value !== "object") {
|
|
@@ -1260,16 +1325,16 @@ function getConfigFormat(pathOrFormat) {
|
|
|
1260
1325
|
}
|
|
1261
1326
|
return formatRegistry[formatName];
|
|
1262
1327
|
}
|
|
1263
|
-
function detectFormat2(
|
|
1264
|
-
const ext = getExtension(
|
|
1328
|
+
function detectFormat2(path42) {
|
|
1329
|
+
const ext = getExtension(path42);
|
|
1265
1330
|
return extensionMap[ext];
|
|
1266
1331
|
}
|
|
1267
|
-
function getExtension(
|
|
1268
|
-
const lastDot =
|
|
1332
|
+
function getExtension(path42) {
|
|
1333
|
+
const lastDot = path42.lastIndexOf(".");
|
|
1269
1334
|
if (lastDot === -1) {
|
|
1270
1335
|
return "";
|
|
1271
1336
|
}
|
|
1272
|
-
return
|
|
1337
|
+
return path42.slice(lastDot).toLowerCase();
|
|
1273
1338
|
}
|
|
1274
1339
|
|
|
1275
1340
|
// packages/config-mutations/src/execution/path-utils.ts
|
|
@@ -1977,7 +2042,7 @@ async function parseStoredDocument(fs14, filePath, raw) {
|
|
|
1977
2042
|
}
|
|
1978
2043
|
}
|
|
1979
2044
|
function normalizeDocument(value) {
|
|
1980
|
-
if (!
|
|
2045
|
+
if (!isRecord2(value)) {
|
|
1981
2046
|
return {};
|
|
1982
2047
|
}
|
|
1983
2048
|
const document = {};
|
|
@@ -1990,7 +2055,7 @@ function normalizeDocument(value) {
|
|
|
1990
2055
|
return document;
|
|
1991
2056
|
}
|
|
1992
2057
|
function normalizeScopeValues(value) {
|
|
1993
|
-
if (!
|
|
2058
|
+
if (!isRecord2(value)) {
|
|
1994
2059
|
return {};
|
|
1995
2060
|
}
|
|
1996
2061
|
const normalized = {};
|
|
@@ -2022,7 +2087,7 @@ function createInvalidBackupPath(filePath) {
|
|
|
2022
2087
|
const baseName = path7.basename(filePath);
|
|
2023
2088
|
return path7.join(directory, `${baseName}.invalid-${createTimestamp()}.json`);
|
|
2024
2089
|
}
|
|
2025
|
-
function
|
|
2090
|
+
function isRecord2(value) {
|
|
2026
2091
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
2027
2092
|
}
|
|
2028
2093
|
function resolveConfigPath(homeDir) {
|
|
@@ -2139,7 +2204,7 @@ function mergeScope(scope, baseScope, overrideScope) {
|
|
|
2139
2204
|
...Object.fromEntries(scopeEntries)
|
|
2140
2205
|
};
|
|
2141
2206
|
}
|
|
2142
|
-
function mergeRuntimeScope(baseScope, overrideScope,
|
|
2207
|
+
function mergeRuntimeScope(baseScope, overrideScope, path42 = []) {
|
|
2143
2208
|
const merged = {};
|
|
2144
2209
|
const keys = /* @__PURE__ */ new Set([...Object.keys(baseScope), ...Object.keys(overrideScope)]);
|
|
2145
2210
|
for (const key of keys) {
|
|
@@ -2151,22 +2216,22 @@ function mergeRuntimeScope(baseScope, overrideScope, path38 = []) {
|
|
|
2151
2216
|
}
|
|
2152
2217
|
continue;
|
|
2153
2218
|
}
|
|
2154
|
-
if (isRuntimeConcatenativeArray([...
|
|
2219
|
+
if (isRuntimeConcatenativeArray([...path42, key]) && Array.isArray(baseValue) && Array.isArray(overrideValue)) {
|
|
2155
2220
|
merged[key] = [...baseValue, ...overrideValue];
|
|
2156
2221
|
continue;
|
|
2157
2222
|
}
|
|
2158
|
-
if (
|
|
2159
|
-
merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...
|
|
2223
|
+
if (isRecord3(baseValue) && isRecord3(overrideValue)) {
|
|
2224
|
+
merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...path42, key]);
|
|
2160
2225
|
continue;
|
|
2161
2226
|
}
|
|
2162
2227
|
merged[key] = overrideValue;
|
|
2163
2228
|
}
|
|
2164
2229
|
return merged;
|
|
2165
2230
|
}
|
|
2166
|
-
function isRuntimeConcatenativeArray(
|
|
2167
|
-
return
|
|
2231
|
+
function isRuntimeConcatenativeArray(path42) {
|
|
2232
|
+
return path42.join(".") === "mounts" || path42.join(".") === "runner.workspace.exclude";
|
|
2168
2233
|
}
|
|
2169
|
-
function
|
|
2234
|
+
function isRecord3(value) {
|
|
2170
2235
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
2171
2236
|
}
|
|
2172
2237
|
|
|
@@ -2285,8 +2350,8 @@ function isPidRunning(pid) {
|
|
|
2285
2350
|
}
|
|
2286
2351
|
function createDefaultFs() {
|
|
2287
2352
|
return {
|
|
2288
|
-
open: (
|
|
2289
|
-
readFile: (
|
|
2353
|
+
open: (path42, flags) => fsPromises.open(path42, flags),
|
|
2354
|
+
readFile: (path42, encoding) => fsPromises.readFile(path42, encoding),
|
|
2290
2355
|
stat: fsPromises.stat,
|
|
2291
2356
|
unlink: fsPromises.unlink
|
|
2292
2357
|
};
|
|
@@ -2579,12 +2644,12 @@ function parseJobEntry(content) {
|
|
|
2579
2644
|
return parsed;
|
|
2580
2645
|
}
|
|
2581
2646
|
function isJobEntry(value) {
|
|
2582
|
-
return
|
|
2647
|
+
return isRecord4(value) && typeof value.id === "string" && typeof value.env_id === "string" && typeof value.env_kind === "string" && typeof value.tool === "string" && Array.isArray(value.argv) && value.argv.every((arg) => typeof arg === "string") && typeof value.cwd === "string" && typeof value.started_at === "string" && isJobStatus(value.status) && (value.exit_code === void 0 || typeof value.exit_code === "number") && (value.exited_at === void 0 || typeof value.exited_at === "string") && (value.log_file === void 0 || typeof value.log_file === "string");
|
|
2583
2648
|
}
|
|
2584
2649
|
function isJobStatus(value) {
|
|
2585
2650
|
return value === "pending" || value === "running" || value === "exited" || value === "killed" || value === "lost";
|
|
2586
2651
|
}
|
|
2587
|
-
function
|
|
2652
|
+
function isRecord4(value) {
|
|
2588
2653
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
2589
2654
|
}
|
|
2590
2655
|
|
|
@@ -2653,7 +2718,7 @@ function createEmptyState() {
|
|
|
2653
2718
|
};
|
|
2654
2719
|
}
|
|
2655
2720
|
function normalizeTemplateState(value) {
|
|
2656
|
-
if (!
|
|
2721
|
+
if (!isRecord5(value)) {
|
|
2657
2722
|
return createEmptyState();
|
|
2658
2723
|
}
|
|
2659
2724
|
return {
|
|
@@ -2662,7 +2727,7 @@ function normalizeTemplateState(value) {
|
|
|
2662
2727
|
};
|
|
2663
2728
|
}
|
|
2664
2729
|
function normalizeTemplateEntries(value) {
|
|
2665
|
-
if (!
|
|
2730
|
+
if (!isRecord5(value)) {
|
|
2666
2731
|
return {};
|
|
2667
2732
|
}
|
|
2668
2733
|
const entries = {};
|
|
@@ -2674,9 +2739,9 @@ function normalizeTemplateEntries(value) {
|
|
|
2674
2739
|
return entries;
|
|
2675
2740
|
}
|
|
2676
2741
|
function isTemplateEntry(value) {
|
|
2677
|
-
return
|
|
2742
|
+
return isRecord5(value) && typeof value.hash === "string" && typeof value.runtime_type === "string" && typeof value.dockerfile_path === "string" && typeof value.built_at === "string" && (value.template_id === void 0 || typeof value.template_id === "string") && (value.image === void 0 || typeof value.image === "string");
|
|
2678
2743
|
}
|
|
2679
|
-
function
|
|
2744
|
+
function isRecord5(value) {
|
|
2680
2745
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
2681
2746
|
}
|
|
2682
2747
|
|
|
@@ -2878,7 +2943,7 @@ function parseYamlFrontmatter(yamlBlock) {
|
|
|
2878
2943
|
if (parsed === null) {
|
|
2879
2944
|
return {};
|
|
2880
2945
|
}
|
|
2881
|
-
if (!
|
|
2946
|
+
if (!isRecord6(parsed)) {
|
|
2882
2947
|
throw new Error("YAML frontmatter must parse to an object.");
|
|
2883
2948
|
}
|
|
2884
2949
|
return parsed;
|
|
@@ -2909,13 +2974,13 @@ function parseSources(value) {
|
|
|
2909
2974
|
if (typeof item === "string") {
|
|
2910
2975
|
return parseSourceRef(item);
|
|
2911
2976
|
}
|
|
2912
|
-
if (!
|
|
2977
|
+
if (!isRecord6(item)) {
|
|
2913
2978
|
throw new Error('Invalid "sources" frontmatter. Expected each source to be a string or object.');
|
|
2914
2979
|
}
|
|
2915
|
-
const
|
|
2980
|
+
const path42 = readRequiredString(item.path, "sources[].path");
|
|
2916
2981
|
const startLine = readOptionalPositiveInteger(item.startLine, "sources[].startLine");
|
|
2917
2982
|
const endLine = readOptionalPositiveInteger(item.endLine, "sources[].endLine");
|
|
2918
|
-
return parseSourceRef(serializeSourceRef({ path:
|
|
2983
|
+
return parseSourceRef(serializeSourceRef({ path: path42, ...startLine === void 0 ? {} : { startLine }, ...endLine === void 0 ? {} : { endLine } }));
|
|
2919
2984
|
});
|
|
2920
2985
|
}
|
|
2921
2986
|
function readOptionalString(value, field) {
|
|
@@ -2948,7 +3013,7 @@ function assertValidLineNumber(line, value) {
|
|
|
2948
3013
|
throw new Error(`Invalid source ref "${value}": line numbers must be positive integers.`);
|
|
2949
3014
|
}
|
|
2950
3015
|
}
|
|
2951
|
-
function
|
|
3016
|
+
function isRecord6(value) {
|
|
2952
3017
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2953
3018
|
}
|
|
2954
3019
|
|
|
@@ -3971,7 +4036,7 @@ function parseOlderThan(value) {
|
|
|
3971
4036
|
|
|
3972
4037
|
// packages/memory/src/ingest.ts
|
|
3973
4038
|
import * as fs11 from "node:fs/promises";
|
|
3974
|
-
import
|
|
4039
|
+
import path35 from "node:path";
|
|
3975
4040
|
|
|
3976
4041
|
// packages/agent-spawn/src/register-factories.ts
|
|
3977
4042
|
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
@@ -4145,6 +4210,38 @@ function wrapForLogTee(argv, jobId) {
|
|
|
4145
4210
|
].join(" && ");
|
|
4146
4211
|
return ["sh", "-c", script];
|
|
4147
4212
|
}
|
|
4213
|
+
async function* streamLogFile(env, jobId, opts) {
|
|
4214
|
+
const fs14 = env.fs ?? nodeFs2;
|
|
4215
|
+
const file = jobLogPath(jobId);
|
|
4216
|
+
let byteOffset = opts.sinceByte ?? 0;
|
|
4217
|
+
while (true) {
|
|
4218
|
+
if (opts.since !== void 0 && !await wasModifiedSince(fs14, file, opts.since)) {
|
|
4219
|
+
await waitForLogChange(fs14, file);
|
|
4220
|
+
continue;
|
|
4221
|
+
}
|
|
4222
|
+
const result = await readLogChunk(fs14, file, byteOffset);
|
|
4223
|
+
if (result !== null) {
|
|
4224
|
+
byteOffset = result.nextByteOffset;
|
|
4225
|
+
yield result.chunk;
|
|
4226
|
+
continue;
|
|
4227
|
+
}
|
|
4228
|
+
await waitForLogChange(fs14, file);
|
|
4229
|
+
}
|
|
4230
|
+
}
|
|
4231
|
+
async function wasModifiedSince(fs14, file, since) {
|
|
4232
|
+
if (fs14.promises.stat === void 0) {
|
|
4233
|
+
return true;
|
|
4234
|
+
}
|
|
4235
|
+
try {
|
|
4236
|
+
const stat7 = await fs14.promises.stat(file);
|
|
4237
|
+
return stat7.mtimeMs >= since.getTime();
|
|
4238
|
+
} catch (error2) {
|
|
4239
|
+
if (isNodeError(error2) && error2.code === "ENOENT") {
|
|
4240
|
+
return false;
|
|
4241
|
+
}
|
|
4242
|
+
throw error2;
|
|
4243
|
+
}
|
|
4244
|
+
}
|
|
4148
4245
|
async function waitForExit(env, jobId, opts = {}) {
|
|
4149
4246
|
const fs14 = env.fs ?? nodeFs2;
|
|
4150
4247
|
const file = jobExitPath(jobId);
|
|
@@ -4168,6 +4265,19 @@ function jobLogPath(jobId) {
|
|
|
4168
4265
|
function jobExitPath(jobId) {
|
|
4169
4266
|
return `${JOB_DIR}/${jobId}.exit`;
|
|
4170
4267
|
}
|
|
4268
|
+
async function readLogChunk(fs14, file, byteOffset) {
|
|
4269
|
+
const contents = await readFileIfExists2(fs14, file);
|
|
4270
|
+
if (contents === null || byteOffset >= contents.byteLength) {
|
|
4271
|
+
return null;
|
|
4272
|
+
}
|
|
4273
|
+
return {
|
|
4274
|
+
chunk: {
|
|
4275
|
+
byteOffset,
|
|
4276
|
+
data: contents.subarray(byteOffset).toString("utf8")
|
|
4277
|
+
},
|
|
4278
|
+
nextByteOffset: contents.byteLength
|
|
4279
|
+
};
|
|
4280
|
+
}
|
|
4171
4281
|
async function readTextFileIfExists(fs14, file) {
|
|
4172
4282
|
const contents = await readFileIfExists2(fs14, file);
|
|
4173
4283
|
return contents?.toString("utf8") ?? null;
|
|
@@ -4183,6 +4293,27 @@ async function readFileIfExists2(fs14, file) {
|
|
|
4183
4293
|
throw error2;
|
|
4184
4294
|
}
|
|
4185
4295
|
}
|
|
4296
|
+
async function waitForLogChange(fs14, file) {
|
|
4297
|
+
const watch = fs14.watch;
|
|
4298
|
+
if (typeof watch !== "function") {
|
|
4299
|
+
await sleep3(POLL_INTERVAL_MS);
|
|
4300
|
+
return;
|
|
4301
|
+
}
|
|
4302
|
+
await new Promise((resolve2) => {
|
|
4303
|
+
let watcher = null;
|
|
4304
|
+
const timer = setTimeout(done, POLL_INTERVAL_MS);
|
|
4305
|
+
function done() {
|
|
4306
|
+
clearTimeout(timer);
|
|
4307
|
+
watcher?.close();
|
|
4308
|
+
resolve2();
|
|
4309
|
+
}
|
|
4310
|
+
try {
|
|
4311
|
+
watcher = watch(file, done);
|
|
4312
|
+
} catch {
|
|
4313
|
+
done();
|
|
4314
|
+
}
|
|
4315
|
+
});
|
|
4316
|
+
}
|
|
4186
4317
|
function sleep3(ms, signal) {
|
|
4187
4318
|
return new Promise((resolve2, reject) => {
|
|
4188
4319
|
let timer = null;
|
|
@@ -4217,6 +4348,35 @@ function isNodeError(error2) {
|
|
|
4217
4348
|
|
|
4218
4349
|
// packages/agent-harness-tools/src/run-poe-command.ts
|
|
4219
4350
|
import { randomBytes } from "node:crypto";
|
|
4351
|
+
|
|
4352
|
+
// packages/agent-harness-tools/src/binary-exists.ts
|
|
4353
|
+
function createBinaryExistsDetectors(binaryName) {
|
|
4354
|
+
const commonPaths = [
|
|
4355
|
+
`/usr/local/bin/${binaryName}`,
|
|
4356
|
+
`/usr/bin/${binaryName}`,
|
|
4357
|
+
`$HOME/.local/bin/${binaryName}`,
|
|
4358
|
+
`$HOME/.claude/local/bin/${binaryName}`
|
|
4359
|
+
];
|
|
4360
|
+
return [
|
|
4361
|
+
{
|
|
4362
|
+
command: "which",
|
|
4363
|
+
args: [binaryName],
|
|
4364
|
+
validate: (result) => result.exitCode === 0
|
|
4365
|
+
},
|
|
4366
|
+
{
|
|
4367
|
+
command: "where",
|
|
4368
|
+
args: [binaryName],
|
|
4369
|
+
validate: (result) => result.exitCode === 0 && result.stdout.trim().length > 0
|
|
4370
|
+
},
|
|
4371
|
+
{
|
|
4372
|
+
command: "sh",
|
|
4373
|
+
args: ["-c", commonPaths.map((p) => `test -f "${p}"`).join(" || ")],
|
|
4374
|
+
validate: (result) => result.exitCode === 0
|
|
4375
|
+
}
|
|
4376
|
+
];
|
|
4377
|
+
}
|
|
4378
|
+
|
|
4379
|
+
// packages/agent-harness-tools/src/run-poe-command.ts
|
|
4220
4380
|
var ULID_ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
4221
4381
|
async function runPoeCommand(opts) {
|
|
4222
4382
|
const jobId = createUlid();
|
|
@@ -4237,12 +4397,18 @@ async function runPoeCommand(opts) {
|
|
|
4237
4397
|
let shouldClose = true;
|
|
4238
4398
|
try {
|
|
4239
4399
|
const upload = env.uploadWorkspace();
|
|
4400
|
+
await Promise.all([pendingJob, upload]);
|
|
4401
|
+
await configureE2bSpawnAgentIfAvailable({
|
|
4402
|
+
env,
|
|
4403
|
+
openSpec: opts.openSpec,
|
|
4404
|
+
factoryType: opts.factory.type
|
|
4405
|
+
});
|
|
4240
4406
|
const argv = wrapCommand ? wrapForLogTee(opts.openSpec.jobLabel.argv, jobId) : opts.openSpec.jobLabel.argv;
|
|
4241
4407
|
const handle = execution?.tty ? env.shell() : env.exec({
|
|
4242
4408
|
command: argv[0],
|
|
4243
4409
|
args: argv.slice(1),
|
|
4244
4410
|
cwd: opts.openSpec.cwd,
|
|
4245
|
-
env:
|
|
4411
|
+
env: resolveExecutionEnv(opts.openSpec),
|
|
4246
4412
|
stdin: execution?.stdin ?? "inherit",
|
|
4247
4413
|
stdout: execution?.stdout ?? "pipe",
|
|
4248
4414
|
stderr: execution?.stderr ?? "pipe",
|
|
@@ -4252,15 +4418,19 @@ async function runPoeCommand(opts) {
|
|
|
4252
4418
|
handle.stdin?.setDefaultEncoding("utf8");
|
|
4253
4419
|
handle.stdin?.end(execution.input);
|
|
4254
4420
|
}
|
|
4255
|
-
const runningJob =
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
})
|
|
4261
|
-
);
|
|
4421
|
+
const runningJob = opts.state.jobs.update(jobId, {
|
|
4422
|
+
status: "running",
|
|
4423
|
+
env_id: env.id,
|
|
4424
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4425
|
+
});
|
|
4262
4426
|
if (opts.detach) {
|
|
4263
4427
|
await runningJob;
|
|
4428
|
+
setDetachedJobContext(env, {
|
|
4429
|
+
id: jobId,
|
|
4430
|
+
tool: opts.openSpec.jobLabel.tool,
|
|
4431
|
+
argv: opts.openSpec.jobLabel.argv
|
|
4432
|
+
});
|
|
4433
|
+
await env.detach();
|
|
4264
4434
|
shouldClose = false;
|
|
4265
4435
|
return { kind: "detached", jobId, envId: env.id };
|
|
4266
4436
|
}
|
|
@@ -4292,6 +4462,97 @@ async function runPoeCommand(opts) {
|
|
|
4292
4462
|
}
|
|
4293
4463
|
}
|
|
4294
4464
|
}
|
|
4465
|
+
async function configureE2bSpawnAgentIfAvailable(opts) {
|
|
4466
|
+
if (opts.factoryType !== "e2b") {
|
|
4467
|
+
return;
|
|
4468
|
+
}
|
|
4469
|
+
const agentId = resolveAgentId(opts.openSpec.jobLabel.tool);
|
|
4470
|
+
const agent = allAgents.find((candidate) => candidate.id === agentId);
|
|
4471
|
+
const binaryName = agent?.binaryName;
|
|
4472
|
+
if (!agentId || !binaryName) {
|
|
4473
|
+
return;
|
|
4474
|
+
}
|
|
4475
|
+
const commandEnv = resolveExecutionEnv(opts.openSpec);
|
|
4476
|
+
const exists = await binaryExists(opts.env, {
|
|
4477
|
+
binaryName,
|
|
4478
|
+
cwd: opts.openSpec.cwd,
|
|
4479
|
+
env: commandEnv
|
|
4480
|
+
});
|
|
4481
|
+
if (!exists) {
|
|
4482
|
+
return;
|
|
4483
|
+
}
|
|
4484
|
+
const result = await runProbeCommand(opts.env, {
|
|
4485
|
+
command: "poe-code",
|
|
4486
|
+
args: ["configure", "--yes", "--provider", "poe", agentId],
|
|
4487
|
+
cwd: opts.openSpec.cwd,
|
|
4488
|
+
env: commandEnv
|
|
4489
|
+
});
|
|
4490
|
+
if (result.exitCode !== 0) {
|
|
4491
|
+
throw new Error(
|
|
4492
|
+
`Failed to configure ${agentId} for Poe inside E2B sandbox.
|
|
4493
|
+
${formatProbeResult(result)}`
|
|
4494
|
+
);
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4497
|
+
async function binaryExists(env, opts) {
|
|
4498
|
+
for (const detector of createBinaryExistsDetectors(opts.binaryName)) {
|
|
4499
|
+
const result = await runProbeCommand(env, {
|
|
4500
|
+
...detector,
|
|
4501
|
+
cwd: opts.cwd,
|
|
4502
|
+
env: opts.env
|
|
4503
|
+
});
|
|
4504
|
+
if (detector.validate(result)) {
|
|
4505
|
+
return true;
|
|
4506
|
+
}
|
|
4507
|
+
}
|
|
4508
|
+
return false;
|
|
4509
|
+
}
|
|
4510
|
+
function resolveExecutionEnv(openSpec) {
|
|
4511
|
+
const execution = openSpec.execution;
|
|
4512
|
+
return execution?.env ?? openSpec.env;
|
|
4513
|
+
}
|
|
4514
|
+
async function runProbeCommand(env, spec) {
|
|
4515
|
+
const handle = env.exec({
|
|
4516
|
+
command: spec.command,
|
|
4517
|
+
args: spec.args,
|
|
4518
|
+
cwd: spec.cwd,
|
|
4519
|
+
env: spec.env,
|
|
4520
|
+
stdin: "ignore",
|
|
4521
|
+
stdout: "pipe",
|
|
4522
|
+
stderr: "pipe"
|
|
4523
|
+
});
|
|
4524
|
+
const stdout = readStream(handle.stdout);
|
|
4525
|
+
const stderr = readStream(handle.stderr);
|
|
4526
|
+
const result = await handle.result;
|
|
4527
|
+
return {
|
|
4528
|
+
exitCode: result.exitCode,
|
|
4529
|
+
stdout: await stdout,
|
|
4530
|
+
stderr: await stderr
|
|
4531
|
+
};
|
|
4532
|
+
}
|
|
4533
|
+
function readStream(stream) {
|
|
4534
|
+
if (!stream) {
|
|
4535
|
+
return Promise.resolve("");
|
|
4536
|
+
}
|
|
4537
|
+
return new Promise((resolve2, reject) => {
|
|
4538
|
+
let output = "";
|
|
4539
|
+
stream.setEncoding("utf8");
|
|
4540
|
+
stream.on("data", (chunk) => {
|
|
4541
|
+
output += chunk.toString();
|
|
4542
|
+
});
|
|
4543
|
+
stream.on("error", reject);
|
|
4544
|
+
stream.on("end", () => resolve2(output));
|
|
4545
|
+
});
|
|
4546
|
+
}
|
|
4547
|
+
function formatProbeResult(result) {
|
|
4548
|
+
return [
|
|
4549
|
+
`Exit code: ${result.exitCode}`,
|
|
4550
|
+
result.stdout.trim() ? `stdout:
|
|
4551
|
+
${result.stdout.trim()}` : "",
|
|
4552
|
+
result.stderr.trim() ? `stderr:
|
|
4553
|
+
${result.stderr.trim()}` : ""
|
|
4554
|
+
].filter(Boolean).join("\n");
|
|
4555
|
+
}
|
|
4295
4556
|
async function runSync(opts) {
|
|
4296
4557
|
const execution = opts.openSpec.execution;
|
|
4297
4558
|
const capture = execution?.captureOutput === true;
|
|
@@ -4303,7 +4564,9 @@ async function runSync(opts) {
|
|
|
4303
4564
|
const download = await opts.env.downloadWorkspace({
|
|
4304
4565
|
conflictPolicy: opts.openSpec.runner?.download_conflict ?? "refuse"
|
|
4305
4566
|
});
|
|
4306
|
-
|
|
4567
|
+
if (opts.closeAfterDownload !== false) {
|
|
4568
|
+
await opts.env.close();
|
|
4569
|
+
}
|
|
4307
4570
|
return {
|
|
4308
4571
|
exitCode,
|
|
4309
4572
|
download,
|
|
@@ -4459,6 +4722,10 @@ function toLogStreamEnv(env) {
|
|
|
4459
4722
|
const candidate = env;
|
|
4460
4723
|
return candidate.fs === void 0 ? {} : { fs: candidate.fs };
|
|
4461
4724
|
}
|
|
4725
|
+
function setDetachedJobContext(env, context) {
|
|
4726
|
+
const candidate = env;
|
|
4727
|
+
candidate.setDetachedJobContext?.(context);
|
|
4728
|
+
}
|
|
4462
4729
|
function isPromiseLike(value) {
|
|
4463
4730
|
return typeof value.then === "function";
|
|
4464
4731
|
}
|
|
@@ -4501,10 +4768,13 @@ function registerExecutionEnvFactory(factory) {
|
|
|
4501
4768
|
executionEnvFactories.set(factory.type, factory);
|
|
4502
4769
|
}
|
|
4503
4770
|
function selectExecutionEnv(runtime) {
|
|
4504
|
-
|
|
4771
|
+
return selectExecutionEnvFactory(runtime.type);
|
|
4772
|
+
}
|
|
4773
|
+
function selectExecutionEnvFactory(type) {
|
|
4774
|
+
const factory = executionEnvFactories.get(type);
|
|
4505
4775
|
if (factory === void 0) {
|
|
4506
4776
|
throw new Error(
|
|
4507
|
-
`No execution environment factory registered for runtime type "${
|
|
4777
|
+
`No execution environment factory registered for runtime type "${type}".`
|
|
4508
4778
|
);
|
|
4509
4779
|
}
|
|
4510
4780
|
return factory;
|
|
@@ -4513,8 +4783,10 @@ function selectExecutionEnv(runtime) {
|
|
|
4513
4783
|
// packages/agent-harness-tools/src/poe-command-execution.ts
|
|
4514
4784
|
function resolvePoeCommandExecution(input) {
|
|
4515
4785
|
const homeDir = input.context?.homeDir ?? os3.homedir();
|
|
4516
|
-
const
|
|
4517
|
-
const
|
|
4786
|
+
const runtimeConfigCwd = input.runtimeConfigCwd ?? input.cwd;
|
|
4787
|
+
const loaded = loadRuntimeConfig(runtimeConfigCwd, homeDir);
|
|
4788
|
+
const config = applyRuntimeOverrides(loaded, input.runtime, runtimeConfigCwd);
|
|
4789
|
+
const resolved = resolveRuntime({ cwd: runtimeConfigCwd, config });
|
|
4518
4790
|
const factory = selectExecutionEnv(resolved.runtime);
|
|
4519
4791
|
const state = input.context?.state ?? loadState(homeDir);
|
|
4520
4792
|
return {
|
|
@@ -4523,6 +4795,7 @@ function resolvePoeCommandExecution(input) {
|
|
|
4523
4795
|
state,
|
|
4524
4796
|
openSpec: {
|
|
4525
4797
|
cwd: input.cwd,
|
|
4798
|
+
runtimeCwd: runtimeConfigCwd,
|
|
4526
4799
|
runtime: resolved.runtime,
|
|
4527
4800
|
runner: config.runner,
|
|
4528
4801
|
state,
|
|
@@ -4538,10 +4811,11 @@ function resolvePoeCommandExecution(input) {
|
|
|
4538
4811
|
}
|
|
4539
4812
|
function applyRuntimeOverrides(config, overrides, cwd = process.cwd()) {
|
|
4540
4813
|
if (!overrides) {
|
|
4541
|
-
return config;
|
|
4814
|
+
return { runtime: config.runtime, runner: config.runner };
|
|
4542
4815
|
}
|
|
4816
|
+
const base = "rawScope" in config && config.rawScope ? { ...config.rawScope } : { ...config.runtime };
|
|
4543
4817
|
const runtime = parseRuntime({
|
|
4544
|
-
...
|
|
4818
|
+
...base,
|
|
4545
4819
|
...overrides.runtime !== void 0 ? { type: overrides.runtime } : {},
|
|
4546
4820
|
...overrides.runtimeImage !== void 0 ? { image: overrides.runtimeImage } : {},
|
|
4547
4821
|
...overrides.runtimeTemplate !== void 0 ? { template_id: overrides.runtimeTemplate } : {},
|
|
@@ -4551,7 +4825,8 @@ function applyRuntimeOverrides(config, overrides, cwd = process.cwd()) {
|
|
|
4551
4825
|
runtime,
|
|
4552
4826
|
runner: {
|
|
4553
4827
|
...config.runner,
|
|
4554
|
-
...overrides.detach === true ? { detach: true } : {}
|
|
4828
|
+
...overrides.detach === true ? { detach: true } : {},
|
|
4829
|
+
...overrides.runnerSync !== void 0 ? { sync: overrides.runnerSync } : {}
|
|
4555
4830
|
}
|
|
4556
4831
|
};
|
|
4557
4832
|
}
|
|
@@ -4569,6 +4844,7 @@ function loadRuntimeConfig(cwd, homeDir) {
|
|
|
4569
4844
|
);
|
|
4570
4845
|
const runtimeScope = resolveScope(runtimeConfigScope.schema, document.runtime, process.env);
|
|
4571
4846
|
return {
|
|
4847
|
+
rawScope: { ...runtimeScope },
|
|
4572
4848
|
runtime: parseRuntime(runtimeScope),
|
|
4573
4849
|
runner: runtimeScope.runner
|
|
4574
4850
|
};
|
|
@@ -4865,14 +5141,15 @@ var dockerExecutionEnvFactory = {
|
|
|
4865
5141
|
context
|
|
4866
5142
|
});
|
|
4867
5143
|
},
|
|
4868
|
-
async attach(envId) {
|
|
5144
|
+
async attach(envId, context) {
|
|
4869
5145
|
const engine = detectEngine();
|
|
4870
5146
|
return createDockerEnv({
|
|
4871
5147
|
id: envId,
|
|
4872
|
-
spec: createAttachedSpec(),
|
|
5148
|
+
spec: createAttachedSpec(context?.cwd),
|
|
4873
5149
|
runner: createHostRunner(),
|
|
4874
5150
|
engine,
|
|
4875
|
-
context: detectContext()
|
|
5151
|
+
context: detectContext(),
|
|
5152
|
+
attachedJobId: context?.jobId
|
|
4876
5153
|
});
|
|
4877
5154
|
}
|
|
4878
5155
|
};
|
|
@@ -4880,7 +5157,7 @@ function createDockerEnv(input) {
|
|
|
4880
5157
|
const containerRef = input.id;
|
|
4881
5158
|
return {
|
|
4882
5159
|
id: containerRef,
|
|
4883
|
-
job: null,
|
|
5160
|
+
job: input.attachedJobId === void 0 ? null : createContainerJob(containerRef, input.runner, input.engine, input.context, input.attachedJobId),
|
|
4884
5161
|
async uploadWorkspace() {
|
|
4885
5162
|
const tempDir = mkdtempSync(path26.join(tmpdir(), "poe-docker-upload-"));
|
|
4886
5163
|
const archivePath = path26.join(tempDir, "workspace.tar");
|
|
@@ -5015,35 +5292,57 @@ async function resolveImage(input) {
|
|
|
5015
5292
|
if (input.runtime.image !== void 0) {
|
|
5016
5293
|
return input.runtime.image;
|
|
5017
5294
|
}
|
|
5295
|
+
const result = await buildDockerRuntimeTemplate({
|
|
5296
|
+
cwd: input.spec.cwd,
|
|
5297
|
+
runtime: input.runtime,
|
|
5298
|
+
state: input.spec.state,
|
|
5299
|
+
runner: input.runner
|
|
5300
|
+
});
|
|
5301
|
+
return result.image;
|
|
5302
|
+
}
|
|
5303
|
+
async function buildDockerRuntimeTemplate(input) {
|
|
5304
|
+
const runner = input.runner ?? createHostRunner();
|
|
5305
|
+
const engine = input.runtime.engine ?? detectEngine();
|
|
5306
|
+
const context = detectContext();
|
|
5018
5307
|
const dockerfilePath = path26.resolve(
|
|
5019
|
-
input.
|
|
5308
|
+
input.cwd,
|
|
5020
5309
|
input.runtime.dockerfile ?? path26.join(".poe-code", "Dockerfile")
|
|
5021
5310
|
);
|
|
5022
|
-
const buildContext = path26.resolve(input.
|
|
5311
|
+
const buildContext = path26.resolve(input.cwd, input.runtime.build_context ?? ".");
|
|
5023
5312
|
const dockerfileBytes = await readFile10(dockerfilePath);
|
|
5024
5313
|
const hash = hashDockerTemplate(dockerfileBytes, input.runtime.build_args ?? {});
|
|
5025
|
-
const cached2 = await input.
|
|
5314
|
+
const cached2 = input.force ? null : await input.state?.templates.get("docker", hash);
|
|
5026
5315
|
if (cached2?.image !== void 0) {
|
|
5027
|
-
return
|
|
5316
|
+
return {
|
|
5317
|
+
backend: "docker",
|
|
5318
|
+
hash,
|
|
5319
|
+
image: cached2.image,
|
|
5320
|
+
cached: true
|
|
5321
|
+
};
|
|
5028
5322
|
}
|
|
5029
5323
|
const image = `poe-code/local:${hash}`;
|
|
5030
5324
|
await buildImage({
|
|
5031
|
-
runner
|
|
5032
|
-
engine
|
|
5033
|
-
context
|
|
5325
|
+
runner,
|
|
5326
|
+
engine,
|
|
5327
|
+
context,
|
|
5034
5328
|
image,
|
|
5035
5329
|
dockerfilePath,
|
|
5036
5330
|
buildContext,
|
|
5037
5331
|
buildArgs: input.runtime.build_args ?? {}
|
|
5038
5332
|
});
|
|
5039
|
-
await input.
|
|
5333
|
+
await input.state?.templates.put("docker", {
|
|
5040
5334
|
hash,
|
|
5041
5335
|
image,
|
|
5042
5336
|
runtime_type: "docker",
|
|
5043
5337
|
dockerfile_path: dockerfilePath,
|
|
5044
5338
|
built_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
5045
5339
|
});
|
|
5046
|
-
return
|
|
5340
|
+
return {
|
|
5341
|
+
backend: "docker",
|
|
5342
|
+
hash,
|
|
5343
|
+
image,
|
|
5344
|
+
cached: false
|
|
5345
|
+
};
|
|
5047
5346
|
}
|
|
5048
5347
|
function hashDockerTemplate(dockerfileBytes, buildArgs) {
|
|
5049
5348
|
const hash = createHash4("sha256");
|
|
@@ -5089,8 +5388,8 @@ function parseDockerRuntime(runtime) {
|
|
|
5089
5388
|
}
|
|
5090
5389
|
async function runAndRead(runner, spec) {
|
|
5091
5390
|
const handle = runner.exec(spec);
|
|
5092
|
-
const stdout =
|
|
5093
|
-
const stderr =
|
|
5391
|
+
const stdout = readStream2(handle.stdout);
|
|
5392
|
+
const stderr = readStream2(handle.stderr);
|
|
5094
5393
|
const result = await handle.result;
|
|
5095
5394
|
const output = await stdout;
|
|
5096
5395
|
if (result.exitCode !== 0) {
|
|
@@ -5105,7 +5404,7 @@ ${errorOutput}` : ""}`
|
|
|
5105
5404
|
async function runOrThrow(runner, spec) {
|
|
5106
5405
|
await runAndRead(runner, spec);
|
|
5107
5406
|
}
|
|
5108
|
-
async function
|
|
5407
|
+
async function readStream2(stream) {
|
|
5109
5408
|
if (stream === null) {
|
|
5110
5409
|
return "";
|
|
5111
5410
|
}
|
|
@@ -5128,9 +5427,9 @@ function buildEnvArgs(env) {
|
|
|
5128
5427
|
function createContainerName() {
|
|
5129
5428
|
return `poe-env-${randomBytes3(6).toString("hex")}`;
|
|
5130
5429
|
}
|
|
5131
|
-
|
|
5430
|
+
function createContainerJob(containerId, runner, engine, context, jobId = containerId) {
|
|
5132
5431
|
return {
|
|
5133
|
-
id:
|
|
5432
|
+
id: jobId,
|
|
5134
5433
|
envId: containerId,
|
|
5135
5434
|
tool: "docker",
|
|
5136
5435
|
argv: ["attach", containerId],
|
|
@@ -5147,14 +5446,32 @@ async function createContainerJob(containerId, runner, engine, context) {
|
|
|
5147
5446
|
stdout: "pipe",
|
|
5148
5447
|
stderr: "pipe"
|
|
5149
5448
|
});
|
|
5150
|
-
const stdout = await
|
|
5449
|
+
const stdout = await readStream2(handle.stdout);
|
|
5151
5450
|
const result = await handle.result;
|
|
5152
5451
|
if (result.exitCode !== 0) {
|
|
5153
5452
|
return "lost";
|
|
5154
5453
|
}
|
|
5155
5454
|
return stdout.trim() === "running" ? "running" : "exited";
|
|
5156
5455
|
},
|
|
5157
|
-
async *stream() {
|
|
5456
|
+
async *stream(opts) {
|
|
5457
|
+
const handle = runner.exec({
|
|
5458
|
+
command: engine,
|
|
5459
|
+
args: [
|
|
5460
|
+
...buildContextArgs(engine, context),
|
|
5461
|
+
"exec",
|
|
5462
|
+
containerId,
|
|
5463
|
+
"sh",
|
|
5464
|
+
"-c",
|
|
5465
|
+
`test -f ${shellQuote2(`/tmp/poe-jobs/${jobId}.log`)} && tail -c +${(opts?.sinceByte ?? 0) + 1} ${shellQuote2(`/tmp/poe-jobs/${jobId}.log`)} || true`
|
|
5466
|
+
],
|
|
5467
|
+
stdout: "pipe",
|
|
5468
|
+
stderr: "pipe"
|
|
5469
|
+
});
|
|
5470
|
+
const stdout = await readStream2(handle.stdout);
|
|
5471
|
+
await handle.result;
|
|
5472
|
+
if (stdout.length > 0) {
|
|
5473
|
+
yield { byteOffset: opts?.sinceByte ?? 0, data: stdout };
|
|
5474
|
+
}
|
|
5158
5475
|
},
|
|
5159
5476
|
async wait() {
|
|
5160
5477
|
const handle = runner.exec({
|
|
@@ -5163,7 +5480,7 @@ async function createContainerJob(containerId, runner, engine, context) {
|
|
|
5163
5480
|
stdout: "pipe",
|
|
5164
5481
|
stderr: "pipe"
|
|
5165
5482
|
});
|
|
5166
|
-
const stdout = await
|
|
5483
|
+
const stdout = await readStream2(handle.stdout);
|
|
5167
5484
|
const result = await handle.result;
|
|
5168
5485
|
return { exitCode: Number.parseInt(stdout.trim(), 10) || result.exitCode };
|
|
5169
5486
|
},
|
|
@@ -5178,9 +5495,9 @@ async function createContainerJob(containerId, runner, engine, context) {
|
|
|
5178
5495
|
}
|
|
5179
5496
|
};
|
|
5180
5497
|
}
|
|
5181
|
-
function createAttachedSpec() {
|
|
5498
|
+
function createAttachedSpec(cwd = "/workspace") {
|
|
5182
5499
|
return {
|
|
5183
|
-
cwd
|
|
5500
|
+
cwd,
|
|
5184
5501
|
runtime: {
|
|
5185
5502
|
type: "docker",
|
|
5186
5503
|
image: "attached",
|
|
@@ -5252,12 +5569,778 @@ var hostExecutionEnvFactory = {
|
|
|
5252
5569
|
// packages/process-runner/src/testing/mock-runner.ts
|
|
5253
5570
|
import { Readable, Writable } from "node:stream";
|
|
5254
5571
|
|
|
5572
|
+
// packages/runner-e2b/src/factory.ts
|
|
5573
|
+
import path30 from "node:path";
|
|
5574
|
+
|
|
5575
|
+
// packages/runner-e2b/src/sdk.ts
|
|
5576
|
+
import { Template, Sandbox } from "e2b";
|
|
5577
|
+
async function createSandbox(opts) {
|
|
5578
|
+
return Sandbox.create(opts.templateId, {
|
|
5579
|
+
apiKey: opts.apiKey,
|
|
5580
|
+
envs: opts.env,
|
|
5581
|
+
...opts.timeoutMinutes === void 0 ? {} : { timeoutMs: opts.timeoutMinutes * 6e4 }
|
|
5582
|
+
});
|
|
5583
|
+
}
|
|
5584
|
+
async function connectSandbox(id, apiKey) {
|
|
5585
|
+
return Sandbox.connect(id, apiKey === void 0 ? void 0 : { apiKey });
|
|
5586
|
+
}
|
|
5587
|
+
async function buildTemplate(opts) {
|
|
5588
|
+
const template = Template({ fileContextPath: opts.buildContext }).fromDockerfile(
|
|
5589
|
+
opts.dockerfilePath
|
|
5590
|
+
);
|
|
5591
|
+
if (opts.fromTemplate !== void 0 && opts.fromTemplate.length > 0) {
|
|
5592
|
+
template.fromTemplate(opts.fromTemplate);
|
|
5593
|
+
}
|
|
5594
|
+
const result = await Template.build(template, opts.name, {
|
|
5595
|
+
apiKey: opts.apiKey,
|
|
5596
|
+
...opts.cpu === void 0 ? {} : { cpuCount: opts.cpu },
|
|
5597
|
+
...opts.memoryMb === void 0 ? {} : { memoryMB: opts.memoryMb },
|
|
5598
|
+
...opts.onLog ? { onBuildLogs: opts.onLog } : {}
|
|
5599
|
+
});
|
|
5600
|
+
return { templateId: result.templateId };
|
|
5601
|
+
}
|
|
5602
|
+
function toArrayBuffer(buffer) {
|
|
5603
|
+
const output = new ArrayBuffer(buffer.byteLength);
|
|
5604
|
+
new Uint8Array(output).set(buffer);
|
|
5605
|
+
return output;
|
|
5606
|
+
}
|
|
5607
|
+
async function readableToString(stream) {
|
|
5608
|
+
if (stream === null) {
|
|
5609
|
+
return "";
|
|
5610
|
+
}
|
|
5611
|
+
stream.setEncoding("utf8");
|
|
5612
|
+
const chunks = [];
|
|
5613
|
+
for await (const chunk of stream) {
|
|
5614
|
+
chunks.push(String(chunk));
|
|
5615
|
+
}
|
|
5616
|
+
return chunks.join("");
|
|
5617
|
+
}
|
|
5618
|
+
|
|
5619
|
+
// packages/runner-e2b/src/template-build.ts
|
|
5620
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
5621
|
+
import { readdir as readdir4, readFile as readFile11 } from "node:fs/promises";
|
|
5622
|
+
import path27 from "node:path";
|
|
5623
|
+
var BUILD_LOG_TAIL_SIZE = 30;
|
|
5624
|
+
async function buildE2bRuntimeTemplate(input) {
|
|
5625
|
+
const dockerfileBytes = await readFile11(input.dockerfilePath);
|
|
5626
|
+
const buildContextFiles = await readBuildContextFiles(input.buildContext);
|
|
5627
|
+
const hash = hashTemplate(dockerfileBytes, buildContextFiles, input.runtime.build_args);
|
|
5628
|
+
const cached2 = input.force === true ? null : await input.state?.templates.get("e2b", hash);
|
|
5629
|
+
if (cached2?.template_id !== void 0) {
|
|
5630
|
+
return { backend: "e2b", hash, templateId: cached2.template_id, cached: true };
|
|
5631
|
+
}
|
|
5632
|
+
const tail = [];
|
|
5633
|
+
const onLog = (entry) => {
|
|
5634
|
+
tail.push(entry.message);
|
|
5635
|
+
if (tail.length > BUILD_LOG_TAIL_SIZE) {
|
|
5636
|
+
tail.shift();
|
|
5637
|
+
}
|
|
5638
|
+
input.onLog?.(entry);
|
|
5639
|
+
};
|
|
5640
|
+
let built;
|
|
5641
|
+
try {
|
|
5642
|
+
built = await buildTemplate({
|
|
5643
|
+
apiKey: input.apiKey,
|
|
5644
|
+
name: `poe-code-${hash.slice(0, 32)}`,
|
|
5645
|
+
dockerfilePath: input.dockerfilePath,
|
|
5646
|
+
buildContext: input.buildContext,
|
|
5647
|
+
cpu: input.runtime.cpu,
|
|
5648
|
+
memoryMb: input.runtime.memory_mb,
|
|
5649
|
+
fromTemplate: input.runtime.from_template,
|
|
5650
|
+
onLog
|
|
5651
|
+
});
|
|
5652
|
+
} catch (error2) {
|
|
5653
|
+
throw decorateBuildError(error2, tail);
|
|
5654
|
+
}
|
|
5655
|
+
await input.state?.templates.put("e2b", {
|
|
5656
|
+
hash,
|
|
5657
|
+
template_id: built.templateId,
|
|
5658
|
+
runtime_type: "e2b",
|
|
5659
|
+
dockerfile_path: input.dockerfilePath,
|
|
5660
|
+
built_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
5661
|
+
});
|
|
5662
|
+
return { backend: "e2b", hash, templateId: built.templateId, cached: false };
|
|
5663
|
+
}
|
|
5664
|
+
function decorateBuildError(error2, tail) {
|
|
5665
|
+
const original = error2 instanceof Error ? error2 : new Error(String(error2));
|
|
5666
|
+
if (tail.length === 0) {
|
|
5667
|
+
return original;
|
|
5668
|
+
}
|
|
5669
|
+
const decorated = new Error(`${original.message}
|
|
5670
|
+
|
|
5671
|
+
Last build output:
|
|
5672
|
+
${tail.join("\n")}`);
|
|
5673
|
+
decorated.stack = original.stack;
|
|
5674
|
+
decorated.cause = original;
|
|
5675
|
+
return decorated;
|
|
5676
|
+
}
|
|
5677
|
+
function hashTemplate(dockerfileBytes, buildContextFiles, buildArgs) {
|
|
5678
|
+
const hash = createHash5("sha256");
|
|
5679
|
+
hash.update(dockerfileBytes);
|
|
5680
|
+
hash.update("\0");
|
|
5681
|
+
for (const file of buildContextFiles) {
|
|
5682
|
+
hash.update(file.relativePath);
|
|
5683
|
+
hash.update("\0");
|
|
5684
|
+
hash.update(file.bytes);
|
|
5685
|
+
hash.update("\0");
|
|
5686
|
+
}
|
|
5687
|
+
for (const [key, value] of Object.entries(buildArgs).sort(
|
|
5688
|
+
([left], [right]) => left.localeCompare(right)
|
|
5689
|
+
)) {
|
|
5690
|
+
hash.update(key);
|
|
5691
|
+
hash.update("=");
|
|
5692
|
+
hash.update(value);
|
|
5693
|
+
hash.update("\0");
|
|
5694
|
+
}
|
|
5695
|
+
return hash.digest("hex");
|
|
5696
|
+
}
|
|
5697
|
+
async function readBuildContextFiles(buildContext) {
|
|
5698
|
+
const files = [];
|
|
5699
|
+
await collectBuildContextFiles(buildContext, "", files);
|
|
5700
|
+
return files.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
|
|
5701
|
+
}
|
|
5702
|
+
async function collectBuildContextFiles(buildContext, relativeDir, files) {
|
|
5703
|
+
const absoluteDir = path27.join(buildContext, relativeDir);
|
|
5704
|
+
const entries = await readdir4(absoluteDir, { withFileTypes: true });
|
|
5705
|
+
for (const entry of entries) {
|
|
5706
|
+
const relativePath = path27.join(relativeDir, entry.name);
|
|
5707
|
+
if (entry.isDirectory()) {
|
|
5708
|
+
await collectBuildContextFiles(buildContext, relativePath, files);
|
|
5709
|
+
continue;
|
|
5710
|
+
}
|
|
5711
|
+
if (!entry.isFile()) {
|
|
5712
|
+
continue;
|
|
5713
|
+
}
|
|
5714
|
+
files.push({
|
|
5715
|
+
relativePath: relativePath.split(path27.sep).join("/"),
|
|
5716
|
+
bytes: await readFile11(path27.join(buildContext, relativePath))
|
|
5717
|
+
});
|
|
5718
|
+
}
|
|
5719
|
+
}
|
|
5720
|
+
|
|
5721
|
+
// packages/runner-e2b/src/opened-env.ts
|
|
5722
|
+
import { mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "node:fs";
|
|
5723
|
+
import { readFile as readFile12, writeFile as writeFile7 } from "node:fs/promises";
|
|
5724
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
5725
|
+
import path29 from "node:path";
|
|
5726
|
+
import { PassThrough, Writable as Writable2 } from "node:stream";
|
|
5727
|
+
|
|
5728
|
+
// packages/runner-e2b/src/job-handle.ts
|
|
5729
|
+
import path28 from "node:path";
|
|
5730
|
+
var JOB_DIR2 = "/tmp/poe-jobs";
|
|
5731
|
+
function createE2bJobHandle(input) {
|
|
5732
|
+
const fs14 = createE2bLogStreamFs(input.sandbox);
|
|
5733
|
+
return {
|
|
5734
|
+
id: input.jobId,
|
|
5735
|
+
envId: input.envId,
|
|
5736
|
+
tool: input.tool,
|
|
5737
|
+
argv: input.argv,
|
|
5738
|
+
async status() {
|
|
5739
|
+
const exit = await readExitCode(input.sandbox, input.jobId);
|
|
5740
|
+
if (exit !== null) {
|
|
5741
|
+
return "exited";
|
|
5742
|
+
}
|
|
5743
|
+
const processes = await input.sandbox.commands.list();
|
|
5744
|
+
const isRunning = input.pid === void 0 ? processes.some((process2) => processMentionsJob(process2, input.jobId)) : processes.some((process2) => process2.pid === input.pid);
|
|
5745
|
+
return isRunning ? "running" : "lost";
|
|
5746
|
+
},
|
|
5747
|
+
stream(opts = {}) {
|
|
5748
|
+
return streamLogFile({ fs: fs14 }, input.jobId, opts);
|
|
5749
|
+
},
|
|
5750
|
+
async wait() {
|
|
5751
|
+
const result = await waitForExit({ fs: fs14 }, input.jobId);
|
|
5752
|
+
const preserveMs = input.preserveAfterExitHours * 60 * 60 * 1e3;
|
|
5753
|
+
if (preserveMs > 0) {
|
|
5754
|
+
await input.sandbox.setTimeout(preserveMs);
|
|
5755
|
+
}
|
|
5756
|
+
return result;
|
|
5757
|
+
},
|
|
5758
|
+
async kill() {
|
|
5759
|
+
const pids = input.pid === void 0 ? (await input.sandbox.commands.list()).filter((process2) => processMentionsJob(process2, input.jobId)).map((process2) => process2.pid) : [input.pid];
|
|
5760
|
+
await Promise.all(pids.map((pid) => input.sandbox.commands.kill(pid)));
|
|
5761
|
+
}
|
|
5762
|
+
};
|
|
5763
|
+
}
|
|
5764
|
+
function createE2bLogStreamFs(sandbox) {
|
|
5765
|
+
return {
|
|
5766
|
+
promises: {
|
|
5767
|
+
async readFile(filePath) {
|
|
5768
|
+
return Buffer.from(await sandbox.files.read(filePath, { format: "bytes" }));
|
|
5769
|
+
},
|
|
5770
|
+
async stat(filePath) {
|
|
5771
|
+
const result = await sandbox.commands.run(
|
|
5772
|
+
`stat -c %Y ${shellQuote3(filePath)} 2>/dev/null || stat -f %m ${shellQuote3(filePath)}`
|
|
5773
|
+
);
|
|
5774
|
+
if (!("stdout" in result)) {
|
|
5775
|
+
throw new Error(`Unable to stat ${filePath}`);
|
|
5776
|
+
}
|
|
5777
|
+
const seconds = Number(result.stdout?.trim());
|
|
5778
|
+
if (!Number.isFinite(seconds)) {
|
|
5779
|
+
throw new Error(`Unable to stat ${filePath}`);
|
|
5780
|
+
}
|
|
5781
|
+
return { mtimeMs: seconds * 1e3 };
|
|
5782
|
+
}
|
|
5783
|
+
},
|
|
5784
|
+
watch(filePath, listener) {
|
|
5785
|
+
let closed = false;
|
|
5786
|
+
let stop = null;
|
|
5787
|
+
void sandbox.files.watchDir(path28.dirname(filePath), listener, { recursive: false }).then((handle) => {
|
|
5788
|
+
if (closed) {
|
|
5789
|
+
void handle.stop();
|
|
5790
|
+
return;
|
|
5791
|
+
}
|
|
5792
|
+
stop = () => {
|
|
5793
|
+
void handle.stop();
|
|
5794
|
+
};
|
|
5795
|
+
});
|
|
5796
|
+
return {
|
|
5797
|
+
close() {
|
|
5798
|
+
closed = true;
|
|
5799
|
+
stop?.();
|
|
5800
|
+
}
|
|
5801
|
+
};
|
|
5802
|
+
}
|
|
5803
|
+
};
|
|
5804
|
+
}
|
|
5805
|
+
function processMentionsJob(process2, jobId) {
|
|
5806
|
+
const needle = `/tmp/poe-jobs/${jobId}`;
|
|
5807
|
+
return process2.cmd.includes(needle) || process2.args.some((arg) => arg.includes(needle));
|
|
5808
|
+
}
|
|
5809
|
+
function shellQuote3(value) {
|
|
5810
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
5811
|
+
}
|
|
5812
|
+
async function readExitCode(sandbox, jobId) {
|
|
5813
|
+
try {
|
|
5814
|
+
const contents = await sandbox.files.read(`${JOB_DIR2}/${jobId}.exit`);
|
|
5815
|
+
const exitCode = Number(contents.trim());
|
|
5816
|
+
return Number.isInteger(exitCode) ? exitCode : null;
|
|
5817
|
+
} catch {
|
|
5818
|
+
return null;
|
|
5819
|
+
}
|
|
5820
|
+
}
|
|
5821
|
+
|
|
5822
|
+
// packages/runner-e2b/src/opened-env.ts
|
|
5823
|
+
var REMOTE_COMMAND_STDERR_TAIL_SIZE = 30;
|
|
5824
|
+
function createOpenedE2bEnv(input) {
|
|
5825
|
+
const hostRunner = input.spec.hostRunner ?? createHostRunner();
|
|
5826
|
+
const hostWorkspaceDir = path29.resolve(input.spec.cwd);
|
|
5827
|
+
const sandboxWorkspaceDir = normalizeSandboxWorkspaceDir(input.runtime.workspace_dir);
|
|
5828
|
+
let lastProcess = null;
|
|
5829
|
+
let detachedJobContext = null;
|
|
5830
|
+
const mapWorkspaceCwd = (cwd) => {
|
|
5831
|
+
if (cwd === void 0) {
|
|
5832
|
+
return void 0;
|
|
5833
|
+
}
|
|
5834
|
+
if (path29.isAbsolute(cwd) && path29.resolve(cwd) === hostWorkspaceDir) {
|
|
5835
|
+
return sandboxWorkspaceDir;
|
|
5836
|
+
}
|
|
5837
|
+
return cwd;
|
|
5838
|
+
};
|
|
5839
|
+
const attachedJobId = input.spec.detachedJobId;
|
|
5840
|
+
const env = {
|
|
5841
|
+
id: input.sandbox.sandboxId,
|
|
5842
|
+
job: attachedJobId ? createE2bJobHandle({
|
|
5843
|
+
sandbox: input.sandbox,
|
|
5844
|
+
envId: input.sandbox.sandboxId,
|
|
5845
|
+
jobId: attachedJobId,
|
|
5846
|
+
tool: input.spec.jobLabel.tool,
|
|
5847
|
+
argv: input.spec.jobLabel.argv,
|
|
5848
|
+
preserveAfterExitHours: input.runtime.preserve_after_exit_hours ?? 24
|
|
5849
|
+
}) : null,
|
|
5850
|
+
fs: createE2bLogStreamFs(input.sandbox),
|
|
5851
|
+
setDetachedJobContext(context) {
|
|
5852
|
+
detachedJobContext = context;
|
|
5853
|
+
},
|
|
5854
|
+
async uploadWorkspace() {
|
|
5855
|
+
if (input.spec.runner?.sync === "none") {
|
|
5856
|
+
return { files: 0, bytes: 0, skipped: [] };
|
|
5857
|
+
}
|
|
5858
|
+
const tempDir = mkdtempSync2(path29.join(tmpdir2(), "poe-e2b-upload-"));
|
|
5859
|
+
const archivePath = path29.join(tempDir, "workspace.tar");
|
|
5860
|
+
try {
|
|
5861
|
+
await runOrThrow2(hostRunner, {
|
|
5862
|
+
command: "tar",
|
|
5863
|
+
args: [
|
|
5864
|
+
...input.spec.uploadIgnoreFiles.flatMap((ignored) => ["--exclude", ignored]),
|
|
5865
|
+
"-cf",
|
|
5866
|
+
archivePath,
|
|
5867
|
+
"-C",
|
|
5868
|
+
input.spec.cwd,
|
|
5869
|
+
"."
|
|
5870
|
+
],
|
|
5871
|
+
stdout: "pipe",
|
|
5872
|
+
stderr: "pipe"
|
|
5873
|
+
});
|
|
5874
|
+
await input.sandbox.files.write(
|
|
5875
|
+
"/tmp/poe-workspace-upload.tar",
|
|
5876
|
+
toArrayBuffer(await readFile12(archivePath))
|
|
5877
|
+
);
|
|
5878
|
+
await runRemoteOrThrow(
|
|
5879
|
+
input.sandbox,
|
|
5880
|
+
createUploadWorkspaceCommand(sandboxWorkspaceDir)
|
|
5881
|
+
);
|
|
5882
|
+
return { files: 0, bytes: 0, skipped: [] };
|
|
5883
|
+
} finally {
|
|
5884
|
+
rmSync2(tempDir, { recursive: true, force: true });
|
|
5885
|
+
}
|
|
5886
|
+
},
|
|
5887
|
+
async downloadWorkspace(opts) {
|
|
5888
|
+
if (input.spec.runner?.sync === "upload" || input.spec.runner?.sync === "none") {
|
|
5889
|
+
return { files: 0, bytes: 0, conflicts: [] };
|
|
5890
|
+
}
|
|
5891
|
+
const tempDir = mkdtempSync2(path29.join(tmpdir2(), "poe-e2b-download-"));
|
|
5892
|
+
const archivePath = path29.join(tempDir, "workspace.tar");
|
|
5893
|
+
try {
|
|
5894
|
+
await runRemoteOrThrow(
|
|
5895
|
+
input.sandbox,
|
|
5896
|
+
`tar -cf /tmp/poe-workspace-download.tar -C ${shellQuote4(sandboxWorkspaceDir)} .`
|
|
5897
|
+
);
|
|
5898
|
+
const archive = await input.sandbox.files.read("/tmp/poe-workspace-download.tar", {
|
|
5899
|
+
format: "bytes"
|
|
5900
|
+
});
|
|
5901
|
+
await writeFile7(archivePath, Buffer.from(archive));
|
|
5902
|
+
await runOrThrow2(hostRunner, {
|
|
5903
|
+
command: "tar",
|
|
5904
|
+
args: [
|
|
5905
|
+
opts.conflictPolicy === "refuse" ? "-xkf" : "-xf",
|
|
5906
|
+
archivePath,
|
|
5907
|
+
"-C",
|
|
5908
|
+
input.spec.cwd
|
|
5909
|
+
],
|
|
5910
|
+
stdout: "pipe",
|
|
5911
|
+
stderr: "pipe"
|
|
5912
|
+
});
|
|
5913
|
+
return { files: 0, bytes: archive.byteLength, conflicts: [] };
|
|
5914
|
+
} finally {
|
|
5915
|
+
rmSync2(tempDir, { recursive: true, force: true });
|
|
5916
|
+
}
|
|
5917
|
+
},
|
|
5918
|
+
exec(spec) {
|
|
5919
|
+
const handle = runE2bCommand(input.sandbox, {
|
|
5920
|
+
...spec,
|
|
5921
|
+
cwd: mapWorkspaceCwd(spec.cwd),
|
|
5922
|
+
env: resolveSandboxCommandEnv(spec.env)
|
|
5923
|
+
});
|
|
5924
|
+
lastProcess = { started: handle.started };
|
|
5925
|
+
return handle;
|
|
5926
|
+
},
|
|
5927
|
+
async detach() {
|
|
5928
|
+
if (detachedJobContext === null) {
|
|
5929
|
+
throw new Error("Cannot detach E2B environment before a job context is registered.");
|
|
5930
|
+
}
|
|
5931
|
+
if (lastProcess === null) {
|
|
5932
|
+
throw new Error("Cannot detach E2B environment before a command is running.");
|
|
5933
|
+
}
|
|
5934
|
+
const command = await lastProcess.started;
|
|
5935
|
+
const preserveAfterExitHours = input.runtime.preserve_after_exit_hours ?? 24;
|
|
5936
|
+
const preserveMs = preserveAfterExitHours * 60 * 60 * 1e3;
|
|
5937
|
+
if (preserveMs > 0) {
|
|
5938
|
+
await input.sandbox.setTimeout(preserveMs);
|
|
5939
|
+
}
|
|
5940
|
+
return createE2bJobHandle({
|
|
5941
|
+
sandbox: input.sandbox,
|
|
5942
|
+
envId: input.sandbox.sandboxId,
|
|
5943
|
+
jobId: detachedJobContext.id,
|
|
5944
|
+
tool: detachedJobContext.tool,
|
|
5945
|
+
argv: detachedJobContext.argv,
|
|
5946
|
+
pid: command.pid,
|
|
5947
|
+
preserveAfterExitHours
|
|
5948
|
+
});
|
|
5949
|
+
},
|
|
5950
|
+
shell() {
|
|
5951
|
+
const shellSpec = input.spec.shellSpec;
|
|
5952
|
+
const command = shellSpec?.command ?? input.spec.env.SHELL ?? "sh";
|
|
5953
|
+
return runE2bPty(input.sandbox, {
|
|
5954
|
+
command,
|
|
5955
|
+
...shellSpec?.args ? { args: shellSpec.args } : {},
|
|
5956
|
+
cwd: mapWorkspaceCwd(shellSpec?.cwd ?? input.spec.cwd),
|
|
5957
|
+
env: resolveSandboxCommandEnv(
|
|
5958
|
+
shellSpec && "env" in shellSpec ? shellSpec.env : input.spec.env
|
|
5959
|
+
),
|
|
5960
|
+
stdin: "inherit",
|
|
5961
|
+
stdout: "inherit",
|
|
5962
|
+
stderr: "inherit",
|
|
5963
|
+
tty: true
|
|
5964
|
+
});
|
|
5965
|
+
},
|
|
5966
|
+
async close() {
|
|
5967
|
+
await input.sandbox.kill();
|
|
5968
|
+
}
|
|
5969
|
+
};
|
|
5970
|
+
return env;
|
|
5971
|
+
}
|
|
5972
|
+
function runE2bCommand(sandbox, spec) {
|
|
5973
|
+
const stdout = spec.stdout === "inherit" ? null : new PassThrough();
|
|
5974
|
+
const stderr = spec.stderr === "inherit" ? null : new PassThrough();
|
|
5975
|
+
let e2bHandle = null;
|
|
5976
|
+
const command = shellCommand([spec.command, ...spec.args ?? []]);
|
|
5977
|
+
const started = sandbox.commands.run(command, {
|
|
5978
|
+
background: true,
|
|
5979
|
+
cwd: spec.cwd,
|
|
5980
|
+
envs: spec.env,
|
|
5981
|
+
stdin: spec.stdin === "pipe",
|
|
5982
|
+
onStdout(data) {
|
|
5983
|
+
stdout?.write(data);
|
|
5984
|
+
if (spec.stdout === "inherit") {
|
|
5985
|
+
process.stdout.write(data);
|
|
5986
|
+
}
|
|
5987
|
+
},
|
|
5988
|
+
onStderr(data) {
|
|
5989
|
+
stderr?.write(data);
|
|
5990
|
+
if (spec.stderr === "inherit") {
|
|
5991
|
+
process.stderr.write(data);
|
|
5992
|
+
}
|
|
5993
|
+
}
|
|
5994
|
+
});
|
|
5995
|
+
const stdin = spec.stdin === "pipe" ? new Writable2({
|
|
5996
|
+
write(chunk, _encoding, callback) {
|
|
5997
|
+
started.then(
|
|
5998
|
+
(handle) => sandbox.commands.sendStdin(
|
|
5999
|
+
handle.pid,
|
|
6000
|
+
Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))
|
|
6001
|
+
)
|
|
6002
|
+
).then(() => callback(), callback);
|
|
6003
|
+
},
|
|
6004
|
+
final(callback) {
|
|
6005
|
+
if (sandbox.commands.closeStdin === void 0) {
|
|
6006
|
+
callback();
|
|
6007
|
+
return;
|
|
6008
|
+
}
|
|
6009
|
+
started.then((handle) => sandbox.commands.closeStdin(handle.pid)).then(() => callback(), callback);
|
|
6010
|
+
}
|
|
6011
|
+
}) : null;
|
|
6012
|
+
const result = started.then((handle) => {
|
|
6013
|
+
e2bHandle = handle;
|
|
6014
|
+
return handle.wait();
|
|
6015
|
+
}).then(
|
|
6016
|
+
(result2) => {
|
|
6017
|
+
stdout?.end();
|
|
6018
|
+
stderr?.end();
|
|
6019
|
+
return { exitCode: result2.exitCode ?? 0 };
|
|
6020
|
+
},
|
|
6021
|
+
(error2) => {
|
|
6022
|
+
stdout?.end();
|
|
6023
|
+
stderr?.end();
|
|
6024
|
+
if (isExitError(error2)) {
|
|
6025
|
+
return { exitCode: error2.exitCode };
|
|
6026
|
+
}
|
|
6027
|
+
return { exitCode: 1 };
|
|
6028
|
+
}
|
|
6029
|
+
);
|
|
6030
|
+
return {
|
|
6031
|
+
get pid() {
|
|
6032
|
+
return e2bHandle?.pid ?? null;
|
|
6033
|
+
},
|
|
6034
|
+
stdin,
|
|
6035
|
+
stdout,
|
|
6036
|
+
stderr,
|
|
6037
|
+
result,
|
|
6038
|
+
kill() {
|
|
6039
|
+
void e2bHandle?.kill();
|
|
6040
|
+
},
|
|
6041
|
+
get e2bHandle() {
|
|
6042
|
+
return e2bHandle;
|
|
6043
|
+
},
|
|
6044
|
+
started
|
|
6045
|
+
};
|
|
6046
|
+
}
|
|
6047
|
+
function runE2bPty(sandbox, spec) {
|
|
6048
|
+
const stdout = new PassThrough();
|
|
6049
|
+
let handleRef = null;
|
|
6050
|
+
const stdin = new Writable2({
|
|
6051
|
+
write(chunk, _encoding, callback) {
|
|
6052
|
+
if (handleRef === null) {
|
|
6053
|
+
callback(new Error("E2B PTY stdin is not ready."));
|
|
6054
|
+
return;
|
|
6055
|
+
}
|
|
6056
|
+
sandbox.pty.sendInput(handleRef.pid, Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))).then(() => callback(), callback);
|
|
6057
|
+
}
|
|
6058
|
+
});
|
|
6059
|
+
const started = sandbox.pty.create({
|
|
6060
|
+
cols: process.stdout.columns || 80,
|
|
6061
|
+
rows: process.stdout.rows || 24,
|
|
6062
|
+
cwd: spec.cwd,
|
|
6063
|
+
envs: spec.env,
|
|
6064
|
+
onData(data) {
|
|
6065
|
+
stdout.write(Buffer.from(data));
|
|
6066
|
+
if (spec.stdout === "inherit") {
|
|
6067
|
+
process.stdout.write(Buffer.from(data));
|
|
6068
|
+
}
|
|
6069
|
+
}
|
|
6070
|
+
});
|
|
6071
|
+
const result = started.then((handle) => {
|
|
6072
|
+
handleRef = handle;
|
|
6073
|
+
return handle.wait();
|
|
6074
|
+
}).then(
|
|
6075
|
+
(result2) => {
|
|
6076
|
+
stdout.end();
|
|
6077
|
+
return { exitCode: result2.exitCode ?? 0 };
|
|
6078
|
+
},
|
|
6079
|
+
() => {
|
|
6080
|
+
stdout.end();
|
|
6081
|
+
return { exitCode: 1 };
|
|
6082
|
+
}
|
|
6083
|
+
);
|
|
6084
|
+
return {
|
|
6085
|
+
get pid() {
|
|
6086
|
+
return handleRef?.pid ?? null;
|
|
6087
|
+
},
|
|
6088
|
+
stdin: spec.stdin === "inherit" ? process.stdin : stdin,
|
|
6089
|
+
stdout: spec.stdout === "inherit" ? null : stdout,
|
|
6090
|
+
stderr: null,
|
|
6091
|
+
result,
|
|
6092
|
+
kill() {
|
|
6093
|
+
void (handleRef === null ? void 0 : sandbox.pty.kill(handleRef.pid));
|
|
6094
|
+
}
|
|
6095
|
+
};
|
|
6096
|
+
}
|
|
6097
|
+
async function runRemoteOrThrow(sandbox, command) {
|
|
6098
|
+
const stdoutTail = createLineTail(REMOTE_COMMAND_STDERR_TAIL_SIZE);
|
|
6099
|
+
const stderrTail = createLineTail(REMOTE_COMMAND_STDERR_TAIL_SIZE);
|
|
6100
|
+
let result;
|
|
6101
|
+
try {
|
|
6102
|
+
result = await sandbox.commands.run(command, {
|
|
6103
|
+
onStdout(data) {
|
|
6104
|
+
stdoutTail.push(data);
|
|
6105
|
+
},
|
|
6106
|
+
onStderr(data) {
|
|
6107
|
+
stderrTail.push(data);
|
|
6108
|
+
}
|
|
6109
|
+
});
|
|
6110
|
+
} catch (error2) {
|
|
6111
|
+
appendRemoteCommandOutput(error2, stdoutTail, stderrTail);
|
|
6112
|
+
if (isCommandExitError(error2)) {
|
|
6113
|
+
throw decorateRemoteCommandError(error2, command, stderrTail.values());
|
|
6114
|
+
}
|
|
6115
|
+
throw error2;
|
|
6116
|
+
}
|
|
6117
|
+
appendRemoteCommandOutput(result, stdoutTail, stderrTail);
|
|
6118
|
+
if ("exitCode" in result && result.exitCode !== 0) {
|
|
6119
|
+
throw decorateRemoteCommandError(
|
|
6120
|
+
new Error(`E2B command failed with exit code ${result.exitCode}`),
|
|
6121
|
+
command,
|
|
6122
|
+
stderrTail.values()
|
|
6123
|
+
);
|
|
6124
|
+
}
|
|
6125
|
+
}
|
|
6126
|
+
function appendRemoteCommandOutput(source, stdoutTail, stderrTail) {
|
|
6127
|
+
if (!source || typeof source !== "object") {
|
|
6128
|
+
return;
|
|
6129
|
+
}
|
|
6130
|
+
const output = source;
|
|
6131
|
+
if (typeof output.stdout === "string") {
|
|
6132
|
+
stdoutTail.push(output.stdout);
|
|
6133
|
+
}
|
|
6134
|
+
if (typeof output.stderr === "string") {
|
|
6135
|
+
stderrTail.push(output.stderr);
|
|
6136
|
+
}
|
|
6137
|
+
}
|
|
6138
|
+
function decorateRemoteCommandError(error2, command, stderrTail) {
|
|
6139
|
+
const original = error2 instanceof Error ? error2 : new Error(String(error2));
|
|
6140
|
+
const tail = stderrTail.length === 0 ? "" : `
|
|
6141
|
+
|
|
6142
|
+
Last stderr output:
|
|
6143
|
+
${stderrTail.join("\n")}`;
|
|
6144
|
+
const decorated = new Error(`E2B command failed: ${command}
|
|
6145
|
+
${original.message}${tail}`);
|
|
6146
|
+
decorated.stack = original.stack;
|
|
6147
|
+
decorated.cause = original;
|
|
6148
|
+
return decorated;
|
|
6149
|
+
}
|
|
6150
|
+
function createLineTail(maxLines) {
|
|
6151
|
+
const lines = [];
|
|
6152
|
+
let pending = "";
|
|
6153
|
+
const appendLine = (line) => {
|
|
6154
|
+
lines.push(trimTrailingCarriageReturn(line));
|
|
6155
|
+
while (lines.length > maxLines) {
|
|
6156
|
+
lines.shift();
|
|
6157
|
+
}
|
|
6158
|
+
};
|
|
6159
|
+
return {
|
|
6160
|
+
push(chunk) {
|
|
6161
|
+
pending += chunk;
|
|
6162
|
+
const parts = pending.split("\n");
|
|
6163
|
+
pending = parts.pop() ?? "";
|
|
6164
|
+
for (const line of parts) {
|
|
6165
|
+
appendLine(line);
|
|
6166
|
+
}
|
|
6167
|
+
},
|
|
6168
|
+
values() {
|
|
6169
|
+
const output = [...lines];
|
|
6170
|
+
if (pending.length > 0) {
|
|
6171
|
+
output.push(trimTrailingCarriageReturn(pending));
|
|
6172
|
+
}
|
|
6173
|
+
return output.slice(-maxLines);
|
|
6174
|
+
}
|
|
6175
|
+
};
|
|
6176
|
+
}
|
|
6177
|
+
function trimTrailingCarriageReturn(value) {
|
|
6178
|
+
return value.endsWith("\r") ? value.slice(0, -1) : value;
|
|
6179
|
+
}
|
|
6180
|
+
async function runOrThrow2(runner, spec) {
|
|
6181
|
+
const handle = runner.exec(spec);
|
|
6182
|
+
const stderr = readableToString(handle.stderr);
|
|
6183
|
+
const result = await handle.result;
|
|
6184
|
+
if (result.exitCode !== 0) {
|
|
6185
|
+
throw new Error(
|
|
6186
|
+
`Command failed with exit code ${result.exitCode}: ${spec.command} ${(spec.args ?? []).join(" ")}
|
|
6187
|
+
${await stderr}`
|
|
6188
|
+
);
|
|
6189
|
+
}
|
|
6190
|
+
}
|
|
6191
|
+
function shellCommand(argv) {
|
|
6192
|
+
return argv.map(shellQuote4).join(" ");
|
|
6193
|
+
}
|
|
6194
|
+
function shellQuote4(value) {
|
|
6195
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
6196
|
+
}
|
|
6197
|
+
function createUploadWorkspaceCommand(sandboxWorkspaceDir) {
|
|
6198
|
+
const quotedWorkspaceDir = shellQuote4(sandboxWorkspaceDir);
|
|
6199
|
+
return [
|
|
6200
|
+
`mkdir -p ${quotedWorkspaceDir} || { command -v sudo >/dev/null 2>&1 && sudo mkdir -p ${quotedWorkspaceDir} && sudo chown "$(id -u):$(id -g)" ${quotedWorkspaceDir}; }`,
|
|
6201
|
+
`test -w ${quotedWorkspaceDir} && tar -xf /tmp/poe-workspace-upload.tar -C ${quotedWorkspaceDir}`
|
|
6202
|
+
].join("\n");
|
|
6203
|
+
}
|
|
6204
|
+
function resolveSandboxCommandEnv(env) {
|
|
6205
|
+
if (env === void 0) {
|
|
6206
|
+
return void 0;
|
|
6207
|
+
}
|
|
6208
|
+
return {
|
|
6209
|
+
...env,
|
|
6210
|
+
HOME: "/home/user"
|
|
6211
|
+
};
|
|
6212
|
+
}
|
|
6213
|
+
function normalizeSandboxWorkspaceDir(workspaceDir) {
|
|
6214
|
+
const resolvedWorkspaceDir = workspaceDir ?? "/workspace";
|
|
6215
|
+
if (!path29.posix.isAbsolute(resolvedWorkspaceDir)) {
|
|
6216
|
+
throw new Error("E2B runtime workspace_dir must be an absolute sandbox path.");
|
|
6217
|
+
}
|
|
6218
|
+
let normalized = path29.posix.normalize(resolvedWorkspaceDir);
|
|
6219
|
+
while (normalized.length > 1 && normalized.endsWith("/")) {
|
|
6220
|
+
normalized = normalized.slice(0, -1);
|
|
6221
|
+
}
|
|
6222
|
+
return normalized;
|
|
6223
|
+
}
|
|
6224
|
+
function isExitError(error2) {
|
|
6225
|
+
return Boolean(
|
|
6226
|
+
error2 && typeof error2 === "object" && typeof error2.exitCode === "number"
|
|
6227
|
+
);
|
|
6228
|
+
}
|
|
6229
|
+
function isCommandExitError(error2) {
|
|
6230
|
+
return isExitError(error2) || Boolean(
|
|
6231
|
+
error2 && typeof error2 === "object" && error2.name === "CommandExitError"
|
|
6232
|
+
);
|
|
6233
|
+
}
|
|
6234
|
+
|
|
6235
|
+
// packages/runner-e2b/src/auth-scope.ts
|
|
6236
|
+
import os4 from "node:os";
|
|
6237
|
+
import { promises as nodeFs4 } from "node:fs";
|
|
6238
|
+
var e2bAuthScope = defineScope("e2b", {
|
|
6239
|
+
api_key: {
|
|
6240
|
+
type: "string",
|
|
6241
|
+
default: "",
|
|
6242
|
+
doc: "E2B API key",
|
|
6243
|
+
env: "E2B_API_KEY"
|
|
6244
|
+
}
|
|
6245
|
+
});
|
|
6246
|
+
async function resolveE2bApiKey(input) {
|
|
6247
|
+
const homeDir = input.homeDir ?? os4.homedir();
|
|
6248
|
+
const fs14 = input.fs ?? nodeFs4;
|
|
6249
|
+
const env = input.env ?? process.env;
|
|
6250
|
+
const document = await readMergedDocument(
|
|
6251
|
+
fs14,
|
|
6252
|
+
resolveConfigPath(homeDir),
|
|
6253
|
+
resolveProjectConfigPath(input.cwd)
|
|
6254
|
+
);
|
|
6255
|
+
const resolved = resolveScope(e2bAuthScope.schema, document.e2b, env);
|
|
6256
|
+
if (resolved.api_key.length === 0) {
|
|
6257
|
+
throw new Error(
|
|
6258
|
+
"No E2B API key. Set E2B_API_KEY or e2b.api_key in ~/.poe-code/config.json."
|
|
6259
|
+
);
|
|
6260
|
+
}
|
|
6261
|
+
return resolved.api_key;
|
|
6262
|
+
}
|
|
6263
|
+
|
|
6264
|
+
// packages/runner-e2b/src/factory.ts
|
|
6265
|
+
var e2bExecutionEnvFactory = {
|
|
6266
|
+
type: "e2b",
|
|
6267
|
+
supportsDetach: true,
|
|
6268
|
+
async open(spec) {
|
|
6269
|
+
const runtime = parseE2bRuntime(spec.runtime);
|
|
6270
|
+
const runtimeCwd = spec.runtimeCwd ?? spec.cwd;
|
|
6271
|
+
const apiKey = await resolveE2bApiKey({ cwd: runtimeCwd });
|
|
6272
|
+
const templateId = runtime.template_id ?? (await buildE2bRuntimeTemplate({
|
|
6273
|
+
runtime,
|
|
6274
|
+
dockerfilePath: path30.resolve(
|
|
6275
|
+
runtimeCwd,
|
|
6276
|
+
runtime.dockerfile ?? path30.join(".poe-code", "Dockerfile")
|
|
6277
|
+
),
|
|
6278
|
+
buildContext: path30.resolve(runtimeCwd, runtime.build_context ?? "."),
|
|
6279
|
+
state: spec.state,
|
|
6280
|
+
apiKey
|
|
6281
|
+
})).templateId;
|
|
6282
|
+
const sandbox = await createSandbox({
|
|
6283
|
+
apiKey,
|
|
6284
|
+
templateId,
|
|
6285
|
+
env: spec.env,
|
|
6286
|
+
timeoutMinutes: runtime.timeout_minutes
|
|
6287
|
+
});
|
|
6288
|
+
return createOpenedE2bEnv({ sandbox, spec, runtime });
|
|
6289
|
+
},
|
|
6290
|
+
async attach(envId, context) {
|
|
6291
|
+
const cwd = context?.cwd ?? process.cwd();
|
|
6292
|
+
const apiKey = await resolveE2bApiKey({ cwd });
|
|
6293
|
+
const sandbox = await connectSandbox(envId, apiKey);
|
|
6294
|
+
return createOpenedE2bEnv({
|
|
6295
|
+
sandbox,
|
|
6296
|
+
spec: {
|
|
6297
|
+
cwd: context?.cwd ?? "/workspace",
|
|
6298
|
+
runtime: {
|
|
6299
|
+
type: "e2b",
|
|
6300
|
+
build_args: {},
|
|
6301
|
+
mounts: [],
|
|
6302
|
+
workspace_dir: "/workspace",
|
|
6303
|
+
preserve_after_exit_hours: 24
|
|
6304
|
+
},
|
|
6305
|
+
env: {},
|
|
6306
|
+
uploadIgnoreFiles: [],
|
|
6307
|
+
jobLabel: { tool: context?.tool ?? "e2b", argv: context?.argv ?? [] },
|
|
6308
|
+
...context?.jobId ? { detachedJobId: context.jobId } : {}
|
|
6309
|
+
},
|
|
6310
|
+
runtime: {
|
|
6311
|
+
type: "e2b",
|
|
6312
|
+
build_args: {},
|
|
6313
|
+
mounts: [],
|
|
6314
|
+
workspace_dir: "/workspace",
|
|
6315
|
+
preserve_after_exit_hours: 24
|
|
6316
|
+
}
|
|
6317
|
+
});
|
|
6318
|
+
}
|
|
6319
|
+
};
|
|
6320
|
+
function parseE2bRuntime(runtime) {
|
|
6321
|
+
if (!runtime || typeof runtime !== "object" || Array.isArray(runtime)) {
|
|
6322
|
+
throw new Error("e2b runtime must be an object");
|
|
6323
|
+
}
|
|
6324
|
+
const record = runtime;
|
|
6325
|
+
if (record.type !== "e2b") {
|
|
6326
|
+
throw new Error('e2b runtime type must be "e2b"');
|
|
6327
|
+
}
|
|
6328
|
+
return record;
|
|
6329
|
+
}
|
|
6330
|
+
|
|
6331
|
+
// packages/runner-e2b/src/index.ts
|
|
6332
|
+
var e2bExecutionEnvFactory2 = e2bExecutionEnvFactory;
|
|
6333
|
+
|
|
5255
6334
|
// packages/agent-spawn/src/register-factories.ts
|
|
5256
6335
|
registerExecutionEnvFactory(hostExecutionEnvFactory);
|
|
5257
6336
|
registerExecutionEnvFactory(dockerExecutionEnvFactory);
|
|
5258
|
-
|
|
6337
|
+
registerExecutionEnvFactory(e2bExecutionEnvFactory2);
|
|
6338
|
+
if (isVitest()) {
|
|
5259
6339
|
registerExecutionEnvFactory(createTestHostExecutionEnvFactory());
|
|
5260
6340
|
}
|
|
6341
|
+
function isVitest() {
|
|
6342
|
+
return process.env.VITEST !== void 0 || process.env.VITEST_POOL_ID !== void 0;
|
|
6343
|
+
}
|
|
5261
6344
|
function createTestHostExecutionEnvFactory() {
|
|
5262
6345
|
return {
|
|
5263
6346
|
type: "host",
|
|
@@ -5619,7 +6702,7 @@ function listMcpSupportedAgents() {
|
|
|
5619
6702
|
|
|
5620
6703
|
// packages/agent-spawn/src/spawn.ts
|
|
5621
6704
|
import { mkdirSync, openSync, writeSync, closeSync } from "node:fs";
|
|
5622
|
-
import
|
|
6705
|
+
import path31 from "node:path";
|
|
5623
6706
|
|
|
5624
6707
|
// packages/agent-spawn/src/configs/resolve-config.ts
|
|
5625
6708
|
function resolveConfig(agentId) {
|
|
@@ -5759,6 +6842,7 @@ async function spawn3(agentId, options, context) {
|
|
|
5759
6842
|
const argv = [binaryName, ...spawnArgs];
|
|
5760
6843
|
const execution = resolvePoeCommandExecution({
|
|
5761
6844
|
cwd: options.cwd ?? process.cwd(),
|
|
6845
|
+
runtimeConfigCwd: options.runtimeConfigCwd,
|
|
5762
6846
|
env: processEnv ?? process.env,
|
|
5763
6847
|
argv,
|
|
5764
6848
|
tool: resolvedId,
|
|
@@ -5767,7 +6851,8 @@ async function spawn3(agentId, options, context) {
|
|
|
5767
6851
|
runtimeImage: options.runtimeImage,
|
|
5768
6852
|
runtimeTemplate: options.runtimeTemplate,
|
|
5769
6853
|
detach: options.detach,
|
|
5770
|
-
mountPoeCode: options.mountPoeCode
|
|
6854
|
+
mountPoeCode: options.mountPoeCode,
|
|
6855
|
+
runnerSync: options.runnerSync
|
|
5771
6856
|
},
|
|
5772
6857
|
context,
|
|
5773
6858
|
openSpec: {
|
|
@@ -5804,6 +6889,7 @@ async function spawn3(agentId, options, context) {
|
|
|
5804
6889
|
stdout: "",
|
|
5805
6890
|
stderr: "",
|
|
5806
6891
|
exitCode: 0,
|
|
6892
|
+
detached: { jobId: result.jobId, envId: result.envId },
|
|
5807
6893
|
...logFilePath ? { logFile: logFilePath } : {}
|
|
5808
6894
|
};
|
|
5809
6895
|
}
|
|
@@ -5825,11 +6911,11 @@ function resolveSpawnLogPath(options) {
|
|
|
5825
6911
|
if (!options.logDir || !options.logFileName) {
|
|
5826
6912
|
return void 0;
|
|
5827
6913
|
}
|
|
5828
|
-
return
|
|
6914
|
+
return path31.join(options.logDir, options.logFileName);
|
|
5829
6915
|
}
|
|
5830
6916
|
function openSpawnLog(filePath) {
|
|
5831
6917
|
try {
|
|
5832
|
-
mkdirSync(
|
|
6918
|
+
mkdirSync(path31.dirname(filePath), { recursive: true });
|
|
5833
6919
|
return openSync(filePath, "a");
|
|
5834
6920
|
} catch {
|
|
5835
6921
|
return void 0;
|
|
@@ -6225,7 +7311,7 @@ import chalk8 from "chalk";
|
|
|
6225
7311
|
|
|
6226
7312
|
// packages/design-system/src/dashboard/terminal.ts
|
|
6227
7313
|
import readline from "node:readline";
|
|
6228
|
-
import { PassThrough } from "node:stream";
|
|
7314
|
+
import { PassThrough as PassThrough2 } from "node:stream";
|
|
6229
7315
|
|
|
6230
7316
|
// packages/design-system/src/prompts/index.ts
|
|
6231
7317
|
import chalk15 from "chalk";
|
|
@@ -6257,9 +7343,9 @@ import chalk16 from "chalk";
|
|
|
6257
7343
|
var DEFAULT_ACTIVITY_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
6258
7344
|
|
|
6259
7345
|
// packages/agent-spawn/src/acp/replay.ts
|
|
6260
|
-
import
|
|
7346
|
+
import path32 from "node:path";
|
|
6261
7347
|
import { homedir as homedir2 } from "node:os";
|
|
6262
|
-
import { open as open2, readdir as
|
|
7348
|
+
import { open as open2, readdir as readdir5 } from "node:fs/promises";
|
|
6263
7349
|
import { createInterface } from "node:readline";
|
|
6264
7350
|
|
|
6265
7351
|
// packages/poe-acp-client/src/acp-client.ts
|
|
@@ -6276,13 +7362,13 @@ import { homedir } from "node:os";
|
|
|
6276
7362
|
import { join } from "node:path";
|
|
6277
7363
|
|
|
6278
7364
|
// packages/agent-spawn/src/acp/middlewares/spawn-log.ts
|
|
6279
|
-
import
|
|
7365
|
+
import path33 from "node:path";
|
|
6280
7366
|
import { homedir as homedir3 } from "node:os";
|
|
6281
7367
|
import { mkdir as mkdir5, open as open3 } from "node:fs/promises";
|
|
6282
7368
|
|
|
6283
7369
|
// packages/memory/src/tokens.ts
|
|
6284
7370
|
import * as fs10 from "node:fs/promises";
|
|
6285
|
-
import
|
|
7371
|
+
import path34 from "node:path";
|
|
6286
7372
|
|
|
6287
7373
|
// packages/tokenfill/dist/tokenizer.js
|
|
6288
7374
|
import { get_encoding } from "tiktoken";
|
|
@@ -6366,11 +7452,11 @@ async function computeTokenStats(root) {
|
|
|
6366
7452
|
}
|
|
6367
7453
|
}
|
|
6368
7454
|
}
|
|
6369
|
-
const repoRoot =
|
|
7455
|
+
const repoRoot = path34.resolve(root, "..", "..");
|
|
6370
7456
|
let sourceTokens = 0;
|
|
6371
7457
|
const missingSources = [];
|
|
6372
7458
|
for (const sourcePath of sourcePaths) {
|
|
6373
|
-
const absPath =
|
|
7459
|
+
const absPath = path34.isAbsolute(sourcePath) ? sourcePath : path34.resolve(repoRoot, sourcePath);
|
|
6374
7460
|
try {
|
|
6375
7461
|
const content = await fs10.readFile(absPath, "utf8");
|
|
6376
7462
|
sourceTokens += countTokens(content);
|
|
@@ -6421,10 +7507,10 @@ function resolveRunners(overrides) {
|
|
|
6421
7507
|
async function ingest(root, opts, runners) {
|
|
6422
7508
|
const resolved = resolveRunners(runners);
|
|
6423
7509
|
const source = await materializeSource(opts.source);
|
|
6424
|
-
const indexMdBytes = await fs11.readFile(
|
|
7510
|
+
const indexMdBytes = await fs11.readFile(path35.join(root, MEMORY_INDEX_RELPATH));
|
|
6425
7511
|
const configOptions = {
|
|
6426
7512
|
fs: fs11,
|
|
6427
|
-
filePath:
|
|
7513
|
+
filePath: path35.join(inferRepoRoot(root), "poe-code.json")
|
|
6428
7514
|
};
|
|
6429
7515
|
const agentId = await resolveAgent(configOptions, opts.agent ?? null) ?? opts.agent ?? "claude-code";
|
|
6430
7516
|
const key = resolved.computeIngestKey({
|
|
@@ -6514,7 +7600,7 @@ async function materializeSource(source) {
|
|
|
6514
7600
|
throw new Error("URL ingest not implemented yet.");
|
|
6515
7601
|
}
|
|
6516
7602
|
function inferRepoRoot(root) {
|
|
6517
|
-
return
|
|
7603
|
+
return path35.resolve(root, "..", "..");
|
|
6518
7604
|
}
|
|
6519
7605
|
async function runWithTimeout(promise, timeoutMs) {
|
|
6520
7606
|
return await new Promise((resolve2, reject) => {
|
|
@@ -7272,8 +8358,8 @@ function printMcpConfig() {
|
|
|
7272
8358
|
}
|
|
7273
8359
|
|
|
7274
8360
|
// packages/agent-skill-config/src/configs.ts
|
|
7275
|
-
import
|
|
7276
|
-
import
|
|
8361
|
+
import os5 from "node:os";
|
|
8362
|
+
import path36 from "node:path";
|
|
7277
8363
|
var agentSkillConfigs = {
|
|
7278
8364
|
"claude-code": {
|
|
7279
8365
|
globalSkillDir: "~/.claude/skills",
|
|
@@ -7306,8 +8392,8 @@ function resolveAgentSupport(input, registry = agentSkillConfigs) {
|
|
|
7306
8392
|
}
|
|
7307
8393
|
|
|
7308
8394
|
// packages/agent-skill-config/src/templates.ts
|
|
7309
|
-
import { readFile as
|
|
7310
|
-
import
|
|
8395
|
+
import { readFile as readFile15, stat as stat6 } from "node:fs/promises";
|
|
8396
|
+
import path37 from "node:path";
|
|
7311
8397
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
7312
8398
|
|
|
7313
8399
|
// packages/agent-skill-config/src/apply.ts
|
|
@@ -7440,7 +8526,7 @@ function resolveConfigPath2(config, platform) {
|
|
|
7440
8526
|
}
|
|
7441
8527
|
|
|
7442
8528
|
// packages/agent-mcp-config/src/apply.ts
|
|
7443
|
-
import
|
|
8529
|
+
import path38 from "node:path";
|
|
7444
8530
|
import { parse as parseYaml3, stringify as stringifyYaml2 } from "yaml";
|
|
7445
8531
|
|
|
7446
8532
|
// packages/agent-mcp-config/src/shapes.ts
|
|
@@ -7532,7 +8618,7 @@ function getShapeTransformer(shape) {
|
|
|
7532
8618
|
|
|
7533
8619
|
// packages/agent-mcp-config/src/apply.ts
|
|
7534
8620
|
function getConfigDirectory(configPath) {
|
|
7535
|
-
return
|
|
8621
|
+
return path38.dirname(configPath);
|
|
7536
8622
|
}
|
|
7537
8623
|
var UnsupportedAgentError2 = class extends Error {
|
|
7538
8624
|
constructor(agentId) {
|
|
@@ -7558,9 +8644,9 @@ function expandHomePath(configPath, homeDir) {
|
|
|
7558
8644
|
return homeDir;
|
|
7559
8645
|
}
|
|
7560
8646
|
if (configPath.startsWith("~/")) {
|
|
7561
|
-
return
|
|
8647
|
+
return path38.join(homeDir, configPath.slice(2));
|
|
7562
8648
|
}
|
|
7563
|
-
return
|
|
8649
|
+
return path38.join(homeDir, configPath.slice(1));
|
|
7564
8650
|
}
|
|
7565
8651
|
function parseYamlDocument(content) {
|
|
7566
8652
|
if (content.trim() === "") {
|
|
@@ -7593,7 +8679,7 @@ async function writeYamlConfig(configPath, document, options) {
|
|
|
7593
8679
|
return;
|
|
7594
8680
|
}
|
|
7595
8681
|
const absolutePath = expandHomePath(configPath, options.homeDir);
|
|
7596
|
-
const configDir =
|
|
8682
|
+
const configDir = path38.dirname(absolutePath);
|
|
7597
8683
|
await options.fs.mkdir(configDir, { recursive: true });
|
|
7598
8684
|
await options.fs.writeFile(absolutePath, serializeYamlDocument(document), {
|
|
7599
8685
|
encoding: "utf8"
|
|
@@ -7771,7 +8857,7 @@ async function installMemory(options) {
|
|
|
7771
8857
|
|
|
7772
8858
|
// packages/memory/src/query.ts
|
|
7773
8859
|
import * as fs12 from "node:fs/promises";
|
|
7774
|
-
import
|
|
8860
|
+
import path39 from "node:path";
|
|
7775
8861
|
async function queryMemory(root, options) {
|
|
7776
8862
|
const pages = await listPages(root);
|
|
7777
8863
|
if (pages.length === 0) {
|
|
@@ -7785,7 +8871,7 @@ async function queryMemory(root, options) {
|
|
|
7785
8871
|
}
|
|
7786
8872
|
const configOptions = {
|
|
7787
8873
|
fs: fs12,
|
|
7788
|
-
filePath:
|
|
8874
|
+
filePath: path39.join(inferRepoRoot2(root), "poe-code.json")
|
|
7789
8875
|
};
|
|
7790
8876
|
const agentId = await resolveAgent(configOptions, options.agent ?? null) ?? options.agent ?? "claude-code";
|
|
7791
8877
|
const context = await selectQueryContext(root, options.question, options.budget);
|
|
@@ -7800,7 +8886,7 @@ async function queryMemory(root, options) {
|
|
|
7800
8886
|
}
|
|
7801
8887
|
async function selectQueryContext(root, question, budget) {
|
|
7802
8888
|
const [indexText, pages] = await Promise.all([
|
|
7803
|
-
fs12.readFile(
|
|
8889
|
+
fs12.readFile(path39.join(root, MEMORY_INDEX_RELPATH), "utf8"),
|
|
7804
8890
|
listPages(root)
|
|
7805
8891
|
]);
|
|
7806
8892
|
const indexTokens = countTokens(indexText);
|
|
@@ -7879,12 +8965,12 @@ function tokenize(text4) {
|
|
|
7879
8965
|
return text4.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length > 0);
|
|
7880
8966
|
}
|
|
7881
8967
|
function inferRepoRoot2(root) {
|
|
7882
|
-
return
|
|
8968
|
+
return path39.resolve(root, "..", "..");
|
|
7883
8969
|
}
|
|
7884
8970
|
|
|
7885
8971
|
// packages/memory/src/explain.ts
|
|
7886
8972
|
import * as fs13 from "node:fs/promises";
|
|
7887
|
-
import
|
|
8973
|
+
import path40 from "node:path";
|
|
7888
8974
|
async function explainPage(root, options) {
|
|
7889
8975
|
const targetPage = await readPageIfPresent(root, options.relPath);
|
|
7890
8976
|
if (targetPage === void 0) {
|
|
@@ -7907,7 +8993,7 @@ async function explainPage(root, options) {
|
|
|
7907
8993
|
}
|
|
7908
8994
|
const configOptions = {
|
|
7909
8995
|
fs: fs13,
|
|
7910
|
-
filePath:
|
|
8996
|
+
filePath: path40.join(inferRepoRoot3(root), "poe-code.json")
|
|
7911
8997
|
};
|
|
7912
8998
|
const agentId = await resolveAgent(configOptions, options.agent ?? null) ?? options.agent ?? "claude-code";
|
|
7913
8999
|
const response = await spawn3(agentId, { prompt });
|
|
@@ -7956,7 +9042,7 @@ async function readPageIfPresent(root, relPath) {
|
|
|
7956
9042
|
}
|
|
7957
9043
|
}
|
|
7958
9044
|
function inferRepoRoot3(root) {
|
|
7959
|
-
return
|
|
9045
|
+
return path40.resolve(root, "..", "..");
|
|
7960
9046
|
}
|
|
7961
9047
|
|
|
7962
9048
|
// packages/memory/src/explain.cli.ts
|
|
@@ -7969,9 +9055,9 @@ async function runMemoryExplain(input) {
|
|
|
7969
9055
|
}
|
|
7970
9056
|
|
|
7971
9057
|
// packages/memory/src/handle.ts
|
|
7972
|
-
import
|
|
9058
|
+
import path41 from "node:path";
|
|
7973
9059
|
function openMemory(opts) {
|
|
7974
|
-
if (!
|
|
9060
|
+
if (!path41.isAbsolute(opts.root)) {
|
|
7975
9061
|
throw new Error(`openMemory: root must be absolute, got ${opts.root}`);
|
|
7976
9062
|
}
|
|
7977
9063
|
const root = opts.root;
|