rlph-cli 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.
Files changed (42) hide show
  1. package/README.md +102 -0
  2. package/dist/agents/base.d.ts +16 -0
  3. package/dist/agents/base.d.ts.map +1 -0
  4. package/dist/agents/base.js +5 -0
  5. package/dist/agents/base.js.map +1 -0
  6. package/dist/agents/claude.d.ts +3 -0
  7. package/dist/agents/claude.d.ts.map +1 -0
  8. package/dist/agents/claude.js +80 -0
  9. package/dist/agents/claude.js.map +1 -0
  10. package/dist/agents/index.d.ts +4 -0
  11. package/dist/agents/index.d.ts.map +1 -0
  12. package/dist/agents/index.js +9 -0
  13. package/dist/agents/index.js.map +1 -0
  14. package/dist/commands/run.d.ts +7 -0
  15. package/dist/commands/run.d.ts.map +1 -0
  16. package/dist/commands/run.js +73 -0
  17. package/dist/commands/run.js.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +16 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/session/index.d.ts +3 -0
  23. package/dist/session/index.d.ts.map +1 -0
  24. package/dist/session/index.js +3 -0
  25. package/dist/session/index.js.map +1 -0
  26. package/dist/session/logger.d.ts +10 -0
  27. package/dist/session/logger.d.ts.map +1 -0
  28. package/dist/session/logger.js +17 -0
  29. package/dist/session/logger.js.map +1 -0
  30. package/dist/session/manager.d.ts +18 -0
  31. package/dist/session/manager.d.ts.map +1 -0
  32. package/dist/session/manager.js +29 -0
  33. package/dist/session/manager.js.map +1 -0
  34. package/dist/utils/files.d.ts +4 -0
  35. package/dist/utils/files.d.ts.map +1 -0
  36. package/dist/utils/files.js +39 -0
  37. package/dist/utils/files.js.map +1 -0
  38. package/dist/utils/index.d.ts +2 -0
  39. package/dist/utils/index.d.ts.map +1 -0
  40. package/dist/utils/index.js +2 -0
  41. package/dist/utils/index.js.map +1 -0
  42. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # Ralph
