@herbcaudill/ralph 0.6.2 → 0.6.4

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 (60) hide show
  1. package/README.md +136 -32
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +6 -2
  4. package/dist/cli.js.map +1 -1
  5. package/dist/components/App.d.ts +2 -1
  6. package/dist/components/App.d.ts.map +1 -1
  7. package/dist/components/App.js +2 -2
  8. package/dist/components/App.js.map +1 -1
  9. package/dist/components/EventDisplay.replay.test.js +2 -2
  10. package/dist/components/EventDisplay.test.js +28 -28
  11. package/dist/components/EventDisplay.test.js.map +1 -1
  12. package/dist/components/InitRalph.d.ts.map +1 -1
  13. package/dist/components/InitRalph.js +16 -1
  14. package/dist/components/InitRalph.js.map +1 -1
  15. package/dist/components/IterationRunner.d.ts +9 -1
  16. package/dist/components/IterationRunner.d.ts.map +1 -1
  17. package/dist/components/IterationRunner.js +179 -92
  18. package/dist/components/IterationRunner.js.map +1 -1
  19. package/dist/components/IterationRunner.test.js +55 -27
  20. package/dist/components/IterationRunner.test.js.map +1 -1
  21. package/dist/components/ProgressBar.d.ts +16 -0
  22. package/dist/components/ProgressBar.d.ts.map +1 -0
  23. package/dist/components/ProgressBar.js +28 -0
  24. package/dist/components/ProgressBar.js.map +1 -0
  25. package/dist/components/ProgressBar.test.d.ts +2 -0
  26. package/dist/components/ProgressBar.test.d.ts.map +1 -0
  27. package/dist/components/ProgressBar.test.js +42 -0
  28. package/dist/components/ProgressBar.test.js.map +1 -0
  29. package/dist/components/eventToBlocks.d.ts +4 -0
  30. package/dist/components/eventToBlocks.d.ts.map +1 -1
  31. package/dist/components/eventToBlocks.js +18 -0
  32. package/dist/components/eventToBlocks.js.map +1 -1
  33. package/dist/components/eventToBlocks.test.js +54 -0
  34. package/dist/components/eventToBlocks.test.js.map +1 -1
  35. package/dist/lib/MessageQueue.d.ts +18 -0
  36. package/dist/lib/MessageQueue.d.ts.map +1 -0
  37. package/dist/lib/MessageQueue.js +56 -0
  38. package/dist/lib/MessageQueue.js.map +1 -0
  39. package/dist/lib/MessageQueue.test.d.ts +2 -0
  40. package/dist/lib/MessageQueue.test.d.ts.map +1 -0
  41. package/dist/lib/MessageQueue.test.js +78 -0
  42. package/dist/lib/MessageQueue.test.js.map +1 -0
  43. package/dist/lib/beadsClient.d.ts +52 -0
  44. package/dist/lib/beadsClient.d.ts.map +1 -0
  45. package/dist/lib/beadsClient.js +171 -0
  46. package/dist/lib/beadsClient.js.map +1 -0
  47. package/dist/lib/formatContentBlock.d.ts +1 -1
  48. package/dist/lib/formatContentBlock.d.ts.map +1 -1
  49. package/dist/lib/formatContentBlock.js +11 -2
  50. package/dist/lib/formatContentBlock.js.map +1 -1
  51. package/dist/lib/getProgress.d.ts +18 -0
  52. package/dist/lib/getProgress.d.ts.map +1 -0
  53. package/dist/lib/getProgress.js +85 -0
  54. package/dist/lib/getProgress.js.map +1 -0
  55. package/dist/lib/getProgress.test.d.ts +2 -0
  56. package/dist/lib/getProgress.test.d.ts.map +1 -0
  57. package/dist/lib/getProgress.test.js +183 -0
  58. package/dist/lib/getProgress.test.js.map +1 -0
  59. package/package.json +1 -1
  60. package/templates/prompt-beads.md +33 -13
