@daonhan/ralph-core 0.1.0 → 0.1.1
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/Dockerfile +5 -1
- package/dist/cli-help.d.ts +9 -0
- package/dist/cli-help.d.ts.map +1 -0
- package/dist/cli-help.js +51 -0
- package/dist/cli-help.js.map +1 -0
- package/dist/gh-main.d.ts +2 -0
- package/dist/gh-main.d.ts.map +1 -0
- package/dist/gh-main.js +43 -0
- package/dist/gh-main.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/loop.d.ts +11 -0
- package/dist/loop.d.ts.map +1 -0
- package/dist/loop.js +26 -0
- package/dist/loop.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +43 -0
- package/dist/main.js.map +1 -0
- package/dist/render.d.ts +8 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +61 -0
- package/dist/render.js.map +1 -0
- package/dist/runner.d.ts +5 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +242 -0
- package/dist/runner.js.map +1 -0
- package/dist/stages.d.ts +23 -0
- package/dist/stages.d.ts.map +1 -0
- package/dist/stages.js +22 -0
- package/dist/stages.js.map +1 -0
- package/package.json +12 -32
- package/templates/ghprompt.md +67 -67
- package/templates/prompt.md +80 -80
package/Dockerfile
CHANGED
|
@@ -15,7 +15,7 @@ RUN wget -qO /tmp/ms.deb https://packages.microsoft.com/config/debian/12/package
|
|
|
15
15
|
&& dpkg -i /tmp/ms.deb \
|
|
16
16
|
&& rm /tmp/ms.deb \
|
|
17
17
|
&& apt-get update \
|
|
18
|
-
&& apt-get install -y dotnet-sdk-
|
|
18
|
+
&& apt-get install -y dotnet-sdk-10.0 \
|
|
19
19
|
&& rm -rf /var/lib/apt/lists/*
|
|
20
20
|
|
|
21
21
|
# GitHub CLI
|
|
@@ -34,6 +34,10 @@ RUN corepack enable
|
|
|
34
34
|
RUN usermod -d /home/agent -m -l agent node
|
|
35
35
|
USER agent
|
|
36
36
|
|
|
37
|
+
# Bind-mounted host workspace may show foreign UID inside container.
|
|
38
|
+
# Tell git to trust any path so `git ...` works against the mount.
|
|
39
|
+
RUN git config --global --add safe.directory '*'
|
|
40
|
+
|
|
37
41
|
# Claude Code CLI
|
|
38
42
|
RUN curl -fsSL https://claude.ai/install.sh | bash
|
|
39
43
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type CliFlags = {
|
|
2
|
+
help: boolean;
|
|
3
|
+
printConfig: boolean;
|
|
4
|
+
rest: string[];
|
|
5
|
+
};
|
|
6
|
+
export declare function parseFlags(argv: string[]): CliFlags;
|
|
7
|
+
export declare function printHelp(bin: string, usage: string, description: string): void;
|
|
8
|
+
export declare function printConfig(bin: string, workspaceDir: string, ralphDir: string, sandcastleDir: string): void;
|
|
9
|
+
//# sourceMappingURL=cli-help.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-help.d.ts","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAE/E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,CAUnD;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAqB/E;AAED,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,IAAI,CAUN"}
|
package/dist/cli-help.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { IMAGE_REF } from "./runner.js";
|
|
4
|
+
export function parseFlags(argv) {
|
|
5
|
+
let help = false;
|
|
6
|
+
let printConfig = false;
|
|
7
|
+
const rest = [];
|
|
8
|
+
for (const a of argv) {
|
|
9
|
+
if (a === "-h" || a === "--help")
|
|
10
|
+
help = true;
|
|
11
|
+
else if (a === "--print-config")
|
|
12
|
+
printConfig = true;
|
|
13
|
+
else
|
|
14
|
+
rest.push(a);
|
|
15
|
+
}
|
|
16
|
+
return { help, printConfig, rest };
|
|
17
|
+
}
|
|
18
|
+
export function printHelp(bin, usage, description) {
|
|
19
|
+
process.stdout.write(`${bin} — ${description}
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
${bin} ${usage}
|
|
23
|
+
${bin} --help | -h
|
|
24
|
+
${bin} --print-config [args...]
|
|
25
|
+
|
|
26
|
+
Flags:
|
|
27
|
+
-h, --help show this help and exit
|
|
28
|
+
--print-config resolve workspace / docker context / image, print, exit without launching docker
|
|
29
|
+
|
|
30
|
+
Environment variables:
|
|
31
|
+
RALPH_WORKSPACE host dir bind-mounted at /home/agent/workspace (default: cwd)
|
|
32
|
+
RALPH_DOCKER_CONTEXT docker build fallback context (default: bundled @daonhan/ralph-core dir)
|
|
33
|
+
RALPH_IMAGE image ref (default: docker.io/daonhan/ralph-sandbox:latest)
|
|
34
|
+
RALPH_IMAGE_TAG legacy alias for RALPH_IMAGE
|
|
35
|
+
|
|
36
|
+
Image resolution: docker image inspect → docker pull → docker build (fallback).
|
|
37
|
+
Build fallback runs only if pull fails AND $RALPH_DOCKER_CONTEXT/Dockerfile exists; expect ~5min.
|
|
38
|
+
`);
|
|
39
|
+
}
|
|
40
|
+
export function printConfig(bin, workspaceDir, ralphDir, sandcastleDir) {
|
|
41
|
+
const dockerfile = join(ralphDir, "Dockerfile");
|
|
42
|
+
const dfPresent = existsSync(dockerfile);
|
|
43
|
+
process.stdout.write(`[${bin}] resolved config
|
|
44
|
+
RALPH_WORKSPACE ${workspaceDir}${process.env.RALPH_WORKSPACE ? "" : " (default: cwd)"}
|
|
45
|
+
RALPH_DOCKER_CONTEXT ${ralphDir}${process.env.RALPH_DOCKER_CONTEXT ? "" : " (default: bundled core dir)"}
|
|
46
|
+
RALPH_IMAGE ${IMAGE_REF}${process.env.RALPH_IMAGE || process.env.RALPH_IMAGE_TAG ? "" : " (default)"}
|
|
47
|
+
Dockerfile at ctx ${dfPresent ? "present" : "MISSING"} (${dockerfile})
|
|
48
|
+
sandcastleDir ${sandcastleDir}
|
|
49
|
+
`);
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=cli-help.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-help.js","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIxC,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,QAAQ;YAAE,IAAI,GAAG,IAAI,CAAC;aACzC,IAAI,CAAC,KAAK,gBAAgB;YAAE,WAAW,GAAG,IAAI,CAAC;;YAC/C,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,KAAa,EAAE,WAAmB;IACvE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,MAAM,WAAW;;;IAG1C,GAAG,IAAI,KAAK;IACZ,GAAG;IACH,GAAG;;;;;;;;;;;;;;CAcN,CAAC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,GAAW,EACX,YAAoB,EACpB,QAAgB,EAChB,aAAqB;IAErB,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACzC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG;0BACJ,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB;0BACpE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,+BAA+B;0BAClF,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa;0BACvF,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,KAAK,UAAU;0BAChD,aAAa;CACtC,CAAC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gh-main.d.ts","sourceRoot":"","sources":["../src/gh-main.ts"],"names":[],"mappings":"AAWA,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsC5D"}
|
package/dist/gh-main.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { dirname, resolve } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { parseFlags, printConfig, printHelp } from "./cli-help.js";
|
|
4
|
+
import { runLoop } from "./loop.js";
|
|
5
|
+
import { STAGES } from "./stages.js";
|
|
6
|
+
const BIN = "ralph-ghafk";
|
|
7
|
+
const USAGE = "<iterations>";
|
|
8
|
+
const DESC = "GitHub-issue-driven Claude Code AFK loop";
|
|
9
|
+
export async function runGhAfk(argv) {
|
|
10
|
+
const flags = parseFlags(argv);
|
|
11
|
+
if (flags.help) {
|
|
12
|
+
printHelp(BIN, USAGE, DESC);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const sandcastleDir = resolve(here, "..");
|
|
17
|
+
const workspaceDir = resolve(process.env.RALPH_WORKSPACE ?? process.cwd());
|
|
18
|
+
const ralphDir = resolve(process.env.RALPH_DOCKER_CONTEXT ?? sandcastleDir);
|
|
19
|
+
if (flags.printConfig) {
|
|
20
|
+
printConfig(BIN, workspaceDir, ralphDir, sandcastleDir);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const [iterationsArg] = flags.rest;
|
|
24
|
+
if (!iterationsArg) {
|
|
25
|
+
console.error(`Usage: ${BIN} ${USAGE}`);
|
|
26
|
+
console.error(` ${BIN} --help`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
const iterations = Number.parseInt(iterationsArg, 10);
|
|
30
|
+
if (!Number.isFinite(iterations) || iterations < 1) {
|
|
31
|
+
console.error(`Invalid iterations: ${iterationsArg}`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
await runLoop({
|
|
35
|
+
stages: [STAGES.ghafkImplementer, STAGES.reviewer],
|
|
36
|
+
inputs: "",
|
|
37
|
+
iterations,
|
|
38
|
+
ralphDir,
|
|
39
|
+
workspaceDir,
|
|
40
|
+
sandcastleDir,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=gh-main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gh-main.js","sourceRoot":"","sources":["../src/gh-main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,GAAG,GAAG,aAAa,CAAC;AAC1B,MAAM,KAAK,GAAG,cAAc,CAAC;AAC7B,MAAM,IAAI,GAAG,0CAA0C,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAc;IAC3C,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAE/B,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC1C,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3E,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,aAAa,CAAC,CAAC;IAE5E,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACtB,WAAW,CAAC,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;QACxD,OAAO;IACT,CAAC;IAED,MAAM,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC;IACnC,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC;QACxC,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,KAAK,CAAC,uBAAuB,aAAa,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,CAAC;QACZ,MAAM,EAAE,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,QAAQ,CAAC;QAClD,MAAM,EAAE,EAAE;QACV,UAAU;QACV,QAAQ;QACR,YAAY;QACZ,aAAa;KACd,CAAC,CAAC;AACL,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { runAfk } from "./main.js";
|
|
2
|
+
export { runGhAfk } from "./gh-main.js";
|
|
3
|
+
export { runLoop, type LoopOptions } from "./loop.js";
|
|
4
|
+
export { STAGES, type Stage } from "./stages.js";
|
|
5
|
+
export { renderTemplate, type RenderOptions, type RenderVars } from "./render.js";
|
|
6
|
+
export { ensureImage, runStage } from "./runner.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { runAfk } from "./main.js";
|
|
2
|
+
export { runGhAfk } from "./gh-main.js";
|
|
3
|
+
export { runLoop } from "./loop.js";
|
|
4
|
+
export { STAGES } from "./stages.js";
|
|
5
|
+
export { renderTemplate } from "./render.js";
|
|
6
|
+
export { ensureImage, runStage } from "./runner.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,OAAO,EAAoB,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,MAAM,EAAc,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,cAAc,EAAuC,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/loop.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Stage } from "./stages.js";
|
|
2
|
+
export type LoopOptions = {
|
|
3
|
+
stages: [Stage, ...Stage[]];
|
|
4
|
+
inputs: string;
|
|
5
|
+
iterations: number;
|
|
6
|
+
ralphDir: string;
|
|
7
|
+
workspaceDir: string;
|
|
8
|
+
sandcastleDir: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function runLoop(opts: LoopOptions): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAIzC,MAAM,MAAM,WAAW,GAAG;IAGxB,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB9D"}
|
package/dist/loop.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { renderTemplate } from "./render.js";
|
|
3
|
+
import { ensureImage, runStage } from "./runner.js";
|
|
4
|
+
const SENTINEL = "<promise>NO MORE TASKS</promise>";
|
|
5
|
+
export async function runLoop(opts) {
|
|
6
|
+
const { stages, inputs, iterations, ralphDir, workspaceDir, sandcastleDir } = opts;
|
|
7
|
+
ensureImage(ralphDir);
|
|
8
|
+
for (let i = 1; i <= iterations; i++) {
|
|
9
|
+
let gateResult = "";
|
|
10
|
+
for (let s = 0; s < stages.length; s++) {
|
|
11
|
+
const stage = stages[s];
|
|
12
|
+
process.stderr.write(`\n[sandcastle] iteration ${i}/${iterations} stage ${s + 1}/${stages.length} (${stage.name})\n`);
|
|
13
|
+
const templatePath = join(sandcastleDir, "templates", stage.template);
|
|
14
|
+
const prompt = renderTemplate(templatePath, { INPUTS: inputs }, { cwd: workspaceDir });
|
|
15
|
+
const result = await runStage(stage, prompt, workspaceDir, i);
|
|
16
|
+
if (s === 0) {
|
|
17
|
+
gateResult = result;
|
|
18
|
+
if (gateResult.includes(SENTINEL)) {
|
|
19
|
+
console.log(`Ralph complete after ${i} iterations.`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=loop.js.map
|
package/dist/loop.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGpD,MAAM,QAAQ,GAAG,kCAAkC,CAAC;AAapD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAiB;IAC7C,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IAEnF,WAAW,CAAC,QAAQ,CAAC,CAAC;IAEtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,UAAU,GAAG,EAAE,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,4BAA4B,CAAC,IAAI,UAAU,UAAU,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK,CAAC,IAAI,KAAK,CAChG,CAAC;YACF,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,EAAE,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;YACtE,MAAM,MAAM,GAAG,cAAc,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;YACvF,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;YAC9D,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACZ,UAAU,GAAG,MAAM,CAAC;gBACpB,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAClC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,cAAc,CAAC,CAAC;oBACrD,OAAO;gBACT,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAWA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsC1D"}
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { dirname, resolve } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { parseFlags, printConfig, printHelp } from "./cli-help.js";
|
|
4
|
+
import { runLoop } from "./loop.js";
|
|
5
|
+
import { STAGES } from "./stages.js";
|
|
6
|
+
const BIN = "ralph-afk";
|
|
7
|
+
const USAGE = "<plan-and-prd> <iterations>";
|
|
8
|
+
const DESC = "plan/PRD-driven Claude Code AFK loop";
|
|
9
|
+
export async function runAfk(argv) {
|
|
10
|
+
const flags = parseFlags(argv);
|
|
11
|
+
if (flags.help) {
|
|
12
|
+
printHelp(BIN, USAGE, DESC);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const sandcastleDir = resolve(here, "..");
|
|
17
|
+
const workspaceDir = resolve(process.env.RALPH_WORKSPACE ?? process.cwd());
|
|
18
|
+
const ralphDir = resolve(process.env.RALPH_DOCKER_CONTEXT ?? sandcastleDir);
|
|
19
|
+
if (flags.printConfig) {
|
|
20
|
+
printConfig(BIN, workspaceDir, ralphDir, sandcastleDir);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const [planAndPrd, iterationsArg] = flags.rest;
|
|
24
|
+
if (!planAndPrd || !iterationsArg) {
|
|
25
|
+
console.error(`Usage: ${BIN} ${USAGE}`);
|
|
26
|
+
console.error(` ${BIN} --help`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
const iterations = Number.parseInt(iterationsArg, 10);
|
|
30
|
+
if (!Number.isFinite(iterations) || iterations < 1) {
|
|
31
|
+
console.error(`Invalid iterations: ${iterationsArg}`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
await runLoop({
|
|
35
|
+
stages: [STAGES.implementer, STAGES.reviewer],
|
|
36
|
+
inputs: planAndPrd,
|
|
37
|
+
iterations,
|
|
38
|
+
ralphDir,
|
|
39
|
+
workspaceDir,
|
|
40
|
+
sandcastleDir,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,GAAG,GAAG,WAAW,CAAC;AACxB,MAAM,KAAK,GAAG,6BAA6B,CAAC;AAC5C,MAAM,IAAI,GAAG,sCAAsC,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAc;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAE/B,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC1C,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3E,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,aAAa,CAAC,CAAC;IAE5E,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACtB,WAAW,CAAC,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;QACxD,OAAO;IACT,CAAC;IAED,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC;IAC/C,IAAI,CAAC,UAAU,IAAI,CAAC,aAAa,EAAE,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC;QACxC,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,KAAK,CAAC,uBAAuB,aAAa,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,CAAC;QACZ,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC;QAC7C,MAAM,EAAE,UAAU;QAClB,UAAU;QACV,QAAQ;QACR,YAAY;QACZ,aAAa;KACd,CAAC,CAAC;AACL,CAAC"}
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAcF,wBAAgB,cAAc,CAC5B,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,UAAU,EAChB,IAAI,GAAE,aAAkB,GACvB,MAAM,CAsCR"}
|
package/dist/render.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, isAbsolute, resolve } from "node:path";
|
|
4
|
+
// Order matters: !?`...` (try-shell w/ ||| fallback) must match before plain !`...`.
|
|
5
|
+
const SHELL_TRY_TAG = /!\?`([^`]+)`/g;
|
|
6
|
+
const SHELL_TAG = /!`([^`]+)`/g;
|
|
7
|
+
const INCLUDE_TAG = /@include:([^\s`)]+)/g;
|
|
8
|
+
const INPUTS_TAG = /\{\{\s*INPUTS\s*\}\}/g;
|
|
9
|
+
const TRY_SEP = "|||";
|
|
10
|
+
function resolveShell() {
|
|
11
|
+
if (process.platform !== "win32")
|
|
12
|
+
return "/bin/bash";
|
|
13
|
+
// Prefer bash.exe (git-for-windows / WSL passthrough) for POSIX redirects + utils.
|
|
14
|
+
const pathDirs = (process.env.PATH ?? "").split(";");
|
|
15
|
+
for (const d of pathDirs) {
|
|
16
|
+
if (!d)
|
|
17
|
+
continue;
|
|
18
|
+
const candidate = resolve(d, "bash.exe");
|
|
19
|
+
if (existsSync(candidate))
|
|
20
|
+
return candidate;
|
|
21
|
+
}
|
|
22
|
+
return "cmd.exe";
|
|
23
|
+
}
|
|
24
|
+
export function renderTemplate(templatePath, vars, opts = {}) {
|
|
25
|
+
const raw = readFileSync(templatePath, "utf8");
|
|
26
|
+
const templateDir = dirname(templatePath);
|
|
27
|
+
const shell = resolveShell();
|
|
28
|
+
const afterInclude = raw.replace(INCLUDE_TAG, (_match, rel) => {
|
|
29
|
+
const target = isAbsolute(rel) ? rel : resolve(templateDir, rel);
|
|
30
|
+
return readFileSync(target, "utf8").replace(/\r?\n$/, "");
|
|
31
|
+
});
|
|
32
|
+
const afterShellTry = afterInclude.replace(SHELL_TRY_TAG, (_match, body) => {
|
|
33
|
+
const sep = body.lastIndexOf(TRY_SEP);
|
|
34
|
+
const cmd = sep >= 0 ? body.slice(0, sep) : body;
|
|
35
|
+
const fallback = sep >= 0 ? body.slice(sep + TRY_SEP.length) : "";
|
|
36
|
+
try {
|
|
37
|
+
const out = execSync(cmd, {
|
|
38
|
+
shell,
|
|
39
|
+
encoding: "utf8",
|
|
40
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
41
|
+
cwd: opts.cwd,
|
|
42
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
43
|
+
});
|
|
44
|
+
return out.replace(/\r?\n$/, "");
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return fallback;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
const afterShell = afterShellTry.replace(SHELL_TAG, (_match, cmd) => {
|
|
51
|
+
const out = execSync(cmd, {
|
|
52
|
+
shell,
|
|
53
|
+
encoding: "utf8",
|
|
54
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
55
|
+
cwd: opts.cwd,
|
|
56
|
+
});
|
|
57
|
+
return out.replace(/\r?\n$/, "");
|
|
58
|
+
});
|
|
59
|
+
return afterShell.replace(INPUTS_TAG, vars.INPUTS);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Stage } from "./stages.js";
|
|
2
|
+
export declare const IMAGE_REF: string;
|
|
3
|
+
export declare function ensureImage(buildContext?: string): void;
|
|
4
|
+
export declare function runStage(stage: Stage, renderedPrompt: string, workspaceDir: string, iteration: number): Promise<string>;
|
|
5
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,eAAO,MAAM,SAAS,QAGoB,CAAC;AAyB3C,wBAAgB,WAAW,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAgCvD;AAED,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,KAAK,EACZ,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAqEjB"}
|
package/dist/runner.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
2
|
+
import { appendFileSync, closeSync, existsSync, mkdirSync, openSync, rmSync, writeFileSync, } from "node:fs";
|
|
3
|
+
import { createInterface } from "node:readline";
|
|
4
|
+
import { join, posix } from "node:path";
|
|
5
|
+
export const IMAGE_REF = process.env.RALPH_IMAGE ??
|
|
6
|
+
process.env.RALPH_IMAGE_TAG ?? // legacy
|
|
7
|
+
"docker.io/daonhan/ralph-sandbox:latest";
|
|
8
|
+
const STDERR_TAIL_LINES = 40;
|
|
9
|
+
const TOOL_INPUT_PREVIEW = 200;
|
|
10
|
+
const TOOL_RESULT_PREVIEW = 400;
|
|
11
|
+
export function ensureImage(buildContext) {
|
|
12
|
+
const inspect = spawnSync("docker", ["image", "inspect", IMAGE_REF], {
|
|
13
|
+
stdio: "ignore",
|
|
14
|
+
});
|
|
15
|
+
if (inspect.status === 0)
|
|
16
|
+
return;
|
|
17
|
+
process.stderr.write(`[sandcastle] Pulling image ${IMAGE_REF}\n`);
|
|
18
|
+
const pull = spawnSync("docker", ["pull", IMAGE_REF], { stdio: "inherit" });
|
|
19
|
+
if (pull.status === 0)
|
|
20
|
+
return;
|
|
21
|
+
if (!buildContext) {
|
|
22
|
+
throw new Error(`docker pull failed for ${IMAGE_REF} and no build context provided. ` +
|
|
23
|
+
`Set RALPH_DOCKER_CONTEXT to a directory containing a Dockerfile, ` +
|
|
24
|
+
`or override RALPH_IMAGE to an image you can pull.`);
|
|
25
|
+
}
|
|
26
|
+
const dockerfile = join(buildContext, "Dockerfile");
|
|
27
|
+
if (!existsSync(dockerfile)) {
|
|
28
|
+
throw new Error(`docker pull failed for ${IMAGE_REF} and no Dockerfile at ${dockerfile}`);
|
|
29
|
+
}
|
|
30
|
+
process.stderr.write(`[sandcastle] pull failed; building ${IMAGE_REF} from ${buildContext}\n`);
|
|
31
|
+
const build = spawnSync("docker", ["build", "-t", IMAGE_REF, buildContext], {
|
|
32
|
+
stdio: "inherit",
|
|
33
|
+
});
|
|
34
|
+
if (build.status !== 0) {
|
|
35
|
+
throw new Error(`docker build failed (exit ${build.status})`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export async function runStage(stage, renderedPrompt, workspaceDir, iteration) {
|
|
39
|
+
const tmpHostDir = join(workspaceDir, ".ralph-tmp");
|
|
40
|
+
mkdirSync(tmpHostDir, { recursive: true });
|
|
41
|
+
const logsDir = join(tmpHostDir, "logs");
|
|
42
|
+
mkdirSync(logsDir, { recursive: true });
|
|
43
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
44
|
+
const logPath = join(logsDir, `${timestamp}-iter${iteration}-${stage.name}.ndjson`);
|
|
45
|
+
const promptName = `.run-${process.pid}-${iteration}-${Date.now()}.md`;
|
|
46
|
+
const promptHostPath = join(tmpHostDir, promptName);
|
|
47
|
+
const promptContainerPath = posix.join(".ralph-tmp", promptName);
|
|
48
|
+
writeFileSync(promptHostPath, renderedPrompt, "utf8");
|
|
49
|
+
process.stderr.write(`[sandcastle] log → ${logPath}\n`);
|
|
50
|
+
try {
|
|
51
|
+
const args = [
|
|
52
|
+
"run",
|
|
53
|
+
"--rm",
|
|
54
|
+
"-i",
|
|
55
|
+
"-v",
|
|
56
|
+
`${workspaceDir}:/home/agent/workspace`,
|
|
57
|
+
"-w",
|
|
58
|
+
"/home/agent/workspace",
|
|
59
|
+
"-e",
|
|
60
|
+
"GIT_CONFIG_COUNT=1",
|
|
61
|
+
"-e",
|
|
62
|
+
"GIT_CONFIG_KEY_0=safe.directory",
|
|
63
|
+
"-e",
|
|
64
|
+
"GIT_CONFIG_VALUE_0=*",
|
|
65
|
+
];
|
|
66
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
67
|
+
if (home) {
|
|
68
|
+
const claudeDir = join(home, ".claude");
|
|
69
|
+
const claudeJson = join(home, ".claude.json");
|
|
70
|
+
const ghConfigDir = join(home, ".config", "gh");
|
|
71
|
+
if (existsSync(claudeDir)) {
|
|
72
|
+
args.push("-v", `${claudeDir}:/home/agent/.claude`);
|
|
73
|
+
}
|
|
74
|
+
if (existsSync(claudeJson)) {
|
|
75
|
+
args.push("-v", `${claudeJson}:/home/agent/.claude.json`);
|
|
76
|
+
}
|
|
77
|
+
if (existsSync(ghConfigDir)) {
|
|
78
|
+
args.push("-v", `${ghConfigDir}:/home/agent/.config/gh:ro`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
args.push(IMAGE_REF, "claude", "--verbose", "--print", "--output-format", "stream-json");
|
|
82
|
+
if (stage.permissionMode) {
|
|
83
|
+
args.push("--permission-mode", stage.permissionMode);
|
|
84
|
+
}
|
|
85
|
+
args.push(`Read the full instructions from the file ./${promptContainerPath} in the current workspace and execute them.`);
|
|
86
|
+
return await streamDocker(args, logPath);
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
rmSync(promptHostPath, { force: true });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function streamDocker(args, logPath) {
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
const logFd = openSync(logPath, "a");
|
|
95
|
+
const child = spawn("docker", args, {
|
|
96
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
97
|
+
});
|
|
98
|
+
let finalResult = "";
|
|
99
|
+
const stderrTail = [];
|
|
100
|
+
const rl = createInterface({ input: child.stdout });
|
|
101
|
+
rl.on("line", (line) => {
|
|
102
|
+
if (!line.startsWith("{"))
|
|
103
|
+
return;
|
|
104
|
+
appendFileSync(logFd, line + "\n");
|
|
105
|
+
let parsed;
|
|
106
|
+
try {
|
|
107
|
+
parsed = JSON.parse(line);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
renderEvent(parsed);
|
|
113
|
+
if (parsed.type === "result") {
|
|
114
|
+
const r = parsed.result;
|
|
115
|
+
if (typeof r === "string")
|
|
116
|
+
finalResult = r;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
const rlErr = createInterface({ input: child.stderr });
|
|
120
|
+
rlErr.on("line", (line) => {
|
|
121
|
+
stderrTail.push(line);
|
|
122
|
+
if (stderrTail.length > STDERR_TAIL_LINES)
|
|
123
|
+
stderrTail.shift();
|
|
124
|
+
process.stderr.write(`[docker] ${line}\n`);
|
|
125
|
+
});
|
|
126
|
+
child.on("error", (err) => {
|
|
127
|
+
closeSync(logFd);
|
|
128
|
+
reject(err);
|
|
129
|
+
});
|
|
130
|
+
child.on("close", (code) => {
|
|
131
|
+
closeSync(logFd);
|
|
132
|
+
if (code !== 0) {
|
|
133
|
+
reject(new Error(`docker run exited with ${code}\n${stderrTail.join("\n")}`));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
resolve(finalResult);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
function renderEvent(ev) {
|
|
141
|
+
switch (ev.type) {
|
|
142
|
+
case "system": {
|
|
143
|
+
const sub = ev.subtype;
|
|
144
|
+
if (sub === "init") {
|
|
145
|
+
const model = ev.model ?? "?";
|
|
146
|
+
const cwd = ev.cwd ?? "?";
|
|
147
|
+
process.stderr.write(`[init] model=${model} cwd=${cwd}\n`);
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
case "assistant": {
|
|
152
|
+
const content = ev.message?.content ?? [];
|
|
153
|
+
for (const block of content) {
|
|
154
|
+
if (block.type === "text" && typeof block.text === "string") {
|
|
155
|
+
process.stdout.write(block.text.replace(/\n/g, "\r\n") + "\r\n\n");
|
|
156
|
+
}
|
|
157
|
+
else if (block.type === "thinking") {
|
|
158
|
+
// Thinking blocks are usually long; show one marker line, not full text.
|
|
159
|
+
process.stderr.write(`[thinking]\n`);
|
|
160
|
+
}
|
|
161
|
+
else if (block.type === "tool_use") {
|
|
162
|
+
const name = block.name ?? "?";
|
|
163
|
+
const preview = previewInput(name, block.input);
|
|
164
|
+
process.stderr.write(`[tool] ${name} ${preview}\n`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
case "user": {
|
|
170
|
+
const content = ev.message?.content ?? [];
|
|
171
|
+
for (const block of content) {
|
|
172
|
+
if (block.type !== "tool_result")
|
|
173
|
+
continue;
|
|
174
|
+
const text = stringifyToolResult(block.content);
|
|
175
|
+
if (block.is_error) {
|
|
176
|
+
const snippet = text.slice(0, TOOL_RESULT_PREVIEW * 2);
|
|
177
|
+
process.stderr.write(`[tool:error] ${snippet}${text.length > snippet.length ? " …" : ""}\n`);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
const snippet = text.replace(/\s+/g, " ").trim().slice(0, TOOL_RESULT_PREVIEW);
|
|
181
|
+
process.stderr.write(`[tool:ok] ${snippet}${text.length > snippet.length ? " …" : ""}\n`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
case "result": {
|
|
187
|
+
const isError = ev.is_error;
|
|
188
|
+
if (isError)
|
|
189
|
+
process.stderr.write(`[result] is_error=true\n`);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
default:
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function previewInput(toolName, input) {
|
|
197
|
+
if (input == null || typeof input !== "object")
|
|
198
|
+
return "";
|
|
199
|
+
const obj = input;
|
|
200
|
+
// Pick the most informative field per tool.
|
|
201
|
+
const keyOrder = {
|
|
202
|
+
Bash: ["command"],
|
|
203
|
+
Edit: ["file_path"],
|
|
204
|
+
Write: ["file_path"],
|
|
205
|
+
Read: ["file_path"],
|
|
206
|
+
Glob: ["pattern", "path"],
|
|
207
|
+
Grep: ["pattern", "path"],
|
|
208
|
+
TodoWrite: [],
|
|
209
|
+
};
|
|
210
|
+
const keys = keyOrder[toolName] ?? Object.keys(obj).slice(0, 2);
|
|
211
|
+
const parts = [];
|
|
212
|
+
for (const k of keys) {
|
|
213
|
+
const v = obj[k];
|
|
214
|
+
if (v == null)
|
|
215
|
+
continue;
|
|
216
|
+
const s = typeof v === "string" ? v : JSON.stringify(v);
|
|
217
|
+
parts.push(`${k}=${truncate(s, TOOL_INPUT_PREVIEW)}`);
|
|
218
|
+
}
|
|
219
|
+
return parts.join(" ");
|
|
220
|
+
}
|
|
221
|
+
function stringifyToolResult(content) {
|
|
222
|
+
if (typeof content === "string")
|
|
223
|
+
return content;
|
|
224
|
+
if (Array.isArray(content)) {
|
|
225
|
+
return content
|
|
226
|
+
.map((c) => {
|
|
227
|
+
if (typeof c === "string")
|
|
228
|
+
return c;
|
|
229
|
+
if (c && typeof c === "object" && "text" in c)
|
|
230
|
+
return String(c.text ?? "");
|
|
231
|
+
return JSON.stringify(c);
|
|
232
|
+
})
|
|
233
|
+
.join("\n");
|
|
234
|
+
}
|
|
235
|
+
return JSON.stringify(content ?? "");
|
|
236
|
+
}
|
|
237
|
+
function truncate(s, max) {
|
|
238
|
+
if (s.length <= max)
|
|
239
|
+
return s;
|
|
240
|
+
return s.slice(0, max - 1) + "…";
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/stages.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type Stage = {
|
|
2
|
+
name: string;
|
|
3
|
+
template: string;
|
|
4
|
+
permissionMode?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const STAGES: {
|
|
7
|
+
implementer: {
|
|
8
|
+
name: string;
|
|
9
|
+
template: string;
|
|
10
|
+
permissionMode: string;
|
|
11
|
+
};
|
|
12
|
+
ghafkImplementer: {
|
|
13
|
+
name: string;
|
|
14
|
+
template: string;
|
|
15
|
+
permissionMode: string;
|
|
16
|
+
};
|
|
17
|
+
reviewer: {
|
|
18
|
+
name: string;
|
|
19
|
+
template: string;
|
|
20
|
+
permissionMode: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=stages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stages.d.ts","sourceRoot":"","sources":["../src/stages.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAMF,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;CAgBlB,CAAC"}
|
package/dist/stages.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// All stages run inside the ephemeral ralph-sandbox container (--rm,
|
|
2
|
+
// bind-mounted workspace only). Bash + edits must auto-approve for AFK to
|
|
3
|
+
// work non-interactively, so every stage uses bypassPermissions. Worst-case
|
|
4
|
+
// blast radius is the workspace tree, recoverable via git.
|
|
5
|
+
export const STAGES = {
|
|
6
|
+
implementer: {
|
|
7
|
+
name: "implementer",
|
|
8
|
+
template: "afk.md",
|
|
9
|
+
permissionMode: "bypassPermissions",
|
|
10
|
+
},
|
|
11
|
+
ghafkImplementer: {
|
|
12
|
+
name: "ghafk-implementer",
|
|
13
|
+
template: "ghafk.md",
|
|
14
|
+
permissionMode: "bypassPermissions",
|
|
15
|
+
},
|
|
16
|
+
reviewer: {
|
|
17
|
+
name: "reviewer",
|
|
18
|
+
template: "review.md",
|
|
19
|
+
permissionMode: "bypassPermissions",
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=stages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stages.js","sourceRoot":"","sources":["../src/stages.ts"],"names":[],"mappings":"AAMA,qEAAqE;AACrE,0EAA0E;AAC1E,4EAA4E;AAC5E,2DAA2D;AAC3D,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,aAAa;QACnB,QAAQ,EAAE,QAAQ;QAClB,cAAc,EAAE,mBAAmB;KACpB;IACjB,gBAAgB,EAAE;QAChB,IAAI,EAAE,mBAAmB;QACzB,QAAQ,EAAE,UAAU;QACpB,cAAc,EAAE,mBAAmB;KACpB;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,WAAW;QACrB,cAAc,EAAE,mBAAmB;KACpB;CAClB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,43 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@daonhan/ralph-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Claude Code AFK orchestration: iteration loop, docker runner, template renderer.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
|
-
".":
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
"./loop": {
|
|
14
|
-
"types": "./dist/loop.d.ts",
|
|
15
|
-
"import": "./dist/loop.js"
|
|
16
|
-
},
|
|
17
|
-
"./runner": {
|
|
18
|
-
"types": "./dist/runner.d.ts",
|
|
19
|
-
"import": "./dist/runner.js"
|
|
20
|
-
},
|
|
21
|
-
"./stages": {
|
|
22
|
-
"types": "./dist/stages.d.ts",
|
|
23
|
-
"import": "./dist/stages.js"
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
"files": [
|
|
27
|
-
"dist",
|
|
28
|
-
"templates",
|
|
29
|
-
"Dockerfile",
|
|
30
|
-
"README.md"
|
|
31
|
-
],
|
|
32
|
-
"engines": {
|
|
33
|
-
"node": ">=20"
|
|
34
|
-
},
|
|
35
|
-
"publishConfig": {
|
|
36
|
-
"access": "public"
|
|
9
|
+
".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" },
|
|
10
|
+
"./loop": { "types": "./dist/loop.d.ts", "import": "./dist/loop.js" },
|
|
11
|
+
"./runner": { "types": "./dist/runner.d.ts", "import": "./dist/runner.js" },
|
|
12
|
+
"./stages": { "types": "./dist/stages.d.ts", "import": "./dist/stages.js" }
|
|
37
13
|
},
|
|
14
|
+
"files": ["dist", "templates", "Dockerfile", "README.md"],
|
|
38
15
|
"scripts": {
|
|
39
16
|
"build": "tsc -p tsconfig.json",
|
|
40
17
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
41
|
-
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
42
|
-
|
|
43
|
-
}
|
|
18
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
19
|
+
"prepublishOnly": "pnpm run clean && pnpm run build"
|
|
20
|
+
},
|
|
21
|
+
"engines": { "node": ">=20" },
|
|
22
|
+
"publishConfig": { "access": "public" }
|
|
23
|
+
}
|
package/templates/ghprompt.md
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
# ISSUES
|
|
2
|
-
|
|
3
|
-
GitHub issues are provided at start of context. Parse it to get open issues with their bodies and comments.
|
|
4
|
-
|
|
5
|
-
You will work on the AFK issues only, not the HITL ones.
|
|
6
|
-
|
|
7
|
-
You've also been passed a file containing the last few commits. Review these to understand what work has been done.
|
|
8
|
-
|
|
9
|
-
If all AFK tasks are complete, output <promise>NO MORE TASKS</promise>.
|
|
10
|
-
|
|
11
|
-
# TASK SELECTION
|
|
12
|
-
|
|
13
|
-
Pick the next task. Prioritize tasks in this order:
|
|
14
|
-
|
|
15
|
-
1. Critical bugfixes
|
|
16
|
-
2. Development infrastructure
|
|
17
|
-
|
|
18
|
-
Getting development infrastructure like tests and types and dev scripts ready is an important precursor to building features.
|
|
19
|
-
|
|
20
|
-
3. Tracer bullets for new features
|
|
21
|
-
|
|
22
|
-
Tracer bullets are small slices of functionality that go through all layers of the system, allowing you to test and validate your approach early. This helps in identifying potential issues and ensures that the overall architecture is sound before investing significant time in development.
|
|
23
|
-
|
|
24
|
-
TL;DR - build a tiny, end-to-end slice of the feature first, then expand it out.
|
|
25
|
-
|
|
26
|
-
4. Polish and quick wins
|
|
27
|
-
5. Refactors
|
|
28
|
-
|
|
29
|
-
# EXPLORATION
|
|
30
|
-
|
|
31
|
-
Explore the repo.
|
|
32
|
-
|
|
33
|
-
# IMPLEMENTATION
|
|
34
|
-
|
|
35
|
-
Complete the task.
|
|
36
|
-
|
|
37
|
-
# FEEDBACK LOOPS
|
|
38
|
-
|
|
39
|
-
Before committing, run the feedback loops:
|
|
40
|
-
|
|
41
|
-
### Frontend / Node
|
|
42
|
-
|
|
43
|
-
- `pnpm run test` to run the tests
|
|
44
|
-
- `pnpm run typecheck` to run the type checker
|
|
45
|
-
|
|
46
|
-
### Backend / Dotnet
|
|
47
|
-
|
|
48
|
-
- `dotnet test` to run the tests
|
|
49
|
-
- `dotnet build` to type-check
|
|
50
|
-
|
|
51
|
-
# COMMIT
|
|
52
|
-
|
|
53
|
-
Make a single `git commit -am` with a short message:
|
|
54
|
-
|
|
55
|
-
- Subject line (≤72 chars): what changed
|
|
56
|
-
- Optional body (≤3 bullets): key decision, blocker for next iteration
|
|
57
|
-
- No file lists (git tracks them), no `Co-Authored-By`
|
|
58
|
-
|
|
59
|
-
# THE ISSUE
|
|
60
|
-
|
|
61
|
-
If the task is complete, close the original GitHub issue.
|
|
62
|
-
|
|
63
|
-
If the task is not complete, leave a comment on the GitHub issue with what was done.
|
|
64
|
-
|
|
65
|
-
# FINAL RULES
|
|
66
|
-
|
|
67
|
-
ONLY WORK ON A SINGLE TASK.
|
|
1
|
+
# ISSUES
|
|
2
|
+
|
|
3
|
+
GitHub issues are provided at start of context. Parse it to get open issues with their bodies and comments.
|
|
4
|
+
|
|
5
|
+
You will work on the AFK issues only, not the HITL ones.
|
|
6
|
+
|
|
7
|
+
You've also been passed a file containing the last few commits. Review these to understand what work has been done.
|
|
8
|
+
|
|
9
|
+
If all AFK tasks are complete, output <promise>NO MORE TASKS</promise>.
|
|
10
|
+
|
|
11
|
+
# TASK SELECTION
|
|
12
|
+
|
|
13
|
+
Pick the next task. Prioritize tasks in this order:
|
|
14
|
+
|
|
15
|
+
1. Critical bugfixes
|
|
16
|
+
2. Development infrastructure
|
|
17
|
+
|
|
18
|
+
Getting development infrastructure like tests and types and dev scripts ready is an important precursor to building features.
|
|
19
|
+
|
|
20
|
+
3. Tracer bullets for new features
|
|
21
|
+
|
|
22
|
+
Tracer bullets are small slices of functionality that go through all layers of the system, allowing you to test and validate your approach early. This helps in identifying potential issues and ensures that the overall architecture is sound before investing significant time in development.
|
|
23
|
+
|
|
24
|
+
TL;DR - build a tiny, end-to-end slice of the feature first, then expand it out.
|
|
25
|
+
|
|
26
|
+
4. Polish and quick wins
|
|
27
|
+
5. Refactors
|
|
28
|
+
|
|
29
|
+
# EXPLORATION
|
|
30
|
+
|
|
31
|
+
Explore the repo.
|
|
32
|
+
|
|
33
|
+
# IMPLEMENTATION
|
|
34
|
+
|
|
35
|
+
Complete the task.
|
|
36
|
+
|
|
37
|
+
# FEEDBACK LOOPS
|
|
38
|
+
|
|
39
|
+
Before committing, run the feedback loops:
|
|
40
|
+
|
|
41
|
+
### Frontend / Node
|
|
42
|
+
|
|
43
|
+
- `pnpm run test` to run the tests
|
|
44
|
+
- `pnpm run typecheck` to run the type checker
|
|
45
|
+
|
|
46
|
+
### Backend / Dotnet
|
|
47
|
+
|
|
48
|
+
- `dotnet test` to run the tests
|
|
49
|
+
- `dotnet build` to type-check
|
|
50
|
+
|
|
51
|
+
# COMMIT
|
|
52
|
+
|
|
53
|
+
Make a single `git commit -am` with a short message:
|
|
54
|
+
|
|
55
|
+
- Subject line (≤72 chars): what changed
|
|
56
|
+
- Optional body (≤3 bullets): key decision, blocker for next iteration
|
|
57
|
+
- No file lists (git tracks them), no `Co-Authored-By`
|
|
58
|
+
|
|
59
|
+
# THE ISSUE
|
|
60
|
+
|
|
61
|
+
If the task is complete, close the original GitHub issue.
|
|
62
|
+
|
|
63
|
+
If the task is not complete, leave a comment on the GitHub issue with what was done.
|
|
64
|
+
|
|
65
|
+
# FINAL RULES
|
|
66
|
+
|
|
67
|
+
ONLY WORK ON A SINGLE TASK.
|
package/templates/prompt.md
CHANGED
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
# ISSUES
|
|
2
|
-
|
|
3
|
-
GitHub issues are provided at start of context. Parse it to get open issues with their bodies and comments.
|
|
4
|
-
|
|
5
|
-
You will work on the AFK issues only, not the HITL ones.
|
|
6
|
-
|
|
7
|
-
You've also been passed a file containing the last few commits. Review these to understand what work has been done.
|
|
8
|
-
|
|
9
|
-
If all AFK tasks are complete, output <promise>NO MORE TASKS</promise>.
|
|
10
|
-
|
|
11
|
-
# TASK SELECTION
|
|
12
|
-
|
|
13
|
-
Pick the next task. Prioritize tasks in this order:
|
|
14
|
-
|
|
15
|
-
1. Critical bugfixes
|
|
16
|
-
2. Development infrastructure
|
|
17
|
-
|
|
18
|
-
Getting development infrastructure like tests and types and dev scripts ready is an important precursor to building features.
|
|
19
|
-
|
|
20
|
-
3. Tracer bullets for new features
|
|
21
|
-
|
|
22
|
-
Tracer bullets are small slices of functionality that go through all layers of the system, allowing you to test and validate your approach early. This helps in identifying potential issues and ensures that the overall architecture is sound before investing significant time in development.
|
|
23
|
-
|
|
24
|
-
TL;DR - build a tiny, end-to-end slice of the feature first, then expand it out.
|
|
25
|
-
|
|
26
|
-
4. Polish and quick wins
|
|
27
|
-
5. Refactors
|
|
28
|
-
|
|
29
|
-
# EXPLORATION
|
|
30
|
-
|
|
31
|
-
Explore the repo.
|
|
32
|
-
|
|
33
|
-
# IMPLEMENTATION
|
|
34
|
-
|
|
35
|
-
Complete the task.
|
|
36
|
-
|
|
37
|
-
# FEEDBACK LOOPS
|
|
38
|
-
|
|
39
|
-
Before committing, run the feedback loops:
|
|
40
|
-
|
|
41
|
-
### Frontend / Node
|
|
42
|
-
|
|
43
|
-
- `pnpm run test` to run the tests
|
|
44
|
-
- `pnpm run typecheck` to run the type checker
|
|
45
|
-
|
|
46
|
-
### Backend / Dotnet
|
|
47
|
-
|
|
48
|
-
- `dotnet test` to run the tests
|
|
49
|
-
- `dotnet build` to type-check
|
|
50
|
-
|
|
51
|
-
**If `dotnet test` or `dotnet build` fails with MSB3248** ("Could not resolve assembly reference" / "file is corrupt") — this is a known virtiofs/9p I/O quirk when the repo is mounted from the Windows host. It is NOT a code defect. Do not defer verification. Re-run with build outputs redirected to `/tmp` and parallelism disabled:
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
dotnet test <path-to-test-csproj> \
|
|
55
|
-
-m:1 \
|
|
56
|
-
/p:UseSharedCompilation=false \
|
|
57
|
-
/p:BuildInParallel=false \
|
|
58
|
-
/p:BaseIntermediateOutputPath=/tmp/ralph-obj/$(basename <path-to-test-csproj> .csproj)/ \
|
|
59
|
-
/p:BaseOutputPath=/tmp/ralph-bin/$(basename <path-to-test-csproj> .csproj)/
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Only if that second attempt also fails may you defer and record the blocker in the commit message.
|
|
63
|
-
|
|
64
|
-
# COMMIT
|
|
65
|
-
|
|
66
|
-
Make a single `git commit -am` with a short message:
|
|
67
|
-
|
|
68
|
-
- Subject line (≤72 chars): what changed
|
|
69
|
-
- Optional body (≤3 bullets): key decision, blocker for next iteration
|
|
70
|
-
- No file lists (git tracks them), no `Co-Authored-By`
|
|
71
|
-
|
|
72
|
-
# THE ISSUE
|
|
73
|
-
|
|
74
|
-
If the task is complete, close the original GitHub issue.
|
|
75
|
-
|
|
76
|
-
If the task is not complete, leave a comment on the GitHub issue with what was done.
|
|
77
|
-
|
|
78
|
-
# FINAL RULES
|
|
79
|
-
|
|
80
|
-
ONLY WORK ON A SINGLE TASK.
|
|
1
|
+
# ISSUES
|
|
2
|
+
|
|
3
|
+
GitHub issues are provided at start of context. Parse it to get open issues with their bodies and comments.
|
|
4
|
+
|
|
5
|
+
You will work on the AFK issues only, not the HITL ones.
|
|
6
|
+
|
|
7
|
+
You've also been passed a file containing the last few commits. Review these to understand what work has been done.
|
|
8
|
+
|
|
9
|
+
If all AFK tasks are complete, output <promise>NO MORE TASKS</promise>.
|
|
10
|
+
|
|
11
|
+
# TASK SELECTION
|
|
12
|
+
|
|
13
|
+
Pick the next task. Prioritize tasks in this order:
|
|
14
|
+
|
|
15
|
+
1. Critical bugfixes
|
|
16
|
+
2. Development infrastructure
|
|
17
|
+
|
|
18
|
+
Getting development infrastructure like tests and types and dev scripts ready is an important precursor to building features.
|
|
19
|
+
|
|
20
|
+
3. Tracer bullets for new features
|
|
21
|
+
|
|
22
|
+
Tracer bullets are small slices of functionality that go through all layers of the system, allowing you to test and validate your approach early. This helps in identifying potential issues and ensures that the overall architecture is sound before investing significant time in development.
|
|
23
|
+
|
|
24
|
+
TL;DR - build a tiny, end-to-end slice of the feature first, then expand it out.
|
|
25
|
+
|
|
26
|
+
4. Polish and quick wins
|
|
27
|
+
5. Refactors
|
|
28
|
+
|
|
29
|
+
# EXPLORATION
|
|
30
|
+
|
|
31
|
+
Explore the repo.
|
|
32
|
+
|
|
33
|
+
# IMPLEMENTATION
|
|
34
|
+
|
|
35
|
+
Complete the task.
|
|
36
|
+
|
|
37
|
+
# FEEDBACK LOOPS
|
|
38
|
+
|
|
39
|
+
Before committing, run the feedback loops:
|
|
40
|
+
|
|
41
|
+
### Frontend / Node
|
|
42
|
+
|
|
43
|
+
- `pnpm run test` to run the tests
|
|
44
|
+
- `pnpm run typecheck` to run the type checker
|
|
45
|
+
|
|
46
|
+
### Backend / Dotnet
|
|
47
|
+
|
|
48
|
+
- `dotnet test` to run the tests
|
|
49
|
+
- `dotnet build` to type-check
|
|
50
|
+
|
|
51
|
+
**If `dotnet test` or `dotnet build` fails with MSB3248** ("Could not resolve assembly reference" / "file is corrupt") — this is a known virtiofs/9p I/O quirk when the repo is mounted from the Windows host. It is NOT a code defect. Do not defer verification. Re-run with build outputs redirected to `/tmp` and parallelism disabled:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
dotnet test <path-to-test-csproj> \
|
|
55
|
+
-m:1 \
|
|
56
|
+
/p:UseSharedCompilation=false \
|
|
57
|
+
/p:BuildInParallel=false \
|
|
58
|
+
/p:BaseIntermediateOutputPath=/tmp/ralph-obj/$(basename <path-to-test-csproj> .csproj)/ \
|
|
59
|
+
/p:BaseOutputPath=/tmp/ralph-bin/$(basename <path-to-test-csproj> .csproj)/
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Only if that second attempt also fails may you defer and record the blocker in the commit message.
|
|
63
|
+
|
|
64
|
+
# COMMIT
|
|
65
|
+
|
|
66
|
+
Make a single `git commit -am` with a short message:
|
|
67
|
+
|
|
68
|
+
- Subject line (≤72 chars): what changed
|
|
69
|
+
- Optional body (≤3 bullets): key decision, blocker for next iteration
|
|
70
|
+
- No file lists (git tracks them), no `Co-Authored-By`
|
|
71
|
+
|
|
72
|
+
# THE ISSUE
|
|
73
|
+
|
|
74
|
+
If the task is complete, close the original GitHub issue.
|
|
75
|
+
|
|
76
|
+
If the task is not complete, leave a comment on the GitHub issue with what was done.
|
|
77
|
+
|
|
78
|
+
# FINAL RULES
|
|
79
|
+
|
|
80
|
+
ONLY WORK ON A SINGLE TASK.
|