poe-code 3.0.120 → 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/cli/commands/auth.js +1 -1
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/install.js +1 -1
- package/dist/cli/commands/install.js.map +1 -1
- package/dist/cli/commands/launch.d.ts +3 -0
- package/dist/cli/commands/launch.js +456 -0
- package/dist/cli/commands/launch.js.map +1 -0
- package/dist/cli/program.js +13 -23
- package/dist/cli/program.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2570 -434
- package/dist/index.js.map +4 -4
- package/dist/sdk/launch.d.ts +45 -0
- package/dist/sdk/launch.js +165 -0
- package/dist/sdk/launch.js.map +1 -0
- package/dist/sdk/process-launcher.d.ts +2 -0
- package/dist/sdk/process-launcher.js +2 -0
- package/dist/sdk/process-launcher.js.map +1 -0
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -925,16 +925,16 @@ function getConfigFormat(pathOrFormat) {
|
|
|
925
925
|
}
|
|
926
926
|
return formatRegistry[formatName];
|
|
927
927
|
}
|
|
928
|
-
function detectFormat(
|
|
929
|
-
const ext = getExtension(
|
|
928
|
+
function detectFormat(path39) {
|
|
929
|
+
const ext = getExtension(path39);
|
|
930
930
|
return extensionMap[ext];
|
|
931
931
|
}
|
|
932
|
-
function getExtension(
|
|
933
|
-
const lastDot =
|
|
932
|
+
function getExtension(path39) {
|
|
933
|
+
const lastDot = path39.lastIndexOf(".");
|
|
934
934
|
if (lastDot === -1) {
|
|
935
935
|
return "";
|
|
936
936
|
}
|
|
937
|
-
return
|
|
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(
|
|
1992
|
+
async readFile(path39, encoding) {
|
|
1993
1993
|
if (encoding) {
|
|
1994
|
-
return base.readFile(
|
|
1994
|
+
return base.readFile(path39, encoding);
|
|
1995
1995
|
}
|
|
1996
|
-
return base.readFile(
|
|
1996
|
+
return base.readFile(path39);
|
|
1997
1997
|
},
|
|
1998
|
-
async writeFile(
|
|
1999
|
-
const previousContent = await tryReadText(base,
|
|
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:
|
|
2003
|
+
path: path39,
|
|
2004
2004
|
nextContent,
|
|
2005
2005
|
previousContent
|
|
2006
2006
|
});
|
|
2007
2007
|
},
|
|
2008
|
-
async mkdir(
|
|
2009
|
-
recorder.record({ type: "mkdir", path:
|
|
2008
|
+
async mkdir(path39, options) {
|
|
2009
|
+
recorder.record({ type: "mkdir", path: path39, options });
|
|
2010
2010
|
},
|
|
2011
|
-
async stat(
|
|
2012
|
-
return base.stat(
|
|
2011
|
+
async stat(path39) {
|
|
2012
|
+
return base.stat(path39);
|
|
2013
2013
|
},
|
|
2014
|
-
async unlink(
|
|
2015
|
-
recorder.record({ type: "unlink", path:
|
|
2014
|
+
async unlink(path39) {
|
|
2015
|
+
recorder.record({ type: "unlink", path: path39 });
|
|
2016
2016
|
},
|
|
2017
|
-
async readdir(
|
|
2018
|
-
return base.readdir(
|
|
2017
|
+
async readdir(path39) {
|
|
2018
|
+
return base.readdir(path39);
|
|
2019
2019
|
}
|
|
2020
2020
|
};
|
|
2021
2021
|
if (typeof base.rm === "function") {
|
|
2022
|
-
proxy.rm = async (
|
|
2023
|
-
recorder.record({ type: "rm", path:
|
|
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(
|
|
2114
|
-
const command = `cat > ${
|
|
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,
|
|
2276
|
+
async function tryReadText(base, path39) {
|
|
2277
2277
|
try {
|
|
2278
|
-
return await base.readFile(
|
|
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
|
|
4126
|
+
let path39;
|
|
4127
4127
|
if (typeof item.content === "string") {
|
|
4128
|
-
|
|
4128
|
+
path39 = item.content;
|
|
4129
4129
|
} else {
|
|
4130
4130
|
try {
|
|
4131
|
-
|
|
4131
|
+
path39 = JSON.stringify(item.content);
|
|
4132
4132
|
} catch {
|
|
4133
|
-
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
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 (
|
|
4730
|
-
toolCall.path =
|
|
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: ((
|
|
6732
|
+
readFile: ((path39, encoding) => {
|
|
6733
6733
|
if (encoding) {
|
|
6734
|
-
return fs2.readFile(
|
|
6734
|
+
return fs2.readFile(path39, encoding);
|
|
6735
6735
|
}
|
|
6736
|
-
return fs2.readFile(
|
|
6736
|
+
return fs2.readFile(path39);
|
|
6737
6737
|
}),
|
|
6738
|
-
writeFile: (
|
|
6739
|
-
mkdir: (
|
|
6738
|
+
writeFile: (path39, data, opts) => fs2.writeFile(path39, data, opts),
|
|
6739
|
+
mkdir: (path39, opts) => fs2.mkdir(path39, opts).then(() => {
|
|
6740
6740
|
}),
|
|
6741
|
-
stat: (
|
|
6742
|
-
rm: (
|
|
6743
|
-
unlink: (
|
|
6744
|
-
readdir: (
|
|
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: (
|
|
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
|
|
7514
|
-
return
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
8074
|
-
const rightName =
|
|
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
|
-
|
|
9584
|
+
path20.join(cwd, ".poe-code", "ralph", "plans"),
|
|
8088
9585
|
".poe-code/ralph/plans"
|
|
8089
9586
|
),
|
|
8090
9587
|
scanDir(
|
|
8091
9588
|
fs3,
|
|
8092
|
-
|
|
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
|
|
9597
|
+
return path20.join(homeDir, dir.slice(2));
|
|
8101
9598
|
}
|
|
8102
|
-
return
|
|
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
|
|
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
|
|
9740
|
+
return path21.join(homeDir, docPath.slice(2));
|
|
8244
9741
|
}
|
|
8245
|
-
return
|
|
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 =
|
|
8277
|
-
const archiveDir =
|
|
8278
|
-
const archivePath =
|
|
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
|
|
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
|
-
|
|
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
|
|
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 =
|
|
8714
|
-
const globalPath =
|
|
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
|
|
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
|
|
10296
|
+
return path23.join(homeDir, docPath.slice(2));
|
|
8800
10297
|
}
|
|
8801
|
-
return
|
|
10298
|
+
return path23.isAbsolute(docPath) ? docPath : path23.resolve(cwd, docPath);
|
|
8802
10299
|
}
|
|
8803
10300
|
function resolveJournalPath(docPath) {
|
|
8804
|
-
return
|
|
8805
|
-
|
|
8806
|
-
`${
|
|
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,10 +10578,48 @@ async function runExperimentLoop(options) {
|
|
|
9081
10578
|
});
|
|
9082
10579
|
continue;
|
|
9083
10580
|
}
|
|
9084
|
-
const
|
|
9085
|
-
|
|
9086
|
-
|
|
9087
|
-
|
|
10581
|
+
const commitMessage = `experiment-loop: ${path23.basename(absoluteDocPath, path23.extname(absoluteDocPath))} #${experimentIndex}`;
|
|
10582
|
+
let commitHash;
|
|
10583
|
+
try {
|
|
10584
|
+
commitHash = await git.commitAll(commitMessage, options.cwd);
|
|
10585
|
+
} catch (commitError) {
|
|
10586
|
+
const errorMessage = commitError instanceof Error ? commitError.message : String(commitError);
|
|
10587
|
+
options.onRecoveryAttempt?.(errorMessage);
|
|
10588
|
+
const recoveryResult = await runAgent({
|
|
10589
|
+
agent: currentSpecifier.agent,
|
|
10590
|
+
prompt: `A git command failed. Fix the issue so the commit can succeed.
|
|
10591
|
+
|
|
10592
|
+
Error:
|
|
10593
|
+
${errorMessage}`,
|
|
10594
|
+
cwd: options.cwd,
|
|
10595
|
+
...model ? { model } : {},
|
|
10596
|
+
...options.signal ? { signal: options.signal } : {}
|
|
10597
|
+
});
|
|
10598
|
+
if (recoveryResult.exitCode !== 0) {
|
|
10599
|
+
const entry2 = createEntry({
|
|
10600
|
+
commit: preExperimentHash,
|
|
10601
|
+
status: "crash",
|
|
10602
|
+
score: null,
|
|
10603
|
+
output: errorMessage,
|
|
10604
|
+
durationMs: Date.now() - experimentStart
|
|
10605
|
+
});
|
|
10606
|
+
experimentsCompleted += 1;
|
|
10607
|
+
lastCrashOutput = entry2.output;
|
|
10608
|
+
await journal.log(entry2);
|
|
10609
|
+
await git.reset(preExperimentHash, options.cwd);
|
|
10610
|
+
options.onReset?.(preExperimentHash);
|
|
10611
|
+
options.onExperimentComplete?.(experimentIndex, entry2);
|
|
10612
|
+
await persistDoc({
|
|
10613
|
+
fs: fs3,
|
|
10614
|
+
docPath: absoluteDocPath,
|
|
10615
|
+
baseline: frontmatter.baseline,
|
|
10616
|
+
experimentsCompleted,
|
|
10617
|
+
experimentsKept
|
|
10618
|
+
});
|
|
10619
|
+
continue;
|
|
10620
|
+
}
|
|
10621
|
+
commitHash = await git.commitAll(commitMessage, options.cwd);
|
|
10622
|
+
}
|
|
9088
10623
|
options.onCommit?.(commitHash);
|
|
9089
10624
|
const evaluationResults = await evaluateChain(metrics, options.cwd, exec3, options.onMetricResult, metricTimeoutMs);
|
|
9090
10625
|
const keep = allMetricsPassed(metrics, evaluationResults) && allScoresImproved(metrics, evaluationResults, frontmatter.baseline);
|
|
@@ -9140,7 +10675,7 @@ var init_loop = __esm({
|
|
|
9140
10675
|
});
|
|
9141
10676
|
|
|
9142
10677
|
// packages/experiment-loop/src/index.ts
|
|
9143
|
-
var
|
|
10678
|
+
var init_src12 = __esm({
|
|
9144
10679
|
"packages/experiment-loop/src/index.ts"() {
|
|
9145
10680
|
"use strict";
|
|
9146
10681
|
init_types2();
|
|
@@ -9154,7 +10689,7 @@ var init_src10 = __esm({
|
|
|
9154
10689
|
});
|
|
9155
10690
|
|
|
9156
10691
|
// src/sdk/experiment.ts
|
|
9157
|
-
import
|
|
10692
|
+
import path24 from "node:path";
|
|
9158
10693
|
import * as fsPromises7 from "node:fs/promises";
|
|
9159
10694
|
function createDefaultFs7() {
|
|
9160
10695
|
return {
|
|
@@ -9180,14 +10715,14 @@ function createDefaultFs7() {
|
|
|
9180
10715
|
}
|
|
9181
10716
|
function resolveAbsoluteDocPath3(docPath, cwd, homeDir) {
|
|
9182
10717
|
if (docPath.startsWith("~/")) {
|
|
9183
|
-
return
|
|
10718
|
+
return path24.join(homeDir, docPath.slice(2));
|
|
9184
10719
|
}
|
|
9185
|
-
return
|
|
10720
|
+
return path24.isAbsolute(docPath) ? docPath : path24.resolve(cwd, docPath);
|
|
9186
10721
|
}
|
|
9187
10722
|
function resolveJournalPath2(docPath) {
|
|
9188
|
-
return
|
|
9189
|
-
|
|
9190
|
-
`${
|
|
10723
|
+
return path24.join(
|
|
10724
|
+
path24.dirname(docPath),
|
|
10725
|
+
`${path24.basename(docPath, path24.extname(docPath))}.journal.jsonl`
|
|
9191
10726
|
);
|
|
9192
10727
|
}
|
|
9193
10728
|
async function runExperiment(options) {
|
|
@@ -9215,7 +10750,7 @@ async function readExperimentJournal(options) {
|
|
|
9215
10750
|
var init_experiment = __esm({
|
|
9216
10751
|
async "src/sdk/experiment.ts"() {
|
|
9217
10752
|
"use strict";
|
|
9218
|
-
|
|
10753
|
+
init_src12();
|
|
9219
10754
|
init_src6();
|
|
9220
10755
|
await init_spawn3();
|
|
9221
10756
|
}
|
|
@@ -9284,99 +10819,393 @@ async function readErrorBody(response) {
|
|
|
9284
10819
|
return void 0;
|
|
9285
10820
|
}
|
|
9286
10821
|
}
|
|
9287
|
-
function extractTextContent(data) {
|
|
9288
|
-
if (!isRecord7(data)) return void 0;
|
|
9289
|
-
const choices = data.choices;
|
|
9290
|
-
if (!Array.isArray(choices) || choices.length === 0) return void 0;
|
|
9291
|
-
const first = choices[0];
|
|
9292
|
-
if (!isRecord7(first)) return void 0;
|
|
9293
|
-
const message = first.message;
|
|
9294
|
-
if (!isRecord7(message)) return void 0;
|
|
9295
|
-
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
|
+
});
|
|
9296
11079
|
}
|
|
9297
|
-
function
|
|
9298
|
-
const
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
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);
|
|
9308
11104
|
}
|
|
9309
|
-
|
|
9310
|
-
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
|
|
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);
|
|
9314
11137
|
}
|
|
9315
|
-
}
|
|
9316
|
-
}
|
|
9317
|
-
if (isValidUrl(content.trim())) {
|
|
9318
|
-
return { url: content.trim() };
|
|
9319
|
-
}
|
|
9320
|
-
const markdownUrl = extractMarkdownUrl(content);
|
|
9321
|
-
if (markdownUrl) {
|
|
9322
|
-
return { url: markdownUrl };
|
|
9323
|
-
}
|
|
9324
|
-
return { content };
|
|
11138
|
+
});
|
|
9325
11139
|
}
|
|
9326
|
-
function
|
|
9327
|
-
|
|
9328
|
-
|
|
9329
|
-
|
|
9330
|
-
|
|
9331
|
-
|
|
9332
|
-
const url = content.slice(urlStart, end);
|
|
9333
|
-
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
|
+
});
|
|
9334
11146
|
}
|
|
9335
|
-
function
|
|
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
|
+
}
|
|
9336
11161
|
try {
|
|
9337
|
-
|
|
9338
|
-
|
|
9339
|
-
|
|
9340
|
-
|
|
11162
|
+
process.kill(-pid, signal);
|
|
11163
|
+
} catch (error) {
|
|
11164
|
+
if (!isMissingProcessGroupError(error)) {
|
|
11165
|
+
throw error;
|
|
11166
|
+
}
|
|
11167
|
+
process.kill(pid, signal);
|
|
9341
11168
|
}
|
|
9342
11169
|
}
|
|
9343
|
-
function
|
|
9344
|
-
return
|
|
11170
|
+
function isMissingProcessGroupError(error) {
|
|
11171
|
+
return error instanceof Error && "code" in error && error.code === "ESRCH";
|
|
9345
11172
|
}
|
|
9346
|
-
|
|
9347
|
-
|
|
9348
|
-
|
|
9349
|
-
|
|
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
|
+
}
|
|
9350
11179
|
}
|
|
9351
|
-
|
|
9352
|
-
|
|
9353
|
-
// src/services/client-instance.ts
|
|
9354
|
-
function setGlobalClient(client) {
|
|
9355
|
-
globalClient = client;
|
|
11180
|
+
return env;
|
|
9356
11181
|
}
|
|
9357
|
-
function
|
|
9358
|
-
if (!
|
|
9359
|
-
|
|
11182
|
+
async function stopDockerArtifacts(record, force) {
|
|
11183
|
+
if (!record.spec?.docker?.containerName) {
|
|
11184
|
+
return;
|
|
9360
11185
|
}
|
|
9361
|
-
|
|
11186
|
+
const engine = resolveEngine(record.spec.docker.engine);
|
|
11187
|
+
const command = force ? "kill" : "stop";
|
|
11188
|
+
spawnSync(engine, [command, record.spec.docker.containerName], { stdio: "ignore" });
|
|
9362
11189
|
}
|
|
9363
|
-
async function
|
|
9364
|
-
if (
|
|
11190
|
+
async function removeDockerArtifacts(record) {
|
|
11191
|
+
if (!record.spec?.docker?.containerName) {
|
|
9365
11192
|
return;
|
|
9366
11193
|
}
|
|
9367
|
-
const
|
|
9368
|
-
|
|
9369
|
-
baseUrl: options.baseUrl,
|
|
9370
|
-
httpClient: options.httpClient
|
|
9371
|
-
});
|
|
9372
|
-
setGlobalClient(client);
|
|
11194
|
+
const engine = resolveEngine(record.spec.docker.engine);
|
|
11195
|
+
spawnSync(engine, ["rm", "-f", record.spec.docker.containerName], { stdio: "ignore" });
|
|
9373
11196
|
}
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
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"() {
|
|
9377
11205
|
"use strict";
|
|
9378
|
-
|
|
9379
|
-
|
|
11206
|
+
init_src10();
|
|
11207
|
+
init_src9();
|
|
11208
|
+
init_execution_context();
|
|
9380
11209
|
}
|
|
9381
11210
|
});
|
|
9382
11211
|
|
|
@@ -9860,13 +11689,13 @@ var init_acp_transport = __esm({
|
|
|
9860
11689
|
env,
|
|
9861
11690
|
requestTimeoutMs,
|
|
9862
11691
|
firstRequestId,
|
|
9863
|
-
spawn:
|
|
11692
|
+
spawn: spawn9 = spawnChildProcess4
|
|
9864
11693
|
} = options;
|
|
9865
11694
|
this.command = command;
|
|
9866
11695
|
this.closed = new Promise((resolve) => {
|
|
9867
11696
|
this.resolveClosed = resolve;
|
|
9868
11697
|
});
|
|
9869
|
-
this.child =
|
|
11698
|
+
this.child = spawn9(command, [...args], {
|
|
9870
11699
|
cwd,
|
|
9871
11700
|
env,
|
|
9872
11701
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -9979,8 +11808,8 @@ function resourceNotFound(resource) {
|
|
|
9979
11808
|
`Resource not found: ${resource}`
|
|
9980
11809
|
);
|
|
9981
11810
|
}
|
|
9982
|
-
function assertAbsolutePath(
|
|
9983
|
-
if (!isAbsolute(
|
|
11811
|
+
function assertAbsolutePath(path39) {
|
|
11812
|
+
if (!isAbsolute(path39)) {
|
|
9984
11813
|
throw invalidParams('"path" must be an absolute path');
|
|
9985
11814
|
}
|
|
9986
11815
|
}
|
|
@@ -10714,7 +12543,7 @@ var init_run_report = __esm({
|
|
|
10714
12543
|
});
|
|
10715
12544
|
|
|
10716
12545
|
// packages/poe-acp-client/src/index.ts
|
|
10717
|
-
var
|
|
12546
|
+
var init_src13 = __esm({
|
|
10718
12547
|
"packages/poe-acp-client/src/index.ts"() {
|
|
10719
12548
|
"use strict";
|
|
10720
12549
|
init_acp_client();
|
|
@@ -11741,7 +13570,7 @@ var init_acp_core = __esm({
|
|
|
11741
13570
|
});
|
|
11742
13571
|
|
|
11743
13572
|
// packages/poe-agent/src/plugins/plugin-args.ts
|
|
11744
|
-
import
|
|
13573
|
+
import path26 from "node:path";
|
|
11745
13574
|
function isObjectRecord3(value) {
|
|
11746
13575
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11747
13576
|
}
|
|
@@ -11772,13 +13601,13 @@ function getOptionalString(args, key) {
|
|
|
11772
13601
|
return value;
|
|
11773
13602
|
}
|
|
11774
13603
|
function resolveAllowedPath(cwd, allowedPaths, inputPath) {
|
|
11775
|
-
const resolvedPath =
|
|
13604
|
+
const resolvedPath = path26.resolve(cwd, inputPath);
|
|
11776
13605
|
const isAllowed = allowedPaths.some((allowedPath) => {
|
|
11777
13606
|
if (allowedPath === resolvedPath) {
|
|
11778
13607
|
return true;
|
|
11779
13608
|
}
|
|
11780
|
-
const rel =
|
|
11781
|
-
return rel.length > 0 && !rel.startsWith("..") && !
|
|
13609
|
+
const rel = path26.relative(allowedPath, resolvedPath);
|
|
13610
|
+
return rel.length > 0 && !rel.startsWith("..") && !path26.isAbsolute(rel);
|
|
11782
13611
|
});
|
|
11783
13612
|
if (!isAllowed) {
|
|
11784
13613
|
throw new Error(`Path is outside allowed paths: ${inputPath}`);
|
|
@@ -11793,7 +13622,7 @@ var init_plugin_args = __esm({
|
|
|
11793
13622
|
|
|
11794
13623
|
// packages/poe-agent/src/plugins/poe-agent-plugin-files.ts
|
|
11795
13624
|
import fsPromises9 from "node:fs/promises";
|
|
11796
|
-
import
|
|
13625
|
+
import path27 from "node:path";
|
|
11797
13626
|
async function fileExists(fs3, filePath) {
|
|
11798
13627
|
try {
|
|
11799
13628
|
await fs3.readFile(filePath, "utf8");
|
|
@@ -11817,9 +13646,9 @@ var init_poe_agent_plugin_files = __esm({
|
|
|
11817
13646
|
"use strict";
|
|
11818
13647
|
init_plugin_args();
|
|
11819
13648
|
filesPlugin = (options = {}) => {
|
|
11820
|
-
const cwd =
|
|
13649
|
+
const cwd = path27.resolve(options.cwd ?? process.cwd());
|
|
11821
13650
|
const allowedPaths = (options.allowedPaths ?? [cwd]).map(
|
|
11822
|
-
(allowedPath) =>
|
|
13651
|
+
(allowedPath) => path27.resolve(cwd, allowedPath)
|
|
11823
13652
|
);
|
|
11824
13653
|
const fs3 = options.fs ?? fsPromises9;
|
|
11825
13654
|
const readFileTool = {
|
|
@@ -11873,7 +13702,7 @@ var init_poe_agent_plugin_files = __esm({
|
|
|
11873
13702
|
async call(args) {
|
|
11874
13703
|
const command = getRequiredString(args, "command");
|
|
11875
13704
|
const filePath = resolveAllowedPath(cwd, allowedPaths, getRequiredString(args, "path"));
|
|
11876
|
-
const displayedPath =
|
|
13705
|
+
const displayedPath = path27.relative(cwd, filePath) || path27.basename(filePath);
|
|
11877
13706
|
if (command === "str_replace") {
|
|
11878
13707
|
const oldStr = getRequiredString(args, "old_str", true);
|
|
11879
13708
|
const newStr = getRequiredString(args, "new_str", true);
|
|
@@ -11893,7 +13722,7 @@ var init_poe_agent_plugin_files = __esm({
|
|
|
11893
13722
|
if (await fileExists(fs3, filePath)) {
|
|
11894
13723
|
throw new Error("File already exists \u2014 use str_replace to edit");
|
|
11895
13724
|
}
|
|
11896
|
-
await fs3.mkdir(
|
|
13725
|
+
await fs3.mkdir(path27.dirname(filePath), { recursive: true });
|
|
11897
13726
|
await fs3.writeFile(filePath, fileText, "utf8");
|
|
11898
13727
|
return `Created file: ${displayedPath}`;
|
|
11899
13728
|
}
|
|
@@ -11934,7 +13763,7 @@ var init_poe_agent_plugin_files = __esm({
|
|
|
11934
13763
|
|
|
11935
13764
|
// packages/poe-agent/src/plugins/poe-agent-plugin-shell.ts
|
|
11936
13765
|
import { exec as execCallback2 } from "node:child_process";
|
|
11937
|
-
import
|
|
13766
|
+
import path28 from "node:path";
|
|
11938
13767
|
import { promisify } from "node:util";
|
|
11939
13768
|
async function defaultRunCommand(command, cwd) {
|
|
11940
13769
|
try {
|
|
@@ -11967,9 +13796,9 @@ var init_poe_agent_plugin_shell = __esm({
|
|
|
11967
13796
|
init_plugin_args();
|
|
11968
13797
|
exec = promisify(execCallback2);
|
|
11969
13798
|
shellPlugin = (options = {}) => {
|
|
11970
|
-
const cwd =
|
|
13799
|
+
const cwd = path28.resolve(options.cwd ?? process.cwd());
|
|
11971
13800
|
const allowedPaths = (options.allowedPaths ?? [cwd]).map(
|
|
11972
|
-
(allowedPath) =>
|
|
13801
|
+
(allowedPath) => path28.resolve(cwd, allowedPath)
|
|
11973
13802
|
);
|
|
11974
13803
|
const runCommand2 = options.runCommand ?? defaultRunCommand;
|
|
11975
13804
|
const runCommandTool = {
|
|
@@ -12008,7 +13837,7 @@ var init_poe_agent_plugin_shell = __esm({
|
|
|
12008
13837
|
// packages/poe-agent/src/system-prompt.ts
|
|
12009
13838
|
import { readFileSync } from "node:fs";
|
|
12010
13839
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
12011
|
-
import { fileURLToPath as
|
|
13840
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
12012
13841
|
function loadSystemPromptSync() {
|
|
12013
13842
|
return readFileSync(SYSTEM_PROMPT_PATH, "utf8");
|
|
12014
13843
|
}
|
|
@@ -12016,7 +13845,7 @@ var SYSTEM_PROMPT_PATH;
|
|
|
12016
13845
|
var init_system_prompt = __esm({
|
|
12017
13846
|
"packages/poe-agent/src/system-prompt.ts"() {
|
|
12018
13847
|
"use strict";
|
|
12019
|
-
SYSTEM_PROMPT_PATH =
|
|
13848
|
+
SYSTEM_PROMPT_PATH = fileURLToPath3(new URL("./SYSTEM_PROMPT.md", import.meta.url));
|
|
12020
13849
|
}
|
|
12021
13850
|
});
|
|
12022
13851
|
|
|
@@ -12753,7 +14582,7 @@ var AgentHost;
|
|
|
12753
14582
|
var init_agent_host = __esm({
|
|
12754
14583
|
"packages/poe-agent/src/runtime/agent-host.ts"() {
|
|
12755
14584
|
"use strict";
|
|
12756
|
-
|
|
14585
|
+
init_src13();
|
|
12757
14586
|
init_agent_session();
|
|
12758
14587
|
init_acp_core();
|
|
12759
14588
|
init_run_context();
|
|
@@ -13120,10 +14949,10 @@ var init_config2 = __esm({
|
|
|
13120
14949
|
});
|
|
13121
14950
|
|
|
13122
14951
|
// packages/tiny-mcp-client/src/internal.ts
|
|
13123
|
-
import { spawn as
|
|
14952
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
13124
14953
|
import { PassThrough } from "node:stream";
|
|
13125
14954
|
function defaultStdioSpawn(command, args, options) {
|
|
13126
|
-
return
|
|
14955
|
+
return spawn7(command, args, options);
|
|
13127
14956
|
}
|
|
13128
14957
|
function serializeJsonRpcMessage2(message) {
|
|
13129
14958
|
return `${JSON.stringify(message)}
|
|
@@ -14040,7 +15869,7 @@ var init_internal = __esm({
|
|
|
14040
15869
|
});
|
|
14041
15870
|
|
|
14042
15871
|
// packages/tiny-mcp-client/src/index.ts
|
|
14043
|
-
var
|
|
15872
|
+
var init_src14 = __esm({
|
|
14044
15873
|
"packages/tiny-mcp-client/src/index.ts"() {
|
|
14045
15874
|
"use strict";
|
|
14046
15875
|
init_internal();
|
|
@@ -14089,7 +15918,7 @@ var DEFAULT_MCP_CLIENT_INFO, PluginApiImpl;
|
|
|
14089
15918
|
var init_plugin_api_impl = __esm({
|
|
14090
15919
|
"packages/poe-agent/src/runtime/plugin-api-impl.ts"() {
|
|
14091
15920
|
"use strict";
|
|
14092
|
-
|
|
15921
|
+
init_src14();
|
|
14093
15922
|
init_hooks();
|
|
14094
15923
|
DEFAULT_MCP_CLIENT_INFO = {
|
|
14095
15924
|
name: "poe-agent",
|
|
@@ -14656,7 +16485,7 @@ __export(src_exports, {
|
|
|
14656
16485
|
agent: () => agent,
|
|
14657
16486
|
createAgentSession: () => createAgentSession
|
|
14658
16487
|
});
|
|
14659
|
-
var
|
|
16488
|
+
var init_src15 = __esm({
|
|
14660
16489
|
"packages/poe-agent/src/index.ts"() {
|
|
14661
16490
|
"use strict";
|
|
14662
16491
|
init_agent();
|
|
@@ -14994,7 +16823,7 @@ function createInMemoryAcpTransport2(options) {
|
|
|
14994
16823
|
}
|
|
14995
16824
|
if (method === "session/new") {
|
|
14996
16825
|
const request = params;
|
|
14997
|
-
const { createAgentSession: createAgentSession2 } = await Promise.resolve().then(() => (
|
|
16826
|
+
const { createAgentSession: createAgentSession2 } = await Promise.resolve().then(() => (init_src15(), src_exports));
|
|
14998
16827
|
const session = await createAgentSession2({
|
|
14999
16828
|
model: options.model,
|
|
15000
16829
|
cwd: request.cwd || options.cwd,
|
|
@@ -15144,7 +16973,7 @@ var init_poe_agent = __esm({
|
|
|
15144
16973
|
"src/providers/poe-agent.ts"() {
|
|
15145
16974
|
"use strict";
|
|
15146
16975
|
init_constants();
|
|
15147
|
-
|
|
16976
|
+
init_src13();
|
|
15148
16977
|
init_create_provider();
|
|
15149
16978
|
poeAgentService = createProvider({
|
|
15150
16979
|
id: "poe-agent",
|
|
@@ -15338,7 +17167,7 @@ var init_container2 = __esm({
|
|
|
15338
17167
|
});
|
|
15339
17168
|
|
|
15340
17169
|
// src/services/config.ts
|
|
15341
|
-
import
|
|
17170
|
+
import path30 from "node:path";
|
|
15342
17171
|
async function deleteConfig(options) {
|
|
15343
17172
|
const { fs: fs3, filePath } = options;
|
|
15344
17173
|
try {
|
|
@@ -15419,7 +17248,7 @@ async function migrateLegacyCredentialsIfNeeded(fs3, filePath) {
|
|
|
15419
17248
|
await migrateLegacyCredentialsFile(fs3, filePath);
|
|
15420
17249
|
}
|
|
15421
17250
|
async function migrateLegacyCredentialsFile(fs3, configPath) {
|
|
15422
|
-
const legacyPath =
|
|
17251
|
+
const legacyPath = path30.join(path30.dirname(configPath), "credentials.json");
|
|
15423
17252
|
const raw = await readFileIfExists(fs3, legacyPath);
|
|
15424
17253
|
if (raw === null) {
|
|
15425
17254
|
return;
|
|
@@ -15487,9 +17316,9 @@ async function recoverInvalidConfig(fs3, filePath, content) {
|
|
|
15487
17316
|
await fs3.writeFile(filePath, EMPTY_DOCUMENT3, { encoding: "utf8" });
|
|
15488
17317
|
}
|
|
15489
17318
|
function createInvalidBackupPath2(filePath) {
|
|
15490
|
-
const directory =
|
|
15491
|
-
const baseName =
|
|
15492
|
-
return
|
|
17319
|
+
const directory = path30.dirname(filePath);
|
|
17320
|
+
const baseName = path30.basename(filePath);
|
|
17321
|
+
return path30.join(directory, `${baseName}.invalid-${createTimestamp()}.json`);
|
|
15493
17322
|
}
|
|
15494
17323
|
function isRecord8(value) {
|
|
15495
17324
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -15708,7 +17537,7 @@ function registerAgentCommand(program, container) {
|
|
|
15708
17537
|
}
|
|
15709
17538
|
let session;
|
|
15710
17539
|
try {
|
|
15711
|
-
const { createAgentSession: createAgentSession2 } = await Promise.resolve().then(() => (
|
|
17540
|
+
const { createAgentSession: createAgentSession2 } = await Promise.resolve().then(() => (init_src15(), src_exports));
|
|
15712
17541
|
session = await createAgentSession2({
|
|
15713
17542
|
model: options.model,
|
|
15714
17543
|
apiKey: options.apiKey,
|
|
@@ -15767,7 +17596,7 @@ var init_agent2 = __esm({
|
|
|
15767
17596
|
});
|
|
15768
17597
|
|
|
15769
17598
|
// src/cli/commands/spawn.ts
|
|
15770
|
-
import
|
|
17599
|
+
import path31 from "node:path";
|
|
15771
17600
|
function registerSpawnCommand(program, container, options = {}) {
|
|
15772
17601
|
const spawnServices = container.registry.list().filter((service) => typeof service.spawn === "function" || getSpawnConfig(service.name)).map((service) => service.name);
|
|
15773
17602
|
const extraServices = options.extraServices ?? [];
|
|
@@ -15969,10 +17798,10 @@ function resolveSpawnWorkingDirectory2(baseDir, candidate) {
|
|
|
15969
17798
|
if (!candidate || candidate.trim().length === 0) {
|
|
15970
17799
|
return void 0;
|
|
15971
17800
|
}
|
|
15972
|
-
if (
|
|
17801
|
+
if (path31.isAbsolute(candidate)) {
|
|
15973
17802
|
return candidate;
|
|
15974
17803
|
}
|
|
15975
|
-
return
|
|
17804
|
+
return path31.resolve(baseDir, candidate);
|
|
15976
17805
|
}
|
|
15977
17806
|
function parseMcpSpawnConfig2(input) {
|
|
15978
17807
|
if (!input) {
|
|
@@ -16090,7 +17919,7 @@ var init_spawn4 = __esm({
|
|
|
16090
17919
|
});
|
|
16091
17920
|
|
|
16092
17921
|
// src/sdk/research.ts
|
|
16093
|
-
import
|
|
17922
|
+
import path32 from "node:path";
|
|
16094
17923
|
async function research(container, options) {
|
|
16095
17924
|
const logger2 = options.logger;
|
|
16096
17925
|
const source = await resolveSource({
|
|
@@ -16125,7 +17954,7 @@ async function research(container, options) {
|
|
|
16125
17954
|
markdown: markdownOutput
|
|
16126
17955
|
});
|
|
16127
17956
|
outputPath = buildOutputPath(container.env.homeDir, options.prompt);
|
|
16128
|
-
await ensureDirectory2(container.fs,
|
|
17957
|
+
await ensureDirectory2(container.fs, path32.dirname(outputPath));
|
|
16129
17958
|
await container.fs.writeFile(outputPath, document, {
|
|
16130
17959
|
encoding: "utf8"
|
|
16131
17960
|
});
|
|
@@ -16200,7 +18029,7 @@ function buildResearchDocument(input) {
|
|
|
16200
18029
|
}
|
|
16201
18030
|
function buildClonePath(homeDir, github) {
|
|
16202
18031
|
const slug = extractRepoSlug(github);
|
|
16203
|
-
return
|
|
18032
|
+
return path32.join(homeDir, ".poe-code", "repos", slug);
|
|
16204
18033
|
}
|
|
16205
18034
|
function extractRepoSlug(value) {
|
|
16206
18035
|
const trimmed = value.trim();
|
|
@@ -16238,7 +18067,7 @@ function extractRepoSlug(value) {
|
|
|
16238
18067
|
function buildOutputPath(homeDir, prompt, now = /* @__PURE__ */ new Date()) {
|
|
16239
18068
|
const timestamp = formatTimestamp2(now);
|
|
16240
18069
|
const slug = buildSlug(prompt);
|
|
16241
|
-
return
|
|
18070
|
+
return path32.join(
|
|
16242
18071
|
homeDir,
|
|
16243
18072
|
".poe-code",
|
|
16244
18073
|
"research",
|
|
@@ -16259,7 +18088,7 @@ async function resolveSource(input) {
|
|
|
16259
18088
|
if (options.github) {
|
|
16260
18089
|
const cloneUrl = resolveGithubCloneUrl(options.github);
|
|
16261
18090
|
const clonePath = buildClonePath(container.env.homeDir, options.github);
|
|
16262
|
-
await ensureDirectory2(container.fs,
|
|
18091
|
+
await ensureDirectory2(container.fs, path32.dirname(clonePath));
|
|
16263
18092
|
const exists = await pathExists2(container.fs, clonePath);
|
|
16264
18093
|
if (!exists) {
|
|
16265
18094
|
const cloneResult = await container.commandRunner(
|
|
@@ -16357,10 +18186,10 @@ function formatYamlString(value) {
|
|
|
16357
18186
|
return JSON.stringify(value);
|
|
16358
18187
|
}
|
|
16359
18188
|
function resolvePath2(baseDir, candidate) {
|
|
16360
|
-
if (
|
|
18189
|
+
if (path32.isAbsolute(candidate)) {
|
|
16361
18190
|
return candidate;
|
|
16362
18191
|
}
|
|
16363
|
-
return
|
|
18192
|
+
return path32.resolve(baseDir, candidate);
|
|
16364
18193
|
}
|
|
16365
18194
|
function teeAcpStream(events) {
|
|
16366
18195
|
const chunks = [];
|
|
@@ -16420,7 +18249,7 @@ async function removePathFallback(fs3, target) {
|
|
|
16420
18249
|
if (stats && typeof stats.isDirectory === "function" && stats.isDirectory()) {
|
|
16421
18250
|
const entries = await fs3.readdir(target);
|
|
16422
18251
|
for (const entry of entries) {
|
|
16423
|
-
await removePathFallback(fs3,
|
|
18252
|
+
await removePathFallback(fs3, path32.join(target, entry));
|
|
16424
18253
|
}
|
|
16425
18254
|
}
|
|
16426
18255
|
try {
|
|
@@ -16586,7 +18415,7 @@ var init_research2 = __esm({
|
|
|
16586
18415
|
});
|
|
16587
18416
|
|
|
16588
18417
|
// src/cli/isolated-env-runner.ts
|
|
16589
|
-
import { spawn as
|
|
18418
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
16590
18419
|
async function isolatedEnvRunner(input) {
|
|
16591
18420
|
const details = await resolveIsolatedEnvDetails(
|
|
16592
18421
|
input.env,
|
|
@@ -16611,7 +18440,7 @@ async function isolatedEnvRunner(input) {
|
|
|
16611
18440
|
);
|
|
16612
18441
|
args = buildArgsWithMergedSettings(args, resolvedSettings);
|
|
16613
18442
|
}
|
|
16614
|
-
const child =
|
|
18443
|
+
const child = spawn8(details.agentBinary, args, {
|
|
16615
18444
|
stdio: "inherit",
|
|
16616
18445
|
env: {
|
|
16617
18446
|
...process.env,
|
|
@@ -16982,7 +18811,7 @@ function registerAuthCommand(program, container) {
|
|
|
16982
18811
|
const auth = program.command("auth").description("Authentication and account commands.").action(async () => {
|
|
16983
18812
|
await executeStatus(program, container);
|
|
16984
18813
|
});
|
|
16985
|
-
auth.command("status").description("Show login
|
|
18814
|
+
auth.command("status").description("Show login status.").action(async () => {
|
|
16986
18815
|
await executeStatus(program, container);
|
|
16987
18816
|
});
|
|
16988
18817
|
auth.command("api_key").description("Display stored API key.").action(async () => {
|
|
@@ -17061,7 +18890,7 @@ var init_auth = __esm({
|
|
|
17061
18890
|
});
|
|
17062
18891
|
|
|
17063
18892
|
// src/cli/commands/config.ts
|
|
17064
|
-
import { execSync } from "node:child_process";
|
|
18893
|
+
import { execSync as execSync3 } from "node:child_process";
|
|
17065
18894
|
function registerConfigCommand(program, container) {
|
|
17066
18895
|
const config = program.command("config").description("Inspect and manage poe-code config files.").action(async () => {
|
|
17067
18896
|
await executeConfigInfo(program, container);
|
|
@@ -17150,7 +18979,7 @@ async function executeConfigEdit(program, container, options) {
|
|
|
17150
18979
|
if (!await pathExists(container.fs, targetPath)) {
|
|
17151
18980
|
await initProjectConfig(container.fs, targetPath);
|
|
17152
18981
|
}
|
|
17153
|
-
|
|
18982
|
+
execSync3(`${editor} ${shlexQuote(targetPath)}`, {
|
|
17154
18983
|
stdio: "inherit"
|
|
17155
18984
|
});
|
|
17156
18985
|
}
|
|
@@ -17200,7 +19029,7 @@ var init_utils3 = __esm({
|
|
|
17200
19029
|
function registerInstallCommand(program, container) {
|
|
17201
19030
|
const serviceNames = container.registry.list().filter((service) => typeof service.install === "function").map((service) => service.name);
|
|
17202
19031
|
const serviceDescription = `Agent to install${formatServiceList(serviceNames)}`;
|
|
17203
|
-
return program.command("install").alias("i").description("Install
|
|
19032
|
+
return program.command("install").alias("i").description("Install agent binary for a configured agent.").argument(
|
|
17204
19033
|
"[agent]",
|
|
17205
19034
|
serviceDescription
|
|
17206
19035
|
).action(async (service) => {
|
|
@@ -17392,7 +19221,7 @@ var init_media_download = __esm({
|
|
|
17392
19221
|
});
|
|
17393
19222
|
|
|
17394
19223
|
// src/cli/commands/generate.ts
|
|
17395
|
-
import
|
|
19224
|
+
import path33 from "node:path";
|
|
17396
19225
|
function registerGenerateCommand(program, container) {
|
|
17397
19226
|
const generate2 = program.command("generate").alias("g").description("Generate content via Poe API").option("--model <model>", `Model identifier (default: ${DEFAULT_TEXT_MODEL})`).option(
|
|
17398
19227
|
"--param <key=value>",
|
|
@@ -17665,11 +19494,11 @@ function getDefaultMimeType(type) {
|
|
|
17665
19494
|
return defaults[type];
|
|
17666
19495
|
}
|
|
17667
19496
|
function resolveOutputPath(filename, cwd) {
|
|
17668
|
-
if (
|
|
19497
|
+
if (path33.isAbsolute(filename)) {
|
|
17669
19498
|
return { path: filename, label: filename };
|
|
17670
19499
|
}
|
|
17671
19500
|
return {
|
|
17672
|
-
path:
|
|
19501
|
+
path: path33.join(cwd, filename),
|
|
17673
19502
|
label: `./${filename}`
|
|
17674
19503
|
};
|
|
17675
19504
|
}
|
|
@@ -18397,7 +20226,7 @@ var init_content = __esm({
|
|
|
18397
20226
|
});
|
|
18398
20227
|
|
|
18399
20228
|
// packages/tiny-stdio-mcp-server/src/index.ts
|
|
18400
|
-
var
|
|
20229
|
+
var init_src16 = __esm({
|
|
18401
20230
|
"packages/tiny-stdio-mcp-server/src/index.ts"() {
|
|
18402
20231
|
"use strict";
|
|
18403
20232
|
init_server();
|
|
@@ -18700,7 +20529,7 @@ var generateTextSchema, generateImageSchema, generateVideoSchema, generateAudioS
|
|
|
18700
20529
|
var init_mcp_server = __esm({
|
|
18701
20530
|
"src/cli/mcp-server.ts"() {
|
|
18702
20531
|
"use strict";
|
|
18703
|
-
|
|
20532
|
+
init_src16();
|
|
18704
20533
|
init_client_instance();
|
|
18705
20534
|
init_constants();
|
|
18706
20535
|
generateTextSchema = defineSchema({
|
|
@@ -18779,150 +20608,26 @@ function parseMcpOutputFormatPreferences(value) {
|
|
|
18779
20608
|
);
|
|
18780
20609
|
}
|
|
18781
20610
|
if (normalized !== "url" && normalized !== "base64" && normalized !== "markdown" && normalized !== "markdown_instructions") {
|
|
18782
|
-
throw new ValidationError(
|
|
18783
|
-
`Invalid --output-format entry "${raw.trim()}". Expected "url", "base64", "markdown", or "markdown_instructions".`
|
|
18784
|
-
);
|
|
18785
|
-
}
|
|
18786
|
-
preferences.push(normalized);
|
|
18787
|
-
}
|
|
18788
|
-
const standaloneFormats = ["markdown", "markdown_instructions"];
|
|
18789
|
-
for (const standalone of standaloneFormats) {
|
|
18790
|
-
if (preferences.includes(standalone) && preferences.length > 1) {
|
|
18791
|
-
throw new ValidationError(
|
|
18792
|
-
`${standalone} output format cannot be combined with other formats. Use ${standalone} alone or choose a different format combination.`
|
|
18793
|
-
);
|
|
18794
|
-
}
|
|
18795
|
-
}
|
|
18796
|
-
return preferences;
|
|
18797
|
-
}
|
|
18798
|
-
var init_mcp_output_format = __esm({
|
|
18799
|
-
"src/cli/mcp-output-format.ts"() {
|
|
18800
|
-
"use strict";
|
|
18801
|
-
init_errors();
|
|
18802
|
-
}
|
|
18803
|
-
});
|
|
18804
|
-
|
|
18805
|
-
// src/utils/execution-context.ts
|
|
18806
|
-
import { basename as basename2, dirname as dirname3 } from "node:path";
|
|
18807
|
-
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
18808
|
-
function detectExecutionContext(input) {
|
|
18809
|
-
const { argv, env, moduleUrl } = input;
|
|
18810
|
-
if (isDevelopmentMode(argv, env)) {
|
|
18811
|
-
return createDevelopmentContext(moduleUrl);
|
|
18812
|
-
}
|
|
18813
|
-
if (isNpxExecution(env)) {
|
|
18814
|
-
const version = detectNpxVersion(env);
|
|
18815
|
-
return createNpxContext(version);
|
|
18816
|
-
}
|
|
18817
|
-
const invoked = basename2(argv[1] ?? "");
|
|
18818
|
-
const isPoeShort = invoked === "poe" || invoked === "poe.cmd" || invoked === "poe.exe";
|
|
18819
|
-
return {
|
|
18820
|
-
mode: "global",
|
|
18821
|
-
command: {
|
|
18822
|
-
command: isPoeShort ? "poe" : "poe-code",
|
|
18823
|
-
args: []
|
|
18824
|
-
}
|
|
18825
|
-
};
|
|
18826
|
-
}
|
|
18827
|
-
function isDevelopmentMode(argv, env) {
|
|
18828
|
-
const scriptPath = argv[1] ?? "";
|
|
18829
|
-
if (scriptPath.endsWith(".ts") || scriptPath.includes("/src/")) {
|
|
18830
|
-
return true;
|
|
18831
|
-
}
|
|
18832
|
-
if (env.npm_lifecycle_event === "dev") {
|
|
18833
|
-
return true;
|
|
18834
|
-
}
|
|
18835
|
-
const nodeOptions = env.NODE_OPTIONS ?? "";
|
|
18836
|
-
if (nodeOptions.includes("tsx") || nodeOptions.includes("ts-node")) {
|
|
18837
|
-
return true;
|
|
18838
|
-
}
|
|
18839
|
-
return false;
|
|
18840
|
-
}
|
|
18841
|
-
function isNpxExecution(env) {
|
|
18842
|
-
const execPath = env.npm_execpath ?? "";
|
|
18843
|
-
if (execPath.includes("npx") || execPath.includes("npm")) {
|
|
18844
|
-
const packagePath = env.npm_package_json ?? "";
|
|
18845
|
-
if (packagePath.includes("_npx") || packagePath.includes(".npm/_cacache")) {
|
|
18846
|
-
return true;
|
|
18847
|
-
}
|
|
18848
|
-
}
|
|
18849
|
-
if (env.npm_command === "exec") {
|
|
18850
|
-
return true;
|
|
18851
|
-
}
|
|
18852
|
-
return false;
|
|
18853
|
-
}
|
|
18854
|
-
function detectNpxVersion(env) {
|
|
18855
|
-
const packageJson = env.npm_package_json ?? "";
|
|
18856
|
-
const packageVersion = env.npm_package_version ?? "";
|
|
18857
|
-
if (packageJson.includes("@beta") || packageVersion.includes("beta")) {
|
|
18858
|
-
return "beta";
|
|
18859
|
-
}
|
|
18860
|
-
if (packageJson.includes("@latest")) {
|
|
18861
|
-
return "latest";
|
|
18862
|
-
}
|
|
18863
|
-
return "default";
|
|
18864
|
-
}
|
|
18865
|
-
function createDevelopmentContext(moduleUrl) {
|
|
18866
|
-
const modulePath = fileURLToPath3(moduleUrl);
|
|
18867
|
-
const srcIndex = modulePath.lastIndexOf("/src/");
|
|
18868
|
-
const projectRoot = srcIndex !== -1 ? modulePath.substring(0, srcIndex) : dirname3(dirname3(modulePath));
|
|
18869
|
-
return {
|
|
18870
|
-
mode: "development",
|
|
18871
|
-
command: {
|
|
18872
|
-
command: "npm",
|
|
18873
|
-
args: ["--silent", "--prefix", projectRoot, "run", "dev", "--"]
|
|
18874
|
-
}
|
|
18875
|
-
};
|
|
18876
|
-
}
|
|
18877
|
-
function createNpxContext(version) {
|
|
18878
|
-
const packageSpec = version === "default" ? "poe-code" : `poe-code@${version}`;
|
|
18879
|
-
return {
|
|
18880
|
-
mode: version === "default" ? "npx" : `npx-${version}`,
|
|
18881
|
-
command: {
|
|
18882
|
-
command: "npx",
|
|
18883
|
-
args: ["--yes", packageSpec]
|
|
18884
|
-
}
|
|
18885
|
-
};
|
|
18886
|
-
}
|
|
18887
|
-
function toMcpServerCommand(execCommand, subcommand) {
|
|
18888
|
-
return {
|
|
18889
|
-
command: execCommand.command,
|
|
18890
|
-
args: [...execCommand.args, subcommand]
|
|
18891
|
-
};
|
|
18892
|
-
}
|
|
18893
|
-
function formatCliHelpCommand(context, args) {
|
|
18894
|
-
const base = formatCliUsageCommand(context);
|
|
18895
|
-
const trailing = args.join(" ");
|
|
18896
|
-
if (trailing.length === 0) {
|
|
18897
|
-
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);
|
|
18898
20616
|
}
|
|
18899
|
-
|
|
18900
|
-
|
|
18901
|
-
|
|
18902
|
-
|
|
18903
|
-
|
|
18904
|
-
|
|
18905
|
-
|
|
18906
|
-
return "npx poe-code";
|
|
18907
|
-
case "npx-latest":
|
|
18908
|
-
return "npx poe-code@latest";
|
|
18909
|
-
case "npx-beta":
|
|
18910
|
-
return "npx poe-code@beta";
|
|
18911
|
-
case "global":
|
|
18912
|
-
default:
|
|
18913
|
-
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
|
+
}
|
|
18914
20624
|
}
|
|
20625
|
+
return preferences;
|
|
18915
20626
|
}
|
|
18916
|
-
|
|
18917
|
-
|
|
18918
|
-
argv: process.argv,
|
|
18919
|
-
env: process.env,
|
|
18920
|
-
moduleUrl
|
|
18921
|
-
});
|
|
18922
|
-
}
|
|
18923
|
-
var init_execution_context = __esm({
|
|
18924
|
-
"src/utils/execution-context.ts"() {
|
|
20627
|
+
var init_mcp_output_format = __esm({
|
|
20628
|
+
"src/cli/mcp-output-format.ts"() {
|
|
18925
20629
|
"use strict";
|
|
20630
|
+
init_errors();
|
|
18926
20631
|
}
|
|
18927
20632
|
});
|
|
18928
20633
|
|
|
@@ -19108,9 +20813,9 @@ var init_shapes = __esm({
|
|
|
19108
20813
|
});
|
|
19109
20814
|
|
|
19110
20815
|
// packages/agent-mcp-config/src/apply.ts
|
|
19111
|
-
import
|
|
20816
|
+
import path34 from "node:path";
|
|
19112
20817
|
function getConfigDirectory(configPath) {
|
|
19113
|
-
return
|
|
20818
|
+
return path34.dirname(configPath);
|
|
19114
20819
|
}
|
|
19115
20820
|
function isConfigObject5(value) {
|
|
19116
20821
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
@@ -19212,7 +20917,7 @@ var init_apply = __esm({
|
|
|
19212
20917
|
});
|
|
19213
20918
|
|
|
19214
20919
|
// packages/agent-mcp-config/src/index.ts
|
|
19215
|
-
var
|
|
20920
|
+
var init_src17 = __esm({
|
|
19216
20921
|
"packages/agent-mcp-config/src/index.ts"() {
|
|
19217
20922
|
"use strict";
|
|
19218
20923
|
init_configs2();
|
|
@@ -19392,7 +21097,7 @@ var init_mcp2 = __esm({
|
|
|
19392
21097
|
init_shared();
|
|
19393
21098
|
init_mcp_output_format();
|
|
19394
21099
|
init_command_not_found();
|
|
19395
|
-
|
|
21100
|
+
init_src17();
|
|
19396
21101
|
init_execution_context();
|
|
19397
21102
|
DEFAULT_MCP_AGENT = "claude-code";
|
|
19398
21103
|
}
|
|
@@ -19400,7 +21105,7 @@ var init_mcp2 = __esm({
|
|
|
19400
21105
|
|
|
19401
21106
|
// packages/agent-skill-config/src/configs.ts
|
|
19402
21107
|
import os2 from "node:os";
|
|
19403
|
-
import
|
|
21108
|
+
import path35 from "node:path";
|
|
19404
21109
|
function resolveAgentSupport2(input, registry = agentSkillConfigs) {
|
|
19405
21110
|
const resolvedId = resolveAgentId(input);
|
|
19406
21111
|
if (!resolvedId) {
|
|
@@ -19592,7 +21297,7 @@ var init_apply2 = __esm({
|
|
|
19592
21297
|
});
|
|
19593
21298
|
|
|
19594
21299
|
// packages/agent-skill-config/src/index.ts
|
|
19595
|
-
var
|
|
21300
|
+
var init_src18 = __esm({
|
|
19596
21301
|
"packages/agent-skill-config/src/index.ts"() {
|
|
19597
21302
|
"use strict";
|
|
19598
21303
|
init_configs3();
|
|
@@ -19817,7 +21522,7 @@ var init_skill = __esm({
|
|
|
19817
21522
|
"src/cli/commands/skill.ts"() {
|
|
19818
21523
|
"use strict";
|
|
19819
21524
|
init_src5();
|
|
19820
|
-
|
|
21525
|
+
init_src18();
|
|
19821
21526
|
init_shared();
|
|
19822
21527
|
init_command_not_found();
|
|
19823
21528
|
DEFAULT_SKILL_AGENT = "claude-code";
|
|
@@ -20486,7 +22191,7 @@ var init_models2 = __esm({
|
|
|
20486
22191
|
});
|
|
20487
22192
|
|
|
20488
22193
|
// src/cli/commands/pipeline.ts
|
|
20489
|
-
import
|
|
22194
|
+
import path36 from "node:path";
|
|
20490
22195
|
import { readFile as readFile9, stat as stat9 } from "node:fs/promises";
|
|
20491
22196
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
20492
22197
|
async function resolvePipelinePlanDirectory(container) {
|
|
@@ -20534,11 +22239,11 @@ function resolveMaxRuns(value) {
|
|
|
20534
22239
|
return parsed;
|
|
20535
22240
|
}
|
|
20536
22241
|
function resolvePipelinePaths(scope, cwd, homeDir) {
|
|
20537
|
-
const rootPath = scope === "global" ?
|
|
22242
|
+
const rootPath = scope === "global" ? path36.join(homeDir, ".poe-code", "pipeline") : path36.join(cwd, ".poe-code", "pipeline");
|
|
20538
22243
|
const displayRoot = scope === "global" ? "~/.poe-code/pipeline" : ".poe-code/pipeline";
|
|
20539
22244
|
return {
|
|
20540
|
-
plansPath:
|
|
20541
|
-
stepsPath:
|
|
22245
|
+
plansPath: path36.join(rootPath, "plans"),
|
|
22246
|
+
stepsPath: path36.join(rootPath, "steps.yaml"),
|
|
20542
22247
|
displayPlansPath: `${displayRoot}/plans`,
|
|
20543
22248
|
displayStepsPath: `${displayRoot}/steps.yaml`
|
|
20544
22249
|
};
|
|
@@ -20549,16 +22254,16 @@ async function loadPipelineTemplates() {
|
|
|
20549
22254
|
}
|
|
20550
22255
|
const packageRoot = await findPackageRoot(fileURLToPath4(import.meta.url));
|
|
20551
22256
|
const templateRoots = [
|
|
20552
|
-
|
|
20553
|
-
|
|
22257
|
+
path36.join(packageRoot, "src", "templates", "pipeline"),
|
|
22258
|
+
path36.join(packageRoot, "dist", "templates", "pipeline")
|
|
20554
22259
|
];
|
|
20555
22260
|
for (const templateRoot of templateRoots) {
|
|
20556
22261
|
if (!await pathExistsOnDisk(templateRoot)) {
|
|
20557
22262
|
continue;
|
|
20558
22263
|
}
|
|
20559
22264
|
const [skillPlan, steps] = await Promise.all([
|
|
20560
|
-
readFile9(
|
|
20561
|
-
readFile9(
|
|
22265
|
+
readFile9(path36.join(templateRoot, "SKILL_plan.md"), "utf8"),
|
|
22266
|
+
readFile9(path36.join(templateRoot, "steps.yaml.hbs"), "utf8")
|
|
20562
22267
|
]);
|
|
20563
22268
|
pipelineTemplatesCache = { skillPlan, steps };
|
|
20564
22269
|
return pipelineTemplatesCache;
|
|
@@ -20577,12 +22282,12 @@ async function pathExistsOnDisk(targetPath) {
|
|
|
20577
22282
|
}
|
|
20578
22283
|
}
|
|
20579
22284
|
async function findPackageRoot(entryFilePath) {
|
|
20580
|
-
let currentPath =
|
|
22285
|
+
let currentPath = path36.dirname(entryFilePath);
|
|
20581
22286
|
while (true) {
|
|
20582
|
-
if (await pathExistsOnDisk(
|
|
22287
|
+
if (await pathExistsOnDisk(path36.join(currentPath, "package.json"))) {
|
|
20583
22288
|
return currentPath;
|
|
20584
22289
|
}
|
|
20585
|
-
const parentPath =
|
|
22290
|
+
const parentPath = path36.dirname(currentPath);
|
|
20586
22291
|
if (parentPath === currentPath) {
|
|
20587
22292
|
throw new Error("Unable to locate package root for Pipeline templates.");
|
|
20588
22293
|
}
|
|
@@ -20873,7 +22578,7 @@ function registerPipelineCommand(program, container) {
|
|
|
20873
22578
|
`Would ${stepsExists ? "overwrite" : "create"}: ${pipelinePaths.displayStepsPath}`
|
|
20874
22579
|
);
|
|
20875
22580
|
} else {
|
|
20876
|
-
await container.fs.mkdir(
|
|
22581
|
+
await container.fs.mkdir(path36.dirname(pipelinePaths.stepsPath), {
|
|
20877
22582
|
recursive: true
|
|
20878
22583
|
});
|
|
20879
22584
|
await container.fs.writeFile(pipelinePaths.stepsPath, templates.steps, {
|
|
@@ -20898,7 +22603,7 @@ var init_pipeline3 = __esm({
|
|
|
20898
22603
|
"use strict";
|
|
20899
22604
|
init_src5();
|
|
20900
22605
|
init_src2();
|
|
20901
|
-
|
|
22606
|
+
init_src18();
|
|
20902
22607
|
init_src4();
|
|
20903
22608
|
init_config3();
|
|
20904
22609
|
init_errors();
|
|
@@ -20912,7 +22617,7 @@ var init_pipeline3 = __esm({
|
|
|
20912
22617
|
});
|
|
20913
22618
|
|
|
20914
22619
|
// src/cli/commands/ralph.ts
|
|
20915
|
-
import
|
|
22620
|
+
import path37 from "node:path";
|
|
20916
22621
|
function formatDuration2(ms) {
|
|
20917
22622
|
const totalSeconds = Math.round(ms / 1e3);
|
|
20918
22623
|
const minutes = Math.floor(totalSeconds / 60);
|
|
@@ -20948,9 +22653,9 @@ function normalizeConfiguredIterations(value) {
|
|
|
20948
22653
|
}
|
|
20949
22654
|
function resolveAbsoluteDocPath4(container, docPath) {
|
|
20950
22655
|
if (docPath.startsWith("~/")) {
|
|
20951
|
-
return
|
|
22656
|
+
return path37.join(container.env.homeDir, docPath.slice(2));
|
|
20952
22657
|
}
|
|
20953
|
-
return
|
|
22658
|
+
return path37.isAbsolute(docPath) ? docPath : path37.resolve(container.env.cwd, docPath);
|
|
20954
22659
|
}
|
|
20955
22660
|
async function resolvePlanDirectory2(container) {
|
|
20956
22661
|
const configDoc = await readMergedDocument(
|
|
@@ -21309,7 +23014,7 @@ var init_ralph3 = __esm({
|
|
|
21309
23014
|
init_src5();
|
|
21310
23015
|
init_src2();
|
|
21311
23016
|
init_src6();
|
|
21312
|
-
|
|
23017
|
+
init_src11();
|
|
21313
23018
|
init_src4();
|
|
21314
23019
|
init_config3();
|
|
21315
23020
|
init_errors();
|
|
@@ -21321,11 +23026,11 @@ var init_ralph3 = __esm({
|
|
|
21321
23026
|
});
|
|
21322
23027
|
|
|
21323
23028
|
// src/cli/commands/experiment.ts
|
|
21324
|
-
import
|
|
23029
|
+
import path38 from "node:path";
|
|
21325
23030
|
import { readFile as readFile10, stat as stat10 } from "node:fs/promises";
|
|
21326
23031
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
21327
23032
|
function resolveExperimentPaths(scope, cwd, homeDir) {
|
|
21328
|
-
const rootPath = scope === "global" ?
|
|
23033
|
+
const rootPath = scope === "global" ? path38.join(homeDir, ".poe-code", "experiments") : path38.join(cwd, ".poe-code", "experiments");
|
|
21329
23034
|
const displayRoot = scope === "global" ? "~/.poe-code/experiments" : ".poe-code/experiments";
|
|
21330
23035
|
return {
|
|
21331
23036
|
experimentsPath: rootPath,
|
|
@@ -21344,12 +23049,12 @@ async function pathExistsOnDisk2(targetPath) {
|
|
|
21344
23049
|
}
|
|
21345
23050
|
}
|
|
21346
23051
|
async function findPackageRoot2(entryFilePath) {
|
|
21347
|
-
let currentPath =
|
|
23052
|
+
let currentPath = path38.dirname(entryFilePath);
|
|
21348
23053
|
while (true) {
|
|
21349
|
-
if (await pathExistsOnDisk2(
|
|
23054
|
+
if (await pathExistsOnDisk2(path38.join(currentPath, "package.json"))) {
|
|
21350
23055
|
return currentPath;
|
|
21351
23056
|
}
|
|
21352
|
-
const parentPath =
|
|
23057
|
+
const parentPath = path38.dirname(currentPath);
|
|
21353
23058
|
if (parentPath === currentPath) {
|
|
21354
23059
|
throw new Error("Unable to locate package root for Experiment templates.");
|
|
21355
23060
|
}
|
|
@@ -21362,16 +23067,16 @@ async function loadExperimentTemplates() {
|
|
|
21362
23067
|
}
|
|
21363
23068
|
const packageRoot = await findPackageRoot2(fileURLToPath5(import.meta.url));
|
|
21364
23069
|
const templateRoots = [
|
|
21365
|
-
|
|
21366
|
-
|
|
23070
|
+
path38.join(packageRoot, "src", "templates", "experiment"),
|
|
23071
|
+
path38.join(packageRoot, "dist", "templates", "experiment")
|
|
21367
23072
|
];
|
|
21368
23073
|
for (const templateRoot of templateRoots) {
|
|
21369
23074
|
if (!await pathExistsOnDisk2(templateRoot)) {
|
|
21370
23075
|
continue;
|
|
21371
23076
|
}
|
|
21372
23077
|
const [skillPlan, runYaml] = await Promise.all([
|
|
21373
|
-
readFile10(
|
|
21374
|
-
readFile10(
|
|
23078
|
+
readFile10(path38.join(templateRoot, "SKILL_experiment.md"), "utf8"),
|
|
23079
|
+
readFile10(path38.join(templateRoot, "run.yaml.hbs"), "utf8")
|
|
21375
23080
|
]);
|
|
21376
23081
|
experimentTemplatesCache = { skillPlan, runYaml };
|
|
21377
23082
|
return experimentTemplatesCache;
|
|
@@ -21449,12 +23154,12 @@ function parseNonNegativeInt(value, fieldName) {
|
|
|
21449
23154
|
}
|
|
21450
23155
|
function resolveAbsoluteDocPath5(container, docPath) {
|
|
21451
23156
|
if (docPath.startsWith("~/")) {
|
|
21452
|
-
return
|
|
23157
|
+
return path38.join(container.env.homeDir, docPath.slice(2));
|
|
21453
23158
|
}
|
|
21454
|
-
return
|
|
23159
|
+
return path38.isAbsolute(docPath) ? docPath : path38.resolve(container.env.cwd, docPath);
|
|
21455
23160
|
}
|
|
21456
23161
|
async function discoverExperimentDocs(container) {
|
|
21457
|
-
const directoryPath =
|
|
23162
|
+
const directoryPath = path38.join(container.env.cwd, EXPERIMENTS_DIRECTORY);
|
|
21458
23163
|
let names;
|
|
21459
23164
|
try {
|
|
21460
23165
|
names = await container.fs.readdir(directoryPath);
|
|
@@ -21469,8 +23174,8 @@ async function discoverExperimentDocs(container) {
|
|
|
21469
23174
|
if (!name.endsWith(".md")) {
|
|
21470
23175
|
continue;
|
|
21471
23176
|
}
|
|
21472
|
-
const relativePath =
|
|
21473
|
-
const absolutePath =
|
|
23177
|
+
const relativePath = path38.join(EXPERIMENTS_DIRECTORY, name);
|
|
23178
|
+
const absolutePath = path38.join(directoryPath, name);
|
|
21474
23179
|
const stat11 = await container.fs.stat(absolutePath);
|
|
21475
23180
|
if (!stat11.isFile()) {
|
|
21476
23181
|
continue;
|
|
@@ -21834,8 +23539,8 @@ function registerExperimentCommand(program, container) {
|
|
|
21834
23539
|
);
|
|
21835
23540
|
}
|
|
21836
23541
|
}
|
|
21837
|
-
const runYamlPath =
|
|
21838
|
-
const runYamlDisplayPath =
|
|
23542
|
+
const runYamlPath = path38.join(experimentPaths.experimentsPath, "run.yaml");
|
|
23543
|
+
const runYamlDisplayPath = path38.join(experimentPaths.displayExperimentsPath, "run.yaml");
|
|
21839
23544
|
if (!await pathExists4(container.fs, runYamlPath)) {
|
|
21840
23545
|
if (flags.dryRun) {
|
|
21841
23546
|
resources.logger.dryRun(`Would create: ${runYamlDisplayPath}`);
|
|
@@ -21860,25 +23565,446 @@ var init_experiment2 = __esm({
|
|
|
21860
23565
|
init_src5();
|
|
21861
23566
|
init_src2();
|
|
21862
23567
|
init_src6();
|
|
21863
|
-
|
|
21864
|
-
|
|
23568
|
+
init_src18();
|
|
23569
|
+
init_src12();
|
|
21865
23570
|
init_errors();
|
|
21866
23571
|
init_shared();
|
|
21867
23572
|
await init_experiment();
|
|
21868
23573
|
DEFAULT_EXPERIMENT_AGENT = "claude-code";
|
|
21869
23574
|
DEFAULT_EXPERIMENT_SCOPE = "local";
|
|
21870
|
-
EXPERIMENTS_DIRECTORY =
|
|
23575
|
+
EXPERIMENTS_DIRECTORY = path38.join(".poe-code", "experiments");
|
|
21871
23576
|
experimentTemplatesCache = null;
|
|
21872
23577
|
}
|
|
21873
23578
|
});
|
|
21874
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
|
+
|
|
21875
24001
|
// package.json
|
|
21876
24002
|
var package_default;
|
|
21877
24003
|
var init_package = __esm({
|
|
21878
24004
|
"package.json"() {
|
|
21879
24005
|
package_default = {
|
|
21880
24006
|
name: "poe-code",
|
|
21881
|
-
version: "3.0.
|
|
24007
|
+
version: "3.0.122",
|
|
21882
24008
|
description: "CLI tool to configure Poe API for developer workflows.",
|
|
21883
24009
|
type: "module",
|
|
21884
24010
|
main: "./dist/index.js",
|
|
@@ -21993,7 +24119,9 @@ var init_package = __esm({
|
|
|
21993
24119
|
typescript: "^5.9.3",
|
|
21994
24120
|
"typescript-eslint": "^8.54.0",
|
|
21995
24121
|
vitest: "^4.0.18",
|
|
21996
|
-
"@poe-code/experiment-loop": "*"
|
|
24122
|
+
"@poe-code/experiment-loop": "*",
|
|
24123
|
+
"@poe-code/process-launcher": "*",
|
|
24124
|
+
"@poe-code/process-runner": "*"
|
|
21997
24125
|
},
|
|
21998
24126
|
repository: {
|
|
21999
24127
|
type: "git",
|
|
@@ -22009,7 +24137,7 @@ __export(program_exports, {
|
|
|
22009
24137
|
createProgram: () => createProgram
|
|
22010
24138
|
});
|
|
22011
24139
|
import { basename as basename3 } from "node:path";
|
|
22012
|
-
import { Command as
|
|
24140
|
+
import { Command as Command3 } from "commander";
|
|
22013
24141
|
function formatCommandHeader(cmd) {
|
|
22014
24142
|
const parts = [];
|
|
22015
24143
|
let current = cmd;
|
|
@@ -22031,7 +24159,7 @@ function formatHelpText(input) {
|
|
|
22031
24159
|
name: "install",
|
|
22032
24160
|
aliases: ["i"],
|
|
22033
24161
|
args: "[agent]",
|
|
22034
|
-
description: "Install
|
|
24162
|
+
description: "Install agent binary for a configured agent"
|
|
22035
24163
|
},
|
|
22036
24164
|
{
|
|
22037
24165
|
name: "configure",
|
|
@@ -22061,7 +24189,7 @@ function formatHelpText(input) {
|
|
|
22061
24189
|
name: "auth status",
|
|
22062
24190
|
aliases: [],
|
|
22063
24191
|
args: "",
|
|
22064
|
-
description: "Show login
|
|
24192
|
+
description: "Show login status"
|
|
22065
24193
|
},
|
|
22066
24194
|
{
|
|
22067
24195
|
name: "agent",
|
|
@@ -22106,10 +24234,10 @@ function formatHelpText(input) {
|
|
|
22106
24234
|
description: "Remove Poe MCP configuration from your agent"
|
|
22107
24235
|
},
|
|
22108
24236
|
{
|
|
22109
|
-
name: "
|
|
24237
|
+
name: "experiment install",
|
|
22110
24238
|
aliases: [],
|
|
22111
|
-
args: "",
|
|
22112
|
-
description: "
|
|
24239
|
+
args: "[agent]",
|
|
24240
|
+
description: "Install the experiment skill into agent configuration"
|
|
22113
24241
|
},
|
|
22114
24242
|
{
|
|
22115
24243
|
name: "skill configure",
|
|
@@ -22159,6 +24287,12 @@ function formatHelpText(input) {
|
|
|
22159
24287
|
args: "[doc]",
|
|
22160
24288
|
description: "Display an experiment journal as a formatted table"
|
|
22161
24289
|
},
|
|
24290
|
+
{
|
|
24291
|
+
name: "launch",
|
|
24292
|
+
aliases: [],
|
|
24293
|
+
args: "",
|
|
24294
|
+
description: "Manage long-running host and Docker processes"
|
|
24295
|
+
},
|
|
22162
24296
|
{
|
|
22163
24297
|
name: "usage",
|
|
22164
24298
|
aliases: ["u"],
|
|
@@ -22176,24 +24310,6 @@ function formatHelpText(input) {
|
|
|
22176
24310
|
aliases: [],
|
|
22177
24311
|
args: "",
|
|
22178
24312
|
description: "Show config file paths and usage hints"
|
|
22179
|
-
},
|
|
22180
|
-
{
|
|
22181
|
-
name: "utils config show",
|
|
22182
|
-
aliases: [],
|
|
22183
|
-
args: "",
|
|
22184
|
-
description: "Show config inputs and resolved result"
|
|
22185
|
-
},
|
|
22186
|
-
{
|
|
22187
|
-
name: "utils config init",
|
|
22188
|
-
aliases: [],
|
|
22189
|
-
args: "",
|
|
22190
|
-
description: "Create a project config file"
|
|
22191
|
-
},
|
|
22192
|
-
{
|
|
22193
|
-
name: "utils config edit",
|
|
22194
|
-
aliases: [],
|
|
22195
|
-
args: "",
|
|
22196
|
-
description: "Open a config file in your editor"
|
|
22197
24313
|
}
|
|
22198
24314
|
];
|
|
22199
24315
|
const nameWidth = Math.max(
|
|
@@ -22297,7 +24413,7 @@ function createProgram(dependencies) {
|
|
|
22297
24413
|
return program;
|
|
22298
24414
|
}
|
|
22299
24415
|
function bootstrapProgram(container) {
|
|
22300
|
-
const program = new
|
|
24416
|
+
const program = new Command3();
|
|
22301
24417
|
const executionContext = detectExecutionContext({
|
|
22302
24418
|
argv: process.argv,
|
|
22303
24419
|
env: container.env.variables,
|
|
@@ -22333,6 +24449,7 @@ function bootstrapProgram(container) {
|
|
|
22333
24449
|
registerPipelineCommand(program, container);
|
|
22334
24450
|
registerRalphCommand(program, container);
|
|
22335
24451
|
registerExperimentCommand(program, container);
|
|
24452
|
+
registerLaunchCommand(program, container);
|
|
22336
24453
|
registerUsageCommand(program, container);
|
|
22337
24454
|
registerModelsCommand(program, container);
|
|
22338
24455
|
program.allowExcessArguments().action(function() {
|
|
@@ -22393,6 +24510,7 @@ var init_program = __esm({
|
|
|
22393
24510
|
await init_pipeline3();
|
|
22394
24511
|
await init_ralph3();
|
|
22395
24512
|
await init_experiment2();
|
|
24513
|
+
init_launch2();
|
|
22396
24514
|
init_package();
|
|
22397
24515
|
init_command_not_found();
|
|
22398
24516
|
init_execution_context();
|
|
@@ -22484,7 +24602,7 @@ __export(bootstrap_exports, {
|
|
|
22484
24602
|
createCliMain: () => createCliMain,
|
|
22485
24603
|
isCliInvocation: () => isCliInvocation
|
|
22486
24604
|
});
|
|
22487
|
-
import * as
|
|
24605
|
+
import * as nodeFs4 from "node:fs/promises";
|
|
22488
24606
|
import * as nodeFsSync3 from "node:fs";
|
|
22489
24607
|
import { realpathSync } from "node:fs";
|
|
22490
24608
|
import { homedir as homedir5 } from "node:os";
|
|
@@ -22559,18 +24677,23 @@ var init_bootstrap = __esm({
|
|
|
22559
24677
|
init_error_logger();
|
|
22560
24678
|
init_errors();
|
|
22561
24679
|
init_prompt_runner();
|
|
22562
|
-
fsAdapter =
|
|
24680
|
+
fsAdapter = nodeFs4;
|
|
22563
24681
|
}
|
|
22564
24682
|
});
|
|
22565
24683
|
|
|
22566
24684
|
// src/index.ts
|
|
22567
24685
|
await init_spawn3();
|
|
22568
24686
|
await init_pipeline2();
|
|
22569
|
-
await init_ralph2();
|
|
22570
|
-
await init_experiment();
|
|
22571
24687
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
22572
24688
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
22573
24689
|
|
|
24690
|
+
// src/sdk/process-launcher.ts
|
|
24691
|
+
init_src10();
|
|
24692
|
+
|
|
24693
|
+
// src/index.ts
|
|
24694
|
+
await init_ralph2();
|
|
24695
|
+
await init_experiment();
|
|
24696
|
+
|
|
22574
24697
|
// src/sdk/generate.ts
|
|
22575
24698
|
init_constants();
|
|
22576
24699
|
init_credentials();
|
|
@@ -22670,13 +24793,14 @@ function normalizeBaseUrl(value) {
|
|
|
22670
24793
|
|
|
22671
24794
|
// src/index.ts
|
|
22672
24795
|
init_credentials();
|
|
24796
|
+
init_launch();
|
|
22673
24797
|
|
|
22674
24798
|
// src/cli/poe-agent-main.ts
|
|
22675
24799
|
init_src6();
|
|
22676
24800
|
init_src5();
|
|
22677
24801
|
init_constants();
|
|
22678
24802
|
init_errors();
|
|
22679
|
-
import
|
|
24803
|
+
import path29 from "node:path";
|
|
22680
24804
|
import { Command } from "commander";
|
|
22681
24805
|
function parseMcpSpawnConfig(input) {
|
|
22682
24806
|
if (!input) {
|
|
@@ -22747,10 +24871,10 @@ function resolveWorkingDirectory(baseDir, candidate) {
|
|
|
22747
24871
|
if (!candidate || candidate.trim().length === 0) {
|
|
22748
24872
|
return void 0;
|
|
22749
24873
|
}
|
|
22750
|
-
if (
|
|
24874
|
+
if (path29.isAbsolute(candidate)) {
|
|
22751
24875
|
return candidate;
|
|
22752
24876
|
}
|
|
22753
|
-
return
|
|
24877
|
+
return path29.resolve(baseDir, candidate);
|
|
22754
24878
|
}
|
|
22755
24879
|
function createPoeAgentProgram() {
|
|
22756
24880
|
const program = new Command();
|
|
@@ -22844,18 +24968,30 @@ if (isCliInvocation2(process.argv, import.meta.url)) {
|
|
|
22844
24968
|
void main();
|
|
22845
24969
|
}
|
|
22846
24970
|
export {
|
|
24971
|
+
createLogWriter,
|
|
24972
|
+
createStateStore,
|
|
24973
|
+
createSupervisor,
|
|
24974
|
+
followLaunchLogs,
|
|
22847
24975
|
generate,
|
|
22848
24976
|
generateAudio,
|
|
22849
24977
|
generateImage,
|
|
22850
24978
|
generateVideo,
|
|
22851
24979
|
getPoeApiKey,
|
|
22852
24980
|
isCliInvocation2 as isCliInvocation,
|
|
24981
|
+
listLaunches,
|
|
22853
24982
|
main,
|
|
22854
24983
|
poeAgentMain,
|
|
22855
24984
|
readExperimentJournal,
|
|
24985
|
+
readLaunchLogs,
|
|
24986
|
+
removeLaunch,
|
|
24987
|
+
restartLaunch,
|
|
22856
24988
|
runExperiment,
|
|
24989
|
+
runLaunchDaemon,
|
|
22857
24990
|
runPipeline2 as runPipeline,
|
|
22858
24991
|
runRalph2 as runRalph,
|
|
22859
|
-
spawn4 as spawn
|
|
24992
|
+
spawn4 as spawn,
|
|
24993
|
+
startLaunch,
|
|
24994
|
+
stopLaunch,
|
|
24995
|
+
waitForReady
|
|
22860
24996
|
};
|
|
22861
24997
|
//# sourceMappingURL=index.js.map
|