@@ -0,0 +1,171 @@
1
+ import { createConnection } from "net";
2
+ import { join } from "path";
3
+ import { existsSync } from "fs";
4
+ const SOCKET_PATH = join(process.cwd(), ".beads", "bd.sock");
5
+ /**
6
+ * Simple RPC client for beads daemon.
7
+ * Connects to .beads/bd.sock and sends JSON-over-newline requests.
8
+ */
9
+ export class BeadsClient {
10
+ socket = null;
11
+ connected = false;
12
+ /**
13
+ * Check if the beads daemon socket exists.
14
+ */
15
+ static socketExists() {
16
+ return existsSync(SOCKET_PATH);
17
+ }
18
+ /**
19
+ * Connect to the beads daemon.
20
+ */
21
+ async connect() {
22
+ if (!BeadsClient.socketExists()) {
23
+ return false;
24
+ }
25
+ return new Promise(resolve => {
26
+ this.socket = createConnection(SOCKET_PATH);
27
+ const timeout = setTimeout(() => {
28
+ this.socket?.destroy();
29
+ this.socket = null;
30
+ resolve(false);
31
+ }, 2000);
32
+ this.socket.on("connect", () => {
33
+ clearTimeout(timeout);
34
+ this.connected = true;
35
+ resolve(true);
36
+ });
37
+ this.socket.on("error", () => {
38
+ clearTimeout(timeout);
39
+ this.socket = null;
40
+ resolve(false);
41
+ });
42
+ });
43
+ }
44
+ /**
45
+ * Send an RPC request and wait for response.
46
+ */
47
+ async execute(operation, args = {}) {
48
+ if (!this.socket || !this.connected) {
49
+ return null;
50
+ }
51
+ return new Promise(resolve => {
52
+ const request = { operation, args };
53
+ const requestLine = JSON.stringify(request) + "\n";
54
+ let responseData = "";
55
+ const onData = (chunk) => {
56
+ responseData += chunk.toString();
57
+ if (responseData.includes("\n")) {
58
+ cleanup();
59
+ try {
60
+ const response = JSON.parse(responseData.trim());
61
+ if (response.success && response.data) {
62
+ resolve(response.data);
63
+ }
64
+ else {
65
+ resolve(null);
66
+ }
67
+ }
68
+ catch {
69
+ resolve(null);
70
+ }
71
+ }
72
+ };
73
+ const onError = () => {
74
+ cleanup();
75
+ resolve(null);
76
+ };
77
+ const timeout = setTimeout(() => {
78
+ cleanup();
79
+ resolve(null);
80
+ }, 5000);
81
+ const cleanup = () => {
82
+ clearTimeout(timeout);
83
+ this.socket?.off("data", onData);
84
+ this.socket?.off("error", onError);
85
+ };
86
+ this.socket.on("data", onData);
87
+ this.socket.on("error", onError);
88
+ this.socket.write(requestLine);
89
+ });
90
+ }
91
+ /**
92
+ * Get mutations since a given timestamp.
93
+ * @param since Unix timestamp in milliseconds (0 for all recent)
94
+ */
95
+ async getMutations(since = 0) {
96
+ const result = await this.execute("get_mutations", { since });
97
+ return result ?? [];
98
+ }
99
+ /**
100
+ * Get ready issues (no blockers).
101
+ */
102
+ async getReady() {
103
+ const result = await this.execute("ready", {});
104
+ return result ?? [];
105
+ }
106
+ /**
107
+ * Close the connection.
108
+ */
109
+ close() {
110
+ if (this.socket) {
111
+ this.socket.destroy();
112
+ this.socket = null;
113
+ this.connected = false;
114
+ }
115
+ }
116
+ }
117
+ /**
118
+ * Poll for new issue creation events.
119
+ * Returns a cleanup function.
120
+ */
121
+ export function watchForNewIssues(onNewIssue, interval = 5000) {
122
+ let lastTimestamp = Date.now();
123
+ let client = null;
124
+ let timeoutId = null;
125
+ let stopped = false;
126
+ const poll = async () => {
127
+ if (stopped)
128
+ return;
129
+ if (!client) {
130
+ client = new BeadsClient();
131
+ const connected = await client.connect();
132
+ if (!connected) {
133
+ // Retry connection later
134
+ timeoutId = setTimeout(poll, interval);
135
+ return;
136
+ }
137
+ }
138
+ try {
139
+ const mutations = await client.getMutations(lastTimestamp);
140
+ for (const mutation of mutations) {
141
+ if (mutation.Type === "create") {
142
+ onNewIssue(mutation);
143
+ }
144
+ // Update timestamp to avoid re-processing
145
+ const mutationTime = new Date(mutation.Timestamp).getTime();
146
+ if (mutationTime > lastTimestamp) {
147
+ lastTimestamp = mutationTime;
148
+ }
149
+ }
150
+ }
151
+ catch {
152
+ // Connection may have been lost, reset client
153
+ client?.close();
154
+ client = null;
155
+ }
156
+ if (!stopped) {
157
+ timeoutId = setTimeout(poll, interval);
158
+ }
159
+ };
160
+ // Start polling
161
+ poll();
162
+ // Return cleanup function
163
+ return () => {
164
+ stopped = true;
165
+ if (timeoutId) {
166
+ clearTimeout(timeoutId);
167
+ }
168
+ client?.close();
169
+ };
170
+ }
171
+ //# sourceMappingURL=beadsClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"beadsClient.js","sourceRoot":"","sources":["../../src/lib/beadsClient.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ import type { ContentBlock } from "../components/eventToBlocks.js";
4
4
  */
