ralphctl 0.4.3 → 0.4.5

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 (28) hide show
  1. package/dist/{add-MG26JWBP.mjs → add-DVPVHENV.mjs} +7 -7
  2. package/dist/{add-ZZYL4BSF.mjs → add-YVXM34RP.mjs} +6 -6
  3. package/dist/{chunk-LDSG7G2T.mjs → chunk-BSB4EDGR.mjs} +2 -2
  4. package/dist/{chunk-RQGD5WS6.mjs → chunk-CBMFRQ4Y.mjs} +3 -3
  5. package/dist/{chunk-Q4AVHUZL.mjs → chunk-FNAAA32W.mjs} +3 -3
  6. package/dist/{chunk-EGUFQNRB.mjs → chunk-GQ2WFKBN.mjs} +3 -3
  7. package/dist/{chunk-LCY32RW4.mjs → chunk-OFILN7QL.mjs} +183 -39
  8. package/dist/{chunk-MDE6KPJQ.mjs → chunk-OGEXYSFS.mjs} +5 -5
  9. package/dist/{chunk-TDBEEHTS.mjs → chunk-PYZEQ2VK.mjs} +5 -5
  10. package/dist/{chunk-57UWLHRH.mjs → chunk-VAZ3LJBI.mjs} +12 -1
  11. package/dist/{chunk-D2HWXEHH.mjs → chunk-WDMLPXOD.mjs} +2 -2
  12. package/dist/{chunk-WZTY77GY.mjs → chunk-XN2UIHBY.mjs} +10 -3
  13. package/dist/{chunk-WOMGKKZY.mjs → chunk-XPLYLRIM.mjs} +319 -15
  14. package/dist/{chunk-2FT37OZX.mjs → chunk-ZLWSPLWI.mjs} +53 -7
  15. package/dist/cli.mjs +19 -17
  16. package/dist/create-Z635FQKO.mjs +15 -0
  17. package/dist/{handle-SYVCFI6Y.mjs → handle-23EFF3BE.mjs} +1 -1
  18. package/dist/{mount-2ANLHHQE.mjs → mount-H2IH3MWE.mjs} +1455 -1193
  19. package/dist/{project-JF47ZWMF.mjs → project-DQHF4ISP.mjs} +3 -3
  20. package/dist/prompts/sprint-feedback.md +4 -0
  21. package/dist/prompts/task-evaluation.md +44 -2
  22. package/dist/prompts/task-execution.md +5 -0
  23. package/dist/{resolver-PG2DZEBX.mjs → resolver-OVPYVW6Q.mjs} +3 -3
  24. package/dist/{sprint-54DOSIJK.mjs → sprint-4E26AB5F.mjs} +4 -4
  25. package/dist/start-2WH4BTDB.mjs +19 -0
  26. package/package.json +1 -1
  27. package/dist/create-PQK6KKRD.mjs +0 -15
  28. package/dist/start-2SZTBKGF.mjs +0 -19
@@ -10,18 +10,18 @@ import {
10
10
  getAiProvider,
11
11
  log,
12
12
  setAiProvider
13
- } from "./chunk-WZTY77GY.mjs";
13
+ } from "./chunk-XN2UIHBY.mjs";
14
14
  import {
15
15
  ensureError,
16
16
  wrapAsync
17
17
  } from "./chunk-IWXBJD2D.mjs";
18
18
  import {
19
19
  assertSafeCwd
20
- } from "./chunk-D2HWXEHH.mjs";
20
+ } from "./chunk-WDMLPXOD.mjs";
21
21
  import {
22
22
  IOError,
23
23
  SpawnError
24
- } from "./chunk-57UWLHRH.mjs";
24
+ } from "./chunk-VAZ3LJBI.mjs";
25
25
 
26
26
  // src/integration/ui/tui/runtime/screen.ts
27
27
  var ENTER_ALT_SCREEN = "\x1B[?1049h";
@@ -166,6 +166,34 @@ var ProcessManager = class _ProcessManager {
166
166
  this.handlersInstalled = true;
167
167
  }
168
168
  }
