poe-code 3.0.121 → 3.0.122

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -925,16 +925,16 @@ function getConfigFormat(pathOrFormat) {
925
925
  }
926
926
  return formatRegistry[formatName];
927
927
  }
928
- function detectFormat(path33) {
929
- const ext = getExtension(path33);
928
+ function detectFormat(path39) {
929
+ const ext = getExtension(path39);
930
930
  return extensionMap[ext];
931
931
  }
932
- function getExtension(path33) {
933
- const lastDot = path33.lastIndexOf(".");
932
+ function getExtension(path39) {
933
+ const lastDot = path39.lastIndexOf(".");
934
934
  if (lastDot === -1) {
935
935
  return "";
936
936
  }
937
- return path33.slice(lastDot).toLowerCase();
937
+ return path39.slice(lastDot).toLowerCase();
938
938
  }
939
939
  var formatRegistry, extensionMap;
940
940
  var init_formats = __esm({
@@ -1989,38 +1989,38 @@ import { createTwoFilesPatch } from "diff";
1989
1989
  import chalk from "chalk";
1990
1990
  function createDryRunFileSystem(base, recorder) {
1991
1991
  const proxy = {
1992
- async readFile(path33, encoding) {
1992
+ async readFile(path39, encoding) {
1993
1993
  if (encoding) {
1994
- return base.readFile(path33, encoding);
1994
+ return base.readFile(path39, encoding);
1995
1995
  }
1996
- return base.readFile(path33);
1996
+ return base.readFile(path39);
1997
1997
  },
1998
- async writeFile(path33, data, options) {
1999
- const previousContent = await tryReadText(base, path33);
1998
+ async writeFile(path39, data, options) {
1999
+ const previousContent = await tryReadText(base, path39);
2000
2000
  const nextContent = formatData(data, options?.encoding);
2001
2001
  recorder.record({
2002
2002
  type: "writeFile",
2003
- path: path33,
2003
+ path: path39,
2004
2004
  nextContent,
2005
2005
  previousContent
2006
2006
  });
2007
2007
  },
2008
- async mkdir(path33, options) {
2009
- recorder.record({ type: "mkdir", path: path33, options });
2008
+ async mkdir(path39, options) {
2009
+ recorder.record({ type: "mkdir", path: path39, options });
2010
2010
  },
2011
- async stat(path33) {
2012
- return base.stat(path33);
2011
+ async stat(path39) {
2012
+ return base.stat(path39);
2013
2013
  },
2014
- async unlink(path33) {
2015
- recorder.record({ type: "unlink", path: path33 });
2014
+ async unlink(path39) {
2015
+ recorder.record({ type: "unlink", path: path39 });
2016
2016
  },
2017
- async readdir(path33) {
2018
- return base.readdir(path33);
2017
+ async readdir(path39) {
2018
+ return base.readdir(path39);
2019
2019
  }
2020
2020
  };
2021
2021
  if (typeof base.rm === "function") {
2022
- proxy.rm = async (path33, options) => {
2023
- recorder.record({ type: "rm", path: path33, options });
2022
+ proxy.rm = async (path39, options) => {
2023
+ recorder.record({ type: "rm", path: path39, options });
2024
2024
  };
2025
2025
  }
2026
2026
  if (typeof base.copyFile === "function") {
@@ -2110,8 +2110,8 @@ function describeWriteChange(previous, next) {
2110
2110
  }
2111
2111
  return "update";
2112
2112
  }
2113
- function renderWriteCommand(path33, change) {
2114
- const command = `cat > ${path33}`;
2113
+ function renderWriteCommand(path39, change) {
2114
+ const command = `cat > ${path39}`;
2115
2115
  if (change === "create") {
2116
2116
  return renderOperationCommand(command, chalk.green, "# create");
2117
2117
  }
@@ -2273,9 +2273,9 @@ function redactTomlLine(line) {
2273
2273
  }
2274
2274
  return line;
2275
2275
  }
2276
- async function tryReadText(base, path33) {
2276
+ async function tryReadText(base, path39) {
2277
2277
  try {
2278
- return await base.readFile(path33, "utf8");
2278
+ return await base.readFile(path39, "utf8");
2279
2279
  } catch (error) {
2280
2280
  if (isNotFound(error)) {
2281
2281
  return null;
@@ -4123,21 +4123,21 @@ async function* adaptClaude(lines) {
4123
4123
  if (blockType !== "tool_result") continue;
4124
4124
  const kind = toolKindsById.get(item.tool_use_id);
4125
4125
  toolKindsById.delete(item.tool_use_id);
4126
- let path33;
4126
+ let path39;
4127
4127
  if (typeof item.content === "string") {
4128
- path33 = item.content;
4128
+ path39 = item.content;
4129
4129
  } else {
4130
4130
  try {
4131
- path33 = JSON.stringify(item.content);
4131
+ path39 = JSON.stringify(item.content);
4132
4132
  } catch {
4133
- path33 = String(item.content);
4133
+ path39 = String(item.content);
4134
4134
  }
4135
4135
  }
4136
4136
  yield {
4137
4137
  event: "tool_complete",
4138
4138
  id: item.tool_use_id,
4139
4139
  kind,
4140
- path: path33
4140
+ path: path39
4141
4141
  };
4142
4142
  }
4143
4143
  }
@@ -4259,10 +4259,10 @@ async function* adaptCodex(lines) {
4259
4259
  const kindFromStart = toolKindById.get(item.id);
4260
4260
  const kind = kindFromStart ?? (itemType === "command_execution" ? "exec" : itemType === "file_edit" ? "edit" : "other");
4261
4261
  const titleFromEvent = isNonEmptyString(item.path) ? item.path : itemType === "mcp_tool_call" ? `${isNonEmptyString(item.server) ? item.server : "unknown"}.${isNonEmptyString(item.tool) ? item.tool : "unknown"}` : void 0;
4262
- const path33 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
4262
+ const path39 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
4263
4263
  toolTitleById.delete(item.id);
4264
4264
  toolKindById.delete(item.id);
4265
- yield { event: "tool_complete", id: item.id, kind, path: path33 };
4265
+ yield { event: "tool_complete", id: item.id, kind, path: path39 };
4266
4266
  }
4267
4267
  }
4268
4268
  }
@@ -4711,7 +4711,7 @@ function updateSessionFromEvent(ctx, event, toolCallsById) {
4711
4711
  }
4712
4712
  const id = readString(event.id);
4713
4713
  const kind = readString(event.kind);
4714
- const path33 = readString(event.path);
4714
+ const path39 = readString(event.path);
4715
4715
  let toolCall = id ? toolCallsById.get(id) : void 0;
4716
4716
  if (!toolCall) {
4717
4717
  toolCall = {};
@@ -4726,8 +4726,8 @@ function updateSessionFromEvent(ctx, event, toolCallsById) {
4726
4726
  if (kind) {
4727
4727
  toolCall.kind = kind;
4728
4728
  }
4729
- if (path33) {
4730
- toolCall.path = path33;
4729
+ if (path39) {
4730
+ toolCall.path = path39;
4731
4731
  }
4732
4732
  }
4733
4733
  var sessionCapture;
@@ -6729,21 +6729,21 @@ function createSdkContainer(options) {
6729
6729
  });
6730
6730
  loggerFactory.setErrorLogger(errorLogger);
6731
6731
  const asyncFs = {
6732
- readFile: ((path33, encoding) => {
6732
+ readFile: ((path39, encoding) => {
6733
6733
  if (encoding) {
6734
- return fs2.readFile(path33, encoding);
6734
+ return fs2.readFile(path39, encoding);
6735
6735
  }
6736
- return fs2.readFile(path33);
6736
+ return fs2.readFile(path39);
6737
6737
  }),
6738
- writeFile: (path33, data, opts) => fs2.writeFile(path33, data, opts),
6739
- mkdir: (path33, opts) => fs2.mkdir(path33, opts).then(() => {
6738
+ writeFile: (path39, data, opts) => fs2.writeFile(path39, data, opts),
6739
+ mkdir: (path39, opts) => fs2.mkdir(path39, opts).then(() => {
6740
6740
  }),
6741
- stat: (path33) => fs2.stat(path33),
6742
- rm: (path33, opts) => fs2.rm(path33, opts),
6743
- unlink: (path33) => fs2.unlink(path33),
6744
- readdir: (path33) => fs2.readdir(path33),
6741
+ stat: (path39) => fs2.stat(path39),
6742
+ rm: (path39, opts) => fs2.rm(path39, opts),
6743
+ unlink: (path39) => fs2.unlink(path39),
6744
+ readdir: (path39) => fs2.readdir(path39),
6745
6745
  copyFile: (src, dest) => fs2.copyFile(src, dest),
6746
- chmod: (path33, mode) => fs2.chmod(path33, mode)
6746
+ chmod: (path39, mode) => fs2.chmod(path39, mode)
6747
6747
  };
6748
6748
  const contextFactory = createCommandContextFactory({ fs: asyncFs });
6749
6749
  const authFs = {
@@ -7510,8 +7510,8 @@ function sleep(ms) {
7510
7510
  return new Promise((resolve) => setTimeout(resolve, ms));
7511
7511
  }
7512
7512
  function backoff(attempt, min, max) {
7513
- const delay = Math.min(max, min * Math.pow(2, attempt));
7514
- return delay + Math.random() * delay * 0.1;
7513
+ const delay2 = Math.min(max, min * Math.pow(2, attempt));
7514
+ return delay2 + Math.random() * delay2 * 0.1;
7515
7515
  }
7516
7516
  function createDefaultFs2() {
7517
7517
  return {
@@ -7889,6 +7889,1503 @@ var init_pipeline2 = __esm({
7889
7889
  }
7890
7890
  });
7891
7891
 
7892
+ // packages/process-launcher/src/state/state-store.ts
7893
+ import path15 from "node:path";
7894
+ import * as nodeFs from "node:fs/promises";
7895
+ function isNotFoundError2(error) {
7896
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
7897
+ }
7898
+ async function removeDirectory2(fs3, directoryPath) {
7899
+ let entries;
7900
+ try {
7901
+ entries = await fs3.readdir(directoryPath);
7902
+ } catch (error) {
7903
+ if (isNotFoundError2(error)) {
7904
+ return;
7905
+ }
7906
+ throw error;
7907
+ }
7908
+ for (const entry of entries) {
7909
+ const entryPath = path15.join(directoryPath, entry);
7910
+ const stat11 = await fs3.stat(entryPath);
7911
+ if (stat11.isFile()) {
7912
+ await fs3.rm(entryPath, { force: true });
7913
+ continue;
7914
+ }
7915
+ await removeDirectory2(fs3, entryPath);
7916
+ }
7917
+ const fsWithDirectoryRemoval = fs3;
7918
+ if (typeof fsWithDirectoryRemoval.rmdir === "function") {
7919
+ await fsWithDirectoryRemoval.rmdir(directoryPath);
7920
+ return;
7921
+ }
7922
+ await fs3.rm(directoryPath, { force: true });
7923
+ }
7924
+ function createStateStore(stateDir, fs3 = nodeFs) {
7925
+ async function read(id) {
7926
+ const statePath = path15.join(stateDir, id, "state.json");
7927
+ try {
7928
+ const content = await fs3.readFile(statePath, "utf8");
7929
+ return JSON.parse(content);
7930
+ } catch (error) {
7931
+ if (isNotFoundError2(error)) {
7932
+ return null;
7933
+ }
7934
+ throw error;
7935
+ }
7936
+ }
7937
+ async function write2(id, state) {
7938
+ const processDir = path15.join(stateDir, id);
7939
+ await fs3.mkdir(processDir, { recursive: true });
7940
+ await fs3.writeFile(path15.join(processDir, "state.json"), `${JSON.stringify(state, null, 2)}
7941
+ `);
7942
+ }
7943
+ async function list() {
7944
+ let entries;
7945
+ try {
7946
+ entries = await fs3.readdir(stateDir);
7947
+ } catch (error) {
7948
+ if (isNotFoundError2(error)) {
7949
+ return [];
7950
+ }
7951
+ throw error;
7952
+ }
7953
+ const states = [];
7954
+ for (const entry of [...entries].sort()) {
7955
+ const entryPath = path15.join(stateDir, entry);
7956
+ try {
7957
+ const stat11 = await fs3.stat(entryPath);
7958
+ if (stat11.isFile()) {
7959
+ continue;
7960
+ }
7961
+ } catch (error) {
7962
+ if (isNotFoundError2(error)) {
7963
+ continue;
7964
+ }
7965
+ throw error;
7966
+ }
7967
+ const state = await read(entry);
7968
+ if (state !== null) {
7969
+ states.push(state);
7970
+ }
7971
+ }
7972
+ return states;
7973
+ }
7974
+ async function remove2(id) {
7975
+ await removeDirectory2(fs3, path15.join(stateDir, id));
7976
+ }
7977
+ return { read, write: write2, list, remove: remove2 };
7978
+ }
7979
+ var init_state_store = __esm({
7980
+ "packages/process-launcher/src/state/state-store.ts"() {
7981
+ "use strict";
7982
+ }
7983
+ });
7984
+
7985
+ // packages/process-launcher/src/logs/log-writer.ts
7986
+ import path16 from "node:path";
7987
+ import * as nodeFs2 from "node:fs/promises";
7988
+ function isNotFoundError3(error) {
7989
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
7990
+ }
7991
+ function getCurrentLogPath(logDir, stream) {
7992
+ return path16.join(logDir, `${stream}.log`);
7993
+ }
7994
+ function getRotatedLogPath(logDir, stream, index) {
7995
+ return path16.join(logDir, `${stream}.${index}.log`);
7996
+ }
7997
+ async function isFile(fs3, filePath) {
7998
+ try {
7999
+ return (await fs3.stat(filePath)).isFile();
8000
+ } catch (error) {
8001
+ if (isNotFoundError3(error)) {
8002
+ return false;
8003
+ }
8004
+ throw error;
8005
+ }
8006
+ }
8007
+ async function removeIfExists(fs3, filePath) {
8008
+ if (!await isFile(fs3, filePath)) {
8009
+ return;
8010
+ }
8011
+ await fs3.rm(filePath, { force: true });
8012
+ }
8013
+ async function moveIfExists(fs3, sourcePath, destinationPath) {
8014
+ if (!await isFile(fs3, sourcePath)) {
8015
+ return;
8016
+ }
8017
+ const content = await fs3.readFile(sourcePath, "utf8");
8018
+ await fs3.writeFile(destinationPath, content);
8019
+ await fs3.rm(sourcePath, { force: true });
8020
+ }
8021
+ function getRotatedLogIndex(fileName, stream) {
8022
+ const prefix = `${stream}.`;
8023
+ const suffix = ".log";
8024
+ if (!fileName.startsWith(prefix) || !fileName.endsWith(suffix)) {
8025
+ return null;
8026
+ }
8027
+ const rawIndex = fileName.slice(prefix.length, -suffix.length);
8028
+ const index = Number.parseInt(rawIndex, 10);
8029
+ if (!Number.isInteger(index) || index < 1 || `${index}` !== rawIndex) {
8030
+ return null;
8031
+ }
8032
+ return index;
8033
+ }
8034
+ async function removeAllStreamLogs(fs3, logDir, stream) {
8035
+ await removeIfExists(fs3, getCurrentLogPath(logDir, stream));
8036
+ try {
8037
+ const fileNames = await fs3.readdir(logDir);
8038
+ for (const fileName of fileNames) {
8039
+ if (getRotatedLogIndex(fileName, stream) === null) {
8040
+ continue;
8041
+ }
8042
+ await fs3.rm(path16.join(logDir, fileName), { force: true });
8043
+ }
8044
+ } catch (error) {
8045
+ if (isNotFoundError3(error)) {
8046
+ return;
8047
+ }
8048
+ throw error;
8049
+ }
8050
+ }
8051
+ function getLines(content) {
8052
+ if (content.length === 0) {
8053
+ return [];
8054
+ }
8055
+ const lines = content.split("\n");
8056
+ if (content.endsWith("\n")) {
8057
+ lines.pop();
8058
+ }
8059
+ return lines;
8060
+ }
8061
+ function createLogWriter(logDir, retainCount, fs3 = nodeFs2) {
8062
+ const maxRetainedRuns = Math.max(0, Math.trunc(retainCount));
8063
+ async function write2(line, stream) {
8064
+ await fs3.mkdir(logDir, { recursive: true });
8065
+ await fs3.appendFile(getCurrentLogPath(logDir, stream), `${line}
8066
+ `);
8067
+ }
8068
+ async function rotateStream(stream) {
8069
+ const currentPath = getCurrentLogPath(logDir, stream);
8070
+ if (maxRetainedRuns === 0) {
8071
+ await removeAllStreamLogs(fs3, logDir, stream);
8072
+ return;
8073
+ }
8074
+ await removeIfExists(fs3, getRotatedLogPath(logDir, stream, maxRetainedRuns));
8075
+ for (let index = maxRetainedRuns - 1; index >= 1; index -= 1) {
8076
+ await moveIfExists(
8077
+ fs3,
8078
+ getRotatedLogPath(logDir, stream, index),
8079
+ getRotatedLogPath(logDir, stream, index + 1)
8080
+ );
8081
+ }
8082
+ await moveIfExists(fs3, currentPath, getRotatedLogPath(logDir, stream, 1));
8083
+ }
8084
+ async function rotate() {
8085
+ await rotateStream("stdout");
8086
+ await rotateStream("stderr");
8087
+ }
8088
+ async function tail(stream, lines = 50) {
8089
+ try {
8090
+ const content = await fs3.readFile(getCurrentLogPath(logDir, stream), "utf8");
8091
+ const allLines = getLines(content);
8092
+ const lineCount = Math.max(0, Math.trunc(lines));
8093
+ if (lineCount === 0) {
8094
+ return [];
8095
+ }
8096
+ return allLines.slice(-lineCount);
8097
+ } catch (error) {
8098
+ if (isNotFoundError3(error)) {
8099
+ return [];
8100
+ }
8101
+ throw error;
8102
+ }
8103
+ }
8104
+ function close() {
8105
+ }
8106
+ return { write: write2, rotate, tail, close };
8107
+ }
8108
+ var init_log_writer = __esm({
8109
+ "packages/process-launcher/src/logs/log-writer.ts"() {
8110
+ "use strict";
8111
+ }
8112
+ });
8113
+
8114
+ // packages/process-launcher/src/health/health-check.ts
8115
+ import net from "node:net";
8116
+ async function waitForReady(check, options) {
8117
+ if (check.kind === "log-pattern") {
8118
+ return waitForLogPattern(check.pattern, options);
8119
+ }
8120
+ return waitForTcp(check, options.signal);
8121
+ }
8122
+ function waitForLogPattern(pattern, options) {
8123
+ if (options.signal?.aborted) {
8124
+ return Promise.resolve(false);
8125
+ }
8126
+ return new Promise((resolve) => {
8127
+ let finished = false;
8128
+ const timeout = setTimeout(() => {
8129
+ finish(false);
8130
+ }, options.timeoutMs ?? 3e4);
8131
+ const logSource = options.onLog;
8132
+ const unsubscribe = logSource?.subscribe?.((line) => {
8133
+ if (line.includes(pattern)) {
8134
+ finish(true);
8135
+ }
8136
+ }) ?? (() => {
8137
+ });
8138
+ const onAbort = () => {
8139
+ finish(false);
8140
+ };
8141
+ options.signal?.addEventListener("abort", onAbort, { once: true });
8142
+ function finish(result) {
8143
+ if (finished) {
8144
+ return;
8145
+ }
8146
+ finished = true;
8147
+ clearTimeout(timeout);
8148
+ options.signal?.removeEventListener("abort", onAbort);
8149
+ unsubscribe();
8150
+ resolve(result);
8151
+ }
8152
+ });
8153
+ }
8154
+ function waitForTcp(check, signal) {
8155
+ if (signal?.aborted) {
8156
+ return Promise.resolve(false);
8157
+ }
8158
+ const timeoutMs = check.timeoutMs ?? 3e4;
8159
+ const deadline = Date.now() + timeoutMs;
8160
+ return new Promise((resolve) => {
8161
+ let finished = false;
8162
+ let activeSocket;
8163
+ let retryTimer;
8164
+ const onAbort = () => {
8165
+ finish(false);
8166
+ };
8167
+ signal?.addEventListener("abort", onAbort, { once: true });
8168
+ attemptConnection();
8169
+ function attemptConnection() {
8170
+ if (finished) {
8171
+ return;
8172
+ }
8173
+ if (signal?.aborted || Date.now() >= deadline) {
8174
+ finish(false);
8175
+ return;
8176
+ }
8177
+ const socket = net.connect({
8178
+ host: check.host ?? "127.0.0.1",
8179
+ port: check.port
8180
+ });
8181
+ activeSocket = socket;
8182
+ const socketTimeoutMs = Math.max(1, Math.min(500, deadline - Date.now()));
8183
+ socket.setTimeout(socketTimeoutMs);
8184
+ socket.once("connect", () => {
8185
+ clearActiveSocket(socket);
8186
+ socket.end();
8187
+ socket.destroy();
8188
+ finish(true);
8189
+ });
8190
+ socket.once("error", () => {
8191
+ failAttempt(socket);
8192
+ });
8193
+ socket.once("timeout", () => {
8194
+ failAttempt(socket);
8195
+ });
8196
+ }
8197
+ function failAttempt(socket) {
8198
+ clearActiveSocket(socket);
8199
+ socket.destroy();
8200
+ if (finished) {
8201
+ return;
8202
+ }
8203
+ const remainingMs = deadline - Date.now();
8204
+ if (remainingMs <= 0) {
8205
+ finish(false);
8206
+ return;
8207
+ }
8208
+ retryTimer = setTimeout(attemptConnection, Math.min(500, remainingMs));
8209
+ }
8210
+ function clearActiveSocket(socket) {
8211
+ if (activeSocket === socket) {
8212
+ activeSocket = void 0;
8213
+ }
8214
+ }
8215
+ function finish(result) {
8216
+ if (finished) {
8217
+ return;
8218
+ }
8219
+ finished = true;
8220
+ if (retryTimer) {
8221
+ clearTimeout(retryTimer);
8222
+ }
8223
+ activeSocket?.destroy();
8224
+ activeSocket = void 0;
8225
+ signal?.removeEventListener("abort", onAbort);
8226
+ resolve(result);
8227
+ }
8228
+ });
8229
+ }
8230
+ var init_health_check = __esm({
8231
+ "packages/process-launcher/src/health/health-check.ts"() {
8232
+ "use strict";
8233
+ }
8234
+ });
8235
+
8236
+ // packages/process-runner/src/docker/context.ts
8237
+ import { execSync } from "node:child_process";
8238
+ function detectContext() {
8239
+ try {
8240
+ const output = execSync("colima list --json", {
8241
+ encoding: "utf-8",
8242
+ stdio: ["pipe", "pipe", "ignore"]
8243
+ });
8244
+ const lines = output.trim().split("\n").filter(Boolean);
8245
+ for (const line of lines) {
8246
+ const profile = JSON.parse(line);
8247
+ if (profile.status === "Running" && profile.runtime === "docker") {
8248
+ const name = profile.name ?? profile.profile;
8249
+ if (!name) {
8250
+ continue;
8251
+ }
8252
+ return name === "default" ? "colima" : `colima-${name}`;
8253
+ }
8254
+ }
8255
+ } catch {
8256
+ return null;
8257
+ }
8258
+ return null;
8259
+ }
8260
+ function buildContextArgs(engine, context) {
8261
+ if (engine === "docker" && context) {
8262
+ return ["--context", context];
8263
+ }
8264
+ return [];
8265
+ }
8266
+ var init_context2 = __esm({
8267
+ "packages/process-runner/src/docker/context.ts"() {
8268
+ "use strict";
8269
+ }
8270
+ });
8271
+
8272
+ // packages/process-runner/src/docker/engine.ts
8273
+ import { execSync as execSync2 } from "node:child_process";
8274
+ function detectEngine() {
8275
+ if (isEngineAvailable("docker")) {
8276
+ return "docker";
8277
+ }
8278
+ if (isEngineAvailable("podman")) {
8279
+ return "podman";
8280
+ }
8281
+ throw new Error(
8282
+ "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"
8283
+ );
8284
+ }
8285
+ function isEngineAvailable(engine) {
8286
+ try {
8287
+ execSync2(`${engine} --version`, {
8288
+ stdio: "ignore"
8289
+ });
8290
+ return true;
8291
+ } catch {
8292
+ return false;
8293
+ }
8294
+ }
8295
+ var init_engine = __esm({
8296
+ "packages/process-runner/src/docker/engine.ts"() {
8297
+ "use strict";
8298
+ }
8299
+ });
8300
+
8301
+ // packages/process-runner/src/docker/args.ts
8302
+ import path17 from "node:path";
8303
+ function buildDockerRunArgs(input) {
8304
+ const args = [input.engine];
8305
+ if (input.engine === "docker" && input.context) {
8306
+ args.push("--context", input.context);
8307
+ }
8308
+ args.push("run");
8309
+ if (input.rm) {
8310
+ args.push("--rm");
8311
+ }
8312
+ if (input.detached) {
8313
+ args.push("-d");
8314
+ }
8315
+ if (input.interactive) {
8316
+ args.push("-i");
8317
+ }
8318
+ if (input.tty) {
8319
+ args.push("-t");
8320
+ }
8321
+ args.push("--name", input.containerName);
8322
+ if (input.cwd !== void 0) {
8323
+ args.push("-w", input.cwd);
8324
+ }
8325
+ for (const [key, value] of Object.entries(input.env ?? {})) {
8326
+ args.push("-e", `${key}=${value}`);
8327
+ }
8328
+ for (const mount of input.mounts) {
8329
+ const volume = `${path17.resolve(mount.source)}:${mount.target}${mount.readonly ? ":ro" : ""}`;
8330
+ args.push("-v", volume);
8331
+ }
8332
+ for (const port of input.ports) {
8333
+ const mapping = `${port.host}:${port.container}${port.protocol === void 0 || port.protocol === "tcp" ? "" : `/${port.protocol}`}`;
8334
+ args.push("-p", mapping);
8335
+ }
8336
+ if (input.network !== void 0) {
8337
+ args.push("--network", input.network);
8338
+ }
8339
+ args.push(...input.extraArgs, input.image, input.command, ...input.args);
8340
+ return args;
8341
+ }
8342
+ var init_args = __esm({
8343
+ "packages/process-runner/src/docker/args.ts"() {
8344
+ "use strict";
8345
+ }
8346
+ });
8347
+
8348
+ // packages/process-runner/src/docker/docker-runner.ts
8349
+ import * as childProcess from "node:child_process";
8350
+ import { randomBytes as randomBytes2 } from "node:crypto";
8351
+ function createDockerRunner(options) {
8352
+ const engine = options.engine ?? detectEngine();
8353
+ const context = options.context ?? detectContext();
8354
+ return {
8355
+ name: "docker",
8356
+ exec(spec) {
8357
+ const stdinMode = spec.stdin ?? "ignore";
8358
+ const stdoutMode = spec.stdout ?? "pipe";
8359
+ const stderrMode = spec.stderr ?? "pipe";
8360
+ const interactiveMode = stdinMode === "inherit" && stdoutMode === "inherit" && stderrMode === "inherit" && spec.tty === true;
8361
+ const containerName = buildContainerName(options.containerName ?? spec.command);
8362
+ const runArgs = buildDockerRunArgs({
8363
+ engine,
8364
+ context,
8365
+ image: options.image,
8366
+ command: spec.command,
8367
+ args: spec.args ?? [],
8368
+ cwd: spec.cwd,
8369
+ env: spec.env,
8370
+ mounts: options.mounts ?? [],
8371
+ ports: options.ports ?? [],
8372
+ network: options.network,
8373
+ containerName,
8374
+ detached: false,
8375
+ interactive: stdinMode === "pipe" || stdinMode === "inherit",
8376
+ tty: spec.tty ?? false,
8377
+ rm: true,
8378
+ extraArgs: options.extraArgs ?? []
8379
+ });
8380
+ const [command, ...args] = runArgs;
8381
+ const child = childProcess.spawn(command, args, {
8382
+ stdio: interactiveMode ? "inherit" : [stdinMode, stdoutMode, stderrMode]
8383
+ });
8384
+ let isResultSettled = false;
8385
+ let resolveResult = null;
8386
+ const result = new Promise((resolve) => {
8387
+ resolveResult = resolve;
8388
+ });
8389
+ const cleanupAbort = bindAbortSignal(spec.signal, () => {
8390
+ spawnControlCommand(engine, context, ["stop", containerName]);
8391
+ });
8392
+ const settleResult = (exitCode) => {
8393
+ if (isResultSettled) {
8394
+ return;
8395
+ }
8396
+ isResultSettled = true;
8397
+ cleanupAbort();
8398
+ resolveResult?.({ exitCode });
8399
+ };
8400
+ child.once("error", () => {
8401
+ settleResult(1);
8402
+ });
8403
+ child.once("close", (code) => {
8404
+ settleResult(code ?? 1);
8405
+ });
8406
+ return {
8407
+ pid: null,
8408
+ stdin: interactiveMode ? null : child.stdin,
8409
+ stdout: interactiveMode ? null : child.stdout,
8410
+ stderr: interactiveMode ? null : child.stderr,
8411
+ result,
8412
+ kill(signal) {
8413
+ if (signal === "SIGKILL") {
8414
+ spawnControlCommand(engine, context, ["kill", containerName]);
8415
+ return;
8416
+ }
8417
+ if (signal === void 0 || signal === "SIGTERM") {
8418
+ spawnControlCommand(engine, context, ["stop", containerName]);
8419
+ return;
8420
+ }
8421
+ spawnControlCommand(engine, context, ["kill", `--signal=${signal}`, containerName]);
8422
+ }
8423
+ };
8424
+ }
8425
+ };
8426
+ }
8427
+ function buildContainerName(name) {
8428
+ const suffix = randomBytes2(3).toString("hex").slice(0, 6);
8429
+ const sanitizedName = sanitizeContainerName(name);
8430
+ return `poe-run-${sanitizedName}-${suffix}`;
8431
+ }
8432
+ function sanitizeContainerName(name) {
8433
+ let sanitized = "";
8434
+ for (const char of name) {
8435
+ if (isContainerNameCharacter(char)) {
8436
+ sanitized += char;
8437
+ continue;
8438
+ }
8439
+ sanitized += "-";
8440
+ }
8441
+ return sanitized.length > 0 ? sanitized : "command";
8442
+ }
8443
+ function isContainerNameCharacter(char) {
8444
+ const code = char.charCodeAt(0);
8445
+ if (code >= 48 && code <= 57) {
8446
+ return true;
8447
+ }
8448
+ if (code >= 65 && code <= 90) {
8449
+ return true;
8450
+ }
8451
+ if (code >= 97 && code <= 122) {
8452
+ return true;
8453
+ }
8454
+ return char === "." || char === "_" || char === "-";
8455
+ }
8456
+ function spawnControlCommand(engine, context, args) {
8457
+ childProcess.spawn(engine, [...buildContextArgs(engine, context), ...args], {
8458
+ stdio: "ignore"
8459
+ });
8460
+ }
8461
+ function bindAbortSignal(signal, onAbort) {
8462
+ if (signal === void 0) {
8463
+ return () => {
8464
+ };
8465
+ }
8466
+ if (signal.aborted) {
8467
+ onAbort();
8468
+ return () => {
8469
+ };
8470
+ }
8471
+ signal.addEventListener("abort", onAbort, { once: true });
8472
+ return () => {
8473
+ signal.removeEventListener("abort", onAbort);
8474
+ };
8475
+ }
8476
+ var init_docker_runner = __esm({
8477
+ "packages/process-runner/src/docker/docker-runner.ts"() {
8478
+ "use strict";
8479
+ init_args();
8480
+ init_context2();
8481
+ init_engine();
8482
+ }
8483
+ });
8484
+
8485
+ // packages/process-runner/src/host/host-runner.ts
8486
+ import * as childProcess2 from "node:child_process";
8487
+ function createHostRunner(options = {}) {
8488
+ const detached = options.detached === true;
8489
+ return {
8490
+ name: "host",
8491
+ exec(spec) {
8492
+ const stdinMode = spec.stdin ?? "ignore";
8493
+ const stdoutMode = spec.stdout ?? "pipe";
8494
+ const stderrMode = spec.stderr ?? "pipe";
8495
+ const child = childProcess2.spawn(spec.command, spec.args ?? [], {
8496
+ cwd: spec.cwd,
8497
+ env: spec.env,
8498
+ stdio: [stdinMode, stdoutMode, stderrMode],
8499
+ ...detached ? { detached: true } : {}
8500
+ });
8501
+ if (detached) {
8502
+ child.unref();
8503
+ }
8504
+ const kill = (signal) => {
8505
+ if (detached && process.platform !== "win32" && child.pid !== void 0) {
8506
+ process.kill(-child.pid, signal);
8507
+ return;
8508
+ }
8509
+ child.kill(signal);
8510
+ };
8511
+ let resolveResult = null;
8512
+ const result = new Promise((resolve) => {
8513
+ resolveResult = resolve;
8514
+ });
8515
+ const cleanupAbort = bindAbortSignal2(spec.signal, () => {
8516
+ kill("SIGTERM");
8517
+ });
8518
+ child.once("close", (code) => {
8519
+ cleanupAbort();
8520
+ resolveResult?.({ exitCode: code ?? 1 });
8521
+ });
8522
+ return {
8523
+ pid: child.pid ?? null,
8524
+ stdin: child.stdin,
8525
+ stdout: child.stdout,
8526
+ stderr: child.stderr,
8527
+ result,
8528
+ kill
8529
+ };
8530
+ }
8531
+ };
8532
+ }
8533
+ function bindAbortSignal2(signal, onAbort) {
8534
+ if (signal === void 0) {
8535
+ return () => {
8536
+ };
8537
+ }
8538
+ if (signal.aborted) {
8539
+ onAbort();
8540
+ return () => {
8541
+ };
8542
+ }
8543
+ signal.addEventListener("abort", onAbort, { once: true });
8544
+ return () => {
8545
+ signal.removeEventListener("abort", onAbort);
8546
+ };
8547
+ }
8548
+ var init_host_runner = __esm({
8549
+ "packages/process-runner/src/host/host-runner.ts"() {
8550
+ "use strict";
8551
+ }
8552
+ });
8553
+
8554
+ // packages/process-runner/src/testing/mock-runner.ts
8555
+ import { Readable, Writable } from "node:stream";
8556
+ var init_mock_runner = __esm({
8557
+ "packages/process-runner/src/testing/mock-runner.ts"() {
8558
+ "use strict";
8559
+ }
8560
+ });
8561
+
8562
+ // packages/process-runner/src/testing/index.ts
8563
+ var init_testing = __esm({
8564
+ "packages/process-runner/src/testing/index.ts"() {
8565
+ "use strict";
8566
+ init_mock_runner();
8567
+ }
8568
+ });
8569
+
8570
+ // packages/process-runner/src/index.ts
8571
+ var init_src9 = __esm({
8572
+ "packages/process-runner/src/index.ts"() {
8573
+ "use strict";
8574
+ init_context2();
8575
+ init_engine();
8576
+ init_docker_runner();
8577
+ init_host_runner();
8578
+ init_testing();
8579
+ }
8580
+ });
8581
+
8582
+ // packages/process-launcher/src/supervisor/supervisor.ts
8583
+ import path18 from "node:path";
8584
+ function createSupervisor(options) {
8585
+ const { spec } = options;
8586
+ const runner = resolveRunner(options);
8587
+ const stateStore = createStateStore(options.stateDir, options.fs);
8588
+ const logWriter = createLogWriter(
8589
+ path18.join(options.stateDir, spec.id, "logs"),
8590
+ spec.logRetainCount ?? 5,
8591
+ options.fs
8592
+ );
8593
+ const logSource = createLogSource(options.onLog);
8594
+ let state = createInitialState(spec, runner);
8595
+ let handle = null;
8596
+ let runId = 0;
8597
+ let startPromise = null;
8598
+ let pendingRestart = null;
8599
+ let activeReadyController = null;
8600
+ let stableTimer = null;
8601
+ let stopRequested = false;
8602
+ const onAbort = () => {
8603
+ void stop();
8604
+ };
8605
+ options.signal?.addEventListener("abort", onAbort, { once: true });
8606
+ async function start() {
8607
+ if (handle !== null || pendingRestart !== null) {
8608
+ return;
8609
+ }
8610
+ if (startPromise !== null) {
8611
+ await startPromise;
8612
+ return;
8613
+ }
8614
+ stopRequested = false;
8615
+ startPromise = launch(false);
8616
+ try {
8617
+ await startPromise;
8618
+ } finally {
8619
+ startPromise = null;
8620
+ }
8621
+ }
8622
+ async function stop() {
8623
+ stopRequested = true;
8624
+ pendingRestart = null;
8625
+ activeReadyController?.abort();
8626
+ activeReadyController = null;
8627
+ const activeHandle = handle;
8628
+ if (activeHandle !== null) {
8629
+ activeHandle.kill("SIGTERM");
8630
+ const exited = await waitForExit(activeHandle, 5e3);
8631
+ if (!exited) {
8632
+ activeHandle.kill("SIGKILL");
8633
+ await activeHandle.result;
8634
+ }
8635
+ }
8636
+ clearStableTimer();
8637
+ handle = null;
8638
+ state.pid = null;
8639
+ state.lastStoppedAt = (/* @__PURE__ */ new Date()).toISOString();
8640
+ await transitionTo("stopped");
8641
+ }
8642
+ async function restart() {
8643
+ await stop();
8644
+ await start();
8645
+ }
8646
+ function getState() {
8647
+ return {
8648
+ ...state,
8649
+ args: [...state.args]
8650
+ };
8651
+ }
8652
+ async function launch(isRestart) {
8653
+ const nextRunId = runId + 1;
8654
+ runId = nextRunId;
8655
+ const nextHandle = runner.exec(createRunSpec(spec));
8656
+ handle = nextHandle;
8657
+ state.pid = nextHandle.pid;
8658
+ state.lastExitCode = null;
8659
+ state.lastStartedAt = (/* @__PURE__ */ new Date()).toISOString();
8660
+ const stdoutPump = pipeOutput(nextHandle.stdout, "stdout", logWriter.write, logSource);
8661
+ const stderrPump = pipeOutput(nextHandle.stderr, "stderr", logWriter.write, logSource);
8662
+ const outputSettled = Promise.all([stdoutPump, stderrPump]).then(() => void 0);
8663
+ scheduleStableReset(nextRunId, nextHandle);
8664
+ void monitorExit(nextHandle, nextRunId, outputSettled);
8665
+ if (spec.readyCheck !== void 0) {
8666
+ await transitionTo("restarting");
8667
+ activeReadyController = new AbortController();
8668
+ const ready = await waitForReady(resolveReadyCheck(spec.readyCheck, spec), {
8669
+ onLog: logSource,
8670
+ signal: activeReadyController.signal
8671
+ });
8672
+ activeReadyController = null;
8673
+ if (runId !== nextRunId || handle !== nextHandle) {
8674
+ return;
8675
+ }
8676
+ if (!ready) {
8677
+ nextHandle.kill("SIGTERM");
8678
+ return;
8679
+ }
8680
+ }
8681
+ if (isRestart || spec.readyCheck !== void 0) {
8682
+ await transitionTo("running");
8683
+ return;
8684
+ }
8685
+ await transitionTo("running");
8686
+ }
8687
+ async function monitorExit(finishedHandle, finishedRunId, outputSettled) {
8688
+ const result = await finishedHandle.result;
8689
+ await outputSettled;
8690
+ if (runId !== finishedRunId) {
8691
+ return;
8692
+ }
8693
+ clearStableTimer();
8694
+ activeReadyController?.abort();
8695
+ activeReadyController = null;
8696
+ handle = null;
8697
+ state.pid = null;
8698
+ state.lastExitCode = result.exitCode;
8699
+ state.lastStoppedAt = (/* @__PURE__ */ new Date()).toISOString();
8700
+ if (stopRequested || options.signal?.aborted) {
8701
+ await transitionTo("stopped");
8702
+ return;
8703
+ }
8704
+ if (!shouldRestart(result.exitCode, spec.restart)) {
8705
+ await transitionTo("stopped");
8706
+ return;
8707
+ }
8708
+ const maxRestarts = spec.maxRestarts ?? 5;
8709
+ if (maxRestarts > 0 && state.restartCount >= maxRestarts) {
8710
+ await transitionTo("crashed");
8711
+ return;
8712
+ }
8713
+ const backoffMs = getBackoffDelay(
8714
+ state.restartCount,
8715
+ spec.backoffMs ?? 1e3,
8716
+ spec.maxBackoffMs ?? 3e4
8717
+ );
8718
+ state.restartCount += 1;
8719
+ await logWriter.rotate();
8720
+ await transitionTo("restarting");
8721
+ const restartToken = /* @__PURE__ */ Symbol("restart");
8722
+ pendingRestart = restartToken;
8723
+ await delay(backoffMs);
8724
+ if (pendingRestart !== restartToken || stopRequested || options.signal?.aborted) {
8725
+ return;
8726
+ }
8727
+ pendingRestart = null;
8728
+ await launch(true);
8729
+ }
8730
+ async function transitionTo(status) {
8731
+ if (state.status === status) {
8732
+ return;
8733
+ }
8734
+ state = {
8735
+ ...state,
8736
+ args: [...state.args],
8737
+ status
8738
+ };
8739
+ await stateStore.write(spec.id, state);
8740
+ options.onStatusChange?.(getState());
8741
+ }
8742
+ function scheduleStableReset(activeRunId, activeHandle) {
8743
+ clearStableTimer();
8744
+ stableTimer = setTimeout(() => {
8745
+ if (runId !== activeRunId || handle !== activeHandle || state.restartCount === 0) {
8746
+ return;
8747
+ }
8748
+ state.restartCount = 0;
8749
+ void stateStore.write(spec.id, getState());
8750
+ }, 6e4);
8751
+ }
8752
+ function clearStableTimer() {
8753
+ if (stableTimer !== null) {
8754
+ clearTimeout(stableTimer);
8755
+ stableTimer = null;
8756
+ }
8757
+ }
8758
+ return {
8759
+ start,
8760
+ stop,
8761
+ restart,
8762
+ getState
8763
+ };
8764
+ }
8765
+ function resolveRunner(options) {
8766
+ if (options.runner !== void 0) {
8767
+ return options.runner;
8768
+ }
8769
+ if (options.spec.docker !== void 0) {
8770
+ return createDockerRunner(options.spec.docker);
8771
+ }
8772
+ return createHostRunner();
8773
+ }
8774
+ function createInitialState(spec, runner) {
8775
+ return {
8776
+ id: spec.id,
8777
+ pid: null,
8778
+ status: "stopped",
8779
+ runtime: spec.docker !== void 0 || runner.name === "docker" ? "docker" : "host",
8780
+ restartCount: 0,
8781
+ lastExitCode: null,
8782
+ lastStartedAt: null,
8783
+ lastStoppedAt: null,
8784
+ command: spec.command,
8785
+ args: [...spec.args ?? []]
8786
+ };
8787
+ }
8788
+ function createRunSpec(spec) {
8789
+ return {
8790
+ command: spec.command,
8791
+ args: spec.args,
8792
+ cwd: spec.cwd,
8793
+ env: spec.env,
8794
+ stderr: "pipe",
8795
+ stdout: "pipe"
8796
+ };
8797
+ }
8798
+ function shouldRestart(exitCode, policy) {
8799
+ if (policy === "always") {
8800
+ return true;
8801
+ }
8802
+ if (policy === "on-failure") {
8803
+ return exitCode !== 0;
8804
+ }
8805
+ return false;
8806
+ }
8807
+ function getBackoffDelay(restartCount, backoffMs, maxBackoffMs) {
8808
+ return Math.min(backoffMs * 2 ** restartCount, maxBackoffMs);
8809
+ }
8810
+ function delay(durationMs) {
8811
+ return new Promise((resolve) => {
8812
+ setTimeout(resolve, durationMs);
8813
+ });
8814
+ }
8815
+ function waitForExit(activeHandle, timeoutMs) {
8816
+ return new Promise((resolve) => {
8817
+ let finished = false;
8818
+ const timeout = setTimeout(() => {
8819
+ finish(false);
8820
+ }, timeoutMs);
8821
+ void activeHandle.result.then(() => {
8822
+ finish(true);
8823
+ });
8824
+ function finish(result) {
8825
+ if (finished) {
8826
+ return;
8827
+ }
8828
+ finished = true;
8829
+ clearTimeout(timeout);
8830
+ resolve(result);
8831
+ }
8832
+ });
8833
+ }
8834
+ function createLogSource(onLog) {
8835
+ const listeners = /* @__PURE__ */ new Set();
8836
+ const log3 = ((line, stream) => {
8837
+ onLog?.(line, stream);
8838
+ for (const listener of listeners) {
8839
+ listener(line, stream);
8840
+ }
8841
+ });
8842
+ log3.subscribe = (listener) => {
8843
+ listeners.add(listener);
8844
+ return () => {
8845
+ listeners.delete(listener);
8846
+ };
8847
+ };
8848
+ return log3;
8849
+ }
8850
+ function pipeOutput(stream, output, write2, onLog) {
8851
+ if (stream === null) {
8852
+ return Promise.resolve();
8853
+ }
8854
+ return new Promise((resolve, reject) => {
8855
+ let remainder = "";
8856
+ let writes = Promise.resolve();
8857
+ stream.setEncoding("utf8");
8858
+ stream.on("data", (chunk) => {
8859
+ remainder += chunk;
8860
+ while (true) {
8861
+ const lineBreak = remainder.indexOf("\n");
8862
+ if (lineBreak === -1) {
8863
+ break;
8864
+ }
8865
+ const rawLine = remainder.slice(0, lineBreak);
8866
+ remainder = remainder.slice(lineBreak + 1);
8867
+ writes = writes.then(async () => {
8868
+ const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
8869
+ onLog(line, output);
8870
+ await write2(line, output);
8871
+ });
8872
+ }
8873
+ });
8874
+ stream.once("end", () => {
8875
+ if (remainder.length > 0) {
8876
+ const finalLine = remainder.endsWith("\r") ? remainder.slice(0, -1) : remainder;
8877
+ writes = writes.then(async () => {
8878
+ onLog(finalLine, output);
8879
+ await write2(finalLine, output);
8880
+ });
8881
+ }
8882
+ void writes.then(() => {
8883
+ resolve();
8884
+ }, reject);
8885
+ });
8886
+ stream.once("error", reject);
8887
+ });
8888
+ }
8889
+ function resolveReadyCheck(check, spec) {
8890
+ if (check.kind !== "tcp" || spec.docker === void 0) {
8891
+ return check;
8892
+ }
8893
+ const portMapping = spec.docker.ports?.find((mapping) => {
8894
+ if (mapping.container !== check.port) {
8895
+ return false;
8896
+ }
8897
+ return mapping.protocol === void 0 || mapping.protocol === "tcp";
8898
+ });
8899
+ if (portMapping === void 0) {
8900
+ return check;
8901
+ }
8902
+ return {
8903
+ ...check,
8904
+ port: portMapping.host
8905
+ };
8906
+ }
8907
+ var init_supervisor = __esm({
8908
+ "packages/process-launcher/src/supervisor/supervisor.ts"() {
8909
+ "use strict";
8910
+ init_src9();
8911
+ init_health_check();
8912
+ init_log_writer();
8913
+ init_state_store();
8914
+ }
8915
+ });
8916
+
8917
+ // packages/process-launcher/src/launcher.ts
8918
+ import path19 from "node:path";
8919
+ import * as nodeFs3 from "node:fs/promises";
8920
+ async function startManagedProcess(options) {
8921
+ const fs3 = options.fs ?? defaultFs();
8922
+ const spec = normalizeSpec(options.spec);
8923
+ const existing = await readManagedProcess({
8924
+ baseDir: options.baseDir,
8925
+ fs: fs3,
8926
+ id: spec.id,
8927
+ isPidRunning: options.isPidRunning
8928
+ });
8929
+ if (isActiveRecord(existing)) {
8930
+ throw new Error(`Managed process "${spec.id}" is already running.`);
8931
+ }
8932
+ await fs3.mkdir(resolveProcessDir(options.baseDir, spec.id), { recursive: true });
8933
+ await writeSpec(fs3, options.baseDir, spec);
8934
+ await writeState(fs3, options.baseDir, createBootstrapState(spec));
8935
+ await writeMeta(fs3, options.baseDir, spec.id, { daemonPid: null });
8936
+ const daemonPid = await options.spawnDaemon(spec.id);
8937
+ await writeMeta(fs3, options.baseDir, spec.id, { daemonPid });
8938
+ const started = await waitForRecord({
8939
+ baseDir: options.baseDir,
8940
+ fs: fs3,
8941
+ id: spec.id,
8942
+ isPidRunning: options.isPidRunning,
8943
+ pollIntervalMs: options.pollIntervalMs,
8944
+ timeoutMs: options.startupTimeoutMs,
8945
+ ready: (record) => record.state !== null && record.state.status !== "restarting"
8946
+ });
8947
+ return started;
8948
+ }
8949
+ async function stopManagedProcess(options) {
8950
+ const fs3 = options.fs ?? defaultFs();
8951
+ const record = await readManagedProcess({
8952
+ baseDir: options.baseDir,
8953
+ fs: fs3,
8954
+ id: options.id,
8955
+ isPidRunning: options.isPidRunning
8956
+ });
8957
+ if (record.spec === null && record.state === null && record.daemonPid === null) {
8958
+ return null;
8959
+ }
8960
+ const signal = options.force ? "SIGKILL" : "SIGTERM";
8961
+ const signalProcess = options.signalProcess ?? defaultSignalProcess;
8962
+ const daemonPid = record.daemonPid;
8963
+ if (daemonPid !== null && isProcessRunning(daemonPid, options.isPidRunning)) {
8964
+ signalProcess(daemonPid, signal);
8965
+ } else if (record.state?.runtime === "host" && record.state.pid !== null) {
8966
+ if (isProcessRunning(record.state.pid, options.isPidRunning)) {
8967
+ signalProcess(record.state.pid, signal);
8968
+ }
8969
+ }
8970
+ if (record.spec?.docker && options.stopRuntimeArtifacts) {
8971
+ await options.stopRuntimeArtifacts({ record, force: Boolean(options.force) });
8972
+ }
8973
+ const stopped = await waitForStop({
8974
+ baseDir: options.baseDir,
8975
+ fs: fs3,
8976
+ id: options.id,
8977
+ isPidRunning: options.isPidRunning,
8978
+ pollIntervalMs: options.pollIntervalMs,
8979
+ timeoutMs: options.stopTimeoutMs
8980
+ });
8981
+ if (isActiveRecord(stopped)) {
8982
+ const persisted = createStoppedState(stopped);
8983
+ await writeState(fs3, options.baseDir, persisted);
8984
+ await writeMeta(fs3, options.baseDir, options.id, { daemonPid: null });
8985
+ return {
8986
+ ...stopped,
8987
+ daemonPid: null,
8988
+ state: persisted
8989
+ };
8990
+ }
8991
+ if (record.state !== null && isActiveStatus(record.state.status) && stopped.state !== null && !isActiveStatus(stopped.state.status)) {
8992
+ await writeState(fs3, options.baseDir, stopped.state);
8993
+ await writeMeta(fs3, options.baseDir, options.id, { daemonPid: null });
8994
+ }
8995
+ return stopped;
8996
+ }
8997
+ async function restartManagedProcess(options) {
8998
+ const fs3 = options.fs ?? defaultFs();
8999
+ const record = await readManagedProcess({
9000
+ baseDir: options.baseDir,
9001
+ fs: fs3,
9002
+ id: options.id,
9003
+ isPidRunning: options.isPidRunning
9004
+ });
9005
+ if (record.spec === null) {
9006
+ throw new Error(`Managed process "${options.id}" was not found.`);
9007
+ }
9008
+ await stopManagedProcess({
9009
+ baseDir: options.baseDir,
9010
+ force: false,
9011
+ fs: fs3,
9012
+ id: options.id,
9013
+ isPidRunning: options.isPidRunning,
9014
+ pollIntervalMs: options.pollIntervalMs,
9015
+ signalProcess: options.signalProcess,
9016
+ stopRuntimeArtifacts: options.stopRuntimeArtifacts,
9017
+ stopTimeoutMs: options.stopTimeoutMs
9018
+ });
9019
+ return await startManagedProcess({
9020
+ baseDir: options.baseDir,
9021
+ fs: fs3,
9022
+ isPidRunning: options.isPidRunning,
9023
+ pollIntervalMs: options.pollIntervalMs,
9024
+ spawnDaemon: options.spawnDaemon,
9025
+ spec: record.spec,
9026
+ startupTimeoutMs: options.startupTimeoutMs
9027
+ });
9028
+ }
9029
+ async function listManagedProcesses(options) {
9030
+ const fs3 = options.fs ?? defaultFs();
9031
+ const ids = await listIds(fs3, options.baseDir);
9032
+ const records = [];
9033
+ for (const id of ids) {
9034
+ records.push(
9035
+ await readManagedProcess({
9036
+ baseDir: options.baseDir,
9037
+ fs: fs3,
9038
+ id,
9039
+ isPidRunning: options.isPidRunning
9040
+ })
9041
+ );
9042
+ }
9043
+ return records.sort((left, right) => {
9044
+ const leftId = left.spec?.id ?? left.state?.id ?? "";
9045
+ const rightId = right.spec?.id ?? right.state?.id ?? "";
9046
+ return leftId.localeCompare(rightId);
9047
+ });
9048
+ }
9049
+ async function readManagedLogs(options) {
9050
+ const fs3 = options.fs ?? defaultFs();
9051
+ const logWriter = createLogWriter(
9052
+ resolveLogDir2(options.baseDir, options.id),
9053
+ 5,
9054
+ fs3
9055
+ );
9056
+ return await logWriter.tail(options.stream ?? "stdout", options.lines ?? 50);
9057
+ }
9058
+ async function* followManagedLogs(options) {
9059
+ const stream = options.stream ?? "stdout";
9060
+ let previous = await readManagedLogs(options);
9061
+ const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
9062
+ while (!options.signal?.aborted) {
9063
+ await sleep2(pollIntervalMs);
9064
+ if (options.signal?.aborted) {
9065
+ return;
9066
+ }
9067
+ const next = await readManagedLogs({
9068
+ baseDir: options.baseDir,
9069
+ fs: options.fs,
9070
+ id: options.id,
9071
+ lines: options.lines,
9072
+ stream
9073
+ });
9074
+ const delta = next.slice(previous.length);
9075
+ previous = next;
9076
+ for (const line of delta) {
9077
+ yield line;
9078
+ }
9079
+ }
9080
+ }
9081
+ async function removeManagedProcess(options) {
9082
+ const fs3 = options.fs ?? defaultFs();
9083
+ const record = await readManagedProcess({
9084
+ baseDir: options.baseDir,
9085
+ fs: fs3,
9086
+ id: options.id,
9087
+ isPidRunning: options.isPidRunning
9088
+ });
9089
+ if (isActiveRecord(record)) {
9090
+ throw new Error(`Managed process "${options.id}" must be stopped before removal.`);
9091
+ }
9092
+ if (record.spec !== null && options.removeRuntimeArtifacts) {
9093
+ await options.removeRuntimeArtifacts({ record });
9094
+ }
9095
+ const stateStore = createStateStore(options.baseDir, fs3);
9096
+ await stateStore.remove(options.id);
9097
+ }
9098
+ async function runManagedProcess(options) {
9099
+ const fs3 = options.fs ?? defaultFs();
9100
+ const spec = await readSpec(fs3, options.baseDir, options.id);
9101
+ if (spec === null) {
9102
+ throw new Error(`Managed process "${options.id}" was not found.`);
9103
+ }
9104
+ const controller = new AbortController();
9105
+ const onExternalAbort = () => {
9106
+ controller.abort();
9107
+ };
9108
+ options.signal?.addEventListener("abort", onExternalAbort, { once: true });
9109
+ const onSignal = () => {
9110
+ controller.abort();
9111
+ };
9112
+ process.once("SIGINT", onSignal);
9113
+ process.once("SIGTERM", onSignal);
9114
+ try {
9115
+ await writeMeta(fs3, options.baseDir, options.id, { daemonPid: process.pid });
9116
+ const supervisor = createSupervisor({
9117
+ fs: fs3,
9118
+ signal: controller.signal,
9119
+ spec,
9120
+ stateDir: options.baseDir
9121
+ });
9122
+ await supervisor.start();
9123
+ const pollIntervalMs = options.pollIntervalMs ?? 250;
9124
+ while (!controller.signal.aborted) {
9125
+ const state = supervisor.getState();
9126
+ if (!isActiveStatus(state.status) && state.pid === null) {
9127
+ return;
9128
+ }
9129
+ await sleep2(pollIntervalMs);
9130
+ }
9131
+ await supervisor.stop();
9132
+ } finally {
9133
+ process.removeListener("SIGINT", onSignal);
9134
+ process.removeListener("SIGTERM", onSignal);
9135
+ options.signal?.removeEventListener("abort", onExternalAbort);
9136
+ await writeMeta(fs3, options.baseDir, options.id, { daemonPid: null });
9137
+ }
9138
+ }
9139
+ async function waitForRecord(options) {
9140
+ const deadline = Date.now() + (options.timeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS);
9141
+ while (Date.now() <= deadline) {
9142
+ const record = await readManagedProcess(options);
9143
+ if (options.ready(record)) {
9144
+ return record;
9145
+ }
9146
+ await sleep2(options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
9147
+ }
9148
+ throw new Error(`Timed out waiting for managed process "${options.id}".`);
9149
+ }
9150
+ async function waitForStop(options) {
9151
+ const deadline = Date.now() + (options.timeoutMs ?? DEFAULT_STOP_TIMEOUT_MS);
9152
+ while (Date.now() <= deadline) {
9153
+ const record = await readManagedProcess(options);
9154
+ if (!isActiveRecord(record)) {
9155
+ return record;
9156
+ }
9157
+ await sleep2(options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
9158
+ }
9159
+ return await readManagedProcess(options);
9160
+ }
9161
+ async function readManagedProcess(options) {
9162
+ const spec = await readSpec(options.fs, options.baseDir, options.id);
9163
+ const state = await readState(options.fs, options.baseDir, options.id);
9164
+ const meta = await readMeta(options.fs, options.baseDir, options.id);
9165
+ return normalizeRecord(
9166
+ { daemonPid: meta?.daemonPid ?? null, spec, state },
9167
+ options.isPidRunning
9168
+ );
9169
+ }
9170
+ function normalizeRecord(record, isPidRunningOverride) {
9171
+ if (record.state === null || !isActiveStatus(record.state.status)) {
9172
+ return {
9173
+ ...record,
9174
+ daemonPid: isProcessRunning(record.daemonPid, isPidRunningOverride) ? record.daemonPid : null
9175
+ };
9176
+ }
9177
+ if (isProcessRunning(record.daemonPid, isPidRunningOverride)) {
9178
+ return record;
9179
+ }
9180
+ return {
9181
+ ...record,
9182
+ daemonPid: null,
9183
+ state: createStoppedState(record)
9184
+ };
9185
+ }
9186
+ function createStoppedState(record) {
9187
+ const spec = record.spec;
9188
+ const state = record.state;
9189
+ if (state !== null) {
9190
+ return {
9191
+ ...state,
9192
+ pid: null,
9193
+ status: state.lastExitCode != null && state.lastExitCode !== 0 ? "crashed" : "stopped",
9194
+ lastStoppedAt: state.lastStoppedAt ?? (/* @__PURE__ */ new Date()).toISOString()
9195
+ };
9196
+ }
9197
+ if (spec === null) {
9198
+ throw new Error("Cannot create a stopped state without spec or state.");
9199
+ }
9200
+ return {
9201
+ args: [...spec.args ?? []],
9202
+ command: spec.command,
9203
+ id: spec.id,
9204
+ lastExitCode: null,
9205
+ lastStartedAt: null,
9206
+ lastStoppedAt: (/* @__PURE__ */ new Date()).toISOString(),
9207
+ pid: null,
9208
+ restartCount: 0,
9209
+ runtime: spec.docker ? "docker" : "host",
9210
+ status: "stopped"
9211
+ };
9212
+ }
9213
+ function createBootstrapState(spec) {
9214
+ return {
9215
+ args: [...spec.args ?? []],
9216
+ command: spec.command,
9217
+ id: spec.id,
9218
+ lastExitCode: null,
9219
+ lastStartedAt: null,
9220
+ lastStoppedAt: null,
9221
+ pid: null,
9222
+ restartCount: 0,
9223
+ runtime: spec.docker ? "docker" : "host",
9224
+ status: "restarting"
9225
+ };
9226
+ }
9227
+ function normalizeSpec(spec) {
9228
+ if (!spec.docker) {
9229
+ return {
9230
+ ...spec,
9231
+ args: [...spec.args ?? []],
9232
+ env: spec.env ? { ...spec.env } : void 0
9233
+ };
9234
+ }
9235
+ return {
9236
+ ...spec,
9237
+ args: [...spec.args ?? []],
9238
+ docker: {
9239
+ ...spec.docker,
9240
+ containerName: spec.docker.containerName ?? buildContainerName2(spec.id),
9241
+ mounts: spec.docker.mounts ? [...spec.docker.mounts] : void 0,
9242
+ ports: spec.docker.ports ? [...spec.docker.ports] : void 0
9243
+ },
9244
+ env: spec.env ? { ...spec.env } : void 0
9245
+ };
9246
+ }
9247
+ function buildContainerName2(id) {
9248
+ let output = "poe-launch-";
9249
+ for (const char of id) {
9250
+ const code = char.charCodeAt(0);
9251
+ const isAlphaNumeric = code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122;
9252
+ output += isAlphaNumeric || char === "." || char === "_" || char === "-" ? char : "-";
9253
+ }
9254
+ return output;
9255
+ }
9256
+ function isActiveRecord(record) {
9257
+ return record.state !== null && isActiveStatus(record.state.status);
9258
+ }
9259
+ function isActiveStatus(status) {
9260
+ return status === "running" || status === "restarting";
9261
+ }
9262
+ async function listIds(fs3, baseDir) {
9263
+ try {
9264
+ const entries = await fs3.readdir(baseDir);
9265
+ const ids = [];
9266
+ for (const entry of entries) {
9267
+ const entryPath = path19.join(baseDir, entry);
9268
+ try {
9269
+ const stat11 = await fs3.stat(entryPath);
9270
+ if (!stat11.isFile()) {
9271
+ ids.push(entry);
9272
+ }
9273
+ } catch (error) {
9274
+ if (!isNotFoundError4(error)) {
9275
+ throw error;
9276
+ }
9277
+ }
9278
+ }
9279
+ return ids.sort();
9280
+ } catch (error) {
9281
+ if (isNotFoundError4(error)) {
9282
+ return [];
9283
+ }
9284
+ throw error;
9285
+ }
9286
+ }
9287
+ async function readSpec(fs3, baseDir, id) {
9288
+ return await readJsonFile(fs3, resolveSpecPath(baseDir, id));
9289
+ }
9290
+ async function writeSpec(fs3, baseDir, spec) {
9291
+ await writeJsonFile(fs3, resolveSpecPath(baseDir, spec.id), spec);
9292
+ }
9293
+ async function readState(fs3, baseDir, id) {
9294
+ return await readJsonFile(fs3, resolveStatePath(baseDir, id));
9295
+ }
9296
+ async function writeState(fs3, baseDir, state) {
9297
+ await writeJsonFile(fs3, resolveStatePath(baseDir, state.id), state);
9298
+ }
9299
+ async function readMeta(fs3, baseDir, id) {
9300
+ return await readJsonFile(fs3, resolveMetaPath(baseDir, id));
9301
+ }
9302
+ async function writeMeta(fs3, baseDir, id, meta) {
9303
+ await writeJsonFile(fs3, resolveMetaPath(baseDir, id), meta);
9304
+ }
9305
+ async function readJsonFile(fs3, filePath) {
9306
+ try {
9307
+ const content = await fs3.readFile(filePath, "utf8");
9308
+ return JSON.parse(content);
9309
+ } catch (error) {
9310
+ if (isNotFoundError4(error)) {
9311
+ return null;
9312
+ }
9313
+ throw error;
9314
+ }
9315
+ }
9316
+ async function writeJsonFile(fs3, filePath, value) {
9317
+ await fs3.mkdir(path19.dirname(filePath), { recursive: true });
9318
+ await fs3.writeFile(filePath, `${JSON.stringify(value, null, 2)}
9319
+ `);
9320
+ }
9321
+ function resolveProcessDir(baseDir, id) {
9322
+ return path19.join(baseDir, id);
9323
+ }
9324
+ function resolveSpecPath(baseDir, id) {
9325
+ return path19.join(resolveProcessDir(baseDir, id), "spec.json");
9326
+ }
9327
+ function resolveStatePath(baseDir, id) {
9328
+ return path19.join(resolveProcessDir(baseDir, id), "state.json");
9329
+ }
9330
+ function resolveMetaPath(baseDir, id) {
9331
+ return path19.join(resolveProcessDir(baseDir, id), "meta.json");
9332
+ }
9333
+ function resolveLogDir2(baseDir, id) {
9334
+ return path19.join(resolveProcessDir(baseDir, id), "logs");
9335
+ }
9336
+ function isNotFoundError4(error) {
9337
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
9338
+ }
9339
+ function defaultFs() {
9340
+ return nodeFs3;
9341
+ }
9342
+ function defaultSignalProcess(pid, signal) {
9343
+ process.kill(pid, signal);
9344
+ }
9345
+ function isProcessRunning(pid, isPidRunningOverride) {
9346
+ if (pid === null) {
9347
+ return false;
9348
+ }
9349
+ if (isPidRunningOverride) {
9350
+ return isPidRunningOverride(pid);
9351
+ }
9352
+ try {
9353
+ process.kill(pid, 0);
9354
+ return true;
9355
+ } catch {
9356
+ return false;
9357
+ }
9358
+ }
9359
+ function sleep2(durationMs) {
9360
+ return new Promise((resolve) => {
9361
+ setTimeout(resolve, durationMs);
9362
+ });
9363
+ }
9364
+ var DEFAULT_POLL_INTERVAL_MS, DEFAULT_STARTUP_TIMEOUT_MS, DEFAULT_STOP_TIMEOUT_MS;
9365
+ var init_launcher = __esm({
9366
+ "packages/process-launcher/src/launcher.ts"() {
9367
+ "use strict";
9368
+ init_log_writer();
9369
+ init_state_store();
9370
+ init_supervisor();
9371
+ DEFAULT_POLL_INTERVAL_MS = 100;
9372
+ DEFAULT_STARTUP_TIMEOUT_MS = 3e4;
9373
+ DEFAULT_STOP_TIMEOUT_MS = 5e3;
9374
+ }
9375
+ });
9376
+
9377
+ // packages/process-launcher/src/index.ts
9378
+ var init_src10 = __esm({
9379
+ "packages/process-launcher/src/index.ts"() {
9380
+ "use strict";
9381
+ init_state_store();
9382
+ init_log_writer();
9383
+ init_health_check();
9384
+ init_supervisor();
9385
+ init_launcher();
9386
+ }
9387
+ });
9388
+
7892
9389
  // packages/ralph/src/frontmatter/frontmatter.ts
7893
9390
  import { parse as parse6, stringify } from "yaml";
7894
9391
  function parseFrontmatter(content) {
@@ -8017,7 +9514,7 @@ var init_frontmatter = __esm({
8017
9514
  });
8018
9515
 
8019
9516
  // packages/ralph/src/discovery/discovery.ts
8020
- import path15 from "node:path";
9517
+ import path20 from "node:path";
8021
9518
  import * as fsPromises4 from "node:fs/promises";
8022
9519
  function createDefaultFs4() {
8023
9520
  return {
@@ -8052,12 +9549,12 @@ async function scanDir(fs3, absoluteDir, displayDir) {
8052
9549
  if (!isMarkdownFile(entry)) {
8053
9550
  continue;
8054
9551
  }
8055
- const absolutePath = path15.join(absoluteDir, entry);
9552
+ const absolutePath = path20.join(absoluteDir, entry);
8056
9553
  const stat11 = await fs3.stat(absolutePath);
8057
9554
  if (!stat11.isFile()) {
8058
9555
  continue;
8059
9556
  }
8060
- const displayPath = path15.join(displayDir, entry);
9557
+ const displayPath = path20.join(displayDir, entry);
8061
9558
  docs.push({
8062
9559
  path: displayPath,
8063
9560
  displayPath
@@ -8070,8 +9567,8 @@ async function discoverDocs(options) {
8070
9567
  const customDir = options.planDirectory?.trim();
8071
9568
  const docs = customDir ? await scanCustomDir(fs3, customDir, options.cwd, options.homeDir) : await scanDefaultDirs(fs3, options.cwd, options.homeDir);
8072
9569
  return docs.sort((left, right) => {
8073
- const leftName = path15.basename(left.displayPath).toLowerCase();
8074
- const rightName = path15.basename(right.displayPath).toLowerCase();
9570
+ const leftName = path20.basename(left.displayPath).toLowerCase();
9571
+ const rightName = path20.basename(right.displayPath).toLowerCase();
8075
9572
  return leftName === rightName ? left.displayPath.localeCompare(right.displayPath) : leftName.localeCompare(rightName);
8076
9573
  });
8077
9574
  }
@@ -8084,12 +9581,12 @@ async function scanDefaultDirs(fs3, cwd, homeDir) {
8084
9581
  const [localDocs, globalDocs] = await Promise.all([
8085
9582
  scanDir(
8086
9583
  fs3,
8087
- path15.join(cwd, ".poe-code", "ralph", "plans"),
9584
+ path20.join(cwd, ".poe-code", "ralph", "plans"),
8088
9585
  ".poe-code/ralph/plans"
8089
9586
  ),
8090
9587
  scanDir(
8091
9588
  fs3,
8092
- path15.join(homeDir, ".poe-code", "ralph", "plans"),
9589
+ path20.join(homeDir, ".poe-code", "ralph", "plans"),
8093
9590
  "~/.poe-code/ralph/plans"
8094
9591
  )
8095
9592
  ]);
@@ -8097,9 +9594,9 @@ async function scanDefaultDirs(fs3, cwd, homeDir) {
8097
9594
  }
8098
9595
  function resolveAbsoluteDirectory2(dir, cwd, homeDir) {
8099
9596
  if (dir.startsWith("~/")) {
8100
- return path15.join(homeDir, dir.slice(2));
9597
+ return path20.join(homeDir, dir.slice(2));
8101
9598
  }
8102
- return path15.isAbsolute(dir) ? dir : path15.resolve(cwd, dir);
9599
+ return path20.isAbsolute(dir) ? dir : path20.resolve(cwd, dir);
8103
9600
  }
8104
9601
  var init_discovery2 = __esm({
8105
9602
  "packages/ralph/src/discovery/discovery.ts"() {
@@ -8108,7 +9605,7 @@ var init_discovery2 = __esm({
8108
9605
  });
8109
9606
 
8110
9607
  // packages/ralph/src/run/ralph.ts
8111
- import path16 from "node:path";
9608
+ import path21 from "node:path";
8112
9609
  import * as fsPromises5 from "node:fs/promises";
8113
9610
  async function runRalph(options) {
8114
9611
  const fs3 = options.fs ?? createDefaultFs5();
@@ -8240,9 +9737,9 @@ function normalizeAgents(agent2) {
8240
9737
  }
8241
9738
  function resolveAbsoluteDocPath(docPath, cwd, homeDir) {
8242
9739
  if (docPath.startsWith("~/")) {
8243
- return path16.join(homeDir, docPath.slice(2));
9740
+ return path21.join(homeDir, docPath.slice(2));
8244
9741
  }
8245
- return path16.isAbsolute(docPath) ? docPath : path16.resolve(cwd, docPath);
9742
+ return path21.isAbsolute(docPath) ? docPath : path21.resolve(cwd, docPath);
8246
9743
  }
8247
9744
  function assertNotAborted2(signal) {
8248
9745
  if (!signal?.aborted) {
@@ -8273,9 +9770,9 @@ async function updateFrontmatter(fs3, absoluteDocPath, body, frontmatter, state,
8273
9770
  await fs3.writeFile(absoluteDocPath, content);
8274
9771
  }
8275
9772
  async function archivePlan2(fs3, absoluteDocPath) {
8276
- const dir = path16.dirname(absoluteDocPath);
8277
- const archiveDir = path16.join(dir, "archive");
8278
- const archivePath = path16.join(archiveDir, path16.basename(absoluteDocPath));
9773
+ const dir = path21.dirname(absoluteDocPath);
9774
+ const archiveDir = path21.join(dir, "archive");
9775
+ const archivePath = path21.join(archiveDir, path21.basename(absoluteDocPath));
8279
9776
  await fs3.mkdir(archiveDir, { recursive: true });
8280
9777
  await fs3.rename(absoluteDocPath, archivePath);
8281
9778
  }
@@ -8299,7 +9796,7 @@ var init_ralph = __esm({
8299
9796
  });
8300
9797
 
8301
9798
  // packages/ralph/src/index.ts
8302
- var init_src9 = __esm({
9799
+ var init_src11 = __esm({
8303
9800
  "packages/ralph/src/index.ts"() {
8304
9801
  "use strict";
8305
9802
  init_frontmatter();
@@ -8328,7 +9825,7 @@ async function runRalph2(options) {
8328
9825
  var init_ralph2 = __esm({
8329
9826
  async "src/sdk/ralph.ts"() {
8330
9827
  "use strict";
8331
- init_src9();
9828
+ init_src11();
8332
9829
  init_src6();
8333
9830
  await init_spawn3();
8334
9831
  }
@@ -8668,7 +10165,7 @@ var init_git = __esm({
8668
10165
  });
8669
10166
 
8670
10167
  // packages/experiment-loop/src/config/loader.ts
8671
- import path17 from "node:path";
10168
+ import path22 from "node:path";
8672
10169
  import { parse as parse7 } from "yaml";
8673
10170
  function isRecord6(value) {
8674
10171
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -8710,8 +10207,8 @@ function defaultRunConfig() {
8710
10207
  return { prompt: DEFAULT_PROMPT };
8711
10208
  }
8712
10209
  async function loadRunConfig(options) {
8713
- const projectPath = path17.join(options.cwd, ".poe-code", "experiments", "run.yaml");
8714
- const globalPath = path17.join(options.homeDir, ".poe-code", "experiments", "run.yaml");
10210
+ const projectPath = path22.join(options.cwd, ".poe-code", "experiments", "run.yaml");
10211
+ const globalPath = path22.join(options.homeDir, ".poe-code", "experiments", "run.yaml");
8715
10212
  const projectContent = await readOptionalFile2(options.fs, projectPath);
8716
10213
  if (projectContent != null) {
8717
10214
  const config = parseRunConfigDocument(projectPath, projectContent);
@@ -8752,7 +10249,7 @@ Do not write to the journal file or commit changes. Both are managed automatical
8752
10249
  // packages/experiment-loop/src/run/loop.ts
8753
10250
  import { exec as execCallback } from "node:child_process";
8754
10251
  import * as fsPromises6 from "node:fs/promises";
8755
- import path18 from "node:path";
10252
+ import path23 from "node:path";
8756
10253
  function createDefaultFs6() {
8757
10254
  return {
8758
10255
  readFile: fsPromises6.readFile,
@@ -8796,14 +10293,14 @@ function createDefaultExec() {
8796
10293
  }
8797
10294
  function resolveAbsoluteDocPath2(docPath, cwd, homeDir) {
8798
10295
  if (docPath.startsWith("~/")) {
8799
- return path18.join(homeDir, docPath.slice(2));
10296
+ return path23.join(homeDir, docPath.slice(2));
8800
10297
  }
8801
- return path18.isAbsolute(docPath) ? docPath : path18.resolve(cwd, docPath);
10298
+ return path23.isAbsolute(docPath) ? docPath : path23.resolve(cwd, docPath);
8802
10299
  }
8803
10300
  function resolveJournalPath(docPath) {
8804
- return path18.join(
8805
- path18.dirname(docPath),
8806
- `${path18.basename(docPath, path18.extname(docPath))}.journal.jsonl`
10301
+ return path23.join(
10302
+ path23.dirname(docPath),
10303
+ `${path23.basename(docPath, path23.extname(docPath))}.journal.jsonl`
8807
10304
  );
8808
10305
  }
8809
10306
  function normalizeMetrics(metric) {
@@ -9081,7 +10578,7 @@ async function runExperimentLoop(options) {
9081
10578
  });
9082
10579
  continue;
9083
10580
  }
9084
- const commitMessage = `experiment-loop: ${path18.basename(absoluteDocPath, path18.extname(absoluteDocPath))} #${experimentIndex}`;
10581
+ const commitMessage = `experiment-loop: ${path23.basename(absoluteDocPath, path23.extname(absoluteDocPath))} #${experimentIndex}`;
9085
10582
  let commitHash;
9086
10583
  try {
9087
10584
  commitHash = await git.commitAll(commitMessage, options.cwd);
@@ -9178,7 +10675,7 @@ var init_loop = __esm({
9178
10675
  });
9179
10676
 
9180
10677
  // packages/experiment-loop/src/index.ts
9181
- var init_src10 = __esm({
10678
+ var init_src12 = __esm({
9182
10679
  "packages/experiment-loop/src/index.ts"() {
9183
10680
  "use strict";
9184
10681
  init_types2();
@@ -9192,7 +10689,7 @@ var init_src10 = __esm({
9192
10689
  });
9193
10690
 
9194
10691
  // src/sdk/experiment.ts
9195
- import path19 from "node:path";
10692
+ import path24 from "node:path";
9196
10693
  import * as fsPromises7 from "node:fs/promises";
9197
10694
  function createDefaultFs7() {
9198
10695
  return {
@@ -9218,14 +10715,14 @@ function createDefaultFs7() {
9218
10715
  }
9219
10716
  function resolveAbsoluteDocPath3(docPath, cwd, homeDir) {
9220
10717
  if (docPath.startsWith("~/")) {
9221
- return path19.join(homeDir, docPath.slice(2));
10718
+ return path24.join(homeDir, docPath.slice(2));
9222
10719
  }
9223
- return path19.isAbsolute(docPath) ? docPath : path19.resolve(cwd, docPath);
10720
+ return path24.isAbsolute(docPath) ? docPath : path24.resolve(cwd, docPath);
9224
10721
  }
9225
10722
  function resolveJournalPath2(docPath) {
9226
- return path19.join(
9227
- path19.dirname(docPath),
9228
- `${path19.basename(docPath, path19.extname(docPath))}.journal.jsonl`
10723
+ return path24.join(
10724
+ path24.dirname(docPath),
10725
+ `${path24.basename(docPath, path24.extname(docPath))}.journal.jsonl`
9229
10726
  );
9230
10727
  }
9231
10728
  async function runExperiment(options) {
@@ -9253,7 +10750,7 @@ async function readExperimentJournal(options) {
9253
10750
  var init_experiment = __esm({
9254
10751
  async "src/sdk/experiment.ts"() {
9255
10752
  "use strict";
9256
- init_src10();
10753
+ init_src12();
9257
10754
  init_src6();
9258
10755
  await init_spawn3();
9259
10756
  }
@@ -9322,99 +10819,393 @@ async function readErrorBody(response) {
9322
10819
  return void 0;
9323
10820
  }
9324
10821
  }
9325
- function extractTextContent(data) {
9326
- if (!isRecord7(data)) return void 0;
9327
- const choices = data.choices;
9328
- if (!Array.isArray(choices) || choices.length === 0) return void 0;
9329
- const first = choices[0];
9330
- if (!isRecord7(first)) return void 0;
9331
- const message = first.message;
9332
- if (!isRecord7(message)) return void 0;
9333
- return typeof message.content === "string" ? message.content : void 0;
10822
+ function extractTextContent(data) {
10823
+ if (!isRecord7(data)) return void 0;
10824
+ const choices = data.choices;
10825
+ if (!Array.isArray(choices) || choices.length === 0) return void 0;
10826
+ const first = choices[0];
10827
+ if (!isRecord7(first)) return void 0;
10828
+ const message = first.message;
10829
+ if (!isRecord7(message)) return void 0;
10830
+ return typeof message.content === "string" ? message.content : void 0;
10831
+ }
10832
+ function extractMediaFromCompletion(data) {
10833
+ const content = extractTextContent(data);
10834
+ if (!content) return {};
10835
+ try {
10836
+ const parsed = JSON.parse(content);
10837
+ if (isRecord7(parsed) && typeof parsed.url === "string") {
10838
+ return {
10839
+ url: parsed.url,
10840
+ mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0,
10841
+ data: typeof parsed.data === "string" ? parsed.data : void 0
10842
+ };
10843
+ }
10844
+ if (isRecord7(parsed) && typeof parsed.data === "string") {
10845
+ return {
10846
+ data: parsed.data,
10847
+ mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0
10848
+ };
10849
+ }
10850
+ } catch {
10851
+ }
10852
+ if (isValidUrl(content.trim())) {
10853
+ return { url: content.trim() };
10854
+ }
10855
+ const markdownUrl = extractMarkdownUrl(content);
10856
+ if (markdownUrl) {
10857
+ return { url: markdownUrl };
10858
+ }
10859
+ return { content };
10860
+ }
10861
+ function extractMarkdownUrl(content) {
10862
+ const start = content.indexOf("](");
10863
+ if (start === -1) return void 0;
10864
+ const urlStart = start + 2;
10865
+ const end = content.indexOf(")", urlStart);
10866
+ if (end === -1) return void 0;
10867
+ const url = content.slice(urlStart, end);
10868
+ return isValidUrl(url) ? url : void 0;
10869
+ }
10870
+ function isValidUrl(value) {
10871
+ try {
10872
+ new URL(value);
10873
+ return true;
10874
+ } catch {
10875
+ return false;
10876
+ }
10877
+ }
10878
+ function isRecord7(value) {
10879
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
10880
+ }
10881
+ var init_llm_client = __esm({
10882
+ "src/services/llm-client.ts"() {
10883
+ "use strict";
10884
+ init_errors();
10885
+ }
10886
+ });
10887
+
10888
+ // src/services/client-instance.ts
10889
+ function setGlobalClient(client) {
10890
+ globalClient = client;
10891
+ }
10892
+ function getGlobalClient() {
10893
+ if (!globalClient) {
10894
+ throw new Error("LLM client not initialized. Call setGlobalClient() first.");
10895
+ }
10896
+ return globalClient;
10897
+ }
10898
+ async function initializeClient(options) {
10899
+ if (globalClient !== null) {
10900
+ return;
10901
+ }
10902
+ const client = createPoeClient({
10903
+ apiKey: options.apiKey,
10904
+ baseUrl: options.baseUrl,
10905
+ httpClient: options.httpClient
10906
+ });
10907
+ setGlobalClient(client);
10908
+ }
10909
+ var globalClient;
10910
+ var init_client_instance = __esm({
10911
+ "src/services/client-instance.ts"() {
10912
+ "use strict";
10913
+ init_llm_client();
10914
+ globalClient = null;
10915
+ }
10916
+ });
10917
+
10918
+ // src/utils/execution-context.ts
10919
+ import { basename as basename2, dirname as dirname3 } from "node:path";
10920
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
10921
+ function detectExecutionContext(input) {
10922
+ const { argv, env, moduleUrl } = input;
10923
+ if (isDevelopmentMode(argv, env)) {
10924
+ return createDevelopmentContext(moduleUrl);
10925
+ }
10926
+ if (isNpxExecution(env)) {
10927
+ const version = detectNpxVersion(env);
10928
+ return createNpxContext(version);
10929
+ }
10930
+ const invoked = basename2(argv[1] ?? "");
10931
+ const isPoeShort = invoked === "poe" || invoked === "poe.cmd" || invoked === "poe.exe";
10932
+ return {
10933
+ mode: "global",
10934
+ command: {
10935
+ command: isPoeShort ? "poe" : "poe-code",
10936
+ args: []
10937
+ }
10938
+ };
10939
+ }
10940
+ function isDevelopmentMode(argv, env) {
10941
+ const scriptPath = argv[1] ?? "";
10942
+ if (scriptPath.endsWith(".ts") || scriptPath.includes("/src/")) {
10943
+ return true;
10944
+ }
10945
+ if (env.npm_lifecycle_event === "dev") {
10946
+ return true;
10947
+ }
10948
+ const nodeOptions = env.NODE_OPTIONS ?? "";
10949
+ if (nodeOptions.includes("tsx") || nodeOptions.includes("ts-node")) {
10950
+ return true;
10951
+ }
10952
+ return false;
10953
+ }
10954
+ function isNpxExecution(env) {
10955
+ const execPath = env.npm_execpath ?? "";
10956
+ if (execPath.includes("npx") || execPath.includes("npm")) {
10957
+ const packagePath = env.npm_package_json ?? "";
10958
+ if (packagePath.includes("_npx") || packagePath.includes(".npm/_cacache")) {
10959
+ return true;
10960
+ }
10961
+ }
10962
+ if (env.npm_command === "exec") {
10963
+ return true;
10964
+ }
10965
+ return false;
10966
+ }
10967
+ function detectNpxVersion(env) {
10968
+ const packageJson = env.npm_package_json ?? "";
10969
+ const packageVersion = env.npm_package_version ?? "";
10970
+ if (packageJson.includes("@beta") || packageVersion.includes("beta")) {
10971
+ return "beta";
10972
+ }
10973
+ if (packageJson.includes("@latest")) {
10974
+ return "latest";
10975
+ }
10976
+ return "default";
10977
+ }
10978
+ function createDevelopmentContext(moduleUrl) {
10979
+ const modulePath = fileURLToPath2(moduleUrl);
10980
+ const srcIndex = modulePath.lastIndexOf("/src/");
10981
+ const projectRoot = srcIndex !== -1 ? modulePath.substring(0, srcIndex) : dirname3(dirname3(modulePath));
10982
+ return {
10983
+ mode: "development",
10984
+ command: {
10985
+ command: "npm",
10986
+ args: ["--silent", "--prefix", projectRoot, "run", "dev", "--"]
10987
+ }
10988
+ };
10989
+ }
10990
+ function createNpxContext(version) {
10991
+ const packageSpec = version === "default" ? "poe-code" : `poe-code@${version}`;
10992
+ return {
10993
+ mode: version === "default" ? "npx" : `npx-${version}`,
10994
+ command: {
10995
+ command: "npx",
10996
+ args: ["--yes", packageSpec]
10997
+ }
10998
+ };
10999
+ }
11000
+ function toMcpServerCommand(execCommand, subcommand) {
11001
+ return {
11002
+ command: execCommand.command,
11003
+ args: [...execCommand.args, subcommand]
11004
+ };
11005
+ }
11006
+ function formatCliHelpCommand(context, args) {
11007
+ const base = formatCliUsageCommand(context);
11008
+ const trailing = args.join(" ");
11009
+ if (trailing.length === 0) {
11010
+ return base;
11011
+ }
11012
+ return `${base} ${trailing}`;
11013
+ }
11014
+ function formatCliUsageCommand(context) {
11015
+ switch (context.mode) {
11016
+ case "development":
11017
+ return "npm run dev --";
11018
+ case "npx":
11019
+ return "npx poe-code";
11020
+ case "npx-latest":
11021
+ return "npx poe-code@latest";
11022
+ case "npx-beta":
11023
+ return "npx poe-code@beta";
11024
+ case "global":
11025
+ default:
11026
+ return context.command.command;
11027
+ }
11028
+ }
11029
+ function getCurrentExecutionContext(moduleUrl) {
11030
+ return detectExecutionContext({
11031
+ argv: process.argv,
11032
+ env: process.env,
11033
+ moduleUrl
11034
+ });
11035
+ }
11036
+ var init_execution_context = __esm({
11037
+ "src/utils/execution-context.ts"() {
11038
+ "use strict";
11039
+ }
11040
+ });
11041
+
11042
+ // src/sdk/launch.ts
11043
+ import path25 from "node:path";
11044
+ import { spawnSync } from "node:child_process";
11045
+ async function startLaunch(options) {
11046
+ const homeDir = resolveHomeDir(options.homeDir);
11047
+ const cwd = options.cwd ?? process.cwd();
11048
+ const variables = options.variables ?? process.env;
11049
+ const executionContext = getCurrentExecutionContext(import.meta.url);
11050
+ const runner = createHostRunner({ detached: true });
11051
+ return await startManagedProcess({
11052
+ baseDir: resolveLaunchBaseDir(homeDir),
11053
+ spec: options.spec,
11054
+ spawnDaemon: async (id) => {
11055
+ const handle = runner.exec({
11056
+ args: [...executionContext.command.args, "launch", "__run", id],
11057
+ command: executionContext.command.command,
11058
+ cwd,
11059
+ env: objectToEnv(variables),
11060
+ stderr: "inherit",
11061
+ stdin: "ignore",
11062
+ stdout: "inherit"
11063
+ });
11064
+ return handle.pid;
11065
+ }
11066
+ });
11067
+ }
11068
+ async function stopLaunch(options) {
11069
+ const homeDir = resolveHomeDir(options.homeDir);
11070
+ return await stopManagedProcess({
11071
+ baseDir: resolveLaunchBaseDir(homeDir),
11072
+ force: options.force,
11073
+ id: options.id,
11074
+ signalProcess: sendSignalToManagedProcess,
11075
+ stopRuntimeArtifacts: async ({ record, force }) => {
11076
+ await stopDockerArtifacts(record, force);
11077
+ }
11078
+ });
9334
11079
  }
9335
- function extractMediaFromCompletion(data) {
9336
- const content = extractTextContent(data);
9337
- if (!content) return {};
9338
- try {
9339
- const parsed = JSON.parse(content);
9340
- if (isRecord7(parsed) && typeof parsed.url === "string") {
9341
- return {
9342
- url: parsed.url,
9343
- mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0,
9344
- data: typeof parsed.data === "string" ? parsed.data : void 0
9345
- };
11080
+ async function restartLaunch(options) {
11081
+ const homeDir = resolveHomeDir(options.homeDir);
11082
+ const cwd = options.cwd ?? process.cwd();
11083
+ const variables = options.variables ?? process.env;
11084
+ const executionContext = getCurrentExecutionContext(import.meta.url);
11085
+ const runner = createHostRunner({ detached: true });
11086
+ return await restartManagedProcess({
11087
+ baseDir: resolveLaunchBaseDir(homeDir),
11088
+ id: options.id,
11089
+ signalProcess: sendSignalToManagedProcess,
11090
+ spawnDaemon: async (id) => {
11091
+ const handle = runner.exec({
11092
+ args: [...executionContext.command.args, "launch", "__run", id],
11093
+ command: executionContext.command.command,
11094
+ cwd,
11095
+ env: objectToEnv(variables),
11096
+ stderr: "inherit",
11097
+ stdin: "ignore",
11098
+ stdout: "inherit"
11099
+ });
11100
+ return handle.pid;
11101
+ },
11102
+ stopRuntimeArtifacts: async ({ record, force }) => {
11103
+ await stopDockerArtifacts(record, force);
9346
11104
  }
9347
- if (isRecord7(parsed) && typeof parsed.data === "string") {
9348
- return {
9349
- data: parsed.data,
9350
- mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0
9351
- };
11105
+ });
11106
+ }
11107
+ async function listLaunches(options = {}) {
11108
+ return await listManagedProcesses({
11109
+ baseDir: resolveLaunchBaseDir(resolveHomeDir(options.homeDir))
11110
+ });
11111
+ }
11112
+ async function readLaunchLogs(options) {
11113
+ return await readManagedLogs({
11114
+ baseDir: resolveLaunchBaseDir(resolveHomeDir(options.homeDir)),
11115
+ id: options.id,
11116
+ lines: options.lines,
11117
+ stream: options.stream
11118
+ });
11119
+ }
11120
+ function followLaunchLogs(options) {
11121
+ const forwarded = {
11122
+ baseDir: resolveLaunchBaseDir(resolveHomeDir(options.homeDir)),
11123
+ id: options.id,
11124
+ lines: options.lines,
11125
+ pollIntervalMs: options.pollIntervalMs,
11126
+ signal: options.signal,
11127
+ stream: options.stream
11128
+ };
11129
+ return followManagedLogs(forwarded);
11130
+ }
11131
+ async function removeLaunch(options) {
11132
+ await removeManagedProcess({
11133
+ baseDir: resolveLaunchBaseDir(resolveHomeDir(options.homeDir)),
11134
+ id: options.id,
11135
+ removeRuntimeArtifacts: async ({ record }) => {
11136
+ await removeDockerArtifacts(record);
9352
11137
  }
9353
- } catch {
9354
- }
9355
- if (isValidUrl(content.trim())) {
9356
- return { url: content.trim() };
9357
- }
9358
- const markdownUrl = extractMarkdownUrl(content);
9359
- if (markdownUrl) {
9360
- return { url: markdownUrl };
9361
- }
9362
- return { content };
11138
+ });
9363
11139
  }
9364
- function extractMarkdownUrl(content) {
9365
- const start = content.indexOf("](");
9366
- if (start === -1) return void 0;
9367
- const urlStart = start + 2;
9368
- const end = content.indexOf(")", urlStart);
9369
- if (end === -1) return void 0;
9370
- const url = content.slice(urlStart, end);
9371
- return isValidUrl(url) ? url : void 0;
11140
+ async function runLaunchDaemon(options) {
11141
+ await runManagedProcess({
11142
+ baseDir: resolveLaunchBaseDir(resolveHomeDir(options.homeDir)),
11143
+ id: options.id,
11144
+ signal: options.signal
11145
+ });
9372
11146
  }
9373
- function isValidUrl(value) {
11147
+ function resolveLaunchBaseDir(homeDir) {
11148
+ return path25.join(homeDir, ".poe-code", "launch");
11149
+ }
11150
+ function resolveHomeDir(homeDir) {
11151
+ if (homeDir) {
11152
+ return homeDir;
11153
+ }
11154
+ return process.env.HOME ?? process.cwd();
11155
+ }
11156
+ function sendSignalToManagedProcess(pid, signal) {
11157
+ if (process.platform === "win32") {
11158
+ process.kill(pid, signal);
11159
+ return;
11160
+ }
9374
11161
  try {
9375
- new URL(value);
9376
- return true;
9377
- } catch {
9378
- return false;
11162
+ process.kill(-pid, signal);
11163
+ } catch (error) {
11164
+ if (!isMissingProcessGroupError(error)) {
11165
+ throw error;
11166
+ }
11167
+ process.kill(pid, signal);
9379
11168
  }
9380
11169
  }
9381
- function isRecord7(value) {
9382
- return Boolean(value && typeof value === "object" && !Array.isArray(value));
11170
+ function isMissingProcessGroupError(error) {
11171
+ return error instanceof Error && "code" in error && error.code === "ESRCH";
9383
11172
  }
9384
- var init_llm_client = __esm({
9385
- "src/services/llm-client.ts"() {
9386
- "use strict";
9387
- init_errors();
11173
+ function objectToEnv(variables) {
11174
+ const env = {};
11175
+ for (const [key, value] of Object.entries(variables)) {
11176
+ if (value !== void 0) {
11177
+ env[key] = value;
11178
+ }
9388
11179
  }
9389
- });
9390
-
9391
- // src/services/client-instance.ts
9392
- function setGlobalClient(client) {
9393
- globalClient = client;
11180
+ return env;
9394
11181
  }
9395
- function getGlobalClient() {
9396
- if (!globalClient) {
9397
- throw new Error("LLM client not initialized. Call setGlobalClient() first.");
11182
+ async function stopDockerArtifacts(record, force) {
11183
+ if (!record.spec?.docker?.containerName) {
11184
+ return;
9398
11185
  }
9399
- return globalClient;
11186
+ const engine = resolveEngine(record.spec.docker.engine);
11187
+ const command = force ? "kill" : "stop";
11188
+ spawnSync(engine, [command, record.spec.docker.containerName], { stdio: "ignore" });
9400
11189
  }
9401
- async function initializeClient(options) {
9402
- if (globalClient !== null) {
11190
+ async function removeDockerArtifacts(record) {
11191
+ if (!record.spec?.docker?.containerName) {
9403
11192
  return;
9404
11193
  }
9405
- const client = createPoeClient({
9406
- apiKey: options.apiKey,
9407
- baseUrl: options.baseUrl,
9408
- httpClient: options.httpClient
9409
- });
9410
- setGlobalClient(client);
11194
+ const engine = resolveEngine(record.spec.docker.engine);
11195
+ spawnSync(engine, ["rm", "-f", record.spec.docker.containerName], { stdio: "ignore" });
9411
11196
  }
9412
- var globalClient;
9413
- var init_client_instance = __esm({
9414
- "src/services/client-instance.ts"() {
11197
+ function resolveEngine(engine) {
11198
+ if (engine) {
11199
+ return engine;
11200
+ }
11201
+ return detectEngine();
11202
+ }
11203
+ var init_launch = __esm({
11204
+ "src/sdk/launch.ts"() {
9415
11205
  "use strict";
9416
- init_llm_client();
9417
- globalClient = null;
11206
+ init_src10();
11207
+ init_src9();
11208
+ init_execution_context();
9418
11209
  }
9419
11210
  });
9420
11211
 
@@ -9898,13 +11689,13 @@ var init_acp_transport = __esm({
9898
11689
  env,
9899
11690
  requestTimeoutMs,
9900
11691
  firstRequestId,
9901
- spawn: spawn7 = spawnChildProcess4
11692
+ spawn: spawn9 = spawnChildProcess4
9902
11693
  } = options;
9903
11694
  this.command = command;
9904
11695
  this.closed = new Promise((resolve) => {
9905
11696
  this.resolveClosed = resolve;
9906
11697
  });
9907
- this.child = spawn7(command, [...args], {
11698
+ this.child = spawn9(command, [...args], {
9908
11699
  cwd,
9909
11700
  env,
9910
11701
  stdio: ["pipe", "pipe", "pipe"]
@@ -10017,8 +11808,8 @@ function resourceNotFound(resource) {
10017
11808
  `Resource not found: ${resource}`
10018
11809
  );
10019
11810
  }
10020
- function assertAbsolutePath(path33) {
10021
- if (!isAbsolute(path33)) {
11811
+ function assertAbsolutePath(path39) {
11812
+ if (!isAbsolute(path39)) {
10022
11813
  throw invalidParams('"path" must be an absolute path');
10023
11814
  }
10024
11815
  }
@@ -10752,7 +12543,7 @@ var init_run_report = __esm({
10752
12543
  });
10753
12544
 
10754
12545
  // packages/poe-acp-client/src/index.ts
10755
- var init_src11 = __esm({
12546
+ var init_src13 = __esm({
10756
12547
  "packages/poe-acp-client/src/index.ts"() {
10757
12548
  "use strict";
10758
12549
  init_acp_client();
@@ -11779,7 +13570,7 @@ var init_acp_core = __esm({
11779
13570
  });
11780
13571
 
11781
13572
  // packages/poe-agent/src/plugins/plugin-args.ts
11782
- import path20 from "node:path";
13573
+ import path26 from "node:path";
11783
13574
  function isObjectRecord3(value) {
11784
13575
  return typeof value === "object" && value !== null && !Array.isArray(value);
11785
13576
  }
@@ -11810,13 +13601,13 @@ function getOptionalString(args, key) {
11810
13601
  return value;
11811
13602
  }
11812
13603
  function resolveAllowedPath(cwd, allowedPaths, inputPath) {
11813
- const resolvedPath = path20.resolve(cwd, inputPath);
13604
+ const resolvedPath = path26.resolve(cwd, inputPath);
11814
13605
  const isAllowed = allowedPaths.some((allowedPath) => {
11815
13606
  if (allowedPath === resolvedPath) {
11816
13607
  return true;
11817
13608
  }
11818
- const rel = path20.relative(allowedPath, resolvedPath);
11819
- return rel.length > 0 && !rel.startsWith("..") && !path20.isAbsolute(rel);
13609
+ const rel = path26.relative(allowedPath, resolvedPath);
13610
+ return rel.length > 0 && !rel.startsWith("..") && !path26.isAbsolute(rel);
11820
13611
  });
11821
13612
  if (!isAllowed) {
11822
13613
  throw new Error(`Path is outside allowed paths: ${inputPath}`);
@@ -11831,7 +13622,7 @@ var init_plugin_args = __esm({
11831
13622
 
11832
13623
  // packages/poe-agent/src/plugins/poe-agent-plugin-files.ts
11833
13624
  import fsPromises9 from "node:fs/promises";
11834
- import path21 from "node:path";
13625
+ import path27 from "node:path";
11835
13626
  async function fileExists(fs3, filePath) {
11836
13627
  try {
11837
13628
  await fs3.readFile(filePath, "utf8");
@@ -11855,9 +13646,9 @@ var init_poe_agent_plugin_files = __esm({
11855
13646
  "use strict";
11856
13647
  init_plugin_args();
11857
13648
  filesPlugin = (options = {}) => {
11858
- const cwd = path21.resolve(options.cwd ?? process.cwd());
13649
+ const cwd = path27.resolve(options.cwd ?? process.cwd());
11859
13650
  const allowedPaths = (options.allowedPaths ?? [cwd]).map(
11860
- (allowedPath) => path21.resolve(cwd, allowedPath)
13651
+ (allowedPath) => path27.resolve(cwd, allowedPath)
11861
13652
  );
11862
13653
  const fs3 = options.fs ?? fsPromises9;
11863
13654
  const readFileTool = {
@@ -11911,7 +13702,7 @@ var init_poe_agent_plugin_files = __esm({
11911
13702
  async call(args) {
11912
13703
  const command = getRequiredString(args, "command");
11913
13704
  const filePath = resolveAllowedPath(cwd, allowedPaths, getRequiredString(args, "path"));
11914
- const displayedPath = path21.relative(cwd, filePath) || path21.basename(filePath);
13705
+ const displayedPath = path27.relative(cwd, filePath) || path27.basename(filePath);
11915
13706
  if (command === "str_replace") {
11916
13707
  const oldStr = getRequiredString(args, "old_str", true);
11917
13708
  const newStr = getRequiredString(args, "new_str", true);
@@ -11931,7 +13722,7 @@ var init_poe_agent_plugin_files = __esm({
11931
13722
  if (await fileExists(fs3, filePath)) {
11932
13723
  throw new Error("File already exists \u2014 use str_replace to edit");
11933
13724
  }
11934
- await fs3.mkdir(path21.dirname(filePath), { recursive: true });
13725
+ await fs3.mkdir(path27.dirname(filePath), { recursive: true });
11935
13726
  await fs3.writeFile(filePath, fileText, "utf8");
11936
13727
  return `Created file: ${displayedPath}`;
11937
13728
  }
@@ -11972,7 +13763,7 @@ var init_poe_agent_plugin_files = __esm({
11972
13763
 
11973
13764
  // packages/poe-agent/src/plugins/poe-agent-plugin-shell.ts
11974
13765
  import { exec as execCallback2 } from "node:child_process";
11975
- import path22 from "node:path";
13766
+ import path28 from "node:path";
11976
13767
  import { promisify } from "node:util";
11977
13768
  async function defaultRunCommand(command, cwd) {
11978
13769
  try {
@@ -12005,9 +13796,9 @@ var init_poe_agent_plugin_shell = __esm({
12005
13796
  init_plugin_args();
12006
13797
  exec = promisify(execCallback2);
12007
13798
  shellPlugin = (options = {}) => {
12008
- const cwd = path22.resolve(options.cwd ?? process.cwd());
13799
+ const cwd = path28.resolve(options.cwd ?? process.cwd());
12009
13800
  const allowedPaths = (options.allowedPaths ?? [cwd]).map(
12010
- (allowedPath) => path22.resolve(cwd, allowedPath)
13801
+ (allowedPath) => path28.resolve(cwd, allowedPath)
12011
13802
  );
12012
13803
  const runCommand2 = options.runCommand ?? defaultRunCommand;
12013
13804
  const runCommandTool = {
@@ -12046,7 +13837,7 @@ var init_poe_agent_plugin_shell = __esm({
12046
13837
  // packages/poe-agent/src/system-prompt.ts
12047
13838
  import { readFileSync } from "node:fs";
12048
13839
  import { readFile as readFile7 } from "node:fs/promises";
12049
- import { fileURLToPath as fileURLToPath2 } from "node:url";
13840
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
12050
13841
  function loadSystemPromptSync() {
12051
13842
  return readFileSync(SYSTEM_PROMPT_PATH, "utf8");
12052
13843
  }
@@ -12054,7 +13845,7 @@ var SYSTEM_PROMPT_PATH;
12054
13845
  var init_system_prompt = __esm({
12055
13846
  "packages/poe-agent/src/system-prompt.ts"() {
12056
13847
  "use strict";
12057
- SYSTEM_PROMPT_PATH = fileURLToPath2(new URL("./SYSTEM_PROMPT.md", import.meta.url));
13848
+ SYSTEM_PROMPT_PATH = fileURLToPath3(new URL("./SYSTEM_PROMPT.md", import.meta.url));
12058
13849
  }
12059
13850
  });
12060
13851
 
@@ -12791,7 +14582,7 @@ var AgentHost;
12791
14582
  var init_agent_host = __esm({
12792
14583
  "packages/poe-agent/src/runtime/agent-host.ts"() {
12793
14584
  "use strict";
12794
- init_src11();
14585
+ init_src13();
12795
14586
  init_agent_session();
12796
14587
  init_acp_core();
12797
14588
  init_run_context();
@@ -13158,10 +14949,10 @@ var init_config2 = __esm({
13158
14949
  });
13159
14950
 
13160
14951
  // packages/tiny-mcp-client/src/internal.ts
13161
- import { spawn as spawn5 } from "node:child_process";
14952
+ import { spawn as spawn7 } from "node:child_process";
13162
14953
  import { PassThrough } from "node:stream";
13163
14954
  function defaultStdioSpawn(command, args, options) {
13164
- return spawn5(command, args, options);
14955
+ return spawn7(command, args, options);
13165
14956
  }
13166
14957
  function serializeJsonRpcMessage2(message) {
13167
14958
  return `${JSON.stringify(message)}
@@ -14078,7 +15869,7 @@ var init_internal = __esm({
14078
15869
  });
14079
15870
 
14080
15871
  // packages/tiny-mcp-client/src/index.ts
14081
- var init_src12 = __esm({
15872
+ var init_src14 = __esm({
14082
15873
  "packages/tiny-mcp-client/src/index.ts"() {
14083
15874
  "use strict";
14084
15875
  init_internal();
@@ -14127,7 +15918,7 @@ var DEFAULT_MCP_CLIENT_INFO, PluginApiImpl;
14127
15918
  var init_plugin_api_impl = __esm({
14128
15919
  "packages/poe-agent/src/runtime/plugin-api-impl.ts"() {
14129
15920
  "use strict";
14130
- init_src12();
15921
+ init_src14();
14131
15922
  init_hooks();
14132
15923
  DEFAULT_MCP_CLIENT_INFO = {
14133
15924
  name: "poe-agent",
@@ -14694,7 +16485,7 @@ __export(src_exports, {
14694
16485
  agent: () => agent,
14695
16486
  createAgentSession: () => createAgentSession
14696
16487
  });
14697
- var init_src13 = __esm({
16488
+ var init_src15 = __esm({
14698
16489
  "packages/poe-agent/src/index.ts"() {
14699
16490
  "use strict";
14700
16491
  init_agent();
@@ -15032,7 +16823,7 @@ function createInMemoryAcpTransport2(options) {
15032
16823
  }
15033
16824
  if (method === "session/new") {
15034
16825
  const request = params;
15035
- const { createAgentSession: createAgentSession2 } = await Promise.resolve().then(() => (init_src13(), src_exports));
16826
+ const { createAgentSession: createAgentSession2 } = await Promise.resolve().then(() => (init_src15(), src_exports));
15036
16827
  const session = await createAgentSession2({
15037
16828
  model: options.model,
15038
16829
  cwd: request.cwd || options.cwd,
@@ -15182,7 +16973,7 @@ var init_poe_agent = __esm({
15182
16973
  "src/providers/poe-agent.ts"() {
15183
16974
  "use strict";
15184
16975
  init_constants();
15185
- init_src11();
16976
+ init_src13();
15186
16977
  init_create_provider();
15187
16978
  poeAgentService = createProvider({
15188
16979
  id: "poe-agent",
@@ -15376,7 +17167,7 @@ var init_container2 = __esm({
15376
17167
  });
15377
17168
 
15378
17169
  // src/services/config.ts
15379
- import path24 from "node:path";
17170
+ import path30 from "node:path";
15380
17171
  async function deleteConfig(options) {
15381
17172
  const { fs: fs3, filePath } = options;
15382
17173
  try {
@@ -15457,7 +17248,7 @@ async function migrateLegacyCredentialsIfNeeded(fs3, filePath) {
15457
17248
  await migrateLegacyCredentialsFile(fs3, filePath);
15458
17249
  }
15459
17250
  async function migrateLegacyCredentialsFile(fs3, configPath) {
15460
- const legacyPath = path24.join(path24.dirname(configPath), "credentials.json");
17251
+ const legacyPath = path30.join(path30.dirname(configPath), "credentials.json");
15461
17252
  const raw = await readFileIfExists(fs3, legacyPath);
15462
17253
  if (raw === null) {
15463
17254
  return;
@@ -15525,9 +17316,9 @@ async function recoverInvalidConfig(fs3, filePath, content) {
15525
17316
  await fs3.writeFile(filePath, EMPTY_DOCUMENT3, { encoding: "utf8" });
15526
17317
  }
15527
17318
  function createInvalidBackupPath2(filePath) {
15528
- const directory = path24.dirname(filePath);
15529
- const baseName = path24.basename(filePath);
15530
- return path24.join(directory, `${baseName}.invalid-${createTimestamp()}.json`);
17319
+ const directory = path30.dirname(filePath);
17320
+ const baseName = path30.basename(filePath);
17321
+ return path30.join(directory, `${baseName}.invalid-${createTimestamp()}.json`);
15531
17322
  }
15532
17323
  function isRecord8(value) {
15533
17324
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
@@ -15746,7 +17537,7 @@ function registerAgentCommand(program, container) {
15746
17537
  }
15747
17538
  let session;
15748
17539
  try {
15749
- const { createAgentSession: createAgentSession2 } = await Promise.resolve().then(() => (init_src13(), src_exports));
17540
+ const { createAgentSession: createAgentSession2 } = await Promise.resolve().then(() => (init_src15(), src_exports));
15750
17541
  session = await createAgentSession2({
15751
17542
  model: options.model,
15752
17543
  apiKey: options.apiKey,
@@ -15805,7 +17596,7 @@ var init_agent2 = __esm({
15805
17596
  });
15806
17597
 
15807
17598
  // src/cli/commands/spawn.ts
15808
- import path25 from "node:path";
17599
+ import path31 from "node:path";
15809
17600
  function registerSpawnCommand(program, container, options = {}) {
15810
17601
  const spawnServices = container.registry.list().filter((service) => typeof service.spawn === "function" || getSpawnConfig(service.name)).map((service) => service.name);
15811
17602
  const extraServices = options.extraServices ?? [];
@@ -16007,10 +17798,10 @@ function resolveSpawnWorkingDirectory2(baseDir, candidate) {
16007
17798
  if (!candidate || candidate.trim().length === 0) {
16008
17799
  return void 0;
16009
17800
  }
16010
- if (path25.isAbsolute(candidate)) {
17801
+ if (path31.isAbsolute(candidate)) {
16011
17802
  return candidate;
16012
17803
  }
16013
- return path25.resolve(baseDir, candidate);
17804
+ return path31.resolve(baseDir, candidate);
16014
17805
  }
16015
17806
  function parseMcpSpawnConfig2(input) {
16016
17807
  if (!input) {
@@ -16128,7 +17919,7 @@ var init_spawn4 = __esm({
16128
17919
  });
16129
17920
 
16130
17921
  // src/sdk/research.ts
16131
- import path26 from "node:path";
17922
+ import path32 from "node:path";
16132
17923
  async function research(container, options) {
16133
17924
  const logger2 = options.logger;
16134
17925
  const source = await resolveSource({
@@ -16163,7 +17954,7 @@ async function research(container, options) {
16163
17954
  markdown: markdownOutput
16164
17955
  });
16165
17956
  outputPath = buildOutputPath(container.env.homeDir, options.prompt);
16166
- await ensureDirectory2(container.fs, path26.dirname(outputPath));
17957
+ await ensureDirectory2(container.fs, path32.dirname(outputPath));
16167
17958
  await container.fs.writeFile(outputPath, document, {
16168
17959
  encoding: "utf8"
16169
17960
  });
@@ -16238,7 +18029,7 @@ function buildResearchDocument(input) {
16238
18029
  }
16239
18030
  function buildClonePath(homeDir, github) {
16240
18031
  const slug = extractRepoSlug(github);
16241
- return path26.join(homeDir, ".poe-code", "repos", slug);
18032
+ return path32.join(homeDir, ".poe-code", "repos", slug);
16242
18033
  }
16243
18034
  function extractRepoSlug(value) {
16244
18035
  const trimmed = value.trim();
@@ -16276,7 +18067,7 @@ function extractRepoSlug(value) {
16276
18067
  function buildOutputPath(homeDir, prompt, now = /* @__PURE__ */ new Date()) {
16277
18068
  const timestamp = formatTimestamp2(now);
16278
18069
  const slug = buildSlug(prompt);
16279
- return path26.join(
18070
+ return path32.join(
16280
18071
  homeDir,
16281
18072
  ".poe-code",
16282
18073
  "research",
@@ -16297,7 +18088,7 @@ async function resolveSource(input) {
16297
18088
  if (options.github) {
16298
18089
  const cloneUrl = resolveGithubCloneUrl(options.github);
16299
18090
  const clonePath = buildClonePath(container.env.homeDir, options.github);
16300
- await ensureDirectory2(container.fs, path26.dirname(clonePath));
18091
+ await ensureDirectory2(container.fs, path32.dirname(clonePath));
16301
18092
  const exists = await pathExists2(container.fs, clonePath);
16302
18093
  if (!exists) {
16303
18094
  const cloneResult = await container.commandRunner(
@@ -16395,10 +18186,10 @@ function formatYamlString(value) {
16395
18186
  return JSON.stringify(value);
16396
18187
  }
16397
18188
  function resolvePath2(baseDir, candidate) {
16398
- if (path26.isAbsolute(candidate)) {
18189
+ if (path32.isAbsolute(candidate)) {
16399
18190
  return candidate;
16400
18191
  }
16401
- return path26.resolve(baseDir, candidate);
18192
+ return path32.resolve(baseDir, candidate);
16402
18193
  }
16403
18194
  function teeAcpStream(events) {
16404
18195
  const chunks = [];
@@ -16458,7 +18249,7 @@ async function removePathFallback(fs3, target) {
16458
18249
  if (stats && typeof stats.isDirectory === "function" && stats.isDirectory()) {
16459
18250
  const entries = await fs3.readdir(target);
16460
18251
  for (const entry of entries) {
16461
- await removePathFallback(fs3, path26.join(target, entry));
18252
+ await removePathFallback(fs3, path32.join(target, entry));
16462
18253
  }
16463
18254
  }
16464
18255
  try {
@@ -16624,7 +18415,7 @@ var init_research2 = __esm({
16624
18415
  });
16625
18416
 
16626
18417
  // src/cli/isolated-env-runner.ts
16627
- import { spawn as spawn6 } from "node:child_process";
18418
+ import { spawn as spawn8 } from "node:child_process";
16628
18419
  async function isolatedEnvRunner(input) {
16629
18420
  const details = await resolveIsolatedEnvDetails(
16630
18421
  input.env,
@@ -16649,7 +18440,7 @@ async function isolatedEnvRunner(input) {
16649
18440
  );
16650
18441
  args = buildArgsWithMergedSettings(args, resolvedSettings);
16651
18442
  }
16652
- const child = spawn6(details.agentBinary, args, {
18443
+ const child = spawn8(details.agentBinary, args, {
16653
18444
  stdio: "inherit",
16654
18445
  env: {
16655
18446
  ...process.env,
@@ -17020,7 +18811,7 @@ function registerAuthCommand(program, container) {
17020
18811
  const auth = program.command("auth").description("Authentication and account commands.").action(async () => {
17021
18812
  await executeStatus(program, container);
17022
18813
  });
17023
- auth.command("status").description("Show login, balance, and configuration status.").action(async () => {
18814
+ auth.command("status").description("Show login status.").action(async () => {
17024
18815
  await executeStatus(program, container);
17025
18816
  });
17026
18817
  auth.command("api_key").description("Display stored API key.").action(async () => {
@@ -17099,7 +18890,7 @@ var init_auth = __esm({
17099
18890
  });
17100
18891
 
17101
18892
  // src/cli/commands/config.ts
17102
- import { execSync } from "node:child_process";
18893
+ import { execSync as execSync3 } from "node:child_process";
17103
18894
  function registerConfigCommand(program, container) {
17104
18895
  const config = program.command("config").description("Inspect and manage poe-code config files.").action(async () => {
17105
18896
  await executeConfigInfo(program, container);
@@ -17188,7 +18979,7 @@ async function executeConfigEdit(program, container, options) {
17188
18979
  if (!await pathExists(container.fs, targetPath)) {
17189
18980
  await initProjectConfig(container.fs, targetPath);
17190
18981
  }
17191
- execSync(`${editor} ${shlexQuote(targetPath)}`, {
18982
+ execSync3(`${editor} ${shlexQuote(targetPath)}`, {
17192
18983
  stdio: "inherit"
17193
18984
  });
17194
18985
  }
@@ -17238,7 +19029,7 @@ var init_utils3 = __esm({
17238
19029
  function registerInstallCommand(program, container) {
17239
19030
  const serviceNames = container.registry.list().filter((service) => typeof service.install === "function").map((service) => service.name);
17240
19031
  const serviceDescription = `Agent to install${formatServiceList(serviceNames)}`;
17241
- return program.command("install").alias("i").description("Install tooling for a configured agent.").argument(
19032
+ return program.command("install").alias("i").description("Install agent binary for a configured agent.").argument(
17242
19033
  "[agent]",
17243
19034
  serviceDescription
17244
19035
  ).action(async (service) => {
@@ -17430,7 +19221,7 @@ var init_media_download = __esm({
17430
19221
  });
17431
19222
 
17432
19223
  // src/cli/commands/generate.ts
17433
- import path27 from "node:path";
19224
+ import path33 from "node:path";
17434
19225
  function registerGenerateCommand(program, container) {
17435
19226
  const generate2 = program.command("generate").alias("g").description("Generate content via Poe API").option("--model <model>", `Model identifier (default: ${DEFAULT_TEXT_MODEL})`).option(
17436
19227
  "--param <key=value>",
@@ -17703,11 +19494,11 @@ function getDefaultMimeType(type) {
17703
19494
  return defaults[type];
17704
19495
  }
17705
19496
  function resolveOutputPath(filename, cwd) {
17706
- if (path27.isAbsolute(filename)) {
19497
+ if (path33.isAbsolute(filename)) {
17707
19498
  return { path: filename, label: filename };
17708
19499
  }
17709
19500
  return {
17710
- path: path27.join(cwd, filename),
19501
+ path: path33.join(cwd, filename),
17711
19502
  label: `./${filename}`
17712
19503
  };
17713
19504
  }
@@ -18435,7 +20226,7 @@ var init_content = __esm({
18435
20226
  });
18436
20227
 
18437
20228
  // packages/tiny-stdio-mcp-server/src/index.ts
18438
- var init_src14 = __esm({
20229
+ var init_src16 = __esm({
18439
20230
  "packages/tiny-stdio-mcp-server/src/index.ts"() {
18440
20231
  "use strict";
18441
20232
  init_server();
@@ -18738,7 +20529,7 @@ var generateTextSchema, generateImageSchema, generateVideoSchema, generateAudioS
18738
20529
  var init_mcp_server = __esm({
18739
20530
  "src/cli/mcp-server.ts"() {
18740
20531
  "use strict";
18741
- init_src14();
20532
+ init_src16();
18742
20533
  init_client_instance();
18743
20534
  init_constants();
18744
20535
  generateTextSchema = defineSchema({
@@ -18817,150 +20608,26 @@ function parseMcpOutputFormatPreferences(value) {
18817
20608
  );
18818
20609
  }
18819
20610
  if (normalized !== "url" && normalized !== "base64" && normalized !== "markdown" && normalized !== "markdown_instructions") {
18820
- throw new ValidationError(
18821
- `Invalid --output-format entry "${raw.trim()}". Expected "url", "base64", "markdown", or "markdown_instructions".`
18822
- );
18823
- }
18824
- preferences.push(normalized);
18825
- }
18826
- const standaloneFormats = ["markdown", "markdown_instructions"];
18827
- for (const standalone of standaloneFormats) {
18828
- if (preferences.includes(standalone) && preferences.length > 1) {
18829
- throw new ValidationError(
18830
- `${standalone} output format cannot be combined with other formats. Use ${standalone} alone or choose a different format combination.`
18831
- );
18832
- }
18833
- }
18834
- return preferences;
18835
- }
18836
- var init_mcp_output_format = __esm({
18837
- "src/cli/mcp-output-format.ts"() {
18838
- "use strict";
18839
- init_errors();
18840
- }
18841
- });
18842
-
18843
- // src/utils/execution-context.ts
18844
- import { basename as basename2, dirname as dirname3 } from "node:path";
18845
- import { fileURLToPath as fileURLToPath3 } from "node:url";
18846
- function detectExecutionContext(input) {
18847
- const { argv, env, moduleUrl } = input;
18848
- if (isDevelopmentMode(argv, env)) {
18849
- return createDevelopmentContext(moduleUrl);
18850
- }
18851
- if (isNpxExecution(env)) {
18852
- const version = detectNpxVersion(env);
18853
- return createNpxContext(version);
18854
- }
18855
- const invoked = basename2(argv[1] ?? "");
18856
- const isPoeShort = invoked === "poe" || invoked === "poe.cmd" || invoked === "poe.exe";
18857
- return {
18858
- mode: "global",
18859
- command: {
18860
- command: isPoeShort ? "poe" : "poe-code",
18861
- args: []
18862
- }
18863
- };
18864
- }
18865
- function isDevelopmentMode(argv, env) {
18866
- const scriptPath = argv[1] ?? "";
18867
- if (scriptPath.endsWith(".ts") || scriptPath.includes("/src/")) {
18868
- return true;
18869
- }
18870
- if (env.npm_lifecycle_event === "dev") {
18871
- return true;
18872
- }
18873
- const nodeOptions = env.NODE_OPTIONS ?? "";
18874
- if (nodeOptions.includes("tsx") || nodeOptions.includes("ts-node")) {
18875
- return true;
18876
- }
18877
- return false;
18878
- }
18879
- function isNpxExecution(env) {
18880
- const execPath = env.npm_execpath ?? "";
18881
- if (execPath.includes("npx") || execPath.includes("npm")) {
18882
- const packagePath = env.npm_package_json ?? "";
18883
- if (packagePath.includes("_npx") || packagePath.includes(".npm/_cacache")) {
18884
- return true;
18885
- }
18886
- }
18887
- if (env.npm_command === "exec") {
18888
- return true;
18889
- }
18890
- return false;
18891
- }
18892
- function detectNpxVersion(env) {
18893
- const packageJson = env.npm_package_json ?? "";
18894
- const packageVersion = env.npm_package_version ?? "";
18895
- if (packageJson.includes("@beta") || packageVersion.includes("beta")) {
18896
- return "beta";
18897
- }
18898
- if (packageJson.includes("@latest")) {
18899
- return "latest";
18900
- }
18901
- return "default";
18902
- }
18903
- function createDevelopmentContext(moduleUrl) {
18904
- const modulePath = fileURLToPath3(moduleUrl);
18905
- const srcIndex = modulePath.lastIndexOf("/src/");
18906
- const projectRoot = srcIndex !== -1 ? modulePath.substring(0, srcIndex) : dirname3(dirname3(modulePath));
18907
- return {
18908
- mode: "development",
18909
- command: {
18910
- command: "npm",
18911
- args: ["--silent", "--prefix", projectRoot, "run", "dev", "--"]
18912
- }
18913
- };
18914
- }
18915
- function createNpxContext(version) {
18916
- const packageSpec = version === "default" ? "poe-code" : `poe-code@${version}`;
18917
- return {
18918
- mode: version === "default" ? "npx" : `npx-${version}`,
18919
- command: {
18920
- command: "npx",
18921
- args: ["--yes", packageSpec]
18922
- }
18923
- };
18924
- }
18925
- function toMcpServerCommand(execCommand, subcommand) {
18926
- return {
18927
- command: execCommand.command,
18928
- args: [...execCommand.args, subcommand]
18929
- };
18930
- }
18931
- function formatCliHelpCommand(context, args) {
18932
- const base = formatCliUsageCommand(context);
18933
- const trailing = args.join(" ");
18934
- if (trailing.length === 0) {
18935
- return base;
20611
+ throw new ValidationError(
20612
+ `Invalid --output-format entry "${raw.trim()}". Expected "url", "base64", "markdown", or "markdown_instructions".`
20613
+ );
20614
+ }
20615
+ preferences.push(normalized);
18936
20616
  }
18937
- return `${base} ${trailing}`;
18938
- }
18939
- function formatCliUsageCommand(context) {
18940
- switch (context.mode) {
18941
- case "development":
18942
- return "npm run dev --";
18943
- case "npx":
18944
- return "npx poe-code";
18945
- case "npx-latest":
18946
- return "npx poe-code@latest";
18947
- case "npx-beta":
18948
- return "npx poe-code@beta";
18949
- case "global":
18950
- default:
18951
- return context.command.command;
20617
+ const standaloneFormats = ["markdown", "markdown_instructions"];
20618
+ for (const standalone of standaloneFormats) {
20619
+ if (preferences.includes(standalone) && preferences.length > 1) {
20620
+ throw new ValidationError(
20621
+ `${standalone} output format cannot be combined with other formats. Use ${standalone} alone or choose a different format combination.`
20622
+ );
20623
+ }
18952
20624
  }
20625
+ return preferences;
18953
20626
  }
18954
- function getCurrentExecutionContext(moduleUrl) {
18955
- return detectExecutionContext({
18956
- argv: process.argv,
18957
- env: process.env,
18958
- moduleUrl
18959
- });
18960
- }
18961
- var init_execution_context = __esm({
18962
- "src/utils/execution-context.ts"() {
20627
+ var init_mcp_output_format = __esm({
20628
+ "src/cli/mcp-output-format.ts"() {
18963
20629
  "use strict";
20630
+ init_errors();
18964
20631
  }
18965
20632
  });
18966
20633
 
@@ -19146,9 +20813,9 @@ var init_shapes = __esm({
19146
20813
  });
19147
20814
 
19148
20815
  // packages/agent-mcp-config/src/apply.ts
19149
- import path28 from "node:path";
20816
+ import path34 from "node:path";
19150
20817
  function getConfigDirectory(configPath) {
19151
- return path28.dirname(configPath);
20818
+ return path34.dirname(configPath);
19152
20819
  }
19153
20820
  function isConfigObject5(value) {
19154
20821
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -19250,7 +20917,7 @@ var init_apply = __esm({
19250
20917
  });
19251
20918
 
19252
20919
  // packages/agent-mcp-config/src/index.ts
19253
- var init_src15 = __esm({
20920
+ var init_src17 = __esm({
19254
20921
  "packages/agent-mcp-config/src/index.ts"() {
19255
20922
  "use strict";
19256
20923
  init_configs2();
@@ -19430,7 +21097,7 @@ var init_mcp2 = __esm({
19430
21097
  init_shared();
19431
21098
  init_mcp_output_format();
19432
21099
  init_command_not_found();
19433
- init_src15();
21100
+ init_src17();
19434
21101
  init_execution_context();
19435
21102
  DEFAULT_MCP_AGENT = "claude-code";
19436
21103
  }
@@ -19438,7 +21105,7 @@ var init_mcp2 = __esm({
19438
21105
 
19439
21106
  // packages/agent-skill-config/src/configs.ts
19440
21107
  import os2 from "node:os";
19441
- import path29 from "node:path";
21108
+ import path35 from "node:path";
19442
21109
  function resolveAgentSupport2(input, registry = agentSkillConfigs) {
19443
21110
  const resolvedId = resolveAgentId(input);
19444
21111
  if (!resolvedId) {
@@ -19630,7 +21297,7 @@ var init_apply2 = __esm({
19630
21297
  });
19631
21298
 
19632
21299
  // packages/agent-skill-config/src/index.ts
19633
- var init_src16 = __esm({
21300
+ var init_src18 = __esm({
19634
21301
  "packages/agent-skill-config/src/index.ts"() {
19635
21302
  "use strict";
19636
21303
  init_configs3();
@@ -19855,7 +21522,7 @@ var init_skill = __esm({
19855
21522
  "src/cli/commands/skill.ts"() {
19856
21523
  "use strict";
19857
21524
  init_src5();
19858
- init_src16();
21525
+ init_src18();
19859
21526
  init_shared();
19860
21527
  init_command_not_found();
19861
21528
  DEFAULT_SKILL_AGENT = "claude-code";
@@ -20524,7 +22191,7 @@ var init_models2 = __esm({
20524
22191
  });
20525
22192
 
20526
22193
  // src/cli/commands/pipeline.ts
20527
- import path30 from "node:path";
22194
+ import path36 from "node:path";
20528
22195
  import { readFile as readFile9, stat as stat9 } from "node:fs/promises";
20529
22196
  import { fileURLToPath as fileURLToPath4 } from "node:url";
20530
22197
  async function resolvePipelinePlanDirectory(container) {
@@ -20572,11 +22239,11 @@ function resolveMaxRuns(value) {
20572
22239
  return parsed;
20573
22240
  }
20574
22241
  function resolvePipelinePaths(scope, cwd, homeDir) {
20575
- const rootPath = scope === "global" ? path30.join(homeDir, ".poe-code", "pipeline") : path30.join(cwd, ".poe-code", "pipeline");
22242
+ const rootPath = scope === "global" ? path36.join(homeDir, ".poe-code", "pipeline") : path36.join(cwd, ".poe-code", "pipeline");
20576
22243
  const displayRoot = scope === "global" ? "~/.poe-code/pipeline" : ".poe-code/pipeline";
20577
22244
  return {
20578
- plansPath: path30.join(rootPath, "plans"),
20579
- stepsPath: path30.join(rootPath, "steps.yaml"),
22245
+ plansPath: path36.join(rootPath, "plans"),
22246
+ stepsPath: path36.join(rootPath, "steps.yaml"),
20580
22247
  displayPlansPath: `${displayRoot}/plans`,
20581
22248
  displayStepsPath: `${displayRoot}/steps.yaml`
20582
22249
  };
@@ -20587,16 +22254,16 @@ async function loadPipelineTemplates() {
20587
22254
  }
20588
22255
  const packageRoot = await findPackageRoot(fileURLToPath4(import.meta.url));
20589
22256
  const templateRoots = [
20590
- path30.join(packageRoot, "src", "templates", "pipeline"),
20591
- path30.join(packageRoot, "dist", "templates", "pipeline")
22257
+ path36.join(packageRoot, "src", "templates", "pipeline"),
22258
+ path36.join(packageRoot, "dist", "templates", "pipeline")
20592
22259
  ];
20593
22260
  for (const templateRoot of templateRoots) {
20594
22261
  if (!await pathExistsOnDisk(templateRoot)) {
20595
22262
  continue;
20596
22263
  }
20597
22264
  const [skillPlan, steps] = await Promise.all([
20598
- readFile9(path30.join(templateRoot, "SKILL_plan.md"), "utf8"),
20599
- readFile9(path30.join(templateRoot, "steps.yaml.hbs"), "utf8")
22265
+ readFile9(path36.join(templateRoot, "SKILL_plan.md"), "utf8"),
22266
+ readFile9(path36.join(templateRoot, "steps.yaml.hbs"), "utf8")
20600
22267
  ]);
20601
22268
  pipelineTemplatesCache = { skillPlan, steps };
20602
22269
  return pipelineTemplatesCache;
@@ -20615,12 +22282,12 @@ async function pathExistsOnDisk(targetPath) {
20615
22282
  }
20616
22283
  }
20617
22284
  async function findPackageRoot(entryFilePath) {
20618
- let currentPath = path30.dirname(entryFilePath);
22285
+ let currentPath = path36.dirname(entryFilePath);
20619
22286
  while (true) {
20620
- if (await pathExistsOnDisk(path30.join(currentPath, "package.json"))) {
22287
+ if (await pathExistsOnDisk(path36.join(currentPath, "package.json"))) {
20621
22288
  return currentPath;
20622
22289
  }
20623
- const parentPath = path30.dirname(currentPath);
22290
+ const parentPath = path36.dirname(currentPath);
20624
22291
  if (parentPath === currentPath) {
20625
22292
  throw new Error("Unable to locate package root for Pipeline templates.");
20626
22293
  }
@@ -20911,7 +22578,7 @@ function registerPipelineCommand(program, container) {
20911
22578
  `Would ${stepsExists ? "overwrite" : "create"}: ${pipelinePaths.displayStepsPath}`
20912
22579
  );
20913
22580
  } else {
20914
- await container.fs.mkdir(path30.dirname(pipelinePaths.stepsPath), {
22581
+ await container.fs.mkdir(path36.dirname(pipelinePaths.stepsPath), {
20915
22582
  recursive: true
20916
22583
  });
20917
22584
  await container.fs.writeFile(pipelinePaths.stepsPath, templates.steps, {
@@ -20936,7 +22603,7 @@ var init_pipeline3 = __esm({
20936
22603
  "use strict";
20937
22604
  init_src5();
20938
22605
  init_src2();
20939
- init_src16();
22606
+ init_src18();
20940
22607
  init_src4();
20941
22608
  init_config3();
20942
22609
  init_errors();
@@ -20950,7 +22617,7 @@ var init_pipeline3 = __esm({
20950
22617
  });
20951
22618
 
20952
22619
  // src/cli/commands/ralph.ts
20953
- import path31 from "node:path";
22620
+ import path37 from "node:path";
20954
22621
  function formatDuration2(ms) {
20955
22622
  const totalSeconds = Math.round(ms / 1e3);
20956
22623
  const minutes = Math.floor(totalSeconds / 60);
@@ -20986,9 +22653,9 @@ function normalizeConfiguredIterations(value) {
20986
22653
  }
20987
22654
  function resolveAbsoluteDocPath4(container, docPath) {
20988
22655
  if (docPath.startsWith("~/")) {
20989
- return path31.join(container.env.homeDir, docPath.slice(2));
22656
+ return path37.join(container.env.homeDir, docPath.slice(2));
20990
22657
  }
20991
- return path31.isAbsolute(docPath) ? docPath : path31.resolve(container.env.cwd, docPath);
22658
+ return path37.isAbsolute(docPath) ? docPath : path37.resolve(container.env.cwd, docPath);
20992
22659
  }
20993
22660
  async function resolvePlanDirectory2(container) {
20994
22661
  const configDoc = await readMergedDocument(
@@ -21347,7 +23014,7 @@ var init_ralph3 = __esm({
21347
23014
  init_src5();
21348
23015
  init_src2();
21349
23016
  init_src6();
21350
- init_src9();
23017
+ init_src11();
21351
23018
  init_src4();
21352
23019
  init_config3();
21353
23020
  init_errors();
@@ -21359,11 +23026,11 @@ var init_ralph3 = __esm({
21359
23026
  });
21360
23027
 
21361
23028
  // src/cli/commands/experiment.ts
21362
- import path32 from "node:path";
23029
+ import path38 from "node:path";
21363
23030
  import { readFile as readFile10, stat as stat10 } from "node:fs/promises";
21364
23031
  import { fileURLToPath as fileURLToPath5 } from "node:url";
21365
23032
  function resolveExperimentPaths(scope, cwd, homeDir) {
21366
- const rootPath = scope === "global" ? path32.join(homeDir, ".poe-code", "experiments") : path32.join(cwd, ".poe-code", "experiments");
23033
+ const rootPath = scope === "global" ? path38.join(homeDir, ".poe-code", "experiments") : path38.join(cwd, ".poe-code", "experiments");
21367
23034
  const displayRoot = scope === "global" ? "~/.poe-code/experiments" : ".poe-code/experiments";
21368
23035
  return {
21369
23036
  experimentsPath: rootPath,
@@ -21382,12 +23049,12 @@ async function pathExistsOnDisk2(targetPath) {
21382
23049
  }
21383
23050
  }
21384
23051
  async function findPackageRoot2(entryFilePath) {
21385
- let currentPath = path32.dirname(entryFilePath);
23052
+ let currentPath = path38.dirname(entryFilePath);
21386
23053
  while (true) {
21387
- if (await pathExistsOnDisk2(path32.join(currentPath, "package.json"))) {
23054
+ if (await pathExistsOnDisk2(path38.join(currentPath, "package.json"))) {
21388
23055
  return currentPath;
21389
23056
  }
21390
- const parentPath = path32.dirname(currentPath);
23057
+ const parentPath = path38.dirname(currentPath);
21391
23058
  if (parentPath === currentPath) {
21392
23059
  throw new Error("Unable to locate package root for Experiment templates.");
21393
23060
  }
@@ -21400,16 +23067,16 @@ async function loadExperimentTemplates() {
21400
23067
  }
21401
23068
  const packageRoot = await findPackageRoot2(fileURLToPath5(import.meta.url));
21402
23069
  const templateRoots = [
21403
- path32.join(packageRoot, "src", "templates", "experiment"),
21404
- path32.join(packageRoot, "dist", "templates", "experiment")
23070
+ path38.join(packageRoot, "src", "templates", "experiment"),
23071
+ path38.join(packageRoot, "dist", "templates", "experiment")
21405
23072
  ];
21406
23073
  for (const templateRoot of templateRoots) {
21407
23074
  if (!await pathExistsOnDisk2(templateRoot)) {
21408
23075
  continue;
21409
23076
  }
21410
23077
  const [skillPlan, runYaml] = await Promise.all([
21411
- readFile10(path32.join(templateRoot, "SKILL_experiment.md"), "utf8"),
21412
- readFile10(path32.join(templateRoot, "run.yaml.hbs"), "utf8")
23078
+ readFile10(path38.join(templateRoot, "SKILL_experiment.md"), "utf8"),
23079
+ readFile10(path38.join(templateRoot, "run.yaml.hbs"), "utf8")
21413
23080
  ]);
21414
23081
  experimentTemplatesCache = { skillPlan, runYaml };
21415
23082
  return experimentTemplatesCache;
@@ -21487,12 +23154,12 @@ function parseNonNegativeInt(value, fieldName) {
21487
23154
  }
21488
23155
  function resolveAbsoluteDocPath5(container, docPath) {
21489
23156
  if (docPath.startsWith("~/")) {
21490
- return path32.join(container.env.homeDir, docPath.slice(2));
23157
+ return path38.join(container.env.homeDir, docPath.slice(2));
21491
23158
  }
21492
- return path32.isAbsolute(docPath) ? docPath : path32.resolve(container.env.cwd, docPath);
23159
+ return path38.isAbsolute(docPath) ? docPath : path38.resolve(container.env.cwd, docPath);
21493
23160
  }
21494
23161
  async function discoverExperimentDocs(container) {
21495
- const directoryPath = path32.join(container.env.cwd, EXPERIMENTS_DIRECTORY);
23162
+ const directoryPath = path38.join(container.env.cwd, EXPERIMENTS_DIRECTORY);
21496
23163
  let names;
21497
23164
  try {
21498
23165
  names = await container.fs.readdir(directoryPath);
@@ -21507,8 +23174,8 @@ async function discoverExperimentDocs(container) {
21507
23174
  if (!name.endsWith(".md")) {
21508
23175
  continue;
21509
23176
  }
21510
- const relativePath = path32.join(EXPERIMENTS_DIRECTORY, name);
21511
- const absolutePath = path32.join(directoryPath, name);
23177
+ const relativePath = path38.join(EXPERIMENTS_DIRECTORY, name);
23178
+ const absolutePath = path38.join(directoryPath, name);
21512
23179
  const stat11 = await container.fs.stat(absolutePath);
21513
23180
  if (!stat11.isFile()) {
21514
23181
  continue;
@@ -21872,8 +23539,8 @@ function registerExperimentCommand(program, container) {
21872
23539
  );
21873
23540
  }
21874
23541
  }
21875
- const runYamlPath = path32.join(experimentPaths.experimentsPath, "run.yaml");
21876
- const runYamlDisplayPath = path32.join(experimentPaths.displayExperimentsPath, "run.yaml");
23542
+ const runYamlPath = path38.join(experimentPaths.experimentsPath, "run.yaml");
23543
+ const runYamlDisplayPath = path38.join(experimentPaths.displayExperimentsPath, "run.yaml");
21877
23544
  if (!await pathExists4(container.fs, runYamlPath)) {
21878
23545
  if (flags.dryRun) {
21879
23546
  resources.logger.dryRun(`Would create: ${runYamlDisplayPath}`);
@@ -21898,25 +23565,446 @@ var init_experiment2 = __esm({
21898
23565
  init_src5();
21899
23566
  init_src2();
21900
23567
  init_src6();
21901
- init_src16();
21902
- init_src10();
23568
+ init_src18();
23569
+ init_src12();
21903
23570
  init_errors();
21904
23571
  init_shared();
21905
23572
  await init_experiment();
21906
23573
  DEFAULT_EXPERIMENT_AGENT = "claude-code";
21907
23574
  DEFAULT_EXPERIMENT_SCOPE = "local";
21908
- EXPERIMENTS_DIRECTORY = path32.join(".poe-code", "experiments");
23575
+ EXPERIMENTS_DIRECTORY = path38.join(".poe-code", "experiments");
21909
23576
  experimentTemplatesCache = null;
21910
23577
  }
21911
23578
  });
21912
23579
 
23580
+ // src/cli/commands/launch.ts
23581
+ import { Option } from "commander";
23582
+ function registerLaunchCommand(program, container) {
23583
+ const launch = program.command("launch").description("Manage long-running host and Docker processes.");
23584
+ launch.command("start [id] [commandArgs...]").usage("<id> -- <command> [args...]").description("Start and supervise a managed process.").addOption(createChoiceOption("--restart <policy>", "Restart policy", ["never", "on-failure", "always"], "on-failure")).option("--max-restarts <n>", "Max consecutive restarts", "5").option("--ready-pattern <string>", "Log substring to wait for before reporting running").option("--ready-port <port>", "TCP port to probe for readiness").option("--cwd <dir>", "Working directory for the managed process").option("--env <entry>", "Environment variable (KEY=VALUE)", collectValues, []).option("--image <image>", "Docker image").option("--mount <src:target[:ro]>", "Docker bind mount", collectValues, []).option("--port <host:container>", "Docker port mapping", collectValues, []).option("--network <name>", "Docker network").addOption(createChoiceOption("--engine <engine>", "Container engine", ["docker", "podman"])).action(async function(id, commandArgs) {
23585
+ const spec = await resolveStartSpec({
23586
+ commandArgs,
23587
+ id,
23588
+ options: this.opts(),
23589
+ program
23590
+ });
23591
+ if (spec === null) {
23592
+ return;
23593
+ }
23594
+ await startLaunch({
23595
+ cwd: container.env.cwd,
23596
+ homeDir: container.env.homeDir,
23597
+ spec
23598
+ });
23599
+ });
23600
+ launch.command("stop <id>").description("Stop a managed process.").option("--force", "Stop immediately with SIGKILL / docker kill").action(async function(id) {
23601
+ const result = await stopLaunch({
23602
+ force: Boolean(this.opts().force),
23603
+ homeDir: container.env.homeDir,
23604
+ id
23605
+ });
23606
+ if (result === null) {
23607
+ throw new ValidationError(`Managed process not found: ${id}`);
23608
+ }
23609
+ });
23610
+ launch.command("restart <id>").description("Restart a managed process.").action(async function(id) {
23611
+ await restartLaunch({ homeDir: container.env.homeDir, id });
23612
+ });
23613
+ launch.command("status").description("List managed processes.").action(async function() {
23614
+ const records = await listLaunches({ homeDir: container.env.homeDir });
23615
+ const flags = resolveCommandFlags(program);
23616
+ const resources = createExecutionResources(container, flags, "launch:status");
23617
+ if (records.length === 0) {
23618
+ resources.logger.info("No managed processes.");
23619
+ return;
23620
+ }
23621
+ resources.logger.info(renderTable({
23622
+ columns: [
23623
+ { name: "ID", title: "ID", alignment: "left", maxLen: 24 },
23624
+ { name: "RUNTIME", title: "RUNTIME", alignment: "left", maxLen: 8 },
23625
+ { name: "STATUS", title: "STATUS", alignment: "left", maxLen: 12 },
23626
+ { name: "PID", title: "PID", alignment: "right", maxLen: 8 },
23627
+ { name: "RESTARTS", title: "RESTARTS", alignment: "right", maxLen: 10 },
23628
+ { name: "UPTIME", title: "UPTIME", alignment: "right", maxLen: 12 },
23629
+ { name: "LAST EXIT", title: "LAST EXIT", alignment: "right", maxLen: 10 }
23630
+ ],
23631
+ rows: records.map(formatStatusRow),
23632
+ theme: getTheme()
23633
+ }));
23634
+ });
23635
+ launch.command("logs <id>").description("Show managed process logs.").option("--follow", "Follow log output").option("--lines <n>", "Number of lines to show", "50").option("--stderr", "Show stderr instead of stdout").action(async function(id) {
23636
+ const options = this.opts();
23637
+ const lines = parseNonNegativeInt2(options.lines, "lines") ?? 50;
23638
+ const stream = options.stderr ? "stderr" : "stdout";
23639
+ const flags = resolveCommandFlags(program);
23640
+ const resources = createExecutionResources(container, flags, `launch:logs:${id}`);
23641
+ const initial = await readLaunchLogs({
23642
+ homeDir: container.env.homeDir,
23643
+ id,
23644
+ lines,
23645
+ stream
23646
+ });
23647
+ if (initial.length > 0) {
23648
+ resources.logger.info(initial.join("\n"));
23649
+ }
23650
+ if (!options.follow) {
23651
+ return;
23652
+ }
23653
+ const controller = new AbortController();
23654
+ const stop = () => {
23655
+ controller.abort();
23656
+ };
23657
+ process.once("SIGINT", stop);
23658
+ process.once("SIGTERM", stop);
23659
+ try {
23660
+ for await (const line of followLaunchLogs({
23661
+ homeDir: container.env.homeDir,
23662
+ id,
23663
+ lines,
23664
+ signal: controller.signal,
23665
+ stream
23666
+ })) {
23667
+ resources.logger.info(line);
23668
+ }
23669
+ } finally {
23670
+ process.removeListener("SIGINT", stop);
23671
+ process.removeListener("SIGTERM", stop);
23672
+ }
23673
+ });
23674
+ launch.command("rm <id>").description("Remove managed process state and logs.").action(async function(id) {
23675
+ await removeLaunch({ homeDir: container.env.homeDir, id });
23676
+ });
23677
+ launch.command("__run <id>", { hidden: true }).action(async function(id) {
23678
+ await runLaunchDaemon({ homeDir: container.env.homeDir, id });
23679
+ });
23680
+ return launch;
23681
+ }
23682
+ async function resolveStartSpec(options) {
23683
+ const flags = resolveCommandFlags(options.program);
23684
+ const id = await resolveProcessId(options.id);
23685
+ if (id === null) {
23686
+ return null;
23687
+ }
23688
+ const commandParts = await resolveCommandParts(options.commandArgs);
23689
+ if (commandParts === null) {
23690
+ return null;
23691
+ }
23692
+ if (commandParts.length === 0) {
23693
+ throw new ValidationError("Command to run is required.");
23694
+ }
23695
+ const runtime = await resolveRuntime({
23696
+ assumeYes: flags.assumeYes,
23697
+ hasCommand: commandParts.length > 0,
23698
+ image: options.options.image
23699
+ });
23700
+ if (runtime === null) {
23701
+ return null;
23702
+ }
23703
+ const restart = await resolveRestart(options.options.restart, flags.assumeYes);
23704
+ if (restart === null) {
23705
+ return null;
23706
+ }
23707
+ const spec = {
23708
+ args: commandParts.slice(1),
23709
+ command: commandParts[0],
23710
+ id,
23711
+ restart
23712
+ };
23713
+ const maxRestarts = parseNonNegativeInt2(options.options.maxRestarts, "max-restarts");
23714
+ if (maxRestarts !== void 0) {
23715
+ spec.maxRestarts = maxRestarts;
23716
+ }
23717
+ if (options.options.cwd) {
23718
+ spec.cwd = options.options.cwd;
23719
+ }
23720
+ const envEntries = options.options.env ?? [];
23721
+ if (envEntries.length > 0) {
23722
+ spec.env = parseEnvEntries(envEntries);
23723
+ }
23724
+ const readyCheck = resolveReadyCheck2(options.options);
23725
+ if (readyCheck) {
23726
+ spec.readyCheck = readyCheck;
23727
+ }
23728
+ if (runtime === "docker") {
23729
+ const image = await resolveDockerImage(options.options.image);
23730
+ if (image === null) {
23731
+ return null;
23732
+ }
23733
+ spec.docker = {
23734
+ image,
23735
+ ...options.options.engine ? { engine: options.options.engine } : {},
23736
+ ...options.options.mount?.length ? { mounts: options.options.mount.map(parseMount) } : {},
23737
+ ...options.options.port?.length ? { ports: options.options.port.map(parsePort) } : {},
23738
+ ...options.options.network ? { network: options.options.network } : {}
23739
+ };
23740
+ }
23741
+ return spec;
23742
+ }
23743
+ async function resolveProcessId(value) {
23744
+ if (value && value.trim().length > 0) {
23745
+ return value.trim();
23746
+ }
23747
+ const entered = await text3({
23748
+ message: "Process ID"
23749
+ });
23750
+ if (isCancel2(entered)) {
23751
+ cancel2("Launch start cancelled.");
23752
+ return null;
23753
+ }
23754
+ const id = typeof entered === "string" ? entered.trim() : "";
23755
+ if (id.length === 0) {
23756
+ throw new ValidationError("Process ID is required.");
23757
+ }
23758
+ return id;
23759
+ }
23760
+ async function resolveCommandParts(commandArgs) {
23761
+ if (commandArgs.length > 0) {
23762
+ return [...commandArgs];
23763
+ }
23764
+ const entered = await text3({
23765
+ message: "Command to run"
23766
+ });
23767
+ if (isCancel2(entered)) {
23768
+ cancel2("Launch start cancelled.");
23769
+ return null;
23770
+ }
23771
+ const value = typeof entered === "string" ? entered.trim() : "";
23772
+ if (value.length === 0) {
23773
+ throw new ValidationError("Command to run is required.");
23774
+ }
23775
+ return splitCommandLine(value);
23776
+ }
23777
+ async function resolveRuntime(options) {
23778
+ if (options.image) {
23779
+ return "docker";
23780
+ }
23781
+ if (options.hasCommand || options.assumeYes) {
23782
+ return "host";
23783
+ }
23784
+ const selected = await select2({
23785
+ message: "Runtime",
23786
+ options: [
23787
+ { label: "host", value: "host" },
23788
+ { label: "docker", value: "docker" }
23789
+ ]
23790
+ });
23791
+ if (isCancel2(selected)) {
23792
+ cancel2("Launch start cancelled.");
23793
+ return null;
23794
+ }
23795
+ return selected;
23796
+ }
23797
+ async function resolveDockerImage(value) {
23798
+ if (value && value.trim().length > 0) {
23799
+ return value.trim();
23800
+ }
23801
+ const entered = await text3({
23802
+ message: "Docker image"
23803
+ });
23804
+ if (isCancel2(entered)) {
23805
+ cancel2("Launch start cancelled.");
23806
+ return null;
23807
+ }
23808
+ const image = typeof entered === "string" ? entered.trim() : "";
23809
+ if (image.length === 0) {
23810
+ throw new ValidationError("Docker image is required when runtime is docker.");
23811
+ }
23812
+ return image;
23813
+ }
23814
+ async function resolveRestart(restart, assumeYes) {
23815
+ if (restart) {
23816
+ return restart;
23817
+ }
23818
+ if (assumeYes) {
23819
+ return "on-failure";
23820
+ }
23821
+ const selected = await select2({
23822
+ message: "Restart policy",
23823
+ options: [
23824
+ { label: "on-failure", value: "on-failure" },
23825
+ { label: "never", value: "never" },
23826
+ { label: "always", value: "always" }
23827
+ ]
23828
+ });
23829
+ if (isCancel2(selected)) {
23830
+ cancel2("Launch start cancelled.");
23831
+ return null;
23832
+ }
23833
+ return selected;
23834
+ }
23835
+ function resolveReadyCheck2(options) {
23836
+ if (options.readyPattern && options.readyPattern.trim().length > 0) {
23837
+ return { kind: "log-pattern", pattern: options.readyPattern.trim() };
23838
+ }
23839
+ const readyPort = parsePositiveInt2(options.readyPort, "ready-port");
23840
+ if (readyPort !== void 0) {
23841
+ return { kind: "tcp", port: readyPort };
23842
+ }
23843
+ return void 0;
23844
+ }
23845
+ function parseEnvEntries(entries) {
23846
+ const env = {};
23847
+ for (const entry of entries) {
23848
+ const separator = entry.indexOf("=");
23849
+ if (separator <= 0) {
23850
+ throw new ValidationError(`Invalid --env value "${entry}". Expected KEY=VALUE.`);
23851
+ }
23852
+ const key = entry.slice(0, separator).trim();
23853
+ const value = entry.slice(separator + 1);
23854
+ if (key.length === 0) {
23855
+ throw new ValidationError(`Invalid --env value "${entry}". Expected KEY=VALUE.`);
23856
+ }
23857
+ env[key] = value;
23858
+ }
23859
+ return env;
23860
+ }
23861
+ function parseMount(value) {
23862
+ const parts = value.split(":");
23863
+ if (parts.length < 2 || parts.length > 3) {
23864
+ throw new ValidationError(`Invalid --mount value "${value}". Expected src:target[:ro].`);
23865
+ }
23866
+ const mount = {
23867
+ source: parts[0],
23868
+ target: parts[1]
23869
+ };
23870
+ if (parts[2] === "ro") {
23871
+ mount.readonly = true;
23872
+ } else if (parts[2] !== void 0) {
23873
+ throw new ValidationError(`Invalid --mount value "${value}". Only :ro is supported.`);
23874
+ }
23875
+ return mount;
23876
+ }
23877
+ function parsePort(value) {
23878
+ const parts = value.split(":");
23879
+ if (parts.length !== 2) {
23880
+ throw new ValidationError(`Invalid --port value "${value}". Expected host:container.`);
23881
+ }
23882
+ return {
23883
+ container: parseRequiredPositiveInt(parts[1], "port"),
23884
+ host: parseRequiredPositiveInt(parts[0], "port")
23885
+ };
23886
+ }
23887
+ function splitCommandLine(value) {
23888
+ const parts = [];
23889
+ let current = "";
23890
+ let quote = null;
23891
+ for (const char of value) {
23892
+ if (quote !== null) {
23893
+ if (char === quote) {
23894
+ quote = null;
23895
+ } else {
23896
+ current += char;
23897
+ }
23898
+ continue;
23899
+ }
23900
+ if (char === "'" || char === '"') {
23901
+ quote = char;
23902
+ continue;
23903
+ }
23904
+ if (char === " " || char === " ") {
23905
+ if (current.length > 0) {
23906
+ parts.push(current);
23907
+ current = "";
23908
+ }
23909
+ continue;
23910
+ }
23911
+ current += char;
23912
+ }
23913
+ if (quote !== null) {
23914
+ throw new ValidationError("Command contains an unterminated quote.");
23915
+ }
23916
+ if (current.length > 0) {
23917
+ parts.push(current);
23918
+ }
23919
+ return parts;
23920
+ }
23921
+ function formatStatusRow(record) {
23922
+ const state = record.state;
23923
+ const id = record.spec?.id ?? state?.id ?? "-";
23924
+ return {
23925
+ ID: id,
23926
+ "LAST EXIT": state?.lastExitCode == null ? "-" : String(state.lastExitCode),
23927
+ PID: state?.pid == null ? "-" : String(state.pid),
23928
+ RESTARTS: state ? String(state.restartCount) : "0",
23929
+ RUNTIME: state?.runtime ?? (record.spec?.docker ? "docker" : "host"),
23930
+ STATUS: state?.status ?? "stopped",
23931
+ UPTIME: formatUptime(state)
23932
+ };
23933
+ }
23934
+ function formatUptime(state) {
23935
+ if (!state || state.status !== "running" && state.status !== "restarting" || !state.lastStartedAt) {
23936
+ return "-";
23937
+ }
23938
+ const startedAt = Date.parse(state.lastStartedAt);
23939
+ if (!Number.isFinite(startedAt)) {
23940
+ return "-";
23941
+ }
23942
+ const totalSeconds = Math.max(0, Math.floor((Date.now() - startedAt) / 1e3));
23943
+ const hours = Math.floor(totalSeconds / 3600);
23944
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
23945
+ const seconds = totalSeconds % 60;
23946
+ if (hours > 0) {
23947
+ return `${hours}h ${minutes}m`;
23948
+ }
23949
+ if (minutes > 0) {
23950
+ return `${minutes}m ${seconds}s`;
23951
+ }
23952
+ return `${seconds}s`;
23953
+ }
23954
+ function createChoiceOption(flags, description, choices, defaultValue) {
23955
+ const option = new Option(flags, description).choices(choices);
23956
+ if (defaultValue !== void 0) {
23957
+ option.default(defaultValue);
23958
+ }
23959
+ return option;
23960
+ }
23961
+ function parsePositiveInt2(value, fieldName) {
23962
+ if (value == null) {
23963
+ return void 0;
23964
+ }
23965
+ const parsed = Number.parseInt(value, 10);
23966
+ if (!Number.isInteger(parsed) || parsed < 1) {
23967
+ throw new ValidationError(`Invalid ${fieldName} "${value}". Expected a positive integer.`);
23968
+ }
23969
+ return parsed;
23970
+ }
23971
+ function parseRequiredPositiveInt(value, fieldName) {
23972
+ const parsed = parsePositiveInt2(value, fieldName);
23973
+ if (parsed === void 0) {
23974
+ throw new ValidationError(`Invalid ${fieldName} "${value}". Expected a positive integer.`);
23975
+ }
23976
+ return parsed;
23977
+ }
23978
+ function parseNonNegativeInt2(value, fieldName) {
23979
+ if (value == null) {
23980
+ return void 0;
23981
+ }
23982
+ const parsed = Number.parseInt(value, 10);
23983
+ if (!Number.isInteger(parsed) || parsed < 0) {
23984
+ throw new ValidationError(`Invalid ${fieldName} "${value}". Expected a non-negative integer.`);
23985
+ }
23986
+ return parsed;
23987
+ }
23988
+ function collectValues(value, previous) {
23989
+ return [...previous, value];
23990
+ }
23991
+ var init_launch2 = __esm({
23992
+ "src/cli/commands/launch.ts"() {
23993
+ "use strict";
23994
+ init_src5();
23995
+ init_shared();
23996
+ init_errors();
23997
+ init_launch();
23998
+ }
23999
+ });
24000
+
21913
24001
  // package.json
21914
24002
  var package_default;
21915
24003
  var init_package = __esm({
21916
24004
  "package.json"() {
21917
24005
  package_default = {
21918
24006
  name: "poe-code",
21919
- version: "3.0.121",
24007
+ version: "3.0.122",
21920
24008
  description: "CLI tool to configure Poe API for developer workflows.",
21921
24009
  type: "module",
21922
24010
  main: "./dist/index.js",
@@ -22031,7 +24119,9 @@ var init_package = __esm({
22031
24119
  typescript: "^5.9.3",
22032
24120
  "typescript-eslint": "^8.54.0",
22033
24121
  vitest: "^4.0.18",
22034
- "@poe-code/experiment-loop": "*"
24122
+ "@poe-code/experiment-loop": "*",
24123
+ "@poe-code/process-launcher": "*",
24124
+ "@poe-code/process-runner": "*"
22035
24125
  },
22036
24126
  repository: {
22037
24127
  type: "git",
@@ -22047,7 +24137,7 @@ __export(program_exports, {
22047
24137
  createProgram: () => createProgram
22048
24138
  });
22049
24139
  import { basename as basename3 } from "node:path";
22050
- import { Command as Command2 } from "commander";
24140
+ import { Command as Command3 } from "commander";
22051
24141
  function formatCommandHeader(cmd) {
22052
24142
  const parts = [];
22053
24143
  let current = cmd;
@@ -22069,7 +24159,7 @@ function formatHelpText(input) {
22069
24159
  name: "install",
22070
24160
  aliases: ["i"],
22071
24161
  args: "[agent]",
22072
- description: "Install tooling for a configured agent"
24162
+ description: "Install agent binary for a configured agent"
22073
24163
  },
22074
24164
  {
22075
24165
  name: "configure",
@@ -22099,7 +24189,7 @@ function formatHelpText(input) {
22099
24189
  name: "auth status",
22100
24190
  aliases: [],
22101
24191
  args: "",
22102
- description: "Show login, balance, and configuration status"
24192
+ description: "Show login status"
22103
24193
  },
22104
24194
  {
22105
24195
  name: "agent",
@@ -22144,10 +24234,10 @@ function formatHelpText(input) {
22144
24234
  description: "Remove Poe MCP configuration from your agent"
22145
24235
  },
22146
24236
  {
22147
- name: "mcp serve",
24237
+ name: "experiment install",
22148
24238
  aliases: [],
22149
- args: "",
22150
- description: "Run the Poe MCP server on stdin/stdout"
24239
+ args: "[agent]",
24240
+ description: "Install the experiment skill into agent configuration"
22151
24241
  },
22152
24242
  {
22153
24243
  name: "skill configure",
@@ -22197,6 +24287,12 @@ function formatHelpText(input) {
22197
24287
  args: "[doc]",
22198
24288
  description: "Display an experiment journal as a formatted table"
22199
24289
  },
24290
+ {
24291
+ name: "launch",
24292
+ aliases: [],
24293
+ args: "",
24294
+ description: "Manage long-running host and Docker processes"
24295
+ },
22200
24296
  {
22201
24297
  name: "usage",
22202
24298
  aliases: ["u"],
@@ -22214,24 +24310,6 @@ function formatHelpText(input) {
22214
24310
  aliases: [],
22215
24311
  args: "",
22216
24312
  description: "Show config file paths and usage hints"
22217
- },
22218
- {
22219
- name: "utils config show",
22220
- aliases: [],
22221
- args: "",
22222
- description: "Show config inputs and resolved result"
22223
- },
22224
- {
22225
- name: "utils config init",
22226
- aliases: [],
22227
- args: "",
22228
- description: "Create a project config file"
22229
- },
22230
- {
22231
- name: "utils config edit",
22232
- aliases: [],
22233
- args: "",
22234
- description: "Open a config file in your editor"
22235
24313
  }
22236
24314
  ];
22237
24315
  const nameWidth = Math.max(
@@ -22335,7 +24413,7 @@ function createProgram(dependencies) {
22335
24413
  return program;
22336
24414
  }
22337
24415
  function bootstrapProgram(container) {
22338
- const program = new Command2();
24416
+ const program = new Command3();
22339
24417
  const executionContext = detectExecutionContext({
22340
24418
  argv: process.argv,
22341
24419
  env: container.env.variables,
@@ -22371,6 +24449,7 @@ function bootstrapProgram(container) {
22371
24449
  registerPipelineCommand(program, container);
22372
24450
  registerRalphCommand(program, container);
22373
24451
  registerExperimentCommand(program, container);
24452
+ registerLaunchCommand(program, container);
22374
24453
  registerUsageCommand(program, container);
22375
24454
  registerModelsCommand(program, container);
22376
24455
  program.allowExcessArguments().action(function() {
@@ -22431,6 +24510,7 @@ var init_program = __esm({
22431
24510
  await init_pipeline3();
22432
24511
  await init_ralph3();
22433
24512
  await init_experiment2();
24513
+ init_launch2();
22434
24514
  init_package();
22435
24515
  init_command_not_found();
22436
24516
  init_execution_context();
@@ -22522,7 +24602,7 @@ __export(bootstrap_exports, {
22522
24602
  createCliMain: () => createCliMain,
22523
24603
  isCliInvocation: () => isCliInvocation
22524
24604
  });
22525
- import * as nodeFs from "node:fs/promises";
24605
+ import * as nodeFs4 from "node:fs/promises";
22526
24606
  import * as nodeFsSync3 from "node:fs";
22527
24607
  import { realpathSync } from "node:fs";
22528
24608
  import { homedir as homedir5 } from "node:os";
@@ -22597,18 +24677,23 @@ var init_bootstrap = __esm({
22597
24677
  init_error_logger();
22598
24678
  init_errors();
22599
24679
  init_prompt_runner();
22600
- fsAdapter = nodeFs;
24680
+ fsAdapter = nodeFs4;
22601
24681
  }
22602
24682
  });
22603
24683
 
22604
24684
  // src/index.ts
22605
24685
  await init_spawn3();
22606
24686
  await init_pipeline2();
22607
- await init_ralph2();
22608
- await init_experiment();
22609
24687
  import { realpathSync as realpathSync2 } from "node:fs";
22610
24688
  import { pathToFileURL as pathToFileURL3 } from "node:url";
22611
24689
 
24690
+ // src/sdk/process-launcher.ts
24691
+ init_src10();
24692
+
24693
+ // src/index.ts
24694
+ await init_ralph2();
24695
+ await init_experiment();
24696
+
22612
24697
  // src/sdk/generate.ts
22613
24698
  init_constants();
22614
24699
  init_credentials();
@@ -22708,13 +24793,14 @@ function normalizeBaseUrl(value) {
22708
24793
 
22709
24794
  // src/index.ts
22710
24795
  init_credentials();
24796
+ init_launch();
22711
24797
 
22712
24798
  // src/cli/poe-agent-main.ts
22713
24799
  init_src6();
22714
24800
  init_src5();
22715
24801
  init_constants();
22716
24802
  init_errors();
22717
- import path23 from "node:path";
24803
+ import path29 from "node:path";
22718
24804
  import { Command } from "commander";
22719
24805
  function parseMcpSpawnConfig(input) {
22720
24806
  if (!input) {
@@ -22785,10 +24871,10 @@ function resolveWorkingDirectory(baseDir, candidate) {
22785
24871
  if (!candidate || candidate.trim().length === 0) {
22786
24872
  return void 0;
22787
24873
  }
22788
- if (path23.isAbsolute(candidate)) {
24874
+ if (path29.isAbsolute(candidate)) {
22789
24875
  return candidate;
22790
24876
  }
22791
- return path23.resolve(baseDir, candidate);
24877
+ return path29.resolve(baseDir, candidate);
22792
24878
  }
22793
24879
  function createPoeAgentProgram() {
22794
24880
  const program = new Command();
@@ -22882,18 +24968,30 @@ if (isCliInvocation2(process.argv, import.meta.url)) {
22882
24968
  void main();
22883
24969
  }
22884
24970
  export {
24971
+ createLogWriter,
24972
+ createStateStore,
24973
+ createSupervisor,
24974
+ followLaunchLogs,
22885
24975
  generate,
22886
24976
  generateAudio,
22887
24977
  generateImage,
22888
24978
  generateVideo,
22889
24979
  getPoeApiKey,
22890
24980
  isCliInvocation2 as isCliInvocation,
24981
+ listLaunches,
22891
24982
  main,
22892
24983
  poeAgentMain,
22893
24984
  readExperimentJournal,
24985
+ readLaunchLogs,
24986
+ removeLaunch,
24987
+ restartLaunch,
22894
24988
  runExperiment,
24989
+ runLaunchDaemon,
22895
24990
  runPipeline2 as runPipeline,
22896
24991
  runRalph2 as runRalph,
22897
- spawn4 as spawn
24992
+ spawn4 as spawn,
24993
+ startLaunch,
24994
+ stopLaunch,
24995
+ waitForReady
22898
24996
  };
22899
24997
  //# sourceMappingURL=index.js.map