5
5
  export declare const formatContentBlock: (block: ContentBlock) => string[];
6
6
  /**
7
- * Format an iteration header
7
+ * Format a round header
8
8
  */
9
9
  export declare const formatIterationHeader: (iteration: number) => string;
10
10
  //# sourceMappingURL=formatContentBlock.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"formatContentBlock.d.ts","sourceRoot":"","sources":["../../src/lib/formatContentBlock.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AA8ClE;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,YAAY,KAAG,MAAM,EAQ9D,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAAI,WAAW,MAAM,KAAG,MAEzD,CAAA"}
1
+ {"version":3,"file":"formatContentBlock.d.ts","sourceRoot":"","sources":["../../src/lib/formatContentBlock.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAqDlE;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,YAAY,KAAG,MAAM,EAY9D,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAAI,WAAW,MAAM,KAAG,MAEzD,CAAA"}
@@ -40,6 +40,12 @@ const formatToolUse = (name, arg) => {
40
40
  }
41
41
  return ` ${formattedName}`;
42
42
  };
43
+ /**
44
+ * Format a user message
45
+ */
46
+ const formatUserMessage = (content) => {
47
+ return chalk.green(`📨 You: ${content}`);
48
+ };
43
49
  /**
44
50
  * Convert a content block to formatted string lines
45
51
  */
@@ -49,12 +55,15 @@ export const formatContentBlock = (block) => {
49
55
  // Split into lines, preserving empty lines for paragraph breaks
50
56
  return formatted.split("\n");
51
57
  }
58
+ if (block.type === "user") {
59
+ return [formatUserMessage(block.content)];
60
+ }
52
61
  return [formatToolUse(block.name, block.arg)];
53
62
  };
54
63
  /**
55
- * Format an iteration header
64
+ * Format a round header
56
65
  */
57
66
  export const formatIterationHeader = (iteration) => {
58
- return chalk.cyan.bold(`─── Iteration ${iteration} ───`);
67
+ return chalk.cyan.bold(`─── Round ${iteration} ───`);
59
68
  };
60
69
  //# sourceMappingURL=formatContentBlock.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"formatContentBlock.js","sourceRoot":"","sources":["../../src/lib/formatContentBlock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB;;GAEG;AACH,MAAM,UAAU,GAAG,CAAC,OAAe,EAAU,EAAE;IAC7C,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,IAAI,CAAC,GAAG,CAAC,CAAA;IACT,IAAI,MAAM,GAAG,KAAK,CAAA;IAClB,IAAI,MAAM,GAAG,KAAK,CAAA;IAElB,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QAC1B,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACjD,MAAM,GAAG,CAAC,MAAM,CAAA;YAChB,CAAC,IAAI,CAAC,CAAA;QACR,CAAC;aAAM,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YAC9B,MAAM,GAAG,CAAC,MAAM,CAAA;YAChB,CAAC,EAAE,CAAA;QACL,CAAC;aAAM,CAAC;YACN,IAAI,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;YAErB,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YAC3B,CAAC;iBAAM,IAAI,MAAM,EAAE,CAAC;gBAClB,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACzB,CAAC;YAED,MAAM,IAAI,IAAI,CAAA;YACd,CAAC,EAAE,CAAA;QACL,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,GAAY,EAAU,EAAE;IAC3D,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACtC,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,KAAK,aAAa,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAA;IAC/C,CAAC;IACD,OAAO,KAAK,aAAa,EAAE,CAAA;AAC7B,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAmB,EAAY,EAAE;IAClE,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC3C,gEAAgE;QAChE,OAAO,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC9B,CAAC;IAED,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;AAC/C,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,SAAiB,EAAU,EAAE;IACjE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,SAAS,MAAM,CAAC,CAAA;AAC1D,CAAC,CAAA"}