169
+ /**
170
+ * Wire a task-scoped AbortSignal to a terminate callback. When the signal
171
+ * aborts, the callback fires once. Returns a disposer that detaches the
172
+ * listener — call it in a `finally` after the child exits so listeners
173
+ * don't accumulate across repeated runs.
174
+ *
175
+ * If the signal is already aborted, terminate runs on the next microtask
176
+ * so the caller always observes a consistent async flow.
177
+ */
178
+ registerAbort(signal, terminate) {
179
+ let fired = false;
180
+ const handler = () => {
181
+ if (fired) return;
182
+ fired = true;
183
+ try {
184
+ terminate();
185
+ } catch (err) {
186
+ log.error(`Error in abort-signal handler: ${err instanceof Error ? err.message : String(err)}`);
187
+ }
188
+ };
189
+ if (signal.aborted) {
190
+ queueMicrotask(handler);
191
+ }
192
+ signal.addEventListener("abort", handler, { once: true });
193
+ return () => {
194
+ signal.removeEventListener("abort", handler);
195
+ };
196
+ }
169
197
  /**
170
198
  * Check if a shutdown is in progress.
171
199
  * Used by execution loops to break immediately on Ctrl+C.
@@ -296,7 +324,8 @@ var processLifecycleAdapter = {
296
324
  ensureHandlers: () => {
297
325
  ProcessManager.getInstance().ensureHandlers();
298
326
  },
299
- isShuttingDown: () => ProcessManager.getInstance().isShuttingDown()
327
+ isShuttingDown: () => ProcessManager.getInstance().isShuttingDown(),
328
+ registerAbort: (signal, terminate) => ProcessManager.getInstance().registerAbort(signal, terminate)
300
329
  };
301
330
 
302
331
  // src/integration/ai/providers/claude.ts
@@ -491,6 +520,15 @@ async function spawnHeadless(options, provider) {
491
520
  reject(new SpawnError("Cannot spawn during shutdown", "", 1));
492
521
  return;
493
522
  }
523
+ let detachAbort = null;
524
+ if (options.abortSignal) {
525
+ detachAbort = manager.registerAbort(options.abortSignal, () => {
526
+ try {
527
+ child.kill("SIGTERM");
528
+ } catch {
529
+ }
530
+ });
531
+ }
494
532
  const MAX_STDOUT_SIZE = 1e7;
495
533
  const MAX_PROMPT_SIZE = 1e6;
496
534
  if (options.prompt) {
@@ -512,6 +550,7 @@ async function spawnHeadless(options, provider) {
512
550
  stderr += data.toString();
513
551
  });
514
552
  child.on("close", (code) => {
553
+ detachAbort?.();
515
554
  void (async () => {
516
555
  const exitCode = code ?? 1;
517
556
  const { result, sessionId: parsedSessionId, model: parsedModel } = p.parseJsonOutput(rawStdout);
@@ -533,6 +572,7 @@ async function spawnHeadless(options, provider) {
533
572
  });
534
573
  });
535
574
  child.on("error", (err) => {
575
+ detachAbort?.();
536
576
  reject(new SpawnError(`Failed to spawn ${p.binary} CLI: ${err.message}`, "", 1));
537
577
  });
538
578
  });
@@ -558,6 +598,9 @@ async function spawnWithRetry(options, retryOptions, provider) {
558
598
  if (attempt > 0 && elapsed >= totalTimeoutMs) {
559
599
  throw new SpawnError(`Total retry timeout exceeded (${String(totalTimeoutMs)}ms)`, "", 1, resumeSessionId);
560
600
  }
601
+ if (options.abortSignal?.aborted) {
602
+ throw new SpawnError("Aborted by caller", "", 1, resumeSessionId);
603
+ }
561
604
  const r = await wrapAsync(async () => spawnHeadless({ ...options, resumeSessionId }, p), ensureError);
562
605
  if (r.ok) return r.value;
563
606
  const err = r.error;
@@ -614,7 +657,8 @@ var ProviderAiSessionAdapter = class {
614
657
  args: options.args,
615
658
  env: options.env,
616
659
  prompt,
617
- resumeSessionId: options.resumeSessionId
660
+ resumeSessionId: options.resumeSessionId,
661
+ abortSignal: options.abortSignal
618
662
  },
619
663
  provider
620
664
  );
@@ -632,7 +676,8 @@ var ProviderAiSessionAdapter = class {
632
676
  args: options.args,
633
677
  env: options.env,
634
678
  prompt,
635
- resumeSessionId: options.resumeSessionId
679
+ resumeSessionId: options.resumeSessionId,
680
+ abortSignal: options.abortSignal
636
681
  },
637
682
  { maxRetries: options.maxRetries },
638
683
  provider
@@ -651,7 +696,8 @@ var ProviderAiSessionAdapter = class {
651
696
  args: options.args,
652
697
  env: options.env,
653
698
  prompt,
654
- resumeSessionId: sessionId
699
+ resumeSessionId: sessionId,
700
+ abortSignal: options.abortSignal
655
701
  },
656
702
  void 0,
657
703
  provider
package/dist/cli.mjs CHANGED
@@ -41,26 +41,26 @@ import {
41
41
  ticketRefineCommand,
42
42
  ticketRemoveCommand,
43
43
  ticketShowCommand
44
- } from "./chunk-WOMGKKZY.mjs";
44
+ } from "./chunk-XPLYLRIM.mjs";
45
45
  import {
46
46
  projectAddCommand
47
- } from "./chunk-TDBEEHTS.mjs";
47
+ } from "./chunk-PYZEQ2VK.mjs";
48
48
  import {
49
49
  sprintCreateCommand
50
- } from "./chunk-Q4AVHUZL.mjs";
50
+ } from "./chunk-FNAAA32W.mjs";
51
51
  import {
52
52
  ticketAddCommand
53
- } from "./chunk-MDE6KPJQ.mjs";
53
+ } from "./chunk-OGEXYSFS.mjs";
54
54
  import {
55
55
  createOnboardPipeline,
56
56
  executePipeline,
57
57
  getTasks,
58
58
  sprintStartCommand
59
- } from "./chunk-LCY32RW4.mjs";
60
- import "./chunk-2FT37OZX.mjs";
59
+ } from "./chunk-OFILN7QL.mjs";
60
+ import "./chunk-ZLWSPLWI.mjs";
61
61
  import {
62
62
  truncate
63
- } from "./chunk-EGUFQNRB.mjs";
63
+ } from "./chunk-GQ2WFKBN.mjs";
64
64
  import {
65
65
  EXIT_ERROR,
66
66
  exitWithCode
@@ -69,11 +69,11 @@ import {
69
69
  getSharedDeps,
70
70
  setSharedDeps
71
71
  } from "./chunk-747KW2RW.mjs";
72
- import "./chunk-LDSG7G2T.mjs";
72
+ import "./chunk-BSB4EDGR.mjs";
73
73
  import {
74
74
  getCurrentSprintOrThrow,
75
75
  getSprint
76
- } from "./chunk-RQGD5WS6.mjs";
76
+ } from "./chunk-CBMFRQ4Y.mjs";
77
77
  import {
78
78
  colors,
79
79
  error,
@@ -85,7 +85,7 @@ import {
85
85
  setCurrentSprint,
86
86
  showError,
87
87
  showSuccess
88
- } from "./chunk-WZTY77GY.mjs";
88
+ } from "./chunk-XN2UIHBY.mjs";
89
89
  import {
90
90
  ensureError,
91
91
  wrapAsync
@@ -93,10 +93,10 @@ import {
93
93
  import {
94
94
  ensureDir,
95
95
  getDataDir
96
- } from "./chunk-D2HWXEHH.mjs";
96
+ } from "./chunk-WDMLPXOD.mjs";
97
97
  import {
98
98
  DomainError
99
- } from "./chunk-57UWLHRH.mjs";
99
+ } from "./chunk-VAZ3LJBI.mjs";
100
100
 
101
101
  // src/application/entrypoint.ts
102
102
  import { Command } from "commander";
@@ -382,7 +382,7 @@ Examples:
382
382
  if (opts?.export) args.push("--export");
383
383
  await sprintInsightsCommand(args);
384
384
  });
385
- sprint.command("start [id]").description("Run automated implementation loop").option("-s, --session", "Interactive AI session (collaborate with your AI provider)").option("-t, --step", "Step through tasks with approval between each").option("-c, --count <n>", "Limit to N tasks").option("--no-commit", "Skip automatic git commit after each task completes").option("--concurrency <n>", "Max parallel tasks (default: auto based on unique repos)").option("--max-retries <n>", "Max rate-limit retries per task (default: 5)").option("--fail-fast", "Stop launching new tasks on first failure").option("-f, --force", "Skip precondition checks (e.g., unplanned tickets)").option("--refresh-check", "Force re-run check scripts even if they already ran this sprint").option("-b, --branch", "Create sprint branch (ralphctl/<sprint-id>) in all repos").option("--branch-name <name>", "Use a custom branch name for sprint execution").option("--max-budget-usd <amount>", "Max USD budget per AI task (Claude only)").option("--fallback-model <model>", "Fallback model when primary is overloaded (Claude only)").option("--max-turns <number>", "Max agentic turns per task (Claude only, default: 200)").addHelpText(
385
+ sprint.command("start [id]").description("Run automated implementation loop").option("-s, --session", "Interactive AI session (collaborate with your AI provider)").option("-t, --step", "Step through tasks with approval between each").option("-c, --count <n>", "Limit to N tasks").option("--no-commit", "Skip automatic git commit after each task completes").option("--concurrency <n>", "Max parallel tasks (default: auto based on unique repos)").option("--max-retries <n>", "Max rate-limit retries per task (default: 5)").option("--fail-fast", "Stop launching new tasks on first failure").option("-f, --force", "Skip precondition checks (e.g., unplanned tickets)").option("--refresh-check", "Force re-run check scripts even if they already ran this sprint").option("-b, --branch", "Create sprint branch (ralphctl/<sprint-id>) in all repos").option("--branch-name <name>", "Use a custom branch name for sprint execution").option("--resume-dirty", "Resume with uncommitted changes intact (skips prompt)").option("--reset-on-resume", "Hard-reset working tree to HEAD before resuming (destructive; skips prompt)").option("--max-budget-usd <amount>", "Max USD budget per AI task (Claude only)").option("--fallback-model <model>", "Fallback model when primary is overloaded (Claude only)").option("--max-turns <number>", "Max agentic turns per task (Claude only, default: 200)").addHelpText(
386
386
  "after",
387
387
  `
388
388
  Exit Codes:
@@ -418,6 +418,8 @@ Branch Management:
418
418
  if (opts?.refreshCheck) args.push("--refresh-check");
419
419
  if (opts?.branch) args.push("--branch");
420
420
  if (opts?.branchName) args.push("--branch-name", opts.branchName);
421
+ if (opts?.resumeDirty) args.push("--resume-dirty");
422
+ if (opts?.resetOnResume) args.push("--reset-on-resume");
421
423
  if (opts?.maxBudgetUsd) args.push("--max-budget-usd", opts.maxBudgetUsd);
422
424
  if (opts?.fallbackModel) args.push("--fallback-model", opts.fallbackModel);
423
425
  if (opts?.maxTurns) args.push("--max-turns", opts.maxTurns);
@@ -747,14 +749,14 @@ function isQuietCommand(argv) {
747
749
  }
748
750
  async function main() {
749
751
  if (process.env["COMP_CWORD"] && process.env["COMP_POINT"] && process.env["COMP_LINE"]) {
750
- const { handleCompletionRequest } = await import("./handle-SYVCFI6Y.mjs");
752
+ const { handleCompletionRequest } = await import("./handle-23EFF3BE.mjs");
751
753
  if (await handleCompletionRequest(program)) return;
752
754
  }
753
755
  const argv = process.argv;
754
756
  const isBare = argv.length <= 2;
755
757
  const isInteractive = argv[2] === "interactive";
756
758
  if (isBare || isInteractive) {
757
- const { mountInkApp } = await import("./mount-2ANLHHQE.mjs");
759
+ const { mountInkApp } = await import("./mount-H2IH3MWE.mjs");
758
760
  const { fallback } = await mountInkApp({ initialView: "repl" });
759
761
  if (!fallback) return;
760
762
  printBanner();
@@ -765,10 +767,10 @@ async function main() {
765
767
  return;
766
768
  }
767
769
  if (argv[2] === "sprint" && argv[3] === "start") {
768
- const { parseSprintStartArgs } = await import("./start-2SZTBKGF.mjs");
770
+ const { parseSprintStartArgs } = await import("./start-2WH4BTDB.mjs");
769
771
  const parsed = parseSprintStartArgs(argv.slice(4));
770
772
  if (parsed.ok) {
771
- const { mountInkApp } = await import("./mount-2ANLHHQE.mjs");
773
+ const { mountInkApp } = await import("./mount-H2IH3MWE.mjs");
772
774
  const { getSharedDeps: getSharedDeps2 } = await import("./bootstrap-FMHG6DRY.mjs");
773
775
  let sprintId;
774
776
  try {
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ sprintCreateCommand
4
+ } from "./chunk-FNAAA32W.mjs";
5
+ import "./chunk-CFUVE2BP.mjs";
6
+ import "./chunk-747KW2RW.mjs";
7
+ import "./chunk-BSB4EDGR.mjs";
8
+ import "./chunk-CBMFRQ4Y.mjs";
9
+ import "./chunk-XN2UIHBY.mjs";
10
+ import "./chunk-IWXBJD2D.mjs";
11
+ import "./chunk-WDMLPXOD.mjs";
12
+ import "./chunk-VAZ3LJBI.mjs";
13
+ export {
14
+ sprintCreateCommand
15
+ };
@@ -7,7 +7,7 @@ async function handleCompletionRequest(program) {
7
7
  return false;
8
8
  }
9
9
  const tabtab = (await import("tabtab")).default;
10
- const { resolveCompletions } = await import("./resolver-PG2DZEBX.mjs");
10
+ const { resolveCompletions } = await import("./resolver-OVPYVW6Q.mjs");
11
11
  const tabEnv = tabtab.parseEnv(env);
12
12
  const completions = await resolveCompletions(program, {
13
13
  line: tabEnv.line,