poe-code 3.0.214 → 3.0.216

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.
@@ -611,11 +611,11 @@ function stripBom(content) {
611
611
  function mergeLayers(layers) {
612
612
  return mergeObjectLayers(layers, []);
613
613
  }
614
- function mergeObjectLayers(layers, path42) {
614
+ function mergeObjectLayers(layers, path45) {
615
615
  const data = {};
616
616
  const sources = {};
617
617
  for (const key of collectKeys(layers)) {
618
- const resolved = resolveKey(layers, key, path42);
618
+ const resolved = resolveKey(layers, key, path45);
619
619
  if (resolved === void 0) {
620
620
  continue;
621
621
  }
@@ -633,7 +633,7 @@ function collectKeys(layers) {
633
633
  }
634
634
  return [...keys];
635
635
  }
636
- function resolveKey(layers, key, path42) {
636
+ function resolveKey(layers, key, path45) {
637
637
  let winningSource;
638
638
  let winningValue;
639
639
  const objectLayers = [];
@@ -663,9 +663,9 @@ function resolveKey(layers, key, path42) {
663
663
  if (winningSource === void 0) {
664
664
  return void 0;
665
665
  }
666
- const fullPath = buildPath(path42, key);
666
+ const fullPath = buildPath(path45, key);
667
667
  if (isPlainObject(winningValue)) {
668
- const merged = mergeObjectLayers(objectLayers, [...path42, key]);
668
+ const merged = mergeObjectLayers(objectLayers, [...path45, key]);
669
669
  return {
670
670
  value: merged.data,
671
671
  sources: {
@@ -690,8 +690,8 @@ function isWinningCandidate(key, value) {
690
690
  }
691
691
  return true;
692
692
  }
693
- function buildPath(path42, key) {
694
- return [...path42, key].join(".");
693
+ function buildPath(path45, key) {
694
+ return [...path45, key].join(".");
695
695
  }
696
696
  function isPlainObject(value) {
697
697
  if (value === null || Array.isArray(value) || typeof value !== "object") {
@@ -1325,16 +1325,16 @@ function getConfigFormat(pathOrFormat) {
1325
1325
  }
1326
1326
  return formatRegistry[formatName];
1327
1327
  }
1328
- function detectFormat2(path42) {
1329
- const ext = getExtension(path42);
1328
+ function detectFormat2(path45) {
1329
+ const ext = getExtension(path45);
1330
1330
  return extensionMap[ext];
1331
1331
  }
1332
- function getExtension(path42) {
1333
- const lastDot = path42.lastIndexOf(".");
1332
+ function getExtension(path45) {
1333
+ const lastDot = path45.lastIndexOf(".");
1334
1334
  if (lastDot === -1) {
1335
1335
  return "";
1336
1336
  }
1337
- return path42.slice(lastDot).toLowerCase();
1337
+ return path45.slice(lastDot).toLowerCase();
1338
1338
  }
1339
1339
 
1340
1340
  // packages/config-mutations/src/execution/path-utils.ts
@@ -2204,7 +2204,7 @@ function mergeScope(scope, baseScope, overrideScope) {
2204
2204
  ...Object.fromEntries(scopeEntries)
2205
2205
  };
2206
2206
  }
2207
- function mergeRuntimeScope(baseScope, overrideScope, path42 = []) {
2207
+ function mergeRuntimeScope(baseScope, overrideScope, path45 = []) {
2208
2208
  const merged = {};
2209
2209
  const keys = /* @__PURE__ */ new Set([...Object.keys(baseScope), ...Object.keys(overrideScope)]);
2210
2210
  for (const key of keys) {
@@ -2216,20 +2216,20 @@ function mergeRuntimeScope(baseScope, overrideScope, path42 = []) {
2216
2216
  }
2217
2217
  continue;
2218
2218
  }
2219
- if (isRuntimeConcatenativeArray([...path42, key]) && Array.isArray(baseValue) && Array.isArray(overrideValue)) {
2219
+ if (isRuntimeConcatenativeArray([...path45, key]) && Array.isArray(baseValue) && Array.isArray(overrideValue)) {
2220
2220
  merged[key] = [...baseValue, ...overrideValue];
2221
2221
  continue;
2222
2222
  }
2223
2223
  if (isRecord3(baseValue) && isRecord3(overrideValue)) {
2224
- merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...path42, key]);
2224
+ merged[key] = mergeRuntimeScope(baseValue, overrideValue, [...path45, key]);
2225
2225
  continue;
2226
2226
  }
2227
2227
  merged[key] = overrideValue;
2228
2228
  }
2229
2229
  return merged;
2230
2230
  }
2231
- function isRuntimeConcatenativeArray(path42) {
2232
- return path42.join(".") === "mounts" || path42.join(".") === "runner.workspace.exclude";
2231
+ function isRuntimeConcatenativeArray(path45) {
2232
+ return path45.join(".") === "mounts" || path45.join(".") === "runner.workspace.exclude";
2233
2233
  }
2234
2234
  function isRecord3(value) {
2235
2235
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
@@ -2350,8 +2350,8 @@ function isPidRunning(pid) {
2350
2350
  }
2351
2351
  function createDefaultFs() {
2352
2352
  return {
2353
- open: (path42, flags) => fsPromises.open(path42, flags),
2354
- readFile: (path42, encoding) => fsPromises.readFile(path42, encoding),
2353
+ open: (path45, flags) => fsPromises.open(path45, flags),
2354
+ readFile: (path45, encoding) => fsPromises.readFile(path45, encoding),
2355
2355
  stat: fsPromises.stat,
2356
2356
  unlink: fsPromises.unlink
2357
2357
  };
@@ -2977,10 +2977,10 @@ function parseSources(value) {
2977
2977
  if (!isRecord6(item)) {
2978
2978
  throw new Error('Invalid "sources" frontmatter. Expected each source to be a string or object.');
2979
2979
  }
2980
- const path42 = readRequiredString(item.path, "sources[].path");
2980
+ const path45 = readRequiredString(item.path, "sources[].path");
2981
2981
  const startLine = readOptionalPositiveInteger(item.startLine, "sources[].startLine");
2982
2982
  const endLine = readOptionalPositiveInteger(item.endLine, "sources[].endLine");
2983
- return parseSourceRef(serializeSourceRef({ path: path42, ...startLine === void 0 ? {} : { startLine }, ...endLine === void 0 ? {} : { endLine } }));
2983
+ return parseSourceRef(serializeSourceRef({ path: path45, ...startLine === void 0 ? {} : { startLine }, ...endLine === void 0 ? {} : { endLine } }));
2984
2984
  });
2985
2985
  }
2986
2986
  function readOptionalString(value, field) {
@@ -4036,7 +4036,7 @@ function parseOlderThan(value) {
4036
4036
 
4037
4037
  // packages/memory/src/ingest.ts
4038
4038
  import * as fs11 from "node:fs/promises";
4039
- import path35 from "node:path";
4039
+ import path38 from "node:path";
4040
4040
 
4041
4041
  // packages/agent-spawn/src/register-factories.ts
4042
4042
  import { spawn as spawnChildProcess2 } from "node:child_process";
@@ -4044,1533 +4044,1676 @@ import { spawn as spawnChildProcess2 } from "node:child_process";
4044
4044
  // packages/agent-harness-tools/src/paths.ts
4045
4045
  import path22 from "node:path";
4046
4046
 
4047
- // packages/agent-defs/src/agents/claude-code.ts
4048
- var claudeCodeAgent = {
4049
- id: "claude-code",
4050
- name: "claude-code",
4051
- label: "Claude Code",
4052
- summary: "Configure Claude Code to route through Poe.",
4053
- aliases: ["claude"],
4054
- binaryName: "claude",
4055
- configPath: "~/.claude/settings.json",
4056
- branding: {
4057
- colors: {
4058
- dark: "#C15F3C",
4059
- light: "#C15F3C"
4060
- }
4061
- }
4062
- };
4047
+ // packages/agent-harness-tools/src/plans.ts
4048
+ import * as fsPromises4 from "node:fs/promises";
4049
+ import path27 from "node:path";
4063
4050
 
4064
- // packages/agent-defs/src/agents/claude-desktop.ts
4065
- var claudeDesktopAgent = {
4066
- id: "claude-desktop",
4067
- name: "claude-desktop",
4068
- label: "Claude Desktop",
4069
- summary: "Anthropic's official desktop application for Claude",
4070
- configPath: "~/.claude/settings.json",
4071
- branding: {
4072
- colors: {
4073
- dark: "#D97757",
4074
- light: "#D97757"
4075
- }
4076
- }
4077
- };
4051
+ // packages/task-list/src/open.ts
4052
+ import * as fsPromises3 from "node:fs/promises";
4078
4053
 
4079
- // packages/agent-defs/src/agents/codex.ts
4080
- var codexAgent = {
4081
- id: "codex",
4082
- name: "codex",
4083
- label: "Codex",
4084
- summary: "Configure Codex to use Poe as the model provider.",
4085
- binaryName: "codex",
4086
- configPath: "~/.codex/config.toml",
4087
- branding: {
4088
- colors: {
4089
- dark: "#D5D9DF",
4090
- light: "#7A7F86"
4091
- }
4054
+ // packages/task-list/src/state-machine.ts
4055
+ function canFireFromState(event, fromState) {
4056
+ if (event.from === "*") {
4057
+ return event.to !== fromState;
4092
4058
  }
4093
- };
4094
-
4095
- // packages/agent-defs/src/agents/opencode.ts
4096
- var openCodeAgent = {
4097
- id: "opencode",
4098
- name: "opencode",
4099
- label: "OpenCode CLI",
4100
- summary: "Configure OpenCode CLI to use the Poe API.",
4101
- binaryName: "opencode",
4102
- configPath: "~/.config/opencode/config.json",
4103
- branding: {
4104
- colors: {
4105
- dark: "#4A4F55",
4106
- light: "#2F3338"
4107
- }
4059
+ return event.from.includes(fromState);
4060
+ }
4061
+ function findEvent(machine, fromState, eventName) {
4062
+ const event = machine.events[eventName];
4063
+ if (event === void 0) {
4064
+ return void 0;
4108
4065
  }
4109
- };
4066
+ return canFireFromState(event, fromState) ? event : void 0;
4067
+ }
4110
4068
 
4111
- // packages/agent-defs/src/agents/kimi.ts
4112
- var kimiAgent = {
4113
- id: "kimi",
4114
- name: "kimi",
4115
- label: "Kimi",
4116
- summary: "Configure Kimi CLI to use Poe API",
4117
- aliases: ["kimi-cli"],
4118
- binaryName: "kimi",
4119
- configPath: "~/.kimi/config.toml",
4120
- branding: {
4121
- colors: {
4122
- dark: "#7B68EE",
4123
- light: "#6A5ACD"
4124
- }
4125
- }
4126
- };
4069
+ // packages/task-list/src/backends/gh-issues-client.ts
4070
+ import { text } from "node:stream/consumers";
4127
4071
 
4128
- // packages/agent-defs/src/agents/goose.ts
4129
- var gooseAgent = {
4130
- id: "goose",
4131
- name: "goose",
4132
- label: "Goose",
4133
- summary: "Block's open-source AI agent with ACP support.",
4134
- binaryName: "goose",
4135
- configPath: "~/.config/goose/config.yaml",
4136
- branding: {
4137
- colors: {
4138
- dark: "#FF6B35",
4139
- light: "#E85D26"
4072
+ // packages/process-runner/src/docker/context.ts
4073
+ import { execSync } from "node:child_process";
4074
+ function detectContext() {
4075
+ try {
4076
+ const output = execSync("colima list --json", {
4077
+ encoding: "utf-8",
4078
+ stdio: ["pipe", "pipe", "ignore"]
4079
+ });
4080
+ const lines = output.trim().split("\n").filter(Boolean);
4081
+ for (const line of lines) {
4082
+ const profile = JSON.parse(line);
4083
+ if (profile.status === "Running" && profile.runtime === "docker") {
4084
+ const name = profile.name ?? profile.profile;
4085
+ if (!name) {
4086
+ continue;
4087
+ }
4088
+ return name === "default" ? "colima" : `colima-${name}`;
4089
+ }
4140
4090
  }
4091
+ } catch {
4092
+ return null;
4141
4093
  }
4142
- };
4143
-
4144
- // packages/agent-defs/src/agents/poe-agent.ts
4145
- var poeAgentAgent = {
4146
- id: "poe-agent",
4147
- name: "poe-agent",
4148
- label: "Poe Agent",
4149
- summary: "Run one-shot prompts with the built-in Poe agent runtime.",
4150
- configPath: "~/.poe-code/config.json",
4151
- branding: {
4152
- colors: {
4153
- dark: "#A465F7",
4154
- light: "#7A3FD3"
4155
- }
4094
+ return null;
4095
+ }
4096
+ function buildContextArgs(engine, context) {
4097
+ if (engine === "docker" && context) {
4098
+ return ["--context", context];
4156
4099
  }
4157
- };
4100
+ return [];
4101
+ }
4158
4102
 
4159
- // packages/agent-defs/src/registry.ts
4160
- var allAgents = [
4161
- claudeCodeAgent,
4162
- claudeDesktopAgent,
4163
- codexAgent,
4164
- openCodeAgent,
4165
- kimiAgent,
4166
- gooseAgent,
4167
- poeAgentAgent
4168
- ];
4169
- var lookup = /* @__PURE__ */ new Map();
4170
- for (const agent of allAgents) {
4171
- const values = [agent.id, agent.name, ...agent.aliases ?? []];
4172
- for (const value of values) {
4173
- const normalized = value.toLowerCase();
4174
- if (!lookup.has(normalized)) {
4175
- lookup.set(normalized, agent.id);
4176
- }
4103
+ // packages/process-runner/src/docker/engine.ts
4104
+ import { execSync as execSync2 } from "node:child_process";
4105
+ function detectEngine() {
4106
+ if (isEngineAvailable("docker")) {
4107
+ return "docker";
4108
+ }
4109
+ if (isEngineAvailable("podman")) {
4110
+ return "podman";
4177
4111
  }
4112
+ throw new Error(
4113
+ "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"
4114
+ );
4178
4115
  }
4179
- function resolveAgentId(input) {
4180
- if (!input) {
4181
- return void 0;
4116
+ function isEngineAvailable(engine) {
4117
+ try {
4118
+ execSync2(`${engine} --version`, {
4119
+ stdio: "ignore"
4120
+ });
4121
+ return true;
4122
+ } catch {
4123
+ return false;
4182
4124
  }
4183
- return lookup.get(input.toLowerCase());
4184
4125
  }
4185
4126
 
4186
- // packages/agent-harness-tools/src/select-agent.ts
4187
- var loopAgents = allAgents.filter(
4188
- (agent) => agent.binaryName !== void 0 || agent.id === "poe-agent"
4189
- );
4190
- var supportedAgents = loopAgents.map((agent) => agent.id).join(", ");
4127
+ // packages/process-runner/src/docker/docker-runner.ts
4128
+ import * as childProcess from "node:child_process";
4129
+ import { randomBytes } from "node:crypto";
4191
4130
 
4192
- // packages/agent-harness-tools/src/run-logs.ts
4131
+ // packages/process-runner/src/docker/args.ts
4193
4132
  import path23 from "node:path";
4194
-
4195
- // packages/agent-harness-tools/src/log-stream.ts
4196
- import nodeFs2 from "node:fs";
4197
- var JOB_DIR = "/tmp/poe-jobs";
4198
- var POLL_INTERVAL_MS = 250;
4199
- function wrapForLogTee(argv, jobId) {
4200
- if (argv.length === 0) {
4201
- throw new Error("wrapForLogTee requires argv to contain at least one argument");
4133
+ function buildDockerRunArgs(input) {
4134
+ const args = [input.engine];
4135
+ if (input.engine === "docker" && input.context) {
4136
+ args.push("--context", input.context);
4202
4137
  }
4203
- const command = argv.map(shellQuote).join(" ");
4204
- const logFile = shellQuote(jobLogPath(jobId));
4205
- const exitFile = shellQuote(jobExitPath(jobId));
4206
- const exitTmpFile = shellQuote(`${jobExitPath(jobId)}.tmp`);
4207
- const script = [
4208
- `mkdir -p ${shellQuote(JOB_DIR)}`,
4209
- `({ (${command}); echo $? > ${exitTmpFile}; } 2>&1 | tee ${logFile}; mv ${exitTmpFile} ${exitFile})`
4210
- ].join(" && ");
4211
- return ["sh", "-c", script];
4212
- }
4213
- async function* streamLogFile(env, jobId, opts) {
4214
- const fs14 = env.fs ?? nodeFs2;
4215
- const file = jobLogPath(jobId);
4216
- let byteOffset = opts.sinceByte ?? 0;
4217
- while (true) {
4218
- if (opts.since !== void 0 && !await wasModifiedSince(fs14, file, opts.since)) {
4219
- await waitForLogChange(fs14, file);
4220
- continue;
4221
- }
4222
- const result = await readLogChunk(fs14, file, byteOffset);
4223
- if (result !== null) {
4224
- byteOffset = result.nextByteOffset;
4225
- yield result.chunk;
4226
- continue;
4227
- }
4228
- await waitForLogChange(fs14, file);
4138
+ args.push("run");
4139
+ if (input.rm) {
4140
+ args.push("--rm");
4229
4141
  }
4230
- }
4231
- async function wasModifiedSince(fs14, file, since) {
4232
- if (fs14.promises.stat === void 0) {
4233
- return true;
4142
+ if (input.detached) {
4143
+ args.push("-d");
4234
4144
  }
4235
- try {
4236
- const stat7 = await fs14.promises.stat(file);
4237
- return stat7.mtimeMs >= since.getTime();
4238
- } catch (error2) {
4239
- if (isNodeError(error2) && error2.code === "ENOENT") {
4240
- return false;
4241
- }
4242
- throw error2;
4145
+ if (input.interactive) {
4146
+ args.push("-i");
4243
4147
  }
4244
- }
4245
- async function waitForExit(env, jobId, opts = {}) {
4246
- const fs14 = env.fs ?? nodeFs2;
4247
- const file = jobExitPath(jobId);
4248
- while (true) {
4249
- throwIfAborted2(opts.signal);
4250
- const contents = await readTextFileIfExists(fs14, file);
4251
- if (contents !== null) {
4252
- const text4 = contents.trim();
4253
- const exitCode = Number(text4);
4254
- if (text4.length === 0 || !Number.isInteger(exitCode)) {
4255
- throw new Error(`Invalid exit code in ${file}: ${contents}`);
4256
- }
4257
- return { exitCode };
4258
- }
4259
- await sleep3(POLL_INTERVAL_MS, opts.signal);
4148
+ if (input.tty) {
4149
+ args.push("-t");
4260
4150
  }
4261
- }
4262
- function jobLogPath(jobId) {
4263
- return `${JOB_DIR}/${jobId}.log`;
4264
- }
4265
- function jobExitPath(jobId) {
4266
- return `${JOB_DIR}/${jobId}.exit`;
4267
- }
4268
- async function readLogChunk(fs14, file, byteOffset) {
4269
- const contents = await readFileIfExists2(fs14, file);
4270
- if (contents === null || byteOffset >= contents.byteLength) {
4271
- return null;
4151
+ args.push("--name", input.containerName);
4152
+ if (input.cwd !== void 0) {
4153
+ args.push("-w", input.cwd);
4272
4154
  }
4273
- return {
4274
- chunk: {
4275
- byteOffset,
4276
- data: contents.subarray(byteOffset).toString("utf8")
4277
- },
4278
- nextByteOffset: contents.byteLength
4279
- };
4280
- }
4281
- async function readTextFileIfExists(fs14, file) {
4282
- const contents = await readFileIfExists2(fs14, file);
4283
- return contents?.toString("utf8") ?? null;
4284
- }
4285
- async function readFileIfExists2(fs14, file) {
4286
- try {
4287
- const contents = await fs14.promises.readFile(file);
4288
- return Buffer.isBuffer(contents) ? contents : Buffer.from(contents);
4289
- } catch (error2) {
4290
- if (isNodeError(error2) && error2.code === "ENOENT") {
4291
- return null;
4292
- }
4293
- throw error2;
4155
+ for (const [key, value] of Object.entries(input.env ?? {})) {
4156
+ args.push("-e", `${key}=${value}`);
4294
4157
  }
4295
- }
4296
- async function waitForLogChange(fs14, file) {
4297
- const watch = fs14.watch;
4298
- if (typeof watch !== "function") {
4299
- await sleep3(POLL_INTERVAL_MS);
4300
- return;
4158
+ for (const mount of input.mounts) {
4159
+ const volume = `${path23.resolve(mount.source)}:${mount.target}${mount.readonly ? ":ro" : ""}`;
4160
+ args.push("-v", volume);
4301
4161
  }
4302
- await new Promise((resolve2) => {
4303
- let watcher = null;
4304
- const timer = setTimeout(done, POLL_INTERVAL_MS);
4305
- function done() {
4306
- clearTimeout(timer);
4307
- watcher?.close();
4308
- resolve2();
4309
- }
4310
- try {
4311
- watcher = watch(file, done);
4312
- } catch {
4313
- done();
4314
- }
4315
- });
4316
- }
4317
- function sleep3(ms, signal) {
4318
- return new Promise((resolve2, reject) => {
4319
- let timer = null;
4320
- const abort = () => {
4321
- if (timer !== null) {
4322
- clearTimeout(timer);
4323
- }
4324
- reject(new Error("waitForExit aborted."));
4325
- };
4326
- if (signal?.aborted) {
4327
- abort();
4328
- return;
4329
- }
4330
- timer = setTimeout(() => {
4331
- signal?.removeEventListener("abort", abort);
4332
- resolve2();
4333
- }, ms);
4334
- signal?.addEventListener("abort", abort, { once: true });
4335
- });
4336
- }
4337
- function throwIfAborted2(signal) {
4338
- if (signal?.aborted) {
4339
- throw new Error("waitForExit aborted.");
4162
+ for (const port of input.ports) {
4163
+ const mapping = `${port.host}:${port.container}${port.protocol === void 0 || port.protocol === "tcp" ? "" : `/${port.protocol}`}`;
4164
+ args.push("-p", mapping);
4340
4165
  }
4341
- }
4342
- function shellQuote(value) {
4343
- return `'${value.replaceAll("'", "'\\''")}'`;
4344
- }
4345
- function isNodeError(error2) {
4346
- return error2 instanceof Error && "code" in error2;
4166
+ if (input.network !== void 0) {
4167
+ args.push("--network", input.network);
4168
+ }
4169
+ args.push(...input.extraArgs, input.image, input.command, ...input.args);
4170
+ return args;
4347
4171
  }
4348
4172
 
4349
- // packages/agent-harness-tools/src/run-poe-command.ts
4350
- import { randomBytes } from "node:crypto";
4173
+ // packages/process-runner/src/docker/docker-execution-env.ts
4174
+ import { createHash as createHash3, randomBytes as randomBytes2 } from "node:crypto";
4175
+ import { mkdtempSync, rmSync } from "node:fs";
4176
+ import { readFile as readFile10 } from "node:fs/promises";
4177
+ import { tmpdir } from "node:os";
4178
+ import path24 from "node:path";
4351
4179
 
4352
- // packages/agent-harness-tools/src/binary-exists.ts
4353
- function createBinaryExistsDetectors(binaryName) {
4354
- const commonPaths = [
4355
- `/usr/local/bin/${binaryName}`,
4356
- `/usr/bin/${binaryName}`,
4357
- `$HOME/.local/bin/${binaryName}`,
4358
- `$HOME/.claude/local/bin/${binaryName}`
4359
- ];
4360
- return [
4361
- {
4362
- command: "which",
4363
- args: [binaryName],
4364
- validate: (result) => result.exitCode === 0
4365
- },
4366
- {
4367
- command: "where",
4368
- args: [binaryName],
4369
- validate: (result) => result.exitCode === 0 && result.stdout.trim().length > 0
4370
- },
4371
- {
4372
- command: "sh",
4373
- args: ["-c", commonPaths.map((p) => `test -f "${p}"`).join(" || ")],
4374
- validate: (result) => result.exitCode === 0
4180
+ // packages/process-runner/src/host/host-runner.ts
4181
+ import { spawn as spawnChildProcess } from "node:child_process";
4182
+ function createHostRunner(options = {}) {
4183
+ const detached = options.detached === true;
4184
+ return {
4185
+ name: "host",
4186
+ exec(spec) {
4187
+ const stdinMode = spec.stdin ?? "ignore";
4188
+ const stdoutMode = spec.stdout ?? "pipe";
4189
+ const stderrMode = spec.stderr ?? "pipe";
4190
+ const stdio = stdinMode === "inherit" && stdoutMode === "inherit" && stderrMode === "inherit" ? "inherit" : [stdinMode, stdoutMode, stderrMode];
4191
+ const child = spawnChildProcess(spec.command, spec.args ?? [], {
4192
+ cwd: spec.cwd,
4193
+ env: spec.env,
4194
+ stdio,
4195
+ ...detached ? { detached: true } : {}
4196
+ });
4197
+ if (detached) {
4198
+ child.unref();
4199
+ }
4200
+ const kill = (signal) => {
4201
+ if (detached && process.platform !== "win32" && child.pid !== void 0) {
4202
+ process.kill(-child.pid, signal);
4203
+ return;
4204
+ }
4205
+ child.kill(signal);
4206
+ };
4207
+ let settled = false;
4208
+ let resolveResult = null;
4209
+ const result = new Promise((resolve2) => {
4210
+ resolveResult = resolve2;
4211
+ });
4212
+ const cleanupAbort = bindAbortSignal(spec.signal, () => {
4213
+ kill("SIGTERM");
4214
+ });
4215
+ child.once("close", (code) => {
4216
+ if (settled) return;
4217
+ settled = true;
4218
+ cleanupAbort();
4219
+ resolveResult?.({ exitCode: code ?? 1 });
4220
+ });
4221
+ child.once("error", () => {
4222
+ if (settled) return;
4223
+ settled = true;
4224
+ cleanupAbort();
4225
+ resolveResult?.({ exitCode: 1 });
4226
+ });
4227
+ return {
4228
+ pid: child.pid ?? null,
4229
+ stdin: child.stdin,
4230
+ stdout: child.stdout,
4231
+ stderr: child.stderr,
4232
+ result,
4233
+ kill
4234
+ };
4375
4235
  }
4376
- ];
4236
+ };
4237
+ }
4238
+ function bindAbortSignal(signal, onAbort) {
4239
+ if (signal === void 0) {
4240
+ return () => {
4241
+ };
4242
+ }
4243
+ if (signal.aborted) {
4244
+ onAbort();
4245
+ return () => {
4246
+ };
4247
+ }
4248
+ signal.addEventListener("abort", onAbort, { once: true });
4249
+ return () => {
4250
+ signal.removeEventListener("abort", onAbort);
4251
+ };
4377
4252
  }
4378
4253
 
4379
- // packages/agent-harness-tools/src/run-poe-command.ts
4380
- var ULID_ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
4381
- async function runPoeCommand(opts) {
4382
- const jobId = createUlid();
4383
- const execution = opts.openSpec.execution;
4384
- const wrapCommand = execution?.wrapForLogTee !== false;
4385
- const pendingJob = opts.state.jobs.put({
4386
- id: jobId,
4387
- env_id: "",
4388
- env_kind: opts.factory.type,
4389
- tool: opts.openSpec.jobLabel.tool,
4390
- argv: opts.openSpec.jobLabel.argv,
4391
- cwd: opts.openSpec.cwd,
4392
- started_at: "",
4393
- status: "pending"
4394
- });
4395
- const opened = opts.factory.open(opts.openSpec);
4396
- const env = isPromiseLike(opened) ? await opened : opened;
4397
- let shouldClose = true;
4398
- try {
4399
- const upload = env.uploadWorkspace();
4400
- await Promise.all([pendingJob, upload]);
4401
- await configureE2bSpawnAgentIfAvailable({
4402
- env,
4403
- openSpec: opts.openSpec,
4404
- factoryType: opts.factory.type
4405
- });
4406
- const argv = wrapCommand ? wrapForLogTee(opts.openSpec.jobLabel.argv, jobId) : opts.openSpec.jobLabel.argv;
4407
- const handle = execution?.tty ? env.shell() : env.exec({
4408
- command: argv[0],
4409
- args: argv.slice(1),
4410
- cwd: opts.openSpec.cwd,
4411
- env: resolveExecutionEnv(opts.openSpec),
4412
- stdin: execution?.stdin ?? "inherit",
4413
- stdout: execution?.stdout ?? "pipe",
4414
- stderr: execution?.stderr ?? "pipe",
4415
- signal: opts.signal
4254
+ // packages/process-runner/src/docker/docker-execution-env.ts
4255
+ var containerCommand = ["sh", "-c", "while :; do sleep 3600; done"];
4256
+ var dockerExecutionEnvFactory = {
4257
+ type: "docker",
4258
+ supportsDetach: true,
4259
+ async open(spec) {
4260
+ const runtime = parseDockerRuntime(spec.runtime);
4261
+ const runner = spec.hostRunner ?? createHostRunner();
4262
+ const engine = runtime.engine ?? detectEngine();
4263
+ const context = detectContext();
4264
+ const image = await resolveImage({
4265
+ spec,
4266
+ runtime,
4267
+ runner,
4268
+ engine,
4269
+ context
4416
4270
  });
4417
- if (execution?.input !== void 0) {
4418
- handle.stdin?.setDefaultEncoding("utf8");
4419
- handle.stdin?.end(execution.input);
4420
- }
4421
- const runningJob = opts.state.jobs.update(jobId, {
4422
- status: "running",
4423
- env_id: env.id,
4424
- started_at: (/* @__PURE__ */ new Date()).toISOString()
4271
+ const containerName = createContainerName();
4272
+ const runArgs = buildDockerRunArgs({
4273
+ engine,
4274
+ context,
4275
+ image,
4276
+ command: containerCommand[0],
4277
+ args: containerCommand.slice(1),
4278
+ cwd: void 0,
4279
+ env: void 0,
4280
+ mounts: runtime.mounts ?? [],
4281
+ ports: [],
4282
+ network: runtime.network,
4283
+ containerName,
4284
+ detached: true,
4285
+ interactive: true,
4286
+ tty: false,
4287
+ rm: false,
4288
+ extraArgs: runtime.extra_args ?? []
4425
4289
  });
4426
- if (opts.detach) {
4427
- await runningJob;
4428
- setDetachedJobContext(env, {
4429
- id: jobId,
4430
- tool: opts.openSpec.jobLabel.tool,
4431
- argv: opts.openSpec.jobLabel.argv
4432
- });
4433
- await env.detach();
4434
- shouldClose = false;
4435
- return { kind: "detached", jobId, envId: env.id };
4436
- }
4437
- const result = await runSync({
4438
- env,
4439
- handle,
4440
- jobId,
4441
- openSpec: opts.openSpec,
4442
- signal: opts.signal,
4443
- wrapCommand
4290
+ const [command, ...args] = runArgs;
4291
+ const id = (await runAndRead(runner, { command, args, stdout: "pipe", stderr: "pipe" })).trim();
4292
+ return createDockerEnv({
4293
+ id,
4294
+ spec,
4295
+ runner,
4296
+ engine,
4297
+ context
4444
4298
  });
4445
- await runningJob;
4446
- shouldClose = false;
4447
- await opts.state.jobs.update(jobId, {
4448
- status: "exited",
4449
- exit_code: result.exitCode,
4450
- exited_at: (/* @__PURE__ */ new Date()).toISOString()
4299
+ },
4300
+ async attach(envId, context) {
4301
+ const engine = detectEngine();
4302
+ return createDockerEnv({
4303
+ id: envId,
4304
+ spec: createAttachedSpec(context?.cwd),
4305
+ runner: createHostRunner(),
4306
+ engine,
4307
+ context: detectContext(),
4308
+ attachedJobId: context?.jobId
4451
4309
  });
4452
- return {
4453
- kind: "sync",
4454
- exitCode: result.exitCode,
4455
- download: result.download,
4456
- ...result.stdout !== void 0 ? { stdout: result.stdout } : {},
4457
- ...result.stderr !== void 0 ? { stderr: result.stderr } : {}
4458
- };
4459
- } finally {
4460
- if (shouldClose) {
4461
- await env.close();
4462
- }
4463
4310
  }
4311
+ };
4312
+ function createDockerEnv(input) {
4313
+ const containerRef = input.id;
4314
+ return {
4315
+ id: containerRef,
4316
+ job: input.attachedJobId === void 0 ? null : createContainerJob(containerRef, input.runner, input.engine, input.context, input.attachedJobId),
4317
+ async uploadWorkspace() {
4318
+ const tempDir = mkdtempSync(path24.join(tmpdir(), "poe-docker-upload-"));
4319
+ const archivePath = path24.join(tempDir, "workspace.tar");
4320
+ try {
4321
+ const excludeArgs = input.spec.uploadIgnoreFiles.flatMap((ignored) => [
4322
+ "--exclude",
4323
+ ignored
4324
+ ]);
4325
+ const tarArgs = [...excludeArgs, "-cf", archivePath, "-C", input.spec.cwd, "."];
4326
+ await runOrThrow(input.runner, {
4327
+ command: "tar",
4328
+ args: tarArgs,
4329
+ stdout: "pipe",
4330
+ stderr: "pipe"
4331
+ });
4332
+ await runOrThrow(input.runner, {
4333
+ command: input.engine,
4334
+ args: [
4335
+ ...buildContextArgs(input.engine, input.context),
4336
+ "cp",
4337
+ archivePath,
4338
+ `${containerRef}:/tmp/poe-workspace-upload.tar`
4339
+ ],
4340
+ stdout: "pipe",
4341
+ stderr: "pipe"
4342
+ });
4343
+ await runOrThrow(input.runner, {
4344
+ command: input.engine,
4345
+ args: [
4346
+ ...buildContextArgs(input.engine, input.context),
4347
+ "exec",
4348
+ containerRef,
4349
+ "sh",
4350
+ "-c",
4351
+ `mkdir -p ${shellQuote(input.spec.cwd)} && tar -xf /tmp/poe-workspace-upload.tar -C ${shellQuote(input.spec.cwd)}`
4352
+ ],
4353
+ stdout: "pipe",
4354
+ stderr: "pipe"
4355
+ });
4356
+ return { files: 0, bytes: 0, skipped: [] };
4357
+ } finally {
4358
+ rmSync(tempDir, { recursive: true, force: true });
4359
+ }
4360
+ },
4361
+ async downloadWorkspace(opts) {
4362
+ const tempDir = mkdtempSync(path24.join(tmpdir(), "poe-docker-download-"));
4363
+ const archivePath = path24.join(tempDir, "workspace.tar");
4364
+ try {
4365
+ await runOrThrow(input.runner, {
4366
+ command: input.engine,
4367
+ args: [
4368
+ ...buildContextArgs(input.engine, input.context),
4369
+ "exec",
4370
+ containerRef,
4371
+ "sh",
4372
+ "-c",
4373
+ `tar -cf /tmp/poe-workspace-download.tar -C ${shellQuote(input.spec.cwd)} .`
4374
+ ],
4375
+ stdout: "pipe",
4376
+ stderr: "pipe"
4377
+ });
4378
+ await runOrThrow(input.runner, {
4379
+ command: input.engine,
4380
+ args: [
4381
+ ...buildContextArgs(input.engine, input.context),
4382
+ "cp",
4383
+ `${containerRef}:/tmp/poe-workspace-download.tar`,
4384
+ archivePath
4385
+ ],
4386
+ stdout: "pipe",
4387
+ stderr: "pipe"
4388
+ });
4389
+ const extractMode = opts.conflictPolicy === "refuse" ? "-xkf" : "-xf";
4390
+ await runOrThrow(input.runner, {
4391
+ command: "tar",
4392
+ args: [extractMode, archivePath, "-C", input.spec.cwd],
4393
+ stdout: "pipe",
4394
+ stderr: "pipe"
4395
+ });
4396
+ return { files: 0, bytes: 0, conflicts: [] };
4397
+ } finally {
4398
+ rmSync(tempDir, { recursive: true, force: true });
4399
+ }
4400
+ },
4401
+ exec(spec) {
4402
+ return input.runner.exec({
4403
+ command: input.engine,
4404
+ args: [
4405
+ ...buildContextArgs(input.engine, input.context),
4406
+ "exec",
4407
+ ...spec.stdin === "pipe" || spec.stdin === "inherit" ? ["-i"] : [],
4408
+ ...spec.tty === true ? ["-t"] : [],
4409
+ ...spec.cwd !== void 0 ? ["-w", spec.cwd] : [],
4410
+ ...buildEnvArgs(spec.env),
4411
+ containerRef,
4412
+ spec.command,
4413
+ ...spec.args ?? []
4414
+ ],
4415
+ stdin: spec.stdin,
4416
+ stdout: spec.stdout,
4417
+ stderr: spec.stderr,
4418
+ tty: spec.tty
4419
+ });
4420
+ },
4421
+ async detach() {
4422
+ return createContainerJob(containerRef, input.runner, input.engine, input.context);
4423
+ },
4424
+ shell() {
4425
+ const shellSpec = input.spec.shellSpec;
4426
+ return this.exec({
4427
+ command: shellSpec?.command ?? input.spec.env.SHELL ?? "sh",
4428
+ ...shellSpec?.args ? { args: shellSpec.args } : {},
4429
+ cwd: input.spec.cwd,
4430
+ env: shellSpec && "env" in shellSpec ? shellSpec.env : input.spec.env,
4431
+ stdin: "inherit",
4432
+ stdout: "inherit",
4433
+ stderr: "inherit",
4434
+ tty: true
4435
+ });
4436
+ },
4437
+ async close() {
4438
+ await runOrThrow(input.runner, {
4439
+ command: input.engine,
4440
+ args: [...buildContextArgs(input.engine, input.context), "rm", "-f", containerRef],
4441
+ stdout: "pipe",
4442
+ stderr: "pipe"
4443
+ });
4444
+ }
4445
+ };
4464
4446
  }
4465
- async function configureE2bSpawnAgentIfAvailable(opts) {
4466
- if (opts.factoryType !== "e2b") {
4467
- return;
4468
- }
4469
- const agentId = resolveAgentId(opts.openSpec.jobLabel.tool);
4470
- const agent = allAgents.find((candidate) => candidate.id === agentId);
4471
- const binaryName = agent?.binaryName;
4472
- if (!agentId || !binaryName) {
4473
- return;
4447
+ async function resolveImage(input) {
4448
+ if (input.runtime.image !== void 0) {
4449
+ return input.runtime.image;
4474
4450
  }
4475
- const commandEnv = resolveExecutionEnv(opts.openSpec);
4476
- const exists = await binaryExists(opts.env, {
4477
- binaryName,
4478
- cwd: opts.openSpec.cwd,
4479
- env: commandEnv
4451
+ const result = await buildDockerRuntimeTemplate({
4452
+ cwd: input.spec.cwd,
4453
+ runtime: input.runtime,
4454
+ state: input.spec.state,
4455
+ runner: input.runner
4480
4456
  });
4481
- if (!exists) {
4482
- return;
4457
+ return result.image;
4458
+ }
4459
+ async function buildDockerRuntimeTemplate(input) {
4460
+ const runner = input.runner ?? createHostRunner();
4461
+ const engine = input.runtime.engine ?? detectEngine();
4462
+ const context = detectContext();
4463
+ const dockerfilePath = path24.resolve(
4464
+ input.cwd,
4465
+ input.runtime.dockerfile ?? path24.join(".poe-code", "Dockerfile")
4466
+ );
4467
+ const buildContext = path24.resolve(input.cwd, input.runtime.build_context ?? ".");
4468
+ const dockerfileBytes = await readFile10(dockerfilePath);
4469
+ const hash = hashDockerTemplate(dockerfileBytes, input.runtime.build_args ?? {});
4470
+ const cached2 = input.force ? null : await input.state?.templates.get("docker", hash);
4471
+ if (cached2?.image !== void 0) {
4472
+ return {
4473
+ backend: "docker",
4474
+ hash,
4475
+ image: cached2.image,
4476
+ cached: true
4477
+ };
4483
4478
  }
4484
- const result = await runProbeCommand(opts.env, {
4485
- command: "poe-code",
4486
- args: ["configure", "--yes", "--provider", "poe", agentId],
4487
- cwd: opts.openSpec.cwd,
4488
- env: commandEnv
4479
+ const image = `poe-code/local:${hash}`;
4480
+ await buildImage({
4481
+ runner,
4482
+ engine,
4483
+ context,
4484
+ image,
4485
+ dockerfilePath,
4486
+ buildContext,
4487
+ buildArgs: input.runtime.build_args ?? {}
4489
4488
  });
4490
- if (result.exitCode !== 0) {
4491
- throw new Error(
4492
- `Failed to configure ${agentId} for Poe inside E2B sandbox.
4493
- ${formatProbeResult(result)}`
4494
- );
4495
- }
4489
+ await input.state?.templates.put("docker", {
4490
+ hash,
4491
+ image,
4492
+ runtime_type: "docker",
4493
+ dockerfile_path: dockerfilePath,
4494
+ built_at: (/* @__PURE__ */ new Date()).toISOString()
4495
+ });
4496
+ return {
4497
+ backend: "docker",
4498
+ hash,
4499
+ image,
4500
+ cached: false
4501
+ };
4496
4502
  }
4497
- async function binaryExists(env, opts) {
4498
- for (const detector of createBinaryExistsDetectors(opts.binaryName)) {
4499
- const result = await runProbeCommand(env, {
4500
- ...detector,
4501
- cwd: opts.cwd,
4502
- env: opts.env
4503
- });
4504
- if (detector.validate(result)) {
4505
- return true;
4506
- }
4503
+ function hashDockerTemplate(dockerfileBytes, buildArgs) {
4504
+ const hash = createHash3("sha256");
4505
+ hash.update(dockerfileBytes);
4506
+ hash.update("\0");
4507
+ for (const [key, value] of sortedBuildArgs(buildArgs)) {
4508
+ hash.update(key);
4509
+ hash.update("=");
4510
+ hash.update(value);
4511
+ hash.update("\0");
4507
4512
  }
4508
- return false;
4509
- }
4510
- function resolveExecutionEnv(openSpec) {
4511
- const execution = openSpec.execution;
4512
- return execution?.env ?? openSpec.env;
4513
+ return hash.digest("hex");
4513
4514
  }
4514
- async function runProbeCommand(env, spec) {
4515
- const handle = env.exec({
4516
- command: spec.command,
4517
- args: spec.args,
4518
- cwd: spec.cwd,
4519
- env: spec.env,
4520
- stdin: "ignore",
4515
+ async function buildImage(input) {
4516
+ await runOrThrow(input.runner, {
4517
+ command: input.engine,
4518
+ args: [
4519
+ ...buildContextArgs(input.engine, input.context),
4520
+ "build",
4521
+ "--tag",
4522
+ input.image,
4523
+ "-f",
4524
+ input.dockerfilePath,
4525
+ ...sortedBuildArgs(input.buildArgs).flatMap(([key, value]) => [
4526
+ "--build-arg",
4527
+ `${key}=${value}`
4528
+ ]),
4529
+ input.buildContext
4530
+ ],
4521
4531
  stdout: "pipe",
4522
4532
  stderr: "pipe"
4523
4533
  });
4534
+ }
4535
+ function parseDockerRuntime(runtime) {
4536
+ if (!runtime || typeof runtime !== "object" || Array.isArray(runtime)) {
4537
+ throw new Error("docker runtime must be an object");
4538
+ }
4539
+ const record = runtime;
4540
+ if (record.type !== "docker") {
4541
+ throw new Error('docker runtime type must be "docker"');
4542
+ }
4543
+ return record;
4544
+ }
4545
+ async function runAndRead(runner, spec) {
4546
+ const handle = runner.exec(spec);
4524
4547
  const stdout = readStream(handle.stdout);
4525
4548
  const stderr = readStream(handle.stderr);
4526
4549
  const result = await handle.result;
4527
- return {
4528
- exitCode: result.exitCode,
4529
- stdout: await stdout,
4530
- stderr: await stderr
4531
- };
4550
+ const output = await stdout;
4551
+ if (result.exitCode !== 0) {
4552
+ const errorOutput = await stderr;
4553
+ throw new Error(
4554
+ `Command failed with exit code ${result.exitCode}: ${spec.command} ${(spec.args ?? []).join(" ")}${errorOutput ? `
4555
+ ${errorOutput}` : ""}`
4556
+ );
4557
+ }
4558
+ return output;
4532
4559
  }
4533
- function readStream(stream) {
4534
- if (!stream) {
4535
- return Promise.resolve("");
4560
+ async function runOrThrow(runner, spec) {
4561
+ await runAndRead(runner, spec);
4562
+ }
4563
+ async function readStream(stream) {
4564
+ if (stream === null) {
4565
+ return "";
4536
4566
  }
4537
- return new Promise((resolve2, reject) => {
4538
- let output = "";
4539
- stream.setEncoding("utf8");
4540
- stream.on("data", (chunk) => {
4541
- output += chunk.toString();
4542
- });
4543
- stream.on("error", reject);
4544
- stream.on("end", () => resolve2(output));
4545
- });
4567
+ stream.setEncoding("utf8");
4568
+ const chunks = [];
4569
+ for await (const chunk of stream) {
4570
+ chunks.push(String(chunk));
4571
+ }
4572
+ return chunks.join("");
4546
4573
  }
4547
- function formatProbeResult(result) {
4548
- return [
4549
- `Exit code: ${result.exitCode}`,
4550
- result.stdout.trim() ? `stdout:
4551
- ${result.stdout.trim()}` : "",
4552
- result.stderr.trim() ? `stderr:
4553
- ${result.stderr.trim()}` : ""
4554
- ].filter(Boolean).join("\n");
4574
+ function sortedBuildArgs(buildArgs) {
4575
+ return Object.entries(buildArgs).sort(([left], [right]) => left.localeCompare(right));
4555
4576
  }
4556
- async function runSync(opts) {
4557
- const execution = opts.openSpec.execution;
4558
- const capture = execution?.captureOutput === true;
4559
- const abort = createAbortSync(opts.signal, opts.handle, execution?.activityTimeoutMs);
4560
- const streamState = capture ? captureRunStreams(opts.handle, execution, abort.resetActivityTimer) : pipeRunStreams(opts.handle);
4561
- abort.resetActivityTimer();
4562
- try {
4563
- const { exitCode } = opts.wrapCommand ? await abort.waitForExit(opts.env, opts.jobId) : await abort.waitForHandle();
4564
- const download = await opts.env.downloadWorkspace({
4565
- conflictPolicy: opts.openSpec.runner?.download_conflict ?? "refuse"
4566
- });
4567
- if (opts.closeAfterDownload !== false) {
4568
- await opts.env.close();
4577
+ function buildEnvArgs(env) {
4578
+ if (env === void 0) {
4579
+ return [];
4580
+ }
4581
+ return Object.entries(env).flatMap(([key, value]) => ["-e", `${key}=${value}`]);
4582
+ }
4583
+ function createContainerName() {
4584
+ return `poe-env-${randomBytes2(6).toString("hex")}`;
4585
+ }
4586
+ function createContainerJob(containerId, runner, engine, context, jobId = containerId) {
4587
+ return {
4588
+ id: jobId,
4589
+ envId: containerId,
4590
+ tool: "docker",
4591
+ argv: ["attach", containerId],
4592
+ async status() {
4593
+ const handle = runner.exec({
4594
+ command: engine,
4595
+ args: [
4596
+ ...buildContextArgs(engine, context),
4597
+ "inspect",
4598
+ "-f",
4599
+ "{{.State.Status}}",
4600
+ containerId
4601
+ ],
4602
+ stdout: "pipe",
4603
+ stderr: "pipe"
4604
+ });
4605
+ const stdout = await readStream(handle.stdout);
4606
+ const result = await handle.result;
4607
+ if (result.exitCode !== 0) {
4608
+ return "lost";
4609
+ }
4610
+ return stdout.trim() === "running" ? "running" : "exited";
4611
+ },
4612
+ async *stream(opts) {
4613
+ const handle = runner.exec({
4614
+ command: engine,
4615
+ args: [
4616
+ ...buildContextArgs(engine, context),
4617
+ "exec",
4618
+ containerId,
4619
+ "sh",
4620
+ "-c",
4621
+ `test -f ${shellQuote(`/tmp/poe-jobs/${jobId}.log`)} && tail -c +${(opts?.sinceByte ?? 0) + 1} ${shellQuote(`/tmp/poe-jobs/${jobId}.log`)} || true`
4622
+ ],
4623
+ stdout: "pipe",
4624
+ stderr: "pipe"
4625
+ });
4626
+ const stdout = await readStream(handle.stdout);
4627
+ await handle.result;
4628
+ if (stdout.length > 0) {
4629
+ yield { byteOffset: opts?.sinceByte ?? 0, data: stdout };
4630
+ }
4631
+ },
4632
+ async wait() {
4633
+ const handle = runner.exec({
4634
+ command: engine,
4635
+ args: [...buildContextArgs(engine, context), "wait", containerId],
4636
+ stdout: "pipe",
4637
+ stderr: "pipe"
4638
+ });
4639
+ const stdout = await readStream(handle.stdout);
4640
+ const result = await handle.result;
4641
+ return { exitCode: Number.parseInt(stdout.trim(), 10) || result.exitCode };
4642
+ },
4643
+ async kill(signal) {
4644
+ const args = signal === void 0 || signal === "SIGTERM" ? ["stop", containerId] : ["kill", ...signal === "SIGKILL" ? [] : [`--signal=${signal}`], containerId];
4645
+ await runOrThrow(runner, {
4646
+ command: engine,
4647
+ args: [...buildContextArgs(engine, context), ...args],
4648
+ stdout: "pipe",
4649
+ stderr: "pipe"
4650
+ });
4569
4651
  }
4570
- return {
4571
- exitCode,
4572
- download,
4573
- ...capture ? { stdout: streamState.stdout(), stderr: streamState.stderr() } : {}
4574
- };
4575
- } finally {
4576
- abort.dispose();
4577
- streamState.dispose();
4578
- }
4652
+ };
4579
4653
  }
4580
- function pipeRunStreams(handle) {
4581
- handle.stdout?.pipe(process.stdout, { end: false });
4582
- handle.stderr?.pipe(process.stderr, { end: false });
4654
+ function createAttachedSpec(cwd = "/workspace") {
4583
4655
  return {
4584
- stdout: () => "",
4585
- stderr: () => "",
4586
- dispose() {
4587
- handle.stdout?.unpipe(process.stdout);
4588
- handle.stderr?.unpipe(process.stderr);
4656
+ cwd,
4657
+ runtime: {
4658
+ type: "docker",
4659
+ image: "attached",
4660
+ build_args: {},
4661
+ mounts: []
4662
+ },
4663
+ env: {},
4664
+ uploadIgnoreFiles: [],
4665
+ jobLabel: {
4666
+ tool: "docker",
4667
+ argv: []
4589
4668
  }
4590
4669
  };
4591
4670
  }
4592
- function captureRunStreams(handle, execution, onActivity) {
4593
- let stdout = "";
4594
- let stderr = "";
4595
- const listeners = [];
4596
- const bind = (stream, onChunk) => {
4597
- if (!stream) return;
4598
- stream.setEncoding("utf8");
4599
- const listener = (chunk) => {
4600
- onActivity();
4601
- onChunk(chunk.toString());
4671
+ function shellQuote(value) {
4672
+ return `'${value.replaceAll("'", "'\\''")}'`;
4673
+ }
4674
+
4675
+ // packages/process-runner/src/host/host-execution-env.ts
4676
+ var hostExecutionEnvFactory = {
4677
+ type: "host",
4678
+ supportsDetach: false,
4679
+ async open(openSpec) {
4680
+ return {
4681
+ id: "host",
4682
+ job: null,
4683
+ async uploadWorkspace() {
4684
+ return {
4685
+ files: 0,
4686
+ bytes: 0,
4687
+ skipped: []
4688
+ };
4689
+ },
4690
+ async downloadWorkspace() {
4691
+ return {
4692
+ files: 0,
4693
+ bytes: 0,
4694
+ conflicts: []
4695
+ };
4696
+ },
4697
+ exec(spec) {
4698
+ return createHostRunner().exec(spec);
4699
+ },
4700
+ async detach() {
4701
+ throw new Error("host runtime does not support detach because host has no addressable env");
4702
+ },
4703
+ shell() {
4704
+ const shellSpec = openSpec.shellSpec;
4705
+ return createHostRunner().exec({
4706
+ command: shellSpec?.command ?? openSpec.env.SHELL ?? process.env.SHELL ?? "sh",
4707
+ ...shellSpec?.args ? { args: shellSpec.args } : {},
4708
+ cwd: openSpec.cwd,
4709
+ env: shellSpec && "env" in shellSpec ? shellSpec.env : openSpec.env,
4710
+ stdin: "inherit",
4711
+ stdout: "inherit",
4712
+ stderr: "inherit",
4713
+ tty: true
4714
+ });
4715
+ },
4716
+ async close() {
4717
+ }
4602
4718
  };
4603
- stream.on("data", listener);
4604
- listeners.push(() => {
4605
- stream.off("data", listener);
4606
- });
4607
- };
4608
- bind(handle.stdout, (chunk) => {
4609
- stdout += chunk;
4610
- execution?.onStdout?.(chunk);
4611
- });
4612
- bind(handle.stderr, (chunk) => {
4613
- stderr += chunk;
4614
- execution?.onStderr?.(chunk);
4615
- });
4616
- return {
4617
- stdout: () => stdout,
4618
- stderr: () => stderr,
4619
- dispose() {
4620
- for (const remove2 of listeners) {
4621
- remove2();
4719
+ },
4720
+ async attach() {
4721
+ throw new Error("host runtime does not support reattach");
4722
+ }
4723
+ };
4724
+
4725
+ // packages/process-runner/src/testing/mock-runner.ts
4726
+ import { Readable, Writable } from "node:stream";
4727
+
4728
+ // packages/task-list/src/backends/utils.ts
4729
+ import path25 from "node:path";
4730
+
4731
+ // packages/task-list/src/backends/markdown-dir.ts
4732
+ import path26 from "node:path";
4733
+ import { parseDocument as parseDocument2, stringify as stringify2 } from "yaml";
4734
+
4735
+ // packages/task-list/src/schema/task.schema.json
4736
+ var task_schema_default = {
4737
+ $schema: "https://json-schema.org/draft/2020-12/schema",
4738
+ $id: "https://poe-platform.github.io/poe-code/schemas/task-list/task.schema.json",
4739
+ title: "Task",
4740
+ description: "Persisted task payload used by task-list backends.",
4741
+ type: "object",
4742
+ properties: {
4743
+ $schema: {
4744
+ type: "string",
4745
+ const: "https://poe-platform.github.io/poe-code/schemas/task-list/task.schema.json"
4746
+ },
4747
+ kind: {
4748
+ type: "string",
4749
+ const: "task"
4750
+ },
4751
+ version: {
4752
+ type: "integer",
4753
+ const: 1
4754
+ },
4755
+ name: {
4756
+ type: "string",
4757
+ minLength: 1
4758
+ },
4759
+ state: {
4760
+ type: "string"
4761
+ },
4762
+ description: {
4763
+ type: "string"
4764
+ }
4765
+ },
4766
+ required: ["name", "state"],
4767
+ additionalProperties: true
4768
+ };
4769
+
4770
+ // packages/task-list/src/state.ts
4771
+ var defaultStateMachine = {
4772
+ initial: "draft",
4773
+ states: ["draft", "planned", "in-progress", "done", "archived"],
4774
+ events: {
4775
+ plan: { from: ["draft"], to: "planned" },
4776
+ start: { from: ["planned"], to: "in-progress" },
4777
+ complete: { from: ["in-progress"], to: "done" },
4778
+ archive: { from: "*", to: "archived" }
4779
+ }
4780
+ };
4781
+ function deriveLegacyTransitions(machine) {
4782
+ const transitions = Object.fromEntries(
4783
+ machine.states.map((state) => [state, /* @__PURE__ */ new Set()])
4784
+ );
4785
+ for (const fromState of machine.states) {
4786
+ for (const eventName of Object.keys(machine.events)) {
4787
+ const event = findEvent(machine, fromState, eventName);
4788
+ if (event !== void 0) {
4789
+ transitions[fromState].add(event.to);
4622
4790
  }
4623
4791
  }
4624
- };
4792
+ }
4793
+ const terminalState = machine.events.archive.to;
4794
+ const activeStates = machine.states.filter((state) => state !== terminalState);
4795
+ for (let index = 1; index < activeStates.length; index += 1) {
4796
+ transitions[activeStates[index]].add(activeStates[index - 1]);
4797
+ }
4798
+ return transitions;
4625
4799
  }
4626
- function createAbortSync(signal, handle, activityTimeoutMs) {
4627
- let activityTimer;
4628
- let timedOut = false;
4629
- const resetActivityTimer = activityTimeoutMs ? () => {
4630
- if (activityTimer) clearTimeout(activityTimer);
4631
- activityTimer = setTimeout(() => {
4632
- timedOut = true;
4633
- handle.kill("SIGTERM");
4634
- notifyAbort?.();
4635
- }, activityTimeoutMs);
4636
- } : () => {
4637
- };
4638
- let notifyAbort;
4639
- if (signal === void 0) {
4640
- return {
4641
- waitForExit: (env, jobId) => waitForExit(toLogStreamEnv(env), jobId),
4642
- waitForHandle: async () => {
4643
- const result = await handle.result;
4644
- if (timedOut) {
4645
- throw createActivityTimeoutError(activityTimeoutMs);
4800
+ var defaultTransitions = deriveLegacyTransitions(defaultStateMachine);
4801
+
4802
+ // packages/task-list/src/backends/markdown-dir.ts
4803
+ var TASK_SCHEMA_ID = task_schema_default.$id;
4804
+
4805
+ // packages/task-list/src/backends/yaml-file.ts
4806
+ import { isMap, parseDocument as parseDocument3 } from "yaml";
4807
+
4808
+ // packages/task-list/src/schema/store.schema.json
4809
+ var store_schema_default = {
4810
+ $schema: "https://json-schema.org/draft/2020-12/schema",
4811
+ $id: "https://poe-platform.github.io/poe-code/schemas/task-list/store.schema.json",
4812
+ title: "Task Store",
4813
+ description: "YAML multi-list task store.",
4814
+ type: "object",
4815
+ properties: {
4816
+ $schema: {
4817
+ type: "string",
4818
+ const: "https://poe-platform.github.io/poe-code/schemas/task-list/store.schema.json"
4819
+ },
4820
+ kind: {
4821
+ type: "string",
4822
+ const: "task-store"
4823
+ },
4824
+ version: {
4825
+ type: "integer",
4826
+ const: 1
4827
+ },
4828
+ lists: {
4829
+ type: "object",
4830
+ additionalProperties: {
4831
+ type: "object",
4832
+ additionalProperties: {
4833
+ $ref: "./task.schema.json"
4646
4834
  }
4647
- return result;
4648
- },
4649
- resetActivityTimer,
4650
- dispose() {
4651
- if (activityTimer) clearTimeout(activityTimer);
4652
4835
  }
4653
- };
4836
+ }
4837
+ },
4838
+ required: ["$schema", "kind", "version", "lists"],
4839
+ additionalProperties: false
4840
+ };
4841
+
4842
+ // packages/task-list/src/backends/yaml-file.ts
4843
+ var STORE_SCHEMA_ID = store_schema_default.$id;
4844
+ var TASK_SCHEMA_ID2 = task_schema_default.$id;
4845
+
4846
+ // packages/agent-defs/src/agents/claude-code.ts
4847
+ var claudeCodeAgent = {
4848
+ id: "claude-code",
4849
+ name: "claude-code",
4850
+ label: "Claude Code",
4851
+ summary: "Configure Claude Code to route through Poe.",
4852
+ aliases: ["claude"],
4853
+ binaryName: "claude",
4854
+ configPath: "~/.claude/settings.json",
4855
+ branding: {
4856
+ colors: {
4857
+ dark: "#C15F3C",
4858
+ light: "#C15F3C"
4859
+ }
4860
+ }
4861
+ };
4862
+
4863
+ // packages/agent-defs/src/agents/claude-desktop.ts
4864
+ var claudeDesktopAgent = {
4865
+ id: "claude-desktop",
4866
+ name: "claude-desktop",
4867
+ label: "Claude Desktop",
4868
+ summary: "Anthropic's official desktop application for Claude",
4869
+ configPath: "~/.claude/settings.json",
4870
+ branding: {
4871
+ colors: {
4872
+ dark: "#D97757",
4873
+ light: "#D97757"
4874
+ }
4875
+ }
4876
+ };
4877
+
4878
+ // packages/agent-defs/src/agents/codex.ts
4879
+ var codexAgent = {
4880
+ id: "codex",
4881
+ name: "codex",
4882
+ label: "Codex",
4883
+ summary: "Configure Codex to use Poe as the model provider.",
4884
+ binaryName: "codex",
4885
+ configPath: "~/.codex/config.toml",
4886
+ branding: {
4887
+ colors: {
4888
+ dark: "#D5D9DF",
4889
+ light: "#7A7F86"
4890
+ }
4891
+ }
4892
+ };
4893
+
4894
+ // packages/agent-defs/src/agents/opencode.ts
4895
+ var openCodeAgent = {
4896
+ id: "opencode",
4897
+ name: "opencode",
4898
+ label: "OpenCode CLI",
4899
+ summary: "Configure OpenCode CLI to use the Poe API.",
4900
+ binaryName: "opencode",
4901
+ configPath: "~/.config/opencode/config.json",
4902
+ branding: {
4903
+ colors: {
4904
+ dark: "#4A4F55",
4905
+ light: "#2F3338"
4906
+ }
4907
+ }
4908
+ };
4909
+
4910
+ // packages/agent-defs/src/agents/kimi.ts
4911
+ var kimiAgent = {
4912
+ id: "kimi",
4913
+ name: "kimi",
4914
+ label: "Kimi",
4915
+ summary: "Configure Kimi CLI to use Poe API",
4916
+ aliases: ["kimi-cli"],
4917
+ binaryName: "kimi",
4918
+ configPath: "~/.kimi/config.toml",
4919
+ branding: {
4920
+ colors: {
4921
+ dark: "#7B68EE",
4922
+ light: "#6A5ACD"
4923
+ }
4654
4924
  }
4655
- const exitWaitController = new AbortController();
4656
- let aborted = signal.aborted;
4657
- const abortedPromise = new Promise((resolve2) => {
4658
- notifyAbort = resolve2;
4659
- });
4660
- const kill = () => {
4661
- aborted = true;
4662
- handle.kill("SIGTERM");
4663
- notifyAbort?.();
4664
- };
4665
- if (signal.aborted) {
4666
- kill();
4667
- } else {
4668
- signal.addEventListener("abort", kill, { once: true });
4925
+ };
4926
+
4927
+ // packages/agent-defs/src/agents/goose.ts
4928
+ var gooseAgent = {
4929
+ id: "goose",
4930
+ name: "goose",
4931
+ label: "Goose",
4932
+ summary: "Block's open-source AI agent with ACP support.",
4933
+ binaryName: "goose",
4934
+ configPath: "~/.config/goose/config.yaml",
4935
+ branding: {
4936
+ colors: {
4937
+ dark: "#FF6B35",
4938
+ light: "#E85D26"
4939
+ }
4669
4940
  }
4670
- return {
4671
- async waitForExit(env, jobId) {
4672
- if (aborted) {
4673
- return handle.result;
4674
- }
4675
- const exit = waitForExit(toLogStreamEnv(env), jobId, {
4676
- signal: exitWaitController.signal
4677
- }).then(
4678
- (value) => ({ kind: "exit", value }),
4679
- (error2) => ({ kind: "error", error: error2 })
4680
- );
4681
- const result = await Promise.race([
4682
- exit,
4683
- abortedPromise.then(() => ({ kind: "abort" }))
4684
- ]);
4685
- if (result.kind === "exit") {
4686
- return result.value;
4687
- }
4688
- if (result.kind === "error") {
4689
- throw result.error;
4690
- }
4691
- exitWaitController.abort();
4692
- return handle.result;
4693
- },
4694
- async waitForHandle() {
4695
- const result = await Promise.race([
4696
- handle.result.then((value) => ({ kind: "exit", value })),
4697
- abortedPromise.then(() => ({ kind: "abort" }))
4698
- ]);
4699
- if (result.kind === "exit") {
4700
- if (aborted) {
4701
- throw createAbortError2();
4702
- }
4703
- if (timedOut) {
4704
- throw createActivityTimeoutError(activityTimeoutMs);
4705
- }
4706
- return result.value;
4707
- }
4708
- if (timedOut) {
4709
- throw createActivityTimeoutError(activityTimeoutMs);
4710
- }
4711
- throw createAbortError2();
4712
- },
4713
- resetActivityTimer,
4714
- dispose() {
4715
- if (activityTimer) clearTimeout(activityTimer);
4716
- exitWaitController.abort();
4717
- signal.removeEventListener("abort", kill);
4941
+ };
4942
+
4943
+ // packages/agent-defs/src/agents/poe-agent.ts
4944
+ var poeAgentAgent = {
4945
+ id: "poe-agent",
4946
+ name: "poe-agent",
4947
+ label: "Poe Agent",
4948
+ summary: "Run one-shot prompts with the built-in Poe agent runtime.",
4949
+ configPath: "~/.poe-code/config.json",
4950
+ branding: {
4951
+ colors: {
4952
+ dark: "#A465F7",
4953
+ light: "#7A3FD3"
4954
+ }
4955
+ }
4956
+ };
4957
+
4958
+ // packages/agent-defs/src/registry.ts
4959
+ var allAgents = [
4960
+ claudeCodeAgent,
4961
+ claudeDesktopAgent,
4962
+ codexAgent,
4963
+ openCodeAgent,
4964
+ kimiAgent,
4965
+ gooseAgent,
4966
+ poeAgentAgent
4967
+ ];
4968
+ var lookup = /* @__PURE__ */ new Map();
4969
+ for (const agent of allAgents) {
4970
+ const values = [agent.id, agent.name, ...agent.aliases ?? []];
4971
+ for (const value of values) {
4972
+ const normalized = value.toLowerCase();
4973
+ if (!lookup.has(normalized)) {
4974
+ lookup.set(normalized, agent.id);
4718
4975
  }
4719
- };
4720
- }
4721
- function toLogStreamEnv(env) {
4722
- const candidate = env;
4723
- return candidate.fs === void 0 ? {} : { fs: candidate.fs };
4724
- }
4725
- function setDetachedJobContext(env, context) {
4726
- const candidate = env;
4727
- candidate.setDetachedJobContext?.(context);
4728
- }
4729
- function isPromiseLike(value) {
4730
- return typeof value.then === "function";
4731
- }
4732
- function createAbortError2() {
4733
- const error2 = new Error("Agent spawn aborted");
4734
- error2.name = "AbortError";
4735
- return error2;
4736
- }
4737
- function createActivityTimeoutError(timeoutMs) {
4738
- const error2 = new Error(`Agent spawn timed out after ${timeoutMs / 1e3}s of inactivity`);
4739
- error2.name = "ActivityTimeoutError";
4740
- return error2;
4741
- }
4742
- function createUlid() {
4743
- const time = BigInt(Date.now());
4744
- const random = randomBytes(10);
4745
- let randomValue = 0n;
4746
- for (const byte of random) {
4747
- randomValue = randomValue << 8n | BigInt(byte);
4748
4976
  }
4749
- return encodeBase32(time, 10) + encodeBase32(randomValue, 16);
4750
4977
  }
4751
- function encodeBase32(value, length) {
4752
- const chars = Array.from({ length }, () => "0");
4753
- let remaining = value;
4754
- for (let index = length - 1; index >= 0; index -= 1) {
4755
- chars[index] = ULID_ALPHABET[Number(remaining & 31n)];
4756
- remaining >>= 5n;
4978
+ function resolveAgentId(input) {
4979
+ if (!input) {
4980
+ return void 0;
4757
4981
  }
4758
- return chars.join("");
4982
+ return lookup.get(input.toLowerCase());
4759
4983
  }
4760
4984
 
4761
- // packages/agent-harness-tools/src/poe-command-execution.ts
4762
- import { existsSync as existsSync2, readFileSync } from "node:fs";
4763
- import os3 from "node:os";
4985
+ // packages/agent-harness-tools/src/select-agent.ts
4986
+ var loopAgents = allAgents.filter(
4987
+ (agent) => agent.binaryName !== void 0 || agent.id === "poe-agent"
4988
+ );
4989
+ var supportedAgents = loopAgents.map((agent) => agent.id).join(", ");
4764
4990
 
4765
- // packages/agent-harness-tools/src/execution-env.ts
4766
- var executionEnvFactories = /* @__PURE__ */ new Map();
4767
- function registerExecutionEnvFactory(factory) {
4768
- executionEnvFactories.set(factory.type, factory);
4991
+ // packages/agent-harness-tools/src/run-logs.ts
4992
+ import path28 from "node:path";
4993
+
4994
+ // packages/agent-harness-tools/src/log-stream.ts
4995
+ import nodeFs2 from "node:fs";
4996
+ var JOB_DIR = "/tmp/poe-jobs";
4997
+ var POLL_INTERVAL_MS = 250;
4998
+ function wrapForLogTee(argv, jobId) {
4999
+ if (argv.length === 0) {
5000
+ throw new Error("wrapForLogTee requires argv to contain at least one argument");
5001
+ }
5002
+ const command = argv.map(shellQuote2).join(" ");
5003
+ const logFile = shellQuote2(jobLogPath(jobId));
5004
+ const exitFile = shellQuote2(jobExitPath(jobId));
5005
+ const exitTmpFile = shellQuote2(`${jobExitPath(jobId)}.tmp`);
5006
+ const script = [
5007
+ `mkdir -p ${shellQuote2(JOB_DIR)}`,
5008
+ `({ (${command}); echo $? > ${exitTmpFile}; } 2>&1 | tee ${logFile}; mv ${exitTmpFile} ${exitFile})`
5009
+ ].join(" && ");
5010
+ return ["sh", "-c", script];
4769
5011
  }
4770
- function selectExecutionEnv(runtime) {
4771
- return selectExecutionEnvFactory(runtime.type);
5012
+ async function* streamLogFile(env, jobId, opts) {
5013
+ const fs14 = env.fs ?? nodeFs2;
5014
+ const file = jobLogPath(jobId);
5015
+ let byteOffset = opts.sinceByte ?? 0;
5016
+ while (true) {
5017
+ if (opts.since !== void 0 && !await wasModifiedSince(fs14, file, opts.since)) {
5018
+ await waitForLogChange(fs14, file);
5019
+ continue;
5020
+ }
5021
+ const result = await readLogChunk(fs14, file, byteOffset);
5022
+ if (result !== null) {
5023
+ byteOffset = result.nextByteOffset;
5024
+ yield result.chunk;
5025
+ continue;
5026
+ }
5027
+ await waitForLogChange(fs14, file);
5028
+ }
4772
5029
  }
4773
- function selectExecutionEnvFactory(type) {
4774
- const factory = executionEnvFactories.get(type);
4775
- if (factory === void 0) {
4776
- throw new Error(
4777
- `No execution environment factory registered for runtime type "${type}".`
4778
- );
5030
+ async function wasModifiedSince(fs14, file, since) {
5031
+ if (fs14.promises.stat === void 0) {
5032
+ return true;
5033
+ }
5034
+ try {
5035
+ const stat7 = await fs14.promises.stat(file);
5036
+ return stat7.mtimeMs >= since.getTime();
5037
+ } catch (error2) {
5038
+ if (isNodeError(error2) && error2.code === "ENOENT") {
5039
+ return false;
5040
+ }
5041
+ throw error2;
4779
5042
  }
4780
- return factory;
4781
5043
  }
4782
-
4783
- // packages/agent-harness-tools/src/poe-command-execution.ts
4784
- function resolvePoeCommandExecution(input) {
4785
- const homeDir = input.context?.homeDir ?? os3.homedir();
4786
- const runtimeConfigCwd = input.runtimeConfigCwd ?? input.cwd;
4787
- const loaded = loadRuntimeConfig(runtimeConfigCwd, homeDir);
4788
- const config = applyRuntimeOverrides(loaded, input.runtime, runtimeConfigCwd);
4789
- const resolved = resolveRuntime({ cwd: runtimeConfigCwd, config });
4790
- const factory = selectExecutionEnv(resolved.runtime);
4791
- const state = input.context?.state ?? loadState(homeDir);
4792
- return {
4793
- factory,
4794
- detach: factory.supportsDetach === true && config.runner.detach,
4795
- state,
4796
- openSpec: {
4797
- cwd: input.cwd,
4798
- runtimeCwd: runtimeConfigCwd,
4799
- runtime: resolved.runtime,
4800
- runner: config.runner,
4801
- state,
4802
- env: input.env,
4803
- uploadIgnoreFiles: config.runner.workspace?.exclude ?? [],
4804
- jobLabel: {
4805
- tool: input.tool,
4806
- argv: input.argv
4807
- },
4808
- ...input.openSpec
5044
+ async function waitForExit(env, jobId, opts = {}) {
5045
+ const fs14 = env.fs ?? nodeFs2;
5046
+ const file = jobExitPath(jobId);
5047
+ while (true) {
5048
+ throwIfAborted2(opts.signal);
5049
+ const contents = await readTextFileIfExists(fs14, file);
5050
+ if (contents !== null) {
5051
+ const text5 = contents.trim();
5052
+ const exitCode = Number(text5);
5053
+ if (text5.length === 0 || !Number.isInteger(exitCode)) {
5054
+ throw new Error(`Invalid exit code in ${file}: ${contents}`);
5055
+ }
5056
+ return { exitCode };
4809
5057
  }
4810
- };
4811
- }
4812
- function applyRuntimeOverrides(config, overrides, cwd = process.cwd()) {
4813
- if (!overrides) {
4814
- return { runtime: config.runtime, runner: config.runner };
5058
+ await sleep3(POLL_INTERVAL_MS, opts.signal);
4815
5059
  }
4816
- const base = "rawScope" in config && config.rawScope ? { ...config.rawScope } : { ...config.runtime };
4817
- const runtime = parseRuntime({
4818
- ...base,
4819
- ...overrides.runtime !== void 0 ? { type: overrides.runtime } : {},
4820
- ...overrides.runtimeImage !== void 0 ? { image: overrides.runtimeImage } : {},
4821
- ...overrides.runtimeTemplate !== void 0 ? { template_id: overrides.runtimeTemplate } : {},
4822
- ...overrides.mountPoeCode === true ? { mounts: [...config.runtime.mounts, createPoeCodeMount(cwd)] } : {}
4823
- });
4824
- return {
4825
- runtime,
4826
- runner: {
4827
- ...config.runner,
4828
- ...overrides.detach === true ? { detach: true } : {},
4829
- ...overrides.runnerSync !== void 0 ? { sync: overrides.runnerSync } : {}
4830
- }
4831
- };
4832
5060
  }
4833
- function createPoeCodeMount(cwd) {
4834
- return {
4835
- source: cwd,
4836
- target: "/usr/local/lib/poe-code",
4837
- readonly: true
4838
- };
5061
+ function jobLogPath(jobId) {
5062
+ return `${JOB_DIR}/${jobId}.log`;
4839
5063
  }
4840
- function loadRuntimeConfig(cwd, homeDir) {
4841
- const document = deepMergeDocuments(
4842
- readConfigDocument(resolveConfigPath(homeDir)),
4843
- readConfigDocument(resolveProjectConfigPath(cwd))
4844
- );
4845
- const runtimeScope = resolveScope(runtimeConfigScope.schema, document.runtime, process.env);
5064
+ function jobExitPath(jobId) {
5065
+ return `${JOB_DIR}/${jobId}.exit`;
5066
+ }
5067
+ async function readLogChunk(fs14, file, byteOffset) {
5068
+ const contents = await readFileIfExists2(fs14, file);
5069
+ if (contents === null || byteOffset >= contents.byteLength) {
5070
+ return null;
5071
+ }
4846
5072
  return {
4847
- rawScope: { ...runtimeScope },
4848
- runtime: parseRuntime(runtimeScope),
4849
- runner: runtimeScope.runner
5073
+ chunk: {
5074
+ byteOffset,
5075
+ data: contents.subarray(byteOffset).toString("utf8")
5076
+ },
5077
+ nextByteOffset: contents.byteLength
4850
5078
  };
4851
5079
  }
4852
- function readConfigDocument(filePath) {
4853
- if (!existsSync2(filePath)) {
4854
- return {};
5080
+ async function readTextFileIfExists(fs14, file) {
5081
+ const contents = await readFileIfExists2(fs14, file);
5082
+ return contents?.toString("utf8") ?? null;
5083
+ }
5084
+ async function readFileIfExists2(fs14, file) {
5085
+ try {
5086
+ const contents = await fs14.promises.readFile(file);
5087
+ return Buffer.isBuffer(contents) ? contents : Buffer.from(contents);
5088
+ } catch (error2) {
5089
+ if (isNodeError(error2) && error2.code === "ENOENT") {
5090
+ return null;
5091
+ }
5092
+ throw error2;
4855
5093
  }
4856
- return JSON.parse(readFileSync(filePath, "utf8"));
4857
5094
  }
4858
- function loadState(homeDir) {
4859
- if (process.env.VITEST === "true") {
4860
- return createMemoryStateManager();
5095
+ async function waitForLogChange(fs14, file) {
5096
+ const watch = fs14.watch;
5097
+ if (typeof watch !== "function") {
5098
+ await sleep3(POLL_INTERVAL_MS);
5099
+ return;
4861
5100
  }
4862
- return createStateManager(homeDir);
5101
+ await new Promise((resolve2) => {
5102
+ let watcher = null;
5103
+ const timer = setTimeout(done, POLL_INTERVAL_MS);
5104
+ function done() {
5105
+ clearTimeout(timer);
5106
+ watcher?.close();
5107
+ resolve2();
5108
+ }
5109
+ try {
5110
+ watcher = watch(file, done);
5111
+ } catch {
5112
+ done();
5113
+ }
5114
+ });
4863
5115
  }
4864
- function createMemoryStateManager() {
4865
- const jobs = /* @__PURE__ */ new Map();
4866
- return {
4867
- templates: {
4868
- async get() {
4869
- return null;
4870
- },
4871
- async put() {
4872
- },
4873
- async remove() {
4874
- },
4875
- async list() {
4876
- return [];
4877
- }
4878
- },
4879
- jobs: {
4880
- async get(id) {
4881
- return jobs.get(id) ?? null;
4882
- },
4883
- async put(entry) {
4884
- jobs.set(entry.id, entry);
4885
- },
4886
- async update(id, patch) {
4887
- const current = jobs.get(id);
4888
- if (!current) {
4889
- return null;
4890
- }
4891
- const updated = { ...current, ...patch, id };
4892
- jobs.set(id, updated);
4893
- return updated;
4894
- },
4895
- async list(filter) {
4896
- const entries = Array.from(jobs.values());
4897
- if (!filter) {
4898
- return entries;
4899
- }
4900
- return entries.filter(
4901
- (entry) => Object.entries(filter).every(([key, value]) => entry[key] === value)
4902
- );
4903
- },
4904
- async remove(id) {
4905
- jobs.delete(id);
5116
+ function sleep3(ms, signal) {
5117
+ return new Promise((resolve2, reject) => {
5118
+ let timer = null;
5119
+ const abort = () => {
5120
+ if (timer !== null) {
5121
+ clearTimeout(timer);
4906
5122
  }
5123
+ reject(new Error("waitForExit aborted."));
5124
+ };
5125
+ if (signal?.aborted) {
5126
+ abort();
5127
+ return;
4907
5128
  }
4908
- };
5129
+ timer = setTimeout(() => {
5130
+ signal?.removeEventListener("abort", abort);
5131
+ resolve2();
5132
+ }, ms);
5133
+ signal?.addEventListener("abort", abort, { once: true });
5134
+ });
5135
+ }
5136
+ function throwIfAborted2(signal) {
5137
+ if (signal?.aborted) {
5138
+ throw new Error("waitForExit aborted.");
5139
+ }
5140
+ }
5141
+ function shellQuote2(value) {
5142
+ return `'${value.replaceAll("'", "'\\''")}'`;
5143
+ }
5144
+ function isNodeError(error2) {
5145
+ return error2 instanceof Error && "code" in error2;
4909
5146
  }
4910
5147
 
4911
- // packages/agent-harness-tools/src/workspace-transfer.ts
4912
- import { createHash as createHash3 } from "node:crypto";
4913
- import { promises as nodeFs3 } from "node:fs";
4914
- import path24 from "node:path";
5148
+ // packages/agent-harness-tools/src/run-poe-command.ts
5149
+ import { randomBytes as randomBytes3 } from "node:crypto";
4915
5150
 
4916
- // packages/process-runner/src/docker/context.ts
4917
- import { execSync } from "node:child_process";
4918
- function detectContext() {
5151
+ // packages/agent-harness-tools/src/binary-exists.ts
5152
+ function createBinaryExistsDetectors(binaryName) {
5153
+ const commonPaths = [
5154
+ `/usr/local/bin/${binaryName}`,
5155
+ `/usr/bin/${binaryName}`,
5156
+ `$HOME/.local/bin/${binaryName}`,
5157
+ `$HOME/.claude/local/bin/${binaryName}`
5158
+ ];
5159
+ return [
5160
+ {
5161
+ command: "which",
5162
+ args: [binaryName],
5163
+ validate: (result) => result.exitCode === 0
5164
+ },
5165
+ {
5166
+ command: "where",
5167
+ args: [binaryName],
5168
+ validate: (result) => result.exitCode === 0 && result.stdout.trim().length > 0
5169
+ },
5170
+ {
5171
+ command: "sh",
5172
+ args: ["-c", commonPaths.map((p) => `test -f "${p}"`).join(" || ")],
5173
+ validate: (result) => result.exitCode === 0
5174
+ }
5175
+ ];
5176
+ }
5177
+
5178
+ // packages/agent-harness-tools/src/run-poe-command.ts
5179
+ var ULID_ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
5180
+ async function runPoeCommand(opts) {
5181
+ const jobId = createUlid();
5182
+ const execution = opts.openSpec.execution;
5183
+ const wrapCommand = execution?.wrapForLogTee !== false;
5184
+ const pendingJob = opts.state.jobs.put({
5185
+ id: jobId,
5186
+ env_id: "",
5187
+ env_kind: opts.factory.type,
5188
+ tool: opts.openSpec.jobLabel.tool,
5189
+ argv: opts.openSpec.jobLabel.argv,
5190
+ cwd: opts.openSpec.cwd,
5191
+ started_at: "",
5192
+ status: "pending"
5193
+ });
5194
+ const opened = opts.factory.open(opts.openSpec);
5195
+ const env = isPromiseLike(opened) ? await opened : opened;
5196
+ let shouldClose = true;
4919
5197
  try {
4920
- const output = execSync("colima list --json", {
4921
- encoding: "utf-8",
4922
- stdio: ["pipe", "pipe", "ignore"]
5198
+ const upload = env.uploadWorkspace();
5199
+ await Promise.all([pendingJob, upload]);
5200
+ await configureE2bSpawnAgentIfAvailable({
5201
+ env,
5202
+ openSpec: opts.openSpec,
5203
+ factoryType: opts.factory.type
5204
+ });
5205
+ const argv = wrapCommand ? wrapForLogTee(opts.openSpec.jobLabel.argv, jobId) : opts.openSpec.jobLabel.argv;
5206
+ const handle = execution?.tty ? env.shell() : env.exec({
5207
+ command: argv[0],
5208
+ args: argv.slice(1),
5209
+ cwd: opts.openSpec.cwd,
5210
+ env: resolveExecutionEnv(opts.openSpec),
5211
+ stdin: execution?.stdin ?? "inherit",
5212
+ stdout: execution?.stdout ?? "pipe",
5213
+ stderr: execution?.stderr ?? "pipe",
5214
+ signal: opts.signal
5215
+ });
5216
+ if (execution?.input !== void 0) {
5217
+ handle.stdin?.setDefaultEncoding("utf8");
5218
+ handle.stdin?.end(execution.input);
5219
+ }
5220
+ const runningJob = opts.state.jobs.update(jobId, {
5221
+ status: "running",
5222
+ env_id: env.id,
5223
+ started_at: (/* @__PURE__ */ new Date()).toISOString()
5224
+ });
5225
+ if (opts.detach) {
5226
+ await runningJob;
5227
+ setDetachedJobContext(env, {
5228
+ id: jobId,
5229
+ tool: opts.openSpec.jobLabel.tool,
5230
+ argv: opts.openSpec.jobLabel.argv
5231
+ });
5232
+ await env.detach();
5233
+ shouldClose = false;
5234
+ return { kind: "detached", jobId, envId: env.id };
5235
+ }
5236
+ const result = await runSync({
5237
+ env,
5238
+ handle,
5239
+ jobId,
5240
+ openSpec: opts.openSpec,
5241
+ signal: opts.signal,
5242
+ wrapCommand
4923
5243
  });
4924
- const lines = output.trim().split("\n").filter(Boolean);
4925
- for (const line of lines) {
4926
- const profile = JSON.parse(line);
4927
- if (profile.status === "Running" && profile.runtime === "docker") {
4928
- const name = profile.name ?? profile.profile;
4929
- if (!name) {
4930
- continue;
4931
- }
4932
- return name === "default" ? "colima" : `colima-${name}`;
4933
- }
5244
+ await runningJob;
5245
+ shouldClose = false;
5246
+ await opts.state.jobs.update(jobId, {
5247
+ status: "exited",
5248
+ exit_code: result.exitCode,
5249
+ exited_at: (/* @__PURE__ */ new Date()).toISOString()
5250
+ });
5251
+ return {
5252
+ kind: "sync",
5253
+ exitCode: result.exitCode,
5254
+ download: result.download,
5255
+ ...result.stdout !== void 0 ? { stdout: result.stdout } : {},
5256
+ ...result.stderr !== void 0 ? { stderr: result.stderr } : {}
5257
+ };
5258
+ } finally {
5259
+ if (shouldClose) {
5260
+ await env.close();
4934
5261
  }
4935
- } catch {
4936
- return null;
4937
5262
  }
4938
- return null;
4939
5263
  }
4940
- function buildContextArgs(engine, context) {
4941
- if (engine === "docker" && context) {
4942
- return ["--context", context];
5264
+ async function configureE2bSpawnAgentIfAvailable(opts) {
5265
+ if (opts.factoryType !== "e2b") {
5266
+ return;
4943
5267
  }
4944
- return [];
4945
- }
4946
-
4947
- // packages/process-runner/src/docker/engine.ts
4948
- import { execSync as execSync2 } from "node:child_process";
4949
- function detectEngine() {
4950
- if (isEngineAvailable("docker")) {
4951
- return "docker";
5268
+ const agentId = resolveAgentId(opts.openSpec.jobLabel.tool);
5269
+ const agent = allAgents.find((candidate) => candidate.id === agentId);
5270
+ const binaryName = agent?.binaryName;
5271
+ if (!agentId || !binaryName) {
5272
+ return;
4952
5273
  }
4953
- if (isEngineAvailable("podman")) {
4954
- return "podman";
5274
+ const commandEnv = resolveExecutionEnv(opts.openSpec);
5275
+ const exists = await binaryExists(opts.env, {
5276
+ binaryName,
5277
+ cwd: opts.openSpec.cwd,
5278
+ env: commandEnv
5279
+ });
5280
+ if (!exists) {
5281
+ return;
5282
+ }
5283
+ const result = await runProbeCommand(opts.env, {
5284
+ command: "poe-code",
5285
+ args: ["configure", "--yes", "--provider", "poe", agentId],
5286
+ cwd: opts.openSpec.cwd,
5287
+ env: commandEnv
5288
+ });
5289
+ if (result.exitCode !== 0) {
5290
+ throw new Error(
5291
+ `Failed to configure ${agentId} for Poe inside E2B sandbox.
5292
+ ${formatProbeResult(result)}`
5293
+ );
4955
5294
  }
4956
- throw new Error(
4957
- "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"
4958
- );
4959
5295
  }
4960
- function isEngineAvailable(engine) {
4961
- try {
4962
- execSync2(`${engine} --version`, {
4963
- stdio: "ignore"
5296
+ async function binaryExists(env, opts) {
5297
+ for (const detector of createBinaryExistsDetectors(opts.binaryName)) {
5298
+ const result = await runProbeCommand(env, {
5299
+ ...detector,
5300
+ cwd: opts.cwd,
5301
+ env: opts.env
4964
5302
  });
4965
- return true;
4966
- } catch {
4967
- return false;
5303
+ if (detector.validate(result)) {
5304
+ return true;
5305
+ }
4968
5306
  }
5307
+ return false;
4969
5308
  }
4970
-
4971
- // packages/process-runner/src/docker/docker-runner.ts
4972
- import * as childProcess from "node:child_process";
4973
- import { randomBytes as randomBytes2 } from "node:crypto";
4974
-
4975
- // packages/process-runner/src/docker/args.ts
4976
- import path25 from "node:path";
4977
- function buildDockerRunArgs(input) {
4978
- const args = [input.engine];
4979
- if (input.engine === "docker" && input.context) {
4980
- args.push("--context", input.context);
4981
- }
4982
- args.push("run");
4983
- if (input.rm) {
4984
- args.push("--rm");
4985
- }
4986
- if (input.detached) {
4987
- args.push("-d");
4988
- }
4989
- if (input.interactive) {
4990
- args.push("-i");
4991
- }
4992
- if (input.tty) {
4993
- args.push("-t");
4994
- }
4995
- args.push("--name", input.containerName);
4996
- if (input.cwd !== void 0) {
4997
- args.push("-w", input.cwd);
4998
- }
4999
- for (const [key, value] of Object.entries(input.env ?? {})) {
5000
- args.push("-e", `${key}=${value}`);
5001
- }
5002
- for (const mount of input.mounts) {
5003
- const volume = `${path25.resolve(mount.source)}:${mount.target}${mount.readonly ? ":ro" : ""}`;
5004
- args.push("-v", volume);
5005
- }
5006
- for (const port of input.ports) {
5007
- const mapping = `${port.host}:${port.container}${port.protocol === void 0 || port.protocol === "tcp" ? "" : `/${port.protocol}`}`;
5008
- args.push("-p", mapping);
5009
- }
5010
- if (input.network !== void 0) {
5011
- args.push("--network", input.network);
5012
- }
5013
- args.push(...input.extraArgs, input.image, input.command, ...input.args);
5014
- return args;
5309
+ function resolveExecutionEnv(openSpec) {
5310
+ const execution = openSpec.execution;
5311
+ return execution?.env ?? openSpec.env;
5015
5312
  }
5016
-
5017
- // packages/process-runner/src/docker/docker-execution-env.ts
5018
- import { createHash as createHash4, randomBytes as randomBytes3 } from "node:crypto";
5019
- import { mkdtempSync, rmSync } from "node:fs";
5020
- import { readFile as readFile10 } from "node:fs/promises";
5021
- import { tmpdir } from "node:os";
5022
- import path26 from "node:path";
5023
-
5024
- // packages/process-runner/src/host/host-runner.ts
5025
- import { spawn as spawnChildProcess } from "node:child_process";
5026
- function createHostRunner(options = {}) {
5027
- const detached = options.detached === true;
5313
+ async function runProbeCommand(env, spec) {
5314
+ const handle = env.exec({
5315
+ command: spec.command,
5316
+ args: spec.args,
5317
+ cwd: spec.cwd,
5318
+ env: spec.env,
5319
+ stdin: "ignore",
5320
+ stdout: "pipe",
5321
+ stderr: "pipe"
5322
+ });
5323
+ const stdout = readStream2(handle.stdout);
5324
+ const stderr = readStream2(handle.stderr);
5325
+ const result = await handle.result;
5028
5326
  return {
5029
- name: "host",
5030
- exec(spec) {
5031
- const stdinMode = spec.stdin ?? "ignore";
5032
- const stdoutMode = spec.stdout ?? "pipe";
5033
- const stderrMode = spec.stderr ?? "pipe";
5034
- const stdio = stdinMode === "inherit" && stdoutMode === "inherit" && stderrMode === "inherit" ? "inherit" : [stdinMode, stdoutMode, stderrMode];
5035
- const child = spawnChildProcess(spec.command, spec.args ?? [], {
5036
- cwd: spec.cwd,
5037
- env: spec.env,
5038
- stdio,
5039
- ...detached ? { detached: true } : {}
5040
- });
5041
- if (detached) {
5042
- child.unref();
5043
- }
5044
- const kill = (signal) => {
5045
- if (detached && process.platform !== "win32" && child.pid !== void 0) {
5046
- process.kill(-child.pid, signal);
5047
- return;
5048
- }
5049
- child.kill(signal);
5050
- };
5051
- let settled = false;
5052
- let resolveResult = null;
5053
- const result = new Promise((resolve2) => {
5054
- resolveResult = resolve2;
5055
- });
5056
- const cleanupAbort = bindAbortSignal(spec.signal, () => {
5057
- kill("SIGTERM");
5058
- });
5059
- child.once("close", (code) => {
5060
- if (settled) return;
5061
- settled = true;
5062
- cleanupAbort();
5063
- resolveResult?.({ exitCode: code ?? 1 });
5064
- });
5065
- child.once("error", () => {
5066
- if (settled) return;
5067
- settled = true;
5068
- cleanupAbort();
5069
- resolveResult?.({ exitCode: 1 });
5070
- });
5071
- return {
5072
- pid: child.pid ?? null,
5073
- stdin: child.stdin,
5074
- stdout: child.stdout,
5075
- stderr: child.stderr,
5076
- result,
5077
- kill
5078
- };
5327
+ exitCode: result.exitCode,
5328
+ stdout: await stdout,
5329
+ stderr: await stderr
5330
+ };
5331
+ }
5332
+ function readStream2(stream) {
5333
+ if (!stream) {
5334
+ return Promise.resolve("");
5335
+ }
5336
+ return new Promise((resolve2, reject) => {
5337
+ let output = "";
5338
+ stream.setEncoding("utf8");
5339
+ stream.on("data", (chunk) => {
5340
+ output += chunk.toString();
5341
+ });
5342
+ stream.on("error", reject);
5343
+ stream.on("end", () => resolve2(output));
5344
+ });
5345
+ }
5346
+ function formatProbeResult(result) {
5347
+ return [
5348
+ `Exit code: ${result.exitCode}`,
5349
+ result.stdout.trim() ? `stdout:
5350
+ ${result.stdout.trim()}` : "",
5351
+ result.stderr.trim() ? `stderr:
5352
+ ${result.stderr.trim()}` : ""
5353
+ ].filter(Boolean).join("\n");
5354
+ }
5355
+ async function runSync(opts) {
5356
+ const execution = opts.openSpec.execution;
5357
+ const capture = execution?.captureOutput === true;
5358
+ const abort = createAbortSync(opts.signal, opts.handle, execution?.activityTimeoutMs);
5359
+ const streamState = capture ? captureRunStreams(opts.handle, execution, abort.resetActivityTimer) : pipeRunStreams(opts.handle);
5360
+ abort.resetActivityTimer();
5361
+ try {
5362
+ const { exitCode } = opts.wrapCommand ? await abort.waitForExit(opts.env, opts.jobId) : await abort.waitForHandle();
5363
+ const download = await opts.env.downloadWorkspace({
5364
+ conflictPolicy: opts.openSpec.runner?.download_conflict ?? "refuse"
5365
+ });
5366
+ if (opts.closeAfterDownload !== false) {
5367
+ await opts.env.close();
5079
5368
  }
5080
- };
5081
- }
5082
- function bindAbortSignal(signal, onAbort) {
5083
- if (signal === void 0) {
5084
- return () => {
5085
- };
5086
- }
5087
- if (signal.aborted) {
5088
- onAbort();
5089
- return () => {
5369
+ return {
5370
+ exitCode,
5371
+ download,
5372
+ ...capture ? { stdout: streamState.stdout(), stderr: streamState.stderr() } : {}
5090
5373
  };
5374
+ } finally {
5375
+ abort.dispose();
5376
+ streamState.dispose();
5091
5377
  }
5092
- signal.addEventListener("abort", onAbort, { once: true });
5093
- return () => {
5094
- signal.removeEventListener("abort", onAbort);
5095
- };
5096
5378
  }
5097
-
5098
- // packages/process-runner/src/docker/docker-execution-env.ts
5099
- var containerCommand = ["sh", "-c", "while :; do sleep 3600; done"];
5100
- var dockerExecutionEnvFactory = {
5101
- type: "docker",
5102
- supportsDetach: true,
5103
- async open(spec) {
5104
- const runtime = parseDockerRuntime(spec.runtime);
5105
- const runner = spec.hostRunner ?? createHostRunner();
5106
- const engine = runtime.engine ?? detectEngine();
5107
- const context = detectContext();
5108
- const image = await resolveImage({
5109
- spec,
5110
- runtime,
5111
- runner,
5112
- engine,
5113
- context
5114
- });
5115
- const containerName = createContainerName();
5116
- const runArgs = buildDockerRunArgs({
5117
- engine,
5118
- context,
5119
- image,
5120
- command: containerCommand[0],
5121
- args: containerCommand.slice(1),
5122
- cwd: void 0,
5123
- env: void 0,
5124
- mounts: runtime.mounts ?? [],
5125
- ports: [],
5126
- network: runtime.network,
5127
- containerName,
5128
- detached: true,
5129
- interactive: true,
5130
- tty: false,
5131
- rm: false,
5132
- extraArgs: runtime.extra_args ?? []
5133
- });
5134
- const [command, ...args] = runArgs;
5135
- const id = (await runAndRead(runner, { command, args, stdout: "pipe", stderr: "pipe" })).trim();
5136
- return createDockerEnv({
5137
- id,
5138
- spec,
5139
- runner,
5140
- engine,
5141
- context
5142
- });
5143
- },
5144
- async attach(envId, context) {
5145
- const engine = detectEngine();
5146
- return createDockerEnv({
5147
- id: envId,
5148
- spec: createAttachedSpec(context?.cwd),
5149
- runner: createHostRunner(),
5150
- engine,
5151
- context: detectContext(),
5152
- attachedJobId: context?.jobId
5153
- });
5154
- }
5155
- };
5156
- function createDockerEnv(input) {
5157
- const containerRef = input.id;
5379
+ function pipeRunStreams(handle) {
5380
+ handle.stdout?.pipe(process.stdout, { end: false });
5381
+ handle.stderr?.pipe(process.stderr, { end: false });
5158
5382
  return {
5159
- id: containerRef,
5160
- job: input.attachedJobId === void 0 ? null : createContainerJob(containerRef, input.runner, input.engine, input.context, input.attachedJobId),
5161
- async uploadWorkspace() {
5162
- const tempDir = mkdtempSync(path26.join(tmpdir(), "poe-docker-upload-"));
5163
- const archivePath = path26.join(tempDir, "workspace.tar");
5164
- try {
5165
- const excludeArgs = input.spec.uploadIgnoreFiles.flatMap((ignored) => [
5166
- "--exclude",
5167
- ignored
5168
- ]);
5169
- const tarArgs = [...excludeArgs, "-cf", archivePath, "-C", input.spec.cwd, "."];
5170
- await runOrThrow(input.runner, {
5171
- command: "tar",
5172
- args: tarArgs,
5173
- stdout: "pipe",
5174
- stderr: "pipe"
5175
- });
5176
- await runOrThrow(input.runner, {
5177
- command: input.engine,
5178
- args: [
5179
- ...buildContextArgs(input.engine, input.context),
5180
- "cp",
5181
- archivePath,
5182
- `${containerRef}:/tmp/poe-workspace-upload.tar`
5183
- ],
5184
- stdout: "pipe",
5185
- stderr: "pipe"
5186
- });
5187
- await runOrThrow(input.runner, {
5188
- command: input.engine,
5189
- args: [
5190
- ...buildContextArgs(input.engine, input.context),
5191
- "exec",
5192
- containerRef,
5193
- "sh",
5194
- "-c",
5195
- `mkdir -p ${shellQuote2(input.spec.cwd)} && tar -xf /tmp/poe-workspace-upload.tar -C ${shellQuote2(input.spec.cwd)}`
5196
- ],
5197
- stdout: "pipe",
5198
- stderr: "pipe"
5199
- });
5200
- return { files: 0, bytes: 0, skipped: [] };
5201
- } finally {
5202
- rmSync(tempDir, { recursive: true, force: true });
5203
- }
5204
- },
5205
- async downloadWorkspace(opts) {
5206
- const tempDir = mkdtempSync(path26.join(tmpdir(), "poe-docker-download-"));
5207
- const archivePath = path26.join(tempDir, "workspace.tar");
5208
- try {
5209
- await runOrThrow(input.runner, {
5210
- command: input.engine,
5211
- args: [
5212
- ...buildContextArgs(input.engine, input.context),
5213
- "exec",
5214
- containerRef,
5215
- "sh",
5216
- "-c",
5217
- `tar -cf /tmp/poe-workspace-download.tar -C ${shellQuote2(input.spec.cwd)} .`
5218
- ],
5219
- stdout: "pipe",
5220
- stderr: "pipe"
5221
- });
5222
- await runOrThrow(input.runner, {
5223
- command: input.engine,
5224
- args: [
5225
- ...buildContextArgs(input.engine, input.context),
5226
- "cp",
5227
- `${containerRef}:/tmp/poe-workspace-download.tar`,
5228
- archivePath
5229
- ],
5230
- stdout: "pipe",
5231
- stderr: "pipe"
5232
- });
5233
- const extractMode = opts.conflictPolicy === "refuse" ? "-xkf" : "-xf";
5234
- await runOrThrow(input.runner, {
5235
- command: "tar",
5236
- args: [extractMode, archivePath, "-C", input.spec.cwd],
5237
- stdout: "pipe",
5238
- stderr: "pipe"
5239
- });
5240
- return { files: 0, bytes: 0, conflicts: [] };
5241
- } finally {
5242
- rmSync(tempDir, { recursive: true, force: true });
5243
- }
5244
- },
5245
- exec(spec) {
5246
- return input.runner.exec({
5247
- command: input.engine,
5248
- args: [
5249
- ...buildContextArgs(input.engine, input.context),
5250
- "exec",
5251
- ...spec.stdin === "pipe" || spec.stdin === "inherit" ? ["-i"] : [],
5252
- ...spec.tty === true ? ["-t"] : [],
5253
- ...spec.cwd !== void 0 ? ["-w", spec.cwd] : [],
5254
- ...buildEnvArgs(spec.env),
5255
- containerRef,
5256
- spec.command,
5257
- ...spec.args ?? []
5258
- ],
5259
- stdin: spec.stdin,
5260
- stdout: spec.stdout,
5261
- stderr: spec.stderr,
5262
- tty: spec.tty
5263
- });
5264
- },
5265
- async detach() {
5266
- return createContainerJob(containerRef, input.runner, input.engine, input.context);
5267
- },
5268
- shell() {
5269
- const shellSpec = input.spec.shellSpec;
5270
- return this.exec({
5271
- command: shellSpec?.command ?? input.spec.env.SHELL ?? "sh",
5272
- ...shellSpec?.args ? { args: shellSpec.args } : {},
5273
- cwd: input.spec.cwd,
5274
- env: shellSpec && "env" in shellSpec ? shellSpec.env : input.spec.env,
5275
- stdin: "inherit",
5276
- stdout: "inherit",
5277
- stderr: "inherit",
5278
- tty: true
5279
- });
5280
- },
5281
- async close() {
5282
- await runOrThrow(input.runner, {
5283
- command: input.engine,
5284
- args: [...buildContextArgs(input.engine, input.context), "rm", "-f", containerRef],
5285
- stdout: "pipe",
5286
- stderr: "pipe"
5287
- });
5383
+ stdout: () => "",
5384
+ stderr: () => "",
5385
+ dispose() {
5386
+ handle.stdout?.unpipe(process.stdout);
5387
+ handle.stderr?.unpipe(process.stderr);
5288
5388
  }
5289
5389
  };
5290
5390
  }
5291
- async function resolveImage(input) {
5292
- if (input.runtime.image !== void 0) {
5293
- return input.runtime.image;
5294
- }
5295
- const result = await buildDockerRuntimeTemplate({
5296
- cwd: input.spec.cwd,
5297
- runtime: input.runtime,
5298
- state: input.spec.state,
5299
- runner: input.runner
5391
+ function captureRunStreams(handle, execution, onActivity) {
5392
+ let stdout = "";
5393
+ let stderr = "";
5394
+ const listeners = [];
5395
+ const bind = (stream, onChunk) => {
5396
+ if (!stream) return;
5397
+ stream.setEncoding("utf8");
5398
+ const listener = (chunk) => {
5399
+ onActivity();
5400
+ onChunk(chunk.toString());
5401
+ };
5402
+ stream.on("data", listener);
5403
+ listeners.push(() => {
5404
+ stream.off("data", listener);
5405
+ });
5406
+ };
5407
+ bind(handle.stdout, (chunk) => {
5408
+ stdout += chunk;
5409
+ execution?.onStdout?.(chunk);
5300
5410
  });
5301
- return result.image;
5411
+ bind(handle.stderr, (chunk) => {
5412
+ stderr += chunk;
5413
+ execution?.onStderr?.(chunk);
5414
+ });
5415
+ return {
5416
+ stdout: () => stdout,
5417
+ stderr: () => stderr,
5418
+ dispose() {
5419
+ for (const remove2 of listeners) {
5420
+ remove2();
5421
+ }
5422
+ }
5423
+ };
5302
5424
  }
5303
- async function buildDockerRuntimeTemplate(input) {
5304
- const runner = input.runner ?? createHostRunner();
5305
- const engine = input.runtime.engine ?? detectEngine();
5306
- const context = detectContext();
5307
- const dockerfilePath = path26.resolve(
5308
- input.cwd,
5309
- input.runtime.dockerfile ?? path26.join(".poe-code", "Dockerfile")
5310
- );
5311
- const buildContext = path26.resolve(input.cwd, input.runtime.build_context ?? ".");
5312
- const dockerfileBytes = await readFile10(dockerfilePath);
5313
- const hash = hashDockerTemplate(dockerfileBytes, input.runtime.build_args ?? {});
5314
- const cached2 = input.force ? null : await input.state?.templates.get("docker", hash);
5315
- if (cached2?.image !== void 0) {
5425
+ function createAbortSync(signal, handle, activityTimeoutMs) {
5426
+ let activityTimer;
5427
+ let timedOut = false;
5428
+ const resetActivityTimer = activityTimeoutMs ? () => {
5429
+ if (activityTimer) clearTimeout(activityTimer);
5430
+ activityTimer = setTimeout(() => {
5431
+ timedOut = true;
5432
+ handle.kill("SIGTERM");
5433
+ notifyAbort?.();
5434
+ }, activityTimeoutMs);
5435
+ } : () => {
5436
+ };
5437
+ let notifyAbort;
5438
+ if (signal === void 0) {
5316
5439
  return {
5317
- backend: "docker",
5318
- hash,
5319
- image: cached2.image,
5320
- cached: true
5440
+ waitForExit: (env, jobId) => waitForExit(toLogStreamEnv(env), jobId),
5441
+ waitForHandle: async () => {
5442
+ const result = await handle.result;
5443
+ if (timedOut) {
5444
+ throw createActivityTimeoutError(activityTimeoutMs);
5445
+ }
5446
+ return result;
5447
+ },
5448
+ resetActivityTimer,
5449
+ dispose() {
5450
+ if (activityTimer) clearTimeout(activityTimer);
5451
+ }
5321
5452
  };
5322
5453
  }
5323
- const image = `poe-code/local:${hash}`;
5324
- await buildImage({
5325
- runner,
5326
- engine,
5327
- context,
5328
- image,
5329
- dockerfilePath,
5330
- buildContext,
5331
- buildArgs: input.runtime.build_args ?? {}
5332
- });
5333
- await input.state?.templates.put("docker", {
5334
- hash,
5335
- image,
5336
- runtime_type: "docker",
5337
- dockerfile_path: dockerfilePath,
5338
- built_at: (/* @__PURE__ */ new Date()).toISOString()
5454
+ const exitWaitController = new AbortController();
5455
+ let aborted = signal.aborted;
5456
+ const abortedPromise = new Promise((resolve2) => {
5457
+ notifyAbort = resolve2;
5339
5458
  });
5459
+ const kill = () => {
5460
+ aborted = true;
5461
+ handle.kill("SIGTERM");
5462
+ notifyAbort?.();
5463
+ };
5464
+ if (signal.aborted) {
5465
+ kill();
5466
+ } else {
5467
+ signal.addEventListener("abort", kill, { once: true });
5468
+ }
5340
5469
  return {
5341
- backend: "docker",
5342
- hash,
5343
- image,
5344
- cached: false
5470
+ async waitForExit(env, jobId) {
5471
+ if (aborted) {
5472
+ return handle.result;
5473
+ }
5474
+ const exit = waitForExit(toLogStreamEnv(env), jobId, {
5475
+ signal: exitWaitController.signal
5476
+ }).then(
5477
+ (value) => ({ kind: "exit", value }),
5478
+ (error2) => ({ kind: "error", error: error2 })
5479
+ );
5480
+ const result = await Promise.race([
5481
+ exit,
5482
+ abortedPromise.then(() => ({ kind: "abort" }))
5483
+ ]);
5484
+ if (result.kind === "exit") {
5485
+ return result.value;
5486
+ }
5487
+ if (result.kind === "error") {
5488
+ throw result.error;
5489
+ }
5490
+ exitWaitController.abort();
5491
+ return handle.result;
5492
+ },
5493
+ async waitForHandle() {
5494
+ const result = await Promise.race([
5495
+ handle.result.then((value) => ({ kind: "exit", value })),
5496
+ abortedPromise.then(() => ({ kind: "abort" }))
5497
+ ]);
5498
+ if (result.kind === "exit") {
5499
+ if (aborted) {
5500
+ throw createAbortError2();
5501
+ }
5502
+ if (timedOut) {
5503
+ throw createActivityTimeoutError(activityTimeoutMs);
5504
+ }
5505
+ return result.value;
5506
+ }
5507
+ if (timedOut) {
5508
+ throw createActivityTimeoutError(activityTimeoutMs);
5509
+ }
5510
+ throw createAbortError2();
5511
+ },
5512
+ resetActivityTimer,
5513
+ dispose() {
5514
+ if (activityTimer) clearTimeout(activityTimer);
5515
+ exitWaitController.abort();
5516
+ signal.removeEventListener("abort", kill);
5517
+ }
5345
5518
  };
5346
5519
  }
5347
- function hashDockerTemplate(dockerfileBytes, buildArgs) {
5348
- const hash = createHash4("sha256");
5349
- hash.update(dockerfileBytes);
5350
- hash.update("\0");
5351
- for (const [key, value] of sortedBuildArgs(buildArgs)) {
5352
- hash.update(key);
5353
- hash.update("=");
5354
- hash.update(value);
5355
- hash.update("\0");
5356
- }
5357
- return hash.digest("hex");
5520
+ function toLogStreamEnv(env) {
5521
+ const candidate = env;
5522
+ return candidate.fs === void 0 ? {} : { fs: candidate.fs };
5358
5523
  }
5359
- async function buildImage(input) {
5360
- await runOrThrow(input.runner, {
5361
- command: input.engine,
5362
- args: [
5363
- ...buildContextArgs(input.engine, input.context),
5364
- "build",
5365
- "--tag",
5366
- input.image,
5367
- "-f",
5368
- input.dockerfilePath,
5369
- ...sortedBuildArgs(input.buildArgs).flatMap(([key, value]) => [
5370
- "--build-arg",
5371
- `${key}=${value}`
5372
- ]),
5373
- input.buildContext
5374
- ],
5375
- stdout: "pipe",
5376
- stderr: "pipe"
5377
- });
5524
+ function setDetachedJobContext(env, context) {
5525
+ const candidate = env;
5526
+ candidate.setDetachedJobContext?.(context);
5378
5527
  }
5379
- function parseDockerRuntime(runtime) {
5380
- if (!runtime || typeof runtime !== "object" || Array.isArray(runtime)) {
5381
- throw new Error("docker runtime must be an object");
5382
- }
5383
- const record = runtime;
5384
- if (record.type !== "docker") {
5385
- throw new Error('docker runtime type must be "docker"');
5528
+ function isPromiseLike(value) {
5529
+ return typeof value.then === "function";
5530
+ }
5531
+ function createAbortError2() {
5532
+ const error2 = new Error("Agent spawn aborted");
5533
+ error2.name = "AbortError";
5534
+ return error2;
5535
+ }
5536
+ function createActivityTimeoutError(timeoutMs) {
5537
+ const error2 = new Error(`Agent spawn timed out after ${timeoutMs / 1e3}s of inactivity`);
5538
+ error2.name = "ActivityTimeoutError";
5539
+ return error2;
5540
+ }
5541
+ function createUlid() {
5542
+ const time = BigInt(Date.now());
5543
+ const random = randomBytes3(10);
5544
+ let randomValue = 0n;
5545
+ for (const byte of random) {
5546
+ randomValue = randomValue << 8n | BigInt(byte);
5386
5547
  }
5387
- return record;
5548
+ return encodeBase32(time, 10) + encodeBase32(randomValue, 16);
5388
5549
  }
5389
- async function runAndRead(runner, spec) {
5390
- const handle = runner.exec(spec);
5391
- const stdout = readStream2(handle.stdout);
5392
- const stderr = readStream2(handle.stderr);
5393
- const result = await handle.result;
5394
- const output = await stdout;
5395
- if (result.exitCode !== 0) {
5396
- const errorOutput = await stderr;
5397
- throw new Error(
5398
- `Command failed with exit code ${result.exitCode}: ${spec.command} ${(spec.args ?? []).join(" ")}${errorOutput ? `
5399
- ${errorOutput}` : ""}`
5400
- );
5550
+ function encodeBase32(value, length) {
5551
+ const chars = Array.from({ length }, () => "0");
5552
+ let remaining = value;
5553
+ for (let index = length - 1; index >= 0; index -= 1) {
5554
+ chars[index] = ULID_ALPHABET[Number(remaining & 31n)];
5555
+ remaining >>= 5n;
5401
5556
  }
5402
- return output;
5557
+ return chars.join("");
5403
5558
  }
5404
- async function runOrThrow(runner, spec) {
5405
- await runAndRead(runner, spec);
5559
+
5560
+ // packages/agent-harness-tools/src/poe-command-execution.ts
5561
+ import { existsSync as existsSync2, readFileSync } from "node:fs";
5562
+ import os3 from "node:os";
5563
+
5564
+ // packages/agent-harness-tools/src/execution-env.ts
5565
+ var executionEnvFactories = /* @__PURE__ */ new Map();
5566
+ function registerExecutionEnvFactory(factory) {
5567
+ executionEnvFactories.set(factory.type, factory);
5406
5568
  }
5407
- async function readStream2(stream) {
5408
- if (stream === null) {
5409
- return "";
5410
- }
5411
- stream.setEncoding("utf8");
5412
- const chunks = [];
5413
- for await (const chunk of stream) {
5414
- chunks.push(String(chunk));
5569
+ function selectExecutionEnv(runtime) {
5570
+ return selectExecutionEnvFactory(runtime.type);
5571
+ }
5572
+ function selectExecutionEnvFactory(type) {
5573
+ const factory = executionEnvFactories.get(type);
5574
+ if (factory === void 0) {
5575
+ throw new Error(
5576
+ `No execution environment factory registered for runtime type "${type}".`
5577
+ );
5415
5578
  }
5416
- return chunks.join("");
5579
+ return factory;
5417
5580
  }
5418
- function sortedBuildArgs(buildArgs) {
5419
- return Object.entries(buildArgs).sort(([left], [right]) => left.localeCompare(right));
5581
+
5582
+ // packages/agent-harness-tools/src/poe-command-execution.ts
5583
+ function resolvePoeCommandExecution(input) {
5584
+ const homeDir = input.context?.homeDir ?? os3.homedir();
5585
+ const runtimeConfigCwd = input.runtimeConfigCwd ?? input.cwd;
5586
+ const loaded = loadRuntimeConfig(runtimeConfigCwd, homeDir);
5587
+ const config = applyRuntimeOverrides(loaded, input.runtime, runtimeConfigCwd);
5588
+ const resolved = resolveRuntime({ cwd: runtimeConfigCwd, config });
5589
+ const factory = selectExecutionEnv(resolved.runtime);
5590
+ const state = input.context?.state ?? loadState(homeDir);
5591
+ return {
5592
+ factory,
5593
+ detach: factory.supportsDetach === true && config.runner.detach,
5594
+ state,
5595
+ openSpec: {
5596
+ cwd: input.cwd,
5597
+ runtimeCwd: runtimeConfigCwd,
5598
+ runtime: resolved.runtime,
5599
+ runner: config.runner,
5600
+ state,
5601
+ env: input.env,
5602
+ uploadIgnoreFiles: config.runner.workspace?.exclude ?? [],
5603
+ jobLabel: {
5604
+ tool: input.tool,
5605
+ argv: input.argv
5606
+ },
5607
+ ...input.openSpec
5608
+ }
5609
+ };
5420
5610
  }
5421
- function buildEnvArgs(env) {
5422
- if (env === void 0) {
5423
- return [];
5611
+ function applyRuntimeOverrides(config, overrides, cwd = process.cwd()) {
5612
+ if (!overrides) {
5613
+ return { runtime: config.runtime, runner: config.runner };
5424
5614
  }
5425
- return Object.entries(env).flatMap(([key, value]) => ["-e", `${key}=${value}`]);
5426
- }
5427
- function createContainerName() {
5428
- return `poe-env-${randomBytes3(6).toString("hex")}`;
5429
- }
5430
- function createContainerJob(containerId, runner, engine, context, jobId = containerId) {
5615
+ const base = "rawScope" in config && config.rawScope ? { ...config.rawScope } : { ...config.runtime };
5616
+ const runtime = parseRuntime({
5617
+ ...base,
5618
+ ...overrides.runtime !== void 0 ? { type: overrides.runtime } : {},
5619
+ ...overrides.runtimeImage !== void 0 ? { image: overrides.runtimeImage } : {},
5620
+ ...overrides.runtimeTemplate !== void 0 ? { template_id: overrides.runtimeTemplate } : {},
5621
+ ...overrides.mountPoeCode === true ? { mounts: [...config.runtime.mounts, createPoeCodeMount(cwd)] } : {}
5622
+ });
5431
5623
  return {
5432
- id: jobId,
5433
- envId: containerId,
5434
- tool: "docker",
5435
- argv: ["attach", containerId],
5436
- async status() {
5437
- const handle = runner.exec({
5438
- command: engine,
5439
- args: [
5440
- ...buildContextArgs(engine, context),
5441
- "inspect",
5442
- "-f",
5443
- "{{.State.Status}}",
5444
- containerId
5445
- ],
5446
- stdout: "pipe",
5447
- stderr: "pipe"
5448
- });
5449
- const stdout = await readStream2(handle.stdout);
5450
- const result = await handle.result;
5451
- if (result.exitCode !== 0) {
5452
- return "lost";
5453
- }
5454
- return stdout.trim() === "running" ? "running" : "exited";
5455
- },
5456
- async *stream(opts) {
5457
- const handle = runner.exec({
5458
- command: engine,
5459
- args: [
5460
- ...buildContextArgs(engine, context),
5461
- "exec",
5462
- containerId,
5463
- "sh",
5464
- "-c",
5465
- `test -f ${shellQuote2(`/tmp/poe-jobs/${jobId}.log`)} && tail -c +${(opts?.sinceByte ?? 0) + 1} ${shellQuote2(`/tmp/poe-jobs/${jobId}.log`)} || true`
5466
- ],
5467
- stdout: "pipe",
5468
- stderr: "pipe"
5469
- });
5470
- const stdout = await readStream2(handle.stdout);
5471
- await handle.result;
5472
- if (stdout.length > 0) {
5473
- yield { byteOffset: opts?.sinceByte ?? 0, data: stdout };
5474
- }
5475
- },
5476
- async wait() {
5477
- const handle = runner.exec({
5478
- command: engine,
5479
- args: [...buildContextArgs(engine, context), "wait", containerId],
5480
- stdout: "pipe",
5481
- stderr: "pipe"
5482
- });
5483
- const stdout = await readStream2(handle.stdout);
5484
- const result = await handle.result;
5485
- return { exitCode: Number.parseInt(stdout.trim(), 10) || result.exitCode };
5486
- },
5487
- async kill(signal) {
5488
- const args = signal === void 0 || signal === "SIGTERM" ? ["stop", containerId] : ["kill", ...signal === "SIGKILL" ? [] : [`--signal=${signal}`], containerId];
5489
- await runOrThrow(runner, {
5490
- command: engine,
5491
- args: [...buildContextArgs(engine, context), ...args],
5492
- stdout: "pipe",
5493
- stderr: "pipe"
5494
- });
5624
+ runtime,
5625
+ runner: {
5626
+ ...config.runner,
5627
+ ...overrides.detach === true ? { detach: true } : {},
5628
+ ...overrides.runnerSync !== void 0 ? { sync: overrides.runnerSync } : {}
5495
5629
  }
5496
5630
  };
5497
5631
  }
5498
- function createAttachedSpec(cwd = "/workspace") {
5632
+ function createPoeCodeMount(cwd) {
5499
5633
  return {
5500
- cwd,
5501
- runtime: {
5502
- type: "docker",
5503
- image: "attached",
5504
- build_args: {},
5505
- mounts: []
5506
- },
5507
- env: {},
5508
- uploadIgnoreFiles: [],
5509
- jobLabel: {
5510
- tool: "docker",
5511
- argv: []
5512
- }
5634
+ source: cwd,
5635
+ target: "/usr/local/lib/poe-code",
5636
+ readonly: true
5513
5637
  };
5514
5638
  }
5515
- function shellQuote2(value) {
5516
- return `'${value.replaceAll("'", "'\\''")}'`;
5639
+ function loadRuntimeConfig(cwd, homeDir) {
5640
+ const document = deepMergeDocuments(
5641
+ readConfigDocument(resolveConfigPath(homeDir)),
5642
+ readConfigDocument(resolveProjectConfigPath(cwd))
5643
+ );
5644
+ const runtimeScope = resolveScope(runtimeConfigScope.schema, document.runtime, process.env);
5645
+ return {
5646
+ rawScope: { ...runtimeScope },
5647
+ runtime: parseRuntime(runtimeScope),
5648
+ runner: runtimeScope.runner
5649
+ };
5517
5650
  }
5518
-
5519
- // packages/process-runner/src/host/host-execution-env.ts
5520
- var hostExecutionEnvFactory = {
5521
- type: "host",
5522
- supportsDetach: false,
5523
- async open(openSpec) {
5524
- return {
5525
- id: "host",
5526
- job: null,
5527
- async uploadWorkspace() {
5528
- return {
5529
- files: 0,
5530
- bytes: 0,
5531
- skipped: []
5532
- };
5651
+ function readConfigDocument(filePath) {
5652
+ if (!existsSync2(filePath)) {
5653
+ return {};
5654
+ }
5655
+ return JSON.parse(readFileSync(filePath, "utf8"));
5656
+ }
5657
+ function loadState(homeDir) {
5658
+ if (process.env.VITEST === "true") {
5659
+ return createMemoryStateManager();
5660
+ }
5661
+ return createStateManager(homeDir);
5662
+ }
5663
+ function createMemoryStateManager() {
5664
+ const jobs = /* @__PURE__ */ new Map();
5665
+ return {
5666
+ templates: {
5667
+ async get() {
5668
+ return null;
5533
5669
  },
5534
- async downloadWorkspace() {
5535
- return {
5536
- files: 0,
5537
- bytes: 0,
5538
- conflicts: []
5539
- };
5670
+ async put() {
5540
5671
  },
5541
- exec(spec) {
5542
- return createHostRunner().exec(spec);
5672
+ async remove() {
5543
5673
  },
5544
- async detach() {
5545
- throw new Error("host runtime does not support detach because host has no addressable env");
5674
+ async list() {
5675
+ return [];
5676
+ }
5677
+ },
5678
+ jobs: {
5679
+ async get(id) {
5680
+ return jobs.get(id) ?? null;
5546
5681
  },
5547
- shell() {
5548
- const shellSpec = openSpec.shellSpec;
5549
- return createHostRunner().exec({
5550
- command: shellSpec?.command ?? openSpec.env.SHELL ?? process.env.SHELL ?? "sh",
5551
- ...shellSpec?.args ? { args: shellSpec.args } : {},
5552
- cwd: openSpec.cwd,
5553
- env: shellSpec && "env" in shellSpec ? shellSpec.env : openSpec.env,
5554
- stdin: "inherit",
5555
- stdout: "inherit",
5556
- stderr: "inherit",
5557
- tty: true
5558
- });
5682
+ async put(entry) {
5683
+ jobs.set(entry.id, entry);
5559
5684
  },
5560
- async close() {
5685
+ async update(id, patch) {
5686
+ const current = jobs.get(id);
5687
+ if (!current) {
5688
+ return null;
5689
+ }
5690
+ const updated = { ...current, ...patch, id };
5691
+ jobs.set(id, updated);
5692
+ return updated;
5693
+ },
5694
+ async list(filter) {
5695
+ const entries = Array.from(jobs.values());
5696
+ if (!filter) {
5697
+ return entries;
5698
+ }
5699
+ return entries.filter(
5700
+ (entry) => Object.entries(filter).every(([key, value]) => entry[key] === value)
5701
+ );
5702
+ },
5703
+ async remove(id) {
5704
+ jobs.delete(id);
5561
5705
  }
5562
- };
5563
- },
5564
- async attach() {
5565
- throw new Error("host runtime does not support reattach");
5566
- }
5567
- };
5706
+ }
5707
+ };
5708
+ }
5568
5709
 
5569
- // packages/process-runner/src/testing/mock-runner.ts
5570
- import { Readable, Writable } from "node:stream";
5710
+ // packages/agent-harness-tools/src/workspace-transfer.ts
5711
+ import { createHash as createHash4 } from "node:crypto";
5712
+ import { promises as nodeFs3 } from "node:fs";
5713
+ import path29 from "node:path";
5571
5714
 
5572
5715
  // packages/runner-e2b/src/factory.ts
5573
- import path30 from "node:path";
5716
+ import path33 from "node:path";
5574
5717
 
5575
5718
  // packages/runner-e2b/src/sdk.ts
5576
5719
  import { Template, Sandbox } from "e2b";
@@ -5619,7 +5762,7 @@ async function readableToString(stream) {
5619
5762
  // packages/runner-e2b/src/template-build.ts
5620
5763
  import { createHash as createHash5 } from "node:crypto";
5621
5764
  import { readdir as readdir4, readFile as readFile11 } from "node:fs/promises";
5622
- import path27 from "node:path";
5765
+ import path30 from "node:path";
5623
5766
  var BUILD_LOG_TAIL_SIZE = 30;
5624
5767
  async function buildE2bRuntimeTemplate(input) {
5625
5768
  const dockerfileBytes = await readFile11(input.dockerfilePath);
@@ -5700,10 +5843,10 @@ async function readBuildContextFiles(buildContext) {
5700
5843
  return files.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
5701
5844
  }
5702
5845
  async function collectBuildContextFiles(buildContext, relativeDir, files) {
5703
- const absoluteDir = path27.join(buildContext, relativeDir);
5846
+ const absoluteDir = path30.join(buildContext, relativeDir);
5704
5847
  const entries = await readdir4(absoluteDir, { withFileTypes: true });
5705
5848
  for (const entry of entries) {
5706
- const relativePath = path27.join(relativeDir, entry.name);
5849
+ const relativePath = path30.join(relativeDir, entry.name);
5707
5850
  if (entry.isDirectory()) {
5708
5851
  await collectBuildContextFiles(buildContext, relativePath, files);
5709
5852
  continue;
@@ -5712,8 +5855,8 @@ async function collectBuildContextFiles(buildContext, relativeDir, files) {
5712
5855
  continue;
5713
5856
  }
5714
5857
  files.push({
5715
- relativePath: relativePath.split(path27.sep).join("/"),
5716
- bytes: await readFile11(path27.join(buildContext, relativePath))
5858
+ relativePath: relativePath.split(path30.sep).join("/"),
5859
+ bytes: await readFile11(path30.join(buildContext, relativePath))
5717
5860
  });
5718
5861
  }
5719
5862
  }
@@ -5722,11 +5865,11 @@ async function collectBuildContextFiles(buildContext, relativeDir, files) {
5722
5865
  import { mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "node:fs";
5723
5866
  import { readFile as readFile12, writeFile as writeFile7 } from "node:fs/promises";
5724
5867
  import { tmpdir as tmpdir2 } from "node:os";
5725
- import path29 from "node:path";
5868
+ import path32 from "node:path";
5726
5869
  import { PassThrough, Writable as Writable2 } from "node:stream";
5727
5870
 
5728
5871
  // packages/runner-e2b/src/job-handle.ts
5729
- import path28 from "node:path";
5872
+ import path31 from "node:path";
5730
5873
  var JOB_DIR2 = "/tmp/poe-jobs";
5731
5874
  function createE2bJobHandle(input) {
5732
5875
  const fs14 = createE2bLogStreamFs(input.sandbox);
@@ -5784,7 +5927,7 @@ function createE2bLogStreamFs(sandbox) {
5784
5927
  watch(filePath, listener) {
5785
5928
  let closed = false;
5786
5929
  let stop = null;
5787
- void sandbox.files.watchDir(path28.dirname(filePath), listener, { recursive: false }).then((handle) => {
5930
+ void sandbox.files.watchDir(path31.dirname(filePath), listener, { recursive: false }).then((handle) => {
5788
5931
  if (closed) {
5789
5932
  void handle.stop();
5790
5933
  return;
@@ -5823,7 +5966,7 @@ async function readExitCode(sandbox, jobId) {
5823
5966
  var REMOTE_COMMAND_STDERR_TAIL_SIZE = 30;
5824
5967
  function createOpenedE2bEnv(input) {
5825
5968
  const hostRunner = input.spec.hostRunner ?? createHostRunner();
5826
- const hostWorkspaceDir = path29.resolve(input.spec.cwd);
5969
+ const hostWorkspaceDir = path32.resolve(input.spec.cwd);
5827
5970
  const sandboxWorkspaceDir = normalizeSandboxWorkspaceDir(input.runtime.workspace_dir);
5828
5971
  let lastProcess = null;
5829
5972
  let detachedJobContext = null;
@@ -5831,7 +5974,7 @@ function createOpenedE2bEnv(input) {
5831
5974
  if (cwd === void 0) {
5832
5975
  return void 0;
5833
5976
  }
5834
- if (path29.isAbsolute(cwd) && path29.resolve(cwd) === hostWorkspaceDir) {
5977
+ if (path32.isAbsolute(cwd) && path32.resolve(cwd) === hostWorkspaceDir) {
5835
5978
  return sandboxWorkspaceDir;
5836
5979
  }
5837
5980
  return cwd;
@@ -5855,8 +5998,8 @@ function createOpenedE2bEnv(input) {
5855
5998
  if (input.spec.runner?.sync === "none") {
5856
5999
  return { files: 0, bytes: 0, skipped: [] };
5857
6000
  }
5858
- const tempDir = mkdtempSync2(path29.join(tmpdir2(), "poe-e2b-upload-"));
5859
- const archivePath = path29.join(tempDir, "workspace.tar");
6001
+ const tempDir = mkdtempSync2(path32.join(tmpdir2(), "poe-e2b-upload-"));
6002
+ const archivePath = path32.join(tempDir, "workspace.tar");
5860
6003
  try {
5861
6004
  await runOrThrow2(hostRunner, {
5862
6005
  command: "tar",
@@ -5888,8 +6031,8 @@ function createOpenedE2bEnv(input) {
5888
6031
  if (input.spec.runner?.sync === "upload" || input.spec.runner?.sync === "none") {
5889
6032
  return { files: 0, bytes: 0, conflicts: [] };
5890
6033
  }
5891
- const tempDir = mkdtempSync2(path29.join(tmpdir2(), "poe-e2b-download-"));
5892
- const archivePath = path29.join(tempDir, "workspace.tar");
6034
+ const tempDir = mkdtempSync2(path32.join(tmpdir2(), "poe-e2b-download-"));
6035
+ const archivePath = path32.join(tempDir, "workspace.tar");
5893
6036
  try {
5894
6037
  await runRemoteOrThrow(
5895
6038
  input.sandbox,
@@ -6212,10 +6355,10 @@ function resolveSandboxCommandEnv(env) {
6212
6355
  }
6213
6356
  function normalizeSandboxWorkspaceDir(workspaceDir) {
6214
6357
  const resolvedWorkspaceDir = workspaceDir ?? "/workspace";
6215
- if (!path29.posix.isAbsolute(resolvedWorkspaceDir)) {
6358
+ if (!path32.posix.isAbsolute(resolvedWorkspaceDir)) {
6216
6359
  throw new Error("E2B runtime workspace_dir must be an absolute sandbox path.");
6217
6360
  }
6218
- let normalized = path29.posix.normalize(resolvedWorkspaceDir);
6361
+ let normalized = path32.posix.normalize(resolvedWorkspaceDir);
6219
6362
  while (normalized.length > 1 && normalized.endsWith("/")) {
6220
6363
  normalized = normalized.slice(0, -1);
6221
6364
  }
@@ -6271,11 +6414,11 @@ var e2bExecutionEnvFactory = {
6271
6414
  const apiKey = await resolveE2bApiKey({ cwd: runtimeCwd });
6272
6415
  const templateId = runtime.template_id ?? (await buildE2bRuntimeTemplate({
6273
6416
  runtime,
6274
- dockerfilePath: path30.resolve(
6417
+ dockerfilePath: path33.resolve(
6275
6418
  runtimeCwd,
6276
- runtime.dockerfile ?? path30.join(".poe-code", "Dockerfile")
6419
+ runtime.dockerfile ?? path33.join(".poe-code", "Dockerfile")
6277
6420
  ),
6278
- buildContext: path30.resolve(runtimeCwd, runtime.build_context ?? "."),
6421
+ buildContext: path33.resolve(runtimeCwd, runtime.build_context ?? "."),
6279
6422
  state: spec.state,
6280
6423
  apiKey
6281
6424
  })).templateId;
@@ -6716,7 +6859,7 @@ function listMcpSupportedAgents() {
6716
6859
 
6717
6860
  // packages/agent-spawn/src/spawn.ts
6718
6861
  import { mkdirSync, openSync, writeSync, closeSync } from "node:fs";
6719
- import path31 from "node:path";
6862
+ import path34 from "node:path";
6720
6863
 
6721
6864
  // packages/agent-spawn/src/configs/resolve-config.ts
6722
6865
  function resolveConfig(agentId) {
@@ -6945,11 +7088,11 @@ function resolveSpawnLogPath(options) {
6945
7088
  if (!options.logDir || !options.logFileName) {
6946
7089
  return void 0;
6947
7090
  }
6948
- return path31.join(options.logDir, options.logFileName);
7091
+ return path34.join(options.logDir, options.logFileName);
6949
7092
  }
6950
7093
  function openSpawnLog(filePath) {
6951
7094
  try {
6952
- mkdirSync(path31.dirname(filePath), { recursive: true });
7095
+ mkdirSync(path34.dirname(filePath), { recursive: true });
6953
7096
  return openSync(filePath, "a");
6954
7097
  } catch {
6955
7098
  return void 0;
@@ -6973,36 +7116,36 @@ function closeSpawnLog(fd) {
6973
7116
  // packages/design-system/src/tokens/colors.ts
6974
7117
  import chalk from "chalk";
6975
7118
  var dark = {
6976
- header: (text4) => chalk.magentaBright.bold(text4),
6977
- divider: (text4) => chalk.dim(text4),
6978
- prompt: (text4) => chalk.cyan(text4),
6979
- number: (text4) => chalk.cyanBright(text4),
6980
- intro: (text4) => chalk.bgMagenta.white(` Poe - ${text4} `),
7119
+ header: (text5) => chalk.magentaBright.bold(text5),
7120
+ divider: (text5) => chalk.dim(text5),
7121
+ prompt: (text5) => chalk.cyan(text5),
7122
+ number: (text5) => chalk.cyanBright(text5),
7123
+ intro: (text5) => chalk.bgMagenta.white(` Poe - ${text5} `),
6981
7124
  resolvedSymbol: chalk.magenta("\u25C7"),
6982
7125
  errorSymbol: chalk.red("\u25A0"),
6983
- accent: (text4) => chalk.cyan(text4),
6984
- muted: (text4) => chalk.dim(text4),
6985
- success: (text4) => chalk.green(text4),
6986
- warning: (text4) => chalk.yellow(text4),
6987
- error: (text4) => chalk.red(text4),
6988
- info: (text4) => chalk.magenta(text4),
6989
- badge: (text4) => chalk.bgYellow.black(` ${text4} `)
7126
+ accent: (text5) => chalk.cyan(text5),
7127
+ muted: (text5) => chalk.dim(text5),
7128
+ success: (text5) => chalk.green(text5),
7129
+ warning: (text5) => chalk.yellow(text5),
7130
+ error: (text5) => chalk.red(text5),
7131
+ info: (text5) => chalk.magenta(text5),
7132
+ badge: (text5) => chalk.bgYellow.black(` ${text5} `)
6990
7133
  };
6991
7134
  var light = {
6992
- header: (text4) => chalk.hex("#a200ff").bold(text4),
6993
- divider: (text4) => chalk.hex("#666666")(text4),
6994
- prompt: (text4) => chalk.hex("#006699").bold(text4),
6995
- number: (text4) => chalk.hex("#0077cc").bold(text4),
6996
- intro: (text4) => chalk.bgHex("#a200ff").white(` Poe - ${text4} `),
7135
+ header: (text5) => chalk.hex("#a200ff").bold(text5),
7136
+ divider: (text5) => chalk.hex("#666666")(text5),
7137
+ prompt: (text5) => chalk.hex("#006699").bold(text5),
7138
+ number: (text5) => chalk.hex("#0077cc").bold(text5),
7139
+ intro: (text5) => chalk.bgHex("#a200ff").white(` Poe - ${text5} `),
6997
7140
  resolvedSymbol: chalk.hex("#a200ff")("\u25C7"),
6998
7141
  errorSymbol: chalk.hex("#cc0000")("\u25A0"),
6999
- accent: (text4) => chalk.hex("#006699").bold(text4),
7000
- muted: (text4) => chalk.hex("#666666")(text4),
7001
- success: (text4) => chalk.hex("#008800")(text4),
7002
- warning: (text4) => chalk.hex("#cc6600")(text4),
7003
- error: (text4) => chalk.hex("#cc0000")(text4),
7004
- info: (text4) => chalk.hex("#a200ff")(text4),
7005
- badge: (text4) => chalk.bgHex("#cc6600").white(` ${text4} `)
7142
+ accent: (text5) => chalk.hex("#006699").bold(text5),
7143
+ muted: (text5) => chalk.hex("#666666")(text5),
7144
+ success: (text5) => chalk.hex("#008800")(text5),
7145
+ warning: (text5) => chalk.hex("#cc6600")(text5),
7146
+ error: (text5) => chalk.hex("#cc0000")(text5),
7147
+ info: (text5) => chalk.hex("#a200ff")(text5),
7148
+ badge: (text5) => chalk.bgHex("#cc6600").white(` ${text5} `)
7006
7149
  };
7007
7150
 
7008
7151
  // packages/design-system/src/tokens/typography.ts
@@ -7377,7 +7520,7 @@ import chalk16 from "chalk";
7377
7520
  var DEFAULT_ACTIVITY_TIMEOUT_MS = 10 * 60 * 1e3;
7378
7521
 
7379
7522
  // packages/agent-spawn/src/acp/replay.ts
7380
- import path32 from "node:path";
7523
+ import path35 from "node:path";
7381
7524
  import { homedir as homedir2 } from "node:os";
7382
7525
  import { open as open2, readdir as readdir5 } from "node:fs/promises";
7383
7526
  import { createInterface } from "node:readline";
@@ -7391,18 +7534,18 @@ import {
7391
7534
  } from "node:child_process";
7392
7535
 
7393
7536
  // packages/poe-acp-client/src/run-report.ts
7394
- import * as fsPromises3 from "node:fs/promises";
7537
+ import * as fsPromises5 from "node:fs/promises";
7395
7538
  import { homedir } from "node:os";
7396
7539
  import { join } from "node:path";
7397
7540
 
7398
7541
  // packages/agent-spawn/src/acp/middlewares/spawn-log.ts
7399
- import path33 from "node:path";
7542
+ import path36 from "node:path";
7400
7543
  import { homedir as homedir3 } from "node:os";
7401
7544
  import { mkdir as mkdir5, open as open3 } from "node:fs/promises";
7402
7545
 
7403
7546
  // packages/memory/src/tokens.ts
7404
7547
  import * as fs10 from "node:fs/promises";
7405
- import path34 from "node:path";
7548
+ import path37 from "node:path";
7406
7549
 
7407
7550
  // packages/tokenfill/dist/tokenizer.js
7408
7551
  import { get_encoding } from "tiktoken";
@@ -7411,19 +7554,19 @@ function createTokenizer(options = {}) {
7411
7554
  const encoding = options.encoding ?? DEFAULT_ENCODING;
7412
7555
  const tokenizer = get_encoding(encoding);
7413
7556
  const utf8Decoder = new TextDecoder();
7414
- const encode = (text4) => tokenizer.encode(text4);
7557
+ const encode = (text5) => tokenizer.encode(text5);
7415
7558
  const decode = (tokens) => {
7416
7559
  const tokenArray = tokens instanceof Uint32Array ? tokens : Uint32Array.from(tokens);
7417
7560
  return utf8Decoder.decode(tokenizer.decode(tokenArray));
7418
7561
  };
7419
- const count = (text4) => encode(text4).length;
7420
- const truncate2 = (text4, tokenCount) => {
7562
+ const count = (text5) => encode(text5).length;
7563
+ const truncate2 = (text5, tokenCount) => {
7421
7564
  if (tokenCount <= 0) {
7422
7565
  return "";
7423
7566
  }
7424
- const tokens = encode(text4);
7567
+ const tokens = encode(text5);
7425
7568
  if (tokens.length <= tokenCount) {
7426
- return text4;
7569
+ return text5;
7427
7570
  }
7428
7571
  return decode(tokens.slice(0, tokenCount));
7429
7572
  };
@@ -7437,9 +7580,9 @@ function createTokenizer(options = {}) {
7437
7580
  };
7438
7581
  }
7439
7582
  var defaultTokenizer;
7440
- function countTokens(text4) {
7583
+ function countTokens(text5) {
7441
7584
  defaultTokenizer ??= createTokenizer();
7442
- return defaultTokenizer.count(text4);
7585
+ return defaultTokenizer.count(text5);
7443
7586
  }
7444
7587
 
7445
7588
  // packages/tokenfill/dist/corpus.js
@@ -7486,11 +7629,11 @@ async function computeTokenStats(root) {
7486
7629
  }
7487
7630
  }
7488
7631
  }
7489
- const repoRoot = path34.resolve(root, "..", "..");
7632
+ const repoRoot = path37.resolve(root, "..", "..");
7490
7633
  let sourceTokens = 0;
7491
7634
  const missingSources = [];
7492
7635
  for (const sourcePath of sourcePaths) {
7493
- const absPath = path34.isAbsolute(sourcePath) ? sourcePath : path34.resolve(repoRoot, sourcePath);
7636
+ const absPath = path37.isAbsolute(sourcePath) ? sourcePath : path37.resolve(repoRoot, sourcePath);
7494
7637
  try {
7495
7638
  const content = await fs10.readFile(absPath, "utf8");
7496
7639
  sourceTokens += countTokens(content);
@@ -7541,10 +7684,10 @@ function resolveRunners(overrides) {
7541
7684
  async function ingest(root, opts, runners) {
7542
7685
  const resolved = resolveRunners(runners);
7543
7686
  const source = await materializeSource(opts.source);
7544
- const indexMdBytes = await fs11.readFile(path35.join(root, MEMORY_INDEX_RELPATH));
7687
+ const indexMdBytes = await fs11.readFile(path38.join(root, MEMORY_INDEX_RELPATH));
7545
7688
  const configOptions = {
7546
7689
  fs: fs11,
7547
- filePath: path35.join(inferRepoRoot(root), "poe-code.json")
7690
+ filePath: path38.join(inferRepoRoot(root), "poe-code.json")
7548
7691
  };
7549
7692
  const agentId = await resolveAgent(configOptions, opts.agent ?? null) ?? opts.agent ?? "claude-code";
7550
7693
  const key = resolved.computeIngestKey({
@@ -7634,7 +7777,7 @@ async function materializeSource(source) {
7634
7777
  throw new Error("URL ingest not implemented yet.");
7635
7778
  }
7636
7779
  function inferRepoRoot(root) {
7637
- return path35.resolve(root, "..", "..");
7780
+ return path38.resolve(root, "..", "..");
7638
7781
  }
7639
7782
  async function runWithTimeout(promise, timeoutMs) {
7640
7783
  return await new Promise((resolve2, reject) => {
@@ -7986,8 +8129,8 @@ var File = class _File {
7986
8129
  const isText = isTextMimeType(mimeType);
7987
8130
  return new _File(data, mimeType, isText);
7988
8131
  }
7989
- static fromText(text4, mimeType = "text/plain") {
7990
- return new _File(text4, mimeType, true);
8132
+ static fromText(text5, mimeType = "text/plain") {
8133
+ return new _File(text5, mimeType, true);
7991
8134
  }
7992
8135
  static fromBase64(base64, mimeType) {
7993
8136
  const data = Buffer.from(base64, "base64");
@@ -7997,18 +8140,18 @@ var File = class _File {
7997
8140
  toContentBlock() {
7998
8141
  const uri = this.name ? `file:///${this.name}` : "file:///data";
7999
8142
  if (this.isText) {
8000
- let text4;
8143
+ let text5;
8001
8144
  if (typeof this.data === "string") {
8002
- text4 = this.data;
8145
+ text5 = this.data;
8003
8146
  } else {
8004
- text4 = new TextDecoder("utf-8").decode(this.data);
8147
+ text5 = new TextDecoder("utf-8").decode(this.data);
8005
8148
  }
8006
8149
  return {
8007
8150
  type: "resource",
8008
8151
  resource: {
8009
8152
  uri,
8010
8153
  mimeType: this.mimeType,
8011
- text: text4
8154
+ text: text5
8012
8155
  }
8013
8156
  };
8014
8157
  } else {
@@ -8393,7 +8536,7 @@ function printMcpConfig() {
8393
8536
 
8394
8537
  // packages/agent-skill-config/src/configs.ts
8395
8538
  import os5 from "node:os";
8396
- import path36 from "node:path";
8539
+ import path39 from "node:path";
8397
8540
  var agentSkillConfigs = {
8398
8541
  "claude-code": {
8399
8542
  globalSkillDir: "~/.claude/skills",
@@ -8427,7 +8570,7 @@ function resolveAgentSupport(input, registry = agentSkillConfigs) {
8427
8570
 
8428
8571
  // packages/agent-skill-config/src/templates.ts
8429
8572
  import { readFile as readFile15, stat as stat6 } from "node:fs/promises";
8430
- import path37 from "node:path";
8573
+ import path40 from "node:path";
8431
8574
  import { fileURLToPath as fileURLToPath2 } from "node:url";
8432
8575
 
8433
8576
  // packages/agent-skill-config/src/apply.ts
@@ -8560,7 +8703,7 @@ function resolveConfigPath2(config, platform) {
8560
8703
  }
8561
8704
 
8562
8705
  // packages/agent-mcp-config/src/apply.ts
8563
- import path38 from "node:path";
8706
+ import path41 from "node:path";
8564
8707
  import { parse as parseYaml3, stringify as stringifyYaml2 } from "yaml";
8565
8708
 
8566
8709
  // packages/agent-mcp-config/src/shapes.ts
@@ -8652,7 +8795,7 @@ function getShapeTransformer(shape) {
8652
8795
 
8653
8796
  // packages/agent-mcp-config/src/apply.ts
8654
8797
  function getConfigDirectory(configPath) {
8655
- return path38.dirname(configPath);
8798
+ return path41.dirname(configPath);
8656
8799
  }
8657
8800
  var UnsupportedAgentError2 = class extends Error {
8658
8801
  constructor(agentId) {
@@ -8678,9 +8821,9 @@ function expandHomePath(configPath, homeDir) {
8678
8821
  return homeDir;
8679
8822
  }
8680
8823
  if (configPath.startsWith("~/")) {
8681
- return path38.join(homeDir, configPath.slice(2));
8824
+ return path41.join(homeDir, configPath.slice(2));
8682
8825
  }
8683
- return path38.join(homeDir, configPath.slice(1));
8826
+ return path41.join(homeDir, configPath.slice(1));
8684
8827
  }
8685
8828
  function parseYamlDocument(content) {
8686
8829
  if (content.trim() === "") {
@@ -8713,7 +8856,7 @@ async function writeYamlConfig(configPath, document, options) {
8713
8856
  return;
8714
8857
  }
8715
8858
  const absolutePath = expandHomePath(configPath, options.homeDir);
8716
- const configDir = path38.dirname(absolutePath);
8859
+ const configDir = path41.dirname(absolutePath);
8717
8860
  await options.fs.mkdir(configDir, { recursive: true });
8718
8861
  await options.fs.writeFile(absolutePath, serializeYamlDocument(document), {
8719
8862
  encoding: "utf8"
@@ -8891,7 +9034,7 @@ async function installMemory(options) {
8891
9034
 
8892
9035
  // packages/memory/src/query.ts
8893
9036
  import * as fs12 from "node:fs/promises";
8894
- import path39 from "node:path";
9037
+ import path42 from "node:path";
8895
9038
  async function queryMemory(root, options) {
8896
9039
  const pages = await listPages(root);
8897
9040
  if (pages.length === 0) {
@@ -8905,7 +9048,7 @@ async function queryMemory(root, options) {
8905
9048
  }
8906
9049
  const configOptions = {
8907
9050
  fs: fs12,
8908
- filePath: path39.join(inferRepoRoot2(root), "poe-code.json")
9051
+ filePath: path42.join(inferRepoRoot2(root), "poe-code.json")
8909
9052
  };
8910
9053
  const agentId = await resolveAgent(configOptions, options.agent ?? null) ?? options.agent ?? "claude-code";
8911
9054
  const context = await selectQueryContext(root, options.question, options.budget);
@@ -8920,7 +9063,7 @@ async function queryMemory(root, options) {
8920
9063
  }
8921
9064
  async function selectQueryContext(root, question, budget) {
8922
9065
  const [indexText, pages] = await Promise.all([
8923
- fs12.readFile(path39.join(root, MEMORY_INDEX_RELPATH), "utf8"),
9066
+ fs12.readFile(path42.join(root, MEMORY_INDEX_RELPATH), "utf8"),
8924
9067
  listPages(root)
8925
9068
  ]);
8926
9069
  const indexTokens = countTokens(indexText);
@@ -8950,8 +9093,8 @@ async function selectQueryContext(root, question, budget) {
8950
9093
  function rankPagesForQuery(pages, question) {
8951
9094
  const terms = tokenize(question);
8952
9095
  const documents = pages.map((page) => {
8953
- const text4 = [page.relPath, page.frontmatter.name ?? "", page.frontmatter.description ?? "", page.body].join("\n").toLowerCase();
8954
- const tokens = tokenize(text4);
9096
+ const text5 = [page.relPath, page.frontmatter.name ?? "", page.frontmatter.description ?? "", page.body].join("\n").toLowerCase();
9097
+ const tokens = tokenize(text5);
8955
9098
  const counts = /* @__PURE__ */ new Map();
8956
9099
  for (const token of tokens) {
8957
9100
  counts.set(token, (counts.get(token) ?? 0) + 1);
@@ -8995,16 +9138,16 @@ function buildQueryPrompt(question, indexText, pages) {
8995
9138
  function renderPageContext(page) {
8996
9139
  return [`FILE: ${page.relPath}`, page.body].join("\n");
8997
9140
  }
8998
- function tokenize(text4) {
8999
- return text4.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length > 0);
9141
+ function tokenize(text5) {
9142
+ return text5.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length > 0);
9000
9143
  }
9001
9144
  function inferRepoRoot2(root) {
9002
- return path39.resolve(root, "..", "..");
9145
+ return path42.resolve(root, "..", "..");
9003
9146
  }
9004
9147
 
9005
9148
  // packages/memory/src/explain.ts
9006
9149
  import * as fs13 from "node:fs/promises";
9007
- import path40 from "node:path";
9150
+ import path43 from "node:path";
9008
9151
  async function explainPage(root, options) {
9009
9152
  const targetPage = await readPageIfPresent(root, options.relPath);
9010
9153
  if (targetPage === void 0) {
@@ -9027,7 +9170,7 @@ async function explainPage(root, options) {
9027
9170
  }
9028
9171
  const configOptions = {
9029
9172
  fs: fs13,
9030
- filePath: path40.join(inferRepoRoot3(root), "poe-code.json")
9173
+ filePath: path43.join(inferRepoRoot3(root), "poe-code.json")
9031
9174
  };
9032
9175
  const agentId = await resolveAgent(configOptions, options.agent ?? null) ?? options.agent ?? "claude-code";
9033
9176
  const response = await spawn3(agentId, { prompt });
@@ -9076,7 +9219,7 @@ async function readPageIfPresent(root, relPath) {
9076
9219
  }
9077
9220
  }
9078
9221
  function inferRepoRoot3(root) {
9079
- return path40.resolve(root, "..", "..");
9222
+ return path43.resolve(root, "..", "..");
9080
9223
  }
9081
9224
 
9082
9225
  // packages/memory/src/explain.cli.ts
@@ -9089,9 +9232,9 @@ async function runMemoryExplain(input) {
9089
9232
  }
9090
9233
 
9091
9234
  // packages/memory/src/handle.ts
9092
- import path41 from "node:path";
9235
+ import path44 from "node:path";
9093
9236
  function openMemory(opts) {
9094
- if (!path41.isAbsolute(opts.root)) {
9237
+ if (!path44.isAbsolute(opts.root)) {
9095
9238
  throw new Error(`openMemory: root must be absolute, got ${opts.root}`);
9096
9239
  }
9097
9240
  const root = opts.root;