poe-code 3.0.93 → 3.0.94
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/program.js +12 -0
- package/dist/cli/program.js.map +1 -1
- package/dist/index.js +1242 -106
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -988,16 +988,16 @@ function getConfigFormat(pathOrFormat) {
|
|
|
988
988
|
}
|
|
989
989
|
return formatRegistry[formatName];
|
|
990
990
|
}
|
|
991
|
-
function detectFormat(
|
|
992
|
-
const ext = getExtension(
|
|
991
|
+
function detectFormat(path26) {
|
|
992
|
+
const ext = getExtension(path26);
|
|
993
993
|
return extensionMap[ext];
|
|
994
994
|
}
|
|
995
|
-
function getExtension(
|
|
996
|
-
const lastDot =
|
|
995
|
+
function getExtension(path26) {
|
|
996
|
+
const lastDot = path26.lastIndexOf(".");
|
|
997
997
|
if (lastDot === -1) {
|
|
998
998
|
return "";
|
|
999
999
|
}
|
|
1000
|
-
return
|
|
1000
|
+
return path26.slice(lastDot).toLowerCase();
|
|
1001
1001
|
}
|
|
1002
1002
|
var formatRegistry, extensionMap;
|
|
1003
1003
|
var init_formats = __esm({
|
|
@@ -1328,8 +1328,8 @@ async function applyChmod(mutation, context, options) {
|
|
|
1328
1328
|
};
|
|
1329
1329
|
}
|
|
1330
1330
|
try {
|
|
1331
|
-
const
|
|
1332
|
-
const currentMode = typeof
|
|
1331
|
+
const stat8 = await context.fs.stat(targetPath);
|
|
1332
|
+
const currentMode = typeof stat8.mode === "number" ? stat8.mode & 511 : null;
|
|
1333
1333
|
if (currentMode === mutation.mode) {
|
|
1334
1334
|
return {
|
|
1335
1335
|
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
@@ -1740,38 +1740,38 @@ import { createTwoFilesPatch } from "diff";
|
|
|
1740
1740
|
import chalk from "chalk";
|
|
1741
1741
|
function createDryRunFileSystem(base, recorder) {
|
|
1742
1742
|
const proxy = {
|
|
1743
|
-
async readFile(
|
|
1743
|
+
async readFile(path26, encoding) {
|
|
1744
1744
|
if (encoding) {
|
|
1745
|
-
return base.readFile(
|
|
1745
|
+
return base.readFile(path26, encoding);
|
|
1746
1746
|
}
|
|
1747
|
-
return base.readFile(
|
|
1747
|
+
return base.readFile(path26);
|
|
1748
1748
|
},
|
|
1749
|
-
async writeFile(
|
|
1750
|
-
const previousContent = await tryReadText(base,
|
|
1749
|
+
async writeFile(path26, data, options) {
|
|
1750
|
+
const previousContent = await tryReadText(base, path26);
|
|
1751
1751
|
const nextContent = formatData(data, options?.encoding);
|
|
1752
1752
|
recorder.record({
|
|
1753
1753
|
type: "writeFile",
|
|
1754
|
-
path:
|
|
1754
|
+
path: path26,
|
|
1755
1755
|
nextContent,
|
|
1756
1756
|
previousContent
|
|
1757
1757
|
});
|
|
1758
1758
|
},
|
|
1759
|
-
async mkdir(
|
|
1760
|
-
recorder.record({ type: "mkdir", path:
|
|
1759
|
+
async mkdir(path26, options) {
|
|
1760
|
+
recorder.record({ type: "mkdir", path: path26, options });
|
|
1761
1761
|
},
|
|
1762
|
-
async stat(
|
|
1763
|
-
return base.stat(
|
|
1762
|
+
async stat(path26) {
|
|
1763
|
+
return base.stat(path26);
|
|
1764
1764
|
},
|
|
1765
|
-
async unlink(
|
|
1766
|
-
recorder.record({ type: "unlink", path:
|
|
1765
|
+
async unlink(path26) {
|
|
1766
|
+
recorder.record({ type: "unlink", path: path26 });
|
|
1767
1767
|
},
|
|
1768
|
-
async readdir(
|
|
1769
|
-
return base.readdir(
|
|
1768
|
+
async readdir(path26) {
|
|
1769
|
+
return base.readdir(path26);
|
|
1770
1770
|
}
|
|
1771
1771
|
};
|
|
1772
1772
|
if (typeof base.rm === "function") {
|
|
1773
|
-
proxy.rm = async (
|
|
1774
|
-
recorder.record({ type: "rm", path:
|
|
1773
|
+
proxy.rm = async (path26, options) => {
|
|
1774
|
+
recorder.record({ type: "rm", path: path26, options });
|
|
1775
1775
|
};
|
|
1776
1776
|
}
|
|
1777
1777
|
if (typeof base.copyFile === "function") {
|
|
@@ -1861,8 +1861,8 @@ function describeWriteChange(previous, next) {
|
|
|
1861
1861
|
}
|
|
1862
1862
|
return "update";
|
|
1863
1863
|
}
|
|
1864
|
-
function renderWriteCommand(
|
|
1865
|
-
const command = `cat > ${
|
|
1864
|
+
function renderWriteCommand(path26, change) {
|
|
1865
|
+
const command = `cat > ${path26}`;
|
|
1866
1866
|
if (change === "create") {
|
|
1867
1867
|
return renderOperationCommand(command, chalk.green, "# create");
|
|
1868
1868
|
}
|
|
@@ -2024,9 +2024,9 @@ function redactTomlLine(line) {
|
|
|
2024
2024
|
}
|
|
2025
2025
|
return line;
|
|
2026
2026
|
}
|
|
2027
|
-
async function tryReadText(base,
|
|
2027
|
+
async function tryReadText(base, path26) {
|
|
2028
2028
|
try {
|
|
2029
|
-
return await base.readFile(
|
|
2029
|
+
return await base.readFile(path26, "utf8");
|
|
2030
2030
|
} catch (error2) {
|
|
2031
2031
|
if (isNotFound(error2)) {
|
|
2032
2032
|
return null;
|
|
@@ -3993,21 +3993,21 @@ async function* adaptClaude(lines) {
|
|
|
3993
3993
|
if (blockType !== "tool_result") continue;
|
|
3994
3994
|
const kind = toolKindsById.get(item.tool_use_id);
|
|
3995
3995
|
toolKindsById.delete(item.tool_use_id);
|
|
3996
|
-
let
|
|
3996
|
+
let path26;
|
|
3997
3997
|
if (typeof item.content === "string") {
|
|
3998
|
-
|
|
3998
|
+
path26 = item.content;
|
|
3999
3999
|
} else {
|
|
4000
4000
|
try {
|
|
4001
|
-
|
|
4001
|
+
path26 = JSON.stringify(item.content);
|
|
4002
4002
|
} catch {
|
|
4003
|
-
|
|
4003
|
+
path26 = String(item.content);
|
|
4004
4004
|
}
|
|
4005
4005
|
}
|
|
4006
4006
|
yield {
|
|
4007
4007
|
event: "tool_complete",
|
|
4008
4008
|
id: item.tool_use_id,
|
|
4009
4009
|
kind,
|
|
4010
|
-
path:
|
|
4010
|
+
path: path26
|
|
4011
4011
|
};
|
|
4012
4012
|
}
|
|
4013
4013
|
}
|
|
@@ -4129,10 +4129,10 @@ async function* adaptCodex(lines) {
|
|
|
4129
4129
|
const kindFromStart = toolKindById.get(item.id);
|
|
4130
4130
|
const kind = kindFromStart ?? (itemType === "command_execution" ? "exec" : itemType === "file_edit" ? "edit" : "other");
|
|
4131
4131
|
const titleFromEvent = isNonEmptyString2(item.path) ? item.path : itemType === "mcp_tool_call" ? `${isNonEmptyString2(item.server) ? item.server : "unknown"}.${isNonEmptyString2(item.tool) ? item.tool : "unknown"}` : void 0;
|
|
4132
|
-
const
|
|
4132
|
+
const path26 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
|
|
4133
4133
|
toolTitleById.delete(item.id);
|
|
4134
4134
|
toolKindById.delete(item.id);
|
|
4135
|
-
yield { event: "tool_complete", id: item.id, kind, path:
|
|
4135
|
+
yield { event: "tool_complete", id: item.id, kind, path: path26 };
|
|
4136
4136
|
}
|
|
4137
4137
|
}
|
|
4138
4138
|
}
|
|
@@ -6045,21 +6045,21 @@ function createSdkContainer(options) {
|
|
|
6045
6045
|
});
|
|
6046
6046
|
loggerFactory.setErrorLogger(errorLogger);
|
|
6047
6047
|
const asyncFs = {
|
|
6048
|
-
readFile: ((
|
|
6048
|
+
readFile: ((path26, encoding) => {
|
|
6049
6049
|
if (encoding) {
|
|
6050
|
-
return fs2.readFile(
|
|
6050
|
+
return fs2.readFile(path26, encoding);
|
|
6051
6051
|
}
|
|
6052
|
-
return fs2.readFile(
|
|
6052
|
+
return fs2.readFile(path26);
|
|
6053
6053
|
}),
|
|
6054
|
-
writeFile: (
|
|
6055
|
-
mkdir: (
|
|
6054
|
+
writeFile: (path26, data, opts) => fs2.writeFile(path26, data, opts),
|
|
6055
|
+
mkdir: (path26, opts) => fs2.mkdir(path26, opts).then(() => {
|
|
6056
6056
|
}),
|
|
6057
|
-
stat: (
|
|
6058
|
-
rm: (
|
|
6059
|
-
unlink: (
|
|
6060
|
-
readdir: (
|
|
6057
|
+
stat: (path26) => fs2.stat(path26),
|
|
6058
|
+
rm: (path26, opts) => fs2.rm(path26, opts),
|
|
6059
|
+
unlink: (path26) => fs2.unlink(path26),
|
|
6060
|
+
readdir: (path26) => fs2.readdir(path26),
|
|
6061
6061
|
copyFile: (src, dest) => fs2.copyFile(src, dest),
|
|
6062
|
-
chmod: (
|
|
6062
|
+
chmod: (path26, mode) => fs2.chmod(path26, mode)
|
|
6063
6063
|
};
|
|
6064
6064
|
const contextFactory = createCommandContextFactory({ fs: asyncFs });
|
|
6065
6065
|
const authFs = {
|
|
@@ -6763,8 +6763,8 @@ function resourceNotFound(resource) {
|
|
|
6763
6763
|
`Resource not found: ${resource}`
|
|
6764
6764
|
);
|
|
6765
6765
|
}
|
|
6766
|
-
function assertAbsolutePath(
|
|
6767
|
-
if (!isAbsolute(
|
|
6766
|
+
function assertAbsolutePath(path26) {
|
|
6767
|
+
if (!isAbsolute(path26)) {
|
|
6768
6768
|
throw invalidParams('"path" must be an absolute path');
|
|
6769
6769
|
}
|
|
6770
6770
|
}
|
|
@@ -14082,8 +14082,8 @@ var init_parseUtil = __esm({
|
|
|
14082
14082
|
init_errors2();
|
|
14083
14083
|
init_en();
|
|
14084
14084
|
makeIssue = (params) => {
|
|
14085
|
-
const { data, path:
|
|
14086
|
-
const fullPath = [...
|
|
14085
|
+
const { data, path: path26, errorMaps, issueData } = params;
|
|
14086
|
+
const fullPath = [...path26, ...issueData.path || []];
|
|
14087
14087
|
const fullIssue = {
|
|
14088
14088
|
...issueData,
|
|
14089
14089
|
path: fullPath
|
|
@@ -14363,11 +14363,11 @@ var init_types4 = __esm({
|
|
|
14363
14363
|
init_parseUtil();
|
|
14364
14364
|
init_util();
|
|
14365
14365
|
ParseInputLazyPath = class {
|
|
14366
|
-
constructor(parent, value,
|
|
14366
|
+
constructor(parent, value, path26, key) {
|
|
14367
14367
|
this._cachedPath = [];
|
|
14368
14368
|
this.parent = parent;
|
|
14369
14369
|
this.data = value;
|
|
14370
|
-
this._path =
|
|
14370
|
+
this._path = path26;
|
|
14371
14371
|
this._key = key;
|
|
14372
14372
|
}
|
|
14373
14373
|
get path() {
|
|
@@ -17871,10 +17871,10 @@ function mergeDefs(...defs) {
|
|
|
17871
17871
|
function cloneDef(schema) {
|
|
17872
17872
|
return mergeDefs(schema._zod.def);
|
|
17873
17873
|
}
|
|
17874
|
-
function getElementAtPath(obj,
|
|
17875
|
-
if (!
|
|
17874
|
+
function getElementAtPath(obj, path26) {
|
|
17875
|
+
if (!path26)
|
|
17876
17876
|
return obj;
|
|
17877
|
-
return
|
|
17877
|
+
return path26.reduce((acc, key) => acc?.[key], obj);
|
|
17878
17878
|
}
|
|
17879
17879
|
function promiseAllObject(promisesObj) {
|
|
17880
17880
|
const keys = Object.keys(promisesObj);
|
|
@@ -18186,11 +18186,11 @@ function aborted(x, startIndex = 0) {
|
|
|
18186
18186
|
}
|
|
18187
18187
|
return false;
|
|
18188
18188
|
}
|
|
18189
|
-
function prefixIssues(
|
|
18189
|
+
function prefixIssues(path26, issues) {
|
|
18190
18190
|
return issues.map((iss) => {
|
|
18191
18191
|
var _a2;
|
|
18192
18192
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
18193
|
-
iss.path.unshift(
|
|
18193
|
+
iss.path.unshift(path26);
|
|
18194
18194
|
return iss;
|
|
18195
18195
|
});
|
|
18196
18196
|
}
|
|
@@ -27244,7 +27244,7 @@ var require_code = __commonJS({
|
|
|
27244
27244
|
else if (arg instanceof Name)
|
|
27245
27245
|
code.push(arg);
|
|
27246
27246
|
else
|
|
27247
|
-
code.push(
|
|
27247
|
+
code.push(interpolate2(arg));
|
|
27248
27248
|
}
|
|
27249
27249
|
exports.addCodeArg = addCodeArg;
|
|
27250
27250
|
function optimize(expr) {
|
|
@@ -27283,7 +27283,7 @@ var require_code = __commonJS({
|
|
|
27283
27283
|
return c2.emptyStr() ? c1 : c1.emptyStr() ? c2 : str`${c1}${c2}`;
|
|
27284
27284
|
}
|
|
27285
27285
|
exports.strConcat = strConcat;
|
|
27286
|
-
function
|
|
27286
|
+
function interpolate2(x) {
|
|
27287
27287
|
return typeof x == "number" || typeof x == "boolean" || x === null ? x : safeStringify2(Array.isArray(x) ? x.join(",") : x);
|
|
27288
27288
|
}
|
|
27289
27289
|
function stringify3(x) {
|
|
@@ -30351,8 +30351,8 @@ var require_utils = __commonJS({
|
|
|
30351
30351
|
}
|
|
30352
30352
|
return ind;
|
|
30353
30353
|
}
|
|
30354
|
-
function removeDotSegments(
|
|
30355
|
-
let input =
|
|
30354
|
+
function removeDotSegments(path26) {
|
|
30355
|
+
let input = path26;
|
|
30356
30356
|
const output = [];
|
|
30357
30357
|
let nextSlash = -1;
|
|
30358
30358
|
let len = 0;
|
|
@@ -30551,8 +30551,8 @@ var require_schemes = __commonJS({
|
|
|
30551
30551
|
wsComponent.secure = void 0;
|
|
30552
30552
|
}
|
|
30553
30553
|
if (wsComponent.resourceName) {
|
|
30554
|
-
const [
|
|
30555
|
-
wsComponent.path =
|
|
30554
|
+
const [path26, query] = wsComponent.resourceName.split("?");
|
|
30555
|
+
wsComponent.path = path26 && path26 !== "/" ? path26 : void 0;
|
|
30556
30556
|
wsComponent.query = query;
|
|
30557
30557
|
wsComponent.resourceName = void 0;
|
|
30558
30558
|
}
|
|
@@ -30704,24 +30704,24 @@ var require_fast_uri = __commonJS({
|
|
|
30704
30704
|
function normalize(uri, options) {
|
|
30705
30705
|
if (typeof uri === "string") {
|
|
30706
30706
|
uri = /** @type {T} */
|
|
30707
|
-
serialize3(
|
|
30707
|
+
serialize3(parse10(uri, options), options);
|
|
30708
30708
|
} else if (typeof uri === "object") {
|
|
30709
30709
|
uri = /** @type {T} */
|
|
30710
|
-
|
|
30710
|
+
parse10(serialize3(uri, options), options);
|
|
30711
30711
|
}
|
|
30712
30712
|
return uri;
|
|
30713
30713
|
}
|
|
30714
30714
|
function resolve(baseURI, relativeURI, options) {
|
|
30715
30715
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
30716
|
-
const resolved = resolveComponent(
|
|
30716
|
+
const resolved = resolveComponent(parse10(baseURI, schemelessOptions), parse10(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
30717
30717
|
schemelessOptions.skipEscape = true;
|
|
30718
30718
|
return serialize3(resolved, schemelessOptions);
|
|
30719
30719
|
}
|
|
30720
30720
|
function resolveComponent(base, relative, options, skipNormalization) {
|
|
30721
30721
|
const target = {};
|
|
30722
30722
|
if (!skipNormalization) {
|
|
30723
|
-
base =
|
|
30724
|
-
relative =
|
|
30723
|
+
base = parse10(serialize3(base, options), options);
|
|
30724
|
+
relative = parse10(serialize3(relative, options), options);
|
|
30725
30725
|
}
|
|
30726
30726
|
options = options || {};
|
|
30727
30727
|
if (!options.tolerant && relative.scheme) {
|
|
@@ -30773,13 +30773,13 @@ var require_fast_uri = __commonJS({
|
|
|
30773
30773
|
function equal(uriA, uriB, options) {
|
|
30774
30774
|
if (typeof uriA === "string") {
|
|
30775
30775
|
uriA = unescape(uriA);
|
|
30776
|
-
uriA = serialize3(normalizeComponentEncoding(
|
|
30776
|
+
uriA = serialize3(normalizeComponentEncoding(parse10(uriA, options), true), { ...options, skipEscape: true });
|
|
30777
30777
|
} else if (typeof uriA === "object") {
|
|
30778
30778
|
uriA = serialize3(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true });
|
|
30779
30779
|
}
|
|
30780
30780
|
if (typeof uriB === "string") {
|
|
30781
30781
|
uriB = unescape(uriB);
|
|
30782
|
-
uriB = serialize3(normalizeComponentEncoding(
|
|
30782
|
+
uriB = serialize3(normalizeComponentEncoding(parse10(uriB, options), true), { ...options, skipEscape: true });
|
|
30783
30783
|
} else if (typeof uriB === "object") {
|
|
30784
30784
|
uriB = serialize3(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true });
|
|
30785
30785
|
}
|
|
@@ -30848,7 +30848,7 @@ var require_fast_uri = __commonJS({
|
|
|
30848
30848
|
return uriTokens.join("");
|
|
30849
30849
|
}
|
|
30850
30850
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
30851
|
-
function
|
|
30851
|
+
function parse10(uri, opts) {
|
|
30852
30852
|
const options = Object.assign({}, opts);
|
|
30853
30853
|
const parsed = {
|
|
30854
30854
|
scheme: void 0,
|
|
@@ -30942,7 +30942,7 @@ var require_fast_uri = __commonJS({
|
|
|
30942
30942
|
resolveComponent,
|
|
30943
30943
|
equal,
|
|
30944
30944
|
serialize: serialize3,
|
|
30945
|
-
parse:
|
|
30945
|
+
parse: parse10
|
|
30946
30946
|
};
|
|
30947
30947
|
module.exports = fastUri;
|
|
30948
30948
|
module.exports.default = fastUri;
|
|
@@ -35311,8 +35311,8 @@ function backoff(attempt, min, max) {
|
|
|
35311
35311
|
}
|
|
35312
35312
|
async function tryRemoveStale(lockPath, staleMs, fs3) {
|
|
35313
35313
|
try {
|
|
35314
|
-
const
|
|
35315
|
-
if (Date.now() -
|
|
35314
|
+
const stat8 = await fs3.stat(lockPath);
|
|
35315
|
+
if (Date.now() - stat8.mtimeMs > staleMs) {
|
|
35316
35316
|
await fs3.rmdir(lockPath);
|
|
35317
35317
|
return true;
|
|
35318
35318
|
}
|
|
@@ -35586,13 +35586,13 @@ function getDirtyFiles(cwd) {
|
|
|
35586
35586
|
for (const line of lines) {
|
|
35587
35587
|
if (!line) continue;
|
|
35588
35588
|
if (line.length < 4) continue;
|
|
35589
|
-
let
|
|
35589
|
+
let path26 = line.slice(3).trim();
|
|
35590
35590
|
const renameArrow = " -> ";
|
|
35591
|
-
const arrowIndex =
|
|
35591
|
+
const arrowIndex = path26.lastIndexOf(renameArrow);
|
|
35592
35592
|
if (arrowIndex >= 0) {
|
|
35593
|
-
|
|
35593
|
+
path26 = path26.slice(arrowIndex + renameArrow.length).trim();
|
|
35594
35594
|
}
|
|
35595
|
-
if (
|
|
35595
|
+
if (path26) files.push(path26);
|
|
35596
35596
|
}
|
|
35597
35597
|
return files;
|
|
35598
35598
|
}
|
|
@@ -35873,17 +35873,17 @@ function serializePlan(prd) {
|
|
|
35873
35873
|
return yaml.endsWith("\n") ? yaml : `${yaml}
|
|
35874
35874
|
`;
|
|
35875
35875
|
}
|
|
35876
|
-
function lockPlanFile(
|
|
35877
|
-
return lockFile(
|
|
35876
|
+
function lockPlanFile(path26) {
|
|
35877
|
+
return lockFile(path26, { retries: 20, minTimeout: 25, maxTimeout: 250 });
|
|
35878
35878
|
}
|
|
35879
|
-
async function writePlan(
|
|
35879
|
+
async function writePlan(path26, prd, options = {}) {
|
|
35880
35880
|
const fs3 = options.fs ?? fsPromises4;
|
|
35881
35881
|
const lock = options.lock ?? lockPlanFile;
|
|
35882
|
-
await fs3.mkdir(dirname3(
|
|
35883
|
-
const release = await lock(
|
|
35882
|
+
await fs3.mkdir(dirname3(path26), { recursive: true });
|
|
35883
|
+
const release = await lock(path26);
|
|
35884
35884
|
try {
|
|
35885
35885
|
const yaml = serializePlan(prd);
|
|
35886
|
-
await fs3.writeFile(
|
|
35886
|
+
await fs3.writeFile(path26, yaml, { encoding: "utf8" });
|
|
35887
35887
|
} finally {
|
|
35888
35888
|
await release();
|
|
35889
35889
|
}
|
|
@@ -35996,8 +35996,8 @@ var init_selector = __esm({
|
|
|
35996
35996
|
// packages/ralph/src/story/updater.ts
|
|
35997
35997
|
import { dirname as dirname4 } from "node:path";
|
|
35998
35998
|
import * as fsPromises5 from "node:fs/promises";
|
|
35999
|
-
function lockPlanFile2(
|
|
36000
|
-
return lockFile(
|
|
35999
|
+
function lockPlanFile2(path26) {
|
|
36000
|
+
return lockFile(path26, { retries: 20, minTimeout: 25, maxTimeout: 250 });
|
|
36001
36001
|
}
|
|
36002
36002
|
function assertStoryStatus(value) {
|
|
36003
36003
|
if (value === "open") return;
|
|
@@ -36072,8 +36072,8 @@ var init_selector2 = __esm({
|
|
|
36072
36072
|
// packages/ralph/src/requirement/updater.ts
|
|
36073
36073
|
import { dirname as dirname5 } from "node:path";
|
|
36074
36074
|
import * as fsPromises6 from "node:fs/promises";
|
|
36075
|
-
function lockPlanFile3(
|
|
36076
|
-
return lockFile(
|
|
36075
|
+
function lockPlanFile3(path26) {
|
|
36076
|
+
return lockFile(path26, { retries: 20, minTimeout: 25, maxTimeout: 250 });
|
|
36077
36077
|
}
|
|
36078
36078
|
function findRequirement(plan, requirementId) {
|
|
36079
36079
|
const req = plan.requirements.find((r) => r.id === requirementId);
|
|
@@ -36136,9 +36136,9 @@ function appendSection(lines, title, items, options) {
|
|
|
36136
36136
|
}
|
|
36137
36137
|
lines.push("");
|
|
36138
36138
|
}
|
|
36139
|
-
async function writeRunMeta(
|
|
36139
|
+
async function writeRunMeta(path26, metadata, options = {}) {
|
|
36140
36140
|
const fs3 = options.fs ?? fsPromises7;
|
|
36141
|
-
await fs3.mkdir(dirname6(
|
|
36141
|
+
await fs3.mkdir(dirname6(path26), { recursive: true });
|
|
36142
36142
|
const lines = [];
|
|
36143
36143
|
lines.push("# Ralph Run Summary", "");
|
|
36144
36144
|
lines.push(`- Run ID: ${metadata.runId}`);
|
|
@@ -36167,7 +36167,7 @@ async function writeRunMeta(path22, metadata, options = {}) {
|
|
|
36167
36167
|
const git = metadata.git ?? null;
|
|
36168
36168
|
if (!git) {
|
|
36169
36169
|
lines.push("");
|
|
36170
|
-
await fs3.writeFile(
|
|
36170
|
+
await fs3.writeFile(path26, lines.join("\n"), { encoding: "utf8" });
|
|
36171
36171
|
return;
|
|
36172
36172
|
}
|
|
36173
36173
|
lines.push("", "## Git");
|
|
@@ -36182,7 +36182,7 @@ async function writeRunMeta(path22, metadata, options = {}) {
|
|
|
36182
36182
|
lines.push("");
|
|
36183
36183
|
} else {
|
|
36184
36184
|
lines.push("");
|
|
36185
|
-
await fs3.writeFile(
|
|
36185
|
+
await fs3.writeFile(path26, lines.join("\n"), { encoding: "utf8" });
|
|
36186
36186
|
return;
|
|
36187
36187
|
}
|
|
36188
36188
|
if (git.commits !== void 0 && git.commits !== null) {
|
|
@@ -36202,7 +36202,7 @@ async function writeRunMeta(path22, metadata, options = {}) {
|
|
|
36202
36202
|
appendSection(lines, "### Uncommitted Changes", git.dirtyFiles, {
|
|
36203
36203
|
emptyLabel: "(none)"
|
|
36204
36204
|
});
|
|
36205
|
-
await fs3.writeFile(
|
|
36205
|
+
await fs3.writeFile(path26, lines.join("\n"), { encoding: "utf8" });
|
|
36206
36206
|
}
|
|
36207
36207
|
var init_metadata = __esm({
|
|
36208
36208
|
"packages/ralph/src/run/metadata.ts"() {
|
|
@@ -36290,9 +36290,9 @@ async function defaultStreamingSpawn(agentId, options) {
|
|
|
36290
36290
|
exitCode: result.exitCode
|
|
36291
36291
|
};
|
|
36292
36292
|
}
|
|
36293
|
-
function absPath(cwd,
|
|
36294
|
-
if (!
|
|
36295
|
-
return
|
|
36293
|
+
function absPath(cwd, path26) {
|
|
36294
|
+
if (!path26) return resolvePath4(cwd);
|
|
36295
|
+
return path26.startsWith("/") ? path26 : resolvePath4(cwd, path26);
|
|
36296
36296
|
}
|
|
36297
36297
|
function pad2(value) {
|
|
36298
36298
|
return value < 10 ? `0${value}` : String(value);
|
|
@@ -36342,8 +36342,8 @@ async function appendToErrorsLog(fs3, errorsLogPath, message) {
|
|
|
36342
36342
|
await fs3.mkdir(dirname7(errorsLogPath), { recursive: true });
|
|
36343
36343
|
await fs3.writeFile(errorsLogPath, `${previous}${next}`, { encoding: "utf8" });
|
|
36344
36344
|
}
|
|
36345
|
-
function lockPlanFile4(
|
|
36346
|
-
return lockFile(
|
|
36345
|
+
function lockPlanFile4(path26) {
|
|
36346
|
+
return lockFile(path26, { retries: 20, minTimeout: 25, maxTimeout: 250 });
|
|
36347
36347
|
}
|
|
36348
36348
|
function getCurrentBranch(cwd) {
|
|
36349
36349
|
try {
|
|
@@ -36534,7 +36534,7 @@ async function buildLoop(options) {
|
|
|
36534
36534
|
});
|
|
36535
36535
|
worktreeBranch = entry.branch;
|
|
36536
36536
|
const worktreePath = entry.path;
|
|
36537
|
-
const symlinkFn = fs3.symlink ?? ((target,
|
|
36537
|
+
const symlinkFn = fs3.symlink ?? ((target, path26) => fsPromises8.symlink(target, path26));
|
|
36538
36538
|
const exec3 = worktreeDeps.exec;
|
|
36539
36539
|
const dirsToLink = [".poe-code-ralph", ".agents/poe-code-ralph"];
|
|
36540
36540
|
for (const dir of dirsToLink) {
|
|
@@ -37235,27 +37235,27 @@ function formatTimestamp3(date4) {
|
|
|
37235
37235
|
const seconds = pad22(date4.getSeconds());
|
|
37236
37236
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
37237
37237
|
}
|
|
37238
|
-
function validateLogPath(
|
|
37239
|
-
if (typeof
|
|
37238
|
+
function validateLogPath(path26) {
|
|
37239
|
+
if (typeof path26 !== "string" || path26.trim().length === 0) {
|
|
37240
37240
|
throw new Error(
|
|
37241
|
-
`Invalid activity log path: expected a non-empty string, got ${String(
|
|
37241
|
+
`Invalid activity log path: expected a non-empty string, got ${String(path26)}`
|
|
37242
37242
|
);
|
|
37243
37243
|
}
|
|
37244
|
-
if (
|
|
37244
|
+
if (path26.includes("\0")) {
|
|
37245
37245
|
throw new Error("Invalid activity log path: contains null byte");
|
|
37246
37246
|
}
|
|
37247
37247
|
}
|
|
37248
|
-
async function logActivity(
|
|
37249
|
-
validateLogPath(
|
|
37248
|
+
async function logActivity(path26, message, options = {}) {
|
|
37249
|
+
validateLogPath(path26);
|
|
37250
37250
|
const fs3 = options.fs ?? fsPromises11;
|
|
37251
|
-
const parent = dirname8(
|
|
37251
|
+
const parent = dirname8(path26);
|
|
37252
37252
|
if (parent && parent !== ".") {
|
|
37253
37253
|
await fs3.mkdir(parent, { recursive: true });
|
|
37254
37254
|
}
|
|
37255
37255
|
const entry = `[${formatTimestamp3(/* @__PURE__ */ new Date())}] ${message}
|
|
37256
37256
|
`;
|
|
37257
37257
|
try {
|
|
37258
|
-
await fs3.appendFile(
|
|
37258
|
+
await fs3.appendFile(path26, entry, { encoding: "utf8" });
|
|
37259
37259
|
} catch (error2) {
|
|
37260
37260
|
const detail = error2 instanceof Error ? error2.message : `Unknown error: ${String(error2)}`;
|
|
37261
37261
|
throw new Error(`Failed to append activity log entry: ${detail}`, { cause: error2 });
|
|
@@ -38583,13 +38583,1137 @@ var init_models = __esm({
|
|
|
38583
38583
|
}
|
|
38584
38584
|
});
|
|
38585
38585
|
|
|
38586
|
+
// packages/pipeline/src/utils.ts
|
|
38587
|
+
function isRecord6(value) {
|
|
38588
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
38589
|
+
}
|
|
38590
|
+
function isNotFound2(error2) {
|
|
38591
|
+
return !!error2 && typeof error2 === "object" && "code" in error2 && error2.code === "ENOENT";
|
|
38592
|
+
}
|
|
38593
|
+
async function readOptionalFile(fs3, filePath) {
|
|
38594
|
+
try {
|
|
38595
|
+
return await fs3.readFile(filePath, "utf8");
|
|
38596
|
+
} catch (error2) {
|
|
38597
|
+
if (isNotFound2(error2)) {
|
|
38598
|
+
return null;
|
|
38599
|
+
}
|
|
38600
|
+
throw error2;
|
|
38601
|
+
}
|
|
38602
|
+
}
|
|
38603
|
+
function assertNotAborted(signal) {
|
|
38604
|
+
if (!signal?.aborted) {
|
|
38605
|
+
return;
|
|
38606
|
+
}
|
|
38607
|
+
throw createAbortError();
|
|
38608
|
+
}
|
|
38609
|
+
function createAbortError() {
|
|
38610
|
+
const error2 = new Error("Pipeline run cancelled");
|
|
38611
|
+
error2.name = "AbortError";
|
|
38612
|
+
return error2;
|
|
38613
|
+
}
|
|
38614
|
+
var init_utils3 = __esm({
|
|
38615
|
+
"packages/pipeline/src/utils.ts"() {
|
|
38616
|
+
"use strict";
|
|
38617
|
+
}
|
|
38618
|
+
});
|
|
38619
|
+
|
|
38620
|
+
// packages/pipeline/src/config/loader.ts
|
|
38621
|
+
import path22 from "node:path";
|
|
38622
|
+
import { parse as parse8 } from "yaml";
|
|
38623
|
+
function asStepMode(value) {
|
|
38624
|
+
if (value === void 0 || value === null) {
|
|
38625
|
+
return "yolo";
|
|
38626
|
+
}
|
|
38627
|
+
if (value === "yolo" || value === "edit" || value === "read") {
|
|
38628
|
+
return value;
|
|
38629
|
+
}
|
|
38630
|
+
throw new Error(`Invalid step mode "${String(value)}". Expected "yolo", "edit", or "read".`);
|
|
38631
|
+
}
|
|
38632
|
+
function parseYamlDocument(filePath, content) {
|
|
38633
|
+
try {
|
|
38634
|
+
return parse8(content);
|
|
38635
|
+
} catch (error2) {
|
|
38636
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
38637
|
+
throw new Error(`Invalid pipeline step config YAML in "${filePath}": ${message}`);
|
|
38638
|
+
}
|
|
38639
|
+
}
|
|
38640
|
+
function parseStepConfigDocument(filePath, content) {
|
|
38641
|
+
const document = parseYamlDocument(filePath, content);
|
|
38642
|
+
if (!isRecord6(document)) {
|
|
38643
|
+
throw new Error(`Invalid pipeline step config in "${filePath}": expected a top-level object.`);
|
|
38644
|
+
}
|
|
38645
|
+
const stepsValue = document.steps;
|
|
38646
|
+
if (stepsValue === void 0 || stepsValue === null) {
|
|
38647
|
+
return {};
|
|
38648
|
+
}
|
|
38649
|
+
if (!isRecord6(stepsValue)) {
|
|
38650
|
+
throw new Error(`Invalid pipeline step config in "${filePath}": "steps" must be an object.`);
|
|
38651
|
+
}
|
|
38652
|
+
const steps = {};
|
|
38653
|
+
for (const [stepName, value] of Object.entries(stepsValue)) {
|
|
38654
|
+
if (!isRecord6(value)) {
|
|
38655
|
+
throw new Error(`Invalid step "${stepName}" in "${filePath}": expected an object.`);
|
|
38656
|
+
}
|
|
38657
|
+
const instruction = value.instruction;
|
|
38658
|
+
if (typeof instruction !== "string" || instruction.length === 0) {
|
|
38659
|
+
throw new Error(`Missing instruction for step "${stepName}" in "${filePath}".`);
|
|
38660
|
+
}
|
|
38661
|
+
const step = {
|
|
38662
|
+
mode: asStepMode(value.mode),
|
|
38663
|
+
instruction
|
|
38664
|
+
};
|
|
38665
|
+
steps[stepName] = step;
|
|
38666
|
+
}
|
|
38667
|
+
return steps;
|
|
38668
|
+
}
|
|
38669
|
+
function parseConfigDocument2(filePath, content) {
|
|
38670
|
+
const document = parseYamlDocument(filePath, content);
|
|
38671
|
+
if (document === null || document === void 0) {
|
|
38672
|
+
return {};
|
|
38673
|
+
}
|
|
38674
|
+
if (!isRecord6(document)) {
|
|
38675
|
+
throw new Error(`Invalid pipeline config in "${filePath}": expected a top-level object.`);
|
|
38676
|
+
}
|
|
38677
|
+
const planPath = document.planPath;
|
|
38678
|
+
if (planPath !== void 0 && typeof planPath !== "string") {
|
|
38679
|
+
throw new Error(`Invalid planPath in "${filePath}": expected a string.`);
|
|
38680
|
+
}
|
|
38681
|
+
return {
|
|
38682
|
+
...typeof planPath === "string" && planPath.trim().length > 0 ? { planPath: planPath.trim() } : {}
|
|
38683
|
+
};
|
|
38684
|
+
}
|
|
38685
|
+
async function loadConfigFile(fs3, filePath) {
|
|
38686
|
+
const content = await readOptionalFile(fs3, filePath);
|
|
38687
|
+
if (content == null) {
|
|
38688
|
+
return {};
|
|
38689
|
+
}
|
|
38690
|
+
return parseConfigDocument2(filePath, content);
|
|
38691
|
+
}
|
|
38692
|
+
async function loadStepsFile(fs3, filePath) {
|
|
38693
|
+
const content = await readOptionalFile(fs3, filePath);
|
|
38694
|
+
if (content == null) {
|
|
38695
|
+
return {};
|
|
38696
|
+
}
|
|
38697
|
+
return parseStepConfigDocument(filePath, content);
|
|
38698
|
+
}
|
|
38699
|
+
async function loadPipelineConfig(options) {
|
|
38700
|
+
const globalPath = path22.join(options.homeDir, ".poe-code", "pipeline", "config.yaml");
|
|
38701
|
+
const projectPath = path22.join(options.cwd, ".poe-code", "pipeline", "config.yaml");
|
|
38702
|
+
const [globalConfig2, projectConfig] = await Promise.all([
|
|
38703
|
+
loadConfigFile(options.fs, globalPath),
|
|
38704
|
+
loadConfigFile(options.fs, projectPath)
|
|
38705
|
+
]);
|
|
38706
|
+
return {
|
|
38707
|
+
...globalConfig2,
|
|
38708
|
+
...projectConfig
|
|
38709
|
+
};
|
|
38710
|
+
}
|
|
38711
|
+
async function loadResolvedSteps(options) {
|
|
38712
|
+
const globalPath = path22.join(options.homeDir, ".poe-code", "pipeline", "steps.yaml");
|
|
38713
|
+
const projectPath = path22.join(options.cwd, ".poe-code", "pipeline", "steps.yaml");
|
|
38714
|
+
const [globalSteps, projectSteps] = await Promise.all([
|
|
38715
|
+
loadStepsFile(options.fs, globalPath),
|
|
38716
|
+
loadStepsFile(options.fs, projectPath)
|
|
38717
|
+
]);
|
|
38718
|
+
return {
|
|
38719
|
+
...globalSteps,
|
|
38720
|
+
...projectSteps
|
|
38721
|
+
};
|
|
38722
|
+
}
|
|
38723
|
+
var init_loader2 = __esm({
|
|
38724
|
+
"packages/pipeline/src/config/loader.ts"() {
|
|
38725
|
+
"use strict";
|
|
38726
|
+
init_utils3();
|
|
38727
|
+
}
|
|
38728
|
+
});
|
|
38729
|
+
|
|
38730
|
+
// packages/pipeline/src/plan/parser.ts
|
|
38731
|
+
import { parse as parse9 } from "yaml";
|
|
38732
|
+
function asRequiredString2(value, field) {
|
|
38733
|
+
if (typeof value === "string" && value.length > 0) {
|
|
38734
|
+
return value;
|
|
38735
|
+
}
|
|
38736
|
+
throw new Error(`Missing ${field}`);
|
|
38737
|
+
}
|
|
38738
|
+
function normalizeStatus2(value, field) {
|
|
38739
|
+
if (typeof value !== "string") {
|
|
38740
|
+
throw new Error(`Invalid ${field}: expected "open", "done", or "failed".`);
|
|
38741
|
+
}
|
|
38742
|
+
const normalized = value.trim().toLowerCase();
|
|
38743
|
+
if (normalized === "open" || normalized === "done" || normalized === "failed") {
|
|
38744
|
+
return normalized;
|
|
38745
|
+
}
|
|
38746
|
+
throw new Error(`Invalid ${field} "${value}". Expected "open", "done", or "failed".`);
|
|
38747
|
+
}
|
|
38748
|
+
function parseTaskStatus(value, availableSteps, taskId) {
|
|
38749
|
+
if (typeof value === "string") {
|
|
38750
|
+
return normalizeStatus2(value, "task status");
|
|
38751
|
+
}
|
|
38752
|
+
if (!isRecord6(value)) {
|
|
38753
|
+
throw new Error(`Invalid status for task "${taskId}": expected a string or step-status map.`);
|
|
38754
|
+
}
|
|
38755
|
+
const statusMap = {};
|
|
38756
|
+
for (const [stepName, stepStatus] of Object.entries(value)) {
|
|
38757
|
+
if (availableSteps && !(stepName in availableSteps)) {
|
|
38758
|
+
throw new Error(`Unknown step "${stepName}" referenced by task "${taskId}".`);
|
|
38759
|
+
}
|
|
38760
|
+
statusMap[stepName] = normalizeStatus2(stepStatus, `step status for "${stepName}"`);
|
|
38761
|
+
}
|
|
38762
|
+
return statusMap;
|
|
38763
|
+
}
|
|
38764
|
+
function parsePlan2(yamlContent, options = {}) {
|
|
38765
|
+
let document;
|
|
38766
|
+
try {
|
|
38767
|
+
document = parse9(yamlContent);
|
|
38768
|
+
} catch (error2) {
|
|
38769
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
38770
|
+
throw new Error(`Invalid plan YAML: ${message}`);
|
|
38771
|
+
}
|
|
38772
|
+
if (!isRecord6(document)) {
|
|
38773
|
+
throw new Error("Invalid plan YAML: expected a top-level object.");
|
|
38774
|
+
}
|
|
38775
|
+
const tasksValue = document.tasks;
|
|
38776
|
+
if (!Array.isArray(tasksValue)) {
|
|
38777
|
+
throw new Error('Invalid plan YAML: expected "tasks" to be an array.');
|
|
38778
|
+
}
|
|
38779
|
+
const ids = /* @__PURE__ */ new Set();
|
|
38780
|
+
const tasks = tasksValue.map((value, index) => {
|
|
38781
|
+
if (!isRecord6(value)) {
|
|
38782
|
+
throw new Error(`Invalid tasks[${index}]: expected an object.`);
|
|
38783
|
+
}
|
|
38784
|
+
const id = asRequiredString2(value.id, `tasks[${index}].id`);
|
|
38785
|
+
if (ids.has(id)) {
|
|
38786
|
+
throw new Error(`Duplicate task id "${id}".`);
|
|
38787
|
+
}
|
|
38788
|
+
ids.add(id);
|
|
38789
|
+
return {
|
|
38790
|
+
id,
|
|
38791
|
+
title: asRequiredString2(value.title, `tasks[${index}].title`),
|
|
38792
|
+
prompt: asRequiredString2(value.prompt, `tasks[${index}].prompt`),
|
|
38793
|
+
status: parseTaskStatus(value.status, options.availableSteps, id)
|
|
38794
|
+
};
|
|
38795
|
+
});
|
|
38796
|
+
return { tasks };
|
|
38797
|
+
}
|
|
38798
|
+
var init_parser2 = __esm({
|
|
38799
|
+
"packages/pipeline/src/plan/parser.ts"() {
|
|
38800
|
+
"use strict";
|
|
38801
|
+
init_utils3();
|
|
38802
|
+
}
|
|
38803
|
+
});
|
|
38804
|
+
|
|
38805
|
+
// packages/pipeline/src/plan/discovery.ts
|
|
38806
|
+
import path23 from "node:path";
|
|
38807
|
+
import * as fsPromises13 from "node:fs/promises";
|
|
38808
|
+
function createDefaultFs() {
|
|
38809
|
+
return {
|
|
38810
|
+
readFile: fsPromises13.readFile,
|
|
38811
|
+
readdir: fsPromises13.readdir,
|
|
38812
|
+
stat: async (filePath) => {
|
|
38813
|
+
const stat8 = await fsPromises13.stat(filePath);
|
|
38814
|
+
return {
|
|
38815
|
+
isFile: () => stat8.isFile(),
|
|
38816
|
+
isDirectory: () => stat8.isDirectory(),
|
|
38817
|
+
mtimeMs: stat8.mtimeMs
|
|
38818
|
+
};
|
|
38819
|
+
}
|
|
38820
|
+
};
|
|
38821
|
+
}
|
|
38822
|
+
function isPlanCandidateFile2(name) {
|
|
38823
|
+
const lower = name.toLowerCase();
|
|
38824
|
+
return lower.startsWith("plan") && (lower.endsWith(".yaml") || lower.endsWith(".yml"));
|
|
38825
|
+
}
|
|
38826
|
+
function countCompletedTasks(planPath, content) {
|
|
38827
|
+
const plan = parsePlan2(content);
|
|
38828
|
+
const total = plan.tasks.length;
|
|
38829
|
+
const done = plan.tasks.filter((task) => {
|
|
38830
|
+
if (typeof task.status === "string") {
|
|
38831
|
+
return task.status === "done";
|
|
38832
|
+
}
|
|
38833
|
+
return Object.values(task.status).every((status) => status === "done");
|
|
38834
|
+
}).length;
|
|
38835
|
+
return {
|
|
38836
|
+
path: planPath,
|
|
38837
|
+
done,
|
|
38838
|
+
total
|
|
38839
|
+
};
|
|
38840
|
+
}
|
|
38841
|
+
async function ensurePlanExists(fs3, cwd, planPath) {
|
|
38842
|
+
const absolutePath = path23.isAbsolute(planPath) ? planPath : path23.resolve(cwd, planPath);
|
|
38843
|
+
try {
|
|
38844
|
+
const stat8 = await fs3.stat(absolutePath);
|
|
38845
|
+
if (!stat8.isFile()) {
|
|
38846
|
+
throw new Error(`Plan not found at "${planPath}".`);
|
|
38847
|
+
}
|
|
38848
|
+
} catch (error2) {
|
|
38849
|
+
if (isNotFound2(error2)) {
|
|
38850
|
+
throw new Error(`Plan not found at "${planPath}".`);
|
|
38851
|
+
}
|
|
38852
|
+
throw error2;
|
|
38853
|
+
}
|
|
38854
|
+
}
|
|
38855
|
+
async function listPlanCandidates2(fs3, cwd) {
|
|
38856
|
+
const plansDir = path23.join(cwd, ".poe-code", "pipeline", "plans");
|
|
38857
|
+
let entries;
|
|
38858
|
+
try {
|
|
38859
|
+
entries = await fs3.readdir(plansDir);
|
|
38860
|
+
} catch (error2) {
|
|
38861
|
+
if (isNotFound2(error2)) {
|
|
38862
|
+
return [];
|
|
38863
|
+
}
|
|
38864
|
+
throw error2;
|
|
38865
|
+
}
|
|
38866
|
+
const candidates = [];
|
|
38867
|
+
for (const entry of entries) {
|
|
38868
|
+
if (!isPlanCandidateFile2(entry)) {
|
|
38869
|
+
continue;
|
|
38870
|
+
}
|
|
38871
|
+
const absolutePath = path23.join(plansDir, entry);
|
|
38872
|
+
const stat8 = await fs3.stat(absolutePath);
|
|
38873
|
+
if (!stat8.isFile()) {
|
|
38874
|
+
continue;
|
|
38875
|
+
}
|
|
38876
|
+
const relativePath = path23.relative(cwd, absolutePath);
|
|
38877
|
+
const content = await fs3.readFile(absolutePath, "utf8");
|
|
38878
|
+
candidates.push(countCompletedTasks(relativePath, content));
|
|
38879
|
+
}
|
|
38880
|
+
candidates.sort((left, right) => left.path.localeCompare(right.path));
|
|
38881
|
+
return candidates;
|
|
38882
|
+
}
|
|
38883
|
+
async function resolvePlanPath2(options) {
|
|
38884
|
+
const fs3 = options.fs ?? createDefaultFs();
|
|
38885
|
+
const explicitPlan = options.plan?.trim();
|
|
38886
|
+
if (explicitPlan) {
|
|
38887
|
+
await ensurePlanExists(fs3, options.cwd, explicitPlan);
|
|
38888
|
+
return explicitPlan;
|
|
38889
|
+
}
|
|
38890
|
+
const config2 = await loadPipelineConfig({
|
|
38891
|
+
cwd: options.cwd,
|
|
38892
|
+
homeDir: options.homeDir,
|
|
38893
|
+
fs: fs3
|
|
38894
|
+
});
|
|
38895
|
+
if (config2.planPath) {
|
|
38896
|
+
await ensurePlanExists(fs3, options.cwd, config2.planPath);
|
|
38897
|
+
return config2.planPath;
|
|
38898
|
+
}
|
|
38899
|
+
const candidates = await listPlanCandidates2(fs3, options.cwd);
|
|
38900
|
+
if (candidates.length >= 1) {
|
|
38901
|
+
if (options.assumeYes) {
|
|
38902
|
+
return candidates[0].path;
|
|
38903
|
+
}
|
|
38904
|
+
if (!options.selectPlan) {
|
|
38905
|
+
return null;
|
|
38906
|
+
}
|
|
38907
|
+
return options.selectPlan({
|
|
38908
|
+
message: "Select a pipeline plan to run",
|
|
38909
|
+
options: candidates.map((candidate) => ({
|
|
38910
|
+
label: `${candidate.path} (${candidate.done}/${candidate.total})`,
|
|
38911
|
+
value: candidate.path
|
|
38912
|
+
}))
|
|
38913
|
+
});
|
|
38914
|
+
}
|
|
38915
|
+
if (options.assumeYes) {
|
|
38916
|
+
throw new Error(
|
|
38917
|
+
"No plan found under .poe-code/pipeline/plans/. Provide --plan <path> to an existing plan file."
|
|
38918
|
+
);
|
|
38919
|
+
}
|
|
38920
|
+
if (!options.promptForPath) {
|
|
38921
|
+
return null;
|
|
38922
|
+
}
|
|
38923
|
+
return options.promptForPath({
|
|
38924
|
+
message: "Enter the pipeline plan path",
|
|
38925
|
+
placeholder: ".poe-code/pipeline/plans/plan.yaml"
|
|
38926
|
+
});
|
|
38927
|
+
}
|
|
38928
|
+
var init_discovery = __esm({
|
|
38929
|
+
"packages/pipeline/src/plan/discovery.ts"() {
|
|
38930
|
+
"use strict";
|
|
38931
|
+
init_loader2();
|
|
38932
|
+
init_parser2();
|
|
38933
|
+
init_utils3();
|
|
38934
|
+
}
|
|
38935
|
+
});
|
|
38936
|
+
|
|
38937
|
+
// packages/pipeline/src/plan/writer.ts
|
|
38938
|
+
import { parseDocument, isMap, isSeq } from "yaml";
|
|
38939
|
+
function getTasksNode(document) {
|
|
38940
|
+
const tasksNode = document.get("tasks", true);
|
|
38941
|
+
if (!tasksNode || !isSeq(tasksNode)) {
|
|
38942
|
+
throw new Error('Invalid plan YAML: expected "tasks" to be a sequence.');
|
|
38943
|
+
}
|
|
38944
|
+
return tasksNode;
|
|
38945
|
+
}
|
|
38946
|
+
function getTaskNode(tasksNode, taskId) {
|
|
38947
|
+
for (const item of tasksNode.items) {
|
|
38948
|
+
if (!isMap(item)) {
|
|
38949
|
+
continue;
|
|
38950
|
+
}
|
|
38951
|
+
if (item.get("id") === taskId) {
|
|
38952
|
+
return item;
|
|
38953
|
+
}
|
|
38954
|
+
}
|
|
38955
|
+
throw new Error(`Task "${taskId}" not found in plan.`);
|
|
38956
|
+
}
|
|
38957
|
+
async function readPlanFile(fs3, planPath) {
|
|
38958
|
+
return fs3.readFile(planPath, "utf8");
|
|
38959
|
+
}
|
|
38960
|
+
async function writeTaskStatus(options) {
|
|
38961
|
+
const content = await readPlanFile(options.fs, options.planPath);
|
|
38962
|
+
const document = parseDocument(content);
|
|
38963
|
+
const tasksNode = getTasksNode(document);
|
|
38964
|
+
const taskNode = getTaskNode(tasksNode, options.taskId);
|
|
38965
|
+
if (options.stepName) {
|
|
38966
|
+
const statusNode = taskNode.get("status", true);
|
|
38967
|
+
if (!statusNode || !isMap(statusNode)) {
|
|
38968
|
+
throw new Error(`Task "${options.taskId}" does not use step statuses.`);
|
|
38969
|
+
}
|
|
38970
|
+
statusNode.set(options.stepName, options.status);
|
|
38971
|
+
} else {
|
|
38972
|
+
taskNode.set("status", options.status);
|
|
38973
|
+
}
|
|
38974
|
+
await options.fs.writeFile(options.planPath, document.toString(), {
|
|
38975
|
+
encoding: "utf8"
|
|
38976
|
+
});
|
|
38977
|
+
}
|
|
38978
|
+
var init_writer2 = __esm({
|
|
38979
|
+
"packages/pipeline/src/plan/writer.ts"() {
|
|
38980
|
+
"use strict";
|
|
38981
|
+
}
|
|
38982
|
+
});
|
|
38983
|
+
|
|
38984
|
+
// packages/pipeline/src/run/runner.ts
|
|
38985
|
+
function getFailedStepName(status) {
|
|
38986
|
+
return Object.entries(status).find(([, value]) => value === "failed")?.[0];
|
|
38987
|
+
}
|
|
38988
|
+
function getOpenStepName(status) {
|
|
38989
|
+
return Object.entries(status).find(([, value]) => value === "open")?.[0];
|
|
38990
|
+
}
|
|
38991
|
+
function selectFromTask(task) {
|
|
38992
|
+
if (typeof task.status === "string") {
|
|
38993
|
+
if (task.status === "done") {
|
|
38994
|
+
return { kind: "completed" };
|
|
38995
|
+
}
|
|
38996
|
+
if (task.status === "failed") {
|
|
38997
|
+
return { kind: "blocked", task };
|
|
38998
|
+
}
|
|
38999
|
+
return { kind: "run", task };
|
|
39000
|
+
}
|
|
39001
|
+
const failedStepName = getFailedStepName(task.status);
|
|
39002
|
+
if (failedStepName) {
|
|
39003
|
+
return { kind: "blocked", task, stepName: failedStepName };
|
|
39004
|
+
}
|
|
39005
|
+
const openStepName = getOpenStepName(task.status);
|
|
39006
|
+
if (openStepName) {
|
|
39007
|
+
return { kind: "run", task, stepName: openStepName };
|
|
39008
|
+
}
|
|
39009
|
+
return { kind: "completed" };
|
|
39010
|
+
}
|
|
39011
|
+
function selectNextExecution(plan, taskId) {
|
|
39012
|
+
const tasks = taskId ? plan.tasks.filter((task) => task.id === taskId) : plan.tasks;
|
|
39013
|
+
if (taskId && tasks.length === 0) {
|
|
39014
|
+
throw new Error(`Task "${taskId}" was not found in the plan.`);
|
|
39015
|
+
}
|
|
39016
|
+
for (const task of tasks) {
|
|
39017
|
+
const selection = selectFromTask(task);
|
|
39018
|
+
if (selection.kind !== "completed") {
|
|
39019
|
+
return selection;
|
|
39020
|
+
}
|
|
39021
|
+
}
|
|
39022
|
+
return { kind: "completed" };
|
|
39023
|
+
}
|
|
39024
|
+
function interpolate(template, values) {
|
|
39025
|
+
let output = template;
|
|
39026
|
+
for (const [key, value] of Object.entries(values)) {
|
|
39027
|
+
output = output.split(`{{${key}}}`).join(value);
|
|
39028
|
+
}
|
|
39029
|
+
return output;
|
|
39030
|
+
}
|
|
39031
|
+
function buildExecutionPrompt(input) {
|
|
39032
|
+
if (!input.selection.stepName) {
|
|
39033
|
+
return input.selection.task.prompt;
|
|
39034
|
+
}
|
|
39035
|
+
const step = input.steps[input.selection.stepName];
|
|
39036
|
+
if (!step) {
|
|
39037
|
+
throw new Error(`Missing step definition for "${input.selection.stepName}".`);
|
|
39038
|
+
}
|
|
39039
|
+
return interpolate(step.instruction, {
|
|
39040
|
+
id: input.selection.task.id,
|
|
39041
|
+
title: input.selection.task.title,
|
|
39042
|
+
prompt: input.selection.task.prompt,
|
|
39043
|
+
plan_path: input.planPath
|
|
39044
|
+
});
|
|
39045
|
+
}
|
|
39046
|
+
var init_runner = __esm({
|
|
39047
|
+
"packages/pipeline/src/run/runner.ts"() {
|
|
39048
|
+
"use strict";
|
|
39049
|
+
}
|
|
39050
|
+
});
|
|
39051
|
+
|
|
39052
|
+
// packages/pipeline/src/lock/lock.ts
|
|
39053
|
+
import * as fsPromises14 from "node:fs/promises";
|
|
39054
|
+
function sleep2(ms) {
|
|
39055
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
39056
|
+
}
|
|
39057
|
+
function backoff2(attempt, min, max) {
|
|
39058
|
+
const delay = Math.min(max, min * Math.pow(2, attempt));
|
|
39059
|
+
return delay + Math.random() * delay * 0.1;
|
|
39060
|
+
}
|
|
39061
|
+
function createDefaultFs2() {
|
|
39062
|
+
return {
|
|
39063
|
+
mkdir: async (filePath) => {
|
|
39064
|
+
await fsPromises14.mkdir(filePath);
|
|
39065
|
+
},
|
|
39066
|
+
rmdir: fsPromises14.rmdir,
|
|
39067
|
+
stat: async (filePath) => {
|
|
39068
|
+
const stat8 = await fsPromises14.stat(filePath);
|
|
39069
|
+
return {
|
|
39070
|
+
isFile: () => stat8.isFile(),
|
|
39071
|
+
isDirectory: () => stat8.isDirectory(),
|
|
39072
|
+
mtimeMs: stat8.mtimeMs
|
|
39073
|
+
};
|
|
39074
|
+
}
|
|
39075
|
+
};
|
|
39076
|
+
}
|
|
39077
|
+
async function lockFile2(filePath, options = {}) {
|
|
39078
|
+
const fs3 = options.fs ?? createDefaultFs2();
|
|
39079
|
+
const retries = options.retries ?? 20;
|
|
39080
|
+
const minTimeout = options.minTimeout ?? 25;
|
|
39081
|
+
const maxTimeout = options.maxTimeout ?? 250;
|
|
39082
|
+
const staleMs = options.staleMs ?? 3e4;
|
|
39083
|
+
const lockPath = `${filePath}.lock`;
|
|
39084
|
+
for (let attempt = 0; attempt <= retries; attempt += 1) {
|
|
39085
|
+
try {
|
|
39086
|
+
await fs3.mkdir(lockPath);
|
|
39087
|
+
let released = false;
|
|
39088
|
+
return async () => {
|
|
39089
|
+
if (released) {
|
|
39090
|
+
return;
|
|
39091
|
+
}
|
|
39092
|
+
released = true;
|
|
39093
|
+
try {
|
|
39094
|
+
await fs3.rmdir(lockPath);
|
|
39095
|
+
} catch (error2) {
|
|
39096
|
+
if (!error2 || typeof error2 !== "object" || !("code" in error2) || error2.code !== "ENOENT") {
|
|
39097
|
+
throw error2;
|
|
39098
|
+
}
|
|
39099
|
+
}
|
|
39100
|
+
};
|
|
39101
|
+
} catch (error2) {
|
|
39102
|
+
if (!error2 || typeof error2 !== "object" || !("code" in error2) || error2.code !== "EEXIST") {
|
|
39103
|
+
throw error2;
|
|
39104
|
+
}
|
|
39105
|
+
const stat8 = await fs3.stat(lockPath);
|
|
39106
|
+
if (Date.now() - stat8.mtimeMs > staleMs) {
|
|
39107
|
+
await fs3.rmdir(lockPath);
|
|
39108
|
+
continue;
|
|
39109
|
+
}
|
|
39110
|
+
if (attempt < retries) {
|
|
39111
|
+
await sleep2(backoff2(attempt, minTimeout, maxTimeout));
|
|
39112
|
+
}
|
|
39113
|
+
}
|
|
39114
|
+
}
|
|
39115
|
+
throw new Error(`Failed to acquire lock on "${filePath}".`);
|
|
39116
|
+
}
|
|
39117
|
+
var init_lock2 = __esm({
|
|
39118
|
+
"packages/pipeline/src/lock/lock.ts"() {
|
|
39119
|
+
"use strict";
|
|
39120
|
+
}
|
|
39121
|
+
});
|
|
39122
|
+
|
|
39123
|
+
// packages/pipeline/src/run/pipeline.ts
|
|
39124
|
+
import path24 from "node:path";
|
|
39125
|
+
import * as fsPromises15 from "node:fs/promises";
|
|
39126
|
+
function createDefaultFs3() {
|
|
39127
|
+
return {
|
|
39128
|
+
readFile: fsPromises15.readFile,
|
|
39129
|
+
writeFile: fsPromises15.writeFile,
|
|
39130
|
+
readdir: fsPromises15.readdir,
|
|
39131
|
+
stat: async (filePath) => {
|
|
39132
|
+
const stat8 = await fsPromises15.stat(filePath);
|
|
39133
|
+
return {
|
|
39134
|
+
isFile: () => stat8.isFile(),
|
|
39135
|
+
isDirectory: () => stat8.isDirectory(),
|
|
39136
|
+
mtimeMs: stat8.mtimeMs
|
|
39137
|
+
};
|
|
39138
|
+
},
|
|
39139
|
+
mkdir: async (filePath, options) => {
|
|
39140
|
+
await fsPromises15.mkdir(filePath, options);
|
|
39141
|
+
},
|
|
39142
|
+
rmdir: fsPromises15.rmdir
|
|
39143
|
+
};
|
|
39144
|
+
}
|
|
39145
|
+
function isAbortError(error2) {
|
|
39146
|
+
return error2 instanceof Error && error2.name === "AbortError";
|
|
39147
|
+
}
|
|
39148
|
+
function resolveMode(stepName, steps) {
|
|
39149
|
+
if (!stepName) {
|
|
39150
|
+
return "yolo";
|
|
39151
|
+
}
|
|
39152
|
+
const step = steps[stepName];
|
|
39153
|
+
if (!step) {
|
|
39154
|
+
throw new Error(`Missing step definition for "${stepName}".`);
|
|
39155
|
+
}
|
|
39156
|
+
return step.mode;
|
|
39157
|
+
}
|
|
39158
|
+
async function runPipeline(options) {
|
|
39159
|
+
const fs3 = options.fs ?? createDefaultFs3();
|
|
39160
|
+
const runAgent = options.runAgent;
|
|
39161
|
+
if (!runAgent) {
|
|
39162
|
+
throw new Error("runPipeline requires a runAgent implementation.");
|
|
39163
|
+
}
|
|
39164
|
+
const planPath = await resolvePlanPath2({
|
|
39165
|
+
cwd: options.cwd,
|
|
39166
|
+
homeDir: options.homeDir,
|
|
39167
|
+
plan: options.plan,
|
|
39168
|
+
assumeYes: options.assumeYes,
|
|
39169
|
+
fs: fs3,
|
|
39170
|
+
selectPlan: options.selectPlan,
|
|
39171
|
+
promptForPath: options.promptForPath
|
|
39172
|
+
});
|
|
39173
|
+
if (!planPath) {
|
|
39174
|
+
return {
|
|
39175
|
+
stopReason: "cancelled",
|
|
39176
|
+
planPath: "",
|
|
39177
|
+
runsCompleted: 0,
|
|
39178
|
+
totalDurationMs: 0
|
|
39179
|
+
};
|
|
39180
|
+
}
|
|
39181
|
+
const absolutePlanPath = path24.isAbsolute(planPath) ? planPath : path24.resolve(options.cwd, planPath);
|
|
39182
|
+
if (options.onPlanResolved) {
|
|
39183
|
+
const content = await fs3.readFile(absolutePlanPath, "utf8");
|
|
39184
|
+
const plan = parsePlan2(content);
|
|
39185
|
+
const total = plan.tasks.length;
|
|
39186
|
+
const done = plan.tasks.filter((t) => {
|
|
39187
|
+
if (typeof t.status === "string") return t.status === "done";
|
|
39188
|
+
return Object.values(t.status).every((s) => s === "done");
|
|
39189
|
+
}).length;
|
|
39190
|
+
const failed = plan.tasks.filter((t) => {
|
|
39191
|
+
if (typeof t.status === "string") return t.status === "failed";
|
|
39192
|
+
return Object.values(t.status).some((s) => s === "failed");
|
|
39193
|
+
}).length;
|
|
39194
|
+
options.onPlanResolved({
|
|
39195
|
+
planPath,
|
|
39196
|
+
done,
|
|
39197
|
+
failed,
|
|
39198
|
+
open: total - done - failed,
|
|
39199
|
+
total
|
|
39200
|
+
});
|
|
39201
|
+
}
|
|
39202
|
+
const maxRuns = options.maxRuns ?? Number.POSITIVE_INFINITY;
|
|
39203
|
+
let runsCompleted = 0;
|
|
39204
|
+
const pipelineStartTime = Date.now();
|
|
39205
|
+
while (runsCompleted < maxRuns) {
|
|
39206
|
+
assertNotAborted(options.signal);
|
|
39207
|
+
const release = await lockFile2(absolutePlanPath, { fs: fs3 });
|
|
39208
|
+
try {
|
|
39209
|
+
const steps = await loadResolvedSteps({
|
|
39210
|
+
cwd: options.cwd,
|
|
39211
|
+
homeDir: options.homeDir,
|
|
39212
|
+
fs: fs3
|
|
39213
|
+
});
|
|
39214
|
+
const content = await fs3.readFile(absolutePlanPath, "utf8");
|
|
39215
|
+
const plan = parsePlan2(content, { availableSteps: steps });
|
|
39216
|
+
const totalTasks = plan.tasks.length;
|
|
39217
|
+
const selection = selectNextExecution(plan, options.task);
|
|
39218
|
+
if (selection.kind === "completed") {
|
|
39219
|
+
return {
|
|
39220
|
+
stopReason: runsCompleted === 0 ? "nothing_to_run" : "completed",
|
|
39221
|
+
planPath,
|
|
39222
|
+
runsCompleted,
|
|
39223
|
+
totalDurationMs: Date.now() - pipelineStartTime
|
|
39224
|
+
};
|
|
39225
|
+
}
|
|
39226
|
+
if (selection.kind === "blocked") {
|
|
39227
|
+
return {
|
|
39228
|
+
stopReason: "failed",
|
|
39229
|
+
planPath,
|
|
39230
|
+
runsCompleted,
|
|
39231
|
+
totalDurationMs: Date.now() - pipelineStartTime,
|
|
39232
|
+
lastTaskId: selection.task.id,
|
|
39233
|
+
...selection.stepName ? { lastStepName: selection.stepName } : {}
|
|
39234
|
+
};
|
|
39235
|
+
}
|
|
39236
|
+
const taskProgress = {
|
|
39237
|
+
taskId: selection.task.id,
|
|
39238
|
+
taskTitle: selection.task.title,
|
|
39239
|
+
...selection.stepName ? { stepName: selection.stepName } : {},
|
|
39240
|
+
index: runsCompleted + 1,
|
|
39241
|
+
total: totalTasks
|
|
39242
|
+
};
|
|
39243
|
+
options.onTaskStart?.(taskProgress);
|
|
39244
|
+
const prompt = buildExecutionPrompt({
|
|
39245
|
+
selection,
|
|
39246
|
+
steps,
|
|
39247
|
+
planPath
|
|
39248
|
+
});
|
|
39249
|
+
const mode = resolveMode(selection.stepName, steps);
|
|
39250
|
+
const taskStartTime = Date.now();
|
|
39251
|
+
let result;
|
|
39252
|
+
try {
|
|
39253
|
+
result = await runAgent({
|
|
39254
|
+
agent: options.agent,
|
|
39255
|
+
prompt,
|
|
39256
|
+
mode,
|
|
39257
|
+
cwd: options.cwd,
|
|
39258
|
+
...options.model ? { model: options.model } : {},
|
|
39259
|
+
...options.signal ? { signal: options.signal } : {}
|
|
39260
|
+
});
|
|
39261
|
+
} catch (error2) {
|
|
39262
|
+
if (isAbortError(error2)) {
|
|
39263
|
+
return {
|
|
39264
|
+
stopReason: "cancelled",
|
|
39265
|
+
planPath,
|
|
39266
|
+
runsCompleted,
|
|
39267
|
+
totalDurationMs: Date.now() - pipelineStartTime,
|
|
39268
|
+
lastTaskId: selection.task.id,
|
|
39269
|
+
...selection.stepName ? { lastStepName: selection.stepName } : {}
|
|
39270
|
+
};
|
|
39271
|
+
}
|
|
39272
|
+
throw error2;
|
|
39273
|
+
}
|
|
39274
|
+
const taskDurationMs = Date.now() - taskStartTime;
|
|
39275
|
+
const success2 = result.exitCode === 0;
|
|
39276
|
+
await writeTaskStatus({
|
|
39277
|
+
fs: fs3,
|
|
39278
|
+
planPath: absolutePlanPath,
|
|
39279
|
+
taskId: selection.task.id,
|
|
39280
|
+
...selection.stepName ? { stepName: selection.stepName } : {},
|
|
39281
|
+
status: success2 ? "done" : "failed"
|
|
39282
|
+
});
|
|
39283
|
+
runsCompleted += 1;
|
|
39284
|
+
options.onTaskComplete?.({
|
|
39285
|
+
...taskProgress,
|
|
39286
|
+
durationMs: taskDurationMs,
|
|
39287
|
+
success: success2
|
|
39288
|
+
});
|
|
39289
|
+
if (!success2) {
|
|
39290
|
+
return {
|
|
39291
|
+
stopReason: "failed",
|
|
39292
|
+
planPath,
|
|
39293
|
+
runsCompleted,
|
|
39294
|
+
totalDurationMs: Date.now() - pipelineStartTime,
|
|
39295
|
+
lastTaskId: selection.task.id,
|
|
39296
|
+
...selection.stepName ? { lastStepName: selection.stepName } : {}
|
|
39297
|
+
};
|
|
39298
|
+
}
|
|
39299
|
+
} finally {
|
|
39300
|
+
await release();
|
|
39301
|
+
}
|
|
39302
|
+
}
|
|
39303
|
+
return {
|
|
39304
|
+
stopReason: "max_runs",
|
|
39305
|
+
planPath,
|
|
39306
|
+
runsCompleted,
|
|
39307
|
+
totalDurationMs: Date.now() - pipelineStartTime
|
|
39308
|
+
};
|
|
39309
|
+
}
|
|
39310
|
+
var init_pipeline2 = __esm({
|
|
39311
|
+
"packages/pipeline/src/run/pipeline.ts"() {
|
|
39312
|
+
"use strict";
|
|
39313
|
+
init_loader2();
|
|
39314
|
+
init_lock2();
|
|
39315
|
+
init_discovery();
|
|
39316
|
+
init_parser2();
|
|
39317
|
+
init_writer2();
|
|
39318
|
+
init_runner();
|
|
39319
|
+
init_utils3();
|
|
39320
|
+
}
|
|
39321
|
+
});
|
|
39322
|
+
|
|
39323
|
+
// packages/pipeline/src/index.ts
|
|
39324
|
+
var init_src14 = __esm({
|
|
39325
|
+
"packages/pipeline/src/index.ts"() {
|
|
39326
|
+
"use strict";
|
|
39327
|
+
init_loader2();
|
|
39328
|
+
init_discovery();
|
|
39329
|
+
init_parser2();
|
|
39330
|
+
init_writer2();
|
|
39331
|
+
init_runner();
|
|
39332
|
+
init_pipeline2();
|
|
39333
|
+
}
|
|
39334
|
+
});
|
|
39335
|
+
|
|
39336
|
+
// src/sdk/pipeline.ts
|
|
39337
|
+
async function runPipeline2(options) {
|
|
39338
|
+
return runPipeline({
|
|
39339
|
+
...options,
|
|
39340
|
+
runAgent: async (input) => {
|
|
39341
|
+
const { events, result } = spawn5(input.agent, {
|
|
39342
|
+
prompt: input.prompt,
|
|
39343
|
+
cwd: input.cwd,
|
|
39344
|
+
model: input.model,
|
|
39345
|
+
mode: input.mode
|
|
39346
|
+
});
|
|
39347
|
+
await renderAcpStream(events);
|
|
39348
|
+
return result;
|
|
39349
|
+
}
|
|
39350
|
+
});
|
|
39351
|
+
}
|
|
39352
|
+
var init_pipeline3 = __esm({
|
|
39353
|
+
async "src/sdk/pipeline.ts"() {
|
|
39354
|
+
"use strict";
|
|
39355
|
+
init_src14();
|
|
39356
|
+
init_src5();
|
|
39357
|
+
await init_spawn3();
|
|
39358
|
+
}
|
|
39359
|
+
});
|
|
39360
|
+
|
|
39361
|
+
// src/cli/commands/pipeline.ts
|
|
39362
|
+
import path25 from "node:path";
|
|
39363
|
+
import { readFile as readFile6, stat as stat7 } from "node:fs/promises";
|
|
39364
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
39365
|
+
function formatDuration2(ms) {
|
|
39366
|
+
const totalSeconds = Math.round(ms / 1e3);
|
|
39367
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
39368
|
+
const seconds = totalSeconds % 60;
|
|
39369
|
+
return minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
|
|
39370
|
+
}
|
|
39371
|
+
function resolvePipelineAgent(value) {
|
|
39372
|
+
if (!value || value.trim().length === 0) {
|
|
39373
|
+
return DEFAULT_PIPELINE_AGENT;
|
|
39374
|
+
}
|
|
39375
|
+
const resolved = resolveAgentId(value.trim());
|
|
39376
|
+
if (!resolved) {
|
|
39377
|
+
throw new ValidationError(`Unsupported agent: ${value}`);
|
|
39378
|
+
}
|
|
39379
|
+
return resolved;
|
|
39380
|
+
}
|
|
39381
|
+
function resolveMaxRuns(value) {
|
|
39382
|
+
if (value == null) {
|
|
39383
|
+
return void 0;
|
|
39384
|
+
}
|
|
39385
|
+
const parsed = Number.parseInt(value, 10);
|
|
39386
|
+
if (!Number.isFinite(parsed) || parsed < 1) {
|
|
39387
|
+
throw new ValidationError(
|
|
39388
|
+
`Invalid max-runs "${value}". Expected a positive integer.`
|
|
39389
|
+
);
|
|
39390
|
+
}
|
|
39391
|
+
return parsed;
|
|
39392
|
+
}
|
|
39393
|
+
function resolvePipelinePaths(scope, cwd, homeDir) {
|
|
39394
|
+
const rootPath = scope === "global" ? path25.join(homeDir, ".poe-code", "pipeline") : path25.join(cwd, ".poe-code", "pipeline");
|
|
39395
|
+
const displayRoot = scope === "global" ? "~/.poe-code/pipeline" : ".poe-code/pipeline";
|
|
39396
|
+
return {
|
|
39397
|
+
plansPath: path25.join(rootPath, "plans"),
|
|
39398
|
+
stepsPath: path25.join(rootPath, "steps.yaml"),
|
|
39399
|
+
displayPlansPath: `${displayRoot}/plans`,
|
|
39400
|
+
displayStepsPath: `${displayRoot}/steps.yaml`
|
|
39401
|
+
};
|
|
39402
|
+
}
|
|
39403
|
+
async function loadPipelineTemplates() {
|
|
39404
|
+
if (pipelineTemplatesCache) {
|
|
39405
|
+
return pipelineTemplatesCache;
|
|
39406
|
+
}
|
|
39407
|
+
const packageRoot = await findPackageRoot(fileURLToPath3(import.meta.url));
|
|
39408
|
+
const templateRoots = [
|
|
39409
|
+
path25.join(packageRoot, "src", "templates", "pipeline"),
|
|
39410
|
+
path25.join(packageRoot, "dist", "templates", "pipeline")
|
|
39411
|
+
];
|
|
39412
|
+
for (const templateRoot of templateRoots) {
|
|
39413
|
+
if (!await pathExistsOnDisk(templateRoot)) {
|
|
39414
|
+
continue;
|
|
39415
|
+
}
|
|
39416
|
+
const [skillPlan, steps] = await Promise.all([
|
|
39417
|
+
readFile6(path25.join(templateRoot, "SKILL_plan.md"), "utf8"),
|
|
39418
|
+
readFile6(path25.join(templateRoot, "steps.yaml.hbs"), "utf8")
|
|
39419
|
+
]);
|
|
39420
|
+
pipelineTemplatesCache = { skillPlan, steps };
|
|
39421
|
+
return pipelineTemplatesCache;
|
|
39422
|
+
}
|
|
39423
|
+
throw new Error("Pipeline templates not found.");
|
|
39424
|
+
}
|
|
39425
|
+
async function pathExistsOnDisk(targetPath) {
|
|
39426
|
+
try {
|
|
39427
|
+
await stat7(targetPath);
|
|
39428
|
+
return true;
|
|
39429
|
+
} catch (error2) {
|
|
39430
|
+
if (error2 && typeof error2 === "object" && "code" in error2 && error2.code === "ENOENT") {
|
|
39431
|
+
return false;
|
|
39432
|
+
}
|
|
39433
|
+
throw error2;
|
|
39434
|
+
}
|
|
39435
|
+
}
|
|
39436
|
+
async function findPackageRoot(entryFilePath) {
|
|
39437
|
+
let currentPath = path25.dirname(entryFilePath);
|
|
39438
|
+
while (true) {
|
|
39439
|
+
if (await pathExistsOnDisk(path25.join(currentPath, "package.json"))) {
|
|
39440
|
+
return currentPath;
|
|
39441
|
+
}
|
|
39442
|
+
const parentPath = path25.dirname(currentPath);
|
|
39443
|
+
if (parentPath === currentPath) {
|
|
39444
|
+
throw new Error("Unable to locate package root for Pipeline templates.");
|
|
39445
|
+
}
|
|
39446
|
+
currentPath = parentPath;
|
|
39447
|
+
}
|
|
39448
|
+
}
|
|
39449
|
+
async function pathExists4(fs3, targetPath) {
|
|
39450
|
+
try {
|
|
39451
|
+
await fs3.stat(targetPath);
|
|
39452
|
+
return true;
|
|
39453
|
+
} catch (error2) {
|
|
39454
|
+
if (error2 && typeof error2 === "object" && "code" in error2 && error2.code === "ENOENT") {
|
|
39455
|
+
return false;
|
|
39456
|
+
}
|
|
39457
|
+
throw error2;
|
|
39458
|
+
}
|
|
39459
|
+
}
|
|
39460
|
+
function registerPipelineCommand(program, container) {
|
|
39461
|
+
const pipeline = program.command("pipeline").description("Run a fixed-step task pipeline plan.");
|
|
39462
|
+
pipeline.command("run").description("Run the selected pipeline plan until completion, failure, cancellation, or cap.").option("--agent <name>", "Agent to run each pipeline step with").option("--model <model>", "Model override passed to the agent").option("--task <id>", "Run only the specified task").option("--plan <path>", "Path to the pipeline plan file").option("--max-runs <n>", "Maximum number of agent executions to perform").action(async function() {
|
|
39463
|
+
const flags = resolveCommandFlags(program);
|
|
39464
|
+
const resources = createExecutionResources(
|
|
39465
|
+
container,
|
|
39466
|
+
flags,
|
|
39467
|
+
"pipeline:run"
|
|
39468
|
+
);
|
|
39469
|
+
const options = this.opts();
|
|
39470
|
+
resources.logger.intro("pipeline run");
|
|
39471
|
+
try {
|
|
39472
|
+
let agent;
|
|
39473
|
+
if (options.agent) {
|
|
39474
|
+
agent = resolvePipelineAgent(options.agent);
|
|
39475
|
+
} else if (flags.assumeYes) {
|
|
39476
|
+
agent = DEFAULT_PIPELINE_AGENT;
|
|
39477
|
+
} else {
|
|
39478
|
+
const selected = await select2({
|
|
39479
|
+
message: "Select agent to run pipeline steps with:",
|
|
39480
|
+
options: supportedAgents2.map((value) => ({
|
|
39481
|
+
value,
|
|
39482
|
+
label: value
|
|
39483
|
+
}))
|
|
39484
|
+
});
|
|
39485
|
+
if (isCancel2(selected)) {
|
|
39486
|
+
cancel2("Pipeline run cancelled.");
|
|
39487
|
+
return;
|
|
39488
|
+
}
|
|
39489
|
+
agent = resolvePipelineAgent(selected);
|
|
39490
|
+
}
|
|
39491
|
+
const result = await runPipeline2({
|
|
39492
|
+
agent,
|
|
39493
|
+
cwd: container.env.cwd,
|
|
39494
|
+
homeDir: container.env.homeDir,
|
|
39495
|
+
...options.model ? { model: options.model } : {},
|
|
39496
|
+
...options.task ? { task: options.task } : {},
|
|
39497
|
+
...options.plan ? { plan: options.plan } : {},
|
|
39498
|
+
...resolveMaxRuns(options.maxRuns) != null ? { maxRuns: resolveMaxRuns(options.maxRuns) } : {},
|
|
39499
|
+
assumeYes: flags.assumeYes,
|
|
39500
|
+
onPlanResolved(summary2) {
|
|
39501
|
+
const configLines = [`Agent: ${agent}`];
|
|
39502
|
+
if (options.model) configLines.push(`Model: ${options.model}`);
|
|
39503
|
+
configLines.push(`Plan: ${summary2.planPath}`);
|
|
39504
|
+
resources.logger.resolved("Config", configLines.join("\n "));
|
|
39505
|
+
const parts = [`${summary2.done}/${summary2.total} done`];
|
|
39506
|
+
if (summary2.failed) parts.push(`${summary2.failed} failed`);
|
|
39507
|
+
if (summary2.open) parts.push(`${summary2.open} open`);
|
|
39508
|
+
resources.logger.resolved("Tasks", parts.join(", "));
|
|
39509
|
+
},
|
|
39510
|
+
selectPlan: async (input) => {
|
|
39511
|
+
const selected = await select2(input);
|
|
39512
|
+
if (isCancel2(selected)) {
|
|
39513
|
+
cancel2("Pipeline run cancelled.");
|
|
39514
|
+
return null;
|
|
39515
|
+
}
|
|
39516
|
+
return typeof selected === "string" ? selected : null;
|
|
39517
|
+
},
|
|
39518
|
+
promptForPath: async (input) => {
|
|
39519
|
+
const value = await text3(input);
|
|
39520
|
+
if (isCancel2(value)) {
|
|
39521
|
+
cancel2("Pipeline run cancelled.");
|
|
39522
|
+
return null;
|
|
39523
|
+
}
|
|
39524
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
39525
|
+
},
|
|
39526
|
+
onTaskStart(progress) {
|
|
39527
|
+
const step = progress.stepName ? ` (${progress.stepName})` : "";
|
|
39528
|
+
resources.logger.info(
|
|
39529
|
+
`Task ${progress.index}/${progress.total}: ${progress.taskId}${step}`
|
|
39530
|
+
);
|
|
39531
|
+
},
|
|
39532
|
+
onTaskComplete(progress) {
|
|
39533
|
+
const duration3 = formatDuration2(progress.durationMs);
|
|
39534
|
+
const status = progress.success ? "done" : "failed";
|
|
39535
|
+
resources.logger.info(
|
|
39536
|
+
`Task ${progress.taskId} ${status} in ${duration3}`
|
|
39537
|
+
);
|
|
39538
|
+
}
|
|
39539
|
+
});
|
|
39540
|
+
const summary = [
|
|
39541
|
+
`Tasks: ${result.runsCompleted}/${result.runsCompleted + (result.stopReason === "completed" || result.stopReason === "nothing_to_run" ? 0 : 1)}`,
|
|
39542
|
+
`Duration: ${formatDuration2(result.totalDurationMs)}`
|
|
39543
|
+
].join("\n ");
|
|
39544
|
+
if (result.stopReason === "failed") {
|
|
39545
|
+
process.exitCode = 1;
|
|
39546
|
+
resources.logger.error(
|
|
39547
|
+
`Pipeline blocked at ${result.lastTaskId}${result.lastStepName ? ` (${result.lastStepName})` : ""}.`
|
|
39548
|
+
);
|
|
39549
|
+
resources.logger.resolved("Run summary", summary);
|
|
39550
|
+
return;
|
|
39551
|
+
}
|
|
39552
|
+
if (result.stopReason === "cancelled") {
|
|
39553
|
+
process.exitCode = 130;
|
|
39554
|
+
resources.logger.warn("Pipeline run cancelled.");
|
|
39555
|
+
resources.logger.resolved("Run summary", summary);
|
|
39556
|
+
return;
|
|
39557
|
+
}
|
|
39558
|
+
if (result.stopReason === "nothing_to_run") {
|
|
39559
|
+
resources.logger.info("Nothing to run.");
|
|
39560
|
+
return;
|
|
39561
|
+
}
|
|
39562
|
+
if (result.stopReason === "max_runs") {
|
|
39563
|
+
resources.logger.info(
|
|
39564
|
+
`Reached max runs (${result.runsCompleted}).`
|
|
39565
|
+
);
|
|
39566
|
+
resources.logger.resolved("Run summary", summary);
|
|
39567
|
+
return;
|
|
39568
|
+
}
|
|
39569
|
+
resources.logger.resolved("Run summary", summary);
|
|
39570
|
+
resources.logger.success("Pipeline run finished.");
|
|
39571
|
+
} finally {
|
|
39572
|
+
resources.context.finalize();
|
|
39573
|
+
}
|
|
39574
|
+
});
|
|
39575
|
+
pipeline.command("install").description("Install the Pipeline /plan skill and scaffold pipeline files.").option("--agent <name>", "Agent to install the Pipeline skill for").option("--local", "Install project-local skill and pipeline files").option("--global", "Install user-global skill and pipeline files").option("--force", "Overwrite an existing steps.yaml scaffold").action(async function() {
|
|
39576
|
+
const flags = resolveCommandFlags(program);
|
|
39577
|
+
const resources = createExecutionResources(
|
|
39578
|
+
container,
|
|
39579
|
+
flags,
|
|
39580
|
+
"pipeline:install"
|
|
39581
|
+
);
|
|
39582
|
+
const options = this.opts();
|
|
39583
|
+
if (options.local && options.global) {
|
|
39584
|
+
throw new ValidationError("Use either --local or --global, not both.");
|
|
39585
|
+
}
|
|
39586
|
+
try {
|
|
39587
|
+
let agent = options.agent;
|
|
39588
|
+
if (!agent) {
|
|
39589
|
+
if (flags.assumeYes) {
|
|
39590
|
+
agent = DEFAULT_PIPELINE_AGENT;
|
|
39591
|
+
} else {
|
|
39592
|
+
const selected = await select2({
|
|
39593
|
+
message: "Select agent to install the Pipeline skill for:",
|
|
39594
|
+
options: supportedAgents2.map((value) => ({
|
|
39595
|
+
value,
|
|
39596
|
+
label: value
|
|
39597
|
+
}))
|
|
39598
|
+
});
|
|
39599
|
+
if (isCancel2(selected)) {
|
|
39600
|
+
cancel2("Pipeline install cancelled.");
|
|
39601
|
+
return;
|
|
39602
|
+
}
|
|
39603
|
+
agent = selected;
|
|
39604
|
+
}
|
|
39605
|
+
}
|
|
39606
|
+
const support = resolveAgentSupport2(agent);
|
|
39607
|
+
if (support.status !== "supported" || !support.id) {
|
|
39608
|
+
throw new ValidationError(`Unsupported agent: ${agent}`);
|
|
39609
|
+
}
|
|
39610
|
+
let scope;
|
|
39611
|
+
if (options.local) {
|
|
39612
|
+
scope = "local";
|
|
39613
|
+
} else if (options.global) {
|
|
39614
|
+
scope = "global";
|
|
39615
|
+
} else if (flags.assumeYes) {
|
|
39616
|
+
scope = DEFAULT_PIPELINE_SCOPE;
|
|
39617
|
+
} else {
|
|
39618
|
+
const selected = await select2({
|
|
39619
|
+
message: "Select install scope:",
|
|
39620
|
+
options: [
|
|
39621
|
+
{ value: "local", label: "Local" },
|
|
39622
|
+
{ value: "global", label: "Global" }
|
|
39623
|
+
]
|
|
39624
|
+
});
|
|
39625
|
+
if (isCancel2(selected)) {
|
|
39626
|
+
cancel2("Pipeline install cancelled.");
|
|
39627
|
+
return;
|
|
39628
|
+
}
|
|
39629
|
+
scope = selected;
|
|
39630
|
+
}
|
|
39631
|
+
resources.logger.intro(`pipeline install (${support.id}, ${scope})`);
|
|
39632
|
+
const templates = await loadPipelineTemplates();
|
|
39633
|
+
const skillResult = await installSkill(
|
|
39634
|
+
support.id,
|
|
39635
|
+
{
|
|
39636
|
+
name: "poe-code-pipeline-plan",
|
|
39637
|
+
content: templates.skillPlan
|
|
39638
|
+
},
|
|
39639
|
+
{
|
|
39640
|
+
fs: container.fs,
|
|
39641
|
+
cwd: container.env.cwd,
|
|
39642
|
+
homeDir: container.env.homeDir,
|
|
39643
|
+
scope,
|
|
39644
|
+
dryRun: flags.dryRun
|
|
39645
|
+
}
|
|
39646
|
+
);
|
|
39647
|
+
if (flags.dryRun) {
|
|
39648
|
+
resources.logger.dryRun(`Would create: ${skillResult.displayPath}`);
|
|
39649
|
+
} else {
|
|
39650
|
+
resources.logger.info(`Create: ${skillResult.displayPath}`);
|
|
39651
|
+
}
|
|
39652
|
+
const pipelinePaths = resolvePipelinePaths(
|
|
39653
|
+
scope,
|
|
39654
|
+
container.env.cwd,
|
|
39655
|
+
container.env.homeDir
|
|
39656
|
+
);
|
|
39657
|
+
if (!await pathExists4(container.fs, pipelinePaths.plansPath)) {
|
|
39658
|
+
if (flags.dryRun) {
|
|
39659
|
+
resources.logger.dryRun(`Would create: ${pipelinePaths.displayPlansPath}`);
|
|
39660
|
+
} else {
|
|
39661
|
+
await container.fs.mkdir(pipelinePaths.plansPath, { recursive: true });
|
|
39662
|
+
resources.logger.info(`Create: ${pipelinePaths.displayPlansPath}`);
|
|
39663
|
+
}
|
|
39664
|
+
}
|
|
39665
|
+
const stepsExists = await pathExists4(container.fs, pipelinePaths.stepsPath);
|
|
39666
|
+
if (stepsExists && !options.force) {
|
|
39667
|
+
resources.logger.info(
|
|
39668
|
+
`Skip: ${pipelinePaths.displayStepsPath} (already exists)`
|
|
39669
|
+
);
|
|
39670
|
+
} else if (flags.dryRun) {
|
|
39671
|
+
resources.logger.dryRun(
|
|
39672
|
+
`Would ${stepsExists ? "overwrite" : "create"}: ${pipelinePaths.displayStepsPath}`
|
|
39673
|
+
);
|
|
39674
|
+
} else {
|
|
39675
|
+
await container.fs.mkdir(path25.dirname(pipelinePaths.stepsPath), {
|
|
39676
|
+
recursive: true
|
|
39677
|
+
});
|
|
39678
|
+
await container.fs.writeFile(pipelinePaths.stepsPath, templates.steps, {
|
|
39679
|
+
encoding: "utf8"
|
|
39680
|
+
});
|
|
39681
|
+
resources.logger.info(
|
|
39682
|
+
`${stepsExists ? "Overwrite" : "Create"}: ${pipelinePaths.displayStepsPath}`
|
|
39683
|
+
);
|
|
39684
|
+
}
|
|
39685
|
+
resources.context.complete({
|
|
39686
|
+
success: `Installed Pipeline skill for ${support.id} and scaffolded ${scope} pipeline files`,
|
|
39687
|
+
dry: `Would install Pipeline skill for ${support.id} and scaffold ${scope} pipeline files`
|
|
39688
|
+
});
|
|
39689
|
+
} finally {
|
|
39690
|
+
resources.context.finalize();
|
|
39691
|
+
}
|
|
39692
|
+
});
|
|
39693
|
+
}
|
|
39694
|
+
var DEFAULT_PIPELINE_AGENT, DEFAULT_PIPELINE_SCOPE, pipelineTemplatesCache;
|
|
39695
|
+
var init_pipeline4 = __esm({
|
|
39696
|
+
async "src/cli/commands/pipeline.ts"() {
|
|
39697
|
+
"use strict";
|
|
39698
|
+
init_src4();
|
|
39699
|
+
init_src3();
|
|
39700
|
+
init_src11();
|
|
39701
|
+
init_errors();
|
|
39702
|
+
init_shared();
|
|
39703
|
+
await init_pipeline3();
|
|
39704
|
+
DEFAULT_PIPELINE_AGENT = "claude-code";
|
|
39705
|
+
DEFAULT_PIPELINE_SCOPE = "local";
|
|
39706
|
+
pipelineTemplatesCache = null;
|
|
39707
|
+
}
|
|
39708
|
+
});
|
|
39709
|
+
|
|
38586
39710
|
// package.json
|
|
38587
39711
|
var package_default;
|
|
38588
39712
|
var init_package = __esm({
|
|
38589
39713
|
"package.json"() {
|
|
38590
39714
|
package_default = {
|
|
38591
39715
|
name: "poe-code",
|
|
38592
|
-
version: "3.0.
|
|
39716
|
+
version: "3.0.94",
|
|
38593
39717
|
description: "CLI tool to configure Poe API for developer workflows.",
|
|
38594
39718
|
type: "module",
|
|
38595
39719
|
main: "./dist/index.js",
|
|
@@ -38793,6 +39917,16 @@ function formatHelpText(input) {
|
|
|
38793
39917
|
args: "[agent]",
|
|
38794
39918
|
description: "Remove agent skills configuration"
|
|
38795
39919
|
},
|
|
39920
|
+
{
|
|
39921
|
+
name: "pipeline install",
|
|
39922
|
+
args: "[agent]",
|
|
39923
|
+
description: "Install pipeline skill into agent configuration"
|
|
39924
|
+
},
|
|
39925
|
+
{
|
|
39926
|
+
name: "pipeline run",
|
|
39927
|
+
args: "",
|
|
39928
|
+
description: "Run a fixed-step task pipeline plan"
|
|
39929
|
+
},
|
|
38796
39930
|
{
|
|
38797
39931
|
name: "usage",
|
|
38798
39932
|
args: "",
|
|
@@ -38953,6 +40087,7 @@ function bootstrapProgram(container) {
|
|
|
38953
40087
|
registerRalphCommand(program, container);
|
|
38954
40088
|
registerUsageCommand(program, container);
|
|
38955
40089
|
registerModelsCommand(program, container);
|
|
40090
|
+
registerPipelineCommand(program, container);
|
|
38956
40091
|
program.allowExcessArguments().action(function() {
|
|
38957
40092
|
const args = this.args;
|
|
38958
40093
|
if (args.length > 0) {
|
|
@@ -39008,6 +40143,7 @@ var init_program = __esm({
|
|
|
39008
40143
|
init_ralph();
|
|
39009
40144
|
init_usage();
|
|
39010
40145
|
init_models();
|
|
40146
|
+
await init_pipeline4();
|
|
39011
40147
|
init_package();
|
|
39012
40148
|
init_command_not_found();
|
|
39013
40149
|
init_execution_context();
|