nightralph 0.0.35 → 0.0.37

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
@@ -38,6 +38,7 @@ so they can't drift as long as you install the skills with this package.
38
38
  + [Claude Sonnet 5](#claude-sonnet-5)
39
39
  + [`pi` + OpenRouter model](#pi--openrouter-model)
40
40
  + [`codex` + Luna](#codex--luna)
41
+ + [`codex` + Terra](#codex--terra)
41
42
 
42
43
  <!-- tocstop -->
43
44
 
@@ -299,23 +300,33 @@ keep the machine awake, but the display can still go dark.
299
300
  #### Claude Opus 4.6
300
301
 
301
302
  ```sh
302
- caffeinate -i npx nightralph claude -m claude-opus-4-6
303
+ caffeinate -i npx nightralph claude -m claude-opus-4-6 --effort high
303
304
  ```
304
305
 
305
306
  #### Claude Sonnet 5
306
307
 
307
308
  ```sh
308
- caffeinate -i npx nightralph claude -m claude-sonnet-5
309
+ caffeinate -i npx nightralph claude -m claude-sonnet-5 --effort high
309
310
  ```
310
311
 
311
312
  #### `pi` + OpenRouter model
312
313
 
313
314
  ```sh
314
- caffeinate -i npx nightralph pi -m openrouter/z-ai/glm-5.3-flash
315
+ caffeinate -i npx nightralph pi -m openrouter/z-ai/glm-5.3-flash --thinking high
315
316
  ```
316
317
 
318
+ ##### pi `--thinking` levels
319
+
320
+ `off`, `minimal`, `low`, `medium`,`high`, and `xhigh`
321
+
317
322
  #### `codex` + Luna
318
323
 
319
324
  ```sh
320
- caffeinate -i npx nightralph codex -m gpt-5.6-luna
321
- ```
325
+ caffeinate -i npx nightralph codex -m gpt-5.6-luna --effort high
326
+ ```
327
+
328
+ #### `codex` + Terra
329
+
330
+ ```sh
331
+ caffeinate -i npx nightralph codex -m gpt-5.6-luna --effort medium
332
+ ```
package/dist/index.js CHANGED
@@ -1292,11 +1292,7 @@ function stripSpecSection(specBody, heading) {
1292
1292
  return out.join("\n");
1293
1293
  }
1294
1294
  __name(stripSpecSection, "stripSpecSection");
1295
- function renderPrompt(specBody, ticket, opts = {}) {
1296
- const testRules = opts.testCmd ? [
1297
- "- Work test-first. For each checklist item, write a failing test at the seams named in the spec's Testing Decisions section, then write only enough code to make it pass.",
1298
- `- Run \`${opts.testCmd}\` before committing. Do not commit with failing tests. The orchestrator runs the same command after you exit and rejects the ticket if it fails.`
1299
- ] : [];
1295
+ function renderPrompt(specBody, ticket, opts) {
1300
1296
  return [
1301
1297
  "---- SPEC CONTEXT ----",
1302
1298
  specBody,
@@ -1306,12 +1302,13 @@ function renderPrompt(specBody, ticket, opts = {}) {
1306
1302
  ticket.body,
1307
1303
  "",
1308
1304
  "---- AGENT INSTRUCTIONS ----",
1309
- "You are an autonomous coding agent. Implement the ticket.",
1305
+ "You are an autonomous coding agent. Implement the ticket using /tdd.",
1310
1306
  "",
1311
1307
  "Follow these rules:",
1312
1308
  "- Read the files directly relevant to the ticket before writing code.",
1313
1309
  "- Do NOT research external APIs or services via web search. Use the spec and ticket body as your sole reference for API shapes.",
1314
- ...testRules,
1310
+ "- Use /tdd for every checklist item. For each item, write a failing test at the seams named in the spec's Testing Decisions section, then write only enough code to make it pass, then refactor.",
1311
+ `- Run \`${opts.testCmd}\` before committing. Do not commit with failing tests. The orchestrator runs the same command after you exit and rejects the ticket if it fails.`,
1315
1312
  "- Do NOT read or modify files outside your current directory (the worktree).",
1316
1313
  "- Do NOT run git push.",
1317
1314
  "- Commit your work when finished.",
@@ -1816,7 +1813,7 @@ function spawnAgent(opts) {
1816
1813
  });
1817
1814
  }
1818
1815
  __name(spawnAgent, "spawnAgent");
1819
- function dryRun(tickets, specBody) {
1816
+ function dryRun(tickets, specBody, testCmd) {
1820
1817
  listTickets(tickets);
1821
1818
  console.log("\nSimulated wave order:");
1822
1819
  for (const { wave, ready } of simulateWaves(tickets)) {
@@ -1838,7 +1835,11 @@ Prompt for first ready ticket (${firstReady[0].filename}):
1838
1835
  `
1839
1836
  );
1840
1837
  console.log(
1841
- renderPrompt(specBody, firstReady[0])
1838
+ renderPrompt(
1839
+ specBody,
1840
+ firstReady[0],
1841
+ { testCmd }
1842
+ )
1842
1843
  );
1843
1844
  }
1844
1845
  }
@@ -1884,7 +1885,7 @@ Prompt for first ready ticket (${firstReady[0].filename}):
1884
1885
  const strategyDesc = opts.conflictStrategy === "respawn" ? "respawn (re-run agent on conflict)" : "stop (stop merging on conflict)";
1885
1886
  console.log(
1886
1887
  `
1887
- Test command: ${opts.testCmd ?? "(none)"}`
1888
+ Test command: ${opts.testCmd}`
1888
1889
  );
1889
1890
  console.log(
1890
1891
  `Effort: ${opts.effort ?? "(provider default)"}`
@@ -1976,22 +1977,20 @@ async function respawnAndRetryMerge(opts) {
1976
1977
  }
1977
1978
  return false;
1978
1979
  }
1979
- if (opts.testCmd) {
1980
- const passed = await runTestGate({
1981
- testCmd: opts.testCmd,
1982
- ticket: opts.ticket,
1983
- worktreePath: opts.worktreePath,
1984
- timeout: opts.timeout,
1985
- logsDir: opts.logsDir,
1986
- log,
1987
- registry: runningAgents
1988
- });
1989
- if (!passed) {
1990
- log(
1991
- ` ${opts.ticket.filename}: tests failed after conflict respawn; not merging`
1992
- );
1993
- return false;
1994
- }
1980
+ const passed = await runTestGate({
1981
+ testCmd: opts.testCmd,
1982
+ ticket: opts.ticket,
1983
+ worktreePath: opts.worktreePath,
1984
+ timeout: opts.timeout,
1985
+ logsDir: opts.logsDir,
1986
+ log,
1987
+ registry: runningAgents
1988
+ });
1989
+ if (!passed) {
1990
+ log(
1991
+ ` ${opts.ticket.filename}: tests failed after conflict respawn; not merging`
1992
+ );
1993
+ return false;
1995
1994
  }
1996
1995
  const mergeResult = await mergeBranch(
1997
1996
  opts.repoRoot,
@@ -2107,30 +2106,28 @@ async function runTicketAttempt(opts) {
2107
2106
  branchName: worktree.branchName
2108
2107
  };
2109
2108
  }
2110
- if (opts.testCmd) {
2111
- const passed = await runTestGate({
2112
- testCmd: opts.testCmd,
2113
- ticket,
2114
- worktreePath: worktree.worktreePath,
2115
- timeout: opts.timeout,
2116
- logsDir: opts.logsDir,
2117
- attempt: opts.attempt,
2118
- log: /* @__PURE__ */ __name((msg) => d.log(msg), "log"),
2119
- registry: runningAgents
2120
- });
2121
- if (!passed) {
2122
- await removeWorktreeQuietly(
2123
- worktree.worktreePath,
2124
- d
2125
- );
2126
- return {
2127
- kind: "failed",
2128
- reason: "tests",
2129
- branchName: worktree.branchName,
2130
- exitCode: 1,
2131
- completedItems: agentResult.completedItems
2132
- };
2133
- }
2109
+ const passed = await runTestGate({
2110
+ testCmd: opts.testCmd,
2111
+ ticket,
2112
+ worktreePath: worktree.worktreePath,
2113
+ timeout: opts.timeout,
2114
+ logsDir: opts.logsDir,
2115
+ attempt: opts.attempt,
2116
+ log: /* @__PURE__ */ __name((msg) => d.log(msg), "log"),
2117
+ registry: runningAgents
2118
+ });
2119
+ if (!passed) {
2120
+ await removeWorktreeQuietly(
2121
+ worktree.worktreePath,
2122
+ d
2123
+ );
2124
+ return {
2125
+ kind: "failed",
2126
+ reason: "tests",
2127
+ branchName: worktree.branchName,
2128
+ exitCode: 1,
2129
+ completedItems: agentResult.completedItems
2130
+ };
2134
2131
  }
2135
2132
  return {
2136
2133
  kind: "ready",
@@ -2204,7 +2201,7 @@ function runProgress(tickets) {
2204
2201
  };
2205
2202
  }
2206
2203
  __name(runProgress, "runProgress");
2207
- async function runWaves(tickets, specBody, agentCmd, model, timeout, logsDir, display, maxTurns, effort, retries, retryDelay) {
2204
+ async function runWaves(tickets, specBody, agentCmd, model, timeout, logsDir, testCmd, display, maxTurns, effort, retries, retryDelay) {
2208
2205
  mkdirSync2(logsDir, { recursive: true });
2209
2206
  const d = display ?? createDisplay();
2210
2207
  const maxAttempts = (retries ?? DEFAULT_RETRIES) + 1;
@@ -2241,7 +2238,11 @@ async function runWaves(tickets, specBody, agentCmd, model, timeout, logsDir, di
2241
2238
  );
2242
2239
  const results = await Promise.allSettled(
2243
2240
  ready.map(async (t) => {
2244
- const prompt = renderPrompt(specBody, t);
2241
+ const prompt = renderPrompt(
2242
+ specBody,
2243
+ t,
2244
+ { testCmd }
2245
+ );
2245
2246
  const label = t.filename.replace(
2246
2247
  /\.md$/,
2247
2248
  ""
@@ -2368,9 +2369,6 @@ async function runWavesIsolated(opts) {
2368
2369
  `nightralph: start ${opts.featureName}`,
2369
2370
  d
2370
2371
  );
2371
- if (!opts.testCmd) {
2372
- d.log(" Test gate disabled: no test command");
2373
- }
2374
2372
  let totalCompleted = 0;
2375
2373
  let waveNum = 0;
2376
2374
  const failedNums = /* @__PURE__ */ new Set();
@@ -2823,7 +2821,7 @@ yargs(hideBin(process.argv)).scriptName("nightralph").usage("$0 <command>").comm
2823
2821
  default: 3600
2824
2822
  }).option("test-cmd", {
2825
2823
  type: "string",
2826
- describe: 'Command run in each worktree after the agent exits; non-zero exit rejects the ticket. Defaults to "npm test" when package.json has a test script. Pass "" to disable.'
2824
+ describe: 'Command run in each worktree after the agent exits; non-zero exit rejects the ticket. Defaults to "npm test".'
2827
2825
  }).option("X", {
2828
2826
  type: "boolean",
2829
2827
  describe: "Stop on merge conflict instead of re-spawning",
@@ -2918,9 +2916,9 @@ async function runExecute(argv) {
2918
2916
  }
2919
2917
  const logsDir = join6(dirname3(dir), "logs");
2920
2918
  const timeout = argv.timeout ?? 900;
2921
- const testCmd = argv.testCmd === void 0 ? detectTestCmd(
2919
+ const testCmd = argv.testCmd || detectTestCmd(
2922
2920
  isGitRepo() ? getRepoRoot() : process.cwd()
2923
- ) : argv.testCmd || null;
2921
+ ) || "npm test";
2924
2922
  const featureName = extractFeatureName(spec);
2925
2923
  const conflictStrategy = argv.stopOnConflict ? "stop" : "respawn";
2926
2924
  const progressPath = join6(
@@ -2942,7 +2940,7 @@ async function runExecute(argv) {
2942
2940
  retryDelay: argv.retryDelay
2943
2941
  });
2944
2942
  } else {
2945
- dryRun(tickets, specBody);
2943
+ dryRun(tickets, specBody, testCmd);
2946
2944
  }
2947
2945
  return;
2948
2946
  }
@@ -2981,6 +2979,7 @@ async function runExecute(argv) {
2981
2979
  argv.model ?? null,
2982
2980
  timeout,
2983
2981
  logsDir,
2982
+ testCmd,
2984
2983
  display,
2985
2984
  argv.maxTurns,
2986
2985
  argv.effort,