ralphctl 0.2.2 → 0.2.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 (29) hide show
  1. package/README.md +3 -3
  2. package/dist/{add-TGJTRHIF.mjs → add-3T225IX5.mjs} +3 -3
  3. package/dist/{add-SEDQ3VK7.mjs → add-6A5432U2.mjs} +4 -4
  4. package/dist/{chunk-XPDI4SYI.mjs → chunk-742XQ7FL.mjs} +3 -3
  5. package/dist/{chunk-XQHEKKDN.mjs → chunk-DUU5346E.mjs} +1 -1
  6. package/dist/{chunk-LG6B7QVO.mjs → chunk-EUNAUHC3.mjs} +1 -1
  7. package/dist/{chunk-ZDEVRTGY.mjs → chunk-IB6OCKZW.mjs} +24 -2
  8. package/dist/{chunk-KPTPKLXY.mjs → chunk-JRFOUFD3.mjs} +1 -1
  9. package/dist/{chunk-XXIHDQOH.mjs → chunk-U62BX47C.mjs} +508 -173
  10. package/dist/{chunk-Q3VWJARJ.mjs → chunk-UBPZHHCD.mjs} +2 -2
  11. package/dist/cli.mjs +105 -16
  12. package/dist/{create-DJHCP7LN.mjs → create-MYGOWO2F.mjs} +3 -3
  13. package/dist/{handle-CCTBNAJZ.mjs → handle-TA4MYNQJ.mjs} +1 -1
  14. package/dist/{project-ZYGNPVGL.mjs → project-YONEJICR.mjs} +2 -2
  15. package/dist/prompts/ideate-auto.md +9 -5
  16. package/dist/prompts/ideate.md +28 -12
  17. package/dist/prompts/plan-auto.md +26 -16
  18. package/dist/prompts/plan-common.md +67 -22
  19. package/dist/prompts/plan-interactive.md +26 -27
  20. package/dist/prompts/task-evaluation-resume.md +22 -0
  21. package/dist/prompts/task-evaluation.md +146 -24
  22. package/dist/prompts/task-execution.md +58 -36
  23. package/dist/prompts/ticket-refine.md +24 -20
  24. package/dist/{resolver-L52KR4GY.mjs → resolver-RXEY6EJE.mjs} +2 -2
  25. package/dist/{sprint-LUXAV3Q3.mjs → sprint-FGLWYWKX.mjs} +2 -2
  26. package/dist/{wizard-D7N5WZ5H.mjs → wizard-HWOH2HPV.mjs} +6 -6
  27. package/package.json +6 -6
  28. package/schemas/task-import.schema.json +7 -0
  29. package/schemas/tasks.schema.json +18 -1
package/README.md CHANGED
@@ -206,9 +206,9 @@ Run `ralphctl <command> --help` for details on any command.
206
206
  | [Contributing](./CONTRIBUTING.md) | Dev setup, code style, PR process |
207
207
  | [Changelog](./CHANGELOG.md) | Version history |
208
208
 
