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.
Files changed (49) hide show
  1. package/dist/cli/commands/experiment.js +11 -4
  2. package/dist/cli/commands/experiment.js.map +1 -1
  3. package/dist/cli/commands/ralph.js +12 -5
  4. package/dist/cli/commands/ralph.js.map +1 -1
  5. package/dist/cli/commands/runtime-options.d.ts +10 -0
  6. package/dist/cli/commands/runtime-options.js +23 -0
  7. package/dist/cli/commands/runtime-options.js.map +1 -0
  8. package/dist/cli/commands/spawn.js +9 -3
  9. package/dist/cli/commands/spawn.js.map +1 -1
  10. package/dist/index.js +21873 -20138
  11. package/dist/index.js.map +4 -4
  12. package/dist/providers/claude-code.js +2741 -1706
  13. package/dist/providers/claude-code.js.map +4 -4
  14. package/dist/providers/codex.js +2770 -1735
  15. package/dist/providers/codex.js.map +4 -4
  16. package/dist/providers/goose.js +2640 -1605
  17. package/dist/providers/goose.js.map +4 -4
  18. package/dist/providers/kimi.js +2740 -1705
  19. package/dist/providers/kimi.js.map +4 -4
  20. package/dist/providers/opencode.js +2741 -1706
  21. package/dist/providers/opencode.js.map +4 -4
  22. package/dist/providers/poe-agent.js +19451 -17229
  23. package/dist/providers/poe-agent.js.map +4 -4
  24. package/dist/providers/spawn-options.d.ts +6 -0
  25. package/dist/sdk/experiment.js +5 -0
  26. package/dist/sdk/experiment.js.map +1 -1
  27. package/dist/sdk/ralph.js +5 -0
  28. package/dist/sdk/ralph.js.map +1 -1
  29. package/dist/sdk/spawn.js +17 -1
  30. package/dist/sdk/spawn.js.map +1 -1
  31. package/dist/sdk/types.d.ts +11 -0
  32. package/package.json +1 -1
  33. package/packages/memory/dist/index.js +2353 -420
  34. package/packages/memory/dist/index.js.map +4 -4
  35. package/packages/superintendent/dist/commands/run.d.ts +35 -0
  36. package/packages/superintendent/dist/commands/run.js +49 -1
  37. package/packages/superintendent/dist/commands/superintendent-group.d.ts +30 -0
  38. package/packages/superintendent/dist/runtime/agent-runner.d.ts +30 -0
  39. package/packages/superintendent/dist/runtime/agent-runner.js +119 -0
  40. package/packages/superintendent/dist/runtime/loop.d.ts +6 -1
  41. package/packages/superintendent/dist/runtime/loop.js +3 -11
  42. package/packages/superintendent/dist/runtime/run-builder.d.ts +1 -0
  43. package/packages/superintendent/dist/runtime/run-builder.js +3 -25
  44. package/packages/superintendent/dist/runtime/run-inspector.d.ts +1 -0
  45. package/packages/superintendent/dist/runtime/run-inspector.js +3 -25
  46. package/packages/superintendent/dist/runtime/run-owner-review.d.ts +1 -0
  47. package/packages/superintendent/dist/runtime/run-owner-review.js +3 -25
  48. package/packages/superintendent/dist/runtime/run-superintendent.d.ts +1 -0
  49. 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, path33) {
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, path33);
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, path33) {
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(path33, key);
601
+ const fullPath = buildPath(path38, key);
453
602
  if (isPlainObject(winningValue)) {
454
- const merged = mergeObjectLayers(objectLayers, [...path33, key]);
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(path33, key) {
480
- return [...path33, key].join(".");
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(path33) {
1115
- const ext = getExtension(path33);
1263
+ function detectFormat2(path38) {
1264
+ const ext = getExtension(path38);
1116
1265
  return extensionMap[ext];
1117
1266
  }
1118
- function getExtension(path33) {
1119
- const lastDot = path33.lastIndexOf(".");
1267
+ function getExtension(path38) {
1268
+ const lastDot = path38.lastIndexOf(".");
1120
1269
  if (lastDot === -1) {
1121
1270
  return "";
1122
1271
  }
1123
- return path33.slice(lastDot).toLowerCase();
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
- // packages/poe-code-config/src/state/fs.ts
1943
- import * as nodeFs from "node:fs/promises";
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
- const configOverride = (await configuredMemoryRoot({
1956
- fs: options.fs,
1957
- filePath: options.configPath,
1958
- projectFilePath: options.projectConfigPath
1959
- }))?.trim();
1960
- if (configOverride && configOverride.length > 0) {
1961
- return resolveAgainstCwd(options.cwd, configOverride);
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 resolveAgainstCwd(cwd, value) {
1966
- return path11.isAbsolute(value) ? value : path11.resolve(cwd, value);
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
- // packages/memory/src/init.ts
1970
- import * as fs from "node:fs/promises";
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
- async function writeFileIfMissing(filePath, content) {
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
- await fs.writeFile(filePath, content, { encoding: "utf8", flag: "wx" });
2280
+ process.kill(pid, 0);
2281
+ return true;
1980
2282
  } catch (error2) {
1981
- if (!hasErrorCode(error2, "EEXIST")) {
1982
- throw error2;
1983
- }
2283
+ return !hasErrorCode(error2, "ESRCH");
1984
2284
  }
1985
2285
  }
1986
- function hasErrorCode(error2, code) {
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
- frontmatter: parsePageFrontmatter(parseYamlFrontmatter(yamlBlock)),
2011
- body: readBody(content, bodyStart)
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 serializeFrontmatter(frontmatter, body) {
2015
- const serialized = {
2016
- ...frontmatter.name === void 0 ? {} : { name: frontmatter.name },
2017
- ...frontmatter.description === void 0 ? {} : { description: frontmatter.description },
2018
- ...frontmatter.lastTouchedAt === void 0 ? {} : { last_touched_at: frontmatter.lastTouchedAt },
2019
- ...frontmatter.sources === void 0 || frontmatter.sources.length === 0 ? {} : { sources: frontmatter.sources.map((source) => serializeSourceRef(source)) }
2020
- };
2021
- if (Object.keys(serialized).length === 0) {
2022
- return body;
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 parseSourceRef(serialized) {
2030
- const [rawPath, rawAnchor] = serialized.split("#", 2);
2031
- const normalizedPath = rawPath?.trim();
2032
- if (normalizedPath === void 0 || normalizedPath.length === 0) {
2033
- throw new Error(`Invalid source ref "${serialized}".`);
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
- if (rawAnchor === void 0) {
2036
- return { path: normalizedPath };
2327
+ return void 0;
2328
+ }
2329
+ async function readLockMetadata(fs14, lockPath) {
2330
+ if (!fs14.readFile) {
2331
+ return void 0;
2037
2332
  }
2038
- const singleLineMatch = /^L(\d+)$/.exec(rawAnchor);
2039
- if (singleLineMatch !== null) {
2040
- const startLine = Number.parseInt(singleLineMatch[1], 10);
2041
- assertValidLineNumber(startLine, serialized);
2042
- return {
2043
- path: normalizedPath,
2044
- startLine
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
- const rangeMatch = /^L(\d+)-L?(\d+)$/.exec(rawAnchor);
2048
- if (rangeMatch !== null) {
2049
- const startLine = Number.parseInt(rangeMatch[1], 10);
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 (!isRecord2(parsed)) {
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 (!isRecord2(item)) {
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 path33 = readRequiredString(item.path, "sources[].path");
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: path33, ...startLine === void 0 ? {} : { startLine }, ...endLine === void 0 ? {} : { endLine } }));
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 isRecord2(value) {
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 createDefaultFs() {
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 sleep(ms) {
3130
+ function sleep2(ms) {
2388
3131
  return new Promise((resolve2) => setTimeout(resolve2, ms));
2389
3132
  }
2390
- function hasErrorCode2(error2, code) {
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 isPidRunning(pid) {
3152
+ function isPidRunning2(pid) {
2410
3153
  try {
2411
3154
  process.kill(pid, 0);
2412
3155
  return true;
2413
3156
  } catch (error2) {
2414
- return !hasErrorCode2(error2, "ESRCH");
3157
+ return !hasErrorCode3(error2, "ESRCH");
2415
3158
  }
2416
3159
  }
2417
- async function removeLockFile(fs14, lockPath) {
3160
+ async function removeLockFile2(fs14, lockPath) {
2418
3161
  try {
2419
3162
  await fs14.unlink(lockPath);
2420
3163
  } catch (error2) {
2421
- if (!hasErrorCode2(error2, "ENOENT")) {
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 (hasErrorCode2(error2, "ENOENT")) {
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 ?? createDefaultFs();
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 ?? 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 removeLockFile(fs14, lockPath);
3194
+ await removeLockFile2(fs14, lockPath);
2452
3195
  }
2453
3196
  } catch (error2) {
2454
- if (!hasErrorCode2(error2, "EEXIST")) {
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 removeLockFile(fs14, lockPath);
3206
+ await removeLockFile2(fs14, lockPath);
2464
3207
  continue;
2465
3208
  }
2466
3209
  if (attempt < retries) {
2467
- await sleep(lockDelay(attempt, minTimeoutMs, maxTimeoutMs));
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
- async function runMemoryCacheClear(input) {
3210
- if (!input.yes) {
3211
- throw new Error("Refusing to clear cache without --yes.");
3212
- }
3213
- const olderThanMs = parseOlderThan(input.olderThan);
3214
- const result = await clearCache(input.root, olderThanMs === void 0 ? {} : { olderThanMs });
3215
- console.log(`removed ${result.removed} cache ${result.removed === 1 ? "entry" : "entries"}`);
3216
- return result;
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 parseOlderThan(value) {
3219
- if (value === void 0) {
3220
- return void 0;
3221
- }
3222
- const duration = parseDuration(value);
3223
- if (duration === null || Number.isNaN(duration) || duration < 0) {
3224
- throw new Error(`Invalid duration for --older-than: "${value}".`);
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 duration;
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 path22 from "node:path";
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 createAbortError() {
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 spawn2(agentId, options, context) {
5744
+ async function spawn3(agentId, options, context) {
3785
5745
  if (options.signal?.aborted) {
3786
- throw createAbortError();
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 child = spawnChildProcess(binaryName, spawnArgs, {
3799
- cwd: options.cwd,
3800
- stdio: [stdinMode ? "pipe" : "inherit", "pipe", "pipe"],
3801
- ...modeEnv ? { env: { ...process.env, ...modeEnv } } : {}
3802
- });
3803
- if (!child.stdout || !child.stderr) {
3804
- throw new Error(`Failed to spawn "${resolvedId}": missing stdio pipes.`);
3805
- }
3806
- const stdoutStream = child.stdout;
3807
- const stderrStream = child.stderr;
3808
- if (stdinMode) {
3809
- if (!child.stdin) {
3810
- throw new Error(`Failed to spawn "${resolvedId}": missing stdin pipe.`);
3811
- }
3812
- child.stdin.setDefaultEncoding("utf8");
3813
- child.stdin.write(options.prompt);
3814
- child.stdin.end();
3815
- }
3816
- return new Promise((resolve2, reject) => {
3817
- let stdout = "";
3818
- let stderr = "";
3819
- let aborted = false;
3820
- let timedOut = false;
3821
- const onAbort = () => {
3822
- aborted = true;
3823
- child.kill("SIGTERM");
3824
- };
3825
- options.signal?.addEventListener("abort", onAbort, { once: true });
3826
- let activityTimer;
3827
- const resetActivityTimer = options.activityTimeoutMs ? () => {
3828
- if (activityTimer) clearTimeout(activityTimer);
3829
- activityTimer = setTimeout(() => {
3830
- timedOut = true;
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
- reject(error2);
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
- child.on("close", (code) => {
3863
- cleanup();
3864
- closeSpawnLog(logFd);
3865
- if (aborted) {
3866
- reject(createAbortError());
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 path22.join(options.logDir, options.logFileName);
5828
+ return path27.join(options.logDir, options.logFileName);
3890
5829
  }
3891
5830
  function openSpawnLog(filePath) {
3892
5831
  try {
3893
- mkdirSync(path22.dirname(filePath), { recursive: true });
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 path23 from "node:path";
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 path24 from "node:path";
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 path25 from "node:path";
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) => readFileSync(join2(corpusDirectoryPath, fileName), "utf8").trim());
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 = path25.resolve(root, "..", "..");
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 = path25.isAbsolute(sourcePath) ? sourcePath : path25.resolve(repoRoot, sourcePath);
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(path26.join(root, MEMORY_INDEX_RELPATH));
6424
+ const indexMdBytes = await fs11.readFile(path31.join(root, MEMORY_INDEX_RELPATH));
4492
6425
  const configOptions = {
4493
6426
  fs: fs11,
4494
- filePath: path26.join(inferRepoRoot(root), "poe-code.json")
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
- spawn2(agentId, { prompt }),
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 path26.resolve(root, "..", "..");
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 os3 from "node:os";
5343
- import path27 from "node:path";
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 supportedAgents = Object.keys(agentSkillConfigs);
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 readFile12, stat as stat6 } from "node:fs/promises";
5377
- import path28 from "node:path";
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 supportedAgents2 = Object.keys(agentMcpConfigs);
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 path29 from "node:path";
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 path29.dirname(configPath);
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 path29.join(homeDir, configPath.slice(2));
7561
+ return path34.join(homeDir, configPath.slice(2));
5629
7562
  }
5630
- return path29.join(homeDir, configPath.slice(1));
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 = path29.dirname(absolutePath);
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 path30 from "node:path";
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: path30.join(inferRepoRoot2(root), "poe-code.json")
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 spawn2(agentId, { prompt: context.prompt });
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(path30.join(root, MEMORY_INDEX_RELPATH), "utf8"),
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 path30.resolve(root, "..", "..");
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 path31 from "node:path";
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: path31.join(inferRepoRoot3(root), "poe-code.json")
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 spawn2(agentId, { prompt });
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 path31.resolve(root, "..", "..");
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 path32 from "node:path";
7972
+ import path37 from "node:path";
6040
7973
  function openMemory(opts) {
6041
- if (!path32.isAbsolute(opts.root)) {
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;