@klaudworks/rmr 0.4.5 → 1.0.0
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/LICENSE +21 -0
- package/README.md +147 -18
- package/dist/index.js +1830 -1229
- package/examples/workflows/feature-dev/planner-agent.md +4 -0
- package/examples/workflows/feature-dev/review-agent.md +8 -0
- package/examples/workflows/feature-dev/tackle-agent.md +6 -0
- package/examples/workflows/feature-dev/workflow.yaml +19 -46
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -9616,26 +9616,6 @@ function String2(descriptor, ...args) {
|
|
|
9616
9616
|
return StringPositional(descriptor);
|
|
9617
9617
|
}
|
|
9618
9618
|
}
|
|
9619
|
-
// src/lib/config.ts
|
|
9620
|
-
import { mkdir } from "node:fs/promises";
|
|
9621
|
-
import { resolve } from "node:path";
|
|
9622
|
-
async function loadConfig(workspaceRoot = process.cwd()) {
|
|
9623
|
-
const root = resolve(workspaceRoot);
|
|
9624
|
-
const rexDir = resolve(root, ".rmr");
|
|
9625
|
-
const config = {
|
|
9626
|
-
workspaceRoot: root,
|
|
9627
|
-
rexDir,
|
|
9628
|
-
runsDir: resolve(rexDir, "runs"),
|
|
9629
|
-
workflowsDir: resolve(rexDir, "workflows")
|
|
9630
|
-
};
|
|
9631
|
-
await Promise.all([
|
|
9632
|
-
mkdir(config.rexDir, { recursive: true }),
|
|
9633
|
-
mkdir(config.runsDir, { recursive: true }),
|
|
9634
|
-
mkdir(config.workflowsDir, { recursive: true })
|
|
9635
|
-
]);
|
|
9636
|
-
return config;
|
|
9637
|
-
}
|
|
9638
|
-
|
|
9639
9619
|
// src/lib/errors.ts
|
|
9640
9620
|
class RmrError extends Error {
|
|
9641
9621
|
code;
|
|
@@ -9674,1157 +9654,1618 @@ class StorageError extends RmrError {
|
|
|
9674
9654
|
}
|
|
9675
9655
|
}
|
|
9676
9656
|
|
|
9677
|
-
//
|
|
9678
|
-
|
|
9679
|
-
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
|
|
9657
|
+
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
9658
|
+
var ANSI_BACKGROUND_OFFSET = 10;
|
|
9659
|
+
var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
|
|
9660
|
+
var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
|
|
9661
|
+
var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
|
|
9662
|
+
var styles = {
|
|
9663
|
+
modifier: {
|
|
9664
|
+
reset: [0, 0],
|
|
9665
|
+
bold: [1, 22],
|
|
9666
|
+
dim: [2, 22],
|
|
9667
|
+
italic: [3, 23],
|
|
9668
|
+
underline: [4, 24],
|
|
9669
|
+
overline: [53, 55],
|
|
9670
|
+
inverse: [7, 27],
|
|
9671
|
+
hidden: [8, 28],
|
|
9672
|
+
strikethrough: [9, 29]
|
|
9673
|
+
},
|
|
9674
|
+
color: {
|
|
9675
|
+
black: [30, 39],
|
|
9676
|
+
red: [31, 39],
|
|
9677
|
+
green: [32, 39],
|
|
9678
|
+
yellow: [33, 39],
|
|
9679
|
+
blue: [34, 39],
|
|
9680
|
+
magenta: [35, 39],
|
|
9681
|
+
cyan: [36, 39],
|
|
9682
|
+
white: [37, 39],
|
|
9683
|
+
blackBright: [90, 39],
|
|
9684
|
+
gray: [90, 39],
|
|
9685
|
+
grey: [90, 39],
|
|
9686
|
+
redBright: [91, 39],
|
|
9687
|
+
greenBright: [92, 39],
|
|
9688
|
+
yellowBright: [93, 39],
|
|
9689
|
+
blueBright: [94, 39],
|
|
9690
|
+
magentaBright: [95, 39],
|
|
9691
|
+
cyanBright: [96, 39],
|
|
9692
|
+
whiteBright: [97, 39]
|
|
9693
|
+
},
|
|
9694
|
+
bgColor: {
|
|
9695
|
+
bgBlack: [40, 49],
|
|
9696
|
+
bgRed: [41, 49],
|
|
9697
|
+
bgGreen: [42, 49],
|
|
9698
|
+
bgYellow: [43, 49],
|
|
9699
|
+
bgBlue: [44, 49],
|
|
9700
|
+
bgMagenta: [45, 49],
|
|
9701
|
+
bgCyan: [46, 49],
|
|
9702
|
+
bgWhite: [47, 49],
|
|
9703
|
+
bgBlackBright: [100, 49],
|
|
9704
|
+
bgGray: [100, 49],
|
|
9705
|
+
bgGrey: [100, 49],
|
|
9706
|
+
bgRedBright: [101, 49],
|
|
9707
|
+
bgGreenBright: [102, 49],
|
|
9708
|
+
bgYellowBright: [103, 49],
|
|
9709
|
+
bgBlueBright: [104, 49],
|
|
9710
|
+
bgMagentaBright: [105, 49],
|
|
9711
|
+
bgCyanBright: [106, 49],
|
|
9712
|
+
bgWhiteBright: [107, 49]
|
|
9683
9713
|
}
|
|
9684
|
-
|
|
9685
|
-
|
|
9686
|
-
|
|
9687
|
-
|
|
9688
|
-
|
|
9689
|
-
|
|
9690
|
-
|
|
9691
|
-
const
|
|
9692
|
-
|
|
9693
|
-
|
|
9694
|
-
|
|
9695
|
-
|
|
9714
|
+
};
|
|
9715
|
+
var modifierNames = Object.keys(styles.modifier);
|
|
9716
|
+
var foregroundColorNames = Object.keys(styles.color);
|
|
9717
|
+
var backgroundColorNames = Object.keys(styles.bgColor);
|
|
9718
|
+
var colorNames = [...foregroundColorNames, ...backgroundColorNames];
|
|
9719
|
+
function assembleStyles() {
|
|
9720
|
+
const codes = new Map;
|
|
9721
|
+
for (const [groupName, group] of Object.entries(styles)) {
|
|
9722
|
+
for (const [styleName, style] of Object.entries(group)) {
|
|
9723
|
+
styles[styleName] = {
|
|
9724
|
+
open: `\x1B[${style[0]}m`,
|
|
9725
|
+
close: `\x1B[${style[1]}m`
|
|
9726
|
+
};
|
|
9727
|
+
group[styleName] = styles[styleName];
|
|
9728
|
+
codes.set(style[0], style[1]);
|
|
9696
9729
|
}
|
|
9697
|
-
|
|
9698
|
-
|
|
9699
|
-
|
|
9700
|
-
|
|
9701
|
-
workflows.push(workflowYaml);
|
|
9702
|
-
continue;
|
|
9703
|
-
} catch {}
|
|
9704
|
-
try {
|
|
9705
|
-
await access(workflowYml);
|
|
9706
|
-
workflows.push(workflowYml);
|
|
9707
|
-
} catch {}
|
|
9708
|
-
}
|
|
9709
|
-
return workflows.filter((filePath) => matchesPartial(filePath, partial)).sort();
|
|
9710
|
-
}
|
|
9711
|
-
|
|
9712
|
-
// src/commands/complete.ts
|
|
9713
|
-
function parseTarget(value) {
|
|
9714
|
-
if (value === "run-id" || value === "workflow") {
|
|
9715
|
-
return value;
|
|
9730
|
+
Object.defineProperty(styles, groupName, {
|
|
9731
|
+
value: group,
|
|
9732
|
+
enumerable: false
|
|
9733
|
+
});
|
|
9716
9734
|
}
|
|
9717
|
-
|
|
9718
|
-
|
|
9719
|
-
|
|
9720
|
-
class CompleteCommand extends Command {
|
|
9721
|
-
static paths = [["complete"]];
|
|
9722
|
-
target = exports_options.String({
|
|
9723
|
-
name: "target"
|
|
9724
|
-
});
|
|
9725
|
-
partial = exports_options.String({
|
|
9726
|
-
required: false,
|
|
9727
|
-
name: "partial"
|
|
9735
|
+
Object.defineProperty(styles, "codes", {
|
|
9736
|
+
value: codes,
|
|
9737
|
+
enumerable: false
|
|
9728
9738
|
});
|
|
9729
|
-
|
|
9730
|
-
|
|
9731
|
-
|
|
9732
|
-
|
|
9733
|
-
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
9739
|
+
styles.color.close = "\x1B[39m";
|
|
9740
|
+
styles.bgColor.close = "\x1B[49m";
|
|
9741
|
+
styles.color.ansi = wrapAnsi16();
|
|
9742
|
+
styles.color.ansi256 = wrapAnsi256();
|
|
9743
|
+
styles.color.ansi16m = wrapAnsi16m();
|
|
9744
|
+
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
9745
|
+
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
9746
|
+
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
9747
|
+
Object.defineProperties(styles, {
|
|
9748
|
+
rgbToAnsi256: {
|
|
9749
|
+
value(red, green, blue) {
|
|
9750
|
+
if (red === green && green === blue) {
|
|
9751
|
+
if (red < 8) {
|
|
9752
|
+
return 16;
|
|
9753
|
+
}
|
|
9754
|
+
if (red > 248) {
|
|
9755
|
+
return 231;
|
|
9756
|
+
}
|
|
9757
|
+
return Math.round((red - 8) / 247 * 24) + 232;
|
|
9758
|
+
}
|
|
9759
|
+
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
|
|
9760
|
+
},
|
|
9761
|
+
enumerable: false
|
|
9762
|
+
},
|
|
9763
|
+
hexToRgb: {
|
|
9764
|
+
value(hex) {
|
|
9765
|
+
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
9766
|
+
if (!matches) {
|
|
9767
|
+
return [0, 0, 0];
|
|
9768
|
+
}
|
|
9769
|
+
let [colorString] = matches;
|
|
9770
|
+
if (colorString.length === 3) {
|
|
9771
|
+
colorString = [...colorString].map((character) => character + character).join("");
|
|
9772
|
+
}
|
|
9773
|
+
const integer = Number.parseInt(colorString, 16);
|
|
9774
|
+
return [
|
|
9775
|
+
integer >> 16 & 255,
|
|
9776
|
+
integer >> 8 & 255,
|
|
9777
|
+
integer & 255
|
|
9778
|
+
];
|
|
9779
|
+
},
|
|
9780
|
+
enumerable: false
|
|
9781
|
+
},
|
|
9782
|
+
hexToAnsi256: {
|
|
9783
|
+
value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
|
|
9784
|
+
enumerable: false
|
|
9785
|
+
},
|
|
9786
|
+
ansi256ToAnsi: {
|
|
9787
|
+
value(code) {
|
|
9788
|
+
if (code < 8) {
|
|
9789
|
+
return 30 + code;
|
|
9790
|
+
}
|
|
9791
|
+
if (code < 16) {
|
|
9792
|
+
return 90 + (code - 8);
|
|
9793
|
+
}
|
|
9794
|
+
let red;
|
|
9795
|
+
let green;
|
|
9796
|
+
let blue;
|
|
9797
|
+
if (code >= 232) {
|
|
9798
|
+
red = ((code - 232) * 10 + 8) / 255;
|
|
9799
|
+
green = red;
|
|
9800
|
+
blue = red;
|
|
9801
|
+
} else {
|
|
9802
|
+
code -= 16;
|
|
9803
|
+
const remainder = code % 36;
|
|
9804
|
+
red = Math.floor(code / 36) / 5;
|
|
9805
|
+
green = Math.floor(remainder / 6) / 5;
|
|
9806
|
+
blue = remainder % 6 / 5;
|
|
9807
|
+
}
|
|
9808
|
+
const value = Math.max(red, green, blue) * 2;
|
|
9809
|
+
if (value === 0) {
|
|
9810
|
+
return 30;
|
|
9811
|
+
}
|
|
9812
|
+
let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
|
|
9813
|
+
if (value === 2) {
|
|
9814
|
+
result += 60;
|
|
9815
|
+
}
|
|
9816
|
+
return result;
|
|
9817
|
+
},
|
|
9818
|
+
enumerable: false
|
|
9819
|
+
},
|
|
9820
|
+
rgbToAnsi: {
|
|
9821
|
+
value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
|
|
9822
|
+
enumerable: false
|
|
9823
|
+
},
|
|
9824
|
+
hexToAnsi: {
|
|
9825
|
+
value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
|
|
9826
|
+
enumerable: false
|
|
9737
9827
|
}
|
|
9738
|
-
|
|
9739
|
-
|
|
9828
|
+
});
|
|
9829
|
+
return styles;
|
|
9740
9830
|
}
|
|
9831
|
+
var ansiStyles = assembleStyles();
|
|
9832
|
+
var ansi_styles_default = ansiStyles;
|
|
9741
9833
|
|
|
9742
|
-
//
|
|
9743
|
-
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
|
|
9750
|
-
return
|
|
9751
|
-
"_rex_complete() {",
|
|
9752
|
-
" local cur prev",
|
|
9753
|
-
" COMPREPLY=()",
|
|
9754
|
-
' cur="${COMP_WORDS[COMP_CWORD]}"',
|
|
9755
|
-
' prev="${COMP_WORDS[COMP_CWORD-1]}"',
|
|
9756
|
-
"",
|
|
9757
|
-
" if [[ ${COMP_CWORD} -eq 1 ]]; then",
|
|
9758
|
-
' COMPREPLY=( $(compgen -W "install run continue complete completion --help --version" -- "${cur}") )',
|
|
9759
|
-
" return 0",
|
|
9760
|
-
" fi",
|
|
9761
|
-
"",
|
|
9762
|
-
' if [[ "${prev}" == "continue" ]]; then',
|
|
9763
|
-
' COMPREPLY=( $(rmr complete run-id "${cur}") )',
|
|
9764
|
-
" return 0",
|
|
9765
|
-
" fi",
|
|
9766
|
-
"",
|
|
9767
|
-
' if [[ "${prev}" == "run" ]]; then',
|
|
9768
|
-
' COMPREPLY=( $(rmr complete workflow "${cur}") )',
|
|
9769
|
-
" return 0",
|
|
9770
|
-
" fi",
|
|
9771
|
-
"",
|
|
9772
|
-
' if [[ "${prev}" == "install" ]]; then',
|
|
9773
|
-
' COMPREPLY=( $(compgen -W "feature-dev" -- "${cur}") )',
|
|
9774
|
-
" return 0",
|
|
9775
|
-
" fi",
|
|
9776
|
-
"}",
|
|
9777
|
-
"complete -F _rex_complete rmr"
|
|
9778
|
-
].join(`
|
|
9779
|
-
`);
|
|
9780
|
-
}
|
|
9781
|
-
function zshScript() {
|
|
9782
|
-
return [
|
|
9783
|
-
"#compdef rmr",
|
|
9784
|
-
"_rex_complete() {",
|
|
9785
|
-
" local -a subcommands",
|
|
9786
|
-
" subcommands=(install run continue complete completion)",
|
|
9787
|
-
"",
|
|
9788
|
-
" if (( CURRENT == 2 )); then",
|
|
9789
|
-
" _describe 'command' subcommands",
|
|
9790
|
-
" return",
|
|
9791
|
-
" fi",
|
|
9792
|
-
"",
|
|
9793
|
-
" if [[ ${words[2]} == continue && $CURRENT -eq 3 ]]; then",
|
|
9794
|
-
' compadd -- $(rmr complete run-id "${words[CURRENT]}")',
|
|
9795
|
-
" return",
|
|
9796
|
-
" fi",
|
|
9797
|
-
"",
|
|
9798
|
-
" if [[ ${words[2]} == run && $CURRENT -eq 3 ]]; then",
|
|
9799
|
-
' compadd -- $(rmr complete workflow "${words[CURRENT]}")',
|
|
9800
|
-
" return",
|
|
9801
|
-
" fi",
|
|
9802
|
-
"",
|
|
9803
|
-
" if [[ ${words[2]} == install && $CURRENT -eq 3 ]]; then",
|
|
9804
|
-
" compadd -- feature-dev",
|
|
9805
|
-
" return",
|
|
9806
|
-
" fi",
|
|
9807
|
-
"}",
|
|
9808
|
-
"compdef _rex_complete rmr"
|
|
9809
|
-
].join(`
|
|
9810
|
-
`);
|
|
9834
|
+
// node_modules/chalk/source/vendor/supports-color/index.js
|
|
9835
|
+
import process2 from "node:process";
|
|
9836
|
+
import os from "node:os";
|
|
9837
|
+
import tty2 from "node:tty";
|
|
9838
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
|
|
9839
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
9840
|
+
const position = argv.indexOf(prefix + flag);
|
|
9841
|
+
const terminatorPosition = argv.indexOf("--");
|
|
9842
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
9811
9843
|
}
|
|
9812
|
-
|
|
9813
|
-
|
|
9814
|
-
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
"function __rex_complete_workflow",
|
|
9819
|
-
" rmr complete workflow (commandline -ct)",
|
|
9820
|
-
"end",
|
|
9821
|
-
"",
|
|
9822
|
-
"complete -c rmr -f",
|
|
9823
|
-
"complete -c rmr -n '__fish_use_subcommand' -a 'install run continue complete completion'",
|
|
9824
|
-
"complete -c rmr -n '__fish_seen_subcommand_from continue' -a '(__rex_complete_run_id)'",
|
|
9825
|
-
"complete -c rmr -n '__fish_seen_subcommand_from run' -a '(__rex_complete_workflow)'",
|
|
9826
|
-
"complete -c rmr -n '__fish_seen_subcommand_from install' -a 'feature-dev'"
|
|
9827
|
-
].join(`
|
|
9828
|
-
`);
|
|
9844
|
+
var { env } = process2;
|
|
9845
|
+
var flagForceColor;
|
|
9846
|
+
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
9847
|
+
flagForceColor = 0;
|
|
9848
|
+
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
9849
|
+
flagForceColor = 1;
|
|
9829
9850
|
}
|
|
9830
|
-
|
|
9831
|
-
|
|
9832
|
-
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
|
|
9837
|
-
|
|
9838
|
-
|
|
9839
|
-
["Show Zsh completion script", "$0 completion zsh"],
|
|
9840
|
-
["Show Fish completion script", "$0 completion fish"]
|
|
9841
|
-
]
|
|
9842
|
-
});
|
|
9843
|
-
shell = exports_options.String({
|
|
9844
|
-
name: "shell"
|
|
9845
|
-
});
|
|
9846
|
-
async execute() {
|
|
9847
|
-
const shell = parseShell(this.shell);
|
|
9848
|
-
const script = shell === "bash" ? bashScript() : shell === "zsh" ? zshScript() : fishScript();
|
|
9849
|
-
process.stdout.write(`${script}
|
|
9850
|
-
`);
|
|
9851
|
-
return 0;
|
|
9851
|
+
function envForceColor() {
|
|
9852
|
+
if ("FORCE_COLOR" in env) {
|
|
9853
|
+
if (env.FORCE_COLOR === "true") {
|
|
9854
|
+
return 1;
|
|
9855
|
+
}
|
|
9856
|
+
if (env.FORCE_COLOR === "false") {
|
|
9857
|
+
return 0;
|
|
9858
|
+
}
|
|
9859
|
+
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
9852
9860
|
}
|
|
9853
9861
|
}
|
|
9854
|
-
|
|
9855
|
-
|
|
9856
|
-
|
|
9857
|
-
import { resolve as resolve3 } from "node:path";
|
|
9858
|
-
function pad(input) {
|
|
9859
|
-
return String(input).padStart(2, "0");
|
|
9860
|
-
}
|
|
9861
|
-
function generateRunId(now = new Date) {
|
|
9862
|
-
const yyyy = now.getUTCFullYear();
|
|
9863
|
-
const mm = pad(now.getUTCMonth() + 1);
|
|
9864
|
-
const dd = pad(now.getUTCDate());
|
|
9865
|
-
const hh = pad(now.getUTCHours());
|
|
9866
|
-
const min = pad(now.getUTCMinutes());
|
|
9867
|
-
const sec = pad(now.getUTCSeconds());
|
|
9868
|
-
return `${yyyy}${mm}${dd}-${hh}${min}${sec}Z`;
|
|
9869
|
-
}
|
|
9870
|
-
function runFilePath(config, runId) {
|
|
9871
|
-
return resolve3(config.runsDir, `${runId}.json`);
|
|
9872
|
-
}
|
|
9873
|
-
function createInitialRunState(options) {
|
|
9874
|
-
const firstStep = options.workflow.steps[0];
|
|
9875
|
-
if (!firstStep) {
|
|
9876
|
-
throw new StorageError("Cannot create run state without at least one workflow step.");
|
|
9862
|
+
function translateLevel(level) {
|
|
9863
|
+
if (level === 0) {
|
|
9864
|
+
return false;
|
|
9877
9865
|
}
|
|
9878
9866
|
return {
|
|
9879
|
-
|
|
9880
|
-
|
|
9881
|
-
|
|
9882
|
-
|
|
9883
|
-
context: {
|
|
9884
|
-
task: options.task,
|
|
9885
|
-
...options.vars
|
|
9886
|
-
},
|
|
9887
|
-
last_harness: {
|
|
9888
|
-
name: resolveHarnessForStep(options.workflow, firstStep.agent),
|
|
9889
|
-
binary: resolveHarnessForStep(options.workflow, firstStep.agent),
|
|
9890
|
-
session_id: null
|
|
9891
|
-
},
|
|
9892
|
-
step_history: [],
|
|
9893
|
-
updated_at: new Date().toISOString()
|
|
9867
|
+
level,
|
|
9868
|
+
hasBasic: true,
|
|
9869
|
+
has256: level >= 2,
|
|
9870
|
+
has16m: level >= 3
|
|
9894
9871
|
};
|
|
9895
9872
|
}
|
|
9896
|
-
function
|
|
9897
|
-
const
|
|
9898
|
-
if (
|
|
9899
|
-
|
|
9873
|
+
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
9874
|
+
const noFlagForceColor = envForceColor();
|
|
9875
|
+
if (noFlagForceColor !== undefined) {
|
|
9876
|
+
flagForceColor = noFlagForceColor;
|
|
9900
9877
|
}
|
|
9901
|
-
|
|
9902
|
-
|
|
9903
|
-
|
|
9904
|
-
|
|
9905
|
-
|
|
9906
|
-
|
|
9907
|
-
|
|
9908
|
-
}, null, 2);
|
|
9909
|
-
await writeFile(path, `${payload}
|
|
9910
|
-
`, "utf8");
|
|
9911
|
-
return path;
|
|
9912
|
-
}
|
|
9913
|
-
async function loadRunState(config, runId) {
|
|
9914
|
-
const path = runFilePath(config, runId);
|
|
9915
|
-
try {
|
|
9916
|
-
const raw = await readFile(path, "utf8");
|
|
9917
|
-
const parsed = JSON.parse(raw);
|
|
9918
|
-
if (!parsed || typeof parsed !== "object" || parsed.run_id !== runId) {
|
|
9919
|
-
throw new StorageError(`Run state file is invalid for run id "${runId}".`);
|
|
9920
|
-
}
|
|
9921
|
-
if (!Array.isArray(parsed.step_history)) {
|
|
9922
|
-
parsed.step_history = [];
|
|
9878
|
+
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
9879
|
+
if (forceColor === 0) {
|
|
9880
|
+
return 0;
|
|
9881
|
+
}
|
|
9882
|
+
if (sniffFlags) {
|
|
9883
|
+
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
9884
|
+
return 3;
|
|
9923
9885
|
}
|
|
9924
|
-
|
|
9925
|
-
|
|
9926
|
-
if (error instanceof StorageError) {
|
|
9927
|
-
throw error;
|
|
9886
|
+
if (hasFlag("color=256")) {
|
|
9887
|
+
return 2;
|
|
9928
9888
|
}
|
|
9929
|
-
throw new StorageError(`Failed to load run state for "${runId}".`);
|
|
9930
9889
|
}
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
// src/lib/prompt-composer.ts
|
|
9934
|
-
import { readFile as readFile2 } from "node:fs/promises";
|
|
9935
|
-
import { dirname, resolve as resolve4 } from "node:path";
|
|
9936
|
-
function stripFrontmatter(content) {
|
|
9937
|
-
const match = content.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/);
|
|
9938
|
-
return match ? content.slice(match[0].length) : content;
|
|
9939
|
-
}
|
|
9940
|
-
async function loadAgentPrompt(workflowPath, promptFileName) {
|
|
9941
|
-
const promptPath = resolve4(dirname(workflowPath), promptFileName);
|
|
9942
|
-
try {
|
|
9943
|
-
const raw = await readFile2(promptPath, "utf8");
|
|
9944
|
-
return stripFrontmatter(raw);
|
|
9945
|
-
} catch {
|
|
9946
|
-
throw new ConfigError(`Agent prompt file not found: ${promptPath}`);
|
|
9890
|
+
if ("TF_BUILD" in env && "AGENT_NAME" in env) {
|
|
9891
|
+
return 1;
|
|
9947
9892
|
}
|
|
9948
|
-
|
|
9949
|
-
|
|
9950
|
-
return `${agentPrompt.trimEnd()}
|
|
9951
|
-
|
|
9952
|
-
${stepInput.trim()}`;
|
|
9953
|
-
}
|
|
9954
|
-
|
|
9955
|
-
// src/lib/harness-adapters.ts
|
|
9956
|
-
function createPassthroughParser() {
|
|
9957
|
-
return (line) => ({ text: line + `
|
|
9958
|
-
` });
|
|
9959
|
-
}
|
|
9960
|
-
function withModelArgs(model, args) {
|
|
9961
|
-
if (!model) {
|
|
9962
|
-
return args;
|
|
9893
|
+
if (haveStream && !streamIsTTY && forceColor === undefined) {
|
|
9894
|
+
return 0;
|
|
9963
9895
|
}
|
|
9964
|
-
|
|
9965
|
-
|
|
9966
|
-
|
|
9967
|
-
|
|
9968
|
-
|
|
9969
|
-
|
|
9970
|
-
|
|
9971
|
-
|
|
9972
|
-
let currentBlockIndex = null;
|
|
9973
|
-
return (line) => {
|
|
9974
|
-
if (!line.trim()) {
|
|
9975
|
-
return null;
|
|
9896
|
+
const min = forceColor || 0;
|
|
9897
|
+
if (env.TERM === "dumb") {
|
|
9898
|
+
return min;
|
|
9899
|
+
}
|
|
9900
|
+
if (process2.platform === "win32") {
|
|
9901
|
+
const osRelease = os.release().split(".");
|
|
9902
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
9903
|
+
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
9976
9904
|
}
|
|
9977
|
-
|
|
9978
|
-
|
|
9979
|
-
|
|
9980
|
-
|
|
9981
|
-
return
|
|
9905
|
+
return 1;
|
|
9906
|
+
}
|
|
9907
|
+
if ("CI" in env) {
|
|
9908
|
+
if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => (key in env))) {
|
|
9909
|
+
return 3;
|
|
9982
9910
|
}
|
|
9983
|
-
|
|
9984
|
-
|
|
9985
|
-
|
|
9986
|
-
|
|
9987
|
-
|
|
9988
|
-
|
|
9989
|
-
|
|
9990
|
-
|
|
9991
|
-
|
|
9992
|
-
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
|
|
9998
|
-
|
|
9999
|
-
|
|
10000
|
-
|
|
10001
|
-
|
|
10002
|
-
|
|
10003
|
-
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
9911
|
+
if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => (sign in env)) || env.CI_NAME === "codeship") {
|
|
9912
|
+
return 1;
|
|
9913
|
+
}
|
|
9914
|
+
return min;
|
|
9915
|
+
}
|
|
9916
|
+
if ("TEAMCITY_VERSION" in env) {
|
|
9917
|
+
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
9918
|
+
}
|
|
9919
|
+
if (env.COLORTERM === "truecolor") {
|
|
9920
|
+
return 3;
|
|
9921
|
+
}
|
|
9922
|
+
if (env.TERM === "xterm-kitty") {
|
|
9923
|
+
return 3;
|
|
9924
|
+
}
|
|
9925
|
+
if (env.TERM === "xterm-ghostty") {
|
|
9926
|
+
return 3;
|
|
9927
|
+
}
|
|
9928
|
+
if (env.TERM === "wezterm") {
|
|
9929
|
+
return 3;
|
|
9930
|
+
}
|
|
9931
|
+
if ("TERM_PROGRAM" in env) {
|
|
9932
|
+
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
9933
|
+
switch (env.TERM_PROGRAM) {
|
|
9934
|
+
case "iTerm.app": {
|
|
9935
|
+
return version >= 3 ? 3 : 2;
|
|
10007
9936
|
}
|
|
10008
|
-
|
|
10009
|
-
|
|
10010
|
-
const result = {
|
|
10011
|
-
text: "",
|
|
10012
|
-
sessionId,
|
|
10013
|
-
toolName: currentToolName,
|
|
10014
|
-
toolInput: currentToolInput || undefined
|
|
10015
|
-
};
|
|
10016
|
-
currentToolName = null;
|
|
10017
|
-
currentToolInput = "";
|
|
10018
|
-
currentBlockIndex = null;
|
|
10019
|
-
return result;
|
|
10020
|
-
}
|
|
9937
|
+
case "Apple_Terminal": {
|
|
9938
|
+
return 2;
|
|
10021
9939
|
}
|
|
10022
|
-
return sessionId ? { text: "", sessionId } : null;
|
|
10023
|
-
}
|
|
10024
|
-
if (type === "result") {
|
|
10025
|
-
return sessionId ? { text: "", sessionId } : null;
|
|
10026
9940
|
}
|
|
10027
|
-
|
|
10028
|
-
|
|
9941
|
+
}
|
|
9942
|
+
if (/-256(color)?$/i.test(env.TERM)) {
|
|
9943
|
+
return 2;
|
|
9944
|
+
}
|
|
9945
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
9946
|
+
return 1;
|
|
9947
|
+
}
|
|
9948
|
+
if ("COLORTERM" in env) {
|
|
9949
|
+
return 1;
|
|
9950
|
+
}
|
|
9951
|
+
return min;
|
|
9952
|
+
}
|
|
9953
|
+
function createSupportsColor(stream, options = {}) {
|
|
9954
|
+
const level = _supportsColor(stream, {
|
|
9955
|
+
streamIsTTY: stream && stream.isTTY,
|
|
9956
|
+
...options
|
|
9957
|
+
});
|
|
9958
|
+
return translateLevel(level);
|
|
9959
|
+
}
|
|
9960
|
+
var supportsColor = {
|
|
9961
|
+
stdout: createSupportsColor({ isTTY: tty2.isatty(1) }),
|
|
9962
|
+
stderr: createSupportsColor({ isTTY: tty2.isatty(2) })
|
|
9963
|
+
};
|
|
9964
|
+
var supports_color_default = supportsColor;
|
|
9965
|
+
|
|
9966
|
+
// node_modules/chalk/source/utilities.js
|
|
9967
|
+
function stringReplaceAll(string, substring, replacer) {
|
|
9968
|
+
let index = string.indexOf(substring);
|
|
9969
|
+
if (index === -1) {
|
|
9970
|
+
return string;
|
|
9971
|
+
}
|
|
9972
|
+
const substringLength = substring.length;
|
|
9973
|
+
let endIndex = 0;
|
|
9974
|
+
let returnValue = "";
|
|
9975
|
+
do {
|
|
9976
|
+
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
9977
|
+
endIndex = index + substringLength;
|
|
9978
|
+
index = string.indexOf(substring, endIndex);
|
|
9979
|
+
} while (index !== -1);
|
|
9980
|
+
returnValue += string.slice(endIndex);
|
|
9981
|
+
return returnValue;
|
|
9982
|
+
}
|
|
9983
|
+
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
9984
|
+
let endIndex = 0;
|
|
9985
|
+
let returnValue = "";
|
|
9986
|
+
do {
|
|
9987
|
+
const gotCR = string[index - 1] === "\r";
|
|
9988
|
+
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? `\r
|
|
9989
|
+
` : `
|
|
9990
|
+
`) + postfix;
|
|
9991
|
+
endIndex = index + 1;
|
|
9992
|
+
index = string.indexOf(`
|
|
9993
|
+
`, endIndex);
|
|
9994
|
+
} while (index !== -1);
|
|
9995
|
+
returnValue += string.slice(endIndex);
|
|
9996
|
+
return returnValue;
|
|
9997
|
+
}
|
|
9998
|
+
|
|
9999
|
+
// node_modules/chalk/source/index.js
|
|
10000
|
+
var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
|
|
10001
|
+
var GENERATOR = Symbol("GENERATOR");
|
|
10002
|
+
var STYLER = Symbol("STYLER");
|
|
10003
|
+
var IS_EMPTY = Symbol("IS_EMPTY");
|
|
10004
|
+
var levelMapping = [
|
|
10005
|
+
"ansi",
|
|
10006
|
+
"ansi",
|
|
10007
|
+
"ansi256",
|
|
10008
|
+
"ansi16m"
|
|
10009
|
+
];
|
|
10010
|
+
var styles2 = Object.create(null);
|
|
10011
|
+
var applyOptions = (object, options = {}) => {
|
|
10012
|
+
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
|
|
10013
|
+
throw new Error("The `level` option should be an integer from 0 to 3");
|
|
10014
|
+
}
|
|
10015
|
+
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
10016
|
+
object.level = options.level === undefined ? colorLevel : options.level;
|
|
10017
|
+
};
|
|
10018
|
+
var chalkFactory = (options) => {
|
|
10019
|
+
const chalk = (...strings) => strings.join(" ");
|
|
10020
|
+
applyOptions(chalk, options);
|
|
10021
|
+
Object.setPrototypeOf(chalk, createChalk.prototype);
|
|
10022
|
+
return chalk;
|
|
10023
|
+
};
|
|
10024
|
+
function createChalk(options) {
|
|
10025
|
+
return chalkFactory(options);
|
|
10026
|
+
}
|
|
10027
|
+
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
|
10028
|
+
for (const [styleName, style] of Object.entries(ansi_styles_default)) {
|
|
10029
|
+
styles2[styleName] = {
|
|
10030
|
+
get() {
|
|
10031
|
+
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
|
|
10032
|
+
Object.defineProperty(this, styleName, { value: builder });
|
|
10033
|
+
return builder;
|
|
10029
10034
|
}
|
|
10030
|
-
return null;
|
|
10031
10035
|
};
|
|
10032
10036
|
}
|
|
10033
|
-
|
|
10034
|
-
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
|
|
10038
|
-
|
|
10039
|
-
|
|
10040
|
-
|
|
10041
|
-
|
|
10042
|
-
|
|
10043
|
-
|
|
10044
|
-
return { binary: "claude", args: withModelArgs(options.model, base) };
|
|
10045
|
-
},
|
|
10046
|
-
createStreamParser: createClaudeStreamParser,
|
|
10047
|
-
resumeTemplate(sessionId) {
|
|
10048
|
-
return `claude --resume ${sessionId}`;
|
|
10049
|
-
}
|
|
10050
|
-
},
|
|
10051
|
-
opencode: {
|
|
10052
|
-
name: "opencode",
|
|
10053
|
-
buildRunCommand(prompt, options) {
|
|
10054
|
-
const args = ["run", prompt];
|
|
10055
|
-
return { binary: "opencode", args: withModelArgs(options.model, args) };
|
|
10056
|
-
},
|
|
10057
|
-
buildResumeCommand(sessionId, prompt, options) {
|
|
10058
|
-
const args = ["--resume", sessionId, "run", prompt];
|
|
10059
|
-
return { binary: "opencode", args: withModelArgs(options.model, args) };
|
|
10060
|
-
},
|
|
10061
|
-
createStreamParser: createPassthroughParser,
|
|
10062
|
-
resumeTemplate(sessionId) {
|
|
10063
|
-
return `opencode --resume ${sessionId}`;
|
|
10064
|
-
}
|
|
10065
|
-
},
|
|
10066
|
-
codex: {
|
|
10067
|
-
name: "codex",
|
|
10068
|
-
buildRunCommand(prompt, options) {
|
|
10069
|
-
const auto = options.allowAll ? ["--full-auto"] : [];
|
|
10070
|
-
const args = [...auto, "exec", prompt];
|
|
10071
|
-
return { binary: "codex", args: withModelArgs(options.model, args) };
|
|
10072
|
-
},
|
|
10073
|
-
buildResumeCommand(sessionId, prompt, options) {
|
|
10074
|
-
const args = ["exec", "resume", sessionId, prompt];
|
|
10075
|
-
return { binary: "codex", args: withModelArgs(options.model, args) };
|
|
10076
|
-
},
|
|
10077
|
-
createStreamParser: createPassthroughParser,
|
|
10078
|
-
resumeTemplate(sessionId) {
|
|
10079
|
-
return `codex exec resume ${sessionId} "<prompt>"`;
|
|
10037
|
+
styles2.visible = {
|
|
10038
|
+
get() {
|
|
10039
|
+
const builder = createBuilder(this, this[STYLER], true);
|
|
10040
|
+
Object.defineProperty(this, "visible", { value: builder });
|
|
10041
|
+
return builder;
|
|
10042
|
+
}
|
|
10043
|
+
};
|
|
10044
|
+
var getModelAnsi = (model, level, type, ...arguments_) => {
|
|
10045
|
+
if (model === "rgb") {
|
|
10046
|
+
if (level === "ansi16m") {
|
|
10047
|
+
return ansi_styles_default[type].ansi16m(...arguments_);
|
|
10080
10048
|
}
|
|
10081
|
-
|
|
10082
|
-
|
|
10083
|
-
name: "copilot",
|
|
10084
|
-
buildRunCommand(prompt, options) {
|
|
10085
|
-
const auto = options.allowAll ? ["--allow-all", "--no-ask-user"] : [];
|
|
10086
|
-
const args = [...auto, "-p", prompt];
|
|
10087
|
-
return { binary: "copilot", args: withModelArgs(options.model, args) };
|
|
10088
|
-
},
|
|
10089
|
-
buildResumeCommand(_sessionId, prompt, options) {
|
|
10090
|
-
const args = ["-p", prompt];
|
|
10091
|
-
return { binary: "copilot", args: withModelArgs(options.model, args) };
|
|
10092
|
-
},
|
|
10093
|
-
createStreamParser: createPassthroughParser,
|
|
10094
|
-
resumeTemplate(sessionId) {
|
|
10095
|
-
return `copilot --resume ${sessionId}`;
|
|
10049
|
+
if (level === "ansi256") {
|
|
10050
|
+
return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
|
|
10096
10051
|
}
|
|
10052
|
+
return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
|
|
10097
10053
|
}
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
const adapter = adapters[name];
|
|
10101
|
-
if (!adapter) {
|
|
10102
|
-
throw new ValidationError(`Unknown harness "${name}".`);
|
|
10054
|
+
if (model === "hex") {
|
|
10055
|
+
return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
|
|
10103
10056
|
}
|
|
10104
|
-
return
|
|
10105
|
-
}
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
|
|
10109
|
-
|
|
10110
|
-
|
|
10111
|
-
|
|
10112
|
-
|
|
10113
|
-
|
|
10114
|
-
|
|
10115
|
-
|
|
10116
|
-
|
|
10117
|
-
|
|
10118
|
-
|
|
10119
|
-
|
|
10120
|
-
|
|
10121
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
10124
|
-
|
|
10125
|
-
|
|
10057
|
+
return ansi_styles_default[type][model](...arguments_);
|
|
10058
|
+
};
|
|
10059
|
+
var usedModels = ["rgb", "hex", "ansi256"];
|
|
10060
|
+
for (const model of usedModels) {
|
|
10061
|
+
styles2[model] = {
|
|
10062
|
+
get() {
|
|
10063
|
+
const { level } = this;
|
|
10064
|
+
return function(...arguments_) {
|
|
10065
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
|
|
10066
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
10067
|
+
};
|
|
10068
|
+
}
|
|
10069
|
+
};
|
|
10070
|
+
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
10071
|
+
styles2[bgModel] = {
|
|
10072
|
+
get() {
|
|
10073
|
+
const { level } = this;
|
|
10074
|
+
return function(...arguments_) {
|
|
10075
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
|
|
10076
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
10077
|
+
};
|
|
10078
|
+
}
|
|
10079
|
+
};
|
|
10080
|
+
}
|
|
10081
|
+
var proto = Object.defineProperties(() => {}, {
|
|
10082
|
+
...styles2,
|
|
10083
|
+
level: {
|
|
10084
|
+
enumerable: true,
|
|
10085
|
+
get() {
|
|
10086
|
+
return this[GENERATOR].level;
|
|
10087
|
+
},
|
|
10088
|
+
set(level) {
|
|
10089
|
+
this[GENERATOR].level = level;
|
|
10090
|
+
}
|
|
10091
|
+
}
|
|
10092
|
+
});
|
|
10093
|
+
var createStyler = (open, close, parent) => {
|
|
10094
|
+
let openAll;
|
|
10095
|
+
let closeAll;
|
|
10096
|
+
if (parent === undefined) {
|
|
10097
|
+
openAll = open;
|
|
10098
|
+
closeAll = close;
|
|
10099
|
+
} else {
|
|
10100
|
+
openAll = parent.openAll + open;
|
|
10101
|
+
closeAll = close + parent.closeAll;
|
|
10102
|
+
}
|
|
10103
|
+
return {
|
|
10104
|
+
open,
|
|
10105
|
+
close,
|
|
10106
|
+
openAll,
|
|
10107
|
+
closeAll,
|
|
10108
|
+
parent
|
|
10109
|
+
};
|
|
10110
|
+
};
|
|
10111
|
+
var createBuilder = (self, _styler, _isEmpty) => {
|
|
10112
|
+
const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
|
|
10113
|
+
Object.setPrototypeOf(builder, proto);
|
|
10114
|
+
builder[GENERATOR] = self;
|
|
10115
|
+
builder[STYLER] = _styler;
|
|
10116
|
+
builder[IS_EMPTY] = _isEmpty;
|
|
10117
|
+
return builder;
|
|
10118
|
+
};
|
|
10119
|
+
var applyStyle = (self, string) => {
|
|
10120
|
+
if (self.level <= 0 || !string) {
|
|
10121
|
+
return self[IS_EMPTY] ? "" : string;
|
|
10122
|
+
}
|
|
10123
|
+
let styler = self[STYLER];
|
|
10124
|
+
if (styler === undefined) {
|
|
10125
|
+
return string;
|
|
10126
|
+
}
|
|
10127
|
+
const { openAll, closeAll } = styler;
|
|
10128
|
+
if (string.includes("\x1B")) {
|
|
10129
|
+
while (styler !== undefined) {
|
|
10130
|
+
string = stringReplaceAll(string, styler.close, styler.open);
|
|
10131
|
+
styler = styler.parent;
|
|
10132
|
+
}
|
|
10133
|
+
}
|
|
10134
|
+
const lfIndex = string.indexOf(`
|
|
10135
|
+
`);
|
|
10136
|
+
if (lfIndex !== -1) {
|
|
10137
|
+
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
|
10138
|
+
}
|
|
10139
|
+
return openAll + string + closeAll;
|
|
10140
|
+
};
|
|
10141
|
+
Object.defineProperties(createChalk.prototype, styles2);
|
|
10142
|
+
var chalk = createChalk();
|
|
10143
|
+
var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
10144
|
+
var source_default = chalk;
|
|
10145
|
+
|
|
10146
|
+
// src/lib/ui.ts
|
|
10147
|
+
import * as readline from "node:readline";
|
|
10148
|
+
|
|
10149
|
+
// src/lib/binary-name.ts
|
|
10150
|
+
import { basename } from "node:path";
|
|
10151
|
+
function detectBinaryName() {
|
|
10152
|
+
const invokedPath = process.argv[1];
|
|
10153
|
+
const invokedName = invokedPath ? basename(invokedPath) : "";
|
|
10154
|
+
if (invokedName !== "" && !invokedName.endsWith(".js") && !invokedName.endsWith(".ts")) {
|
|
10155
|
+
return invokedName;
|
|
10156
|
+
}
|
|
10157
|
+
return "rmr";
|
|
10158
|
+
}
|
|
10159
|
+
var binaryName = detectBinaryName();
|
|
10160
|
+
|
|
10161
|
+
// src/lib/ui.ts
|
|
10162
|
+
var isTTY = process.stdout.isTTY === true;
|
|
10163
|
+
function getTerminalWidth() {
|
|
10164
|
+
return process.stdout.columns ?? 80;
|
|
10165
|
+
}
|
|
10166
|
+
function getBoxWidth() {
|
|
10167
|
+
const termWidth = getTerminalWidth();
|
|
10168
|
+
return Math.max(40, termWidth - 2);
|
|
10169
|
+
}
|
|
10170
|
+
function truncate(text, maxLength) {
|
|
10171
|
+
if (text.length <= maxLength) {
|
|
10172
|
+
return text;
|
|
10173
|
+
}
|
|
10174
|
+
return text.slice(0, maxLength - 3) + "...";
|
|
10175
|
+
}
|
|
10176
|
+
function wrapText(text, maxWidth) {
|
|
10177
|
+
if (text.length <= maxWidth) {
|
|
10178
|
+
return [text];
|
|
10179
|
+
}
|
|
10180
|
+
const lines = [];
|
|
10181
|
+
let remaining = text;
|
|
10182
|
+
while (remaining.length > maxWidth) {
|
|
10183
|
+
let breakAt = remaining.lastIndexOf(" ", maxWidth);
|
|
10184
|
+
if (breakAt <= 0) {
|
|
10185
|
+
breakAt = maxWidth;
|
|
10186
|
+
}
|
|
10187
|
+
lines.push(remaining.slice(0, breakAt));
|
|
10188
|
+
remaining = remaining.slice(breakAt).trimStart();
|
|
10189
|
+
}
|
|
10190
|
+
if (remaining) {
|
|
10191
|
+
lines.push(remaining);
|
|
10192
|
+
}
|
|
10193
|
+
return lines;
|
|
10194
|
+
}
|
|
10195
|
+
function stripAnsi(text) {
|
|
10196
|
+
return text.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").replace(/\x1b\][^\x07]*(?:\x07|\x1b\\)/g, "");
|
|
10197
|
+
}
|
|
10198
|
+
function displayWidth(text) {
|
|
10199
|
+
return Array.from(text).length;
|
|
10200
|
+
}
|
|
10201
|
+
var ui = {
|
|
10202
|
+
get isTTY() {
|
|
10203
|
+
return isTTY;
|
|
10204
|
+
},
|
|
10205
|
+
workflowHeader(info) {
|
|
10206
|
+
const line = isTTY ? "─" : "-";
|
|
10207
|
+
const corner = {
|
|
10208
|
+
tl: isTTY ? "╭" : "+",
|
|
10209
|
+
tr: isTTY ? "╮" : "+",
|
|
10210
|
+
bl: isTTY ? "╰" : "+",
|
|
10211
|
+
br: isTTY ? "╯" : "+"
|
|
10212
|
+
};
|
|
10213
|
+
const width = getBoxWidth();
|
|
10214
|
+
const contentWidth = width - 4;
|
|
10215
|
+
const border = line.repeat(width - 2);
|
|
10216
|
+
const labelWidth = 10;
|
|
10217
|
+
const valueWidth = contentWidth - labelWidth;
|
|
10218
|
+
const formatLine = (label, value) => {
|
|
10219
|
+
const paddedLabel = label ? `${label}:`.padEnd(labelWidth) : " ".repeat(labelWidth);
|
|
10220
|
+
const truncatedValue = truncate(value, valueWidth);
|
|
10221
|
+
return `${paddedLabel}${truncatedValue}`.padEnd(contentWidth);
|
|
10222
|
+
};
|
|
10223
|
+
process.stdout.write(`
|
|
10224
|
+
`);
|
|
10225
|
+
process.stdout.write(isTTY ? source_default.cyan(`${corner.tl}${line} ${info.title} ${border.slice(info.title.length + 3)}${corner.tr}
|
|
10226
|
+
`) : `${corner.tl}${line} ${info.title} ${border.slice(info.title.length + 3)}${corner.tr}
|
|
10227
|
+
`);
|
|
10228
|
+
process.stdout.write(isTTY ? source_default.dim(`│ ${formatLine("workflow", info.workflow)} │
|
|
10229
|
+
`) : `│ ${formatLine("workflow", info.workflow)} │
|
|
10230
|
+
`);
|
|
10231
|
+
process.stdout.write(isTTY ? source_default.dim(`│ ${formatLine("run-id", info.runId)} │
|
|
10232
|
+
`) : `│ ${formatLine("run-id", info.runId)} │
|
|
10233
|
+
`);
|
|
10234
|
+
const taskLines = info.task.split(`
|
|
10235
|
+
`).flatMap((line2) => {
|
|
10236
|
+
if (line2 === "") {
|
|
10237
|
+
return [""];
|
|
10238
|
+
}
|
|
10239
|
+
return wrapText(line2, valueWidth);
|
|
10240
|
+
});
|
|
10241
|
+
for (let i = 0;i < taskLines.length; i++) {
|
|
10242
|
+
const label = i === 0 ? "task" : "";
|
|
10243
|
+
const content = formatLine(label, taskLines[i] ?? "");
|
|
10244
|
+
process.stdout.write(isTTY ? source_default.dim(`│ ${content} │
|
|
10245
|
+
`) : `│ ${content} │
|
|
10246
|
+
`);
|
|
10247
|
+
}
|
|
10248
|
+
process.stdout.write(isTTY ? source_default.cyan(`${corner.bl}${border}${corner.br}
|
|
10249
|
+
`) : `${corner.bl}${border}${corner.br}
|
|
10250
|
+
`);
|
|
10251
|
+
process.stdout.write(`
|
|
10252
|
+
`);
|
|
10253
|
+
},
|
|
10254
|
+
stepStart(stepNumber, stepId, harness, model) {
|
|
10255
|
+
const line = isTTY ? "─" : "-";
|
|
10256
|
+
const corner = { tl: isTTY ? "┌" : "+", tr: isTTY ? "┐" : "+" };
|
|
10257
|
+
const label = ` Step ${stepNumber}: ${stepId} `;
|
|
10258
|
+
const width = getBoxWidth();
|
|
10259
|
+
const remaining = Math.max(0, width - label.length - 2);
|
|
10260
|
+
const border = line.repeat(remaining);
|
|
10261
|
+
process.stdout.write(`
|
|
10262
|
+
`);
|
|
10263
|
+
process.stdout.write(isTTY ? source_default.cyan.bold(`${corner.tl}${line}${label}${border}${corner.tr}
|
|
10264
|
+
`) : `${corner.tl}${line}${label}${border}${corner.tr}
|
|
10265
|
+
`);
|
|
10266
|
+
const metaLine = ` harness: ${harness} model: ${model ?? "(default)"}`;
|
|
10267
|
+
process.stdout.write(isTTY ? source_default.dim(`${metaLine}
|
|
10268
|
+
`) : `${metaLine}
|
|
10269
|
+
`);
|
|
10270
|
+
process.stdout.write(`
|
|
10271
|
+
`);
|
|
10272
|
+
},
|
|
10273
|
+
stepEnd() {
|
|
10274
|
+
const line = isTTY ? "─" : "-";
|
|
10275
|
+
const corner = { bl: isTTY ? "└" : "+", br: isTTY ? "┘" : "+" };
|
|
10276
|
+
const width = getBoxWidth();
|
|
10277
|
+
const border = line.repeat(width - 2);
|
|
10278
|
+
process.stdout.write(`
|
|
10279
|
+
`);
|
|
10280
|
+
process.stdout.write(isTTY ? source_default.cyan(`${corner.bl}${border}${corner.br}
|
|
10281
|
+
`) : `${corner.bl}${border}${corner.br}
|
|
10282
|
+
`);
|
|
10283
|
+
},
|
|
10284
|
+
printToolCall(toolName, toolInput) {
|
|
10285
|
+
const width = getBoxWidth();
|
|
10286
|
+
const maxInputLength = width - 10;
|
|
10287
|
+
const truncatedInput = truncate(toolInput, maxInputLength);
|
|
10288
|
+
if (isTTY) {
|
|
10289
|
+
process.stderr.write(source_default.cyan(` ${toolName} `) + source_default.dim(truncatedInput) + `
|
|
10290
|
+
`);
|
|
10291
|
+
} else {
|
|
10292
|
+
process.stderr.write(` ${toolName} ${truncatedInput}
|
|
10293
|
+
`);
|
|
10294
|
+
}
|
|
10295
|
+
},
|
|
10296
|
+
stepOutputs(values) {
|
|
10297
|
+
const entries = Object.entries(values);
|
|
10298
|
+
if (entries.length === 0) {
|
|
10299
|
+
return;
|
|
10300
|
+
}
|
|
10301
|
+
const width = getBoxWidth();
|
|
10302
|
+
const labelPrefix = " ";
|
|
10303
|
+
const separator = ": ";
|
|
10304
|
+
process.stdout.write(`
|
|
10305
|
+
`);
|
|
10306
|
+
for (const [key, value] of entries) {
|
|
10307
|
+
const label = `rmr:${key}`;
|
|
10308
|
+
const firstLineIndent = labelPrefix.length + label.length + separator.length;
|
|
10309
|
+
const continuationIndent = " ".repeat(firstLineIndent);
|
|
10310
|
+
const maxValueWidth = width - firstLineIndent;
|
|
10311
|
+
const valueLines = value.split(`
|
|
10312
|
+
`);
|
|
10313
|
+
const wrappedLines = [];
|
|
10314
|
+
for (const vline of valueLines) {
|
|
10315
|
+
if (vline.length <= maxValueWidth) {
|
|
10316
|
+
wrappedLines.push(vline);
|
|
10317
|
+
} else {
|
|
10318
|
+
let remaining = vline;
|
|
10319
|
+
while (remaining.length > maxValueWidth) {
|
|
10320
|
+
let breakAt = remaining.lastIndexOf(" ", maxValueWidth);
|
|
10321
|
+
if (breakAt <= 0) {
|
|
10322
|
+
breakAt = maxValueWidth;
|
|
10323
|
+
}
|
|
10324
|
+
wrappedLines.push(remaining.slice(0, breakAt));
|
|
10325
|
+
remaining = remaining.slice(breakAt).trimStart();
|
|
10326
|
+
}
|
|
10327
|
+
if (remaining) {
|
|
10328
|
+
wrappedLines.push(remaining);
|
|
10329
|
+
}
|
|
10330
|
+
}
|
|
10331
|
+
}
|
|
10332
|
+
const firstLine = wrappedLines[0] ?? "";
|
|
10333
|
+
if (isTTY) {
|
|
10334
|
+
process.stdout.write(source_default.cyan(`${labelPrefix}${label}`) + source_default.dim(`${separator}${firstLine}`) + `
|
|
10335
|
+
`);
|
|
10336
|
+
} else {
|
|
10337
|
+
process.stdout.write(`${labelPrefix}${label}${separator}${firstLine}
|
|
10338
|
+
`);
|
|
10339
|
+
}
|
|
10340
|
+
for (let i = 1;i < wrappedLines.length; i++) {
|
|
10341
|
+
if (isTTY) {
|
|
10342
|
+
process.stdout.write(source_default.dim(`${continuationIndent}${wrappedLines[i]}`) + `
|
|
10343
|
+
`);
|
|
10344
|
+
} else {
|
|
10345
|
+
process.stdout.write(`${continuationIndent}${wrappedLines[i]}
|
|
10346
|
+
`);
|
|
10347
|
+
}
|
|
10348
|
+
}
|
|
10349
|
+
}
|
|
10350
|
+
},
|
|
10351
|
+
content(text) {
|
|
10352
|
+
process.stdout.write(text);
|
|
10353
|
+
},
|
|
10354
|
+
success(text) {
|
|
10355
|
+
const icon = isTTY ? "✓ " : "";
|
|
10356
|
+
process.stdout.write(isTTY ? source_default.green(`${icon}${text}
|
|
10357
|
+
`) : `${icon}${text}
|
|
10358
|
+
`);
|
|
10359
|
+
},
|
|
10360
|
+
warning(text) {
|
|
10361
|
+
const icon = isTTY ? "⚠ " : "";
|
|
10362
|
+
process.stderr.write(isTTY ? source_default.yellow(`${icon}${text}
|
|
10363
|
+
`) : `${icon}${text}
|
|
10364
|
+
`);
|
|
10365
|
+
},
|
|
10366
|
+
error(text) {
|
|
10367
|
+
const icon = isTTY ? "✗ " : "";
|
|
10368
|
+
process.stderr.write(isTTY ? source_default.red(`${icon}${text}
|
|
10369
|
+
`) : `${icon}${text}
|
|
10370
|
+
`);
|
|
10371
|
+
},
|
|
10372
|
+
info(text) {
|
|
10373
|
+
process.stdout.write(`${text}
|
|
10374
|
+
`);
|
|
10375
|
+
},
|
|
10376
|
+
dim(text) {
|
|
10377
|
+
process.stdout.write(isTTY ? source_default.gray(text) : text);
|
|
10378
|
+
},
|
|
10379
|
+
pauseInstructions(info) {
|
|
10380
|
+
process.stderr.write(`
|
|
10381
|
+
`);
|
|
10382
|
+
ui.warning(`Paused: ${info.reason}`);
|
|
10383
|
+
process.stderr.write(`
|
|
10384
|
+
`);
|
|
10385
|
+
process.stdout.write(isTTY ? source_default.dim(`Resume workflow:
|
|
10386
|
+
`) : `Resume workflow:
|
|
10387
|
+
`);
|
|
10388
|
+
process.stdout.write(` ${binaryName} continue ${info.runId}
|
|
10389
|
+
`);
|
|
10390
|
+
process.stdout.write(`
|
|
10391
|
+
`);
|
|
10392
|
+
process.stdout.write(isTTY ? source_default.dim(`Resume with a hint:
|
|
10393
|
+
`) : `Resume with a hint:
|
|
10394
|
+
`);
|
|
10395
|
+
process.stdout.write(` ${binaryName} continue ${info.runId} --hint "your guidance here"
|
|
10396
|
+
`);
|
|
10397
|
+
process.stdout.write(`
|
|
10398
|
+
`);
|
|
10399
|
+
process.stdout.write(isTTY ? source_default.dim(`Resume agent session directly:
|
|
10400
|
+
`) : `Resume agent session directly:
|
|
10401
|
+
`);
|
|
10402
|
+
process.stdout.write(` ${info.resumeCommand}
|
|
10403
|
+
`);
|
|
10404
|
+
process.stdout.write(`
|
|
10405
|
+
`);
|
|
10126
10406
|
},
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
|
|
10130
|
-
|
|
10131
|
-
|
|
10132
|
-
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
redBright: [91, 39],
|
|
10140
|
-
greenBright: [92, 39],
|
|
10141
|
-
yellowBright: [93, 39],
|
|
10142
|
-
blueBright: [94, 39],
|
|
10143
|
-
magentaBright: [95, 39],
|
|
10144
|
-
cyanBright: [96, 39],
|
|
10145
|
-
whiteBright: [97, 39]
|
|
10407
|
+
prompt(message) {
|
|
10408
|
+
return new Promise((resolve) => {
|
|
10409
|
+
const rl = readline.createInterface({
|
|
10410
|
+
input: process.stdin,
|
|
10411
|
+
output: process.stdout
|
|
10412
|
+
});
|
|
10413
|
+
const styledMessage = isTTY ? source_default.cyan(message) : message;
|
|
10414
|
+
rl.question(styledMessage, (answer) => {
|
|
10415
|
+
rl.close();
|
|
10416
|
+
resolve(answer);
|
|
10417
|
+
});
|
|
10418
|
+
});
|
|
10146
10419
|
},
|
|
10147
|
-
|
|
10148
|
-
|
|
10149
|
-
|
|
10150
|
-
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
|
|
10157
|
-
|
|
10158
|
-
|
|
10159
|
-
|
|
10160
|
-
|
|
10161
|
-
|
|
10162
|
-
|
|
10163
|
-
|
|
10164
|
-
|
|
10165
|
-
|
|
10166
|
-
|
|
10167
|
-
};
|
|
10168
|
-
|
|
10169
|
-
|
|
10170
|
-
|
|
10171
|
-
|
|
10172
|
-
|
|
10173
|
-
|
|
10174
|
-
|
|
10175
|
-
for (const [styleName, style] of Object.entries(group)) {
|
|
10176
|
-
styles[styleName] = {
|
|
10177
|
-
open: `\x1B[${style[0]}m`,
|
|
10178
|
-
close: `\x1B[${style[1]}m`
|
|
10420
|
+
multilinePrompt(message) {
|
|
10421
|
+
return new Promise((resolve) => {
|
|
10422
|
+
const input = process.stdin;
|
|
10423
|
+
const output = process.stdout;
|
|
10424
|
+
const supportsRawMode = input.isTTY && typeof input.setRawMode === "function";
|
|
10425
|
+
const styledMessage = isTTY ? source_default.cyan(message) : message;
|
|
10426
|
+
const linePrompt = isTTY ? source_default.cyan("> ") : "> ";
|
|
10427
|
+
const promptWidth = displayWidth(stripAnsi(linePrompt));
|
|
10428
|
+
let buffer = "";
|
|
10429
|
+
let cursor = 0;
|
|
10430
|
+
let settled = false;
|
|
10431
|
+
let renderedRowCount = 0;
|
|
10432
|
+
if (!supportsRawMode) {
|
|
10433
|
+
const rl = readline.createInterface({
|
|
10434
|
+
input,
|
|
10435
|
+
output
|
|
10436
|
+
});
|
|
10437
|
+
rl.question(`${styledMessage} `, (answer) => {
|
|
10438
|
+
rl.close();
|
|
10439
|
+
resolve(answer);
|
|
10440
|
+
});
|
|
10441
|
+
return;
|
|
10442
|
+
}
|
|
10443
|
+
const cleanup = () => {
|
|
10444
|
+
input.off("data", onData);
|
|
10445
|
+
input.off("error", onError);
|
|
10446
|
+
input.setRawMode(false);
|
|
10447
|
+
input.pause();
|
|
10179
10448
|
};
|
|
10180
|
-
|
|
10181
|
-
|
|
10182
|
-
|
|
10183
|
-
|
|
10184
|
-
|
|
10185
|
-
|
|
10186
|
-
|
|
10187
|
-
|
|
10188
|
-
|
|
10189
|
-
|
|
10190
|
-
|
|
10191
|
-
|
|
10192
|
-
|
|
10193
|
-
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
|
|
10200
|
-
|
|
10201
|
-
|
|
10202
|
-
|
|
10203
|
-
|
|
10204
|
-
|
|
10205
|
-
|
|
10206
|
-
|
|
10207
|
-
|
|
10208
|
-
|
|
10449
|
+
const finish = (value) => {
|
|
10450
|
+
if (settled) {
|
|
10451
|
+
return;
|
|
10452
|
+
}
|
|
10453
|
+
settled = true;
|
|
10454
|
+
cleanup();
|
|
10455
|
+
resolve(value);
|
|
10456
|
+
};
|
|
10457
|
+
const clearRenderedBuffer = () => {
|
|
10458
|
+
if (renderedRowCount === 0) {
|
|
10459
|
+
return;
|
|
10460
|
+
}
|
|
10461
|
+
readline.cursorTo(output, 0);
|
|
10462
|
+
if (renderedRowCount > 1) {
|
|
10463
|
+
readline.moveCursor(output, 0, -(renderedRowCount - 1));
|
|
10464
|
+
}
|
|
10465
|
+
readline.clearScreenDown(output);
|
|
10466
|
+
};
|
|
10467
|
+
const getRenderedRowCount = (lines) => {
|
|
10468
|
+
const columns = Math.max(1, getTerminalWidth());
|
|
10469
|
+
let rows = 0;
|
|
10470
|
+
for (const line of lines) {
|
|
10471
|
+
const lineWidth = promptWidth + displayWidth(line);
|
|
10472
|
+
rows += Math.max(1, Math.ceil(lineWidth / columns));
|
|
10473
|
+
}
|
|
10474
|
+
return rows;
|
|
10475
|
+
};
|
|
10476
|
+
const getCursorPosition = () => {
|
|
10477
|
+
const textBeforeCursor = buffer.slice(0, cursor);
|
|
10478
|
+
const linesBeforeCursor = textBeforeCursor.split(`
|
|
10479
|
+
`);
|
|
10480
|
+
const line = linesBeforeCursor.length - 1;
|
|
10481
|
+
const col = linesBeforeCursor[line]?.length ?? 0;
|
|
10482
|
+
return { line, col };
|
|
10483
|
+
};
|
|
10484
|
+
const getLineStart = (lineNum) => {
|
|
10485
|
+
const lines = buffer.split(`
|
|
10486
|
+
`);
|
|
10487
|
+
let idx = 0;
|
|
10488
|
+
for (let i = 0;i < lineNum && i < lines.length; i++) {
|
|
10489
|
+
idx += (lines[i]?.length ?? 0) + 1;
|
|
10490
|
+
}
|
|
10491
|
+
return idx;
|
|
10492
|
+
};
|
|
10493
|
+
const getLineEnd = (lineNum) => {
|
|
10494
|
+
const lines = buffer.split(`
|
|
10495
|
+
`);
|
|
10496
|
+
if (lineNum >= lines.length) {
|
|
10497
|
+
return buffer.length;
|
|
10498
|
+
}
|
|
10499
|
+
return getLineStart(lineNum) + (lines[lineNum]?.length ?? 0);
|
|
10500
|
+
};
|
|
10501
|
+
const renderBuffer = () => {
|
|
10502
|
+
clearRenderedBuffer();
|
|
10503
|
+
const lines = buffer.split(`
|
|
10504
|
+
`);
|
|
10505
|
+
for (let i = 0;i < lines.length; i++) {
|
|
10506
|
+
output.write(`${linePrompt}${lines[i] ?? ""}`);
|
|
10507
|
+
if (i < lines.length - 1) {
|
|
10508
|
+
output.write(`
|
|
10509
|
+
`);
|
|
10209
10510
|
}
|
|
10210
|
-
return Math.round((red - 8) / 247 * 24) + 232;
|
|
10211
10511
|
}
|
|
10212
|
-
|
|
10213
|
-
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
|
|
10219
|
-
|
|
10220
|
-
|
|
10512
|
+
renderedRowCount = getRenderedRowCount(lines);
|
|
10513
|
+
const { line: cursorLine, col: cursorCol } = getCursorPosition();
|
|
10514
|
+
const columns = Math.max(1, getTerminalWidth());
|
|
10515
|
+
let rowsFromEnd = 0;
|
|
10516
|
+
for (let i = lines.length - 1;i > cursorLine; i--) {
|
|
10517
|
+
const lineWidth = promptWidth + displayWidth(lines[i] ?? "");
|
|
10518
|
+
rowsFromEnd += Math.max(1, Math.ceil(lineWidth / columns));
|
|
10519
|
+
}
|
|
10520
|
+
const cursorLineWidth = promptWidth + cursorCol;
|
|
10521
|
+
const totalLineWidth = promptWidth + displayWidth(lines[cursorLine] ?? "");
|
|
10522
|
+
const totalRowsInCursorLine = Math.max(1, Math.ceil(totalLineWidth / columns));
|
|
10523
|
+
const cursorRowInLine = Math.floor(cursorLineWidth / columns);
|
|
10524
|
+
const rowsAfterCursorInLine = totalRowsInCursorLine - cursorRowInLine - 1;
|
|
10525
|
+
rowsFromEnd += rowsAfterCursorInLine;
|
|
10526
|
+
if (rowsFromEnd > 0) {
|
|
10527
|
+
readline.moveCursor(output, 0, -rowsFromEnd);
|
|
10528
|
+
}
|
|
10529
|
+
readline.cursorTo(output, cursorLineWidth % columns);
|
|
10530
|
+
};
|
|
10531
|
+
const insertText = (text) => {
|
|
10532
|
+
const normalized = text.replace(/\r\n/g, `
|
|
10533
|
+
`).replace(/\r/g, `
|
|
10534
|
+
`);
|
|
10535
|
+
if (!normalized) {
|
|
10536
|
+
return;
|
|
10221
10537
|
}
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10538
|
+
buffer = buffer.slice(0, cursor) + normalized + buffer.slice(cursor);
|
|
10539
|
+
cursor += normalized.length;
|
|
10540
|
+
renderBuffer();
|
|
10541
|
+
};
|
|
10542
|
+
const submit = () => {
|
|
10543
|
+
const lines = buffer.split(`
|
|
10544
|
+
`);
|
|
10545
|
+
const lastLineIdx = lines.length - 1;
|
|
10546
|
+
const columns = Math.max(1, getTerminalWidth());
|
|
10547
|
+
const { line: cursorLine } = getCursorPosition();
|
|
10548
|
+
let rowsToEnd = 0;
|
|
10549
|
+
for (let i = cursorLine + 1;i < lines.length; i++) {
|
|
10550
|
+
const lineWidth = promptWidth + displayWidth(lines[i] ?? "");
|
|
10551
|
+
rowsToEnd += Math.max(1, Math.ceil(lineWidth / columns));
|
|
10552
|
+
}
|
|
10553
|
+
const cursorLineWidth = promptWidth + displayWidth(lines[cursorLine] ?? "");
|
|
10554
|
+
const totalRowsInCursorLine = Math.max(1, Math.ceil(cursorLineWidth / columns));
|
|
10555
|
+
const { col: cursorCol } = getCursorPosition();
|
|
10556
|
+
const cursorRowInLine = Math.floor((promptWidth + cursorCol) / columns);
|
|
10557
|
+
rowsToEnd += totalRowsInCursorLine - cursorRowInLine - 1;
|
|
10558
|
+
if (rowsToEnd > 0) {
|
|
10559
|
+
readline.moveCursor(output, 0, rowsToEnd);
|
|
10560
|
+
}
|
|
10561
|
+
const lastLineWidth = promptWidth + displayWidth(lines[lastLineIdx] ?? "");
|
|
10562
|
+
readline.cursorTo(output, lastLineWidth % columns);
|
|
10563
|
+
output.write(`
|
|
10564
|
+
`);
|
|
10565
|
+
finish(buffer);
|
|
10566
|
+
};
|
|
10567
|
+
const cancel = () => {
|
|
10568
|
+
output.write(`
|
|
10569
|
+
`);
|
|
10570
|
+
finish("");
|
|
10571
|
+
};
|
|
10572
|
+
const onError = () => {
|
|
10573
|
+
finish(buffer);
|
|
10574
|
+
};
|
|
10575
|
+
const onData = (chunk) => {
|
|
10576
|
+
const value = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
10577
|
+
if (value === "\x03") {
|
|
10578
|
+
cancel();
|
|
10579
|
+
return;
|
|
10225
10580
|
}
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
integer >> 8 & 255,
|
|
10230
|
-
integer & 255
|
|
10231
|
-
];
|
|
10232
|
-
},
|
|
10233
|
-
enumerable: false
|
|
10234
|
-
},
|
|
10235
|
-
hexToAnsi256: {
|
|
10236
|
-
value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
|
|
10237
|
-
enumerable: false
|
|
10238
|
-
},
|
|
10239
|
-
ansi256ToAnsi: {
|
|
10240
|
-
value(code) {
|
|
10241
|
-
if (code < 8) {
|
|
10242
|
-
return 30 + code;
|
|
10581
|
+
if (value === "\x04") {
|
|
10582
|
+
submit();
|
|
10583
|
+
return;
|
|
10243
10584
|
}
|
|
10244
|
-
if (
|
|
10245
|
-
|
|
10585
|
+
if (value === "\x01") {
|
|
10586
|
+
const { line } = getCursorPosition();
|
|
10587
|
+
cursor = getLineStart(line);
|
|
10588
|
+
renderBuffer();
|
|
10589
|
+
return;
|
|
10246
10590
|
}
|
|
10247
|
-
|
|
10248
|
-
|
|
10249
|
-
|
|
10250
|
-
|
|
10251
|
-
|
|
10252
|
-
green = red;
|
|
10253
|
-
blue = red;
|
|
10254
|
-
} else {
|
|
10255
|
-
code -= 16;
|
|
10256
|
-
const remainder = code % 36;
|
|
10257
|
-
red = Math.floor(code / 36) / 5;
|
|
10258
|
-
green = Math.floor(remainder / 6) / 5;
|
|
10259
|
-
blue = remainder % 6 / 5;
|
|
10591
|
+
if (value === "\x05") {
|
|
10592
|
+
const { line } = getCursorPosition();
|
|
10593
|
+
cursor = getLineEnd(line);
|
|
10594
|
+
renderBuffer();
|
|
10595
|
+
return;
|
|
10260
10596
|
}
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
|
|
10597
|
+
if (value === "\x15") {
|
|
10598
|
+
const { line } = getCursorPosition();
|
|
10599
|
+
const lineStart = getLineStart(line);
|
|
10600
|
+
buffer = buffer.slice(0, lineStart) + buffer.slice(cursor);
|
|
10601
|
+
cursor = lineStart;
|
|
10602
|
+
renderBuffer();
|
|
10603
|
+
return;
|
|
10264
10604
|
}
|
|
10265
|
-
|
|
10266
|
-
|
|
10267
|
-
|
|
10605
|
+
if (value === "\x17") {
|
|
10606
|
+
if (cursor === 0) {
|
|
10607
|
+
return;
|
|
10608
|
+
}
|
|
10609
|
+
let newCursor = cursor - 1;
|
|
10610
|
+
while (newCursor > 0 && /\s/.test(buffer[newCursor] ?? "")) {
|
|
10611
|
+
newCursor--;
|
|
10612
|
+
}
|
|
10613
|
+
while (newCursor > 0 && !/\s/.test(buffer[newCursor - 1] ?? "")) {
|
|
10614
|
+
newCursor--;
|
|
10615
|
+
}
|
|
10616
|
+
buffer = buffer.slice(0, newCursor) + buffer.slice(cursor);
|
|
10617
|
+
cursor = newCursor;
|
|
10618
|
+
renderBuffer();
|
|
10619
|
+
return;
|
|
10268
10620
|
}
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
|
|
10274
|
-
|
|
10275
|
-
|
|
10276
|
-
|
|
10277
|
-
|
|
10278
|
-
|
|
10279
|
-
|
|
10621
|
+
if (value === "\r" || value === `
|
|
10622
|
+
`) {
|
|
10623
|
+
insertText(`
|
|
10624
|
+
`);
|
|
10625
|
+
return;
|
|
10626
|
+
}
|
|
10627
|
+
if (value === "" || value === "\b") {
|
|
10628
|
+
if (cursor > 0) {
|
|
10629
|
+
buffer = buffer.slice(0, cursor - 1) + buffer.slice(cursor);
|
|
10630
|
+
cursor--;
|
|
10631
|
+
renderBuffer();
|
|
10632
|
+
}
|
|
10633
|
+
return;
|
|
10634
|
+
}
|
|
10635
|
+
if (value.length > 1) {
|
|
10636
|
+
const withoutBracketedPasteMarkers = value.replace(/\x1b\[200~/g, "").replace(/\x1b\[201~/g, "");
|
|
10637
|
+
if (withoutBracketedPasteMarkers.startsWith("\x1B")) {
|
|
10638
|
+
const seq = withoutBracketedPasteMarkers;
|
|
10639
|
+
if (seq === "\x1B[D") {
|
|
10640
|
+
if (cursor > 0) {
|
|
10641
|
+
cursor--;
|
|
10642
|
+
renderBuffer();
|
|
10643
|
+
}
|
|
10644
|
+
return;
|
|
10645
|
+
}
|
|
10646
|
+
if (seq === "\x1B[C") {
|
|
10647
|
+
if (cursor < buffer.length) {
|
|
10648
|
+
cursor++;
|
|
10649
|
+
renderBuffer();
|
|
10650
|
+
}
|
|
10651
|
+
return;
|
|
10652
|
+
}
|
|
10653
|
+
if (seq === "\x1B[A") {
|
|
10654
|
+
const { line, col } = getCursorPosition();
|
|
10655
|
+
if (line > 0) {
|
|
10656
|
+
const prevLineStart = getLineStart(line - 1);
|
|
10657
|
+
const prevLineEnd = getLineEnd(line - 1);
|
|
10658
|
+
const prevLineLen = prevLineEnd - prevLineStart;
|
|
10659
|
+
cursor = prevLineStart + Math.min(col, prevLineLen);
|
|
10660
|
+
renderBuffer();
|
|
10661
|
+
}
|
|
10662
|
+
return;
|
|
10663
|
+
}
|
|
10664
|
+
if (seq === "\x1B[B") {
|
|
10665
|
+
const lines = buffer.split(`
|
|
10666
|
+
`);
|
|
10667
|
+
const { line, col } = getCursorPosition();
|
|
10668
|
+
if (line < lines.length - 1) {
|
|
10669
|
+
const nextLineStart = getLineStart(line + 1);
|
|
10670
|
+
const nextLineEnd = getLineEnd(line + 1);
|
|
10671
|
+
const nextLineLen = nextLineEnd - nextLineStart;
|
|
10672
|
+
cursor = nextLineStart + Math.min(col, nextLineLen);
|
|
10673
|
+
renderBuffer();
|
|
10674
|
+
}
|
|
10675
|
+
return;
|
|
10676
|
+
}
|
|
10677
|
+
if (seq === "\x1B[H" || seq === "\x1B[1~" || seq === "\x1BOH") {
|
|
10678
|
+
const { line } = getCursorPosition();
|
|
10679
|
+
cursor = getLineStart(line);
|
|
10680
|
+
renderBuffer();
|
|
10681
|
+
return;
|
|
10682
|
+
}
|
|
10683
|
+
if (seq === "\x1B[F" || seq === "\x1B[4~" || seq === "\x1BOF") {
|
|
10684
|
+
const { line } = getCursorPosition();
|
|
10685
|
+
cursor = getLineEnd(line);
|
|
10686
|
+
renderBuffer();
|
|
10687
|
+
return;
|
|
10688
|
+
}
|
|
10689
|
+
if (!/[\r\n]/.test(withoutBracketedPasteMarkers)) {
|
|
10690
|
+
return;
|
|
10691
|
+
}
|
|
10692
|
+
}
|
|
10693
|
+
insertText(withoutBracketedPasteMarkers);
|
|
10694
|
+
return;
|
|
10695
|
+
}
|
|
10696
|
+
if (value >= " ") {
|
|
10697
|
+
insertText(value);
|
|
10698
|
+
}
|
|
10699
|
+
};
|
|
10700
|
+
output.write(styledMessage);
|
|
10701
|
+
output.write(`
|
|
10702
|
+
`);
|
|
10703
|
+
input.setRawMode(true);
|
|
10704
|
+
input.setEncoding("utf8");
|
|
10705
|
+
input.resume();
|
|
10706
|
+
input.on("data", onData);
|
|
10707
|
+
input.on("error", onError);
|
|
10708
|
+
renderBuffer();
|
|
10709
|
+
});
|
|
10710
|
+
}
|
|
10711
|
+
};
|
|
10712
|
+
|
|
10713
|
+
// src/commands/base.ts
|
|
10714
|
+
class BaseCommand extends Command {
|
|
10715
|
+
async catch(error) {
|
|
10716
|
+
if (error instanceof RmrError) {
|
|
10717
|
+
ui.error(error.message);
|
|
10718
|
+
process.exitCode = 1;
|
|
10719
|
+
return;
|
|
10280
10720
|
}
|
|
10281
|
-
|
|
10282
|
-
|
|
10721
|
+
throw error;
|
|
10722
|
+
}
|
|
10723
|
+
}
|
|
10724
|
+
|
|
10725
|
+
// src/lib/config.ts
|
|
10726
|
+
import { mkdir } from "node:fs/promises";
|
|
10727
|
+
import { resolve } from "node:path";
|
|
10728
|
+
async function loadConfig(workspaceRoot = process.cwd()) {
|
|
10729
|
+
const root = resolve(workspaceRoot);
|
|
10730
|
+
const rexDir = resolve(root, ".rmr");
|
|
10731
|
+
const config = {
|
|
10732
|
+
workspaceRoot: root,
|
|
10733
|
+
rexDir,
|
|
10734
|
+
runsDir: resolve(rexDir, "runs"),
|
|
10735
|
+
workflowsDir: resolve(rexDir, "workflows")
|
|
10736
|
+
};
|
|
10737
|
+
await Promise.all([
|
|
10738
|
+
mkdir(config.rexDir, { recursive: true }),
|
|
10739
|
+
mkdir(config.runsDir, { recursive: true }),
|
|
10740
|
+
mkdir(config.workflowsDir, { recursive: true })
|
|
10741
|
+
]);
|
|
10742
|
+
return config;
|
|
10283
10743
|
}
|
|
10284
|
-
var ansiStyles = assembleStyles();
|
|
10285
|
-
var ansi_styles_default = ansiStyles;
|
|
10286
10744
|
|
|
10287
|
-
//
|
|
10288
|
-
import
|
|
10289
|
-
import
|
|
10290
|
-
|
|
10291
|
-
|
|
10292
|
-
|
|
10293
|
-
|
|
10294
|
-
|
|
10295
|
-
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
10745
|
+
// src/lib/completions.ts
|
|
10746
|
+
import { access, readdir } from "node:fs/promises";
|
|
10747
|
+
import { resolve as resolve2 } from "node:path";
|
|
10748
|
+
function matchesPartial(value, partial) {
|
|
10749
|
+
if (!partial) {
|
|
10750
|
+
return true;
|
|
10751
|
+
}
|
|
10752
|
+
return value.startsWith(partial);
|
|
10296
10753
|
}
|
|
10297
|
-
|
|
10298
|
-
|
|
10299
|
-
|
|
10300
|
-
flagForceColor = 0;
|
|
10301
|
-
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
10302
|
-
flagForceColor = 1;
|
|
10754
|
+
async function listRunIdCompletions(config, partial = "") {
|
|
10755
|
+
const entries = await readdir(config.runsDir, { withFileTypes: true });
|
|
10756
|
+
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).filter((id) => matchesPartial(id, partial)).sort();
|
|
10303
10757
|
}
|
|
10304
|
-
function
|
|
10305
|
-
|
|
10306
|
-
|
|
10307
|
-
|
|
10308
|
-
|
|
10309
|
-
|
|
10310
|
-
return 0;
|
|
10758
|
+
async function listWorkflowCompletions(config, partial = "") {
|
|
10759
|
+
const entries = await readdir(config.workflowsDir, { withFileTypes: true });
|
|
10760
|
+
const workflows = [];
|
|
10761
|
+
for (const entry of entries) {
|
|
10762
|
+
if (!entry.isDirectory()) {
|
|
10763
|
+
continue;
|
|
10311
10764
|
}
|
|
10312
|
-
|
|
10765
|
+
const workflowYaml = resolve2(config.workflowsDir, entry.name, "workflow.yaml");
|
|
10766
|
+
const workflowYml = resolve2(config.workflowsDir, entry.name, "workflow.yml");
|
|
10767
|
+
try {
|
|
10768
|
+
await access(workflowYaml);
|
|
10769
|
+
workflows.push(workflowYaml);
|
|
10770
|
+
continue;
|
|
10771
|
+
} catch {}
|
|
10772
|
+
try {
|
|
10773
|
+
await access(workflowYml);
|
|
10774
|
+
workflows.push(workflowYml);
|
|
10775
|
+
} catch {}
|
|
10313
10776
|
}
|
|
10777
|
+
return workflows.filter((filePath) => matchesPartial(filePath, partial)).sort();
|
|
10314
10778
|
}
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
|
|
10779
|
+
|
|
10780
|
+
// src/commands/complete.ts
|
|
10781
|
+
function parseTarget(value) {
|
|
10782
|
+
if (value === "run-id" || value === "workflow") {
|
|
10783
|
+
return value;
|
|
10318
10784
|
}
|
|
10319
|
-
|
|
10320
|
-
level,
|
|
10321
|
-
hasBasic: true,
|
|
10322
|
-
has256: level >= 2,
|
|
10323
|
-
has16m: level >= 3
|
|
10324
|
-
};
|
|
10785
|
+
throw new UserInputError(`Invalid completion target "${value}".`);
|
|
10325
10786
|
}
|
|
10326
|
-
|
|
10327
|
-
|
|
10328
|
-
|
|
10329
|
-
|
|
10330
|
-
|
|
10331
|
-
|
|
10332
|
-
|
|
10333
|
-
|
|
10334
|
-
|
|
10335
|
-
|
|
10336
|
-
|
|
10337
|
-
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
|
|
10787
|
+
|
|
10788
|
+
class CompleteCommand extends BaseCommand {
|
|
10789
|
+
static paths = [["complete"]];
|
|
10790
|
+
target = exports_options.String({
|
|
10791
|
+
name: "target"
|
|
10792
|
+
});
|
|
10793
|
+
partial = exports_options.String({
|
|
10794
|
+
required: false,
|
|
10795
|
+
name: "partial"
|
|
10796
|
+
});
|
|
10797
|
+
async execute() {
|
|
10798
|
+
const config = await loadConfig();
|
|
10799
|
+
const target = parseTarget(this.target);
|
|
10800
|
+
const query = this.partial ?? "";
|
|
10801
|
+
const suggestions = target === "run-id" ? await listRunIdCompletions(config, query) : await listWorkflowCompletions(config, query);
|
|
10802
|
+
for (const value of suggestions) {
|
|
10803
|
+
process.stdout.write(`${value}
|
|
10804
|
+
`);
|
|
10341
10805
|
}
|
|
10342
|
-
}
|
|
10343
|
-
if ("TF_BUILD" in env && "AGENT_NAME" in env) {
|
|
10344
|
-
return 1;
|
|
10345
|
-
}
|
|
10346
|
-
if (haveStream && !streamIsTTY && forceColor === undefined) {
|
|
10347
10806
|
return 0;
|
|
10348
10807
|
}
|
|
10349
|
-
const min = forceColor || 0;
|
|
10350
|
-
if (env.TERM === "dumb") {
|
|
10351
|
-
return min;
|
|
10352
|
-
}
|
|
10353
|
-
if (process2.platform === "win32") {
|
|
10354
|
-
const osRelease = os.release().split(".");
|
|
10355
|
-
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
10356
|
-
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
10357
|
-
}
|
|
10358
|
-
return 1;
|
|
10359
|
-
}
|
|
10360
|
-
if ("CI" in env) {
|
|
10361
|
-
if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => (key in env))) {
|
|
10362
|
-
return 3;
|
|
10363
|
-
}
|
|
10364
|
-
if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => (sign in env)) || env.CI_NAME === "codeship") {
|
|
10365
|
-
return 1;
|
|
10366
|
-
}
|
|
10367
|
-
return min;
|
|
10368
|
-
}
|
|
10369
|
-
if ("TEAMCITY_VERSION" in env) {
|
|
10370
|
-
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
10371
|
-
}
|
|
10372
|
-
if (env.COLORTERM === "truecolor") {
|
|
10373
|
-
return 3;
|
|
10374
|
-
}
|
|
10375
|
-
if (env.TERM === "xterm-kitty") {
|
|
10376
|
-
return 3;
|
|
10377
|
-
}
|
|
10378
|
-
if (env.TERM === "xterm-ghostty") {
|
|
10379
|
-
return 3;
|
|
10380
|
-
}
|
|
10381
|
-
if (env.TERM === "wezterm") {
|
|
10382
|
-
return 3;
|
|
10383
|
-
}
|
|
10384
|
-
if ("TERM_PROGRAM" in env) {
|
|
10385
|
-
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
10386
|
-
switch (env.TERM_PROGRAM) {
|
|
10387
|
-
case "iTerm.app": {
|
|
10388
|
-
return version >= 3 ? 3 : 2;
|
|
10389
|
-
}
|
|
10390
|
-
case "Apple_Terminal": {
|
|
10391
|
-
return 2;
|
|
10392
|
-
}
|
|
10393
|
-
}
|
|
10394
|
-
}
|
|
10395
|
-
if (/-256(color)?$/i.test(env.TERM)) {
|
|
10396
|
-
return 2;
|
|
10397
|
-
}
|
|
10398
|
-
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
10399
|
-
return 1;
|
|
10400
|
-
}
|
|
10401
|
-
if ("COLORTERM" in env) {
|
|
10402
|
-
return 1;
|
|
10403
|
-
}
|
|
10404
|
-
return min;
|
|
10405
|
-
}
|
|
10406
|
-
function createSupportsColor(stream, options = {}) {
|
|
10407
|
-
const level = _supportsColor(stream, {
|
|
10408
|
-
streamIsTTY: stream && stream.isTTY,
|
|
10409
|
-
...options
|
|
10410
|
-
});
|
|
10411
|
-
return translateLevel(level);
|
|
10412
10808
|
}
|
|
10413
|
-
var supportsColor = {
|
|
10414
|
-
stdout: createSupportsColor({ isTTY: tty2.isatty(1) }),
|
|
10415
|
-
stderr: createSupportsColor({ isTTY: tty2.isatty(2) })
|
|
10416
|
-
};
|
|
10417
|
-
var supports_color_default = supportsColor;
|
|
10418
10809
|
|
|
10419
|
-
//
|
|
10420
|
-
function
|
|
10421
|
-
|
|
10422
|
-
|
|
10423
|
-
return string;
|
|
10810
|
+
// src/commands/completion.ts
|
|
10811
|
+
function parseShell(value) {
|
|
10812
|
+
if (value === "bash" || value === "zsh" || value === "fish") {
|
|
10813
|
+
return value;
|
|
10424
10814
|
}
|
|
10425
|
-
|
|
10426
|
-
|
|
10427
|
-
|
|
10428
|
-
|
|
10429
|
-
|
|
10430
|
-
|
|
10431
|
-
|
|
10432
|
-
}
|
|
10433
|
-
|
|
10434
|
-
|
|
10815
|
+
throw new UserInputError(`Unsupported shell "${value}". Use bash, zsh, or fish.`);
|
|
10816
|
+
}
|
|
10817
|
+
function bashScript() {
|
|
10818
|
+
return [
|
|
10819
|
+
"_rex_complete() {",
|
|
10820
|
+
" local cur prev",
|
|
10821
|
+
" COMPREPLY=()",
|
|
10822
|
+
' cur="${COMP_WORDS[COMP_CWORD]}"',
|
|
10823
|
+
' prev="${COMP_WORDS[COMP_CWORD-1]}"',
|
|
10824
|
+
"",
|
|
10825
|
+
" if [[ ${COMP_CWORD} -eq 1 ]]; then",
|
|
10826
|
+
' COMPREPLY=( $(compgen -W "install run continue complete completion --help --version" -- "${cur}") )',
|
|
10827
|
+
" return 0",
|
|
10828
|
+
" fi",
|
|
10829
|
+
"",
|
|
10830
|
+
' if [[ "${prev}" == "continue" ]]; then',
|
|
10831
|
+
` COMPREPLY=( $(${binaryName} complete run-id "\${cur}") )`,
|
|
10832
|
+
" return 0",
|
|
10833
|
+
" fi",
|
|
10834
|
+
"",
|
|
10835
|
+
' if [[ "${prev}" == "run" ]]; then',
|
|
10836
|
+
` COMPREPLY=( $(${binaryName} complete workflow "\${cur}") )`,
|
|
10837
|
+
" return 0",
|
|
10838
|
+
" fi",
|
|
10839
|
+
"",
|
|
10840
|
+
' if [[ "${prev}" == "install" ]]; then',
|
|
10841
|
+
' COMPREPLY=( $(compgen -W "feature-dev" -- "${cur}") )',
|
|
10842
|
+
" return 0",
|
|
10843
|
+
" fi",
|
|
10844
|
+
"}",
|
|
10845
|
+
`complete -F _rex_complete ${binaryName}`
|
|
10846
|
+
].join(`
|
|
10847
|
+
`);
|
|
10848
|
+
}
|
|
10849
|
+
function zshScript() {
|
|
10850
|
+
return [
|
|
10851
|
+
`#compdef ${binaryName}`,
|
|
10852
|
+
"_rex_complete() {",
|
|
10853
|
+
" local -a subcommands",
|
|
10854
|
+
" subcommands=(install run continue complete completion)",
|
|
10855
|
+
"",
|
|
10856
|
+
" if (( CURRENT == 2 )); then",
|
|
10857
|
+
" _describe 'command' subcommands",
|
|
10858
|
+
" return",
|
|
10859
|
+
" fi",
|
|
10860
|
+
"",
|
|
10861
|
+
" if [[ ${words[2]} == continue && $CURRENT -eq 3 ]]; then",
|
|
10862
|
+
` compadd -- $(${binaryName} complete run-id "\${words[CURRENT]}")`,
|
|
10863
|
+
" return",
|
|
10864
|
+
" fi",
|
|
10865
|
+
"",
|
|
10866
|
+
" if [[ ${words[2]} == run && $CURRENT -eq 3 ]]; then",
|
|
10867
|
+
` compadd -- $(${binaryName} complete workflow "\${words[CURRENT]}")`,
|
|
10868
|
+
" return",
|
|
10869
|
+
" fi",
|
|
10870
|
+
"",
|
|
10871
|
+
" if [[ ${words[2]} == install && $CURRENT -eq 3 ]]; then",
|
|
10872
|
+
" compadd -- feature-dev",
|
|
10873
|
+
" return",
|
|
10874
|
+
" fi",
|
|
10875
|
+
"}",
|
|
10876
|
+
`compdef _rex_complete ${binaryName}`
|
|
10877
|
+
].join(`
|
|
10878
|
+
`);
|
|
10435
10879
|
}
|
|
10436
|
-
function
|
|
10437
|
-
|
|
10438
|
-
|
|
10439
|
-
|
|
10440
|
-
|
|
10441
|
-
|
|
10442
|
-
|
|
10443
|
-
`
|
|
10444
|
-
|
|
10445
|
-
|
|
10446
|
-
`,
|
|
10447
|
-
|
|
10448
|
-
|
|
10449
|
-
|
|
10880
|
+
function fishScript() {
|
|
10881
|
+
return [
|
|
10882
|
+
"function __rex_complete_run_id",
|
|
10883
|
+
` ${binaryName} complete run-id (commandline -ct)`,
|
|
10884
|
+
"end",
|
|
10885
|
+
"",
|
|
10886
|
+
"function __rex_complete_workflow",
|
|
10887
|
+
` ${binaryName} complete workflow (commandline -ct)`,
|
|
10888
|
+
"end",
|
|
10889
|
+
"",
|
|
10890
|
+
`complete -c ${binaryName} -f`,
|
|
10891
|
+
`complete -c ${binaryName} -n '__fish_use_subcommand' -a 'install run continue complete completion'`,
|
|
10892
|
+
`complete -c ${binaryName} -n '__fish_seen_subcommand_from continue' -a '(__rex_complete_run_id)'`,
|
|
10893
|
+
`complete -c ${binaryName} -n '__fish_seen_subcommand_from run' -a '(__rex_complete_workflow)'`,
|
|
10894
|
+
`complete -c ${binaryName} -n '__fish_seen_subcommand_from install' -a 'feature-dev'`
|
|
10895
|
+
].join(`
|
|
10896
|
+
`);
|
|
10450
10897
|
}
|
|
10451
10898
|
|
|
10452
|
-
|
|
10453
|
-
|
|
10454
|
-
|
|
10455
|
-
|
|
10456
|
-
|
|
10457
|
-
|
|
10458
|
-
|
|
10459
|
-
|
|
10460
|
-
|
|
10461
|
-
|
|
10462
|
-
]
|
|
10463
|
-
|
|
10464
|
-
|
|
10465
|
-
|
|
10466
|
-
|
|
10899
|
+
class CompletionCommand extends BaseCommand {
|
|
10900
|
+
static paths = [["completion"]];
|
|
10901
|
+
static usage = Command.Usage({
|
|
10902
|
+
category: "Workflow",
|
|
10903
|
+
description: "Print optional shell completion setup script.",
|
|
10904
|
+
details: "Generates completion script text for your shell. Source the output in your shell profile to enable command and dynamic argument completion.",
|
|
10905
|
+
examples: [
|
|
10906
|
+
["Show Bash completion script", "$0 completion bash"],
|
|
10907
|
+
["Show Zsh completion script", "$0 completion zsh"],
|
|
10908
|
+
["Show Fish completion script", "$0 completion fish"]
|
|
10909
|
+
]
|
|
10910
|
+
});
|
|
10911
|
+
shell = exports_options.String({
|
|
10912
|
+
name: "shell"
|
|
10913
|
+
});
|
|
10914
|
+
async execute() {
|
|
10915
|
+
const shell = parseShell(this.shell);
|
|
10916
|
+
const script = shell === "bash" ? bashScript() : shell === "zsh" ? zshScript() : fishScript();
|
|
10917
|
+
process.stdout.write(`${script}
|
|
10918
|
+
`);
|
|
10919
|
+
return 0;
|
|
10467
10920
|
}
|
|
10468
|
-
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
10469
|
-
object.level = options.level === undefined ? colorLevel : options.level;
|
|
10470
|
-
};
|
|
10471
|
-
var chalkFactory = (options) => {
|
|
10472
|
-
const chalk = (...strings) => strings.join(" ");
|
|
10473
|
-
applyOptions(chalk, options);
|
|
10474
|
-
Object.setPrototypeOf(chalk, createChalk.prototype);
|
|
10475
|
-
return chalk;
|
|
10476
|
-
};
|
|
10477
|
-
function createChalk(options) {
|
|
10478
|
-
return chalkFactory(options);
|
|
10479
10921
|
}
|
|
10480
|
-
|
|
10481
|
-
|
|
10482
|
-
|
|
10483
|
-
|
|
10484
|
-
|
|
10485
|
-
|
|
10486
|
-
return builder;
|
|
10487
|
-
}
|
|
10488
|
-
};
|
|
10922
|
+
|
|
10923
|
+
// src/lib/run-state.ts
|
|
10924
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
10925
|
+
import { resolve as resolve3 } from "node:path";
|
|
10926
|
+
function pad(input) {
|
|
10927
|
+
return String(input).padStart(2, "0");
|
|
10489
10928
|
}
|
|
10490
|
-
|
|
10491
|
-
|
|
10492
|
-
|
|
10493
|
-
|
|
10494
|
-
|
|
10495
|
-
|
|
10496
|
-
|
|
10497
|
-
|
|
10498
|
-
if (model === "rgb") {
|
|
10499
|
-
if (level === "ansi16m") {
|
|
10500
|
-
return ansi_styles_default[type].ansi16m(...arguments_);
|
|
10501
|
-
}
|
|
10502
|
-
if (level === "ansi256") {
|
|
10503
|
-
return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
|
|
10504
|
-
}
|
|
10505
|
-
return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
|
|
10506
|
-
}
|
|
10507
|
-
if (model === "hex") {
|
|
10508
|
-
return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
|
|
10509
|
-
}
|
|
10510
|
-
return ansi_styles_default[type][model](...arguments_);
|
|
10511
|
-
};
|
|
10512
|
-
var usedModels = ["rgb", "hex", "ansi256"];
|
|
10513
|
-
for (const model of usedModels) {
|
|
10514
|
-
styles2[model] = {
|
|
10515
|
-
get() {
|
|
10516
|
-
const { level } = this;
|
|
10517
|
-
return function(...arguments_) {
|
|
10518
|
-
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
|
|
10519
|
-
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
10520
|
-
};
|
|
10521
|
-
}
|
|
10522
|
-
};
|
|
10523
|
-
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
10524
|
-
styles2[bgModel] = {
|
|
10525
|
-
get() {
|
|
10526
|
-
const { level } = this;
|
|
10527
|
-
return function(...arguments_) {
|
|
10528
|
-
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
|
|
10529
|
-
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
10530
|
-
};
|
|
10531
|
-
}
|
|
10532
|
-
};
|
|
10929
|
+
function generateRunId(now = new Date) {
|
|
10930
|
+
const yyyy = now.getUTCFullYear();
|
|
10931
|
+
const mm = pad(now.getUTCMonth() + 1);
|
|
10932
|
+
const dd = pad(now.getUTCDate());
|
|
10933
|
+
const hh = pad(now.getUTCHours());
|
|
10934
|
+
const min = pad(now.getUTCMinutes());
|
|
10935
|
+
const sec = pad(now.getUTCSeconds());
|
|
10936
|
+
return `${yyyy}${mm}${dd}-${hh}${min}${sec}Z`;
|
|
10533
10937
|
}
|
|
10534
|
-
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
|
|
10538
|
-
|
|
10539
|
-
|
|
10540
|
-
|
|
10541
|
-
set(level) {
|
|
10542
|
-
this[GENERATOR].level = level;
|
|
10543
|
-
}
|
|
10544
|
-
}
|
|
10545
|
-
});
|
|
10546
|
-
var createStyler = (open, close, parent) => {
|
|
10547
|
-
let openAll;
|
|
10548
|
-
let closeAll;
|
|
10549
|
-
if (parent === undefined) {
|
|
10550
|
-
openAll = open;
|
|
10551
|
-
closeAll = close;
|
|
10552
|
-
} else {
|
|
10553
|
-
openAll = parent.openAll + open;
|
|
10554
|
-
closeAll = close + parent.closeAll;
|
|
10938
|
+
function runFilePath(config, runId) {
|
|
10939
|
+
return resolve3(config.runsDir, `${runId}.json`);
|
|
10940
|
+
}
|
|
10941
|
+
function createInitialRunState(options) {
|
|
10942
|
+
const firstStep = options.workflow.steps[0];
|
|
10943
|
+
if (!firstStep) {
|
|
10944
|
+
throw new StorageError("Cannot create run state without at least one workflow step.");
|
|
10555
10945
|
}
|
|
10556
10946
|
return {
|
|
10557
|
-
|
|
10558
|
-
|
|
10559
|
-
|
|
10560
|
-
|
|
10561
|
-
|
|
10947
|
+
run_id: options.runId,
|
|
10948
|
+
workflow_path: options.workflowPath,
|
|
10949
|
+
status: "running",
|
|
10950
|
+
current_step: firstStep.id,
|
|
10951
|
+
context: {
|
|
10952
|
+
task: options.task,
|
|
10953
|
+
...options.vars
|
|
10954
|
+
},
|
|
10955
|
+
last_harness: {
|
|
10956
|
+
name: firstStep.harness,
|
|
10957
|
+
binary: firstStep.harness,
|
|
10958
|
+
session_id: null
|
|
10959
|
+
},
|
|
10960
|
+
step_history: [],
|
|
10961
|
+
updated_at: new Date().toISOString()
|
|
10562
10962
|
};
|
|
10563
|
-
}
|
|
10564
|
-
|
|
10565
|
-
const
|
|
10566
|
-
|
|
10567
|
-
|
|
10568
|
-
|
|
10569
|
-
|
|
10570
|
-
|
|
10571
|
-
|
|
10572
|
-
|
|
10573
|
-
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
|
|
10580
|
-
|
|
10581
|
-
|
|
10582
|
-
|
|
10583
|
-
|
|
10584
|
-
styler = styler.parent;
|
|
10963
|
+
}
|
|
10964
|
+
async function saveRunState(config, state) {
|
|
10965
|
+
const path = runFilePath(config, state.run_id);
|
|
10966
|
+
const payload = JSON.stringify({
|
|
10967
|
+
...state,
|
|
10968
|
+
updated_at: new Date().toISOString()
|
|
10969
|
+
}, null, 2);
|
|
10970
|
+
await writeFile(path, `${payload}
|
|
10971
|
+
`, "utf8");
|
|
10972
|
+
return path;
|
|
10973
|
+
}
|
|
10974
|
+
async function loadRunState(config, runId) {
|
|
10975
|
+
const path = runFilePath(config, runId);
|
|
10976
|
+
try {
|
|
10977
|
+
const raw = await readFile(path, "utf8");
|
|
10978
|
+
const parsed = JSON.parse(raw);
|
|
10979
|
+
if (!parsed || typeof parsed !== "object" || parsed.run_id !== runId) {
|
|
10980
|
+
throw new StorageError(`Run state file is invalid for run id "${runId}".`);
|
|
10981
|
+
}
|
|
10982
|
+
if (!Array.isArray(parsed.step_history)) {
|
|
10983
|
+
parsed.step_history = [];
|
|
10585
10984
|
}
|
|
10985
|
+
return parsed;
|
|
10986
|
+
} catch (error) {
|
|
10987
|
+
if (error instanceof StorageError) {
|
|
10988
|
+
throw error;
|
|
10989
|
+
}
|
|
10990
|
+
throw new StorageError(`Failed to load run state for "${runId}".`);
|
|
10586
10991
|
}
|
|
10587
|
-
|
|
10588
|
-
|
|
10589
|
-
|
|
10590
|
-
|
|
10992
|
+
}
|
|
10993
|
+
|
|
10994
|
+
// src/lib/prompt-composer.ts
|
|
10995
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
10996
|
+
import { dirname, resolve as resolve4 } from "node:path";
|
|
10997
|
+
function stripFrontmatter(content) {
|
|
10998
|
+
const match = content.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/);
|
|
10999
|
+
return match ? content.slice(match[0].length) : content;
|
|
11000
|
+
}
|
|
11001
|
+
async function loadPromptFile(workflowPath, promptFileName) {
|
|
11002
|
+
const promptPath = resolve4(dirname(workflowPath), promptFileName);
|
|
11003
|
+
try {
|
|
11004
|
+
const raw = await readFile2(promptPath, "utf8");
|
|
11005
|
+
return stripFrontmatter(raw);
|
|
11006
|
+
} catch {
|
|
11007
|
+
throw new ConfigError(`Prompt file not found: ${promptPath}`);
|
|
10591
11008
|
}
|
|
10592
|
-
|
|
10593
|
-
|
|
10594
|
-
|
|
10595
|
-
|
|
10596
|
-
|
|
10597
|
-
|
|
11009
|
+
}
|
|
11010
|
+
function composePrompt(promptFile, promptInline) {
|
|
11011
|
+
const parts = [];
|
|
11012
|
+
if (promptFile) {
|
|
11013
|
+
parts.push(promptFile.trimEnd());
|
|
11014
|
+
}
|
|
11015
|
+
if (promptInline) {
|
|
11016
|
+
parts.push(promptInline.trimEnd());
|
|
11017
|
+
}
|
|
11018
|
+
return parts.join(`
|
|
10598
11019
|
|
|
10599
|
-
|
|
10600
|
-
var isTTY = process.stdout.isTTY === true;
|
|
10601
|
-
function getTerminalWidth() {
|
|
10602
|
-
return process.stdout.columns ?? 80;
|
|
11020
|
+
`);
|
|
10603
11021
|
}
|
|
10604
|
-
|
|
10605
|
-
|
|
10606
|
-
|
|
11022
|
+
|
|
11023
|
+
// src/lib/harness-adapters.ts
|
|
11024
|
+
function createPassthroughParser() {
|
|
11025
|
+
return (line) => ({ text: line + `
|
|
11026
|
+
` });
|
|
10607
11027
|
}
|
|
10608
|
-
function
|
|
10609
|
-
if (
|
|
10610
|
-
return
|
|
11028
|
+
function withModelArgs(model, args) {
|
|
11029
|
+
if (!model) {
|
|
11030
|
+
return args;
|
|
10611
11031
|
}
|
|
10612
|
-
return
|
|
11032
|
+
return [...args, "--model", model];
|
|
10613
11033
|
}
|
|
10614
|
-
function
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
|
|
10619
|
-
|
|
10620
|
-
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
11034
|
+
function opencodePermissionEnv() {
|
|
11035
|
+
return {
|
|
11036
|
+
OPENCODE_PERMISSION: JSON.stringify({
|
|
11037
|
+
"*": "allow",
|
|
11038
|
+
external_directory: "allow",
|
|
11039
|
+
doom_loop: "allow"
|
|
11040
|
+
})
|
|
11041
|
+
};
|
|
11042
|
+
}
|
|
11043
|
+
function claudeStreamFlags() {
|
|
11044
|
+
return ["--output-format", "stream-json", "--verbose", "--include-partial-messages"];
|
|
11045
|
+
}
|
|
11046
|
+
function createOpenCodeStreamParser() {
|
|
11047
|
+
return (line) => {
|
|
11048
|
+
if (!line.trim()) {
|
|
11049
|
+
return null;
|
|
10624
11050
|
}
|
|
10625
|
-
|
|
10626
|
-
|
|
10627
|
-
|
|
10628
|
-
|
|
10629
|
-
|
|
10630
|
-
|
|
10631
|
-
|
|
11051
|
+
let obj;
|
|
11052
|
+
try {
|
|
11053
|
+
obj = JSON.parse(line);
|
|
11054
|
+
} catch {
|
|
11055
|
+
return null;
|
|
11056
|
+
}
|
|
11057
|
+
const type = obj.type;
|
|
11058
|
+
const sessionId = typeof obj.sessionID === "string" ? obj.sessionID : undefined;
|
|
11059
|
+
if (type === "text") {
|
|
11060
|
+
const part = obj.part;
|
|
11061
|
+
const text = typeof part?.text === "string" ? part.text : "";
|
|
11062
|
+
return { text, sessionId };
|
|
11063
|
+
}
|
|
11064
|
+
if (type === "tool_use") {
|
|
11065
|
+
const part = obj.part;
|
|
11066
|
+
const toolName = typeof part?.tool === "string" ? part.tool : undefined;
|
|
11067
|
+
const state = part?.state;
|
|
11068
|
+
const input = state?.input;
|
|
11069
|
+
const toolInput = input ? JSON.stringify(input) : undefined;
|
|
11070
|
+
return { text: "", sessionId, toolName, toolInput };
|
|
11071
|
+
}
|
|
11072
|
+
if (sessionId) {
|
|
11073
|
+
return { text: "", sessionId };
|
|
11074
|
+
}
|
|
11075
|
+
return null;
|
|
11076
|
+
};
|
|
10632
11077
|
}
|
|
10633
|
-
|
|
10634
|
-
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
workflowHeader(info) {
|
|
10638
|
-
const line = isTTY ? "─" : "-";
|
|
10639
|
-
const corner = {
|
|
10640
|
-
tl: isTTY ? "╭" : "+",
|
|
10641
|
-
tr: isTTY ? "╮" : "+",
|
|
10642
|
-
bl: isTTY ? "╰" : "+",
|
|
10643
|
-
br: isTTY ? "╯" : "+"
|
|
10644
|
-
};
|
|
10645
|
-
const width = getBoxWidth();
|
|
10646
|
-
const contentWidth = width - 4;
|
|
10647
|
-
const border = line.repeat(width - 2);
|
|
10648
|
-
const labelWidth = 10;
|
|
10649
|
-
const valueWidth = contentWidth - labelWidth;
|
|
10650
|
-
const formatLine = (label, value) => {
|
|
10651
|
-
const paddedLabel = label ? `${label}:`.padEnd(labelWidth) : " ".repeat(labelWidth);
|
|
10652
|
-
const truncatedValue = truncate(value, valueWidth);
|
|
10653
|
-
return `${paddedLabel}${truncatedValue}`.padEnd(contentWidth);
|
|
10654
|
-
};
|
|
10655
|
-
process.stdout.write(`
|
|
10656
|
-
`);
|
|
10657
|
-
process.stdout.write(isTTY ? source_default.cyan(`${corner.tl}${line} ${info.title} ${border.slice(info.title.length + 3)}${corner.tr}
|
|
10658
|
-
`) : `${corner.tl}${line} ${info.title} ${border.slice(info.title.length + 3)}${corner.tr}
|
|
10659
|
-
`);
|
|
10660
|
-
process.stdout.write(isTTY ? source_default.dim(`│ ${formatLine("workflow", info.workflow)} │
|
|
10661
|
-
`) : `│ ${formatLine("workflow", info.workflow)} │
|
|
10662
|
-
`);
|
|
10663
|
-
process.stdout.write(isTTY ? source_default.dim(`│ ${formatLine("run-id", info.runId)} │
|
|
10664
|
-
`) : `│ ${formatLine("run-id", info.runId)} │
|
|
10665
|
-
`);
|
|
10666
|
-
process.stdout.write(isTTY ? source_default.dim(`│ ${formatLine("step", info.currentStep)} │
|
|
10667
|
-
`) : `│ ${formatLine("step", info.currentStep)} │
|
|
10668
|
-
`);
|
|
10669
|
-
const taskLines = wrapText(info.task, valueWidth);
|
|
10670
|
-
for (let i = 0;i < taskLines.length; i++) {
|
|
10671
|
-
const label = i === 0 ? "task" : "";
|
|
10672
|
-
const content = formatLine(label, taskLines[i] ?? "");
|
|
10673
|
-
process.stdout.write(isTTY ? source_default.dim(`│ ${content} │
|
|
10674
|
-
`) : `│ ${content} │
|
|
10675
|
-
`);
|
|
11078
|
+
function createCodexStreamParser() {
|
|
11079
|
+
return (line) => {
|
|
11080
|
+
if (!line.trim()) {
|
|
11081
|
+
return null;
|
|
10676
11082
|
}
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
|
|
10682
|
-
},
|
|
10683
|
-
stepStart(stepNumber, stepId, agentId) {
|
|
10684
|
-
const line = isTTY ? "─" : "-";
|
|
10685
|
-
const corner = { tl: isTTY ? "┌" : "+", tr: isTTY ? "┐" : "+" };
|
|
10686
|
-
const label = ` Step ${stepNumber}: ${stepId} (${agentId}) `;
|
|
10687
|
-
const width = getBoxWidth();
|
|
10688
|
-
const remaining = Math.max(0, width - label.length - 2);
|
|
10689
|
-
const border = line.repeat(remaining);
|
|
10690
|
-
process.stdout.write(`
|
|
10691
|
-
`);
|
|
10692
|
-
process.stdout.write(isTTY ? source_default.cyan.bold(`${corner.tl}${line}${label}${border}${corner.tr}
|
|
10693
|
-
`) : `${corner.tl}${line}${label}${border}${corner.tr}
|
|
10694
|
-
`);
|
|
10695
|
-
process.stdout.write(`
|
|
10696
|
-
`);
|
|
10697
|
-
},
|
|
10698
|
-
stepEnd() {
|
|
10699
|
-
const line = isTTY ? "─" : "-";
|
|
10700
|
-
const corner = { bl: isTTY ? "└" : "+", br: isTTY ? "┘" : "+" };
|
|
10701
|
-
const width = getBoxWidth();
|
|
10702
|
-
const border = line.repeat(width - 2);
|
|
10703
|
-
process.stdout.write(`
|
|
10704
|
-
`);
|
|
10705
|
-
process.stdout.write(isTTY ? source_default.cyan(`${corner.bl}${border}${corner.br}
|
|
10706
|
-
`) : `${corner.bl}${border}${corner.br}
|
|
10707
|
-
`);
|
|
10708
|
-
},
|
|
10709
|
-
printToolCall(toolName, toolInput) {
|
|
10710
|
-
const width = getBoxWidth();
|
|
10711
|
-
const maxInputLength = width - 10;
|
|
10712
|
-
const truncatedInput = truncate(toolInput, maxInputLength);
|
|
10713
|
-
if (isTTY) {
|
|
10714
|
-
process.stderr.write(source_default.cyan(` ${toolName} `) + source_default.dim(truncatedInput) + `
|
|
10715
|
-
`);
|
|
10716
|
-
} else {
|
|
10717
|
-
process.stderr.write(` ${toolName} ${truncatedInput}
|
|
10718
|
-
`);
|
|
11083
|
+
let obj;
|
|
11084
|
+
try {
|
|
11085
|
+
obj = JSON.parse(line);
|
|
11086
|
+
} catch {
|
|
11087
|
+
return null;
|
|
10719
11088
|
}
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
return;
|
|
11089
|
+
const type = obj.type;
|
|
11090
|
+
if (type === "thread.started") {
|
|
11091
|
+
const sessionId = typeof obj.thread_id === "string" ? obj.thread_id : undefined;
|
|
11092
|
+
return sessionId ? { text: "", sessionId } : null;
|
|
10725
11093
|
}
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
|
|
10737
|
-
|
|
10738
|
-
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
|
|
11094
|
+
if (type === "item.completed") {
|
|
11095
|
+
const item = obj.item;
|
|
11096
|
+
if (!item) {
|
|
11097
|
+
return null;
|
|
11098
|
+
}
|
|
11099
|
+
if (item.type === "agent_message") {
|
|
11100
|
+
const text = typeof item.text === "string" ? item.text : "";
|
|
11101
|
+
return { text };
|
|
11102
|
+
}
|
|
11103
|
+
if (item.type === "command_execution") {
|
|
11104
|
+
const command = typeof item.command === "string" ? item.command : "shell";
|
|
11105
|
+
return { text: "", toolName: "shell", toolInput: command };
|
|
11106
|
+
}
|
|
11107
|
+
return null;
|
|
11108
|
+
}
|
|
11109
|
+
if (type === "item.started") {
|
|
11110
|
+
const item = obj.item;
|
|
11111
|
+
if (item?.type === "command_execution") {
|
|
11112
|
+
const command = typeof item.command === "string" ? item.command : "shell";
|
|
11113
|
+
return { text: "", toolName: "shell", toolInput: command };
|
|
11114
|
+
}
|
|
11115
|
+
return null;
|
|
11116
|
+
}
|
|
11117
|
+
return null;
|
|
11118
|
+
};
|
|
11119
|
+
}
|
|
11120
|
+
function createClaudeStreamParser() {
|
|
11121
|
+
let currentToolName = null;
|
|
11122
|
+
let currentToolInput = "";
|
|
11123
|
+
let currentBlockIndex = null;
|
|
11124
|
+
return (line) => {
|
|
11125
|
+
if (!line.trim()) {
|
|
11126
|
+
return null;
|
|
11127
|
+
}
|
|
11128
|
+
let obj;
|
|
11129
|
+
try {
|
|
11130
|
+
obj = JSON.parse(line);
|
|
11131
|
+
} catch {
|
|
11132
|
+
return null;
|
|
11133
|
+
}
|
|
11134
|
+
const type = obj.type;
|
|
11135
|
+
const sessionId = typeof obj.session_id === "string" ? obj.session_id : undefined;
|
|
11136
|
+
if (type === "stream_event") {
|
|
11137
|
+
const event = obj.event;
|
|
11138
|
+
const index = typeof event?.index === "number" ? event.index : null;
|
|
11139
|
+
if (event?.type === "content_block_start") {
|
|
11140
|
+
const block = event.content_block;
|
|
11141
|
+
if (block?.type === "tool_use" && typeof block.name === "string") {
|
|
11142
|
+
currentToolName = block.name;
|
|
11143
|
+
currentToolInput = "";
|
|
11144
|
+
currentBlockIndex = index;
|
|
11145
|
+
return sessionId ? { text: "", sessionId } : null;
|
|
10755
11146
|
}
|
|
10756
11147
|
}
|
|
10757
|
-
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
|
|
10761
|
-
|
|
10762
|
-
|
|
10763
|
-
|
|
11148
|
+
if (event?.type === "content_block_delta") {
|
|
11149
|
+
const delta = event.delta;
|
|
11150
|
+
if (delta?.type === "text_delta" && typeof delta.text === "string") {
|
|
11151
|
+
return { text: delta.text, sessionId };
|
|
11152
|
+
}
|
|
11153
|
+
if (delta?.type === "input_json_delta" && typeof delta.partial_json === "string") {
|
|
11154
|
+
currentToolInput += delta.partial_json;
|
|
11155
|
+
return sessionId ? { text: "", sessionId } : null;
|
|
11156
|
+
}
|
|
11157
|
+
return sessionId ? { text: "", sessionId } : null;
|
|
10764
11158
|
}
|
|
10765
|
-
|
|
10766
|
-
if (
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
11159
|
+
if (event?.type === "content_block_stop") {
|
|
11160
|
+
if (currentToolName && index === currentBlockIndex) {
|
|
11161
|
+
const result = {
|
|
11162
|
+
text: "",
|
|
11163
|
+
sessionId,
|
|
11164
|
+
toolName: currentToolName,
|
|
11165
|
+
toolInput: currentToolInput || undefined
|
|
11166
|
+
};
|
|
11167
|
+
currentToolName = null;
|
|
11168
|
+
currentToolInput = "";
|
|
11169
|
+
currentBlockIndex = null;
|
|
11170
|
+
return result;
|
|
10772
11171
|
}
|
|
10773
11172
|
}
|
|
11173
|
+
return sessionId ? { text: "", sessionId } : null;
|
|
11174
|
+
}
|
|
11175
|
+
if (type === "result") {
|
|
11176
|
+
return sessionId ? { text: "", sessionId } : null;
|
|
11177
|
+
}
|
|
11178
|
+
if (type === "system") {
|
|
11179
|
+
return sessionId ? { text: "", sessionId } : null;
|
|
11180
|
+
}
|
|
11181
|
+
return null;
|
|
11182
|
+
};
|
|
11183
|
+
}
|
|
11184
|
+
var adapters = {
|
|
11185
|
+
claude: {
|
|
11186
|
+
name: "claude",
|
|
11187
|
+
buildRunCommand(prompt, options) {
|
|
11188
|
+
const allowArgs = options.allowAll ? ["--dangerously-skip-permissions"] : [];
|
|
11189
|
+
const base = ["-p", prompt, ...claudeStreamFlags()];
|
|
11190
|
+
return { binary: "claude", args: withModelArgs(options.model, [...allowArgs, ...base]) };
|
|
11191
|
+
},
|
|
11192
|
+
buildResumeCommand(sessionId, prompt, options) {
|
|
11193
|
+
const allowArgs = options.allowAll ? ["--dangerously-skip-permissions"] : [];
|
|
11194
|
+
const base = [...allowArgs, "--resume", sessionId, "-p", prompt, ...claudeStreamFlags()];
|
|
11195
|
+
return { binary: "claude", args: withModelArgs(options.model, base) };
|
|
11196
|
+
},
|
|
11197
|
+
createStreamParser: createClaudeStreamParser,
|
|
11198
|
+
resumeTemplate(sessionId) {
|
|
11199
|
+
return `claude --resume ${sessionId}`;
|
|
10774
11200
|
}
|
|
10775
11201
|
},
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
|
|
10788
|
-
|
|
10789
|
-
|
|
10790
|
-
|
|
10791
|
-
|
|
10792
|
-
|
|
10793
|
-
|
|
10794
|
-
|
|
10795
|
-
|
|
10796
|
-
|
|
10797
|
-
|
|
10798
|
-
process.stdout.write(`${text}
|
|
10799
|
-
`);
|
|
11202
|
+
opencode: {
|
|
11203
|
+
name: "opencode",
|
|
11204
|
+
buildRunCommand(prompt, options) {
|
|
11205
|
+
const args = ["run", "--format", "json", prompt];
|
|
11206
|
+
return {
|
|
11207
|
+
binary: "opencode",
|
|
11208
|
+
args: withModelArgs(options.model, args),
|
|
11209
|
+
...options.allowAll ? { env: opencodePermissionEnv() } : {}
|
|
11210
|
+
};
|
|
11211
|
+
},
|
|
11212
|
+
buildResumeCommand(sessionId, prompt, options) {
|
|
11213
|
+
const args = ["run", "--format", "json", "--session", sessionId, prompt];
|
|
11214
|
+
return {
|
|
11215
|
+
binary: "opencode",
|
|
11216
|
+
args: withModelArgs(options.model, args),
|
|
11217
|
+
...options.allowAll ? { env: opencodePermissionEnv() } : {}
|
|
11218
|
+
};
|
|
11219
|
+
},
|
|
11220
|
+
createStreamParser: createOpenCodeStreamParser,
|
|
11221
|
+
resumeTemplate(sessionId) {
|
|
11222
|
+
return `opencode run --session ${sessionId}`;
|
|
11223
|
+
}
|
|
10800
11224
|
},
|
|
10801
|
-
|
|
10802
|
-
|
|
11225
|
+
codex: {
|
|
11226
|
+
name: "codex",
|
|
11227
|
+
buildRunCommand(prompt, options) {
|
|
11228
|
+
const auto = options.allowAll ? ["--dangerously-bypass-approvals-and-sandbox"] : [];
|
|
11229
|
+
const args = ["exec", "--json", ...auto, prompt];
|
|
11230
|
+
return { binary: "codex", args: withModelArgs(options.model, args) };
|
|
11231
|
+
},
|
|
11232
|
+
buildResumeCommand(sessionId, prompt, options) {
|
|
11233
|
+
const auto = options.allowAll ? ["--dangerously-bypass-approvals-and-sandbox"] : [];
|
|
11234
|
+
const args = ["exec", "resume", "--json", ...auto, sessionId, prompt];
|
|
11235
|
+
return { binary: "codex", args: withModelArgs(options.model, args) };
|
|
11236
|
+
},
|
|
11237
|
+
createStreamParser: createCodexStreamParser,
|
|
11238
|
+
resumeTemplate(sessionId) {
|
|
11239
|
+
return `codex exec resume ${sessionId} "<prompt>"`;
|
|
11240
|
+
}
|
|
10803
11241
|
},
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
|
|
10816
|
-
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
`);
|
|
10820
|
-
process.stdout.write(` ${info.resumeCommand}
|
|
10821
|
-
`);
|
|
10822
|
-
process.stdout.write(`
|
|
10823
|
-
`);
|
|
11242
|
+
copilot: {
|
|
11243
|
+
name: "copilot",
|
|
11244
|
+
buildRunCommand(prompt, options) {
|
|
11245
|
+
const auto = options.allowAll ? ["--allow-all", "--no-ask-user"] : [];
|
|
11246
|
+
const args = [...auto, "-p", prompt];
|
|
11247
|
+
return { binary: "copilot", args: withModelArgs(options.model, args) };
|
|
11248
|
+
},
|
|
11249
|
+
buildResumeCommand(_sessionId, prompt, options) {
|
|
11250
|
+
const args = ["-p", prompt];
|
|
11251
|
+
return { binary: "copilot", args: withModelArgs(options.model, args) };
|
|
11252
|
+
},
|
|
11253
|
+
createStreamParser: createPassthroughParser,
|
|
11254
|
+
resumeTemplate(sessionId) {
|
|
11255
|
+
return `copilot --resume ${sessionId}`;
|
|
11256
|
+
}
|
|
10824
11257
|
}
|
|
10825
11258
|
};
|
|
11259
|
+
function getHarnessAdapter(name) {
|
|
11260
|
+
const adapter = adapters[name];
|
|
11261
|
+
if (!adapter) {
|
|
11262
|
+
throw new ValidationError(`Unknown harness "${name}".`);
|
|
11263
|
+
}
|
|
11264
|
+
return adapter;
|
|
11265
|
+
}
|
|
10826
11266
|
|
|
10827
11267
|
// src/lib/process-runner.ts
|
|
11268
|
+
import { spawn } from "node:child_process";
|
|
10828
11269
|
function formatToolInput(toolInput) {
|
|
10829
11270
|
try {
|
|
10830
11271
|
const parsed = JSON.parse(toolInput);
|
|
@@ -10845,7 +11286,8 @@ function formatToolInput(toolInput) {
|
|
|
10845
11286
|
async function runHarnessCommand(command, parseStreamLine) {
|
|
10846
11287
|
return new Promise((resolve5, reject) => {
|
|
10847
11288
|
const child = spawn(command.binary, command.args, {
|
|
10848
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
11289
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
11290
|
+
...command.env ? { env: { ...process.env, ...command.env } } : {}
|
|
10849
11291
|
});
|
|
10850
11292
|
child.on("error", (err) => {
|
|
10851
11293
|
if (err.code === "ENOENT") {
|
|
@@ -10997,6 +11439,20 @@ function outputSnippet(output) {
|
|
|
10997
11439
|
const compact = trimmed.replace(/\s+/g, " ");
|
|
10998
11440
|
return compact.length > 220 ? `${compact.slice(0, 220)}...` : compact;
|
|
10999
11441
|
}
|
|
11442
|
+
function harnessExitReason(params) {
|
|
11443
|
+
const stderrSnippet = outputSnippet(params.stderr);
|
|
11444
|
+
const outputPreview = outputSnippet(params.combinedOutput);
|
|
11445
|
+
const details = [`harness=${params.harness}`];
|
|
11446
|
+
if (params.model) {
|
|
11447
|
+
details.push(`model=${params.model}`);
|
|
11448
|
+
}
|
|
11449
|
+
if (stderrSnippet !== "(no output)") {
|
|
11450
|
+
details.push(`stderr=${stderrSnippet}`);
|
|
11451
|
+
} else if (outputPreview !== "(no output)") {
|
|
11452
|
+
details.push(`output=${outputPreview}`);
|
|
11453
|
+
}
|
|
11454
|
+
return `Harness exited with code ${params.exitCode} at step "${params.stepId}" (${details.join("; ")}).`;
|
|
11455
|
+
}
|
|
11000
11456
|
async function pauseRun(config, runState, reason, harnessName, sessionId) {
|
|
11001
11457
|
runState.status = "paused_human";
|
|
11002
11458
|
await saveRunState(config, runState);
|
|
@@ -11008,12 +11464,12 @@ async function pauseRun(config, runState, reason, harnessName, sessionId) {
|
|
|
11008
11464
|
resumeCommand: adapter.resumeTemplate(resolvedSession)
|
|
11009
11465
|
});
|
|
11010
11466
|
}
|
|
11011
|
-
function applyOutputToContext(context,
|
|
11467
|
+
function applyOutputToContext(context, stepId, values) {
|
|
11012
11468
|
for (const [key, value] of Object.entries(values)) {
|
|
11013
11469
|
if (key === "status" || key === "next_state") {
|
|
11014
11470
|
continue;
|
|
11015
11471
|
}
|
|
11016
|
-
context[`${
|
|
11472
|
+
context[`${stepId}.${key}`] = value;
|
|
11017
11473
|
}
|
|
11018
11474
|
}
|
|
11019
11475
|
async function runWorkflow(config, workflow, runState, options) {
|
|
@@ -11028,27 +11484,23 @@ async function runWorkflow(config, workflow, runState, options) {
|
|
|
11028
11484
|
await pauseRun(config, runState, `Current step "${runState.current_step}" not found in workflow.`, runState.last_harness?.name ?? "claude", runState.last_harness?.session_id ?? null);
|
|
11029
11485
|
return runState;
|
|
11030
11486
|
}
|
|
11031
|
-
const agent = workflow.agents.find((item) => item.id === step.agent);
|
|
11032
|
-
if (!agent) {
|
|
11033
|
-
await pauseRun(config, runState, `Unknown agent "${step.agent}" for step "${step.id}".`, runState.last_harness?.name ?? "claude", runState.last_harness?.session_id ?? null);
|
|
11034
|
-
return runState;
|
|
11035
|
-
}
|
|
11036
11487
|
const stepStartedAt = new Date().toISOString();
|
|
11037
|
-
ui.stepStart(stepNumber, step.id, agent.id);
|
|
11038
11488
|
try {
|
|
11039
|
-
assertRequiredInputs(step.
|
|
11040
|
-
const
|
|
11489
|
+
assertRequiredInputs(step.requires.inputs, runState.context);
|
|
11490
|
+
const fileContent = step.prompt_file ? await loadPromptFile(runState.workflow_path, step.prompt_file) : undefined;
|
|
11491
|
+
const rawPrompt = composePrompt(fileContent, step.prompt);
|
|
11492
|
+
const resolvedPrompt = resolveTemplate(rawPrompt, runState.context);
|
|
11041
11493
|
const injectedHint = isFirstIteration && typeof options.overrides?.hint === "string" ? options.overrides.hint.trim() : "";
|
|
11042
|
-
const
|
|
11494
|
+
const prompt = injectedHint ? `${resolvedPrompt}
|
|
11043
11495
|
|
|
11044
|
-
Note: ${injectedHint}` :
|
|
11045
|
-
const
|
|
11046
|
-
const prompt = composePrompt(agentPrompt, renderedInput);
|
|
11047
|
-
const harness = options.overrides?.harness ?? agent.harness;
|
|
11496
|
+
Note: ${injectedHint}` : resolvedPrompt;
|
|
11497
|
+
const harness = step.harness;
|
|
11048
11498
|
const adapter = getHarnessAdapter(harness);
|
|
11049
|
-
const effectiveModel =
|
|
11499
|
+
const effectiveModel = step.model;
|
|
11050
11500
|
const adapterOptions = typeof effectiveModel === "string" ? { allowAll: options.allowAll, model: effectiveModel } : { allowAll: options.allowAll };
|
|
11051
|
-
|
|
11501
|
+
ui.stepStart(stepNumber, step.id, harness, effectiveModel);
|
|
11502
|
+
const lastSessionMatchesHarness = runState.last_harness?.name === harness ? runState.last_harness.session_id : null;
|
|
11503
|
+
const selectedSessionId = isFirstIteration && options.overrides?.sessionId ? options.overrides.sessionId : lastSessionMatchesHarness;
|
|
11052
11504
|
const command = isFirstIteration && selectedSessionId ? adapter.buildResumeCommand(selectedSessionId, prompt, {
|
|
11053
11505
|
...adapterOptions
|
|
11054
11506
|
}) : adapter.buildRunCommand(prompt, {
|
|
@@ -11064,7 +11516,14 @@ Note: ${injectedHint}` : resolvedInput;
|
|
|
11064
11516
|
runState.last_harness.session_id = result.sessionId;
|
|
11065
11517
|
}
|
|
11066
11518
|
if (result.exitCode !== 0) {
|
|
11067
|
-
await pauseRun(config, runState,
|
|
11519
|
+
await pauseRun(config, runState, harnessExitReason({
|
|
11520
|
+
stepId: step.id,
|
|
11521
|
+
harness,
|
|
11522
|
+
exitCode: result.exitCode,
|
|
11523
|
+
stderr: result.stderr,
|
|
11524
|
+
combinedOutput: result.combinedOutput,
|
|
11525
|
+
...effectiveModel ? { model: effectiveModel } : {}
|
|
11526
|
+
}), harness, runState.last_harness.session_id);
|
|
11068
11527
|
return runState;
|
|
11069
11528
|
}
|
|
11070
11529
|
if (result.combinedOutput.includes(HUMAN_SENTINEL)) {
|
|
@@ -11074,15 +11533,15 @@ Note: ${injectedHint}` : resolvedInput;
|
|
|
11074
11533
|
let stepOutput;
|
|
11075
11534
|
try {
|
|
11076
11535
|
stepOutput = parseRmrOutput(result.combinedOutput);
|
|
11077
|
-
validateRequiredOutputKeys(stepOutput, step.outputs
|
|
11536
|
+
validateRequiredOutputKeys(stepOutput, step.requires.outputs);
|
|
11078
11537
|
} catch (error) {
|
|
11079
11538
|
const message = error instanceof Error ? error.message : "Failed to parse step output.";
|
|
11080
|
-
await pauseRun(config, runState,
|
|
11539
|
+
await pauseRun(config, runState, message, harness, runState.last_harness.session_id);
|
|
11081
11540
|
return runState;
|
|
11082
11541
|
}
|
|
11083
11542
|
ui.stepOutputs(stepOutput.values);
|
|
11084
11543
|
applyOutputToContext(runState.context, step.id, stepOutput.values);
|
|
11085
|
-
const nextState = stepOutput.next_state ?? step.
|
|
11544
|
+
const nextState = stepOutput.next_state ?? step.next_step;
|
|
11086
11545
|
if (!isValidTarget(workflow, nextState)) {
|
|
11087
11546
|
await pauseRun(config, runState, `Invalid next_state "${nextState}" at step "${step.id}".`, harness, runState.last_harness.session_id);
|
|
11088
11547
|
return runState;
|
|
@@ -11094,7 +11553,6 @@ Note: ${injectedHint}` : resolvedInput;
|
|
|
11094
11553
|
const stepExecution = {
|
|
11095
11554
|
step_number: stepNumber,
|
|
11096
11555
|
step_id: step.id,
|
|
11097
|
-
agent_id: agent.id,
|
|
11098
11556
|
session_id: runState.last_harness?.session_id ?? null,
|
|
11099
11557
|
started_at: stepStartedAt,
|
|
11100
11558
|
completed_at: new Date().toISOString()
|
|
@@ -11114,25 +11572,13 @@ Note: ${injectedHint}` : resolvedInput;
|
|
|
11114
11572
|
isFirstIteration = false;
|
|
11115
11573
|
} catch (error) {
|
|
11116
11574
|
const reason = error instanceof Error ? error.message : "Unknown execution error.";
|
|
11117
|
-
await pauseRun(config, runState, `${reason} (step "${step.id}")`,
|
|
11575
|
+
await pauseRun(config, runState, `${reason} (step "${step.id}")`, step.harness, runState.last_harness?.session_id ?? null);
|
|
11118
11576
|
return runState;
|
|
11119
11577
|
}
|
|
11120
11578
|
}
|
|
11121
11579
|
return runState;
|
|
11122
11580
|
}
|
|
11123
11581
|
|
|
11124
|
-
// src/lib/types.ts
|
|
11125
|
-
var HARNESSES = ["claude", "opencode", "codex", "copilot"];
|
|
11126
|
-
function parseHarnessOverride(value) {
|
|
11127
|
-
if (!value) {
|
|
11128
|
-
return;
|
|
11129
|
-
}
|
|
11130
|
-
if (!HARNESSES.includes(value)) {
|
|
11131
|
-
throw new UserInputError(`Invalid harness override "${value}". Expected one of: ${HARNESSES.join(", ")}.`);
|
|
11132
|
-
}
|
|
11133
|
-
return value;
|
|
11134
|
-
}
|
|
11135
|
-
|
|
11136
11582
|
// src/lib/version.ts
|
|
11137
11583
|
import { readFileSync } from "node:fs";
|
|
11138
11584
|
import { dirname as dirname2, resolve as resolve5 } from "node:path";
|
|
@@ -11308,81 +11754,85 @@ async function loadWorkflowDefinition(workflowPath) {
|
|
|
11308
11754
|
const id = ensureString(parsed.id, "id");
|
|
11309
11755
|
const name = ensureString(parsed.name, "name");
|
|
11310
11756
|
const version = typeof parsed.version === "string" ? parsed.version : undefined;
|
|
11311
|
-
|
|
11312
|
-
|
|
11757
|
+
let topLevelHarness;
|
|
11758
|
+
if (typeof parsed.harness === "string" && parsed.harness.trim() !== "") {
|
|
11759
|
+
const h = parsed.harness.trim();
|
|
11760
|
+
if (!SUPPORTED_HARNESSES.has(h)) {
|
|
11761
|
+
throw new ValidationError(`Unsupported top-level harness "${h}".`);
|
|
11762
|
+
}
|
|
11763
|
+
topLevelHarness = h;
|
|
11313
11764
|
}
|
|
11765
|
+
const topLevelModel = typeof parsed.model === "string" && parsed.model.trim() !== "" ? parsed.model.trim() : undefined;
|
|
11314
11766
|
if (!Array.isArray(parsed.steps) || parsed.steps.length === 0) {
|
|
11315
11767
|
throw new ValidationError("Workflow must define a non-empty steps array.");
|
|
11316
11768
|
}
|
|
11317
|
-
const
|
|
11318
|
-
if (!
|
|
11319
|
-
throw new ValidationError(`Invalid
|
|
11320
|
-
}
|
|
11321
|
-
const agent = rawAgent;
|
|
11322
|
-
const agentId = ensureString(agent.id, `agents[${index}].id`);
|
|
11323
|
-
const harness = ensureString(agent.harness, `agents[${index}].harness`);
|
|
11324
|
-
if (!SUPPORTED_HARNESSES.has(harness)) {
|
|
11325
|
-
throw new ValidationError(`Unsupported harness "${harness}" for agent "${agentId}".`);
|
|
11769
|
+
const steps = parsed.steps.map((rawStep, index) => {
|
|
11770
|
+
if (!rawStep || typeof rawStep !== "object") {
|
|
11771
|
+
throw new ValidationError(`Invalid steps[${index}] definition.`);
|
|
11326
11772
|
}
|
|
11327
|
-
const
|
|
11328
|
-
const
|
|
11773
|
+
const step = rawStep;
|
|
11774
|
+
const stepId = ensureString(step.id, `steps[${index}].id`);
|
|
11775
|
+
let harness;
|
|
11776
|
+
if (typeof step.harness === "string" && step.harness.trim() !== "") {
|
|
11777
|
+
harness = step.harness.trim();
|
|
11778
|
+
if (!SUPPORTED_HARNESSES.has(harness)) {
|
|
11779
|
+
throw new ValidationError(`Unsupported harness "${harness}" for step "${stepId}".`);
|
|
11780
|
+
}
|
|
11781
|
+
} else if (topLevelHarness) {
|
|
11782
|
+
harness = topLevelHarness;
|
|
11783
|
+
} else {
|
|
11784
|
+
throw new ValidationError(`Step "${stepId}" has no harness and no top-level harness default is defined.`);
|
|
11785
|
+
}
|
|
11786
|
+
const stepModel = step.model;
|
|
11787
|
+
const effectiveModel = typeof stepModel === "string" && stepModel.trim() !== "" ? stepModel : topLevelModel;
|
|
11788
|
+
const hasPromptFile = typeof step.prompt_file === "string" && step.prompt_file.trim() !== "";
|
|
11789
|
+
const hasPrompt = typeof step.prompt === "string" && step.prompt.trim() !== "";
|
|
11790
|
+
if (!hasPromptFile && !hasPrompt) {
|
|
11791
|
+
throw new ValidationError(`Step "${stepId}" must define at least one of "prompt_file" or "prompt".`);
|
|
11792
|
+
}
|
|
11793
|
+
const requires = step.requires;
|
|
11794
|
+
const requiresInputs = requires && Array.isArray(requires.inputs) ? ensureStringArray(requires.inputs, `steps[${index}].requires.inputs`) : [];
|
|
11795
|
+
const requiresOutputs = requires && Array.isArray(requires.outputs) ? ensureStringArray(requires.outputs, `steps[${index}].requires.outputs`) : [];
|
|
11329
11796
|
const normalized = {
|
|
11330
|
-
id:
|
|
11797
|
+
id: stepId,
|
|
11331
11798
|
harness,
|
|
11332
|
-
|
|
11799
|
+
next_step: ensureString(step.next_step, `steps[${index}].next_step`),
|
|
11800
|
+
requires: {
|
|
11801
|
+
inputs: requiresInputs,
|
|
11802
|
+
outputs: requiresOutputs
|
|
11803
|
+
}
|
|
11333
11804
|
};
|
|
11334
|
-
if (
|
|
11335
|
-
|
|
11336
|
-
...normalized,
|
|
11337
|
-
model
|
|
11338
|
-
};
|
|
11805
|
+
if (hasPromptFile) {
|
|
11806
|
+
normalized.prompt_file = step.prompt_file.trim();
|
|
11339
11807
|
}
|
|
11340
|
-
|
|
11341
|
-
|
|
11342
|
-
const steps = parsed.steps.map((rawStep, index) => {
|
|
11343
|
-
if (!rawStep || typeof rawStep !== "object") {
|
|
11344
|
-
throw new ValidationError(`Invalid steps[${index}] definition.`);
|
|
11808
|
+
if (hasPrompt) {
|
|
11809
|
+
normalized.prompt = step.prompt;
|
|
11345
11810
|
}
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
if (!outputs || typeof outputs !== "object") {
|
|
11349
|
-
throw new ValidationError(`Invalid step field "steps[${index}].outputs": expected object.`);
|
|
11811
|
+
if (effectiveModel) {
|
|
11812
|
+
normalized.model = effectiveModel;
|
|
11350
11813
|
}
|
|
11351
|
-
return
|
|
11352
|
-
id: ensureString(step.id, `steps[${index}].id`),
|
|
11353
|
-
agent: ensureString(step.agent, `steps[${index}].agent`),
|
|
11354
|
-
default_next: ensureString(step.default_next, `steps[${index}].default_next`),
|
|
11355
|
-
input_required: ensureStringArray(step.input_required, `steps[${index}].input_required`),
|
|
11356
|
-
outputs: {
|
|
11357
|
-
required: ensureStringArray(outputs.required, `steps[${index}].outputs.required`)
|
|
11358
|
-
},
|
|
11359
|
-
input: ensureString(step.input, `steps[${index}].input`)
|
|
11360
|
-
};
|
|
11814
|
+
return normalized;
|
|
11361
11815
|
});
|
|
11362
|
-
validateUniqueness(agents.map((agent) => agent.id), "agent");
|
|
11363
11816
|
validateUniqueness(steps.map((step) => step.id), "step");
|
|
11364
|
-
const knownAgents = new Set(agents.map((agent) => agent.id));
|
|
11365
11817
|
const knownSteps = new Set(steps.map((step) => step.id));
|
|
11366
11818
|
for (const step of steps) {
|
|
11367
|
-
if (!knownAgents.has(step.agent)) {
|
|
11368
|
-
throw new ValidationError(`Unknown agent "${step.agent}" referenced by step "${step.id}".`);
|
|
11369
|
-
}
|
|
11370
11819
|
const validTransitionTargets = new Set([...knownSteps, "done", "human_intervention"]);
|
|
11371
|
-
if (!validTransitionTargets.has(step.
|
|
11372
|
-
throw new ValidationError(`Invalid
|
|
11820
|
+
if (!validTransitionTargets.has(step.next_step)) {
|
|
11821
|
+
throw new ValidationError(`Invalid next_step "${step.next_step}" in step "${step.id}".`);
|
|
11373
11822
|
}
|
|
11374
11823
|
}
|
|
11375
11824
|
return {
|
|
11376
11825
|
id,
|
|
11377
11826
|
name,
|
|
11378
11827
|
...version && { version },
|
|
11379
|
-
|
|
11828
|
+
...topLevelHarness && { harness: topLevelHarness },
|
|
11829
|
+
...topLevelModel && { model: topLevelModel },
|
|
11380
11830
|
steps
|
|
11381
11831
|
};
|
|
11382
11832
|
}
|
|
11383
11833
|
|
|
11384
11834
|
// src/commands/continue.ts
|
|
11385
|
-
class ContinueCommand extends
|
|
11835
|
+
class ContinueCommand extends BaseCommand {
|
|
11386
11836
|
static paths = [["continue"]];
|
|
11387
11837
|
static usage = Command.Usage({
|
|
11388
11838
|
category: "Workflow",
|
|
@@ -11396,8 +11846,8 @@ class ContinueCommand extends Command {
|
|
|
11396
11846
|
'$0 continue 20260316-153210Z --hint "Plan mode only: read and propose changes, do not edit files."'
|
|
11397
11847
|
],
|
|
11398
11848
|
[
|
|
11399
|
-
"Force
|
|
11400
|
-
"$0 continue 20260316-153210Z --
|
|
11849
|
+
"Force session override",
|
|
11850
|
+
"$0 continue 20260316-153210Z --session-id abc123"
|
|
11401
11851
|
]
|
|
11402
11852
|
]
|
|
11403
11853
|
});
|
|
@@ -11408,10 +11858,6 @@ class ContinueCommand extends Command {
|
|
|
11408
11858
|
required: false,
|
|
11409
11859
|
description: "Override current step id before resuming."
|
|
11410
11860
|
});
|
|
11411
|
-
harness = exports_options.String("--harness", {
|
|
11412
|
-
required: false,
|
|
11413
|
-
description: "Override harness for the resumed step."
|
|
11414
|
-
});
|
|
11415
11861
|
sessionId = exports_options.String("--session-id", {
|
|
11416
11862
|
required: false,
|
|
11417
11863
|
description: "Force harness session id for resume attempt."
|
|
@@ -11420,35 +11866,36 @@ class ContinueCommand extends Command {
|
|
|
11420
11866
|
required: false,
|
|
11421
11867
|
description: "Inject a one-time hint into the resumed harness prompt."
|
|
11422
11868
|
});
|
|
11869
|
+
allowAll = exports_options.Boolean("--allow-all", true, {
|
|
11870
|
+
description: "Enable harness auto-approval flags when supported (default: true)."
|
|
11871
|
+
});
|
|
11872
|
+
noAllowAll = exports_options.Boolean("--no-allow-all", false, {
|
|
11873
|
+
description: "Disable harness auto-approval flags."
|
|
11874
|
+
});
|
|
11423
11875
|
async execute() {
|
|
11424
11876
|
const showUpdateNotice = startUpdateCheck();
|
|
11425
11877
|
const config = await loadConfig();
|
|
11426
11878
|
const runState = await loadRunState(config, this.runId);
|
|
11427
11879
|
const workflow = await loadWorkflowDefinition(runState.workflow_path);
|
|
11428
|
-
const harnessOverride = parseHarnessOverride(this.harness);
|
|
11429
11880
|
runState.status = "running";
|
|
11430
11881
|
if (this.step) {
|
|
11431
11882
|
runState.current_step = this.step;
|
|
11432
11883
|
}
|
|
11884
|
+
const effectiveAllowAll = this.noAllowAll ? false : this.allowAll;
|
|
11433
11885
|
ui.workflowHeader({
|
|
11434
|
-
title:
|
|
11886
|
+
title: `${binaryName} continue`,
|
|
11435
11887
|
workflow: runState.workflow_path,
|
|
11436
11888
|
workflowId: workflow.id,
|
|
11437
11889
|
task: runState.context["task"] ?? "(continuing)",
|
|
11438
11890
|
runId: this.runId,
|
|
11439
|
-
currentStep: runState.current_step,
|
|
11440
11891
|
runFile: "",
|
|
11441
|
-
allowAll:
|
|
11442
|
-
harness: this.harness,
|
|
11892
|
+
allowAll: effectiveAllowAll,
|
|
11443
11893
|
varsCount: 0
|
|
11444
11894
|
});
|
|
11445
11895
|
const overrides = {};
|
|
11446
11896
|
if (this.step) {
|
|
11447
11897
|
overrides.stepId = this.step;
|
|
11448
11898
|
}
|
|
11449
|
-
if (harnessOverride) {
|
|
11450
|
-
overrides.harness = harnessOverride;
|
|
11451
|
-
}
|
|
11452
11899
|
if (this.sessionId) {
|
|
11453
11900
|
overrides.sessionId = this.sessionId;
|
|
11454
11901
|
}
|
|
@@ -11456,7 +11903,7 @@ class ContinueCommand extends Command {
|
|
|
11456
11903
|
overrides.hint = this.hint;
|
|
11457
11904
|
}
|
|
11458
11905
|
await runWorkflow(config, workflow, runState, {
|
|
11459
|
-
allowAll:
|
|
11906
|
+
allowAll: effectiveAllowAll,
|
|
11460
11907
|
overrides
|
|
11461
11908
|
});
|
|
11462
11909
|
showUpdateNotice();
|
|
@@ -11480,7 +11927,7 @@ function getExamplesWorkflowsDir() {
|
|
|
11480
11927
|
return fromSrc;
|
|
11481
11928
|
}
|
|
11482
11929
|
|
|
11483
|
-
class InstallCommand extends
|
|
11930
|
+
class InstallCommand extends BaseCommand {
|
|
11484
11931
|
static paths = [["install"]];
|
|
11485
11932
|
static usage = Command.Usage({
|
|
11486
11933
|
category: "Setup",
|
|
@@ -11506,76 +11953,191 @@ class InstallCommand extends Command {
|
|
|
11506
11953
|
}
|
|
11507
11954
|
if (existsSync(destinationDir)) {
|
|
11508
11955
|
ui.info(`Workflow already installed at .rmr/workflows/${this.workflowName}/`);
|
|
11509
|
-
ui.info(`Run it with:
|
|
11956
|
+
ui.info(`Run it with: ${binaryName} run .rmr/workflows/${this.workflowName}/workflow.yaml --task "Describe your task"`);
|
|
11510
11957
|
return 0;
|
|
11511
11958
|
}
|
|
11512
11959
|
await cp(sourceDir, destinationDir, { recursive: true, force: false, errorOnExist: true });
|
|
11513
11960
|
ui.success(`installed .rmr/workflows/${this.workflowName}/`);
|
|
11514
|
-
ui.info(`Run it with:
|
|
11961
|
+
ui.info(`Run it with: ${binaryName} run .rmr/workflows/${this.workflowName}/workflow.yaml --task "Describe your task"`);
|
|
11962
|
+
return 0;
|
|
11963
|
+
}
|
|
11964
|
+
}
|
|
11965
|
+
|
|
11966
|
+
// src/commands/list.ts
|
|
11967
|
+
import { readdir as readdir3 } from "node:fs/promises";
|
|
11968
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
11969
|
+
import { dirname as dirname4, resolve as resolve8 } from "node:path";
|
|
11970
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
11971
|
+
function getExamplesWorkflowsDir2() {
|
|
11972
|
+
const thisDir = dirname4(fileURLToPath3(import.meta.url));
|
|
11973
|
+
const fromDist = resolve8(thisDir, "..", "examples", "workflows");
|
|
11974
|
+
const fromSrc = resolve8(thisDir, "..", "..", "examples", "workflows");
|
|
11975
|
+
if (existsSync2(fromDist))
|
|
11976
|
+
return fromDist;
|
|
11977
|
+
if (existsSync2(fromSrc))
|
|
11978
|
+
return fromSrc;
|
|
11979
|
+
return fromSrc;
|
|
11980
|
+
}
|
|
11981
|
+
async function getInstalledWorkflows(workflowsDir) {
|
|
11982
|
+
if (!existsSync2(workflowsDir)) {
|
|
11983
|
+
return [];
|
|
11984
|
+
}
|
|
11985
|
+
const entries = await readdir3(workflowsDir, { withFileTypes: true });
|
|
11986
|
+
const workflows = [];
|
|
11987
|
+
for (const entry of entries) {
|
|
11988
|
+
if (!entry.isDirectory())
|
|
11989
|
+
continue;
|
|
11990
|
+
const workflowPath = resolve8(workflowsDir, entry.name, "workflow.yaml");
|
|
11991
|
+
if (!existsSync2(workflowPath))
|
|
11992
|
+
continue;
|
|
11993
|
+
try {
|
|
11994
|
+
const workflow = await loadWorkflowDefinition(workflowPath);
|
|
11995
|
+
workflows.push({
|
|
11996
|
+
id: workflow.id,
|
|
11997
|
+
name: workflow.name,
|
|
11998
|
+
path: `.rmr/workflows/${entry.name}/workflow.yaml`
|
|
11999
|
+
});
|
|
12000
|
+
} catch {
|
|
12001
|
+
workflows.push({
|
|
12002
|
+
id: entry.name,
|
|
12003
|
+
name: "(invalid workflow.yaml)",
|
|
12004
|
+
path: `.rmr/workflows/${entry.name}/workflow.yaml`
|
|
12005
|
+
});
|
|
12006
|
+
}
|
|
12007
|
+
}
|
|
12008
|
+
return workflows.sort((a, b) => a.id.localeCompare(b.id));
|
|
12009
|
+
}
|
|
12010
|
+
async function getBundledWorkflows(examplesDir) {
|
|
12011
|
+
if (!existsSync2(examplesDir)) {
|
|
12012
|
+
return [];
|
|
12013
|
+
}
|
|
12014
|
+
const entries = await readdir3(examplesDir, { withFileTypes: true });
|
|
12015
|
+
const workflows = [];
|
|
12016
|
+
for (const entry of entries) {
|
|
12017
|
+
if (!entry.isDirectory())
|
|
12018
|
+
continue;
|
|
12019
|
+
const workflowPath = resolve8(examplesDir, entry.name, "workflow.yaml");
|
|
12020
|
+
if (!existsSync2(workflowPath))
|
|
12021
|
+
continue;
|
|
12022
|
+
try {
|
|
12023
|
+
const workflow = await loadWorkflowDefinition(workflowPath);
|
|
12024
|
+
workflows.push({
|
|
12025
|
+
id: workflow.id,
|
|
12026
|
+
name: workflow.name,
|
|
12027
|
+
path: entry.name
|
|
12028
|
+
});
|
|
12029
|
+
} catch {
|
|
12030
|
+
workflows.push({
|
|
12031
|
+
id: entry.name,
|
|
12032
|
+
name: "(invalid workflow.yaml)",
|
|
12033
|
+
path: entry.name
|
|
12034
|
+
});
|
|
12035
|
+
}
|
|
12036
|
+
}
|
|
12037
|
+
return workflows.sort((a, b) => a.id.localeCompare(b.id));
|
|
12038
|
+
}
|
|
12039
|
+
|
|
12040
|
+
class ListCommand extends BaseCommand {
|
|
12041
|
+
static paths = [["list"]];
|
|
12042
|
+
static usage = Command.Usage({
|
|
12043
|
+
category: "Setup",
|
|
12044
|
+
description: "List installed and available workflows.",
|
|
12045
|
+
details: "Shows workflows installed in `.rmr/workflows/` and bundled workflows available for installation.",
|
|
12046
|
+
examples: [["List all workflows", "$0 list"]]
|
|
12047
|
+
});
|
|
12048
|
+
async execute() {
|
|
12049
|
+
const config = await loadConfig();
|
|
12050
|
+
const examplesDir = getExamplesWorkflowsDir2();
|
|
12051
|
+
const installed = await getInstalledWorkflows(config.workflowsDir);
|
|
12052
|
+
const bundled = await getBundledWorkflows(examplesDir);
|
|
12053
|
+
const installedIds = new Set(installed.map((w) => w.id));
|
|
12054
|
+
if (installed.length > 0) {
|
|
12055
|
+
ui.info("Installed workflows:");
|
|
12056
|
+
for (const workflow of installed) {
|
|
12057
|
+
ui.info(` ${workflow.id.padEnd(16)} ${workflow.name.padEnd(24)} ${workflow.path}`);
|
|
12058
|
+
}
|
|
12059
|
+
ui.info("");
|
|
12060
|
+
}
|
|
12061
|
+
const available = bundled.filter((w) => !installedIds.has(w.id));
|
|
12062
|
+
if (available.length > 0) {
|
|
12063
|
+
ui.info("Available to install:");
|
|
12064
|
+
for (const workflow of available) {
|
|
12065
|
+
ui.info(` ${workflow.id.padEnd(16)} ${binaryName} install ${workflow.path}`);
|
|
12066
|
+
}
|
|
12067
|
+
ui.info("");
|
|
12068
|
+
}
|
|
12069
|
+
if (installed.length === 0 && bundled.length > 0) {
|
|
12070
|
+
ui.info("No workflows installed yet. Install one with:");
|
|
12071
|
+
ui.info(` ${binaryName} install ${bundled[0]?.path}`);
|
|
12072
|
+
ui.info("");
|
|
12073
|
+
}
|
|
12074
|
+
if (installed.length === 0 && bundled.length === 0) {
|
|
12075
|
+
ui.info("No workflows found.");
|
|
12076
|
+
}
|
|
11515
12077
|
return 0;
|
|
11516
12078
|
}
|
|
11517
12079
|
}
|
|
11518
12080
|
|
|
11519
12081
|
// src/commands/root.ts
|
|
11520
|
-
import { basename } from "node:path";
|
|
12082
|
+
import { basename as basename2 } from "node:path";
|
|
11521
12083
|
function detectShell() {
|
|
11522
12084
|
const raw = process.env.SHELL;
|
|
11523
12085
|
if (!raw) {
|
|
11524
12086
|
return null;
|
|
11525
12087
|
}
|
|
11526
|
-
const shell =
|
|
12088
|
+
const shell = basename2(raw);
|
|
11527
12089
|
if (shell === "bash" || shell === "zsh" || shell === "fish") {
|
|
11528
12090
|
return shell;
|
|
11529
12091
|
}
|
|
11530
12092
|
return null;
|
|
11531
12093
|
}
|
|
11532
12094
|
|
|
11533
|
-
class RootCommand extends
|
|
12095
|
+
class RootCommand extends BaseCommand {
|
|
11534
12096
|
static paths = [Command.Default];
|
|
11535
12097
|
async execute() {
|
|
11536
12098
|
const shell = detectShell();
|
|
11537
|
-
process.stdout.write(
|
|
12099
|
+
process.stdout.write(`${binaryName} ${getVersion()} - multi-step coding workflows for AI agents
|
|
11538
12100
|
|
|
11539
12101
|
`);
|
|
11540
12102
|
process.stdout.write(`Setup
|
|
11541
12103
|
`);
|
|
11542
|
-
process.stdout.write(`
|
|
12104
|
+
process.stdout.write(` ${binaryName} install <name> Install bundled workflow into .rmr/workflows/
|
|
11543
12105
|
|
|
11544
12106
|
`);
|
|
11545
12107
|
process.stdout.write(`Workflow
|
|
11546
12108
|
`);
|
|
11547
|
-
process.stdout.write(`
|
|
12109
|
+
process.stdout.write(` ${binaryName} run <workflow-path> Start a new workflow run (requires --task/-t or --task-file/-f)
|
|
11548
12110
|
`);
|
|
11549
|
-
process.stdout.write(`
|
|
12111
|
+
process.stdout.write(` ${binaryName} continue <run-id> Resume a paused or interrupted run
|
|
11550
12112
|
|
|
11551
12113
|
`);
|
|
11552
12114
|
process.stdout.write(`Shell Completion (optional)
|
|
11553
12115
|
`);
|
|
11554
12116
|
if (shell === "fish") {
|
|
11555
|
-
process.stdout.write(`
|
|
12117
|
+
process.stdout.write(` ${binaryName} completion fish > ~/.config/fish/completions/${binaryName}.fish
|
|
11556
12118
|
|
|
11557
12119
|
`);
|
|
11558
12120
|
} else if (shell) {
|
|
11559
12121
|
const rcFile = shell === "zsh" ? "~/.zshrc" : "~/.bashrc";
|
|
11560
|
-
process.stdout.write(` echo 'eval "$(
|
|
12122
|
+
process.stdout.write(` echo 'eval "$(${binaryName} completion ${shell})"' >> ${rcFile}
|
|
11561
12123
|
`);
|
|
11562
12124
|
process.stdout.write(` source ${rcFile}
|
|
11563
12125
|
|
|
11564
12126
|
`);
|
|
11565
12127
|
} else {
|
|
11566
|
-
process.stdout.write(` echo 'eval "$(
|
|
12128
|
+
process.stdout.write(` echo 'eval "$(${binaryName} completion zsh)"' >> ~/.zshrc && source ~/.zshrc
|
|
11567
12129
|
`);
|
|
11568
|
-
process.stdout.write(` echo 'eval "$(
|
|
12130
|
+
process.stdout.write(` echo 'eval "$(${binaryName} completion bash)"' >> ~/.bashrc && source ~/.bashrc
|
|
11569
12131
|
`);
|
|
11570
|
-
process.stdout.write(`
|
|
12132
|
+
process.stdout.write(` ${binaryName} completion fish > ~/.config/fish/completions/${binaryName}.fish
|
|
11571
12133
|
|
|
11572
12134
|
`);
|
|
11573
12135
|
}
|
|
11574
12136
|
process.stdout.write(`More
|
|
11575
12137
|
`);
|
|
11576
|
-
process.stdout.write(`
|
|
12138
|
+
process.stdout.write(` ${binaryName} --help Show full help with all options
|
|
11577
12139
|
`);
|
|
11578
|
-
process.stdout.write(`
|
|
12140
|
+
process.stdout.write(` ${binaryName} <command> --help Show help for a specific command
|
|
11579
12141
|
`);
|
|
11580
12142
|
return 0;
|
|
11581
12143
|
}
|
|
@@ -11617,8 +12179,8 @@ var logger = {
|
|
|
11617
12179
|
};
|
|
11618
12180
|
|
|
11619
12181
|
// src/commands/run.ts
|
|
11620
|
-
import { readFile as readFile4 } from "node:fs/promises";
|
|
11621
|
-
import { resolve as
|
|
12182
|
+
import { readFile as readFile4, stat } from "node:fs/promises";
|
|
12183
|
+
import { resolve as resolve9 } from "node:path";
|
|
11622
12184
|
function parseVar(input) {
|
|
11623
12185
|
const index = input.indexOf("=");
|
|
11624
12186
|
if (index < 1 || index === input.length - 1) {
|
|
@@ -11629,8 +12191,57 @@ function parseVar(input) {
|
|
|
11629
12191
|
value: input.slice(index + 1).trim()
|
|
11630
12192
|
};
|
|
11631
12193
|
}
|
|
12194
|
+
function getErrorMessage(error) {
|
|
12195
|
+
if (error instanceof Error) {
|
|
12196
|
+
return error.message;
|
|
12197
|
+
}
|
|
12198
|
+
if (typeof error === "string") {
|
|
12199
|
+
return error;
|
|
12200
|
+
}
|
|
12201
|
+
try {
|
|
12202
|
+
return JSON.stringify(error);
|
|
12203
|
+
} catch {
|
|
12204
|
+
return "Unknown error";
|
|
12205
|
+
}
|
|
12206
|
+
}
|
|
12207
|
+
function isErrnoLike(error) {
|
|
12208
|
+
return typeof error === "object" && error !== null;
|
|
12209
|
+
}
|
|
12210
|
+
async function resolveWorkflowPath(inputPath) {
|
|
12211
|
+
const absolutePath = resolve9(inputPath);
|
|
12212
|
+
try {
|
|
12213
|
+
const pathStat = await stat(absolutePath);
|
|
12214
|
+
if (!pathStat.isDirectory()) {
|
|
12215
|
+
return absolutePath;
|
|
12216
|
+
}
|
|
12217
|
+
const yamlPath = resolve9(absolutePath, "workflow.yaml");
|
|
12218
|
+
try {
|
|
12219
|
+
const yamlStat = await stat(yamlPath);
|
|
12220
|
+
if (yamlStat.isFile()) {
|
|
12221
|
+
return yamlPath;
|
|
12222
|
+
}
|
|
12223
|
+
} catch {}
|
|
12224
|
+
const ymlPath = resolve9(absolutePath, "workflow.yml");
|
|
12225
|
+
try {
|
|
12226
|
+
const ymlStat = await stat(ymlPath);
|
|
12227
|
+
if (ymlStat.isFile()) {
|
|
12228
|
+
return ymlPath;
|
|
12229
|
+
}
|
|
12230
|
+
} catch {}
|
|
12231
|
+
throw new UserInputError(`Workflow directory does not contain workflow.yaml or workflow.yml: ${absolutePath}`);
|
|
12232
|
+
} catch (error) {
|
|
12233
|
+
if (isErrnoLike(error) && error.code === "ENOENT") {
|
|
12234
|
+
const hint = absolutePath.includes(`${resolve9(".rmr")}/workflow/`) ? " Did you mean .rmr/workflows/?" : "";
|
|
12235
|
+
throw new UserInputError(`Workflow does not exist: ${absolutePath}${hint}`);
|
|
12236
|
+
}
|
|
12237
|
+
if (error instanceof UserInputError) {
|
|
12238
|
+
throw error;
|
|
12239
|
+
}
|
|
12240
|
+
throw new UserInputError(`Failed to access workflow path "${absolutePath}": ${getErrorMessage(error)}`);
|
|
12241
|
+
}
|
|
12242
|
+
}
|
|
11632
12243
|
|
|
11633
|
-
class RunCommand extends
|
|
12244
|
+
class RunCommand extends BaseCommand {
|
|
11634
12245
|
static paths = [["run"]];
|
|
11635
12246
|
static usage = Command.Usage({
|
|
11636
12247
|
category: "Workflow",
|
|
@@ -11642,14 +12253,6 @@ class RunCommand extends Command {
|
|
|
11642
12253
|
'$0 run .rmr/workflows/feature-dev/workflow.yaml --task "Implement auth middleware"'
|
|
11643
12254
|
],
|
|
11644
12255
|
["Run with task file", "$0 run .rmr/workflows/feature-dev/workflow.yaml --task-file task.md"],
|
|
11645
|
-
[
|
|
11646
|
-
"Override harness",
|
|
11647
|
-
'$0 run .rmr/workflows/feature-dev/workflow.yaml --task "Fix bug" --harness opencode'
|
|
11648
|
-
],
|
|
11649
|
-
[
|
|
11650
|
-
"Override model",
|
|
11651
|
-
'$0 run .rmr/workflows/feature-dev/workflow.yaml --task "Fix bug" --model openai/gpt-5.3-codex-high'
|
|
11652
|
-
],
|
|
11653
12256
|
[
|
|
11654
12257
|
"Run with extra variables",
|
|
11655
12258
|
'$0 run .rmr/workflows/feature-dev/workflow.yaml --task "Ship feature" --var issue_id=123 --var env=staging'
|
|
@@ -11671,14 +12274,6 @@ class RunCommand extends Command {
|
|
|
11671
12274
|
required: false,
|
|
11672
12275
|
description: "Path to file containing task description."
|
|
11673
12276
|
});
|
|
11674
|
-
harness = exports_options.String("--harness", {
|
|
11675
|
-
required: false,
|
|
11676
|
-
description: "Override harness for all workflow steps."
|
|
11677
|
-
});
|
|
11678
|
-
model = exports_options.String("--model", {
|
|
11679
|
-
required: false,
|
|
11680
|
-
description: "Override model for all workflow steps (e.g., openai/gpt-5.3-codex-high)."
|
|
11681
|
-
});
|
|
11682
12277
|
vars = exports_options.Array("--var", [], {
|
|
11683
12278
|
description: "Inject initial variables as key=value (repeatable)."
|
|
11684
12279
|
});
|
|
@@ -11694,7 +12289,7 @@ class RunCommand extends Command {
|
|
|
11694
12289
|
}
|
|
11695
12290
|
if (this.taskFile) {
|
|
11696
12291
|
try {
|
|
11697
|
-
const content = await readFile4(
|
|
12292
|
+
const content = await readFile4(resolve9(this.taskFile), "utf-8");
|
|
11698
12293
|
const task = content.trim();
|
|
11699
12294
|
return { task, displayTask: `(file: ${this.taskFile})` };
|
|
11700
12295
|
} catch (error) {
|
|
@@ -11705,18 +12300,34 @@ class RunCommand extends Command {
|
|
|
11705
12300
|
if (this.taskFlag) {
|
|
11706
12301
|
return { task: this.taskFlag, displayTask: this.taskFlag };
|
|
11707
12302
|
}
|
|
12303
|
+
if (process.stdin.isTTY) {
|
|
12304
|
+
ui.warning("No task provided. Enter your task below. Press Ctrl+D to submit.");
|
|
12305
|
+
const task = await ui.multilinePrompt("Task: ");
|
|
12306
|
+
const trimmedTask = task.trim();
|
|
12307
|
+
if (!trimmedTask) {
|
|
12308
|
+
throw new UserInputError("Task cannot be empty.");
|
|
12309
|
+
}
|
|
12310
|
+
return { task: trimmedTask, displayTask: trimmedTask };
|
|
12311
|
+
}
|
|
11708
12312
|
throw new UserInputError("No task provided. Use --task/-t or --task-file/-f.");
|
|
11709
12313
|
}
|
|
11710
12314
|
async execute() {
|
|
11711
12315
|
const showUpdateNotice = startUpdateCheck();
|
|
11712
12316
|
const config = await loadConfig();
|
|
11713
|
-
const { task, displayTask } = await this.resolveTask();
|
|
11714
|
-
const harnessOverride = parseHarnessOverride(this.harness);
|
|
11715
12317
|
const parsedVars = this.vars.map(parseVar);
|
|
11716
12318
|
const effectiveAllowAll = this.noAllowAll ? false : this.allowAll;
|
|
11717
12319
|
const varsObject = Object.fromEntries(parsedVars.map((entry) => [entry.key, entry.value]));
|
|
11718
|
-
const workflowPath =
|
|
11719
|
-
|
|
12320
|
+
const workflowPath = await resolveWorkflowPath(this.workflowPath);
|
|
12321
|
+
let workflow;
|
|
12322
|
+
try {
|
|
12323
|
+
workflow = await loadWorkflowDefinition(workflowPath);
|
|
12324
|
+
} catch (error) {
|
|
12325
|
+
if (isErrnoLike(error) && error.code === "ENOENT") {
|
|
12326
|
+
throw new UserInputError(`Workflow does not exist: ${workflowPath}`);
|
|
12327
|
+
}
|
|
12328
|
+
throw new UserInputError(`Failed to load workflow "${workflowPath}": ${getErrorMessage(error)}`);
|
|
12329
|
+
}
|
|
12330
|
+
const { task, displayTask } = await this.resolveTask();
|
|
11720
12331
|
const runId = generateRunId();
|
|
11721
12332
|
const runState = createInitialRunState({
|
|
11722
12333
|
runId,
|
|
@@ -11727,28 +12338,17 @@ class RunCommand extends Command {
|
|
|
11727
12338
|
});
|
|
11728
12339
|
const runPath = await saveRunState(config, runState);
|
|
11729
12340
|
ui.workflowHeader({
|
|
11730
|
-
title:
|
|
12341
|
+
title: `${binaryName} config`,
|
|
11731
12342
|
workflow: workflowPath,
|
|
11732
12343
|
workflowId: workflow.id,
|
|
11733
12344
|
task: displayTask,
|
|
11734
12345
|
runId: runState.run_id,
|
|
11735
|
-
currentStep: runState.current_step,
|
|
11736
12346
|
runFile: runPath,
|
|
11737
12347
|
allowAll: effectiveAllowAll,
|
|
11738
|
-
harness: this.harness,
|
|
11739
|
-
model: this.model,
|
|
11740
12348
|
varsCount: parsedVars.length
|
|
11741
12349
|
});
|
|
11742
|
-
const overrides = {};
|
|
11743
|
-
if (harnessOverride) {
|
|
11744
|
-
overrides.harness = harnessOverride;
|
|
11745
|
-
}
|
|
11746
|
-
if (this.model) {
|
|
11747
|
-
overrides.model = this.model;
|
|
11748
|
-
}
|
|
11749
12350
|
await runWorkflow(config, workflow, runState, {
|
|
11750
|
-
allowAll: effectiveAllowAll
|
|
11751
|
-
...Object.keys(overrides).length > 0 && { overrides }
|
|
12351
|
+
allowAll: effectiveAllowAll
|
|
11752
12352
|
});
|
|
11753
12353
|
showUpdateNotice();
|
|
11754
12354
|
return 0;
|
|
@@ -11758,7 +12358,7 @@ class RunCommand extends Command {
|
|
|
11758
12358
|
// src/index.ts
|
|
11759
12359
|
var [, , ...args] = process.argv;
|
|
11760
12360
|
var cli = new Cli({
|
|
11761
|
-
binaryName
|
|
12361
|
+
binaryName,
|
|
11762
12362
|
binaryVersion: getVersion(),
|
|
11763
12363
|
enableColors: false
|
|
11764
12364
|
});
|
|
@@ -11766,13 +12366,14 @@ cli.register(exports_builtins.HelpCommand);
|
|
|
11766
12366
|
cli.register(exports_builtins.VersionCommand);
|
|
11767
12367
|
cli.register(RootCommand);
|
|
11768
12368
|
cli.register(InstallCommand);
|
|
12369
|
+
cli.register(ListCommand);
|
|
11769
12370
|
cli.register(RunCommand);
|
|
11770
12371
|
cli.register(ContinueCommand);
|
|
11771
12372
|
cli.register(CompleteCommand);
|
|
11772
12373
|
cli.register(CompletionCommand);
|
|
11773
12374
|
try {
|
|
11774
12375
|
const exitCode = await cli.run(args);
|
|
11775
|
-
process.exitCode = exitCode;
|
|
12376
|
+
process.exitCode = Math.max(process.exitCode ?? 0, exitCode);
|
|
11776
12377
|
} catch (error) {
|
|
11777
12378
|
if (error instanceof RmrError) {
|
|
11778
12379
|
logger.error(`${error.code}: ${error.message}`);
|