209
- **Blog posts:** [Building ralphctl](https://lukasgrigis.dev/blog/building-ralphctl) (
210
- backstory) | [From task CLI to agent harness](https://lukasgrigis.dev/blog/ralphctl-agent-harness/) (evaluator
211
- deep-dive)
209
+ **Blog posts:** [Building ralphctl](https://lukasgrigis.dev/blog/building-ralphctl) (backstory) | [From task CLI to agent harness](https://lukasgrigis.dev/blog/ralphctl-agent-harness/) (evaluator deep-dive)
210
+
211
+ **Further reading:** [Harness Engineering for Coding Agent Users](https://martinfowler.com/articles/harness-engineering.html) — Martin Fowler (April 2026) | [Harness Design for Long-Running Application Development](https://www.anthropic.com/engineering/harness-design-long-running-apps) — Anthropic Engineering
212
212
 
213
213
  ---
214
214
 
@@ -2,12 +2,12 @@
2
2
  import {
3
3
  addCheckScriptToRepository,
4
4
  projectAddCommand
5
- } from "./chunk-Q3VWJARJ.mjs";
5
+ } from "./chunk-UBPZHHCD.mjs";
6
6
  import "./chunk-7LZ6GOGN.mjs";
7
7
  import "./chunk-7TG3EAQ2.mjs";
8
- import "./chunk-LG6B7QVO.mjs";
8
+ import "./chunk-EUNAUHC3.mjs";
9
9
  import "./chunk-OEUJDSHY.mjs";
10
- import "./chunk-ZDEVRTGY.mjs";
10
+ import "./chunk-IB6OCKZW.mjs";
11
11
  import "./chunk-EDJX7TT6.mjs";
12
12
  import "./chunk-QBXHAXHI.mjs";
13
13
  export {
@@ -2,12 +2,12 @@
2
2
  import {
3
3
  addSingleTicketInteractive,
4
4
  ticketAddCommand
5
- } from "./chunk-XPDI4SYI.mjs";
5
+ } from "./chunk-742XQ7FL.mjs";
6
6
  import "./chunk-7TG3EAQ2.mjs";
7
- import "./chunk-LG6B7QVO.mjs";
8
- import "./chunk-KPTPKLXY.mjs";
7
+ import "./chunk-EUNAUHC3.mjs";
8
+ import "./chunk-JRFOUFD3.mjs";
9
9
  import "./chunk-OEUJDSHY.mjs";
10
- import "./chunk-ZDEVRTGY.mjs";
10
+ import "./chunk-IB6OCKZW.mjs";
11
11
  import "./chunk-EDJX7TT6.mjs";
12
12
  import "./chunk-QBXHAXHI.mjs";
13
13
  export {
@@ -6,14 +6,14 @@ import {
6
6
  import {
7
7
  listProjects,
8
8
  projectExists
9
- } from "./chunk-LG6B7QVO.mjs";
9
+ } from "./chunk-EUNAUHC3.mjs";
10
10
  import {
11
11
  assertSprintStatus,
12
12
  generateUuid8,
13
13
  getEditor,
14
14
  resolveSprintId,
15
15
  setEditor
16
- } from "./chunk-KPTPKLXY.mjs";
16
+ } from "./chunk-JRFOUFD3.mjs";
17
17
  import {
18
18
  ensureError,
19
19
  unwrapOrThrow,
@@ -24,7 +24,7 @@ import {
24
24
  getSprintFilePath,
25
25
  readValidatedJson,
26
26
  writeValidatedJson
27
- } from "./chunk-ZDEVRTGY.mjs";
27
+ } from "./chunk-IB6OCKZW.mjs";
28
28
  import {
29
29
  IOError,
30
30
  IssueFetchError,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  createSprint,
4
4
  setCurrentSprint
5
- } from "./chunk-KPTPKLXY.mjs";
5
+ } from "./chunk-JRFOUFD3.mjs";
6
6
  import {
7
7
  emoji,
8
8
  field,
@@ -7,7 +7,7 @@ import {
7
7
  readValidatedJson,
8
8
  validateProjectPath,
9
9
  writeValidatedJson
10
- } from "./chunk-ZDEVRTGY.mjs";
10
+ } from "./chunk-IB6OCKZW.mjs";
11
11
  import {
12
12
  ParseError,
13
13
  ProjectExistsError,
@@ -53,13 +53,27 @@ function getTasksFilePath(sprintId) {
53
53
  function getProgressFilePath(sprintId) {
54
54
  return join(getSprintDir(sprintId), "progress.md");
55
55
  }
56
+ function getEvaluationsDir(sprintId) {
57
+ return join(getSprintDir(sprintId), "evaluations");
58
+ }
59
+ function getEvaluationFilePath(sprintId, taskId) {
60
+ assertSafeSegment(taskId, "task ID");
61
+ return join(getEvaluationsDir(sprintId), `${taskId}.md`);
62
+ }
63
+ function assertSafeSegment(segment, label) {
64
+ if (!segment || segment.includes("/") || segment.includes("\\") || segment.includes("..") || segment.includes("\0")) {
65
+ throw new Error(`Path traversal detected in ${label}: ${segment}`);
66
+ }
67
+ }
56
68
  function getRefinementDir(sprintId, ticketId) {
69
+ assertSafeSegment(ticketId, "ticket ID");
57
70
  return join(getSprintDir(sprintId), "refinement", ticketId);
58
71
  }
59
72
  function getPlanningDir(sprintId) {
60
73
  return join(getSprintDir(sprintId), "planning");
61
74
  }
62
75
  function getIdeateDir(sprintId, ticketId) {
76
+ assertSafeSegment(ticketId, "ticket ID");
63
77
  return join(getSprintDir(sprintId), "ideation", ticketId);
64
78
  }
65
79
  function getSchemaPath(schemaName) {
@@ -196,6 +210,7 @@ import { z } from "zod";
196
210
  var SprintStatusSchema = z.enum(["draft", "active", "closed"]);
197
211
  var TaskStatusSchema = z.enum(["todo", "in_progress", "done"]);
198
212
  var RequirementStatusSchema = z.enum(["pending", "approved"]);
213
+ var EvaluationStatusSchema = z.enum(["passed", "failed", "malformed"]);
199
214
  var RepositorySchema = z.object({
200
215
  name: z.string().min(1),
201
216
  // Auto-derived from basename(path)
@@ -233,6 +248,7 @@ var TaskSchema = z.object({
233
248
  name: z.string().min(1),
234
249
  description: z.string().optional(),
235
250
  steps: z.array(z.string()).default([]),
251
+ verificationCriteria: z.array(z.string()).default([]),
236
252
  status: TaskStatusSchema.default("todo"),
237
253
  order: z.number().int().positive(),
238
254
  ticketId: z.string().optional(),
@@ -246,8 +262,12 @@ var TaskSchema = z.object({
246
262
  // Output from verification run
247
263
  evaluated: z.boolean().default(false),
248
264
  // Whether evaluation passed
249
- evaluationOutput: z.string().optional()
250
- // Output from evaluation run
265
+ evaluationOutput: z.string().optional(),
266
+ // Truncated output from evaluation run (full critique lives in evaluationFile)
267
+ evaluationStatus: EvaluationStatusSchema.optional(),
268
+ // Discriminator: 'passed' | 'failed' | 'malformed'
269
+ evaluationFile: z.string().optional()
270
+ // Sidecar file path containing the full untruncated critique
251
271
  });
252
272
  var TasksSchema = z.array(TaskSchema);
253
273
  var ImportTaskSchema = z.object({
@@ -257,6 +277,7 @@ var ImportTaskSchema = z.object({
257
277
  // Required
258
278
  description: z.string().optional(),
259
279
  steps: z.array(z.string()).optional(),
280
+ verificationCriteria: z.array(z.string()).optional(),
260
281
  ticketId: z.string().optional(),
261
282
  blockedBy: z.array(z.string()).optional(),
262
283
  projectPath: z.string().min(1)
@@ -300,6 +321,7 @@ export {
300
321
  getSprintFilePath,
301
322
  getTasksFilePath,
302
323
  getProgressFilePath,
324
+ getEvaluationFilePath,
303
325
  getRefinementDir,
304
326
  getPlanningDir,
305
327
  getIdeateDir,
@@ -21,7 +21,7 @@ import {
21
21
  readValidatedJson,
22
22
  removeDir,
23
23
  writeValidatedJson
24
- } from "./chunk-ZDEVRTGY.mjs";
24
+ } from "./chunk-IB6OCKZW.mjs";
25
25
  import {
26
26
  LockError,
27
27
  NoCurrentSprintError,