nightralph 0.0.21 → 0.0.23

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/dist/index.js CHANGED
@@ -27,7 +27,8 @@ var SKILL_DIRS = [
27
27
  "domain-modeling",
28
28
  "to-spec",
29
29
  "to-tickets",
30
- "tdd"
30
+ "tdd",
31
+ "codebase-design"
31
32
  ];
32
33
  var DOC_TEMPLATES = [
33
34
  "triage-labels.md",
@@ -295,7 +296,7 @@ function createWorktree(opts) {
295
296
  return result;
296
297
  }
297
298
  __name(createWorktree, "createWorktree");
298
- async function removeWorktree(worktreePath, opts) {
299
+ async function removeWorktreeNow(worktreePath, opts) {
299
300
  const args = [
300
301
  "-C",
301
302
  worktreePath,
@@ -306,6 +307,15 @@ async function removeWorktree(worktreePath, opts) {
306
307
  args.push(worktreePath);
307
308
  await execFileAsync("git", args);
308
309
  }
310
+ __name(removeWorktreeNow, "removeWorktreeNow");
311
+ function removeWorktree(worktreePath, opts) {
312
+ const result = worktreeQueue.then(
313
+ () => removeWorktreeNow(worktreePath, opts)
314
+ );
315
+ worktreeQueue = result.catch(() => {
316
+ });
317
+ return result;
318
+ }
309
319
  __name(removeWorktree, "removeWorktree");
310
320
  function hasNewCommits(repoRoot, base, branch) {
311
321
  const stdout = execFileSync(
@@ -1024,6 +1034,9 @@ function runTestCmd(opts) {
1024
1034
  stdio: ["ignore", "pipe", "pipe"],
1025
1035
  detached: true
1026
1036
  });
1037
+ if (child.pid !== void 0 && opts.registry) {
1038
+ opts.registry.add(child.pid);
1039
+ }
1027
1040
  const chunks = [];
1028
1041
  child.stdout.on("data", (d) => chunks.push(String(d)));
1029
1042
  child.stderr.on("data", (d) => chunks.push(String(d)));
@@ -1042,6 +1055,9 @@ function runTestCmd(opts) {
1042
1055
  if (settled) return;
1043
1056
  settled = true;
1044
1057
  clearTimeout(timer);
1058
+ if (child.pid !== void 0 && opts.registry) {
1059
+ opts.registry.delete(child.pid);
1060
+ }
1045
1061
  chunks.push(String(err));
1046
1062
  resolve({
1047
1063
  exitCode: 1,
@@ -1052,6 +1068,9 @@ function runTestCmd(opts) {
1052
1068
  if (settled) return;
1053
1069
  settled = true;
1054
1070
  clearTimeout(timer);
1071
+ if (child.pid !== void 0 && opts.registry) {
1072
+ opts.registry.delete(child.pid);
1073
+ }
1055
1074
  resolve({
1056
1075
  exitCode: code ?? 1,
1057
1076
  output: chunks.join("")
@@ -1242,6 +1261,7 @@ function renderMergePrompt(specBody, ticket) {
1242
1261
  "3. Commit the resolved files.",
1243
1262
  "",
1244
1263
  "Do NOT re-implement the ticket from scratch.",
1264
+ "Do NOT read or modify files outside your current directory (the worktree).",
1245
1265
  "Do NOT run git push."
1246
1266
  ].join("\n");
1247
1267
  }
@@ -1623,6 +1643,7 @@ function spawnAgent(opts) {
1623
1643
  __name(finish, "finish");
1624
1644
  proc.on("exit", (code) => {
1625
1645
  graceTimer = setTimeout(() => {
1646
+ killProcessGroup(proc.pid);
1626
1647
  proc.stdout.destroy();
1627
1648
  proc.stderr.destroy();
1628
1649
  finish(code ?? 1);
@@ -1733,7 +1754,7 @@ Test command: ${opts.testCmd ?? "(none)"}`
1733
1754
  `Retries: ${opts.retries ?? DEFAULT_RETRIES}`
1734
1755
  );
1735
1756
  console.log(
1736
- `Retry delay: ${opts.retryDelay ?? DEFAULT_RETRY_DELAY}s`
1757
+ `Retry delay: ${opts.retryDelay ?? 0}s`
1737
1758
  );
1738
1759
  console.log(
1739
1760
  `
@@ -1746,7 +1767,8 @@ async function runTestGate(opts) {
1746
1767
  const result = await runTestCmd({
1747
1768
  cmd: opts.testCmd,
1748
1769
  cwd: opts.worktreePath,
1749
- timeout: opts.timeout
1770
+ timeout: opts.timeout,
1771
+ registry: opts.registry
1750
1772
  });
1751
1773
  const testLogPath = attemptLogPath(
1752
1774
  opts.logsDir,
@@ -1822,7 +1844,8 @@ async function respawnAndRetryMerge(opts) {
1822
1844
  worktreePath: opts.worktreePath,
1823
1845
  timeout: opts.timeout,
1824
1846
  logsDir: opts.logsDir,
1825
- log
1847
+ log,
1848
+ registry: runningAgents
1826
1849
  });
1827
1850
  if (!passed) {
1828
1851
  log(
@@ -1938,7 +1961,12 @@ async function runTicketAttempt(opts) {
1938
1961
  opts.baseBranch,
1939
1962
  worktree.branchName
1940
1963
  )) {
1941
- return { kind: "no-commits" };
1964
+ await removeWorktreeQuietly(worktree.worktreePath, d);
1965
+ return {
1966
+ kind: "no-commits",
1967
+ worktreePath: worktree.worktreePath,
1968
+ branchName: worktree.branchName
1969
+ };
1942
1970
  }
1943
1971
  if (opts.testCmd) {
1944
1972
  const passed = await runTestGate({
@@ -1948,7 +1976,8 @@ async function runTicketAttempt(opts) {
1948
1976
  timeout: opts.timeout,
1949
1977
  logsDir: opts.logsDir,
1950
1978
  attempt: opts.attempt,
1951
- log: /* @__PURE__ */ __name((msg) => d.log(msg), "log")
1979
+ log: /* @__PURE__ */ __name((msg) => d.log(msg), "log"),
1980
+ registry: runningAgents
1952
1981
  });
1953
1982
  if (!passed) {
1954
1983
  await removeWorktreeQuietly(
@@ -1977,7 +2006,11 @@ async function runTicketAttempts(opts) {
1977
2006
  const maxAttempts = opts.retries + 1;
1978
2007
  const isPi = basename2(opts.agentCmd) === "pi";
1979
2008
  let thinking = opts.thinking;
1980
- let outcome = { kind: "no-commits" };
2009
+ let outcome = {
2010
+ kind: "no-commits",
2011
+ worktreePath: "",
2012
+ branchName: ""
2013
+ };
1981
2014
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1982
2015
  if (attempt === 1) {
1983
2016
  d.log(` Starting ${ticket.filename}`);
@@ -2238,6 +2271,18 @@ async function runWavesIsolated(opts) {
2238
2271
  d.log(
2239
2272
  ` ${ticket.filename}: failed to create worktree: ${formatErrorMessage(outcome.error)}`
2240
2273
  );
2274
+ checkTicket(progress, ticket.num, {
2275
+ branch: "",
2276
+ exitCode: -1,
2277
+ done: false
2278
+ });
2279
+ await saveProgress(
2280
+ repoRoot,
2281
+ progressPath,
2282
+ progress,
2283
+ `nightralph: ${ticket.filename} worktree error`,
2284
+ d
2285
+ );
2241
2286
  continue;
2242
2287
  }
2243
2288
  if (outcome.kind === "error") {
@@ -2246,6 +2291,18 @@ async function runWavesIsolated(opts) {
2246
2291
  d.log(
2247
2292
  ` ${ticket.filename}: attempt error: ` + formatErrorMessage(outcome.error)
2248
2293
  );
2294
+ checkTicket(progress, ticket.num, {
2295
+ branch: outcome.branchName ?? "",
2296
+ exitCode: -1,
2297
+ done: false
2298
+ });
2299
+ await saveProgress(
2300
+ repoRoot,
2301
+ progressPath,
2302
+ progress,
2303
+ `nightralph: ${ticket.filename} error`,
2304
+ d
2305
+ );
2249
2306
  continue;
2250
2307
  }
2251
2308
  if (outcome.kind === "no-commits") {
@@ -2254,6 +2311,18 @@ async function runWavesIsolated(opts) {
2254
2311
  d.log(
2255
2312
  ` ${ticket.filename}: agent exited 0 but made no changes; leaving ticket ready-for-agent`
2256
2313
  );
2314
+ checkTicket(progress, ticket.num, {
2315
+ branch: outcome.branchName,
2316
+ exitCode: 0,
2317
+ done: false
2318
+ });
2319
+ await saveProgress(
2320
+ repoRoot,
2321
+ progressPath,
2322
+ progress,
2323
+ `nightralph: ${ticket.filename} no commits`,
2324
+ d
2325
+ );
2257
2326
  continue;
2258
2327
  }
2259
2328
  if (outcome.kind === "failed") {