nightralph 0.0.29 → 0.0.32

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/README.md CHANGED
@@ -26,12 +26,18 @@ so they can't drift as long as you install the skills with this package.
26
26
  - [Workflow](#workflow)
27
27
  * [Create Issues](#create-issues)
28
28
  * [Examples](#examples)
29
+ * [Interface](#interface)
30
+ + [`--spec ` option](#--spec--option)
29
31
  - [How It Works](#how-it-works)
30
32
  * [Select a ticket](#select-a-ticket)
31
33
  * [Worktrees](#worktrees)
32
34
  * [Progress](#progress)
33
35
  - [Keep Your Machine Awake](#keep-your-machine-awake)
34
36
  * [Mac OS](#mac-os)
37
+ + [Claude Opus 4.6](#claude-opus-46)
38
+ + [Claude Sonnet 5](#claude-sonnet-5)
39
+ + [`pi` + OpenRouter model](#pi--openrouter-model)
40
+ + [`codex` + Luna](#codex--luna)
35
41
 
36
42
  <!-- tocstop -->
37
43
 
@@ -107,7 +113,6 @@ before a ticket can be marked `done`.
107
113
  > then follow with `to-tickets`.
108
114
  >
109
115
 
110
-
111
116
  ### Examples
112
117
 
113
118
  After you have the tickets, use the `nightralph` loop to execute.
@@ -124,6 +129,9 @@ npx nightralph pi -m openrouter/z-ai/glm-5.3-flash
124
129
  # Dry run to inspect the dependency graph and prompt
125
130
  npx nightralph codex --dry-run
126
131
 
132
+ # Use codex with a specific model
133
+ npx nightralph codex -m gpt-5.6-luna
134
+
127
135
  # Specify a feature by name
128
136
  npx nightralph claude -m claude-opus-4-6 --spec my-feature
129
137
 
@@ -133,15 +141,11 @@ npx nightralph claude -m claude-opus-4-6 --max-turns 30
133
141
  # Same thing, using the positional shorthand
134
142
  npx nightralph claude -m claude-opus-4-6 30
135
143
 
136
- # Start pi at medium thinking and allow one escalated retry
137
- npx nightralph pi -m openrouter/z-ai/glm-5.3-flash --thinking medium --retries 1
144
+ # Start pi at medium effort and allow one escalated retry
145
+ npx nightralph pi -m openrouter/z-ai/glm-5.3-flash --effort medium --retries 1
138
146
  ```
139
147
 
140
- #### `--spec <name>` option
141
-
142
- A feature name that resolves to `.scratch/<name>/`.
143
- The spec file is `.scratch/<name>/spec.md` and the issues directory
144
- is `.scratch/<name>/issues/`.
148
+ ### Interface
145
149
 
146
150
  Flags:
147
151
 
@@ -156,8 +160,8 @@ Flags:
156
160
  | `--timeout` | no | `3600` | Kill the agent after N seconds. A killed agent is not a failure: its work is kept (see Notes) |
157
161
  | `--test-cmd <cmd>` | no | auto | Run in each worktree after the agent exits; non-zero exit rejects the ticket. Auto-detects `npm test`. Pass `""` to disable. Shares the agent's `--timeout`. The command runs in a fresh git worktree, which contains only tracked files, so a project that needs an install step should include it, for example `--test-cmd 'npm ci && npm test'` |
158
162
  | `--max-turns <n>` | no | -- | Max agentic turns per ticket. Forwarded verbatim as `--max-turns <n>` to the provider CLI. Only `claude` accepts it; `codex` and `pi` reject it as an unknown option and the agent exits immediately. Applies to every agent spawn, including a re-spawn after a merge conflict. When omitted, `claude` applies no turn limit, so `--timeout` is the only cap. Reaching the limit is an error exit, so the ticket is recorded as failed |
159
- | `--thinking <level>` | no | -- | Starting thinking level for `pi`, one of `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`. Forwarded as `--thinking <level>`. Omitted = pi's own default. Ignored for other providers. Each retry steps up from here (see `--retries`) |
160
- | `--retries <n>` | no | `2` | Extra attempts per ticket after a failed run. Each retry starts from a fresh worktree; with `pi` it also raises the thinking level (see Notes). `0` disables retries |
163
+ | `--effort <level>` | no | -- | Starting effort/reasoning level. Each provider has its own ladder: `claude` supports `low`, `medium`, `high`, `xhigh`, `max` (forwarded as `--effort`); `codex` supports `low`, `medium`, `high` (forwarded as `-c model_reasoning_effort=<level>`); `pi` supports `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max` (forwarded as `--thinking`). Omitted = provider default. Each retry steps up from here (see `--retries`) |
164
+ | `--retries <n>` | no | `3` | Extra attempts per ticket after a failed run. Each retry starts from a fresh worktree and raises the effort level one rung (see Notes). `0` disables retries |
161
165
  | `--retry-delay <n>` | no | `30` | Seconds to wait before the first retry; doubles each further retry (30s, 60s, 120s, ...). `0` disables the wait |
162
166
 
163
167
 
@@ -185,15 +189,15 @@ Flags:
185
189
  ticket is recorded as failed. Non-zero exit, exit 0 with no new
186
190
  commits, and a red test command all count as failures; a timeout
187
191
  does not (see below). Each retry discards the previous worktree
188
- and starts from a fresh one. With `pi`, each retry raises the
189
- thinking level: without `--thinking` the first retry uses `high`
190
- and the second `max`; with `--thinking <level>` each retry steps
191
- one level up from the previous attempt, stopping at `max`.
192
- `claude` and `codex` are retried at the same settings. Retries
193
- are spaced with exponential backoff controlled by `--retry-delay`:
194
- the first retry waits `--retry-delay` seconds, the second waits
195
- double that, and so on. This lets provider outages clear before
196
- burning the next attempt. Retry
192
+ and starts from a fresh one. Each retry also raises the effort
193
+ level one rung up the provider's ladder: without `--effort` the
194
+ first retry uses `high`; with `--effort <level>` each retry
195
+ steps one level up from the previous attempt, stopping at the
196
+ provider's max (`max` for claude/pi, `high` for codex).
197
+ Retries are spaced with exponential backoff controlled by
198
+ `--retry-delay`: the first retry waits `--retry-delay` seconds,
199
+ the second waits double that, and so on. This lets provider
200
+ outages clear before burning the next attempt. Retry
197
201
  logs are written to `<dir>/../logs/<ticket>.attempt<n>.log`
198
202
  (and `.attempt<n>.test.log` for the test command) so the first
199
203
  attempt's log is kept.
@@ -237,6 +241,13 @@ Flags:
237
241
  tool-use proposals so the agent runs non-interactively)
238
242
 
239
243
 
244
+ #### `--spec <name>` option
245
+
246
+ A feature name that resolves to `.scratch/<name>/`.
247
+ The spec file is `.scratch/<name>/spec.md` and the issues directory
248
+ is `.scratch/<name>/issues/`.
249
+
250
+
240
251
  ## How It Works
241
252
 
242
253
  All currently eligible tickets are grouped into a
package/dist/index.js CHANGED
@@ -1376,13 +1376,7 @@ var EFFORT_LADDERS = {
1376
1376
  "xhigh",
1377
1377
  "max"
1378
1378
  ],
1379
- codex: [
1380
- "minimal",
1381
- "low",
1382
- "medium",
1383
- "high",
1384
- "xhigh"
1385
- ]
1379
+ codex: ["low", "medium", "high"]
1386
1380
  };
1387
1381
  var ALL_EFFORT_LEVELS = [
1388
1382
  "off",
@@ -1536,12 +1530,21 @@ function spawnAgent(opts) {
1536
1530
  if (opts.model) {
1537
1531
  args.push("--model", opts.model);
1538
1532
  }
1539
- if (opts.maxTurns) {
1540
- args.push("--max-turns", String(opts.maxTurns));
1541
- }
1542
1533
  const providerName = basename2(opts.agentCmd);
1543
1534
  const isClaude = providerName === "claude";
1544
1535
  const isPi = providerName === "pi";
1536
+ if (opts.maxTurns) {
1537
+ if (isClaude) {
1538
+ args.push(
1539
+ "--max-turns",
1540
+ String(opts.maxTurns)
1541
+ );
1542
+ } else if (opts.onLine) {
1543
+ opts.onLine(
1544
+ `Warning: --max-turns not supported by ${providerName}, skipping`
1545
+ );
1546
+ }
1547
+ }
1545
1548
  if (opts.effort && providerName in EFFORT_LADDERS) {
1546
1549
  const ladder = EFFORT_LADDERS[providerName];
1547
1550
  if (!ladder.includes(opts.effort)) {
@@ -1555,7 +1558,10 @@ function spawnAgent(opts) {
1555
1558
  } else if (isClaude) {
1556
1559
  args.push("--effort", opts.effort);
1557
1560
  } else if (providerName === "codex") {
1558
- args.push("-e", opts.effort);
1561
+ args.push(
1562
+ "-c",
1563
+ `model_reasoning_effort=${opts.effort}`
1564
+ );
1559
1565
  }
1560
1566
  }
1561
1567
  const prefix = opts.label ? ` [${opts.label}] ` : " ";
@@ -2214,10 +2220,17 @@ async function runWaves(tickets, specBody, agentCmd, model, timeout, logsDir, di
2214
2220
  );
2215
2221
  }
2216
2222
  if (waveCompleted === 0) {
2223
+ const remaining3 = findReadyTickets(tickets).filter((t) => !failedNums.has(t.num));
2224
+ if (remaining3.length === 0) {
2225
+ d.log(
2226
+ "\nNo tickets completed this wave and no ready tickets remain. Stopping."
2227
+ );
2228
+ break;
2229
+ }
2217
2230
  d.log(
2218
- "\nNo tickets completed this wave. Stopping."
2231
+ `
2232
+ No tickets completed this wave. ${remaining3.length} ready ticket${remaining3.length === 1 ? "" : "s"} remain; continuing.`
2219
2233
  );
2220
- break;
2221
2234
  }
2222
2235
  }
2223
2236
  const remaining = tickets.filter(
@@ -2548,10 +2561,19 @@ Merge stopped at ${mergeResult.stoppedAt.branch}`
2548
2561
  }
2549
2562
  }
2550
2563
  if (waveCompleted === 0) {
2564
+ const remaining3 = findReadyTickets(
2565
+ opts.tickets
2566
+ ).filter((t) => !failedNums.has(t.num));
2567
+ if (remaining3.length === 0) {
2568
+ d.log(
2569
+ "\nNo tickets completed this wave and no ready tickets remain. Stopping."
2570
+ );
2571
+ break;
2572
+ }
2551
2573
  d.log(
2552
- "\nNo tickets completed this wave. Stopping."
2574
+ `
2575
+ No tickets completed this wave. ${remaining3.length} ready ticket${remaining3.length === 1 ? "" : "s"} remain; continuing.`
2553
2576
  );
2554
- break;
2555
2577
  }
2556
2578
  }
2557
2579
  const remaining = opts.tickets.filter(