ralph-codex 0.1.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/CHANGELOG.md +6 -0
- package/LICENSE +21 -0
- package/README.md +216 -0
- package/bin/ralph-codex.js +56 -0
- package/package.json +49 -0
- package/src/commands/docker.js +174 -0
- package/src/commands/init.js +413 -0
- package/src/commands/plan.js +1129 -0
- package/src/commands/refine.js +1 -0
- package/src/commands/reset.js +105 -0
- package/src/commands/revise.js +571 -0
- package/src/commands/run.js +1225 -0
- package/src/commands/view.js +695 -0
- package/src/ui/terminal.js +137 -0
- package/templates/ralph.config.yml +53 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import cliProgress from "cli-progress";
|
|
4
|
+
|
|
5
|
+
const isTty = Boolean(process.stdout.isTTY);
|
|
6
|
+
const colorEnabled = isTty && !process.env.NO_COLOR;
|
|
7
|
+
|
|
8
|
+
const wrap = (fn) => (text) => (colorEnabled ? fn(text) : text);
|
|
9
|
+
const grayFn = pc.gray || pc.dim;
|
|
10
|
+
|
|
11
|
+
const colors = {
|
|
12
|
+
red: wrap(pc.red),
|
|
13
|
+
green: wrap(pc.green),
|
|
14
|
+
yellow: wrap(pc.yellow),
|
|
15
|
+
blue: wrap(pc.blue),
|
|
16
|
+
magenta: wrap(pc.magenta),
|
|
17
|
+
cyan: wrap(pc.cyan),
|
|
18
|
+
gray: wrap(grayFn),
|
|
19
|
+
dim: wrap(pc.dim),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function createSpinner(text) {
|
|
23
|
+
if (!isTty || process.env.NO_COLOR) {
|
|
24
|
+
if (text) process.stdout.write(`${text}\n`);
|
|
25
|
+
return {
|
|
26
|
+
start() {},
|
|
27
|
+
stop() {},
|
|
28
|
+
succeed() {},
|
|
29
|
+
fail() {},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const spinner = ora({
|
|
34
|
+
text,
|
|
35
|
+
spinner: { interval: 120, frames: ["-", "\\", "|", "/"] },
|
|
36
|
+
});
|
|
37
|
+
spinner.start();
|
|
38
|
+
return spinner;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function createProgressBar() {
|
|
42
|
+
if (!isTty) return null;
|
|
43
|
+
return new cliProgress.SingleBar(
|
|
44
|
+
{
|
|
45
|
+
format: `${colors.cyan("{bar}")} {percentage}% | {value}/{total} tasks | ~{blocked} | Iter {iteration}/{iterations}`,
|
|
46
|
+
barCompleteChar: "#",
|
|
47
|
+
barIncompleteChar: "-",
|
|
48
|
+
hideCursor: true,
|
|
49
|
+
clearOnComplete: false,
|
|
50
|
+
stopOnComplete: false,
|
|
51
|
+
forceRedraw: true,
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function createLogStyler() {
|
|
57
|
+
const pathRegex =
|
|
58
|
+
/(^|\s)(\.{0,2}\/[A-Za-z0-9._/-]+|[A-Za-z0-9._-]+\/[A-Za-z0-9._/-]+|[A-Za-z0-9._-]+\.(?:js|ts|tsx|jsx|md|yml|yaml|json|toml|go|py|rs|java|kt|sh|bash|zsh|sql|css|scss|html|txt))(?!\w)/g;
|
|
59
|
+
|
|
60
|
+
let inCodeBlock = false;
|
|
61
|
+
let inHeader = false;
|
|
62
|
+
let inDiffHunk = false;
|
|
63
|
+
|
|
64
|
+
const highlightInline = (line) =>
|
|
65
|
+
line.replace(/`([^`]+)`/g, (match) => colors.blue(match));
|
|
66
|
+
const highlightPaths = (line) =>
|
|
67
|
+
line.replace(pathRegex, (match, prefix, pathPart) => {
|
|
68
|
+
return `${prefix}${colors.magenta(pathPart)}`;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const formatLine = (line) => {
|
|
72
|
+
if (!colorEnabled || line === "") return line;
|
|
73
|
+
const trimmed = line.trim();
|
|
74
|
+
if (trimmed === "--------") {
|
|
75
|
+
inHeader = !inHeader;
|
|
76
|
+
return colors.gray(line);
|
|
77
|
+
}
|
|
78
|
+
if (inHeader) return colors.gray(line);
|
|
79
|
+
if (trimmed.startsWith("```")) {
|
|
80
|
+
inCodeBlock = !inCodeBlock;
|
|
81
|
+
return colors.gray(line);
|
|
82
|
+
}
|
|
83
|
+
if (inCodeBlock) return colors.gray(line);
|
|
84
|
+
|
|
85
|
+
if (/^diff --|^index |^\+\+\+|^---/.test(trimmed)) {
|
|
86
|
+
inDiffHunk = false;
|
|
87
|
+
return colors.magenta(line);
|
|
88
|
+
}
|
|
89
|
+
if (/^@@/.test(trimmed)) {
|
|
90
|
+
inDiffHunk = true;
|
|
91
|
+
return colors.magenta(line);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const looksLikeList = /^[-+]\s+/.test(trimmed);
|
|
95
|
+
if (inDiffHunk && /^\+\s?/.test(trimmed) && !/^\+\+\+/.test(trimmed) && !looksLikeList) {
|
|
96
|
+
return colors.green(line);
|
|
97
|
+
}
|
|
98
|
+
if (inDiffHunk && /^-\s?/.test(trimmed) && !/^---/.test(trimmed) && !looksLikeList) {
|
|
99
|
+
return colors.red(line);
|
|
100
|
+
}
|
|
101
|
+
if (/^-\s+\[[xX]\]/.test(trimmed)) return colors.green(line);
|
|
102
|
+
if (/^-\s+\[~\]/.test(trimmed)) return colors.yellow(line);
|
|
103
|
+
if (/^-\s+\[\s\]/.test(trimmed)) return colors.gray(line);
|
|
104
|
+
|
|
105
|
+
if (/\b(error|failed|exception|traceback|fatal)\b/i.test(trimmed)) {
|
|
106
|
+
return colors.red(line);
|
|
107
|
+
}
|
|
108
|
+
if (/\b(warn|warning|deprecated)\b/i.test(trimmed)) {
|
|
109
|
+
return colors.yellow(line);
|
|
110
|
+
}
|
|
111
|
+
if (/\b(success|succeeded|done|complete|completed)\b/i.test(trimmed)) {
|
|
112
|
+
return colors.green(line);
|
|
113
|
+
}
|
|
114
|
+
if (/^#{1,6}\s+/.test(trimmed)) return colors.cyan(line);
|
|
115
|
+
if (trimmed.endsWith("?")) return colors.yellow(line);
|
|
116
|
+
if (/^\$\s+/.test(trimmed) || /^>\s+/.test(trimmed)) {
|
|
117
|
+
return colors.blue(line);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let styled = highlightInline(line);
|
|
121
|
+
if (!styled.includes("`")) {
|
|
122
|
+
styled = highlightPaths(styled);
|
|
123
|
+
}
|
|
124
|
+
if (trimmed.length >= 140) return colors.dim(styled);
|
|
125
|
+
return styled;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
return { formatLine };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export {
|
|
132
|
+
colors,
|
|
133
|
+
colorEnabled,
|
|
134
|
+
createSpinner,
|
|
135
|
+
createProgressBar,
|
|
136
|
+
createLogStyler,
|
|
137
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
|
|
3
|
+
codex:
|
|
4
|
+
model: null # Example: gpt-5-codex
|
|
5
|
+
profile: null # Codex CLI profile name
|
|
6
|
+
sandbox: null # read-only | workspace-write | danger-full-access
|
|
7
|
+
ask_for_approval: null # untrusted | on-failure | on-request | never
|
|
8
|
+
full_auto: false # true enables workspace-write + on-request
|
|
9
|
+
model_reasoning_effort: null # low | medium | high | xhigh
|
|
10
|
+
|
|
11
|
+
docker:
|
|
12
|
+
enabled: false
|
|
13
|
+
use_for_plan: false
|
|
14
|
+
dockerfile: Dockerfile.ralph
|
|
15
|
+
image: ralph-runner
|
|
16
|
+
base_image: node:20-bullseye
|
|
17
|
+
workdir: /workspace
|
|
18
|
+
codex_install: npm install -g @openai/codex
|
|
19
|
+
codex_home: .ralph/codex # Writable codex home inside the repo
|
|
20
|
+
mount_codex_config: true # Seed codex_home from host ~/.codex if empty
|
|
21
|
+
tty: auto # auto | true | false
|
|
22
|
+
pass_env:
|
|
23
|
+
- OPENAI_API_KEY
|
|
24
|
+
apt_packages:
|
|
25
|
+
- git
|
|
26
|
+
- python3
|
|
27
|
+
npm_globals: []
|
|
28
|
+
pip_packages: []
|
|
29
|
+
auto_fix: true
|
|
30
|
+
fix_attempts: 2
|
|
31
|
+
fix_use_host: true
|
|
32
|
+
fix_log: .ralph/docker-build.log
|
|
33
|
+
cleanup: image # none | image | all
|
|
34
|
+
|
|
35
|
+
plan:
|
|
36
|
+
auto_detect_success_criteria: false
|
|
37
|
+
tasks_path: tasks.md
|
|
38
|
+
success_choices:
|
|
39
|
+
- Run the project's primary test suite
|
|
40
|
+
- Run relevant linters or static checks
|
|
41
|
+
- Run the project's build or CI checks
|
|
42
|
+
default_success_criteria:
|
|
43
|
+
- Run the project's primary test suite
|
|
44
|
+
|
|
45
|
+
run:
|
|
46
|
+
tasks_path: tasks.md
|
|
47
|
+
max_iterations: 15
|
|
48
|
+
max_iteration_seconds: null # soft limit per iteration
|
|
49
|
+
max_total_seconds: null # hard limit for the full run
|
|
50
|
+
completion_promise: LOOP_COMPLETE
|
|
51
|
+
tail_log: true
|
|
52
|
+
tail_scratchpad: false
|
|
53
|
+
required_commands: []
|