poe-code 3.0.202 → 3.0.203
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/experiment.js +11 -4
- package/dist/cli/commands/experiment.js.map +1 -1
- package/dist/cli/commands/ralph.js +12 -5
- package/dist/cli/commands/ralph.js.map +1 -1
- package/dist/cli/commands/runtime-options.d.ts +10 -0
- package/dist/cli/commands/runtime-options.js +23 -0
- package/dist/cli/commands/runtime-options.js.map +1 -0
- package/dist/cli/commands/spawn.js +9 -3
- package/dist/cli/commands/spawn.js.map +1 -1
- package/dist/index.js +21873 -20138
- package/dist/index.js.map +4 -4
- package/dist/providers/claude-code.js +2741 -1706
- package/dist/providers/claude-code.js.map +4 -4
- package/dist/providers/codex.js +2770 -1735
- package/dist/providers/codex.js.map +4 -4
- package/dist/providers/goose.js +2640 -1605
- package/dist/providers/goose.js.map +4 -4
- package/dist/providers/kimi.js +2740 -1705
- package/dist/providers/kimi.js.map +4 -4
- package/dist/providers/opencode.js +2741 -1706
- package/dist/providers/opencode.js.map +4 -4
- package/dist/providers/poe-agent.js +19451 -17229
- package/dist/providers/poe-agent.js.map +4 -4
- package/dist/providers/spawn-options.d.ts +6 -0
- package/dist/sdk/experiment.js +5 -0
- package/dist/sdk/experiment.js.map +1 -1
- package/dist/sdk/ralph.js +5 -0
- package/dist/sdk/ralph.js.map +1 -1
- package/dist/sdk/spawn.js +17 -1
- package/dist/sdk/spawn.js.map +1 -1
- package/dist/sdk/types.d.ts +11 -0
- package/package.json +1 -1
- package/packages/memory/dist/index.js +2353 -420
- package/packages/memory/dist/index.js.map +4 -4
- package/packages/superintendent/dist/commands/run.d.ts +35 -0
- package/packages/superintendent/dist/commands/run.js +49 -1
- package/packages/superintendent/dist/commands/superintendent-group.d.ts +30 -0
- package/packages/superintendent/dist/runtime/agent-runner.d.ts +30 -0
- package/packages/superintendent/dist/runtime/agent-runner.js +119 -0
- package/packages/superintendent/dist/runtime/loop.d.ts +6 -1
- package/packages/superintendent/dist/runtime/loop.js +3 -11
- package/packages/superintendent/dist/runtime/run-builder.d.ts +1 -0
- package/packages/superintendent/dist/runtime/run-builder.js +3 -25
- package/packages/superintendent/dist/runtime/run-inspector.d.ts +1 -0
- package/packages/superintendent/dist/runtime/run-inspector.js +3 -25
- package/packages/superintendent/dist/runtime/run-owner-review.d.ts +1 -0
- package/packages/superintendent/dist/runtime/run-owner-review.js +3 -25
- package/packages/superintendent/dist/runtime/run-superintendent.d.ts +1 -0
- package/packages/superintendent/dist/runtime/run-superintendent.js +3 -25
|
@@ -165,6 +165,136 @@ function parseRunner(raw) {
|
|
|
165
165
|
workspace: parseRunnerWorkspace(record.workspace)
|
|
166
166
|
});
|
|
167
167
|
}
|
|
168
|
+
function parseRuntime(raw) {
|
|
169
|
+
if (raw === void 0) {
|
|
170
|
+
return {
|
|
171
|
+
type: "host",
|
|
172
|
+
build_args: {},
|
|
173
|
+
mounts: []
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const record = asRecord(raw);
|
|
177
|
+
if (record === void 0) {
|
|
178
|
+
throw new Error("runtime: expected an object.");
|
|
179
|
+
}
|
|
180
|
+
const type = parseRuntimeType(record.type);
|
|
181
|
+
const shared = parseSharedRuntimeFields(record);
|
|
182
|
+
if (type === "docker") {
|
|
183
|
+
return omitUndefined({
|
|
184
|
+
...shared,
|
|
185
|
+
type,
|
|
186
|
+
image: parseOptionalString(record.image),
|
|
187
|
+
dockerfile: parseOptionalString(record.dockerfile),
|
|
188
|
+
build_context: parseOptionalString(record.build_context),
|
|
189
|
+
engine: parseEngine(record.engine),
|
|
190
|
+
network: parseOptionalString(record.network),
|
|
191
|
+
extra_args: parseOptionalStringArray(record.extra_args)
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
if (type === "e2b") {
|
|
195
|
+
const preserveAfterExitHours = parseOptionalNumber(record.preserve_after_exit_hours) ?? 24;
|
|
196
|
+
if (preserveAfterExitHours < 0 || preserveAfterExitHours > 168) {
|
|
197
|
+
throw new Error("preserve_after_exit_hours: expected a number from 0 to 168.");
|
|
198
|
+
}
|
|
199
|
+
return omitUndefined({
|
|
200
|
+
...shared,
|
|
201
|
+
type,
|
|
202
|
+
template_id: parseOptionalString(record.template_id),
|
|
203
|
+
dockerfile: parseOptionalString(record.dockerfile),
|
|
204
|
+
build_context: parseOptionalString(record.build_context),
|
|
205
|
+
cpu: parseOptionalNumber(record.cpu),
|
|
206
|
+
memory_mb: parseOptionalNumber(record.memory_mb),
|
|
207
|
+
timeout_minutes: parseOptionalNumber(record.timeout_minutes),
|
|
208
|
+
preserve_after_exit_hours: preserveAfterExitHours,
|
|
209
|
+
api_key_env: parseOptionalString(record.api_key_env) ?? "E2B_API_KEY"
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
...shared,
|
|
214
|
+
type
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function resolveRuntime({
|
|
218
|
+
cwd,
|
|
219
|
+
config
|
|
220
|
+
}) {
|
|
221
|
+
const runtime = config.runtime;
|
|
222
|
+
return runtimeResolvers[runtime.type]({ cwd, runtime });
|
|
223
|
+
}
|
|
224
|
+
var runtimeResolvers = {
|
|
225
|
+
host({ runtime }) {
|
|
226
|
+
return {
|
|
227
|
+
runtime,
|
|
228
|
+
runner: "host",
|
|
229
|
+
dockerfilePath: null,
|
|
230
|
+
buildContext: null
|
|
231
|
+
};
|
|
232
|
+
},
|
|
233
|
+
docker({ cwd, runtime }) {
|
|
234
|
+
const dockerRuntime = runtime;
|
|
235
|
+
const { dockerfilePath, buildContext } = resolveRuntimeBuildPaths(cwd, dockerRuntime);
|
|
236
|
+
if (dockerRuntime.image !== void 0) {
|
|
237
|
+
return {
|
|
238
|
+
runtime: dockerRuntime,
|
|
239
|
+
runner: "docker",
|
|
240
|
+
dockerfilePath: null,
|
|
241
|
+
buildContext: null
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
if (!existsSync(dockerfilePath)) {
|
|
245
|
+
throw new Error(`Docker runtime requires image or a Dockerfile at ${dockerfilePath}.`);
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
runtime: dockerRuntime,
|
|
249
|
+
runner: "docker",
|
|
250
|
+
dockerfilePath,
|
|
251
|
+
buildContext
|
|
252
|
+
};
|
|
253
|
+
},
|
|
254
|
+
e2b({ cwd, runtime }) {
|
|
255
|
+
const e2bRuntime = runtime;
|
|
256
|
+
const { dockerfilePath, buildContext } = resolveRuntimeBuildPaths(cwd, e2bRuntime);
|
|
257
|
+
if (e2bRuntime.template_id !== void 0) {
|
|
258
|
+
return {
|
|
259
|
+
runtime: e2bRuntime,
|
|
260
|
+
runner: "e2b",
|
|
261
|
+
dockerfilePath: null,
|
|
262
|
+
buildContext: null
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
if (!existsSync(dockerfilePath)) {
|
|
266
|
+
throw new Error(`E2B runtime requires template_id or a Dockerfile at ${dockerfilePath}.`);
|
|
267
|
+
}
|
|
268
|
+
return {
|
|
269
|
+
runtime: e2bRuntime,
|
|
270
|
+
runner: "e2b",
|
|
271
|
+
dockerfilePath,
|
|
272
|
+
buildContext
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
function resolveRuntimeBuildPaths(cwd, runtime) {
|
|
277
|
+
return {
|
|
278
|
+
dockerfilePath: path2.resolve(cwd, runtime.dockerfile ?? path2.join(".poe-code", "Dockerfile")),
|
|
279
|
+
buildContext: path2.resolve(cwd, runtime.build_context ?? ".")
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
function parseSharedRuntimeFields(record) {
|
|
283
|
+
return omitUndefined({
|
|
284
|
+
build_args: parseBuildArgs(record.build_args),
|
|
285
|
+
mounts: parseMounts(record.mounts),
|
|
286
|
+
link: parseOptionalString(record.link)
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
function parseRuntimeType(value) {
|
|
290
|
+
if (value === void 0) {
|
|
291
|
+
return "host";
|
|
292
|
+
}
|
|
293
|
+
if (value === "host" || value === "docker" || value === "e2b") {
|
|
294
|
+
return value;
|
|
295
|
+
}
|
|
296
|
+
throw new Error('type: expected "host", "docker", or "e2b".');
|
|
297
|
+
}
|
|
168
298
|
function createDefaultRunnerScope() {
|
|
169
299
|
return {
|
|
170
300
|
detach: false,
|
|
@@ -244,6 +374,18 @@ function parseMounts(value) {
|
|
|
244
374
|
});
|
|
245
375
|
});
|
|
246
376
|
}
|
|
377
|
+
function parseOptionalString(value) {
|
|
378
|
+
if (value === void 0) {
|
|
379
|
+
return void 0;
|
|
380
|
+
}
|
|
381
|
+
if (typeof value !== "string") {
|
|
382
|
+
throw new Error("expected a string.");
|
|
383
|
+
}
|
|
384
|
+
if (value.length === 0) {
|
|
385
|
+
return void 0;
|
|
386
|
+
}
|
|
387
|
+
return value;
|
|
388
|
+
}
|
|
247
389
|
function parseOptionalStringArray(value, key = "") {
|
|
248
390
|
if (value === void 0) {
|
|
249
391
|
return void 0;
|
|
@@ -258,6 +400,13 @@ function parseOptionalStringArray(value, key = "") {
|
|
|
258
400
|
return entry;
|
|
259
401
|
});
|
|
260
402
|
}
|
|
403
|
+
function parseEngine(value) {
|
|
404
|
+
const engine = parseOptionalString(value);
|
|
405
|
+
if (engine === void 0 || engine === "docker" || engine === "podman") {
|
|
406
|
+
return engine;
|
|
407
|
+
}
|
|
408
|
+
throw new Error('engine: expected "docker" or "podman".');
|
|
409
|
+
}
|
|
261
410
|
function parseOptionalNumber(value, key = "") {
|
|
262
411
|
if (value === void 0) {
|
|
263
412
|
return void 0;
|
|
@@ -397,11 +546,11 @@ function stripBom(content) {
|
|
|
397
546
|
function mergeLayers(layers) {
|
|
398
547
|
return mergeObjectLayers(layers, []);
|
|
399
548
|
}
|
|
400
|
-
function mergeObjectLayers(layers,
|
|
549
|
+
function mergeObjectLayers(layers, path38) {
|
|
401
550
|
const data = {};
|
|
402
551
|
const sources = {};
|
|
403
552
|
for (const key of collectKeys(layers)) {
|
|
404
|
-
const resolved = resolveKey(layers, key,
|
|
553
|
+
const resolved = resolveKey(layers, key, path38);
|
|
405
554
|
if (resolved === void 0) {
|
|
406
555
|
continue;
|
|
407
556
|
}
|
|
@@ -419,7 +568,7 @@ function collectKeys(layers) {
|
|
|
419
568
|
}
|
|
420
569
|
return [...keys];
|
|
421
570
|
}
|
|
422
|
-
function resolveKey(layers, key,
|
|
571
|
+
function resolveKey(layers, key, path38) {
|
|
423
572
|
let winningSource;
|
|
424
573
|
let winningValue;
|
|
425
574
|
const objectLayers = [];
|
|
@@ -449,9 +598,9 @@ function resolveKey(layers, key, path33) {
|
|
|
449
598
|
if (winningSource === void 0) {
|
|
450
599
|
return void 0;
|
|
451
600
|
}
|
|
452
|
-
const fullPath = buildPath(
|
|
601
|
+
const fullPath = buildPath(path38, key);
|
|
453
602
|
if (isPlainObject(winningValue)) {
|
|
454
|
-
const merged = mergeObjectLayers(objectLayers, [...
|
|
603
|
+
const merged = mergeObjectLayers(objectLayers, [...path38, key]);
|
|
455
604
|
return {
|
|
456
605
|
value: merged.data,
|
|
457
606
|
sources: {
|
|
@@ -476,8 +625,8 @@ function isWinningCandidate(key, value) {
|
|
|
476
625
|
}
|
|
477
626
|
return true;
|
|
478
627
|
}
|
|
479
|
-
function buildPath(
|
|
480
|
-
return [...
|
|
628
|
+
function buildPath(path38, key) {
|
|
629
|
+
return [...path38, key].join(".");
|
|
481
630
|
}
|
|
482
631
|
function isPlainObject(value) {
|
|
483
632
|
if (value === null || Array.isArray(value) || typeof value !== "object") {
|
|
@@ -1111,16 +1260,16 @@ function getConfigFormat(pathOrFormat) {
|
|
|
1111
1260
|
}
|
|
1112
1261
|
return formatRegistry[formatName];
|
|
1113
1262
|
}
|
|
1114
|
-
function detectFormat2(
|
|
1115
|
-
const ext = getExtension(
|
|
1263
|
+
function detectFormat2(path38) {
|
|
1264
|
+
const ext = getExtension(path38);
|
|
1116
1265
|
return extensionMap[ext];
|
|
1117
1266
|
}
|
|
1118
|
-
function getExtension(
|
|
1119
|
-
const lastDot =
|
|
1267
|
+
function getExtension(path38) {
|
|
1268
|
+
const lastDot = path38.lastIndexOf(".");
|
|
1120
1269
|
if (lastDot === -1) {
|
|
1121
1270
|
return "";
|
|
1122
1271
|
}
|
|
1123
|
-
return
|
|
1272
|
+
return path38.slice(lastDot).toLowerCase();
|
|
1124
1273
|
}
|
|
1125
1274
|
|
|
1126
1275
|
// packages/config-mutations/src/execution/path-utils.ts
|
|
@@ -1876,9 +2025,151 @@ function createInvalidBackupPath(filePath) {
|
|
|
1876
2025
|
function isRecord(value) {
|
|
1877
2026
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
1878
2027
|
}
|
|
2028
|
+
function resolveConfigPath(homeDir) {
|
|
2029
|
+
return path7.join(homeDir, ".poe-code", "config.json");
|
|
2030
|
+
}
|
|
2031
|
+
function resolveProjectConfigPath(cwd) {
|
|
2032
|
+
return path7.join(cwd, ".poe-code", "config.json");
|
|
2033
|
+
}
|
|
1879
2034
|
var EMPTY_DOCUMENT = `${JSON.stringify({}, null, 2)}
|
|
1880
2035
|
`;
|
|
1881
2036
|
|
|
2037
|
+
// packages/poe-code-config/src/resolve.ts
|
|
2038
|
+
function resolveScope(schema, fileValues, env = {}) {
|
|
2039
|
+
const resolved = {};
|
|
2040
|
+
for (const key of Object.keys(schema)) {
|
|
2041
|
+
const field = schema[key];
|
|
2042
|
+
const envValue = resolveEnvValue(field, env, key);
|
|
2043
|
+
const fileValue = resolveFileValue(field, fileValues?.[key], key);
|
|
2044
|
+
resolved[key] = envValue ?? fileValue ?? field.default;
|
|
2045
|
+
}
|
|
2046
|
+
return resolved;
|
|
2047
|
+
}
|
|
2048
|
+
function resolveEnvValue(field, env, key) {
|
|
2049
|
+
if (!field.env) {
|
|
2050
|
+
return void 0;
|
|
2051
|
+
}
|
|
2052
|
+
const raw = env[field.env];
|
|
2053
|
+
if (raw === void 0) {
|
|
2054
|
+
return void 0;
|
|
2055
|
+
}
|
|
2056
|
+
return coerceValue(field, raw, key);
|
|
2057
|
+
}
|
|
2058
|
+
function resolveFileValue(field, value, key) {
|
|
2059
|
+
return coerceValue(field, value, key);
|
|
2060
|
+
}
|
|
2061
|
+
function coerceValue(field, value, key) {
|
|
2062
|
+
switch (field.type) {
|
|
2063
|
+
case "string":
|
|
2064
|
+
return typeof value === "string" ? value : void 0;
|
|
2065
|
+
case "number":
|
|
2066
|
+
return coerceNumber(value);
|
|
2067
|
+
case "boolean":
|
|
2068
|
+
return coerceBoolean(value);
|
|
2069
|
+
case "json":
|
|
2070
|
+
return coerceJson(field, value, key);
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
function coerceNumber(value) {
|
|
2074
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2075
|
+
return value;
|
|
2076
|
+
}
|
|
2077
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
2078
|
+
return void 0;
|
|
2079
|
+
}
|
|
2080
|
+
const parsed = Number(value);
|
|
2081
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
2082
|
+
}
|
|
2083
|
+
function coerceBoolean(value) {
|
|
2084
|
+
if (typeof value === "boolean") {
|
|
2085
|
+
return value;
|
|
2086
|
+
}
|
|
2087
|
+
if (value === "true" || value === "1") {
|
|
2088
|
+
return true;
|
|
2089
|
+
}
|
|
2090
|
+
if (value === "false" || value === "0") {
|
|
2091
|
+
return false;
|
|
2092
|
+
}
|
|
2093
|
+
return void 0;
|
|
2094
|
+
}
|
|
2095
|
+
function coerceJson(field, value, key) {
|
|
2096
|
+
if (value === void 0) {
|
|
2097
|
+
return void 0;
|
|
2098
|
+
}
|
|
2099
|
+
const parsedValue = parseJsonValue(value, key);
|
|
2100
|
+
try {
|
|
2101
|
+
return field.parse(parsedValue);
|
|
2102
|
+
} catch (error2) {
|
|
2103
|
+
const message2 = error2 instanceof Error ? error2.message : "Invalid JSON value.";
|
|
2104
|
+
throw new Error(`Invalid config value for "${key}": ${message2}`);
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
function parseJsonValue(value, key) {
|
|
2108
|
+
if (typeof value !== "string") {
|
|
2109
|
+
return value;
|
|
2110
|
+
}
|
|
2111
|
+
try {
|
|
2112
|
+
return JSON.parse(value);
|
|
2113
|
+
} catch {
|
|
2114
|
+
throw new Error(`Invalid config value for "${key}": expected valid JSON.`);
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
// packages/poe-code-config/src/merge.ts
|
|
2119
|
+
function deepMergeDocuments(base, override) {
|
|
2120
|
+
const merged = {};
|
|
2121
|
+
const scopes = /* @__PURE__ */ new Set([...Object.keys(base), ...Object.keys(override)]);
|
|
2122
|
+
for (const scope of scopes) {
|
|
2123
|
+
const baseScope = base[scope] ?? {};
|
|
2124
|
+
const overrideScope = override[scope] ?? {};
|
|
2125
|
+
const nextScope = mergeScope(scope, baseScope, overrideScope);
|
|
2126
|
+
if (Object.keys(nextScope).length > 0) {
|
|
2127
|
+
merged[scope] = nextScope;
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
return merged;
|
|
2131
|
+
}
|
|
2132
|
+
function mergeScope(scope, baseScope, overrideScope) {
|
|
2133
|
+
if (scope === "runtime") {
|
|
2134
|
+
return mergeRuntimeScope(baseScope, overrideScope);
|
|
2135
|
+
}
|
|
2136
|
+
const scopeEntries = Object.entries(overrideScope).filter(([, value]) => value !== void 0);
|
|
2137
|
+
return {
|
|
2138
|
+
...baseScope,
|
|
2139
|
+
...Object.fromEntries(scopeEntries)
|
|
2140
|
+
};
|
|
2141
|
+
}
|
|
2142
|
+
function mergeRuntimeScope(baseScope, overrideScope, path38 = []) {
|
|
2143
|
+
const merged = {};
|
|
2144
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(baseScope), ...Object.keys(overrideScope)]);
|
|
2145
|
+
for (const key of keys) {
|
|
2146
|
+
const baseValue = baseScope[key];
|
|
2147
|
+
const overrideValue = overrideScope[key];
|
|
2148
|
+
if (overrideValue === void 0) {
|
|
2149
|
+
if (baseValue !== void 0) {
|
|
2150
|
+
merged[key] = baseValue;
|
|
2151
|
+
}
|
|
2152
|
+
continue;
|
|
2153
|
+
}
|
|
2154
|
+
if (isRuntimeConcatenativeArray([...path38, key]) && Array.isArray(baseValue) && Array.isArray(overrideValue)) {
|
|
2155
|
+
merged[key] = [...baseValue, ...overrideValue];
|
|
2156
|
+
continue;
|
|
2157
|
+
}
|
|
2158
|
+
if (isRecord2(baseValue) && isRecord2(overrideValue)) {
|
|
2159
|
+
merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...path38, key]);
|
|
2160
|
+
continue;
|
|
2161
|
+
}
|
|
2162
|
+
merged[key] = overrideValue;
|
|
2163
|
+
}
|
|
2164
|
+
return merged;
|
|
2165
|
+
}
|
|
2166
|
+
function isRuntimeConcatenativeArray(path38) {
|
|
2167
|
+
return path38.join(".") === "mounts" || path38.join(".") === "runner.workspace.exclude";
|
|
2168
|
+
}
|
|
2169
|
+
function isRecord2(value) {
|
|
2170
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
2171
|
+
}
|
|
2172
|
+
|
|
1882
2173
|
// packages/poe-code-config/src/memory.ts
|
|
1883
2174
|
async function configuredMemoryRoot(options) {
|
|
1884
2175
|
return (await resolveMemoryConfig(options)).root;
|
|
@@ -1938,115 +2229,567 @@ import path9 from "node:path";
|
|
|
1938
2229
|
// packages/file-lock/src/lock.ts
|
|
1939
2230
|
import * as fsPromises from "node:fs/promises";
|
|
1940
2231
|
import * as os from "node:os";
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
// packages/poe-code-config/src/state/templates.ts
|
|
1946
|
-
import path10 from "node:path";
|
|
1947
|
-
|
|
1948
|
-
// packages/memory/src/resolve-root.ts
|
|
1949
|
-
var MEMORY_ROOT_ENV_VAR = "POE_CODE_MEMORY_ROOT";
|
|
1950
|
-
async function resolveConfiguredMemoryRoot(options) {
|
|
1951
|
-
const envOverride = options.env[MEMORY_ROOT_ENV_VAR]?.trim();
|
|
1952
|
-
if (envOverride && envOverride.length > 0) {
|
|
1953
|
-
return resolveAgainstCwd(options.cwd, envOverride);
|
|
2232
|
+
var LockTimeoutError = class extends Error {
|
|
2233
|
+
constructor(message2) {
|
|
2234
|
+
super(message2);
|
|
2235
|
+
this.name = "LockTimeoutError";
|
|
1954
2236
|
}
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
2237
|
+
};
|
|
2238
|
+
function createAbortError() {
|
|
2239
|
+
const error2 = new Error("The operation was aborted.");
|
|
2240
|
+
error2.name = "AbortError";
|
|
2241
|
+
return error2;
|
|
2242
|
+
}
|
|
2243
|
+
function throwIfAborted(signal) {
|
|
2244
|
+
if (signal?.aborted) {
|
|
2245
|
+
throw createAbortError();
|
|
1962
2246
|
}
|
|
1963
|
-
return resolveMemoryRoot(options.cwd);
|
|
1964
2247
|
}
|
|
1965
|
-
function
|
|
1966
|
-
|
|
2248
|
+
function sleep(ms, signal) {
|
|
2249
|
+
if (!signal) {
|
|
2250
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
2251
|
+
}
|
|
2252
|
+
if (signal.aborted) {
|
|
2253
|
+
return Promise.reject(createAbortError());
|
|
2254
|
+
}
|
|
2255
|
+
return new Promise((resolve2, reject) => {
|
|
2256
|
+
const timeoutId = setTimeout(() => {
|
|
2257
|
+
signal.removeEventListener("abort", onAbort);
|
|
2258
|
+
resolve2();
|
|
2259
|
+
}, ms);
|
|
2260
|
+
const onAbort = () => {
|
|
2261
|
+
clearTimeout(timeoutId);
|
|
2262
|
+
signal.removeEventListener("abort", onAbort);
|
|
2263
|
+
reject(createAbortError());
|
|
2264
|
+
};
|
|
2265
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
2266
|
+
});
|
|
1967
2267
|
}
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
import path12 from "node:path";
|
|
1972
|
-
async function initMemory(root) {
|
|
1973
|
-
await fs.mkdir(path12.join(root, MEMORY_PAGES_DIR_RELPATH), { recursive: true });
|
|
1974
|
-
await writeFileIfMissing(path12.join(root, MEMORY_INDEX_RELPATH), "# Memory index\n");
|
|
1975
|
-
await writeFileIfMissing(path12.join(root, MEMORY_LOG_RELPATH), "");
|
|
2268
|
+
function backoff(attempt, minTimeout, maxTimeout) {
|
|
2269
|
+
const delay = Math.min(maxTimeout, minTimeout * 2 ** attempt);
|
|
2270
|
+
return delay + Math.random() * delay * 0.1;
|
|
1976
2271
|
}
|
|
1977
|
-
|
|
2272
|
+
function hasErrorCode(error2, code) {
|
|
2273
|
+
return !!error2 && typeof error2 === "object" && "code" in error2 && error2.code === code;
|
|
2274
|
+
}
|
|
2275
|
+
function hasAnyErrorCode(error2, codes) {
|
|
2276
|
+
return codes.some((code) => hasErrorCode(error2, code));
|
|
2277
|
+
}
|
|
2278
|
+
function isPidRunning(pid) {
|
|
1978
2279
|
try {
|
|
1979
|
-
|
|
2280
|
+
process.kill(pid, 0);
|
|
2281
|
+
return true;
|
|
1980
2282
|
} catch (error2) {
|
|
1981
|
-
|
|
1982
|
-
throw error2;
|
|
1983
|
-
}
|
|
2283
|
+
return !hasErrorCode(error2, "ESRCH");
|
|
1984
2284
|
}
|
|
1985
2285
|
}
|
|
1986
|
-
function
|
|
1987
|
-
return typeof error2 === "object" && error2 !== null && "code" in error2 && error2.code === code;
|
|
1988
|
-
}
|
|
1989
|
-
|
|
1990
|
-
// packages/memory/src/pages.ts
|
|
1991
|
-
import * as fs2 from "node:fs/promises";
|
|
1992
|
-
import path13 from "node:path";
|
|
1993
|
-
|
|
1994
|
-
// packages/memory/src/frontmatter.ts
|
|
1995
|
-
import { parse as parse5, stringify } from "yaml";
|
|
1996
|
-
function parseFrontmatter(markdown) {
|
|
1997
|
-
const content = markdown.startsWith("\uFEFF") ? markdown.slice(1) : markdown;
|
|
1998
|
-
const openingLineBreak = readOpeningLineBreak(content);
|
|
1999
|
-
if (openingLineBreak === void 0) {
|
|
2000
|
-
return {
|
|
2001
|
-
frontmatter: {},
|
|
2002
|
-
body: markdown
|
|
2003
|
-
};
|
|
2004
|
-
}
|
|
2005
|
-
const frontmatterStart = 3 + openingLineBreak.length;
|
|
2006
|
-
const closingFenceIndex = findClosingFence(content, frontmatterStart);
|
|
2007
|
-
const yamlBlock = content.slice(frontmatterStart, closingFenceIndex);
|
|
2008
|
-
const bodyStart = closingFenceIndex + 4;
|
|
2286
|
+
function createDefaultFs() {
|
|
2009
2287
|
return {
|
|
2010
|
-
|
|
2011
|
-
|
|
2288
|
+
open: (path38, flags) => fsPromises.open(path38, flags),
|
|
2289
|
+
readFile: (path38, encoding) => fsPromises.readFile(path38, encoding),
|
|
2290
|
+
stat: fsPromises.stat,
|
|
2291
|
+
unlink: fsPromises.unlink
|
|
2012
2292
|
};
|
|
2013
2293
|
}
|
|
2014
|
-
function
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2294
|
+
async function removeLockFile(fs14, lockPath, signal) {
|
|
2295
|
+
for (let attempt = 0; attempt <= 4; attempt += 1) {
|
|
2296
|
+
throwIfAborted(signal);
|
|
2297
|
+
try {
|
|
2298
|
+
await fs14.unlink(lockPath);
|
|
2299
|
+
return;
|
|
2300
|
+
} catch (error2) {
|
|
2301
|
+
if (hasErrorCode(error2, "ENOENT")) {
|
|
2302
|
+
return;
|
|
2303
|
+
}
|
|
2304
|
+
if (!hasAnyErrorCode(error2, ["EPERM", "EBUSY"]) || attempt === 4) {
|
|
2305
|
+
throw error2;
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
await sleep(25 * 2 ** attempt, signal);
|
|
2023
2309
|
}
|
|
2024
|
-
return `---
|
|
2025
|
-
${stringify(serialized).trimEnd()}
|
|
2026
|
-
---
|
|
2027
|
-
${body}`;
|
|
2028
2310
|
}
|
|
2029
|
-
function
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2311
|
+
function parseLockMetadata(content) {
|
|
2312
|
+
try {
|
|
2313
|
+
const parsed = JSON.parse(content);
|
|
2314
|
+
if (!parsed || typeof parsed !== "object" || !("host" in parsed) || !("pid" in parsed)) {
|
|
2315
|
+
return void 0;
|
|
2316
|
+
}
|
|
2317
|
+
const { host, pid } = parsed;
|
|
2318
|
+
if (typeof host === "string" && typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0) {
|
|
2319
|
+
return {
|
|
2320
|
+
host,
|
|
2321
|
+
pid
|
|
2322
|
+
};
|
|
2323
|
+
}
|
|
2324
|
+
} catch (ignoredError) {
|
|
2325
|
+
void ignoredError;
|
|
2034
2326
|
}
|
|
2035
|
-
|
|
2036
|
-
|
|
2327
|
+
return void 0;
|
|
2328
|
+
}
|
|
2329
|
+
async function readLockMetadata(fs14, lockPath) {
|
|
2330
|
+
if (!fs14.readFile) {
|
|
2331
|
+
return void 0;
|
|
2037
2332
|
}
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
};
|
|
2333
|
+
try {
|
|
2334
|
+
return parseLockMetadata(await fs14.readFile(lockPath, "utf8"));
|
|
2335
|
+
} catch (error2) {
|
|
2336
|
+
if (hasErrorCode(error2, "ENOENT")) {
|
|
2337
|
+
return null;
|
|
2338
|
+
}
|
|
2339
|
+
return void 0;
|
|
2046
2340
|
}
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2341
|
+
}
|
|
2342
|
+
async function shouldReclaimLock(options) {
|
|
2343
|
+
const metadata = await readLockMetadata(options.fs, options.lockPath);
|
|
2344
|
+
if (metadata === null) {
|
|
2345
|
+
return "missing";
|
|
2346
|
+
}
|
|
2347
|
+
if (metadata?.host === os.hostname()) {
|
|
2348
|
+
return !options.isPidRunning(metadata.pid);
|
|
2349
|
+
}
|
|
2350
|
+
return Date.now() - options.stat.mtimeMs > options.staleMs;
|
|
2351
|
+
}
|
|
2352
|
+
async function writeLockMetadata(handle) {
|
|
2353
|
+
try {
|
|
2354
|
+
await handle.writeFile(
|
|
2355
|
+
JSON.stringify({ pid: process.pid, host: os.hostname(), acquiredAt: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
2356
|
+
{ encoding: "utf8" }
|
|
2357
|
+
);
|
|
2358
|
+
} catch (ignoredError) {
|
|
2359
|
+
void ignoredError;
|
|
2360
|
+
}
|
|
2361
|
+
try {
|
|
2362
|
+
await handle.close();
|
|
2363
|
+
} catch (ignoredError) {
|
|
2364
|
+
void ignoredError;
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
async function acquireFileLock(filePath, options = {}) {
|
|
2368
|
+
const fs14 = options.fs ?? createDefaultFs();
|
|
2369
|
+
const retries = options.retries ?? 20;
|
|
2370
|
+
const minTimeout = options.minTimeout ?? 25;
|
|
2371
|
+
const maxTimeout = options.maxTimeout ?? 250;
|
|
2372
|
+
const staleMs = options.staleMs ?? 1e3;
|
|
2373
|
+
const pidIsRunning = options.isPidRunning ?? isPidRunning;
|
|
2374
|
+
const lockPath = `${filePath}.lock`;
|
|
2375
|
+
let attempt = 0;
|
|
2376
|
+
while (attempt <= retries) {
|
|
2377
|
+
throwIfAborted(options.signal);
|
|
2378
|
+
try {
|
|
2379
|
+
const handle = await fs14.open(lockPath, "wx");
|
|
2380
|
+
await writeLockMetadata(handle);
|
|
2381
|
+
let released = false;
|
|
2382
|
+
return async () => {
|
|
2383
|
+
if (released) {
|
|
2384
|
+
return;
|
|
2385
|
+
}
|
|
2386
|
+
released = true;
|
|
2387
|
+
await removeLockFile(fs14, lockPath, options.signal);
|
|
2388
|
+
};
|
|
2389
|
+
} catch (error2) {
|
|
2390
|
+
if (!hasErrorCode(error2, "EEXIST")) {
|
|
2391
|
+
throw error2;
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
let stat7;
|
|
2395
|
+
try {
|
|
2396
|
+
stat7 = await fs14.stat(lockPath);
|
|
2397
|
+
} catch (statError) {
|
|
2398
|
+
if (hasErrorCode(statError, "ENOENT")) {
|
|
2399
|
+
continue;
|
|
2400
|
+
}
|
|
2401
|
+
throw statError;
|
|
2402
|
+
}
|
|
2403
|
+
const reclaimLock = await shouldReclaimLock({
|
|
2404
|
+
fs: fs14,
|
|
2405
|
+
isPidRunning: pidIsRunning,
|
|
2406
|
+
lockPath,
|
|
2407
|
+
staleMs,
|
|
2408
|
+
stat: stat7
|
|
2409
|
+
});
|
|
2410
|
+
if (reclaimLock === "missing") {
|
|
2411
|
+
continue;
|
|
2412
|
+
}
|
|
2413
|
+
if (reclaimLock) {
|
|
2414
|
+
await removeLockFile(fs14, lockPath, options.signal);
|
|
2415
|
+
continue;
|
|
2416
|
+
}
|
|
2417
|
+
if (attempt >= retries) {
|
|
2418
|
+
break;
|
|
2419
|
+
}
|
|
2420
|
+
await sleep(backoff(attempt, minTimeout, maxTimeout), options.signal);
|
|
2421
|
+
attempt += 1;
|
|
2422
|
+
}
|
|
2423
|
+
throw new LockTimeoutError(`Failed to acquire lock on "${filePath}".`);
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
// packages/poe-code-config/src/state/fs.ts
|
|
2427
|
+
import * as nodeFs from "node:fs/promises";
|
|
2428
|
+
var defaultStateFs = nodeFs;
|
|
2429
|
+
function isNotFoundError(error2) {
|
|
2430
|
+
return error2 instanceof Error && "code" in error2 && error2.code === "ENOENT";
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
// packages/poe-code-config/src/state/jobs.ts
|
|
2434
|
+
function createJobRegistry(homeDir, fs14 = defaultStateFs) {
|
|
2435
|
+
const jobsDir = path9.join(homeDir, ".poe-code", "state", "jobs");
|
|
2436
|
+
function jobPath(id) {
|
|
2437
|
+
assertSafeJobId(id);
|
|
2438
|
+
return path9.join(jobsDir, `${id}.json`);
|
|
2439
|
+
}
|
|
2440
|
+
async function get(id) {
|
|
2441
|
+
try {
|
|
2442
|
+
return parseJobEntry(await fs14.readFile(jobPath(id), "utf8"));
|
|
2443
|
+
} catch (error2) {
|
|
2444
|
+
if (isNotFoundError(error2)) {
|
|
2445
|
+
return null;
|
|
2446
|
+
}
|
|
2447
|
+
throw error2;
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
async function put(entry) {
|
|
2451
|
+
assertJobEntry(entry);
|
|
2452
|
+
const filePath = jobPath(entry.id);
|
|
2453
|
+
await fs14.mkdir(jobsDir, { recursive: true });
|
|
2454
|
+
const release = await acquireFileLock(filePath, { fs: fs14 });
|
|
2455
|
+
try {
|
|
2456
|
+
await writeJobAtomically(filePath, entry);
|
|
2457
|
+
} finally {
|
|
2458
|
+
await release();
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
async function update(id, patch) {
|
|
2462
|
+
const filePath = jobPath(id);
|
|
2463
|
+
await fs14.mkdir(jobsDir, { recursive: true });
|
|
2464
|
+
const release = await acquireFileLock(filePath, { fs: fs14 });
|
|
2465
|
+
try {
|
|
2466
|
+
const current = await get(id);
|
|
2467
|
+
if (current === null) {
|
|
2468
|
+
return null;
|
|
2469
|
+
}
|
|
2470
|
+
const updated = {
|
|
2471
|
+
...current,
|
|
2472
|
+
...patch,
|
|
2473
|
+
id: current.id
|
|
2474
|
+
};
|
|
2475
|
+
assertJobEntry(updated);
|
|
2476
|
+
await writeJobAtomically(filePath, updated);
|
|
2477
|
+
return updated;
|
|
2478
|
+
} finally {
|
|
2479
|
+
await release();
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
async function list(filter = {}) {
|
|
2483
|
+
let entries;
|
|
2484
|
+
try {
|
|
2485
|
+
entries = await fs14.readdir(jobsDir);
|
|
2486
|
+
} catch (error2) {
|
|
2487
|
+
if (isNotFoundError(error2)) {
|
|
2488
|
+
return [];
|
|
2489
|
+
}
|
|
2490
|
+
throw error2;
|
|
2491
|
+
}
|
|
2492
|
+
const jobs = [];
|
|
2493
|
+
for (const entry of entries.sort()) {
|
|
2494
|
+
if (!entry.endsWith(".json")) {
|
|
2495
|
+
continue;
|
|
2496
|
+
}
|
|
2497
|
+
const filePath = path9.join(jobsDir, entry);
|
|
2498
|
+
const stat7 = await fs14.stat(filePath);
|
|
2499
|
+
if (!stat7.isFile()) {
|
|
2500
|
+
continue;
|
|
2501
|
+
}
|
|
2502
|
+
const job = parseJobEntry(await fs14.readFile(filePath, "utf8"));
|
|
2503
|
+
if (matchesFilter(job, filter)) {
|
|
2504
|
+
jobs.push(job);
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
return jobs;
|
|
2508
|
+
}
|
|
2509
|
+
async function remove2(id) {
|
|
2510
|
+
const filePath = jobPath(id);
|
|
2511
|
+
try {
|
|
2512
|
+
await fs14.stat(jobsDir);
|
|
2513
|
+
} catch (error2) {
|
|
2514
|
+
if (isNotFoundError(error2)) {
|
|
2515
|
+
return;
|
|
2516
|
+
}
|
|
2517
|
+
throw error2;
|
|
2518
|
+
}
|
|
2519
|
+
const release = await acquireFileLock(filePath, { fs: fs14 });
|
|
2520
|
+
try {
|
|
2521
|
+
await fs14.unlink(filePath);
|
|
2522
|
+
} catch (error2) {
|
|
2523
|
+
if (!isNotFoundError(error2)) {
|
|
2524
|
+
throw error2;
|
|
2525
|
+
}
|
|
2526
|
+
} finally {
|
|
2527
|
+
await release();
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
async function writeJobAtomically(filePath, entry) {
|
|
2531
|
+
await fs14.mkdir(path9.dirname(filePath), { recursive: true });
|
|
2532
|
+
const tempPath = `${filePath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
2533
|
+
try {
|
|
2534
|
+
await fs14.writeFile(tempPath, `${JSON.stringify(entry, null, 2)}
|
|
2535
|
+
`, {
|
|
2536
|
+
encoding: "utf8"
|
|
2537
|
+
});
|
|
2538
|
+
await fs14.rename(tempPath, filePath);
|
|
2539
|
+
} catch (error2) {
|
|
2540
|
+
await removeTempFile(tempPath);
|
|
2541
|
+
throw error2;
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
async function removeTempFile(tempPath) {
|
|
2545
|
+
try {
|
|
2546
|
+
await fs14.unlink(tempPath);
|
|
2547
|
+
} catch (error2) {
|
|
2548
|
+
if (!isNotFoundError(error2)) {
|
|
2549
|
+
throw error2;
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
return {
|
|
2554
|
+
get,
|
|
2555
|
+
put,
|
|
2556
|
+
update,
|
|
2557
|
+
list,
|
|
2558
|
+
remove: remove2
|
|
2559
|
+
};
|
|
2560
|
+
}
|
|
2561
|
+
function assertSafeJobId(id) {
|
|
2562
|
+
if (id.length === 0 || id === "." || id === ".." || path9.isAbsolute(id) || id.includes("/") || id.includes("\\") || id.includes("\0")) {
|
|
2563
|
+
throw new Error("Invalid job id.");
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
function assertJobEntry(entry) {
|
|
2567
|
+
if (!isJobEntry(entry)) {
|
|
2568
|
+
throw new Error("Invalid job entry.");
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
function matchesFilter(job, filter) {
|
|
2572
|
+
return (filter.env_id === void 0 || job.env_id === filter.env_id) && (filter.env_kind === void 0 || job.env_kind === filter.env_kind) && (filter.tool === void 0 || job.tool === filter.tool) && (filter.status === void 0 || job.status === filter.status);
|
|
2573
|
+
}
|
|
2574
|
+
function parseJobEntry(content) {
|
|
2575
|
+
const parsed = JSON.parse(content);
|
|
2576
|
+
if (!isJobEntry(parsed)) {
|
|
2577
|
+
throw new Error("Invalid job state file.");
|
|
2578
|
+
}
|
|
2579
|
+
return parsed;
|
|
2580
|
+
}
|
|
2581
|
+
function isJobEntry(value) {
|
|
2582
|
+
return isRecord3(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
|
+
}
|
|
2584
|
+
function isJobStatus(value) {
|
|
2585
|
+
return value === "pending" || value === "running" || value === "exited" || value === "killed" || value === "lost";
|
|
2586
|
+
}
|
|
2587
|
+
function isRecord3(value) {
|
|
2588
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
// packages/poe-code-config/src/state/templates.ts
|
|
2592
|
+
import path10 from "node:path";
|
|
2593
|
+
function createTemplateRegistry(homeDir, fs14 = defaultStateFs) {
|
|
2594
|
+
const filePath = path10.join(homeDir, ".poe-code", "state", "templates.json");
|
|
2595
|
+
async function readState() {
|
|
2596
|
+
try {
|
|
2597
|
+
const raw = await fs14.readFile(filePath, "utf8");
|
|
2598
|
+
return normalizeTemplateState(JSON.parse(raw));
|
|
2599
|
+
} catch (error2) {
|
|
2600
|
+
if (isNotFoundError(error2)) {
|
|
2601
|
+
return createEmptyState();
|
|
2602
|
+
}
|
|
2603
|
+
throw error2;
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
async function writeState(state) {
|
|
2607
|
+
await fs14.writeFile(filePath, `${JSON.stringify(state, null, 2)}
|
|
2608
|
+
`, {
|
|
2609
|
+
encoding: "utf8"
|
|
2610
|
+
});
|
|
2611
|
+
}
|
|
2612
|
+
async function updateState(mutator) {
|
|
2613
|
+
await fs14.mkdir(path10.dirname(filePath), { recursive: true });
|
|
2614
|
+
const release = await acquireFileLock(filePath, { fs: fs14 });
|
|
2615
|
+
try {
|
|
2616
|
+
const state = await readState();
|
|
2617
|
+
mutator(state);
|
|
2618
|
+
await writeState(state);
|
|
2619
|
+
} finally {
|
|
2620
|
+
await release();
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
async function get(backend, hash) {
|
|
2624
|
+
const state = await readState();
|
|
2625
|
+
return state[backend][hash] ?? null;
|
|
2626
|
+
}
|
|
2627
|
+
async function put(backend, entry) {
|
|
2628
|
+
await updateState((state) => {
|
|
2629
|
+
state[backend][entry.hash] = entry;
|
|
2630
|
+
});
|
|
2631
|
+
}
|
|
2632
|
+
async function remove2(backend, hash) {
|
|
2633
|
+
await updateState((state) => {
|
|
2634
|
+
delete state[backend][hash];
|
|
2635
|
+
});
|
|
2636
|
+
}
|
|
2637
|
+
async function list(backend) {
|
|
2638
|
+
const state = await readState();
|
|
2639
|
+
const entries = backend === void 0 ? [...Object.values(state.docker), ...Object.values(state.e2b)] : Object.values(state[backend]);
|
|
2640
|
+
return entries.sort((left, right) => left.hash.localeCompare(right.hash));
|
|
2641
|
+
}
|
|
2642
|
+
return {
|
|
2643
|
+
get,
|
|
2644
|
+
put,
|
|
2645
|
+
remove: remove2,
|
|
2646
|
+
list
|
|
2647
|
+
};
|
|
2648
|
+
}
|
|
2649
|
+
function createEmptyState() {
|
|
2650
|
+
return {
|
|
2651
|
+
docker: {},
|
|
2652
|
+
e2b: {}
|
|
2653
|
+
};
|
|
2654
|
+
}
|
|
2655
|
+
function normalizeTemplateState(value) {
|
|
2656
|
+
if (!isRecord4(value)) {
|
|
2657
|
+
return createEmptyState();
|
|
2658
|
+
}
|
|
2659
|
+
return {
|
|
2660
|
+
docker: normalizeTemplateEntries(value.docker),
|
|
2661
|
+
e2b: normalizeTemplateEntries(value.e2b)
|
|
2662
|
+
};
|
|
2663
|
+
}
|
|
2664
|
+
function normalizeTemplateEntries(value) {
|
|
2665
|
+
if (!isRecord4(value)) {
|
|
2666
|
+
return {};
|
|
2667
|
+
}
|
|
2668
|
+
const entries = {};
|
|
2669
|
+
for (const [hash, entry] of Object.entries(value)) {
|
|
2670
|
+
if (isTemplateEntry(entry) && entry.hash === hash) {
|
|
2671
|
+
entries[hash] = entry;
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
return entries;
|
|
2675
|
+
}
|
|
2676
|
+
function isTemplateEntry(value) {
|
|
2677
|
+
return isRecord4(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
|
+
}
|
|
2679
|
+
function isRecord4(value) {
|
|
2680
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2683
|
+
// packages/poe-code-config/src/state/index.ts
|
|
2684
|
+
function createStateManager(homeDir, fs14) {
|
|
2685
|
+
return {
|
|
2686
|
+
templates: createTemplateRegistry(homeDir, fs14),
|
|
2687
|
+
jobs: createJobRegistry(homeDir, fs14)
|
|
2688
|
+
};
|
|
2689
|
+
}
|
|
2690
|
+
|
|
2691
|
+
// packages/memory/src/resolve-root.ts
|
|
2692
|
+
var MEMORY_ROOT_ENV_VAR = "POE_CODE_MEMORY_ROOT";
|
|
2693
|
+
async function resolveConfiguredMemoryRoot(options) {
|
|
2694
|
+
const envOverride = options.env[MEMORY_ROOT_ENV_VAR]?.trim();
|
|
2695
|
+
if (envOverride && envOverride.length > 0) {
|
|
2696
|
+
return resolveAgainstCwd(options.cwd, envOverride);
|
|
2697
|
+
}
|
|
2698
|
+
const configOverride = (await configuredMemoryRoot({
|
|
2699
|
+
fs: options.fs,
|
|
2700
|
+
filePath: options.configPath,
|
|
2701
|
+
projectFilePath: options.projectConfigPath
|
|
2702
|
+
}))?.trim();
|
|
2703
|
+
if (configOverride && configOverride.length > 0) {
|
|
2704
|
+
return resolveAgainstCwd(options.cwd, configOverride);
|
|
2705
|
+
}
|
|
2706
|
+
return resolveMemoryRoot(options.cwd);
|
|
2707
|
+
}
|
|
2708
|
+
function resolveAgainstCwd(cwd, value) {
|
|
2709
|
+
return path11.isAbsolute(value) ? value : path11.resolve(cwd, value);
|
|
2710
|
+
}
|
|
2711
|
+
|
|
2712
|
+
// packages/memory/src/init.ts
|
|
2713
|
+
import * as fs from "node:fs/promises";
|
|
2714
|
+
import path12 from "node:path";
|
|
2715
|
+
async function initMemory(root) {
|
|
2716
|
+
await fs.mkdir(path12.join(root, MEMORY_PAGES_DIR_RELPATH), { recursive: true });
|
|
2717
|
+
await writeFileIfMissing(path12.join(root, MEMORY_INDEX_RELPATH), "# Memory index\n");
|
|
2718
|
+
await writeFileIfMissing(path12.join(root, MEMORY_LOG_RELPATH), "");
|
|
2719
|
+
}
|
|
2720
|
+
async function writeFileIfMissing(filePath, content) {
|
|
2721
|
+
try {
|
|
2722
|
+
await fs.writeFile(filePath, content, { encoding: "utf8", flag: "wx" });
|
|
2723
|
+
} catch (error2) {
|
|
2724
|
+
if (!hasErrorCode2(error2, "EEXIST")) {
|
|
2725
|
+
throw error2;
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
function hasErrorCode2(error2, code) {
|
|
2730
|
+
return typeof error2 === "object" && error2 !== null && "code" in error2 && error2.code === code;
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
// packages/memory/src/pages.ts
|
|
2734
|
+
import * as fs2 from "node:fs/promises";
|
|
2735
|
+
import path13 from "node:path";
|
|
2736
|
+
|
|
2737
|
+
// packages/memory/src/frontmatter.ts
|
|
2738
|
+
import { parse as parse5, stringify } from "yaml";
|
|
2739
|
+
function parseFrontmatter(markdown) {
|
|
2740
|
+
const content = markdown.startsWith("\uFEFF") ? markdown.slice(1) : markdown;
|
|
2741
|
+
const openingLineBreak = readOpeningLineBreak(content);
|
|
2742
|
+
if (openingLineBreak === void 0) {
|
|
2743
|
+
return {
|
|
2744
|
+
frontmatter: {},
|
|
2745
|
+
body: markdown
|
|
2746
|
+
};
|
|
2747
|
+
}
|
|
2748
|
+
const frontmatterStart = 3 + openingLineBreak.length;
|
|
2749
|
+
const closingFenceIndex = findClosingFence(content, frontmatterStart);
|
|
2750
|
+
const yamlBlock = content.slice(frontmatterStart, closingFenceIndex);
|
|
2751
|
+
const bodyStart = closingFenceIndex + 4;
|
|
2752
|
+
return {
|
|
2753
|
+
frontmatter: parsePageFrontmatter(parseYamlFrontmatter(yamlBlock)),
|
|
2754
|
+
body: readBody(content, bodyStart)
|
|
2755
|
+
};
|
|
2756
|
+
}
|
|
2757
|
+
function serializeFrontmatter(frontmatter, body) {
|
|
2758
|
+
const serialized = {
|
|
2759
|
+
...frontmatter.name === void 0 ? {} : { name: frontmatter.name },
|
|
2760
|
+
...frontmatter.description === void 0 ? {} : { description: frontmatter.description },
|
|
2761
|
+
...frontmatter.lastTouchedAt === void 0 ? {} : { last_touched_at: frontmatter.lastTouchedAt },
|
|
2762
|
+
...frontmatter.sources === void 0 || frontmatter.sources.length === 0 ? {} : { sources: frontmatter.sources.map((source) => serializeSourceRef(source)) }
|
|
2763
|
+
};
|
|
2764
|
+
if (Object.keys(serialized).length === 0) {
|
|
2765
|
+
return body;
|
|
2766
|
+
}
|
|
2767
|
+
return `---
|
|
2768
|
+
${stringify(serialized).trimEnd()}
|
|
2769
|
+
---
|
|
2770
|
+
${body}`;
|
|
2771
|
+
}
|
|
2772
|
+
function parseSourceRef(serialized) {
|
|
2773
|
+
const [rawPath, rawAnchor] = serialized.split("#", 2);
|
|
2774
|
+
const normalizedPath = rawPath?.trim();
|
|
2775
|
+
if (normalizedPath === void 0 || normalizedPath.length === 0) {
|
|
2776
|
+
throw new Error(`Invalid source ref "${serialized}".`);
|
|
2777
|
+
}
|
|
2778
|
+
if (rawAnchor === void 0) {
|
|
2779
|
+
return { path: normalizedPath };
|
|
2780
|
+
}
|
|
2781
|
+
const singleLineMatch = /^L(\d+)$/.exec(rawAnchor);
|
|
2782
|
+
if (singleLineMatch !== null) {
|
|
2783
|
+
const startLine = Number.parseInt(singleLineMatch[1], 10);
|
|
2784
|
+
assertValidLineNumber(startLine, serialized);
|
|
2785
|
+
return {
|
|
2786
|
+
path: normalizedPath,
|
|
2787
|
+
startLine
|
|
2788
|
+
};
|
|
2789
|
+
}
|
|
2790
|
+
const rangeMatch = /^L(\d+)-L?(\d+)$/.exec(rawAnchor);
|
|
2791
|
+
if (rangeMatch !== null) {
|
|
2792
|
+
const startLine = Number.parseInt(rangeMatch[1], 10);
|
|
2050
2793
|
const endLine = Number.parseInt(rangeMatch[2], 10);
|
|
2051
2794
|
assertValidLineNumber(startLine, serialized);
|
|
2052
2795
|
assertValidLineNumber(endLine, serialized);
|
|
@@ -2135,7 +2878,7 @@ function parseYamlFrontmatter(yamlBlock) {
|
|
|
2135
2878
|
if (parsed === null) {
|
|
2136
2879
|
return {};
|
|
2137
2880
|
}
|
|
2138
|
-
if (!
|
|
2881
|
+
if (!isRecord5(parsed)) {
|
|
2139
2882
|
throw new Error("YAML frontmatter must parse to an object.");
|
|
2140
2883
|
}
|
|
2141
2884
|
return parsed;
|
|
@@ -2166,13 +2909,13 @@ function parseSources(value) {
|
|
|
2166
2909
|
if (typeof item === "string") {
|
|
2167
2910
|
return parseSourceRef(item);
|
|
2168
2911
|
}
|
|
2169
|
-
if (!
|
|
2912
|
+
if (!isRecord5(item)) {
|
|
2170
2913
|
throw new Error('Invalid "sources" frontmatter. Expected each source to be a string or object.');
|
|
2171
2914
|
}
|
|
2172
|
-
const
|
|
2915
|
+
const path38 = readRequiredString(item.path, "sources[].path");
|
|
2173
2916
|
const startLine = readOptionalPositiveInteger(item.startLine, "sources[].startLine");
|
|
2174
2917
|
const endLine = readOptionalPositiveInteger(item.endLine, "sources[].endLine");
|
|
2175
|
-
return parseSourceRef(serializeSourceRef({ path:
|
|
2918
|
+
return parseSourceRef(serializeSourceRef({ path: path38, ...startLine === void 0 ? {} : { startLine }, ...endLine === void 0 ? {} : { endLine } }));
|
|
2176
2919
|
});
|
|
2177
2920
|
}
|
|
2178
2921
|
function readOptionalString(value, field) {
|
|
@@ -2205,7 +2948,7 @@ function assertValidLineNumber(line, value) {
|
|
|
2205
2948
|
throw new Error(`Invalid source ref "${value}": line numbers must be positive integers.`);
|
|
2206
2949
|
}
|
|
2207
2950
|
}
|
|
2208
|
-
function
|
|
2951
|
+
function isRecord5(value) {
|
|
2209
2952
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2210
2953
|
}
|
|
2211
2954
|
|
|
@@ -2377,17 +3120,17 @@ import path18 from "node:path";
|
|
|
2377
3120
|
// packages/memory/src/lock.ts
|
|
2378
3121
|
import * as fsPromises2 from "node:fs/promises";
|
|
2379
3122
|
import path16 from "node:path";
|
|
2380
|
-
function
|
|
3123
|
+
function createDefaultFs2() {
|
|
2381
3124
|
return {
|
|
2382
3125
|
readFile: (filePath, encoding) => fsPromises2.readFile(filePath, encoding),
|
|
2383
3126
|
unlink: fsPromises2.unlink,
|
|
2384
3127
|
writeFile: (filePath, data, options) => fsPromises2.writeFile(filePath, data, options)
|
|
2385
3128
|
};
|
|
2386
3129
|
}
|
|
2387
|
-
function
|
|
3130
|
+
function sleep2(ms) {
|
|
2388
3131
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
2389
3132
|
}
|
|
2390
|
-
function
|
|
3133
|
+
function hasErrorCode3(error2, code) {
|
|
2391
3134
|
return typeof error2 === "object" && error2 !== null && "code" in error2 && error2.code === code;
|
|
2392
3135
|
}
|
|
2393
3136
|
function lockDelay(attempt, minTimeoutMs, maxTimeoutMs) {
|
|
@@ -2406,19 +3149,19 @@ function parsePid(input) {
|
|
|
2406
3149
|
const pid = Number.parseInt(value, 10);
|
|
2407
3150
|
return Number.isSafeInteger(pid) && pid > 0 ? pid : void 0;
|
|
2408
3151
|
}
|
|
2409
|
-
function
|
|
3152
|
+
function isPidRunning2(pid) {
|
|
2410
3153
|
try {
|
|
2411
3154
|
process.kill(pid, 0);
|
|
2412
3155
|
return true;
|
|
2413
3156
|
} catch (error2) {
|
|
2414
|
-
return !
|
|
3157
|
+
return !hasErrorCode3(error2, "ESRCH");
|
|
2415
3158
|
}
|
|
2416
3159
|
}
|
|
2417
|
-
async function
|
|
3160
|
+
async function removeLockFile2(fs14, lockPath) {
|
|
2418
3161
|
try {
|
|
2419
3162
|
await fs14.unlink(lockPath);
|
|
2420
3163
|
} catch (error2) {
|
|
2421
|
-
if (!
|
|
3164
|
+
if (!hasErrorCode3(error2, "ENOENT")) {
|
|
2422
3165
|
throw error2;
|
|
2423
3166
|
}
|
|
2424
3167
|
}
|
|
@@ -2427,20 +3170,20 @@ async function readLockPid(fs14, lockPath) {
|
|
|
2427
3170
|
try {
|
|
2428
3171
|
return parsePid(await fs14.readFile(lockPath, "utf8"));
|
|
2429
3172
|
} catch (error2) {
|
|
2430
|
-
if (
|
|
3173
|
+
if (hasErrorCode3(error2, "ENOENT")) {
|
|
2431
3174
|
return null;
|
|
2432
3175
|
}
|
|
2433
3176
|
throw error2;
|
|
2434
3177
|
}
|
|
2435
3178
|
}
|
|
2436
3179
|
async function withLock(root, run, options = {}) {
|
|
2437
|
-
const fs14 = options.fs ??
|
|
3180
|
+
const fs14 = options.fs ?? createDefaultFs2();
|
|
2438
3181
|
const lockPath = path16.join(root, MEMORY_LOCK_RELPATH);
|
|
2439
3182
|
const pid = options.pid ?? process.pid;
|
|
2440
3183
|
const retries = options.retries ?? 20;
|
|
2441
3184
|
const minTimeoutMs = options.minTimeoutMs ?? 25;
|
|
2442
3185
|
const maxTimeoutMs = options.maxTimeoutMs ?? 250;
|
|
2443
|
-
const pidIsRunning = options.isPidRunning ??
|
|
3186
|
+
const pidIsRunning = options.isPidRunning ?? isPidRunning2;
|
|
2444
3187
|
for (let attempt = 0; attempt <= retries; attempt += 1) {
|
|
2445
3188
|
try {
|
|
2446
3189
|
await fs14.writeFile(lockPath, `${pid}
|
|
@@ -2448,10 +3191,10 @@ async function withLock(root, run, options = {}) {
|
|
|
2448
3191
|
try {
|
|
2449
3192
|
return await run();
|
|
2450
3193
|
} finally {
|
|
2451
|
-
await
|
|
3194
|
+
await removeLockFile2(fs14, lockPath);
|
|
2452
3195
|
}
|
|
2453
3196
|
} catch (error2) {
|
|
2454
|
-
if (!
|
|
3197
|
+
if (!hasErrorCode3(error2, "EEXIST")) {
|
|
2455
3198
|
throw error2;
|
|
2456
3199
|
}
|
|
2457
3200
|
}
|
|
@@ -2460,11 +3203,11 @@ async function withLock(root, run, options = {}) {
|
|
|
2460
3203
|
continue;
|
|
2461
3204
|
}
|
|
2462
3205
|
if (existingPid === void 0 || !pidIsRunning(existingPid)) {
|
|
2463
|
-
await
|
|
3206
|
+
await removeLockFile2(fs14, lockPath);
|
|
2464
3207
|
continue;
|
|
2465
3208
|
}
|
|
2466
3209
|
if (attempt < retries) {
|
|
2467
|
-
await
|
|
3210
|
+
await sleep2(lockDelay(attempt, minTimeoutMs, maxTimeoutMs));
|
|
2468
3211
|
}
|
|
2469
3212
|
}
|
|
2470
3213
|
throw new Error(`Failed to acquire memory lock at "${lockPath}".`);
|
|
@@ -3201,37 +3944,1401 @@ function isMissing3(error2) {
|
|
|
3201
3944
|
return typeof error2 === "object" && error2 !== null && "code" in error2 && error2.code === "ENOENT";
|
|
3202
3945
|
}
|
|
3203
3946
|
|
|
3204
|
-
// packages/memory/src/cache.cli.ts
|
|
3205
|
-
import parseDuration from "parse-duration";
|
|
3206
|
-
async function runMemoryCacheStatus() {
|
|
3207
|
-
console.log("cache status not implemented yet");
|
|
3947
|
+
// packages/memory/src/cache.cli.ts
|
|
3948
|
+
import parseDuration from "parse-duration";
|
|
3949
|
+
async function runMemoryCacheStatus() {
|
|
3950
|
+
console.log("cache status not implemented yet");
|
|
3951
|
+
}
|
|
3952
|
+
async function runMemoryCacheClear(input) {
|
|
3953
|
+
if (!input.yes) {
|
|
3954
|
+
throw new Error("Refusing to clear cache without --yes.");
|
|
3955
|
+
}
|
|
3956
|
+
const olderThanMs = parseOlderThan(input.olderThan);
|
|
3957
|
+
const result = await clearCache(input.root, olderThanMs === void 0 ? {} : { olderThanMs });
|
|
3958
|
+
console.log(`removed ${result.removed} cache ${result.removed === 1 ? "entry" : "entries"}`);
|
|
3959
|
+
return result;
|
|
3960
|
+
}
|
|
3961
|
+
function parseOlderThan(value) {
|
|
3962
|
+
if (value === void 0) {
|
|
3963
|
+
return void 0;
|
|
3964
|
+
}
|
|
3965
|
+
const duration = parseDuration(value);
|
|
3966
|
+
if (duration === null || Number.isNaN(duration) || duration < 0) {
|
|
3967
|
+
throw new Error(`Invalid duration for --older-than: "${value}".`);
|
|
3968
|
+
}
|
|
3969
|
+
return duration;
|
|
3970
|
+
}
|
|
3971
|
+
|
|
3972
|
+
// packages/memory/src/ingest.ts
|
|
3973
|
+
import * as fs11 from "node:fs/promises";
|
|
3974
|
+
import path31 from "node:path";
|
|
3975
|
+
|
|
3976
|
+
// packages/agent-spawn/src/register-factories.ts
|
|
3977
|
+
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
3978
|
+
|
|
3979
|
+
// packages/agent-harness-tools/src/paths.ts
|
|
3980
|
+
import path22 from "node:path";
|
|
3981
|
+
|
|
3982
|
+
// packages/agent-defs/src/agents/claude-code.ts
|
|
3983
|
+
var claudeCodeAgent = {
|
|
3984
|
+
id: "claude-code",
|
|
3985
|
+
name: "claude-code",
|
|
3986
|
+
label: "Claude Code",
|
|
3987
|
+
summary: "Configure Claude Code to route through Poe.",
|
|
3988
|
+
aliases: ["claude"],
|
|
3989
|
+
binaryName: "claude",
|
|
3990
|
+
configPath: "~/.claude/settings.json",
|
|
3991
|
+
branding: {
|
|
3992
|
+
colors: {
|
|
3993
|
+
dark: "#C15F3C",
|
|
3994
|
+
light: "#C15F3C"
|
|
3995
|
+
}
|
|
3996
|
+
}
|
|
3997
|
+
};
|
|
3998
|
+
|
|
3999
|
+
// packages/agent-defs/src/agents/claude-desktop.ts
|
|
4000
|
+
var claudeDesktopAgent = {
|
|
4001
|
+
id: "claude-desktop",
|
|
4002
|
+
name: "claude-desktop",
|
|
4003
|
+
label: "Claude Desktop",
|
|
4004
|
+
summary: "Anthropic's official desktop application for Claude",
|
|
4005
|
+
configPath: "~/.claude/settings.json",
|
|
4006
|
+
branding: {
|
|
4007
|
+
colors: {
|
|
4008
|
+
dark: "#D97757",
|
|
4009
|
+
light: "#D97757"
|
|
4010
|
+
}
|
|
4011
|
+
}
|
|
4012
|
+
};
|
|
4013
|
+
|
|
4014
|
+
// packages/agent-defs/src/agents/codex.ts
|
|
4015
|
+
var codexAgent = {
|
|
4016
|
+
id: "codex",
|
|
4017
|
+
name: "codex",
|
|
4018
|
+
label: "Codex",
|
|
4019
|
+
summary: "Configure Codex to use Poe as the model provider.",
|
|
4020
|
+
binaryName: "codex",
|
|
4021
|
+
configPath: "~/.codex/config.toml",
|
|
4022
|
+
branding: {
|
|
4023
|
+
colors: {
|
|
4024
|
+
dark: "#D5D9DF",
|
|
4025
|
+
light: "#7A7F86"
|
|
4026
|
+
}
|
|
4027
|
+
}
|
|
4028
|
+
};
|
|
4029
|
+
|
|
4030
|
+
// packages/agent-defs/src/agents/opencode.ts
|
|
4031
|
+
var openCodeAgent = {
|
|
4032
|
+
id: "opencode",
|
|
4033
|
+
name: "opencode",
|
|
4034
|
+
label: "OpenCode CLI",
|
|
4035
|
+
summary: "Configure OpenCode CLI to use the Poe API.",
|
|
4036
|
+
binaryName: "opencode",
|
|
4037
|
+
configPath: "~/.config/opencode/config.json",
|
|
4038
|
+
branding: {
|
|
4039
|
+
colors: {
|
|
4040
|
+
dark: "#4A4F55",
|
|
4041
|
+
light: "#2F3338"
|
|
4042
|
+
}
|
|
4043
|
+
}
|
|
4044
|
+
};
|
|
4045
|
+
|
|
4046
|
+
// packages/agent-defs/src/agents/kimi.ts
|
|
4047
|
+
var kimiAgent = {
|
|
4048
|
+
id: "kimi",
|
|
4049
|
+
name: "kimi",
|
|
4050
|
+
label: "Kimi",
|
|
4051
|
+
summary: "Configure Kimi CLI to use Poe API",
|
|
4052
|
+
aliases: ["kimi-cli"],
|
|
4053
|
+
binaryName: "kimi",
|
|
4054
|
+
configPath: "~/.kimi/config.toml",
|
|
4055
|
+
branding: {
|
|
4056
|
+
colors: {
|
|
4057
|
+
dark: "#7B68EE",
|
|
4058
|
+
light: "#6A5ACD"
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
4061
|
+
};
|
|
4062
|
+
|
|
4063
|
+
// packages/agent-defs/src/agents/goose.ts
|
|
4064
|
+
var gooseAgent = {
|
|
4065
|
+
id: "goose",
|
|
4066
|
+
name: "goose",
|
|
4067
|
+
label: "Goose",
|
|
4068
|
+
summary: "Block's open-source AI agent with ACP support.",
|
|
4069
|
+
binaryName: "goose",
|
|
4070
|
+
configPath: "~/.config/goose/config.yaml",
|
|
4071
|
+
branding: {
|
|
4072
|
+
colors: {
|
|
4073
|
+
dark: "#FF6B35",
|
|
4074
|
+
light: "#E85D26"
|
|
4075
|
+
}
|
|
4076
|
+
}
|
|
4077
|
+
};
|
|
4078
|
+
|
|
4079
|
+
// packages/agent-defs/src/agents/poe-agent.ts
|
|
4080
|
+
var poeAgentAgent = {
|
|
4081
|
+
id: "poe-agent",
|
|
4082
|
+
name: "poe-agent",
|
|
4083
|
+
label: "Poe Agent",
|
|
4084
|
+
summary: "Run one-shot prompts with the built-in Poe agent runtime.",
|
|
4085
|
+
configPath: "~/.poe-code/config.json",
|
|
4086
|
+
branding: {
|
|
4087
|
+
colors: {
|
|
4088
|
+
dark: "#A465F7",
|
|
4089
|
+
light: "#7A3FD3"
|
|
4090
|
+
}
|
|
4091
|
+
}
|
|
4092
|
+
};
|
|
4093
|
+
|
|
4094
|
+
// packages/agent-defs/src/registry.ts
|
|
4095
|
+
var allAgents = [
|
|
4096
|
+
claudeCodeAgent,
|
|
4097
|
+
claudeDesktopAgent,
|
|
4098
|
+
codexAgent,
|
|
4099
|
+
openCodeAgent,
|
|
4100
|
+
kimiAgent,
|
|
4101
|
+
gooseAgent,
|
|
4102
|
+
poeAgentAgent
|
|
4103
|
+
];
|
|
4104
|
+
var lookup = /* @__PURE__ */ new Map();
|
|
4105
|
+
for (const agent of allAgents) {
|
|
4106
|
+
const values = [agent.id, agent.name, ...agent.aliases ?? []];
|
|
4107
|
+
for (const value of values) {
|
|
4108
|
+
const normalized = value.toLowerCase();
|
|
4109
|
+
if (!lookup.has(normalized)) {
|
|
4110
|
+
lookup.set(normalized, agent.id);
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
}
|
|
4114
|
+
function resolveAgentId(input) {
|
|
4115
|
+
if (!input) {
|
|
4116
|
+
return void 0;
|
|
4117
|
+
}
|
|
4118
|
+
return lookup.get(input.toLowerCase());
|
|
4119
|
+
}
|
|
4120
|
+
|
|
4121
|
+
// packages/agent-harness-tools/src/select-agent.ts
|
|
4122
|
+
var loopAgents = allAgents.filter(
|
|
4123
|
+
(agent) => agent.binaryName !== void 0 || agent.id === "poe-agent"
|
|
4124
|
+
);
|
|
4125
|
+
var supportedAgents = loopAgents.map((agent) => agent.id).join(", ");
|
|
4126
|
+
|
|
4127
|
+
// packages/agent-harness-tools/src/run-logs.ts
|
|
4128
|
+
import path23 from "node:path";
|
|
4129
|
+
|
|
4130
|
+
// packages/agent-harness-tools/src/log-stream.ts
|
|
4131
|
+
import nodeFs2 from "node:fs";
|
|
4132
|
+
var JOB_DIR = "/tmp/poe-jobs";
|
|
4133
|
+
var POLL_INTERVAL_MS = 250;
|
|
4134
|
+
function wrapForLogTee(argv, jobId) {
|
|
4135
|
+
if (argv.length === 0) {
|
|
4136
|
+
throw new Error("wrapForLogTee requires argv to contain at least one argument");
|
|
4137
|
+
}
|
|
4138
|
+
const command = argv.map(shellQuote).join(" ");
|
|
4139
|
+
const logFile = shellQuote(jobLogPath(jobId));
|
|
4140
|
+
const exitFile = shellQuote(jobExitPath(jobId));
|
|
4141
|
+
const exitTmpFile = shellQuote(`${jobExitPath(jobId)}.tmp`);
|
|
4142
|
+
const script = [
|
|
4143
|
+
`mkdir -p ${shellQuote(JOB_DIR)}`,
|
|
4144
|
+
`({ (${command}); echo $? > ${exitTmpFile}; } 2>&1 | tee ${logFile}; mv ${exitTmpFile} ${exitFile})`
|
|
4145
|
+
].join(" && ");
|
|
4146
|
+
return ["sh", "-c", script];
|
|
4147
|
+
}
|
|
4148
|
+
async function waitForExit(env, jobId, opts = {}) {
|
|
4149
|
+
const fs14 = env.fs ?? nodeFs2;
|
|
4150
|
+
const file = jobExitPath(jobId);
|
|
4151
|
+
while (true) {
|
|
4152
|
+
throwIfAborted2(opts.signal);
|
|
4153
|
+
const contents = await readTextFileIfExists(fs14, file);
|
|
4154
|
+
if (contents !== null) {
|
|
4155
|
+
const text4 = contents.trim();
|
|
4156
|
+
const exitCode = Number(text4);
|
|
4157
|
+
if (text4.length === 0 || !Number.isInteger(exitCode)) {
|
|
4158
|
+
throw new Error(`Invalid exit code in ${file}: ${contents}`);
|
|
4159
|
+
}
|
|
4160
|
+
return { exitCode };
|
|
4161
|
+
}
|
|
4162
|
+
await sleep3(POLL_INTERVAL_MS, opts.signal);
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
4165
|
+
function jobLogPath(jobId) {
|
|
4166
|
+
return `${JOB_DIR}/${jobId}.log`;
|
|
4167
|
+
}
|
|
4168
|
+
function jobExitPath(jobId) {
|
|
4169
|
+
return `${JOB_DIR}/${jobId}.exit`;
|
|
4170
|
+
}
|
|
4171
|
+
async function readTextFileIfExists(fs14, file) {
|
|
4172
|
+
const contents = await readFileIfExists2(fs14, file);
|
|
4173
|
+
return contents?.toString("utf8") ?? null;
|
|
4174
|
+
}
|
|
4175
|
+
async function readFileIfExists2(fs14, file) {
|
|
4176
|
+
try {
|
|
4177
|
+
const contents = await fs14.promises.readFile(file);
|
|
4178
|
+
return Buffer.isBuffer(contents) ? contents : Buffer.from(contents);
|
|
4179
|
+
} catch (error2) {
|
|
4180
|
+
if (isNodeError(error2) && error2.code === "ENOENT") {
|
|
4181
|
+
return null;
|
|
4182
|
+
}
|
|
4183
|
+
throw error2;
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
function sleep3(ms, signal) {
|
|
4187
|
+
return new Promise((resolve2, reject) => {
|
|
4188
|
+
let timer = null;
|
|
4189
|
+
const abort = () => {
|
|
4190
|
+
if (timer !== null) {
|
|
4191
|
+
clearTimeout(timer);
|
|
4192
|
+
}
|
|
4193
|
+
reject(new Error("waitForExit aborted."));
|
|
4194
|
+
};
|
|
4195
|
+
if (signal?.aborted) {
|
|
4196
|
+
abort();
|
|
4197
|
+
return;
|
|
4198
|
+
}
|
|
4199
|
+
timer = setTimeout(() => {
|
|
4200
|
+
signal?.removeEventListener("abort", abort);
|
|
4201
|
+
resolve2();
|
|
4202
|
+
}, ms);
|
|
4203
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
4204
|
+
});
|
|
4205
|
+
}
|
|
4206
|
+
function throwIfAborted2(signal) {
|
|
4207
|
+
if (signal?.aborted) {
|
|
4208
|
+
throw new Error("waitForExit aborted.");
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4211
|
+
function shellQuote(value) {
|
|
4212
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
4213
|
+
}
|
|
4214
|
+
function isNodeError(error2) {
|
|
4215
|
+
return error2 instanceof Error && "code" in error2;
|
|
4216
|
+
}
|
|
4217
|
+
|
|
4218
|
+
// packages/agent-harness-tools/src/run-poe-command.ts
|
|
4219
|
+
import { randomBytes } from "node:crypto";
|
|
4220
|
+
var ULID_ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
4221
|
+
async function runPoeCommand(opts) {
|
|
4222
|
+
const jobId = createUlid();
|
|
4223
|
+
const execution = opts.openSpec.execution;
|
|
4224
|
+
const wrapCommand = execution?.wrapForLogTee !== false;
|
|
4225
|
+
const pendingJob = opts.state.jobs.put({
|
|
4226
|
+
id: jobId,
|
|
4227
|
+
env_id: "",
|
|
4228
|
+
env_kind: opts.factory.type,
|
|
4229
|
+
tool: opts.openSpec.jobLabel.tool,
|
|
4230
|
+
argv: opts.openSpec.jobLabel.argv,
|
|
4231
|
+
cwd: opts.openSpec.cwd,
|
|
4232
|
+
started_at: "",
|
|
4233
|
+
status: "pending"
|
|
4234
|
+
});
|
|
4235
|
+
const opened = opts.factory.open(opts.openSpec);
|
|
4236
|
+
const env = isPromiseLike(opened) ? await opened : opened;
|
|
4237
|
+
let shouldClose = true;
|
|
4238
|
+
try {
|
|
4239
|
+
const upload = env.uploadWorkspace();
|
|
4240
|
+
const argv = wrapCommand ? wrapForLogTee(opts.openSpec.jobLabel.argv, jobId) : opts.openSpec.jobLabel.argv;
|
|
4241
|
+
const handle = execution?.tty ? env.shell() : env.exec({
|
|
4242
|
+
command: argv[0],
|
|
4243
|
+
args: argv.slice(1),
|
|
4244
|
+
cwd: opts.openSpec.cwd,
|
|
4245
|
+
env: execution && "env" in execution ? execution.env : opts.openSpec.env,
|
|
4246
|
+
stdin: execution?.stdin ?? "inherit",
|
|
4247
|
+
stdout: execution?.stdout ?? "pipe",
|
|
4248
|
+
stderr: execution?.stderr ?? "pipe",
|
|
4249
|
+
signal: opts.signal
|
|
4250
|
+
});
|
|
4251
|
+
if (execution?.input !== void 0) {
|
|
4252
|
+
handle.stdin?.setDefaultEncoding("utf8");
|
|
4253
|
+
handle.stdin?.end(execution.input);
|
|
4254
|
+
}
|
|
4255
|
+
const runningJob = Promise.all([pendingJob, upload]).then(
|
|
4256
|
+
() => opts.state.jobs.update(jobId, {
|
|
4257
|
+
status: "running",
|
|
4258
|
+
env_id: env.id,
|
|
4259
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4260
|
+
})
|
|
4261
|
+
);
|
|
4262
|
+
if (opts.detach) {
|
|
4263
|
+
await runningJob;
|
|
4264
|
+
shouldClose = false;
|
|
4265
|
+
return { kind: "detached", jobId, envId: env.id };
|
|
4266
|
+
}
|
|
4267
|
+
const result = await runSync({
|
|
4268
|
+
env,
|
|
4269
|
+
handle,
|
|
4270
|
+
jobId,
|
|
4271
|
+
openSpec: opts.openSpec,
|
|
4272
|
+
signal: opts.signal,
|
|
4273
|
+
wrapCommand
|
|
4274
|
+
});
|
|
4275
|
+
await runningJob;
|
|
4276
|
+
shouldClose = false;
|
|
4277
|
+
await opts.state.jobs.update(jobId, {
|
|
4278
|
+
status: "exited",
|
|
4279
|
+
exit_code: result.exitCode,
|
|
4280
|
+
exited_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4281
|
+
});
|
|
4282
|
+
return {
|
|
4283
|
+
kind: "sync",
|
|
4284
|
+
exitCode: result.exitCode,
|
|
4285
|
+
download: result.download,
|
|
4286
|
+
...result.stdout !== void 0 ? { stdout: result.stdout } : {},
|
|
4287
|
+
...result.stderr !== void 0 ? { stderr: result.stderr } : {}
|
|
4288
|
+
};
|
|
4289
|
+
} finally {
|
|
4290
|
+
if (shouldClose) {
|
|
4291
|
+
await env.close();
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
}
|
|
4295
|
+
async function runSync(opts) {
|
|
4296
|
+
const execution = opts.openSpec.execution;
|
|
4297
|
+
const capture = execution?.captureOutput === true;
|
|
4298
|
+
const abort = createAbortSync(opts.signal, opts.handle, execution?.activityTimeoutMs);
|
|
4299
|
+
const streamState = capture ? captureRunStreams(opts.handle, execution, abort.resetActivityTimer) : pipeRunStreams(opts.handle);
|
|
4300
|
+
abort.resetActivityTimer();
|
|
4301
|
+
try {
|
|
4302
|
+
const { exitCode } = opts.wrapCommand ? await abort.waitForExit(opts.env, opts.jobId) : await abort.waitForHandle();
|
|
4303
|
+
const download = await opts.env.downloadWorkspace({
|
|
4304
|
+
conflictPolicy: opts.openSpec.runner?.download_conflict ?? "refuse"
|
|
4305
|
+
});
|
|
4306
|
+
await opts.env.close();
|
|
4307
|
+
return {
|
|
4308
|
+
exitCode,
|
|
4309
|
+
download,
|
|
4310
|
+
...capture ? { stdout: streamState.stdout(), stderr: streamState.stderr() } : {}
|
|
4311
|
+
};
|
|
4312
|
+
} finally {
|
|
4313
|
+
abort.dispose();
|
|
4314
|
+
streamState.dispose();
|
|
4315
|
+
}
|
|
4316
|
+
}
|
|
4317
|
+
function pipeRunStreams(handle) {
|
|
4318
|
+
handle.stdout?.pipe(process.stdout, { end: false });
|
|
4319
|
+
handle.stderr?.pipe(process.stderr, { end: false });
|
|
4320
|
+
return {
|
|
4321
|
+
stdout: () => "",
|
|
4322
|
+
stderr: () => "",
|
|
4323
|
+
dispose() {
|
|
4324
|
+
handle.stdout?.unpipe(process.stdout);
|
|
4325
|
+
handle.stderr?.unpipe(process.stderr);
|
|
4326
|
+
}
|
|
4327
|
+
};
|
|
4328
|
+
}
|
|
4329
|
+
function captureRunStreams(handle, execution, onActivity) {
|
|
4330
|
+
let stdout = "";
|
|
4331
|
+
let stderr = "";
|
|
4332
|
+
const listeners = [];
|
|
4333
|
+
const bind = (stream, onChunk) => {
|
|
4334
|
+
if (!stream) return;
|
|
4335
|
+
stream.setEncoding("utf8");
|
|
4336
|
+
const listener = (chunk) => {
|
|
4337
|
+
onActivity();
|
|
4338
|
+
onChunk(chunk.toString());
|
|
4339
|
+
};
|
|
4340
|
+
stream.on("data", listener);
|
|
4341
|
+
listeners.push(() => {
|
|
4342
|
+
stream.off("data", listener);
|
|
4343
|
+
});
|
|
4344
|
+
};
|
|
4345
|
+
bind(handle.stdout, (chunk) => {
|
|
4346
|
+
stdout += chunk;
|
|
4347
|
+
execution?.onStdout?.(chunk);
|
|
4348
|
+
});
|
|
4349
|
+
bind(handle.stderr, (chunk) => {
|
|
4350
|
+
stderr += chunk;
|
|
4351
|
+
execution?.onStderr?.(chunk);
|
|
4352
|
+
});
|
|
4353
|
+
return {
|
|
4354
|
+
stdout: () => stdout,
|
|
4355
|
+
stderr: () => stderr,
|
|
4356
|
+
dispose() {
|
|
4357
|
+
for (const remove2 of listeners) {
|
|
4358
|
+
remove2();
|
|
4359
|
+
}
|
|
4360
|
+
}
|
|
4361
|
+
};
|
|
4362
|
+
}
|
|
4363
|
+
function createAbortSync(signal, handle, activityTimeoutMs) {
|
|
4364
|
+
let activityTimer;
|
|
4365
|
+
let timedOut = false;
|
|
4366
|
+
const resetActivityTimer = activityTimeoutMs ? () => {
|
|
4367
|
+
if (activityTimer) clearTimeout(activityTimer);
|
|
4368
|
+
activityTimer = setTimeout(() => {
|
|
4369
|
+
timedOut = true;
|
|
4370
|
+
handle.kill("SIGTERM");
|
|
4371
|
+
notifyAbort?.();
|
|
4372
|
+
}, activityTimeoutMs);
|
|
4373
|
+
} : () => {
|
|
4374
|
+
};
|
|
4375
|
+
let notifyAbort;
|
|
4376
|
+
if (signal === void 0) {
|
|
4377
|
+
return {
|
|
4378
|
+
waitForExit: (env, jobId) => waitForExit(toLogStreamEnv(env), jobId),
|
|
4379
|
+
waitForHandle: async () => {
|
|
4380
|
+
const result = await handle.result;
|
|
4381
|
+
if (timedOut) {
|
|
4382
|
+
throw createActivityTimeoutError(activityTimeoutMs);
|
|
4383
|
+
}
|
|
4384
|
+
return result;
|
|
4385
|
+
},
|
|
4386
|
+
resetActivityTimer,
|
|
4387
|
+
dispose() {
|
|
4388
|
+
if (activityTimer) clearTimeout(activityTimer);
|
|
4389
|
+
}
|
|
4390
|
+
};
|
|
4391
|
+
}
|
|
4392
|
+
const exitWaitController = new AbortController();
|
|
4393
|
+
let aborted = signal.aborted;
|
|
4394
|
+
const abortedPromise = new Promise((resolve2) => {
|
|
4395
|
+
notifyAbort = resolve2;
|
|
4396
|
+
});
|
|
4397
|
+
const kill = () => {
|
|
4398
|
+
aborted = true;
|
|
4399
|
+
handle.kill("SIGTERM");
|
|
4400
|
+
notifyAbort?.();
|
|
4401
|
+
};
|
|
4402
|
+
if (signal.aborted) {
|
|
4403
|
+
kill();
|
|
4404
|
+
} else {
|
|
4405
|
+
signal.addEventListener("abort", kill, { once: true });
|
|
4406
|
+
}
|
|
4407
|
+
return {
|
|
4408
|
+
async waitForExit(env, jobId) {
|
|
4409
|
+
if (aborted) {
|
|
4410
|
+
return handle.result;
|
|
4411
|
+
}
|
|
4412
|
+
const exit = waitForExit(toLogStreamEnv(env), jobId, {
|
|
4413
|
+
signal: exitWaitController.signal
|
|
4414
|
+
}).then(
|
|
4415
|
+
(value) => ({ kind: "exit", value }),
|
|
4416
|
+
(error2) => ({ kind: "error", error: error2 })
|
|
4417
|
+
);
|
|
4418
|
+
const result = await Promise.race([
|
|
4419
|
+
exit,
|
|
4420
|
+
abortedPromise.then(() => ({ kind: "abort" }))
|
|
4421
|
+
]);
|
|
4422
|
+
if (result.kind === "exit") {
|
|
4423
|
+
return result.value;
|
|
4424
|
+
}
|
|
4425
|
+
if (result.kind === "error") {
|
|
4426
|
+
throw result.error;
|
|
4427
|
+
}
|
|
4428
|
+
exitWaitController.abort();
|
|
4429
|
+
return handle.result;
|
|
4430
|
+
},
|
|
4431
|
+
async waitForHandle() {
|
|
4432
|
+
const result = await Promise.race([
|
|
4433
|
+
handle.result.then((value) => ({ kind: "exit", value })),
|
|
4434
|
+
abortedPromise.then(() => ({ kind: "abort" }))
|
|
4435
|
+
]);
|
|
4436
|
+
if (result.kind === "exit") {
|
|
4437
|
+
if (aborted) {
|
|
4438
|
+
throw createAbortError2();
|
|
4439
|
+
}
|
|
4440
|
+
if (timedOut) {
|
|
4441
|
+
throw createActivityTimeoutError(activityTimeoutMs);
|
|
4442
|
+
}
|
|
4443
|
+
return result.value;
|
|
4444
|
+
}
|
|
4445
|
+
if (timedOut) {
|
|
4446
|
+
throw createActivityTimeoutError(activityTimeoutMs);
|
|
4447
|
+
}
|
|
4448
|
+
throw createAbortError2();
|
|
4449
|
+
},
|
|
4450
|
+
resetActivityTimer,
|
|
4451
|
+
dispose() {
|
|
4452
|
+
if (activityTimer) clearTimeout(activityTimer);
|
|
4453
|
+
exitWaitController.abort();
|
|
4454
|
+
signal.removeEventListener("abort", kill);
|
|
4455
|
+
}
|
|
4456
|
+
};
|
|
4457
|
+
}
|
|
4458
|
+
function toLogStreamEnv(env) {
|
|
4459
|
+
const candidate = env;
|
|
4460
|
+
return candidate.fs === void 0 ? {} : { fs: candidate.fs };
|
|
4461
|
+
}
|
|
4462
|
+
function isPromiseLike(value) {
|
|
4463
|
+
return typeof value.then === "function";
|
|
4464
|
+
}
|
|
4465
|
+
function createAbortError2() {
|
|
4466
|
+
const error2 = new Error("Agent spawn aborted");
|
|
4467
|
+
error2.name = "AbortError";
|
|
4468
|
+
return error2;
|
|
4469
|
+
}
|
|
4470
|
+
function createActivityTimeoutError(timeoutMs) {
|
|
4471
|
+
const error2 = new Error(`Agent spawn timed out after ${timeoutMs / 1e3}s of inactivity`);
|
|
4472
|
+
error2.name = "ActivityTimeoutError";
|
|
4473
|
+
return error2;
|
|
4474
|
+
}
|
|
4475
|
+
function createUlid() {
|
|
4476
|
+
const time = BigInt(Date.now());
|
|
4477
|
+
const random = randomBytes(10);
|
|
4478
|
+
let randomValue = 0n;
|
|
4479
|
+
for (const byte of random) {
|
|
4480
|
+
randomValue = randomValue << 8n | BigInt(byte);
|
|
4481
|
+
}
|
|
4482
|
+
return encodeBase32(time, 10) + encodeBase32(randomValue, 16);
|
|
4483
|
+
}
|
|
4484
|
+
function encodeBase32(value, length) {
|
|
4485
|
+
const chars = Array.from({ length }, () => "0");
|
|
4486
|
+
let remaining = value;
|
|
4487
|
+
for (let index = length - 1; index >= 0; index -= 1) {
|
|
4488
|
+
chars[index] = ULID_ALPHABET[Number(remaining & 31n)];
|
|
4489
|
+
remaining >>= 5n;
|
|
4490
|
+
}
|
|
4491
|
+
return chars.join("");
|
|
4492
|
+
}
|
|
4493
|
+
|
|
4494
|
+
// packages/agent-harness-tools/src/poe-command-execution.ts
|
|
4495
|
+
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
4496
|
+
import os3 from "node:os";
|
|
4497
|
+
|
|
4498
|
+
// packages/agent-harness-tools/src/execution-env.ts
|
|
4499
|
+
var executionEnvFactories = /* @__PURE__ */ new Map();
|
|
4500
|
+
function registerExecutionEnvFactory(factory) {
|
|
4501
|
+
executionEnvFactories.set(factory.type, factory);
|
|
4502
|
+
}
|
|
4503
|
+
function selectExecutionEnv(runtime) {
|
|
4504
|
+
const factory = executionEnvFactories.get(runtime.type);
|
|
4505
|
+
if (factory === void 0) {
|
|
4506
|
+
throw new Error(
|
|
4507
|
+
`No execution environment factory registered for runtime type "${runtime.type}".`
|
|
4508
|
+
);
|
|
4509
|
+
}
|
|
4510
|
+
return factory;
|
|
4511
|
+
}
|
|
4512
|
+
|
|
4513
|
+
// packages/agent-harness-tools/src/poe-command-execution.ts
|
|
4514
|
+
function resolvePoeCommandExecution(input) {
|
|
4515
|
+
const homeDir = input.context?.homeDir ?? os3.homedir();
|
|
4516
|
+
const config = applyRuntimeOverrides(loadRuntimeConfig(input.cwd, homeDir), input.runtime, input.cwd);
|
|
4517
|
+
const resolved = resolveRuntime({ cwd: input.cwd, config });
|
|
4518
|
+
const factory = selectExecutionEnv(resolved.runtime);
|
|
4519
|
+
const state = input.context?.state ?? loadState(homeDir);
|
|
4520
|
+
return {
|
|
4521
|
+
factory,
|
|
4522
|
+
detach: factory.supportsDetach === true && config.runner.detach,
|
|
4523
|
+
state,
|
|
4524
|
+
openSpec: {
|
|
4525
|
+
cwd: input.cwd,
|
|
4526
|
+
runtime: resolved.runtime,
|
|
4527
|
+
runner: config.runner,
|
|
4528
|
+
state,
|
|
4529
|
+
env: input.env,
|
|
4530
|
+
uploadIgnoreFiles: config.runner.workspace?.exclude ?? [],
|
|
4531
|
+
jobLabel: {
|
|
4532
|
+
tool: input.tool,
|
|
4533
|
+
argv: input.argv
|
|
4534
|
+
},
|
|
4535
|
+
...input.openSpec
|
|
4536
|
+
}
|
|
4537
|
+
};
|
|
4538
|
+
}
|
|
4539
|
+
function applyRuntimeOverrides(config, overrides, cwd = process.cwd()) {
|
|
4540
|
+
if (!overrides) {
|
|
4541
|
+
return config;
|
|
4542
|
+
}
|
|
4543
|
+
const runtime = parseRuntime({
|
|
4544
|
+
...config.runtime,
|
|
4545
|
+
...overrides.runtime !== void 0 ? { type: overrides.runtime } : {},
|
|
4546
|
+
...overrides.runtimeImage !== void 0 ? { image: overrides.runtimeImage } : {},
|
|
4547
|
+
...overrides.runtimeTemplate !== void 0 ? { template_id: overrides.runtimeTemplate } : {},
|
|
4548
|
+
...overrides.mountPoeCode === true ? { mounts: [...config.runtime.mounts, createPoeCodeMount(cwd)] } : {}
|
|
4549
|
+
});
|
|
4550
|
+
return {
|
|
4551
|
+
runtime,
|
|
4552
|
+
runner: {
|
|
4553
|
+
...config.runner,
|
|
4554
|
+
...overrides.detach === true ? { detach: true } : {}
|
|
4555
|
+
}
|
|
4556
|
+
};
|
|
4557
|
+
}
|
|
4558
|
+
function createPoeCodeMount(cwd) {
|
|
4559
|
+
return {
|
|
4560
|
+
source: cwd,
|
|
4561
|
+
target: "/usr/local/lib/poe-code",
|
|
4562
|
+
readonly: true
|
|
4563
|
+
};
|
|
4564
|
+
}
|
|
4565
|
+
function loadRuntimeConfig(cwd, homeDir) {
|
|
4566
|
+
const document = deepMergeDocuments(
|
|
4567
|
+
readConfigDocument(resolveConfigPath(homeDir)),
|
|
4568
|
+
readConfigDocument(resolveProjectConfigPath(cwd))
|
|
4569
|
+
);
|
|
4570
|
+
const runtimeScope = resolveScope(runtimeConfigScope.schema, document.runtime, process.env);
|
|
4571
|
+
return {
|
|
4572
|
+
runtime: parseRuntime(runtimeScope),
|
|
4573
|
+
runner: runtimeScope.runner
|
|
4574
|
+
};
|
|
4575
|
+
}
|
|
4576
|
+
function readConfigDocument(filePath) {
|
|
4577
|
+
if (!existsSync2(filePath)) {
|
|
4578
|
+
return {};
|
|
4579
|
+
}
|
|
4580
|
+
return JSON.parse(readFileSync(filePath, "utf8"));
|
|
4581
|
+
}
|
|
4582
|
+
function loadState(homeDir) {
|
|
4583
|
+
if (process.env.VITEST === "true") {
|
|
4584
|
+
return createMemoryStateManager();
|
|
4585
|
+
}
|
|
4586
|
+
return createStateManager(homeDir);
|
|
4587
|
+
}
|
|
4588
|
+
function createMemoryStateManager() {
|
|
4589
|
+
const jobs = /* @__PURE__ */ new Map();
|
|
4590
|
+
return {
|
|
4591
|
+
templates: {
|
|
4592
|
+
async get() {
|
|
4593
|
+
return null;
|
|
4594
|
+
},
|
|
4595
|
+
async put() {
|
|
4596
|
+
},
|
|
4597
|
+
async remove() {
|
|
4598
|
+
},
|
|
4599
|
+
async list() {
|
|
4600
|
+
return [];
|
|
4601
|
+
}
|
|
4602
|
+
},
|
|
4603
|
+
jobs: {
|
|
4604
|
+
async get(id) {
|
|
4605
|
+
return jobs.get(id) ?? null;
|
|
4606
|
+
},
|
|
4607
|
+
async put(entry) {
|
|
4608
|
+
jobs.set(entry.id, entry);
|
|
4609
|
+
},
|
|
4610
|
+
async update(id, patch) {
|
|
4611
|
+
const current = jobs.get(id);
|
|
4612
|
+
if (!current) {
|
|
4613
|
+
return null;
|
|
4614
|
+
}
|
|
4615
|
+
const updated = { ...current, ...patch, id };
|
|
4616
|
+
jobs.set(id, updated);
|
|
4617
|
+
return updated;
|
|
4618
|
+
},
|
|
4619
|
+
async list(filter) {
|
|
4620
|
+
const entries = Array.from(jobs.values());
|
|
4621
|
+
if (!filter) {
|
|
4622
|
+
return entries;
|
|
4623
|
+
}
|
|
4624
|
+
return entries.filter(
|
|
4625
|
+
(entry) => Object.entries(filter).every(([key, value]) => entry[key] === value)
|
|
4626
|
+
);
|
|
4627
|
+
},
|
|
4628
|
+
async remove(id) {
|
|
4629
|
+
jobs.delete(id);
|
|
4630
|
+
}
|
|
4631
|
+
}
|
|
4632
|
+
};
|
|
4633
|
+
}
|
|
4634
|
+
|
|
4635
|
+
// packages/agent-harness-tools/src/workspace-transfer.ts
|
|
4636
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
4637
|
+
import { promises as nodeFs3 } from "node:fs";
|
|
4638
|
+
import path24 from "node:path";
|
|
4639
|
+
|
|
4640
|
+
// packages/process-runner/src/docker/context.ts
|
|
4641
|
+
import { execSync } from "node:child_process";
|
|
4642
|
+
function detectContext() {
|
|
4643
|
+
try {
|
|
4644
|
+
const output = execSync("colima list --json", {
|
|
4645
|
+
encoding: "utf-8",
|
|
4646
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
4647
|
+
});
|
|
4648
|
+
const lines = output.trim().split("\n").filter(Boolean);
|
|
4649
|
+
for (const line of lines) {
|
|
4650
|
+
const profile = JSON.parse(line);
|
|
4651
|
+
if (profile.status === "Running" && profile.runtime === "docker") {
|
|
4652
|
+
const name = profile.name ?? profile.profile;
|
|
4653
|
+
if (!name) {
|
|
4654
|
+
continue;
|
|
4655
|
+
}
|
|
4656
|
+
return name === "default" ? "colima" : `colima-${name}`;
|
|
4657
|
+
}
|
|
4658
|
+
}
|
|
4659
|
+
} catch {
|
|
4660
|
+
return null;
|
|
4661
|
+
}
|
|
4662
|
+
return null;
|
|
4663
|
+
}
|
|
4664
|
+
function buildContextArgs(engine, context) {
|
|
4665
|
+
if (engine === "docker" && context) {
|
|
4666
|
+
return ["--context", context];
|
|
4667
|
+
}
|
|
4668
|
+
return [];
|
|
4669
|
+
}
|
|
4670
|
+
|
|
4671
|
+
// packages/process-runner/src/docker/engine.ts
|
|
4672
|
+
import { execSync as execSync2 } from "node:child_process";
|
|
4673
|
+
function detectEngine() {
|
|
4674
|
+
if (isEngineAvailable("docker")) {
|
|
4675
|
+
return "docker";
|
|
4676
|
+
}
|
|
4677
|
+
if (isEngineAvailable("podman")) {
|
|
4678
|
+
return "podman";
|
|
4679
|
+
}
|
|
4680
|
+
throw new Error(
|
|
4681
|
+
"No container engine found. Please install Docker or Podman:\n - Docker Desktop: https://www.docker.com/products/docker-desktop\n - Colima (macOS): brew install colima && colima start\n - Podman: https://podman.io/docs/installation"
|
|
4682
|
+
);
|
|
4683
|
+
}
|
|
4684
|
+
function isEngineAvailable(engine) {
|
|
4685
|
+
try {
|
|
4686
|
+
execSync2(`${engine} --version`, {
|
|
4687
|
+
stdio: "ignore"
|
|
4688
|
+
});
|
|
4689
|
+
return true;
|
|
4690
|
+
} catch {
|
|
4691
|
+
return false;
|
|
4692
|
+
}
|
|
4693
|
+
}
|
|
4694
|
+
|
|
4695
|
+
// packages/process-runner/src/docker/docker-runner.ts
|
|
4696
|
+
import * as childProcess from "node:child_process";
|
|
4697
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
4698
|
+
|
|
4699
|
+
// packages/process-runner/src/docker/args.ts
|
|
4700
|
+
import path25 from "node:path";
|
|
4701
|
+
function buildDockerRunArgs(input) {
|
|
4702
|
+
const args = [input.engine];
|
|
4703
|
+
if (input.engine === "docker" && input.context) {
|
|
4704
|
+
args.push("--context", input.context);
|
|
4705
|
+
}
|
|
4706
|
+
args.push("run");
|
|
4707
|
+
if (input.rm) {
|
|
4708
|
+
args.push("--rm");
|
|
4709
|
+
}
|
|
4710
|
+
if (input.detached) {
|
|
4711
|
+
args.push("-d");
|
|
4712
|
+
}
|
|
4713
|
+
if (input.interactive) {
|
|
4714
|
+
args.push("-i");
|
|
4715
|
+
}
|
|
4716
|
+
if (input.tty) {
|
|
4717
|
+
args.push("-t");
|
|
4718
|
+
}
|
|
4719
|
+
args.push("--name", input.containerName);
|
|
4720
|
+
if (input.cwd !== void 0) {
|
|
4721
|
+
args.push("-w", input.cwd);
|
|
4722
|
+
}
|
|
4723
|
+
for (const [key, value] of Object.entries(input.env ?? {})) {
|
|
4724
|
+
args.push("-e", `${key}=${value}`);
|
|
4725
|
+
}
|
|
4726
|
+
for (const mount of input.mounts) {
|
|
4727
|
+
const volume = `${path25.resolve(mount.source)}:${mount.target}${mount.readonly ? ":ro" : ""}`;
|
|
4728
|
+
args.push("-v", volume);
|
|
4729
|
+
}
|
|
4730
|
+
for (const port of input.ports) {
|
|
4731
|
+
const mapping = `${port.host}:${port.container}${port.protocol === void 0 || port.protocol === "tcp" ? "" : `/${port.protocol}`}`;
|
|
4732
|
+
args.push("-p", mapping);
|
|
4733
|
+
}
|
|
4734
|
+
if (input.network !== void 0) {
|
|
4735
|
+
args.push("--network", input.network);
|
|
4736
|
+
}
|
|
4737
|
+
args.push(...input.extraArgs, input.image, input.command, ...input.args);
|
|
4738
|
+
return args;
|
|
4739
|
+
}
|
|
4740
|
+
|
|
4741
|
+
// packages/process-runner/src/docker/docker-execution-env.ts
|
|
4742
|
+
import { createHash as createHash4, randomBytes as randomBytes3 } from "node:crypto";
|
|
4743
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
4744
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
4745
|
+
import { tmpdir } from "node:os";
|
|
4746
|
+
import path26 from "node:path";
|
|
4747
|
+
|
|
4748
|
+
// packages/process-runner/src/host/host-runner.ts
|
|
4749
|
+
import { spawn as spawnChildProcess } from "node:child_process";
|
|
4750
|
+
function createHostRunner(options = {}) {
|
|
4751
|
+
const detached = options.detached === true;
|
|
4752
|
+
return {
|
|
4753
|
+
name: "host",
|
|
4754
|
+
exec(spec) {
|
|
4755
|
+
const stdinMode = spec.stdin ?? "ignore";
|
|
4756
|
+
const stdoutMode = spec.stdout ?? "pipe";
|
|
4757
|
+
const stderrMode = spec.stderr ?? "pipe";
|
|
4758
|
+
const stdio = stdinMode === "inherit" && stdoutMode === "inherit" && stderrMode === "inherit" ? "inherit" : [stdinMode, stdoutMode, stderrMode];
|
|
4759
|
+
const child = spawnChildProcess(spec.command, spec.args ?? [], {
|
|
4760
|
+
cwd: spec.cwd,
|
|
4761
|
+
env: spec.env,
|
|
4762
|
+
stdio,
|
|
4763
|
+
...detached ? { detached: true } : {}
|
|
4764
|
+
});
|
|
4765
|
+
if (detached) {
|
|
4766
|
+
child.unref();
|
|
4767
|
+
}
|
|
4768
|
+
const kill = (signal) => {
|
|
4769
|
+
if (detached && process.platform !== "win32" && child.pid !== void 0) {
|
|
4770
|
+
process.kill(-child.pid, signal);
|
|
4771
|
+
return;
|
|
4772
|
+
}
|
|
4773
|
+
child.kill(signal);
|
|
4774
|
+
};
|
|
4775
|
+
let settled = false;
|
|
4776
|
+
let resolveResult = null;
|
|
4777
|
+
const result = new Promise((resolve2) => {
|
|
4778
|
+
resolveResult = resolve2;
|
|
4779
|
+
});
|
|
4780
|
+
const cleanupAbort = bindAbortSignal(spec.signal, () => {
|
|
4781
|
+
kill("SIGTERM");
|
|
4782
|
+
});
|
|
4783
|
+
child.once("close", (code) => {
|
|
4784
|
+
if (settled) return;
|
|
4785
|
+
settled = true;
|
|
4786
|
+
cleanupAbort();
|
|
4787
|
+
resolveResult?.({ exitCode: code ?? 1 });
|
|
4788
|
+
});
|
|
4789
|
+
child.once("error", () => {
|
|
4790
|
+
if (settled) return;
|
|
4791
|
+
settled = true;
|
|
4792
|
+
cleanupAbort();
|
|
4793
|
+
resolveResult?.({ exitCode: 1 });
|
|
4794
|
+
});
|
|
4795
|
+
return {
|
|
4796
|
+
pid: child.pid ?? null,
|
|
4797
|
+
stdin: child.stdin,
|
|
4798
|
+
stdout: child.stdout,
|
|
4799
|
+
stderr: child.stderr,
|
|
4800
|
+
result,
|
|
4801
|
+
kill
|
|
4802
|
+
};
|
|
4803
|
+
}
|
|
4804
|
+
};
|
|
4805
|
+
}
|
|
4806
|
+
function bindAbortSignal(signal, onAbort) {
|
|
4807
|
+
if (signal === void 0) {
|
|
4808
|
+
return () => {
|
|
4809
|
+
};
|
|
4810
|
+
}
|
|
4811
|
+
if (signal.aborted) {
|
|
4812
|
+
onAbort();
|
|
4813
|
+
return () => {
|
|
4814
|
+
};
|
|
4815
|
+
}
|
|
4816
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
4817
|
+
return () => {
|
|
4818
|
+
signal.removeEventListener("abort", onAbort);
|
|
4819
|
+
};
|
|
4820
|
+
}
|
|
4821
|
+
|
|
4822
|
+
// packages/process-runner/src/docker/docker-execution-env.ts
|
|
4823
|
+
var containerCommand = ["sh", "-c", "while :; do sleep 3600; done"];
|
|
4824
|
+
var dockerExecutionEnvFactory = {
|
|
4825
|
+
type: "docker",
|
|
4826
|
+
supportsDetach: true,
|
|
4827
|
+
async open(spec) {
|
|
4828
|
+
const runtime = parseDockerRuntime(spec.runtime);
|
|
4829
|
+
const runner = spec.hostRunner ?? createHostRunner();
|
|
4830
|
+
const engine = runtime.engine ?? detectEngine();
|
|
4831
|
+
const context = detectContext();
|
|
4832
|
+
const image = await resolveImage({
|
|
4833
|
+
spec,
|
|
4834
|
+
runtime,
|
|
4835
|
+
runner,
|
|
4836
|
+
engine,
|
|
4837
|
+
context
|
|
4838
|
+
});
|
|
4839
|
+
const containerName = createContainerName();
|
|
4840
|
+
const runArgs = buildDockerRunArgs({
|
|
4841
|
+
engine,
|
|
4842
|
+
context,
|
|
4843
|
+
image,
|
|
4844
|
+
command: containerCommand[0],
|
|
4845
|
+
args: containerCommand.slice(1),
|
|
4846
|
+
cwd: void 0,
|
|
4847
|
+
env: void 0,
|
|
4848
|
+
mounts: runtime.mounts ?? [],
|
|
4849
|
+
ports: [],
|
|
4850
|
+
network: runtime.network,
|
|
4851
|
+
containerName,
|
|
4852
|
+
detached: true,
|
|
4853
|
+
interactive: true,
|
|
4854
|
+
tty: false,
|
|
4855
|
+
rm: false,
|
|
4856
|
+
extraArgs: runtime.extra_args ?? []
|
|
4857
|
+
});
|
|
4858
|
+
const [command, ...args] = runArgs;
|
|
4859
|
+
const id = (await runAndRead(runner, { command, args, stdout: "pipe", stderr: "pipe" })).trim();
|
|
4860
|
+
return createDockerEnv({
|
|
4861
|
+
id,
|
|
4862
|
+
spec,
|
|
4863
|
+
runner,
|
|
4864
|
+
engine,
|
|
4865
|
+
context
|
|
4866
|
+
});
|
|
4867
|
+
},
|
|
4868
|
+
async attach(envId) {
|
|
4869
|
+
const engine = detectEngine();
|
|
4870
|
+
return createDockerEnv({
|
|
4871
|
+
id: envId,
|
|
4872
|
+
spec: createAttachedSpec(),
|
|
4873
|
+
runner: createHostRunner(),
|
|
4874
|
+
engine,
|
|
4875
|
+
context: detectContext()
|
|
4876
|
+
});
|
|
4877
|
+
}
|
|
4878
|
+
};
|
|
4879
|
+
function createDockerEnv(input) {
|
|
4880
|
+
const containerRef = input.id;
|
|
4881
|
+
return {
|
|
4882
|
+
id: containerRef,
|
|
4883
|
+
job: null,
|
|
4884
|
+
async uploadWorkspace() {
|
|
4885
|
+
const tempDir = mkdtempSync(path26.join(tmpdir(), "poe-docker-upload-"));
|
|
4886
|
+
const archivePath = path26.join(tempDir, "workspace.tar");
|
|
4887
|
+
try {
|
|
4888
|
+
const excludeArgs = input.spec.uploadIgnoreFiles.flatMap((ignored) => [
|
|
4889
|
+
"--exclude",
|
|
4890
|
+
ignored
|
|
4891
|
+
]);
|
|
4892
|
+
const tarArgs = [...excludeArgs, "-cf", archivePath, "-C", input.spec.cwd, "."];
|
|
4893
|
+
await runOrThrow(input.runner, {
|
|
4894
|
+
command: "tar",
|
|
4895
|
+
args: tarArgs,
|
|
4896
|
+
stdout: "pipe",
|
|
4897
|
+
stderr: "pipe"
|
|
4898
|
+
});
|
|
4899
|
+
await runOrThrow(input.runner, {
|
|
4900
|
+
command: input.engine,
|
|
4901
|
+
args: [
|
|
4902
|
+
...buildContextArgs(input.engine, input.context),
|
|
4903
|
+
"cp",
|
|
4904
|
+
archivePath,
|
|
4905
|
+
`${containerRef}:/tmp/poe-workspace-upload.tar`
|
|
4906
|
+
],
|
|
4907
|
+
stdout: "pipe",
|
|
4908
|
+
stderr: "pipe"
|
|
4909
|
+
});
|
|
4910
|
+
await runOrThrow(input.runner, {
|
|
4911
|
+
command: input.engine,
|
|
4912
|
+
args: [
|
|
4913
|
+
...buildContextArgs(input.engine, input.context),
|
|
4914
|
+
"exec",
|
|
4915
|
+
containerRef,
|
|
4916
|
+
"sh",
|
|
4917
|
+
"-c",
|
|
4918
|
+
`mkdir -p ${shellQuote2(input.spec.cwd)} && tar -xf /tmp/poe-workspace-upload.tar -C ${shellQuote2(input.spec.cwd)}`
|
|
4919
|
+
],
|
|
4920
|
+
stdout: "pipe",
|
|
4921
|
+
stderr: "pipe"
|
|
4922
|
+
});
|
|
4923
|
+
return { files: 0, bytes: 0, skipped: [] };
|
|
4924
|
+
} finally {
|
|
4925
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
4926
|
+
}
|
|
4927
|
+
},
|
|
4928
|
+
async downloadWorkspace(opts) {
|
|
4929
|
+
const tempDir = mkdtempSync(path26.join(tmpdir(), "poe-docker-download-"));
|
|
4930
|
+
const archivePath = path26.join(tempDir, "workspace.tar");
|
|
4931
|
+
try {
|
|
4932
|
+
await runOrThrow(input.runner, {
|
|
4933
|
+
command: input.engine,
|
|
4934
|
+
args: [
|
|
4935
|
+
...buildContextArgs(input.engine, input.context),
|
|
4936
|
+
"exec",
|
|
4937
|
+
containerRef,
|
|
4938
|
+
"sh",
|
|
4939
|
+
"-c",
|
|
4940
|
+
`tar -cf /tmp/poe-workspace-download.tar -C ${shellQuote2(input.spec.cwd)} .`
|
|
4941
|
+
],
|
|
4942
|
+
stdout: "pipe",
|
|
4943
|
+
stderr: "pipe"
|
|
4944
|
+
});
|
|
4945
|
+
await runOrThrow(input.runner, {
|
|
4946
|
+
command: input.engine,
|
|
4947
|
+
args: [
|
|
4948
|
+
...buildContextArgs(input.engine, input.context),
|
|
4949
|
+
"cp",
|
|
4950
|
+
`${containerRef}:/tmp/poe-workspace-download.tar`,
|
|
4951
|
+
archivePath
|
|
4952
|
+
],
|
|
4953
|
+
stdout: "pipe",
|
|
4954
|
+
stderr: "pipe"
|
|
4955
|
+
});
|
|
4956
|
+
const extractMode = opts.conflictPolicy === "refuse" ? "-xkf" : "-xf";
|
|
4957
|
+
await runOrThrow(input.runner, {
|
|
4958
|
+
command: "tar",
|
|
4959
|
+
args: [extractMode, archivePath, "-C", input.spec.cwd],
|
|
4960
|
+
stdout: "pipe",
|
|
4961
|
+
stderr: "pipe"
|
|
4962
|
+
});
|
|
4963
|
+
return { files: 0, bytes: 0, conflicts: [] };
|
|
4964
|
+
} finally {
|
|
4965
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
4966
|
+
}
|
|
4967
|
+
},
|
|
4968
|
+
exec(spec) {
|
|
4969
|
+
return input.runner.exec({
|
|
4970
|
+
command: input.engine,
|
|
4971
|
+
args: [
|
|
4972
|
+
...buildContextArgs(input.engine, input.context),
|
|
4973
|
+
"exec",
|
|
4974
|
+
...spec.stdin === "pipe" || spec.stdin === "inherit" ? ["-i"] : [],
|
|
4975
|
+
...spec.tty === true ? ["-t"] : [],
|
|
4976
|
+
...spec.cwd !== void 0 ? ["-w", spec.cwd] : [],
|
|
4977
|
+
...buildEnvArgs(spec.env),
|
|
4978
|
+
containerRef,
|
|
4979
|
+
spec.command,
|
|
4980
|
+
...spec.args ?? []
|
|
4981
|
+
],
|
|
4982
|
+
stdin: spec.stdin,
|
|
4983
|
+
stdout: spec.stdout,
|
|
4984
|
+
stderr: spec.stderr,
|
|
4985
|
+
tty: spec.tty
|
|
4986
|
+
});
|
|
4987
|
+
},
|
|
4988
|
+
async detach() {
|
|
4989
|
+
return createContainerJob(containerRef, input.runner, input.engine, input.context);
|
|
4990
|
+
},
|
|
4991
|
+
shell() {
|
|
4992
|
+
const shellSpec = input.spec.shellSpec;
|
|
4993
|
+
return this.exec({
|
|
4994
|
+
command: shellSpec?.command ?? input.spec.env.SHELL ?? "sh",
|
|
4995
|
+
...shellSpec?.args ? { args: shellSpec.args } : {},
|
|
4996
|
+
cwd: input.spec.cwd,
|
|
4997
|
+
env: shellSpec && "env" in shellSpec ? shellSpec.env : input.spec.env,
|
|
4998
|
+
stdin: "inherit",
|
|
4999
|
+
stdout: "inherit",
|
|
5000
|
+
stderr: "inherit",
|
|
5001
|
+
tty: true
|
|
5002
|
+
});
|
|
5003
|
+
},
|
|
5004
|
+
async close() {
|
|
5005
|
+
await runOrThrow(input.runner, {
|
|
5006
|
+
command: input.engine,
|
|
5007
|
+
args: [...buildContextArgs(input.engine, input.context), "rm", "-f", containerRef],
|
|
5008
|
+
stdout: "pipe",
|
|
5009
|
+
stderr: "pipe"
|
|
5010
|
+
});
|
|
5011
|
+
}
|
|
5012
|
+
};
|
|
5013
|
+
}
|
|
5014
|
+
async function resolveImage(input) {
|
|
5015
|
+
if (input.runtime.image !== void 0) {
|
|
5016
|
+
return input.runtime.image;
|
|
5017
|
+
}
|
|
5018
|
+
const dockerfilePath = path26.resolve(
|
|
5019
|
+
input.spec.cwd,
|
|
5020
|
+
input.runtime.dockerfile ?? path26.join(".poe-code", "Dockerfile")
|
|
5021
|
+
);
|
|
5022
|
+
const buildContext = path26.resolve(input.spec.cwd, input.runtime.build_context ?? ".");
|
|
5023
|
+
const dockerfileBytes = await readFile10(dockerfilePath);
|
|
5024
|
+
const hash = hashDockerTemplate(dockerfileBytes, input.runtime.build_args ?? {});
|
|
5025
|
+
const cached2 = await input.spec.state?.templates.get("docker", hash);
|
|
5026
|
+
if (cached2?.image !== void 0) {
|
|
5027
|
+
return cached2.image;
|
|
5028
|
+
}
|
|
5029
|
+
const image = `poe-code/local:${hash}`;
|
|
5030
|
+
await buildImage({
|
|
5031
|
+
runner: input.runner,
|
|
5032
|
+
engine: input.engine,
|
|
5033
|
+
context: input.context,
|
|
5034
|
+
image,
|
|
5035
|
+
dockerfilePath,
|
|
5036
|
+
buildContext,
|
|
5037
|
+
buildArgs: input.runtime.build_args ?? {}
|
|
5038
|
+
});
|
|
5039
|
+
await input.spec.state?.templates.put("docker", {
|
|
5040
|
+
hash,
|
|
5041
|
+
image,
|
|
5042
|
+
runtime_type: "docker",
|
|
5043
|
+
dockerfile_path: dockerfilePath,
|
|
5044
|
+
built_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
5045
|
+
});
|
|
5046
|
+
return image;
|
|
5047
|
+
}
|
|
5048
|
+
function hashDockerTemplate(dockerfileBytes, buildArgs) {
|
|
5049
|
+
const hash = createHash4("sha256");
|
|
5050
|
+
hash.update(dockerfileBytes);
|
|
5051
|
+
hash.update("\0");
|
|
5052
|
+
for (const [key, value] of sortedBuildArgs(buildArgs)) {
|
|
5053
|
+
hash.update(key);
|
|
5054
|
+
hash.update("=");
|
|
5055
|
+
hash.update(value);
|
|
5056
|
+
hash.update("\0");
|
|
5057
|
+
}
|
|
5058
|
+
return hash.digest("hex");
|
|
5059
|
+
}
|
|
5060
|
+
async function buildImage(input) {
|
|
5061
|
+
await runOrThrow(input.runner, {
|
|
5062
|
+
command: input.engine,
|
|
5063
|
+
args: [
|
|
5064
|
+
...buildContextArgs(input.engine, input.context),
|
|
5065
|
+
"build",
|
|
5066
|
+
"--tag",
|
|
5067
|
+
input.image,
|
|
5068
|
+
"-f",
|
|
5069
|
+
input.dockerfilePath,
|
|
5070
|
+
...sortedBuildArgs(input.buildArgs).flatMap(([key, value]) => [
|
|
5071
|
+
"--build-arg",
|
|
5072
|
+
`${key}=${value}`
|
|
5073
|
+
]),
|
|
5074
|
+
input.buildContext
|
|
5075
|
+
],
|
|
5076
|
+
stdout: "pipe",
|
|
5077
|
+
stderr: "pipe"
|
|
5078
|
+
});
|
|
5079
|
+
}
|
|
5080
|
+
function parseDockerRuntime(runtime) {
|
|
5081
|
+
if (!runtime || typeof runtime !== "object" || Array.isArray(runtime)) {
|
|
5082
|
+
throw new Error("docker runtime must be an object");
|
|
5083
|
+
}
|
|
5084
|
+
const record = runtime;
|
|
5085
|
+
if (record.type !== "docker") {
|
|
5086
|
+
throw new Error('docker runtime type must be "docker"');
|
|
5087
|
+
}
|
|
5088
|
+
return record;
|
|
5089
|
+
}
|
|
5090
|
+
async function runAndRead(runner, spec) {
|
|
5091
|
+
const handle = runner.exec(spec);
|
|
5092
|
+
const stdout = readStream(handle.stdout);
|
|
5093
|
+
const stderr = readStream(handle.stderr);
|
|
5094
|
+
const result = await handle.result;
|
|
5095
|
+
const output = await stdout;
|
|
5096
|
+
if (result.exitCode !== 0) {
|
|
5097
|
+
const errorOutput = await stderr;
|
|
5098
|
+
throw new Error(
|
|
5099
|
+
`Command failed with exit code ${result.exitCode}: ${spec.command} ${(spec.args ?? []).join(" ")}${errorOutput ? `
|
|
5100
|
+
${errorOutput}` : ""}`
|
|
5101
|
+
);
|
|
5102
|
+
}
|
|
5103
|
+
return output;
|
|
5104
|
+
}
|
|
5105
|
+
async function runOrThrow(runner, spec) {
|
|
5106
|
+
await runAndRead(runner, spec);
|
|
5107
|
+
}
|
|
5108
|
+
async function readStream(stream) {
|
|
5109
|
+
if (stream === null) {
|
|
5110
|
+
return "";
|
|
5111
|
+
}
|
|
5112
|
+
stream.setEncoding("utf8");
|
|
5113
|
+
const chunks = [];
|
|
5114
|
+
for await (const chunk of stream) {
|
|
5115
|
+
chunks.push(String(chunk));
|
|
5116
|
+
}
|
|
5117
|
+
return chunks.join("");
|
|
5118
|
+
}
|
|
5119
|
+
function sortedBuildArgs(buildArgs) {
|
|
5120
|
+
return Object.entries(buildArgs).sort(([left], [right]) => left.localeCompare(right));
|
|
5121
|
+
}
|
|
5122
|
+
function buildEnvArgs(env) {
|
|
5123
|
+
if (env === void 0) {
|
|
5124
|
+
return [];
|
|
5125
|
+
}
|
|
5126
|
+
return Object.entries(env).flatMap(([key, value]) => ["-e", `${key}=${value}`]);
|
|
5127
|
+
}
|
|
5128
|
+
function createContainerName() {
|
|
5129
|
+
return `poe-env-${randomBytes3(6).toString("hex")}`;
|
|
5130
|
+
}
|
|
5131
|
+
async function createContainerJob(containerId, runner, engine, context) {
|
|
5132
|
+
return {
|
|
5133
|
+
id: containerId,
|
|
5134
|
+
envId: containerId,
|
|
5135
|
+
tool: "docker",
|
|
5136
|
+
argv: ["attach", containerId],
|
|
5137
|
+
async status() {
|
|
5138
|
+
const handle = runner.exec({
|
|
5139
|
+
command: engine,
|
|
5140
|
+
args: [
|
|
5141
|
+
...buildContextArgs(engine, context),
|
|
5142
|
+
"inspect",
|
|
5143
|
+
"-f",
|
|
5144
|
+
"{{.State.Status}}",
|
|
5145
|
+
containerId
|
|
5146
|
+
],
|
|
5147
|
+
stdout: "pipe",
|
|
5148
|
+
stderr: "pipe"
|
|
5149
|
+
});
|
|
5150
|
+
const stdout = await readStream(handle.stdout);
|
|
5151
|
+
const result = await handle.result;
|
|
5152
|
+
if (result.exitCode !== 0) {
|
|
5153
|
+
return "lost";
|
|
5154
|
+
}
|
|
5155
|
+
return stdout.trim() === "running" ? "running" : "exited";
|
|
5156
|
+
},
|
|
5157
|
+
async *stream() {
|
|
5158
|
+
},
|
|
5159
|
+
async wait() {
|
|
5160
|
+
const handle = runner.exec({
|
|
5161
|
+
command: engine,
|
|
5162
|
+
args: [...buildContextArgs(engine, context), "wait", containerId],
|
|
5163
|
+
stdout: "pipe",
|
|
5164
|
+
stderr: "pipe"
|
|
5165
|
+
});
|
|
5166
|
+
const stdout = await readStream(handle.stdout);
|
|
5167
|
+
const result = await handle.result;
|
|
5168
|
+
return { exitCode: Number.parseInt(stdout.trim(), 10) || result.exitCode };
|
|
5169
|
+
},
|
|
5170
|
+
async kill(signal) {
|
|
5171
|
+
const args = signal === void 0 || signal === "SIGTERM" ? ["stop", containerId] : ["kill", ...signal === "SIGKILL" ? [] : [`--signal=${signal}`], containerId];
|
|
5172
|
+
await runOrThrow(runner, {
|
|
5173
|
+
command: engine,
|
|
5174
|
+
args: [...buildContextArgs(engine, context), ...args],
|
|
5175
|
+
stdout: "pipe",
|
|
5176
|
+
stderr: "pipe"
|
|
5177
|
+
});
|
|
5178
|
+
}
|
|
5179
|
+
};
|
|
5180
|
+
}
|
|
5181
|
+
function createAttachedSpec() {
|
|
5182
|
+
return {
|
|
5183
|
+
cwd: "/workspace",
|
|
5184
|
+
runtime: {
|
|
5185
|
+
type: "docker",
|
|
5186
|
+
image: "attached",
|
|
5187
|
+
build_args: {},
|
|
5188
|
+
mounts: []
|
|
5189
|
+
},
|
|
5190
|
+
env: {},
|
|
5191
|
+
uploadIgnoreFiles: [],
|
|
5192
|
+
jobLabel: {
|
|
5193
|
+
tool: "docker",
|
|
5194
|
+
argv: []
|
|
5195
|
+
}
|
|
5196
|
+
};
|
|
5197
|
+
}
|
|
5198
|
+
function shellQuote2(value) {
|
|
5199
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
5200
|
+
}
|
|
5201
|
+
|
|
5202
|
+
// packages/process-runner/src/host/host-execution-env.ts
|
|
5203
|
+
var hostExecutionEnvFactory = {
|
|
5204
|
+
type: "host",
|
|
5205
|
+
supportsDetach: false,
|
|
5206
|
+
async open(openSpec) {
|
|
5207
|
+
return {
|
|
5208
|
+
id: "host",
|
|
5209
|
+
job: null,
|
|
5210
|
+
async uploadWorkspace() {
|
|
5211
|
+
return {
|
|
5212
|
+
files: 0,
|
|
5213
|
+
bytes: 0,
|
|
5214
|
+
skipped: []
|
|
5215
|
+
};
|
|
5216
|
+
},
|
|
5217
|
+
async downloadWorkspace() {
|
|
5218
|
+
return {
|
|
5219
|
+
files: 0,
|
|
5220
|
+
bytes: 0,
|
|
5221
|
+
conflicts: []
|
|
5222
|
+
};
|
|
5223
|
+
},
|
|
5224
|
+
exec(spec) {
|
|
5225
|
+
return createHostRunner().exec(spec);
|
|
5226
|
+
},
|
|
5227
|
+
async detach() {
|
|
5228
|
+
throw new Error("host runtime does not support detach because host has no addressable env");
|
|
5229
|
+
},
|
|
5230
|
+
shell() {
|
|
5231
|
+
const shellSpec = openSpec.shellSpec;
|
|
5232
|
+
return createHostRunner().exec({
|
|
5233
|
+
command: shellSpec?.command ?? openSpec.env.SHELL ?? process.env.SHELL ?? "sh",
|
|
5234
|
+
...shellSpec?.args ? { args: shellSpec.args } : {},
|
|
5235
|
+
cwd: openSpec.cwd,
|
|
5236
|
+
env: shellSpec && "env" in shellSpec ? shellSpec.env : openSpec.env,
|
|
5237
|
+
stdin: "inherit",
|
|
5238
|
+
stdout: "inherit",
|
|
5239
|
+
stderr: "inherit",
|
|
5240
|
+
tty: true
|
|
5241
|
+
});
|
|
5242
|
+
},
|
|
5243
|
+
async close() {
|
|
5244
|
+
}
|
|
5245
|
+
};
|
|
5246
|
+
},
|
|
5247
|
+
async attach() {
|
|
5248
|
+
throw new Error("host runtime does not support reattach");
|
|
5249
|
+
}
|
|
5250
|
+
};
|
|
5251
|
+
|
|
5252
|
+
// packages/process-runner/src/testing/mock-runner.ts
|
|
5253
|
+
import { Readable, Writable } from "node:stream";
|
|
5254
|
+
|
|
5255
|
+
// packages/agent-spawn/src/register-factories.ts
|
|
5256
|
+
registerExecutionEnvFactory(hostExecutionEnvFactory);
|
|
5257
|
+
registerExecutionEnvFactory(dockerExecutionEnvFactory);
|
|
5258
|
+
if (process.env.VITEST === "true") {
|
|
5259
|
+
registerExecutionEnvFactory(createTestHostExecutionEnvFactory());
|
|
3208
5260
|
}
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
5261
|
+
function createTestHostExecutionEnvFactory() {
|
|
5262
|
+
return {
|
|
5263
|
+
type: "host",
|
|
5264
|
+
supportsDetach: false,
|
|
5265
|
+
open: ((openSpec) => {
|
|
5266
|
+
return {
|
|
5267
|
+
id: "host",
|
|
5268
|
+
job: null,
|
|
5269
|
+
async uploadWorkspace() {
|
|
5270
|
+
return { files: 0, bytes: 0, skipped: [] };
|
|
5271
|
+
},
|
|
5272
|
+
async downloadWorkspace() {
|
|
5273
|
+
return { files: 0, bytes: 0, conflicts: [] };
|
|
5274
|
+
},
|
|
5275
|
+
exec(spec) {
|
|
5276
|
+
return runHost(spawnChildProcess2, spec);
|
|
5277
|
+
},
|
|
5278
|
+
async detach() {
|
|
5279
|
+
throw new Error(
|
|
5280
|
+
"host runtime does not support detach because host has no addressable env"
|
|
5281
|
+
);
|
|
5282
|
+
},
|
|
5283
|
+
shell() {
|
|
5284
|
+
return runHost(spawnChildProcess2, {
|
|
5285
|
+
command: openSpec.shellSpec?.command ?? openSpec.env.SHELL ?? process.env.SHELL ?? "sh",
|
|
5286
|
+
args: openSpec.shellSpec?.args,
|
|
5287
|
+
cwd: openSpec.cwd,
|
|
5288
|
+
env: openSpec.shellSpec && "env" in openSpec.shellSpec ? openSpec.shellSpec.env : openSpec.env,
|
|
5289
|
+
stdin: "inherit",
|
|
5290
|
+
stdout: "inherit",
|
|
5291
|
+
stderr: "inherit",
|
|
5292
|
+
tty: true
|
|
5293
|
+
});
|
|
5294
|
+
},
|
|
5295
|
+
async close() {
|
|
5296
|
+
}
|
|
5297
|
+
};
|
|
5298
|
+
}),
|
|
5299
|
+
async attach() {
|
|
5300
|
+
throw new Error("host runtime does not support reattach");
|
|
5301
|
+
}
|
|
5302
|
+
};
|
|
3217
5303
|
}
|
|
3218
|
-
function
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
const
|
|
3223
|
-
|
|
3224
|
-
|
|
5304
|
+
function runHost(spawnProcess, spec) {
|
|
5305
|
+
const stdin = spec.stdin ?? "ignore";
|
|
5306
|
+
const stdout = spec.stdout ?? "pipe";
|
|
5307
|
+
const stderr = spec.stderr ?? "pipe";
|
|
5308
|
+
const stdio = stdin === "inherit" && stdout === "inherit" && stderr === "inherit" ? "inherit" : [stdin, stdout, stderr];
|
|
5309
|
+
const child = spawnProcess(spec.command, spec.args ?? [], {
|
|
5310
|
+
cwd: spec.cwd,
|
|
5311
|
+
env: spec.env,
|
|
5312
|
+
stdio
|
|
5313
|
+
});
|
|
5314
|
+
const result = new Promise((resolve2) => {
|
|
5315
|
+
child.once("close", (code) => {
|
|
5316
|
+
resolve2({ exitCode: code ?? 1 });
|
|
5317
|
+
});
|
|
5318
|
+
child.once("error", () => {
|
|
5319
|
+
resolve2({ exitCode: 1 });
|
|
5320
|
+
});
|
|
5321
|
+
});
|
|
5322
|
+
const kill = (signal) => {
|
|
5323
|
+
child.kill(signal);
|
|
5324
|
+
};
|
|
5325
|
+
if (spec.signal?.aborted) {
|
|
5326
|
+
kill("SIGTERM");
|
|
5327
|
+
} else {
|
|
5328
|
+
spec.signal?.addEventListener("abort", () => kill("SIGTERM"), { once: true });
|
|
3225
5329
|
}
|
|
3226
|
-
return
|
|
5330
|
+
return {
|
|
5331
|
+
pid: child.pid ?? null,
|
|
5332
|
+
stdin: child.stdin,
|
|
5333
|
+
stdout: child.stdout,
|
|
5334
|
+
stderr: child.stderr,
|
|
5335
|
+
result,
|
|
5336
|
+
kill
|
|
5337
|
+
};
|
|
3227
5338
|
}
|
|
3228
5339
|
|
|
3229
|
-
// packages/memory/src/ingest.ts
|
|
3230
|
-
import * as fs11 from "node:fs/promises";
|
|
3231
|
-
import path26 from "node:path";
|
|
3232
|
-
|
|
3233
5340
|
// packages/agent-spawn/src/run-command.ts
|
|
3234
|
-
import { spawn } from "node:child_process";
|
|
5341
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
3235
5342
|
|
|
3236
5343
|
// packages/agent-spawn/src/types.ts
|
|
3237
5344
|
function resolveModeConfig(modeConfig) {
|
|
@@ -3244,145 +5351,6 @@ function resolveModeConfig(modeConfig) {
|
|
|
3244
5351
|
};
|
|
3245
5352
|
}
|
|
3246
5353
|
|
|
3247
|
-
// packages/agent-defs/src/agents/claude-code.ts
|
|
3248
|
-
var claudeCodeAgent = {
|
|
3249
|
-
id: "claude-code",
|
|
3250
|
-
name: "claude-code",
|
|
3251
|
-
label: "Claude Code",
|
|
3252
|
-
summary: "Configure Claude Code to route through Poe.",
|
|
3253
|
-
aliases: ["claude"],
|
|
3254
|
-
binaryName: "claude",
|
|
3255
|
-
configPath: "~/.claude/settings.json",
|
|
3256
|
-
branding: {
|
|
3257
|
-
colors: {
|
|
3258
|
-
dark: "#C15F3C",
|
|
3259
|
-
light: "#C15F3C"
|
|
3260
|
-
}
|
|
3261
|
-
}
|
|
3262
|
-
};
|
|
3263
|
-
|
|
3264
|
-
// packages/agent-defs/src/agents/claude-desktop.ts
|
|
3265
|
-
var claudeDesktopAgent = {
|
|
3266
|
-
id: "claude-desktop",
|
|
3267
|
-
name: "claude-desktop",
|
|
3268
|
-
label: "Claude Desktop",
|
|
3269
|
-
summary: "Anthropic's official desktop application for Claude",
|
|
3270
|
-
configPath: "~/.claude/settings.json",
|
|
3271
|
-
branding: {
|
|
3272
|
-
colors: {
|
|
3273
|
-
dark: "#D97757",
|
|
3274
|
-
light: "#D97757"
|
|
3275
|
-
}
|
|
3276
|
-
}
|
|
3277
|
-
};
|
|
3278
|
-
|
|
3279
|
-
// packages/agent-defs/src/agents/codex.ts
|
|
3280
|
-
var codexAgent = {
|
|
3281
|
-
id: "codex",
|
|
3282
|
-
name: "codex",
|
|
3283
|
-
label: "Codex",
|
|
3284
|
-
summary: "Configure Codex to use Poe as the model provider.",
|
|
3285
|
-
binaryName: "codex",
|
|
3286
|
-
configPath: "~/.codex/config.toml",
|
|
3287
|
-
branding: {
|
|
3288
|
-
colors: {
|
|
3289
|
-
dark: "#D5D9DF",
|
|
3290
|
-
light: "#7A7F86"
|
|
3291
|
-
}
|
|
3292
|
-
}
|
|
3293
|
-
};
|
|
3294
|
-
|
|
3295
|
-
// packages/agent-defs/src/agents/opencode.ts
|
|
3296
|
-
var openCodeAgent = {
|
|
3297
|
-
id: "opencode",
|
|
3298
|
-
name: "opencode",
|
|
3299
|
-
label: "OpenCode CLI",
|
|
3300
|
-
summary: "Configure OpenCode CLI to use the Poe API.",
|
|
3301
|
-
binaryName: "opencode",
|
|
3302
|
-
configPath: "~/.config/opencode/config.json",
|
|
3303
|
-
branding: {
|
|
3304
|
-
colors: {
|
|
3305
|
-
dark: "#4A4F55",
|
|
3306
|
-
light: "#2F3338"
|
|
3307
|
-
}
|
|
3308
|
-
}
|
|
3309
|
-
};
|
|
3310
|
-
|
|
3311
|
-
// packages/agent-defs/src/agents/kimi.ts
|
|
3312
|
-
var kimiAgent = {
|
|
3313
|
-
id: "kimi",
|
|
3314
|
-
name: "kimi",
|
|
3315
|
-
label: "Kimi",
|
|
3316
|
-
summary: "Configure Kimi CLI to use Poe API",
|
|
3317
|
-
aliases: ["kimi-cli"],
|
|
3318
|
-
binaryName: "kimi",
|
|
3319
|
-
configPath: "~/.kimi/config.toml",
|
|
3320
|
-
branding: {
|
|
3321
|
-
colors: {
|
|
3322
|
-
dark: "#7B68EE",
|
|
3323
|
-
light: "#6A5ACD"
|
|
3324
|
-
}
|
|
3325
|
-
}
|
|
3326
|
-
};
|
|
3327
|
-
|
|
3328
|
-
// packages/agent-defs/src/agents/goose.ts
|
|
3329
|
-
var gooseAgent = {
|
|
3330
|
-
id: "goose",
|
|
3331
|
-
name: "goose",
|
|
3332
|
-
label: "Goose",
|
|
3333
|
-
summary: "Block's open-source AI agent with ACP support.",
|
|
3334
|
-
binaryName: "goose",
|
|
3335
|
-
configPath: "~/.config/goose/config.yaml",
|
|
3336
|
-
branding: {
|
|
3337
|
-
colors: {
|
|
3338
|
-
dark: "#FF6B35",
|
|
3339
|
-
light: "#E85D26"
|
|
3340
|
-
}
|
|
3341
|
-
}
|
|
3342
|
-
};
|
|
3343
|
-
|
|
3344
|
-
// packages/agent-defs/src/agents/poe-agent.ts
|
|
3345
|
-
var poeAgentAgent = {
|
|
3346
|
-
id: "poe-agent",
|
|
3347
|
-
name: "poe-agent",
|
|
3348
|
-
label: "Poe Agent",
|
|
3349
|
-
summary: "Run one-shot prompts with the built-in Poe agent runtime.",
|
|
3350
|
-
configPath: "~/.poe-code/config.json",
|
|
3351
|
-
branding: {
|
|
3352
|
-
colors: {
|
|
3353
|
-
dark: "#A465F7",
|
|
3354
|
-
light: "#7A3FD3"
|
|
3355
|
-
}
|
|
3356
|
-
}
|
|
3357
|
-
};
|
|
3358
|
-
|
|
3359
|
-
// packages/agent-defs/src/registry.ts
|
|
3360
|
-
var allAgents = [
|
|
3361
|
-
claudeCodeAgent,
|
|
3362
|
-
claudeDesktopAgent,
|
|
3363
|
-
codexAgent,
|
|
3364
|
-
openCodeAgent,
|
|
3365
|
-
kimiAgent,
|
|
3366
|
-
gooseAgent,
|
|
3367
|
-
poeAgentAgent
|
|
3368
|
-
];
|
|
3369
|
-
var lookup = /* @__PURE__ */ new Map();
|
|
3370
|
-
for (const agent of allAgents) {
|
|
3371
|
-
const values = [agent.id, agent.name, ...agent.aliases ?? []];
|
|
3372
|
-
for (const value of values) {
|
|
3373
|
-
const normalized = value.toLowerCase();
|
|
3374
|
-
if (!lookup.has(normalized)) {
|
|
3375
|
-
lookup.set(normalized, agent.id);
|
|
3376
|
-
}
|
|
3377
|
-
}
|
|
3378
|
-
}
|
|
3379
|
-
function resolveAgentId(input) {
|
|
3380
|
-
if (!input) {
|
|
3381
|
-
return void 0;
|
|
3382
|
-
}
|
|
3383
|
-
return lookup.get(input.toLowerCase());
|
|
3384
|
-
}
|
|
3385
|
-
|
|
3386
5354
|
// packages/agent-spawn/src/configs/mcp.ts
|
|
3387
5355
|
function toJsonMcpServers(servers) {
|
|
3388
5356
|
const out = {};
|
|
@@ -3650,9 +5618,8 @@ function listMcpSupportedAgents() {
|
|
|
3650
5618
|
}
|
|
3651
5619
|
|
|
3652
5620
|
// packages/agent-spawn/src/spawn.ts
|
|
3653
|
-
import { spawn as spawnChildProcess } from "node:child_process";
|
|
3654
5621
|
import { mkdirSync, openSync, writeSync, closeSync } from "node:fs";
|
|
3655
|
-
import
|
|
5622
|
+
import path27 from "node:path";
|
|
3656
5623
|
|
|
3657
5624
|
// packages/agent-spawn/src/configs/resolve-config.ts
|
|
3658
5625
|
function resolveConfig(agentId) {
|
|
@@ -3702,18 +5669,11 @@ function stripModelNamespace(model) {
|
|
|
3702
5669
|
}
|
|
3703
5670
|
|
|
3704
5671
|
// packages/agent-spawn/src/spawn.ts
|
|
3705
|
-
function
|
|
5672
|
+
function createAbortError3() {
|
|
3706
5673
|
const error2 = new Error("Agent spawn aborted");
|
|
3707
5674
|
error2.name = "AbortError";
|
|
3708
5675
|
return error2;
|
|
3709
5676
|
}
|
|
3710
|
-
function createActivityTimeoutError(timeoutMs) {
|
|
3711
|
-
const error2 = new Error(
|
|
3712
|
-
`Agent spawn timed out after ${timeoutMs / 1e3}s of inactivity`
|
|
3713
|
-
);
|
|
3714
|
-
error2.name = "ActivityTimeoutError";
|
|
3715
|
-
return error2;
|
|
3716
|
-
}
|
|
3717
5677
|
function resolveCliConfig(agentId) {
|
|
3718
5678
|
const resolved = resolveConfig(agentId);
|
|
3719
5679
|
if (!resolved.spawnConfig) {
|
|
@@ -3781,9 +5741,9 @@ function buildCliArgs(config, options, stdinMode) {
|
|
|
3781
5741
|
}
|
|
3782
5742
|
return { args, env: mode.env };
|
|
3783
5743
|
}
|
|
3784
|
-
async function
|
|
5744
|
+
async function spawn3(agentId, options, context) {
|
|
3785
5745
|
if (options.signal?.aborted) {
|
|
3786
|
-
throw
|
|
5746
|
+
throw createAbortError3();
|
|
3787
5747
|
}
|
|
3788
5748
|
const { agentId: resolvedId, binaryName, spawnConfig } = resolveCliConfig(agentId);
|
|
3789
5749
|
const stdinMode = options.useStdin && spawnConfig.stdinMode ? spawnConfig.stdinMode : void 0;
|
|
@@ -3795,89 +5755,68 @@ async function spawn2(agentId, options, context) {
|
|
|
3795
5755
|
}
|
|
3796
5756
|
const logFilePath = resolveSpawnLogPath(options);
|
|
3797
5757
|
const logFd = logFilePath ? openSpawnLog(logFilePath) : void 0;
|
|
3798
|
-
const
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
}
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
child.kill("SIGTERM");
|
|
3832
|
-
}, options.activityTimeoutMs);
|
|
3833
|
-
} : void 0;
|
|
3834
|
-
resetActivityTimer?.();
|
|
3835
|
-
const cleanup = () => {
|
|
3836
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
3837
|
-
if (activityTimer) clearTimeout(activityTimer);
|
|
3838
|
-
};
|
|
3839
|
-
stdoutStream.setEncoding("utf8");
|
|
3840
|
-
stdoutStream.on("data", (chunk) => {
|
|
3841
|
-
stdout += chunk;
|
|
3842
|
-
resetActivityTimer?.();
|
|
3843
|
-
if (options.tee?.stdout) options.tee.stdout.write(chunk);
|
|
3844
|
-
appendSpawnLog(logFd, chunk);
|
|
3845
|
-
});
|
|
3846
|
-
stderrStream.setEncoding("utf8");
|
|
3847
|
-
stderrStream.on("data", (chunk) => {
|
|
3848
|
-
stderr += chunk;
|
|
3849
|
-
resetActivityTimer?.();
|
|
3850
|
-
if (options.tee?.stderr) options.tee.stderr.write(chunk);
|
|
3851
|
-
appendSpawnLog(logFd, chunk);
|
|
3852
|
-
});
|
|
3853
|
-
child.on("error", (error2) => {
|
|
3854
|
-
cleanup();
|
|
3855
|
-
closeSpawnLog(logFd);
|
|
3856
|
-
if (aborted) {
|
|
3857
|
-
reject(createAbortError());
|
|
3858
|
-
return;
|
|
5758
|
+
const processEnv = modeEnv ? { ...process.env, ...modeEnv } : void 0;
|
|
5759
|
+
const argv = [binaryName, ...spawnArgs];
|
|
5760
|
+
const execution = resolvePoeCommandExecution({
|
|
5761
|
+
cwd: options.cwd ?? process.cwd(),
|
|
5762
|
+
env: processEnv ?? process.env,
|
|
5763
|
+
argv,
|
|
5764
|
+
tool: resolvedId,
|
|
5765
|
+
runtime: {
|
|
5766
|
+
runtime: options.runtime,
|
|
5767
|
+
runtimeImage: options.runtimeImage,
|
|
5768
|
+
runtimeTemplate: options.runtimeTemplate,
|
|
5769
|
+
detach: options.detach,
|
|
5770
|
+
mountPoeCode: options.mountPoeCode
|
|
5771
|
+
},
|
|
5772
|
+
context,
|
|
5773
|
+
openSpec: {
|
|
5774
|
+
execution: {
|
|
5775
|
+
wrapForLogTee: false,
|
|
5776
|
+
stdin: stdinMode ? "pipe" : "inherit",
|
|
5777
|
+
stdout: "pipe",
|
|
5778
|
+
stderr: "pipe",
|
|
5779
|
+
env: processEnv,
|
|
5780
|
+
input: stdinMode ? options.prompt : void 0,
|
|
5781
|
+
captureOutput: true,
|
|
5782
|
+
activityTimeoutMs: options.activityTimeoutMs,
|
|
5783
|
+
onStdout(chunk) {
|
|
5784
|
+
options.tee?.stdout?.write(chunk);
|
|
5785
|
+
appendSpawnLog(logFd, chunk);
|
|
5786
|
+
},
|
|
5787
|
+
onStderr(chunk) {
|
|
5788
|
+
options.tee?.stderr?.write(chunk);
|
|
5789
|
+
appendSpawnLog(logFd, chunk);
|
|
5790
|
+
}
|
|
3859
5791
|
}
|
|
3860
|
-
|
|
5792
|
+
}
|
|
5793
|
+
});
|
|
5794
|
+
try {
|
|
5795
|
+
const result = await runPoeCommand({
|
|
5796
|
+
factory: execution.factory,
|
|
5797
|
+
openSpec: execution.openSpec,
|
|
5798
|
+
detach: execution.detach,
|
|
5799
|
+
state: execution.state,
|
|
5800
|
+
signal: options.signal
|
|
3861
5801
|
});
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
return;
|
|
3868
|
-
}
|
|
3869
|
-
if (timedOut) {
|
|
3870
|
-
reject(createActivityTimeoutError(options.activityTimeoutMs));
|
|
3871
|
-
return;
|
|
3872
|
-
}
|
|
3873
|
-
resolve2({
|
|
3874
|
-
stdout,
|
|
3875
|
-
stderr,
|
|
3876
|
-
exitCode: code ?? 1,
|
|
5802
|
+
if (result.kind === "detached") {
|
|
5803
|
+
return {
|
|
5804
|
+
stdout: "",
|
|
5805
|
+
stderr: "",
|
|
5806
|
+
exitCode: 0,
|
|
3877
5807
|
...logFilePath ? { logFile: logFilePath } : {}
|
|
3878
|
-
}
|
|
3879
|
-
}
|
|
3880
|
-
|
|
5808
|
+
};
|
|
5809
|
+
}
|
|
5810
|
+
const captured = result;
|
|
5811
|
+
return {
|
|
5812
|
+
stdout: captured.stdout ?? "",
|
|
5813
|
+
stderr: captured.stderr ?? "",
|
|
5814
|
+
exitCode: result.exitCode,
|
|
5815
|
+
...logFilePath ? { logFile: logFilePath } : {}
|
|
5816
|
+
};
|
|
5817
|
+
} finally {
|
|
5818
|
+
closeSpawnLog(logFd);
|
|
5819
|
+
}
|
|
3881
5820
|
}
|
|
3882
5821
|
function resolveSpawnLogPath(options) {
|
|
3883
5822
|
if (options.logPath) {
|
|
@@ -3886,11 +5825,11 @@ function resolveSpawnLogPath(options) {
|
|
|
3886
5825
|
if (!options.logDir || !options.logFileName) {
|
|
3887
5826
|
return void 0;
|
|
3888
5827
|
}
|
|
3889
|
-
return
|
|
5828
|
+
return path27.join(options.logDir, options.logFileName);
|
|
3890
5829
|
}
|
|
3891
5830
|
function openSpawnLog(filePath) {
|
|
3892
5831
|
try {
|
|
3893
|
-
mkdirSync(
|
|
5832
|
+
mkdirSync(path27.dirname(filePath), { recursive: true });
|
|
3894
5833
|
return openSync(filePath, "a");
|
|
3895
5834
|
} catch {
|
|
3896
5835
|
return void 0;
|
|
@@ -3911,9 +5850,6 @@ function closeSpawnLog(fd) {
|
|
|
3911
5850
|
}
|
|
3912
5851
|
}
|
|
3913
5852
|
|
|
3914
|
-
// packages/agent-spawn/src/spawn-interactive.ts
|
|
3915
|
-
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
3916
|
-
|
|
3917
5853
|
// packages/design-system/src/tokens/colors.ts
|
|
3918
5854
|
import chalk from "chalk";
|
|
3919
5855
|
var dark = {
|
|
@@ -4321,7 +6257,7 @@ import chalk16 from "chalk";
|
|
|
4321
6257
|
var DEFAULT_ACTIVITY_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
4322
6258
|
|
|
4323
6259
|
// packages/agent-spawn/src/acp/replay.ts
|
|
4324
|
-
import
|
|
6260
|
+
import path28 from "node:path";
|
|
4325
6261
|
import { homedir as homedir2 } from "node:os";
|
|
4326
6262
|
import { open as open2, readdir as readdir4 } from "node:fs/promises";
|
|
4327
6263
|
import { createInterface } from "node:readline";
|
|
@@ -4339,17 +6275,14 @@ import * as fsPromises3 from "node:fs/promises";
|
|
|
4339
6275
|
import { homedir } from "node:os";
|
|
4340
6276
|
import { join } from "node:path";
|
|
4341
6277
|
|
|
4342
|
-
// packages/agent-spawn/src/acp/spawn.ts
|
|
4343
|
-
import { spawn as spawnChildProcess4 } from "node:child_process";
|
|
4344
|
-
|
|
4345
6278
|
// packages/agent-spawn/src/acp/middlewares/spawn-log.ts
|
|
4346
|
-
import
|
|
6279
|
+
import path29 from "node:path";
|
|
4347
6280
|
import { homedir as homedir3 } from "node:os";
|
|
4348
6281
|
import { mkdir as mkdir5, open as open3 } from "node:fs/promises";
|
|
4349
6282
|
|
|
4350
6283
|
// packages/memory/src/tokens.ts
|
|
4351
6284
|
import * as fs10 from "node:fs/promises";
|
|
4352
|
-
import
|
|
6285
|
+
import path30 from "node:path";
|
|
4353
6286
|
|
|
4354
6287
|
// packages/tokenfill/dist/tokenizer.js
|
|
4355
6288
|
import { get_encoding } from "tiktoken";
|
|
@@ -4390,7 +6323,7 @@ function countTokens(text4) {
|
|
|
4390
6323
|
}
|
|
4391
6324
|
|
|
4392
6325
|
// packages/tokenfill/dist/corpus.js
|
|
4393
|
-
import { readdirSync, readFileSync } from "node:fs";
|
|
6326
|
+
import { readdirSync, readFileSync as readFileSync2 } from "node:fs";
|
|
4394
6327
|
import { dirname, join as join2 } from "node:path";
|
|
4395
6328
|
import { fileURLToPath } from "node:url";
|
|
4396
6329
|
var CORPUS_ARTICLE_SEPARATOR = "\n\n";
|
|
@@ -4403,7 +6336,7 @@ function loadBuiltInCorpusArticles() {
|
|
|
4403
6336
|
if (corpusFileNames.length === 0) {
|
|
4404
6337
|
throw new Error(`No built-in corpus markdown files found in ${corpusDirectoryPath}`);
|
|
4405
6338
|
}
|
|
4406
|
-
return corpusFileNames.map((fileName) =>
|
|
6339
|
+
return corpusFileNames.map((fileName) => readFileSync2(join2(corpusDirectoryPath, fileName), "utf8").trim());
|
|
4407
6340
|
}
|
|
4408
6341
|
var BUILT_IN_CORPUS_ARTICLES = loadBuiltInCorpusArticles();
|
|
4409
6342
|
|
|
@@ -4433,11 +6366,11 @@ async function computeTokenStats(root) {
|
|
|
4433
6366
|
}
|
|
4434
6367
|
}
|
|
4435
6368
|
}
|
|
4436
|
-
const repoRoot =
|
|
6369
|
+
const repoRoot = path30.resolve(root, "..", "..");
|
|
4437
6370
|
let sourceTokens = 0;
|
|
4438
6371
|
const missingSources = [];
|
|
4439
6372
|
for (const sourcePath of sourcePaths) {
|
|
4440
|
-
const absPath =
|
|
6373
|
+
const absPath = path30.isAbsolute(sourcePath) ? sourcePath : path30.resolve(repoRoot, sourcePath);
|
|
4441
6374
|
try {
|
|
4442
6375
|
const content = await fs10.readFile(absPath, "utf8");
|
|
4443
6376
|
sourceTokens += countTokens(content);
|
|
@@ -4488,10 +6421,10 @@ function resolveRunners(overrides) {
|
|
|
4488
6421
|
async function ingest(root, opts, runners) {
|
|
4489
6422
|
const resolved = resolveRunners(runners);
|
|
4490
6423
|
const source = await materializeSource(opts.source);
|
|
4491
|
-
const indexMdBytes = await fs11.readFile(
|
|
6424
|
+
const indexMdBytes = await fs11.readFile(path31.join(root, MEMORY_INDEX_RELPATH));
|
|
4492
6425
|
const configOptions = {
|
|
4493
6426
|
fs: fs11,
|
|
4494
|
-
filePath:
|
|
6427
|
+
filePath: path31.join(inferRepoRoot(root), "poe-code.json")
|
|
4495
6428
|
};
|
|
4496
6429
|
const agentId = await resolveAgent(configOptions, opts.agent ?? null) ?? opts.agent ?? "claude-code";
|
|
4497
6430
|
const key = resolved.computeIngestKey({
|
|
@@ -4529,7 +6462,7 @@ async function ingest(root, opts, runners) {
|
|
|
4529
6462
|
let timeoutError;
|
|
4530
6463
|
try {
|
|
4531
6464
|
const result = await runWithTimeout(
|
|
4532
|
-
|
|
6465
|
+
spawn3(agentId, { prompt }),
|
|
4533
6466
|
opts.timeoutMs ?? await configuredTimeout(configOptions)
|
|
4534
6467
|
);
|
|
4535
6468
|
exitCode = result.exitCode;
|
|
@@ -4581,7 +6514,7 @@ async function materializeSource(source) {
|
|
|
4581
6514
|
throw new Error("URL ingest not implemented yet.");
|
|
4582
6515
|
}
|
|
4583
6516
|
function inferRepoRoot(root) {
|
|
4584
|
-
return
|
|
6517
|
+
return path31.resolve(root, "..", "..");
|
|
4585
6518
|
}
|
|
4586
6519
|
async function runWithTimeout(promise, timeoutMs) {
|
|
4587
6520
|
return await new Promise((resolve2, reject) => {
|
|
@@ -5339,8 +7272,8 @@ function printMcpConfig() {
|
|
|
5339
7272
|
}
|
|
5340
7273
|
|
|
5341
7274
|
// packages/agent-skill-config/src/configs.ts
|
|
5342
|
-
import
|
|
5343
|
-
import
|
|
7275
|
+
import os4 from "node:os";
|
|
7276
|
+
import path32 from "node:path";
|
|
5344
7277
|
var agentSkillConfigs = {
|
|
5345
7278
|
"claude-code": {
|
|
5346
7279
|
globalSkillDir: "~/.claude/skills",
|
|
@@ -5359,7 +7292,7 @@ var agentSkillConfigs = {
|
|
|
5359
7292
|
localSkillDir: ".agents/skills"
|
|
5360
7293
|
}
|
|
5361
7294
|
};
|
|
5362
|
-
var
|
|
7295
|
+
var supportedAgents2 = Object.keys(agentSkillConfigs);
|
|
5363
7296
|
function resolveAgentSupport(input, registry = agentSkillConfigs) {
|
|
5364
7297
|
const resolvedId = resolveAgentId(input);
|
|
5365
7298
|
if (!resolvedId) {
|
|
@@ -5373,8 +7306,8 @@ function resolveAgentSupport(input, registry = agentSkillConfigs) {
|
|
|
5373
7306
|
}
|
|
5374
7307
|
|
|
5375
7308
|
// packages/agent-skill-config/src/templates.ts
|
|
5376
|
-
import { readFile as
|
|
5377
|
-
import
|
|
7309
|
+
import { readFile as readFile13, stat as stat6 } from "node:fs/promises";
|
|
7310
|
+
import path33 from "node:path";
|
|
5378
7311
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
5379
7312
|
|
|
5380
7313
|
// packages/agent-skill-config/src/apply.ts
|
|
@@ -5480,7 +7413,7 @@ var agentMcpConfigs = {
|
|
|
5480
7413
|
shape: "goose"
|
|
5481
7414
|
}
|
|
5482
7415
|
};
|
|
5483
|
-
var
|
|
7416
|
+
var supportedAgents3 = Object.keys(agentMcpConfigs);
|
|
5484
7417
|
function resolveAgentSupport2(input, registry = agentMcpConfigs) {
|
|
5485
7418
|
const resolvedId = resolveAgentId(input);
|
|
5486
7419
|
if (!resolvedId) {
|
|
@@ -5507,7 +7440,7 @@ function resolveConfigPath2(config, platform) {
|
|
|
5507
7440
|
}
|
|
5508
7441
|
|
|
5509
7442
|
// packages/agent-mcp-config/src/apply.ts
|
|
5510
|
-
import
|
|
7443
|
+
import path34 from "node:path";
|
|
5511
7444
|
import { parse as parseYaml3, stringify as stringifyYaml2 } from "yaml";
|
|
5512
7445
|
|
|
5513
7446
|
// packages/agent-mcp-config/src/shapes.ts
|
|
@@ -5599,7 +7532,7 @@ function getShapeTransformer(shape) {
|
|
|
5599
7532
|
|
|
5600
7533
|
// packages/agent-mcp-config/src/apply.ts
|
|
5601
7534
|
function getConfigDirectory(configPath) {
|
|
5602
|
-
return
|
|
7535
|
+
return path34.dirname(configPath);
|
|
5603
7536
|
}
|
|
5604
7537
|
var UnsupportedAgentError2 = class extends Error {
|
|
5605
7538
|
constructor(agentId) {
|
|
@@ -5625,9 +7558,9 @@ function expandHomePath(configPath, homeDir) {
|
|
|
5625
7558
|
return homeDir;
|
|
5626
7559
|
}
|
|
5627
7560
|
if (configPath.startsWith("~/")) {
|
|
5628
|
-
return
|
|
7561
|
+
return path34.join(homeDir, configPath.slice(2));
|
|
5629
7562
|
}
|
|
5630
|
-
return
|
|
7563
|
+
return path34.join(homeDir, configPath.slice(1));
|
|
5631
7564
|
}
|
|
5632
7565
|
function parseYamlDocument(content) {
|
|
5633
7566
|
if (content.trim() === "") {
|
|
@@ -5660,7 +7593,7 @@ async function writeYamlConfig(configPath, document, options) {
|
|
|
5660
7593
|
return;
|
|
5661
7594
|
}
|
|
5662
7595
|
const absolutePath = expandHomePath(configPath, options.homeDir);
|
|
5663
|
-
const configDir =
|
|
7596
|
+
const configDir = path34.dirname(absolutePath);
|
|
5664
7597
|
await options.fs.mkdir(configDir, { recursive: true });
|
|
5665
7598
|
await options.fs.writeFile(absolutePath, serializeYamlDocument(document), {
|
|
5666
7599
|
encoding: "utf8"
|
|
@@ -5838,7 +7771,7 @@ async function installMemory(options) {
|
|
|
5838
7771
|
|
|
5839
7772
|
// packages/memory/src/query.ts
|
|
5840
7773
|
import * as fs12 from "node:fs/promises";
|
|
5841
|
-
import
|
|
7774
|
+
import path35 from "node:path";
|
|
5842
7775
|
async function queryMemory(root, options) {
|
|
5843
7776
|
const pages = await listPages(root);
|
|
5844
7777
|
if (pages.length === 0) {
|
|
@@ -5852,11 +7785,11 @@ async function queryMemory(root, options) {
|
|
|
5852
7785
|
}
|
|
5853
7786
|
const configOptions = {
|
|
5854
7787
|
fs: fs12,
|
|
5855
|
-
filePath:
|
|
7788
|
+
filePath: path35.join(inferRepoRoot2(root), "poe-code.json")
|
|
5856
7789
|
};
|
|
5857
7790
|
const agentId = await resolveAgent(configOptions, options.agent ?? null) ?? options.agent ?? "claude-code";
|
|
5858
7791
|
const context = await selectQueryContext(root, options.question, options.budget);
|
|
5859
|
-
const result = await
|
|
7792
|
+
const result = await spawn3(agentId, { prompt: context.prompt });
|
|
5860
7793
|
return {
|
|
5861
7794
|
answer: result.answer,
|
|
5862
7795
|
citations: result.citations,
|
|
@@ -5867,7 +7800,7 @@ async function queryMemory(root, options) {
|
|
|
5867
7800
|
}
|
|
5868
7801
|
async function selectQueryContext(root, question, budget) {
|
|
5869
7802
|
const [indexText, pages] = await Promise.all([
|
|
5870
|
-
fs12.readFile(
|
|
7803
|
+
fs12.readFile(path35.join(root, MEMORY_INDEX_RELPATH), "utf8"),
|
|
5871
7804
|
listPages(root)
|
|
5872
7805
|
]);
|
|
5873
7806
|
const indexTokens = countTokens(indexText);
|
|
@@ -5946,12 +7879,12 @@ function tokenize(text4) {
|
|
|
5946
7879
|
return text4.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length > 0);
|
|
5947
7880
|
}
|
|
5948
7881
|
function inferRepoRoot2(root) {
|
|
5949
|
-
return
|
|
7882
|
+
return path35.resolve(root, "..", "..");
|
|
5950
7883
|
}
|
|
5951
7884
|
|
|
5952
7885
|
// packages/memory/src/explain.ts
|
|
5953
7886
|
import * as fs13 from "node:fs/promises";
|
|
5954
|
-
import
|
|
7887
|
+
import path36 from "node:path";
|
|
5955
7888
|
async function explainPage(root, options) {
|
|
5956
7889
|
const targetPage = await readPageIfPresent(root, options.relPath);
|
|
5957
7890
|
if (targetPage === void 0) {
|
|
@@ -5974,10 +7907,10 @@ async function explainPage(root, options) {
|
|
|
5974
7907
|
}
|
|
5975
7908
|
const configOptions = {
|
|
5976
7909
|
fs: fs13,
|
|
5977
|
-
filePath:
|
|
7910
|
+
filePath: path36.join(inferRepoRoot3(root), "poe-code.json")
|
|
5978
7911
|
};
|
|
5979
7912
|
const agentId = await resolveAgent(configOptions, options.agent ?? null) ?? options.agent ?? "claude-code";
|
|
5980
|
-
const response = await
|
|
7913
|
+
const response = await spawn3(agentId, { prompt });
|
|
5981
7914
|
return {
|
|
5982
7915
|
answer: response.answer,
|
|
5983
7916
|
citations: response.citations,
|
|
@@ -6023,7 +7956,7 @@ async function readPageIfPresent(root, relPath) {
|
|
|
6023
7956
|
}
|
|
6024
7957
|
}
|
|
6025
7958
|
function inferRepoRoot3(root) {
|
|
6026
|
-
return
|
|
7959
|
+
return path36.resolve(root, "..", "..");
|
|
6027
7960
|
}
|
|
6028
7961
|
|
|
6029
7962
|
// packages/memory/src/explain.cli.ts
|
|
@@ -6036,9 +7969,9 @@ async function runMemoryExplain(input) {
|
|
|
6036
7969
|
}
|
|
6037
7970
|
|
|
6038
7971
|
// packages/memory/src/handle.ts
|
|
6039
|
-
import
|
|
7972
|
+
import path37 from "node:path";
|
|
6040
7973
|
function openMemory(opts) {
|
|
6041
|
-
if (!
|
|
7974
|
+
if (!path37.isAbsolute(opts.root)) {
|
|
6042
7975
|
throw new Error(`openMemory: root must be absolute, got ${opts.root}`);
|
|
6043
7976
|
}
|
|
6044
7977
|
const root = opts.root;
|