1
+ {"version":3,"file":"formatContentBlock.js","sourceRoot":"","sources":["../../src/lib/formatContentBlock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB;;GAEG;AACH,MAAM,UAAU,GAAG,CAAC,OAAe,EAAU,EAAE;IAC7C,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,IAAI,CAAC,GAAG,CAAC,CAAA;IACT,IAAI,MAAM,GAAG,KAAK,CAAA;IAClB,IAAI,MAAM,GAAG,KAAK,CAAA;IAElB,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QAC1B,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACjD,MAAM,GAAG,CAAC,MAAM,CAAA;YAChB,CAAC,IAAI,CAAC,CAAA;QACR,CAAC;aAAM,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YAC9B,MAAM,GAAG,CAAC,MAAM,CAAA;YAChB,CAAC,EAAE,CAAA;QACL,CAAC;aAAM,CAAC;YACN,IAAI,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;YAErB,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YAC3B,CAAC;iBAAM,IAAI,MAAM,EAAE,CAAC;gBAClB,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACzB,CAAC;YAED,MAAM,IAAI,IAAI,CAAA;YACd,CAAC,EAAE,CAAA;QACL,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,GAAY,EAAU,EAAE;IAC3D,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACtC,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,KAAK,aAAa,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAA;IAC/C,CAAC;IACD,OAAO,KAAK,aAAa,EAAE,CAAA;AAC7B,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,iBAAiB,GAAG,CAAC,OAAe,EAAU,EAAE;IACpD,OAAO,KAAK,CAAC,KAAK,CAAC,WAAW,OAAO,EAAE,CAAC,CAAA;AAC1C,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAmB,EAAY,EAAE;IAClE,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC3C,gEAAgE;QAChE,OAAO,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC9B,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC1B,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;IAC3C,CAAC;IAED,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;AAC/C,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,SAAiB,EAAU,EAAE;IACjE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,SAAS,MAAM,CAAC,CAAA;AACtD,CAAC,CAAA"}
@@ -0,0 +1,18 @@
1
+ export type ProgressData = {
2
+ type: "beads" | "todo" | "none";
3
+ remaining: number;
4
+ total: number;
5
+ };
6
+ /**
7
+ * Get progress data from the workspace.
8
+ *
9
+ * For beads workspaces: remaining = open issues, total = provided initialOpen or calculated
10
+ * For todo.md workspaces: remaining = unchecked items, total = all items
11
+ */
12
+ export declare const getProgress: (initialOpen?: number) => ProgressData;
13
+ /**
14
+ * Get the initial open issue count for beads workspaces.
15
+ * Call this once at startup to capture the baseline.
16
+ */
17
+ export declare const getInitialBeadsCount: () => number | undefined;
18
+ //# sourceMappingURL=getProgress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getProgress.d.ts","sourceRoot":"","sources":["../../src/lib/getProgress.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAMD;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,cAAc,MAAM,KAAG,YAYlD,CAAA;AAoDD;;;GAGG;AACH,eAAO,MAAM,oBAAoB,QAAO,MAAM,GAAG,SAwBhD,CAAA"}
@@ -0,0 +1,85 @@
1
+ import { existsSync, readFileSync } from "fs";
2
+ import { join } from "path";
3
+ import { execSync } from "child_process";
4
+ const beadsDir = join(process.cwd(), ".beads");
5
+ const ralphDir = join(process.cwd(), ".ralph");
6
+ const todoFile = join(ralphDir, "todo.md");
7
+ /**
8
+ * Get progress data from the workspace.
9
+ *
10
+ * For beads workspaces: remaining = open issues, total = provided initialOpen or calculated
11
+ * For todo.md workspaces: remaining = unchecked items, total = all items
12
+ */
13
+ export const getProgress = (initialOpen) => {
14
+ // Check for beads workspace first
15
+ if (existsSync(beadsDir)) {
16
+ return getBeadsProgress(initialOpen);
17
+ }
18
+ // Check for todo.md
19
+ if (existsSync(todoFile)) {
20
+ return getTodoProgress();
21
+ }
22
+ return { type: "none", remaining: 0, total: 0 };
23
+ };
24
+ const getBeadsProgress = (initialOpen) => {
25
+ try {
26
+ // Get open + in_progress issues count using bd count
27
+ const openCount = parseInt(execSync("bd count --status=open", {
28
+ encoding: "utf-8",
29
+ stdio: ["pipe", "pipe", "pipe"],
30
+ }).trim(), 10);
31
+ const inProgressCount = parseInt(execSync("bd count --status=in_progress", {
32
+ encoding: "utf-8",
33
+ stdio: ["pipe", "pipe", "pipe"],
34
+ }).trim(), 10);
35
+ const remaining = openCount + inProgressCount;
36
+ // Total is the initial count (baseline) when provided, otherwise current remaining
37
+ // If more issues are opened during the run (remaining > initialOpen), use the larger value
38
+ const total = initialOpen !== undefined ? Math.max(initialOpen, remaining) : remaining;
39
+ return { type: "beads", remaining, total };
40
+ }
41
+ catch {
42
+ // If bd command fails, return no progress
43
+ return { type: "none", remaining: 0, total: 0 };
44
+ }
45
+ };
46
+ const getTodoProgress = () => {
47
+ try {
48
+ const content = readFileSync(todoFile, "utf-8");
49
+ // Count unchecked items: - [ ]
50
+ const uncheckedMatches = content.match(/- \[ \]/g);
51
+ const unchecked = uncheckedMatches ? uncheckedMatches.length : 0;
52
+ // Count checked items: - [x] or - [X]
53
+ const checkedMatches = content.match(/- \[[xX]\]/g);
54
+ const checked = checkedMatches ? checkedMatches.length : 0;
55
+ const total = unchecked + checked;
56
+ return { type: "todo", remaining: unchecked, total };
57
+ }
58
+ catch {
59
+ return { type: "none", remaining: 0, total: 0 };
60
+ }
61
+ };
62
+ /**
63
+ * Get the initial open issue count for beads workspaces.
64
+ * Call this once at startup to capture the baseline.
65
+ */
66
+ export const getInitialBeadsCount = () => {
67
+ if (!existsSync(beadsDir)) {
68
+ return undefined;
69
+ }
70
+ try {
71
+ const openCount = parseInt(execSync("bd count --status=open", {
72
+ encoding: "utf-8",
73
+ stdio: ["pipe", "pipe", "pipe"],
74
+ }).trim(), 10);
75
+ const inProgressCount = parseInt(execSync("bd count --status=in_progress", {
76
+ encoding: "utf-8",
77
+ stdio: ["pipe", "pipe", "pipe"],
78
+ }).trim(), 10);
79
+ return openCount + inProgressCount;
80
+ }
81
+ catch {
82
+ return undefined;
83
+ }
84
+ };
85
+ //# sourceMappingURL=getProgress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getProgress.js","sourceRoot":"","sources":["../../src/lib/getProgress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=getProgress.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getProgress.test.d.ts","sourceRoot":"","sources":["../../src/lib/getProgress.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,183 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { getProgress, getInitialBeadsCount } from "./getProgress.js";
3
+ import * as fs from "fs";
4
+ import * as child_process from "child_process";
5
+ vi.mock("fs");
6
+ vi.mock("child_process");
7
+ const mockExistsSync = vi.mocked(fs.existsSync);
8
+ const mockReadFileSync = vi.mocked(fs.readFileSync);
9
+ const mockExecSync = vi.mocked(child_process.execSync);
10
+ describe("getProgress", () => {
11
+ beforeEach(() => {
12
+ vi.clearAllMocks();
13
+ });
14
+ afterEach(() => {
15
+ vi.restoreAllMocks();
16
+ });
17
+ describe("with beads workspace", () => {
18
+ it("returns beads progress when .beads directory exists", () => {
19
+ mockExistsSync.mockImplementation(path => {
20
+ if (typeof path === "string" && path.endsWith(".beads"))
21
+ return true;
22
+ return false;
23
+ });
24
+ // First call returns open count, second returns in_progress count
25
+ mockExecSync.mockReturnValueOnce("2").mockReturnValueOnce("1");
26
+ const result = getProgress(5);
27
+ expect(result.type).toBe("beads");
28
+ expect(result.remaining).toBe(3);
29
+ expect(result.total).toBe(5);
30
+ });
31
+ it("handles empty beads list", () => {
32
+ mockExistsSync.mockImplementation(path => {
33
+ if (typeof path === "string" && path.endsWith(".beads"))
34
+ return true;
35
+ return false;
36
+ });
37
+ mockExecSync.mockReturnValueOnce("0").mockReturnValueOnce("0");
38
+ const result = getProgress(5);
39
+ expect(result.type).toBe("beads");
40
+ expect(result.remaining).toBe(0);
41
+ expect(result.total).toBe(5);
42
+ });
43
+ it("uses remaining as total when no initial provided", () => {
44
+ mockExistsSync.mockImplementation(path => {
45
+ if (typeof path === "string" && path.endsWith(".beads"))
46
+ return true;
47
+ return false;
48
+ });
49
+ mockExecSync.mockReturnValueOnce("2").mockReturnValueOnce("0");
50
+ const result = getProgress();
51
+ expect(result.type).toBe("beads");
52
+ expect(result.remaining).toBe(2);
53
+ expect(result.total).toBe(2);
54
+ });
55
+ it("returns none when bd command fails", () => {
56
+ mockExistsSync.mockImplementation(path => {
57
+ if (typeof path === "string" && path.endsWith(".beads"))
58
+ return true;
59
+ return false;
60
+ });
61
+ mockExecSync.mockImplementation(() => {
62
+ throw new Error("Command failed");
63
+ });
64
+ const result = getProgress();
65
+ expect(result.type).toBe("none");
66
+ });
67
+ });
68
+ describe("with todo.md workspace", () => {
69
+ it("returns todo progress when todo.md exists", () => {
70
+ mockExistsSync.mockImplementation(path => {
71
+ if (typeof path === "string" && path.endsWith(".beads"))
72
+ return false;
73
+ if (typeof path === "string" && path.endsWith("todo.md"))
74
+ return true;
75
+ return false;
76
+ });
77
+ mockReadFileSync.mockReturnValue(`
78
+ ### To do
79
+ - [ ] Task 1
80
+ - [ ] Task 2
81
+ - [x] Task 3
82
+ - [X] Task 4
83
+
84
+ ### Done
85
+ `);
86
+ const result = getProgress();
87
+ expect(result.type).toBe("todo");
88
+ expect(result.remaining).toBe(2);
89
+ expect(result.total).toBe(4);
90
+ });
91
+ it("handles all unchecked items", () => {
92
+ mockExistsSync.mockImplementation(path => {
93
+ if (typeof path === "string" && path.endsWith(".beads"))
94
+ return false;
95
+ if (typeof path === "string" && path.endsWith("todo.md"))
96
+ return true;
97
+ return false;
98
+ });
99
+ mockReadFileSync.mockReturnValue(`
100
+ - [ ] Task 1
101
+ - [ ] Task 2
102
+ - [ ] Task 3
103
+ `);
104
+ const result = getProgress();
105
+ expect(result.type).toBe("todo");
106
+ expect(result.remaining).toBe(3);
107
+ expect(result.total).toBe(3);
108
+ });
109
+ it("handles all checked items", () => {
110
+ mockExistsSync.mockImplementation(path => {
111
+ if (typeof path === "string" && path.endsWith(".beads"))
112
+ return false;
113
+ if (typeof path === "string" && path.endsWith("todo.md"))
114
+ return true;
115
+ return false;
116
+ });
117
+ mockReadFileSync.mockReturnValue(`
118
+ - [x] Task 1
119
+ - [X] Task 2
120
+ `);
121
+ const result = getProgress();
122
+ expect(result.type).toBe("todo");
123
+ expect(result.remaining).toBe(0);
124
+ expect(result.total).toBe(2);
125
+ });
126
+ it("handles empty todo file", () => {
127
+ mockExistsSync.mockImplementation(path => {
128
+ if (typeof path === "string" && path.endsWith(".beads"))
129
+ return false;
130
+ if (typeof path === "string" && path.endsWith("todo.md"))
131
+ return true;
132
+ return false;
133
+ });
134
+ mockReadFileSync.mockReturnValue("");
135
+ const result = getProgress();
136
+ expect(result.type).toBe("todo");
137
+ expect(result.remaining).toBe(0);
138
+ expect(result.total).toBe(0);
139
+ });
140
+ });
141
+ describe("with no workspace", () => {
142
+ it("returns none when neither .beads nor todo.md exists", () => {
143
+ mockExistsSync.mockReturnValue(false);
144
+ const result = getProgress();
145
+ expect(result.type).toBe("none");
146
+ expect(result.remaining).toBe(0);
147
+ expect(result.total).toBe(0);
148
+ });
149
+ });
150
+ });
151
+ describe("getInitialBeadsCount", () => {
152
+ beforeEach(() => {
153
+ vi.clearAllMocks();
154
+ });
155
+ it("returns count when .beads exists", () => {
156
+ mockExistsSync.mockImplementation(path => {
157
+ if (typeof path === "string" && path.endsWith(".beads"))
158
+ return true;
159
+ return false;
160
+ });
161
+ mockExecSync.mockReturnValueOnce("2").mockReturnValueOnce("1");
162
+ const result = getInitialBeadsCount();
163
+ expect(result).toBe(3);
164
+ });
165
+ it("returns undefined when .beads does not exist", () => {
166
+ mockExistsSync.mockReturnValue(false);
167
+ const result = getInitialBeadsCount();
168
+ expect(result).toBeUndefined();
169
+ });
170
+ it("returns undefined when bd command fails", () => {
171
+ mockExistsSync.mockImplementation(path => {
172
+ if (typeof path === "string" && path.endsWith(".beads"))
173
+ return true;
174
+ return false;
175
+ });
176
+ mockExecSync.mockImplementation(() => {
177
+ throw new Error("Command failed");
178
+ });
179
+ const result = getInitialBeadsCount();
180
+ expect(result).toBeUndefined();
181
+ });
182
+ });
183
+ //# sourceMappingURL=getProgress.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getProgress.test.js","sourceRoot":"","sources":["../../src/lib/getProgress.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@herbcaudill/ralph",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "Autonomous AI iteration engine for Claude CLI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,22 +1,42 @@
1
1
  Before doing anything, run `pnpm build && pnpm test:all`.
2
2
 
3
- If there are build errors or test failures, fix them until the build succeeds and all tests pass. Commit your changes and end your turn.
3
+ If there are build errors or test failures:
4
4
 
5
- Otherwise, run `bd ready` to list unblocked issues.
5
+ - File an issue describing the errors.
6
+ - End your turn.
6
7
 
7
- If there are no open issues, immediately output <promise>COMPLETE</promise> and exit.
8
+ If there are no errors:
8
9
 
9
- Otherwise, find the highest-priority issue to work on, and work only on that task. Only work on a single issue in a single turn. If the issue you choose is complex, your task is to break it into sub-issues and then end your turn.
10
+ - Run `bd ready` to list unblocked issues.
10
11
 
11
- Mark the issue as in progress with `bd update <id> --status=in_progress`
12
+ If there are no open issues:
13
+
14
+ - Immediately output <promise>COMPLETE</promise>
15
+ - End your turn
16
+
17
+ If there are open issues:
18
+
19
+ - Find the highest-priority issue to work on. Use your best judgement.
20
+ - Output `✨ <task name>`.
21
+ - Mark the issue as in progress with `bd update <id> --status=in_progress`
22
+ - Work only on that task. Only work on a single issue in a single turn. If the issue you choose is complex, your task is to break it into sub-issues and then end your turn.
23
+ - While you're working, if you notice something else that needs to be done - follow-up tasks, other things that don't seem to be working right - open new issues.
24
+ - Where applicable, add tests to validate your changes and confirm that they pass.
25
+ - Update CLAUDE.md with any relevant changes.
12
26
 
13
27
  When you complete a task:
14
28
 
15
- - Where applicable, add tests to validate your changes and confirm that they pass
16
- - Update AGENTS.md with any relevant changes
17
- - Run `pnpm build && pnpm test:all`
18
- - Run `pnpm format`
19
- - Close the issue: `bd close <id>`
20
- - Commit and push your work
21
- - Output "🚀"
22
- - End your turn
29
+ - Run `ppnpm format`.
30
+ - Run `pnpm build && pnpm test:all`.
31
+ - Commit and push your work.
32
+ - Record a summary of the changes you made as a comment in the issue with `bd comments <id> --add "...markdown summary of changes"`.
33
+ - Close the issue: `bd close <id>`.
34
+ - Output `✅ <task name>`.
35
+ - End your turn.
36
+
37
+ ### Commit message format
38
+
39
+ ```
40
+ <concise summary of changes> (<issue id>)
41
+ <more detailed summary of changes>
42
+ ```