2
+
3
+ Loop coding agent CLI - run AI coding agents headlessly in a loop.
4
+
5
+ Inspired by [Geoff Huntley's ralph technique](https://ghuntley.com/ralph/) - putting a coding agent in a while loop and letting it work autonomously.
6
+
7
+ ```bash
8
+ while :; do cat prompt.md | claude -p; done
9
+ ```
10
+
11
+ Ralph wraps this pattern into a proper CLI with session logging, iteration limits, and automatic task completion detection.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ # npm
17
+ npm install -g rlph-cli
18
+
19
+ # or run directly
20
+ npx rlph-cli run -p "your task"
21
+ ```
22
+
23
+ ### From source
24
+
25
+ ```bash
26
+ git clone https://github.com/rem4ik4ever/ralph.git
27
+ cd ralph
28
+ bun install
29
+ bun run build
30
+ bun link
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ ```bash
36
+ ralph run -p <prompt> [-a agent] [-i iterations]
37
+ ```
38
+
39
+ ### Options
40
+
41
+ | Flag | Description | Default |
42
+ |------|-------------|---------|
43
+ | `-p, --prompt <files...>` | Prompt text or files to pass to agent | required |
44
+ | `-a, --agent <agent>` | Agent type (currently: claude) | `claude` |
45
+ | `-i, --iterations <n>` | Max loop iterations | `4` |
46
+
47
+ ### Examples
48
+
49
+ **Simple task**
50
+ ```bash
51
+ ralph run -p "fix the login bug" -i 3
52
+ ```
53
+
54
+ **Using a prompt file**
55
+ ```bash
56
+ ralph run -p prompt.md -i 10
57
+ ```
58
+
59
+ **Multiple prompts/files**
60
+ ```bash
61
+ ralph run -p task.md context.md "also add tests"
62
+ ```
63
+
64
+ **Long running task**
65
+ ```bash
66
+ ralph run -p "port this codebase from React to Vue" -i 50
67
+ ```
68
+
69
+ ## How it works
70
+
71
+ 1. Ralph reads your prompt (text or files)
72
+ 2. Appends completion instructions asking agent to output `<ralph>RALPH_COMPLETED</ralph>` when done
73
+ 3. Runs the agent in a loop up to N iterations
74
+ 4. Streams output in real-time
75
+ 5. Stops early if agent signals completion
76
+ 6. Logs each iteration to `~/.ralph/sessions/<session-id>/`
77
+
78
+ ## Session logs
79
+
80
+ All sessions are logged to `~/.ralph/sessions/`:
81
+
82
+ ```
83
+ ~/.ralph/sessions/
84
+ └── <session-id>/
85
+ ├── meta.json # session metadata
86
+ ├── 0.log # iteration 0 output
87
+ ├── 1.log # iteration 1 output
88
+ └── ...
89
+ ```
90
+
91
+ ## Supported agents
92
+
93
+ - `claude` - Claude Code CLI (requires [claude](https://claude.ai/claude-code) installed)
94
+
95
+ ## Requirements
96
+
97
+ - Node.js >= 18
98
+ - Claude Code CLI installed and authenticated
99
+
100
+ ## License
101
+
102
+ MIT
@@ -0,0 +1,16 @@
1
+ export interface AgentResult {
2
+ output: string;
3
+ exitCode: number;
4
+ duration: number;
5
+ }
6
+ export interface ExecuteOptions {
7
+ onOutput?: (chunk: string) => void;
8
+ }
9
+ export interface Agent {
10
+ name: string;
11
+ execute(prompt: string, cwd: string, options?: ExecuteOptions): Promise<AgentResult>;
12
+ }
13
+ export type AgentType = 'claude';
14
+ export declare const SUPPORTED_AGENTS: AgentType[];
15
+ export declare function isValidAgent(agent: string): agent is AgentType;
16
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/agents/base.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACnC;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;CACrF;AAED,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAA;AAEhC,eAAO,MAAM,gBAAgB,EAAE,SAAS,EAAe,CAAA;AAEvD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,SAAS,CAE9D"}
@@ -0,0 +1,5 @@
1
+ export const SUPPORTED_AGENTS = ['claude'];
2
+ export function isValidAgent(agent) {
3
+ return SUPPORTED_AGENTS.includes(agent);
4
+ }
5
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/agents/base.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,gBAAgB,GAAgB,CAAC,QAAQ,CAAC,CAAA;AAEvD,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,KAAkB,CAAC,CAAA;AACtD,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Agent } from './base.js';
2
+ export declare const claude: Agent;
3
+ //# sourceMappingURL=claude.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/agents/claude.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAA+B,MAAM,WAAW,CAAA;AAmBnE,eAAO,MAAM,MAAM,EAAE,KAqEpB,CAAA"}
@@ -0,0 +1,80 @@
1
+ import { spawn } from 'node:child_process';
2
+ function parseStreamJson(line) {
3
+ try {
4
+ const data = JSON.parse(line);
5
+ // Only parse assistant messages, skip result (already streamed)
6
+ if (data.type === 'assistant' && data.message?.content) {
7
+ for (const block of data.message.content) {
8
+ if (block.type === 'text') {
9
+ return block.text;
10
+ }
11
+ }
12
+ }
13
+ }
14
+ catch {
15
+ // Not valid JSON, ignore
16
+ }
17
+ return null;
18
+ }
19
+ export const claude = {
20
+ name: 'claude',
21
+ async execute(prompt, cwd, options) {
22
+ const startTime = Date.now();
23
+ const onOutput = options?.onOutput;
24
+ return new Promise((resolve, reject) => {
25
+ const proc = spawn('claude', [
26
+ '-p',
27
+ '--dangerously-skip-permissions',
28
+ '--output-format', 'stream-json',
29
+ '--verbose',
30
+ ], {
31
+ cwd,
32
+ stdio: ['pipe', 'pipe', 'pipe'],
33
+ shell: true,
34
+ });
35
+ let output = '';
36
+ let stderr = '';
37
+ let buffer = '';
38
+ proc.stdout.on('data', (data) => {
39
+ buffer += data.toString();
40
+ const lines = buffer.split('\n');
41
+ buffer = lines.pop() || ''; // Keep incomplete line in buffer
42
+ for (const line of lines) {
43
+ if (!line.trim())
44
+ continue;
45
+ const text = parseStreamJson(line);
46
+ if (text) {
47
+ output += text;
48
+ onOutput?.(text);
49
+ }
50
+ }
51
+ });
52
+ proc.stderr.on('data', (data) => {
53
+ const chunk = data.toString();
54
+ stderr += chunk;
55
+ });
56
+ proc.on('error', (err) => {
57
+ reject(new Error(`Failed to spawn claude: ${err.message}`));
58
+ });
59
+ proc.on('close', (code) => {
60
+ // Process any remaining buffer
61
+ if (buffer.trim()) {
62
+ const text = parseStreamJson(buffer);
63
+ if (text) {
64
+ output += text;
65
+ onOutput?.(text);
66
+ }
67
+ }
68
+ const duration = Date.now() - startTime;
69
+ resolve({
70
+ output: output + (stderr ? `\n[stderr]\n${stderr}` : ''),
71
+ exitCode: code ?? 1,
72
+ duration,
73
+ });
74
+ });
75
+ proc.stdin.write(prompt);
76
+ proc.stdin.end();
77
+ });
78
+ },
79
+ };
80
+ //# sourceMappingURL=claude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/agents/claude.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Agent, AgentType } from './base.js';
2
+ export declare function getAgent(type: AgentType): Agent;
3
+ export * from './base.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAOjD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,KAAK,CAE/C;AAED,cAAc,WAAW,CAAA"}
@@ -0,0 +1,9 @@
1
+ import { claude } from './claude.js';
2
+ const agents = {
3
+ claude,
4
+ };
5
+ export function getAgent(type) {
6
+ return agents[type];
7
+ }
8
+ export * from './base.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,MAAM,MAAM,GAA6B;IACvC,MAAM;CACP,CAAA;AAED,MAAM,UAAU,QAAQ,CAAC,IAAe;IACtC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAA;AACrB,CAAC;AAED,cAAc,WAAW,CAAA"}
@@ -0,0 +1,7 @@
1
+ export interface RunOptions {
2
+ prompt: string[];
3
+ agent: string;
4
+ iterations: string;
5
+ }
6
+ export declare function run(opts: RunOptions): Promise<void>;
7
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,wBAAsB,GAAG,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA4EzD"}
@@ -0,0 +1,73 @@
1
+ import chalk from 'chalk';
2
+ import { getAgent, isValidAgent } from '../agents/index.js';
3
+ import { createSession, writeLog, getSessionDir } from '../session/index.js';
4
+ import { buildPrompt, COMPLETION_MARKER } from '../utils/index.js';
5
+ export async function run(opts) {
6
+ // Validate agent
7
+ if (!isValidAgent(opts.agent)) {
8
+ console.error(chalk.red(`Unknown agent: ${opts.agent}`));
9
+ console.error(`Supported agents: claude`);
10
+ process.exit(1);
11
+ }
12
+ // Validate iterations
13
+ const iterations = parseInt(opts.iterations, 10);
14
+ if (isNaN(iterations) || iterations <= 0) {
15
+ console.error(chalk.red(`Iterations must be a positive number, got: ${opts.iterations}`));
16
+ process.exit(1);
17
+ }
18
+ const agent = getAgent(opts.agent);
19
+ // Build prompt with completion instructions
20
+ let prompt;
21
+ try {
22
+ prompt = await buildPrompt(opts.prompt);
23
+ }
24
+ catch (err) {
25
+ const message = err instanceof Error ? err.message : String(err);
26
+ console.error(chalk.red(`Failed to read prompt files: ${message}`));
27
+ process.exit(1);
28
+ }
29
+ // Create session
30
+ const sessionId = await createSession({
31
+ promptFiles: opts.prompt,
32
+ agent: opts.agent,
33
+ iterations,
34
+ });
35
+ console.log(chalk.blue(`Session: ${sessionId}`));
36
+ console.log(chalk.gray(`Agent: ${agent.name}`));
37
+ console.log(chalk.gray(`Iterations: ${iterations}`));
38
+ console.log();
39
+ // Run loop
40
+ let completed = false;
41
+ let actualIterations = 0;
42
+ for (let i = 0; i < iterations; i++) {
43
+ actualIterations++;
44
+ console.log(chalk.yellow(`[${i + 1}/${iterations}] Running ${agent.name}...`));
45
+ console.log();
46
+ const result = await agent.execute(prompt, process.cwd(), {
47
+ onOutput: (chunk) => process.stdout.write(chunk),
48
+ });
49
+ console.log();
50
+ await writeLog(sessionId, i, result);
51
+ if (result.exitCode !== 0) {
52
+ console.log(chalk.red(` Exit code: ${result.exitCode}`));
53
+ }
54
+ else {
55
+ console.log(chalk.green(` Done (${result.duration}ms)`));
56
+ }
57
+ // Check for completion marker
58
+ if (result.output.includes(COMPLETION_MARKER)) {
59
+ console.log(chalk.cyan(` Agent signaled task complete`));
60
+ completed = true;
61
+ break;
62
+ }
63
+ }
64
+ console.log();
65
+ if (completed) {
66
+ console.log(chalk.green(`Task completed after ${actualIterations} iteration(s)`));
67
+ }
68
+ else {
69
+ console.log(chalk.yellow(`Reached max iterations (${iterations})`));
70
+ }
71
+ console.log(chalk.gray(`Logs: ${getSessionDir(sessionId)}`));
72
+ }
73
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import { run } from './commands/run.js';
4
+ program
5
+ .name('ralph')
6
+ .description('Loop coding agent CLI - run agents headlessly in a loop')
7
+ .version('0.1.0');
8
+ program
9
+ .command('run')
10
+ .description('Run an agent in a loop')
11
+ .requiredOption('-p, --prompt <files...>', 'Prompt files to pass to agent')
12
+ .option('-a, --agent <agent>', 'Agent type', 'claude')
13
+ .option('-i, --iterations <n>', 'Number of loop iterations', '4')
14
+ .action(run);
15
+ program.parse();
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAA;AAEvC,OAAO;KACJ,IAAI,CAAC,OAAO,CAAC;KACb,WAAW,CAAC,yDAAyD,CAAC;KACtE,OAAO,CAAC,OAAO,CAAC,CAAA;AAEnB,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,wBAAwB,CAAC;KACrC,cAAc,CAAC,yBAAyB,EAAE,+BAA+B,CAAC;KAC1E,MAAM,CAAC,qBAAqB,EAAE,YAAY,EAAE,QAAQ,CAAC;KACrD,MAAM,CAAC,sBAAsB,EAAE,2BAA2B,EAAE,GAAG,CAAC;KAChE,MAAM,CAAC,GAAG,CAAC,CAAA;AAEd,OAAO,CAAC,KAAK,EAAE,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from './manager.js';
2
+ export * from './logger.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from './manager.js';
2
+ export * from './logger.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,10 @@
1
+ import type { AgentResult } from '../agents/base.js';
2
+ export interface LogEntry {
3
+ iteration: number;
4
+ timestamp: string;
5
+ duration: number;
6
+ exitCode: number;
7
+ output: string;
8
+ }
9
+ export declare function writeLog(sessionId: string, iteration: number, result: AgentResult): Promise<void>;
10
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/session/logger.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAGpD,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,IAAI,CAAC,CAcf"}
@@ -0,0 +1,17 @@
1
+ import { writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { getSessionDir } from './manager.js';
4
+ export async function writeLog(sessionId, iteration, result) {
5
+ const sessionDir = getSessionDir(sessionId);
6
+ const logPath = join(sessionDir, `${iteration}.log`);
7
+ const header = [
8
+ `# Iteration ${iteration}`,
9
+ `Timestamp: ${new Date().toISOString()}`,
10
+ `Duration: ${result.duration}ms`,
11
+ `Exit Code: ${result.exitCode}`,
12
+ '---',
13
+ '',
14
+ ].join('\n');
15
+ await writeFile(logPath, header + result.output);
16
+ }
17
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/session/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAU5C,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,SAAiB,EACjB,SAAiB,EACjB,MAAmB;IAEnB,MAAM,UAAU,GAAG,aAAa,CAAC,SAAS,CAAC,CAAA;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,SAAS,MAAM,CAAC,CAAA;IAEpD,MAAM,MAAM,GAAG;QACb,eAAe,SAAS,EAAE;QAC1B,cAAc,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;QACxC,aAAa,MAAM,CAAC,QAAQ,IAAI;QAChC,cAAc,MAAM,CAAC,QAAQ,EAAE;QAC/B,KAAK;QACL,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEZ,MAAM,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;AAClD,CAAC"}
@@ -0,0 +1,18 @@
1
+ export interface SessionMeta {
2
+ id: string;
3
+ promptFiles: string[];
4
+ agent: string;
5
+ cwd: string;
6
+ iterations: number;
7
+ startTime: string;
8
+ }
9
+ export declare function getRalphDir(): string;
10
+ export declare function getSessionsDir(): string;
11
+ export declare function getSessionDir(sessionId: string): string;
12
+ export interface CreateSessionOpts {
13
+ promptFiles: string[];
14
+ agent: string;
15
+ iterations: number;
16
+ }
17
+ export declare function createSession(opts: CreateSessionOpts): Promise<string>;
18
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/session/manager.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkB5E"}
@@ -0,0 +1,29 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { nanoid } from 'nanoid';
5
+ export function getRalphDir() {
6
+ return join(homedir(), '.ralph');
7
+ }
8
+ export function getSessionsDir() {
9
+ return join(getRalphDir(), 'sessions');
10
+ }
11
+ export function getSessionDir(sessionId) {
12
+ return join(getSessionsDir(), sessionId);
13
+ }
14
+ export async function createSession(opts) {
15
+ const sessionId = nanoid(10);
16
+ const sessionDir = getSessionDir(sessionId);
17
+ await mkdir(sessionDir, { recursive: true });
18
+ const meta = {
19
+ id: sessionId,
20
+ promptFiles: opts.promptFiles,
21
+ agent: opts.agent,
22
+ cwd: process.cwd(),
23
+ iterations: opts.iterations,
24
+ startTime: new Date().toISOString(),
25
+ };
26
+ await writeFile(join(sessionDir, 'meta.json'), JSON.stringify(meta, null, 2));
27
+ return sessionId;
28
+ }
29
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/session/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAW/B,MAAM,UAAU,WAAW;IACzB,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAA;AAClC,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,UAAU,CAAC,CAAA;AACxC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,OAAO,IAAI,CAAC,cAAc,EAAE,EAAE,SAAS,CAAC,CAAA;AAC1C,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAuB;IACzD,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,CAAA;IAC5B,MAAM,UAAU,GAAG,aAAa,CAAC,SAAS,CAAC,CAAA;IAE3C,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE5C,MAAM,IAAI,GAAgB;QACxB,EAAE,EAAE,SAAS;QACb,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAA;IAED,MAAM,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;IAE7E,OAAO,SAAS,CAAA;AAClB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const COMPLETION_MARKER = "<ralph>RALPH_COMPLETED</ralph>";
2
+ export declare function readPromptFiles(inputs: string[]): Promise<string>;
3
+ export declare function buildPrompt(inputs: string[]): Promise<string>;
4
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/utils/files.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB,mCAAmC,CAAA;AAmBjE,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBvE;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAGnE"}
@@ -0,0 +1,39 @@
1
+ import { readFile, access } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ export const COMPLETION_MARKER = '<ralph>RALPH_COMPLETED</ralph>';
4
+ const COMPLETION_INSTRUCTIONS = `
5
+ ---
6
+ When you have fully completed the task with no remaining work, include this marker in your final response:
7
+ ${COMPLETION_MARKER}
8
+
9
+ Only use this marker when the task is 100% complete.
10
+ `;
11
+ async function fileExists(path) {
12
+ try {
13
+ await access(path);
14
+ return true;
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
20
+ export async function readPromptFiles(inputs) {
21
+ const contents = [];
22
+ for (const input of inputs) {
23
+ const absolutePath = resolve(process.cwd(), input);
24
+ if (await fileExists(absolutePath)) {
25
+ const content = await readFile(absolutePath, 'utf-8');
26
+ contents.push(content);
27
+ }
28
+ else {
29
+ // treat as direct text
30
+ contents.push(input);
31
+ }
32
+ }
33
+ return contents.join('\n\n');
34
+ }
35
+ export async function buildPrompt(inputs) {
36
+ const content = await readPromptFiles(inputs);
37
+ return content + COMPLETION_INSTRUCTIONS;
38
+ }
39
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/utils/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,MAAM,CAAC,MAAM,iBAAiB,GAAG,gCAAgC,CAAA;AAEjE,MAAM,uBAAuB,GAAG;;;EAG9B,iBAAiB;;;CAGlB,CAAA;AAED,KAAK,UAAU,UAAU,CAAC,IAAY;IACpC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;QAClB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAgB;IACpD,MAAM,QAAQ,GAAa,EAAE,CAAA;IAE7B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAA;QAElD,IAAI,MAAM,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACnC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;YACrD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACxB,CAAC;aAAM,CAAC;YACN,uBAAuB;YACvB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtB,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAgB;IAChD,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,CAAA;IAC7C,OAAO,OAAO,GAAG,uBAAuB,CAAA;AAC1C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './files.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA"}
@@ -0,0 +1,2 @@
1
+ export * from './files.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "rlph-cli",
3
+ "version": "0.1.0",
4
+ "description": "Loop coding agent CLI - run agents headlessly in a loop",
5
+ "type": "module",
6
+ "bin": {
7
+ "ralph": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "engines": {
13
+ "node": ">=18"
14
+ },
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "dev": "tsc --watch",
18
+ "test": "vitest run",
19
+ "test:watch": "vitest",
20
+ "test:coverage": "vitest run --coverage",
21
+ "prepublishOnly": "bun run build"
22
+ },
23
+ "keywords": [
24
+ "cli",
25
+ "agent",
26
+ "claude",
27
+ "loop",
28
+ "automation"
29
+ ],
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/rem4ik4ever/ralph.git"
34
+ },
35
+ "dependencies": {
36
+ "chalk": "^5.3.0",
37
+ "commander": "^12.1.0",
38
+ "nanoid": "^5.0.9"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^22.10.5",
42
+ "@vitest/coverage-v8": "^2.1.8",
43
+ "typescript": "^5.7.3",
44
+ "vitest": "^2.1.8"
45
+ }
46
+ }