nexrall-code 0.5.159 → 0.5.161

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 (2) hide show
  1. package/dist/index.js +108 -24
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10369,9 +10369,18 @@ var require_client = __commonJS({
10369
10369
  const haveCompleteMessage = () => completedMessage !== null;
10370
10370
  const partialInputs = {};
10371
10371
  let heartbeatWatchdog;
10372
+ let onControllerAbort;
10372
10373
  try {
10373
10374
  await new Promise((resolve11, reject) => {
10374
10375
  const stream = response.body;
10376
+ onControllerAbort = () => {
10377
+ stream.destroy?.();
10378
+ resolve11();
10379
+ };
10380
+ if (controller.signal.aborted)
10381
+ onControllerAbort();
10382
+ else
10383
+ controller.signal.addEventListener("abort", onControllerAbort, { once: true });
10375
10384
  const HEARTBEAT_TIMEOUT_MS = 9e4;
10376
10385
  const FIRST_EVENT_TIMEOUT_MS = Number(process.env.NEXRALL_FIRST_EVENT_TIMEOUT_MS) || 3e5;
10377
10386
  const PROGRESS_TIMEOUT_MS = Number(process.env.NEXRALL_PROGRESS_TIMEOUT_MS) || 15e4;
@@ -10646,6 +10655,8 @@ var require_client = __commonJS({
10646
10655
  } finally {
10647
10656
  if (heartbeatWatchdog !== void 0)
10648
10657
  clearInterval(heartbeatWatchdog);
10658
+ if (onControllerAbort)
10659
+ controller.signal.removeEventListener("abort", onControllerAbort);
10649
10660
  }
10650
10661
  if (completedMessage) {
10651
10662
  return completedMessage;
@@ -172524,6 +172535,8 @@ function jobState(dir, m2) {
172524
172535
  if (Number.isFinite(n))
172525
172536
  return { state: n === 0 ? "done" : "failed", exitCode: n };
172526
172537
  }
172538
+ if (fs25.existsSync(path25.join(dir, `${m2.id}.killed`)))
172539
+ return { state: alive(m2.pid) ? "running" : "killed" };
172527
172540
  return { state: alive(m2.pid) ? "running" : "lost" };
172528
172541
  }
172529
172542
  function listJobs(dir = bgDir()) {
@@ -172574,9 +172587,13 @@ function startJob(o) {
172574
172587
  fs25.writeFileSync(path25.join(dir, `${id}.json`), JSON.stringify(meta));
172575
172588
  return meta;
172576
172589
  }
172577
- function killJob(job) {
172590
+ function killJob(job, dir = bgDir()) {
172578
172591
  if (job.state !== "running")
172579
172592
  return false;
172593
+ try {
172594
+ fs25.writeFileSync(path25.join(dir, `${job.id}.killed`), "");
172595
+ } catch {
172596
+ }
172580
172597
  try {
172581
172598
  process.kill(-job.pid, "SIGTERM");
172582
172599
  return true;
@@ -172601,9 +172618,67 @@ function formatJobs(jobs) {
172601
172618
  return `${j.id} ${st.padEnd(11)} ${ago(j.startedAt).padStart(4)} ago ${j.prompt.replace(/\s+/g, " ").slice(0, 60)}`;
172602
172619
  }).join("\n");
172603
172620
  }
172604
- async function followLog(job, follow, write = (s2) => process.stdout.write(s2), dir = bgDir()) {
172621
+ function renderJobLine(line) {
172622
+ const t2 = line.trim();
172623
+ if (!t2)
172624
+ return "";
172625
+ let o;
172626
+ try {
172627
+ o = JSON.parse(t2);
172628
+ } catch {
172629
+ return line + "\n";
172630
+ }
172631
+ switch (o.type) {
172632
+ case "start":
172633
+ return `\u2500\u2500 started (${o.model ?? "model"})
172634
+ `;
172635
+ case "text":
172636
+ return o.text ?? "";
172637
+ case "tool_use": {
172638
+ const inp = o.input && typeof o.input === "object" ? Object.values(o.input).find((v) => typeof v === "string") : void 0;
172639
+ return `
172640
+ \u25B8 ${o.tool}${inp ? " " + inp.replace(/\s+/g, " ").slice(0, 80) : ""}
172641
+ `;
172642
+ }
172643
+ case "tool_result":
172644
+ return o.ok === false ? ` \u2717 ${o.tool}: ${o.error ?? "failed"}
172645
+ ` : ` \u2713 ${o.tool}
172646
+ `;
172647
+ case "permission_denied":
172648
+ return ` \u2717 denied: ${o.tool ?? ""} ${o.reason ?? ""}
172649
+ `;
172650
+ case "error":
172651
+ return `
172652
+ \u2717 error: ${o.error ?? ""}
172653
+ `;
172654
+ case "budget_exceeded":
172655
+ return "\n\u2717 budget exceeded\n";
172656
+ case "result":
172657
+ return `
172658
+ \u2500\u2500 done
172659
+ `;
172660
+ default:
172661
+ return "";
172662
+ }
172663
+ }
172664
+ async function followLog(job, follow, write = (s2) => process.stdout.write(s2), dir = bgDir(), pretty = false) {
172605
172665
  const log = path25.join(dir, `${job.id}.log`);
172606
172666
  let pos = 0;
172667
+ let carry = "";
172668
+ const emit = (chunk) => {
172669
+ if (!pretty) {
172670
+ write(chunk);
172671
+ return;
172672
+ }
172673
+ carry += chunk;
172674
+ const lines = carry.split("\n");
172675
+ carry = lines.pop() ?? "";
172676
+ for (const l2 of lines) {
172677
+ const r2 = renderJobLine(l2);
172678
+ if (r2)
172679
+ write(r2);
172680
+ }
172681
+ };
172607
172682
  const drain = () => {
172608
172683
  let size = 0;
172609
172684
  try {
@@ -172617,7 +172692,7 @@ async function followLog(job, follow, write = (s2) => process.stdout.write(s2),
172617
172692
  try {
172618
172693
  const buf = Buffer.alloc(size - pos);
172619
172694
  fs25.readSync(fd, buf, 0, buf.length, pos);
172620
- write(buf.toString("utf8"));
172695
+ emit(buf.toString("utf8"));
172621
172696
  pos = size;
172622
172697
  } finally {
172623
172698
  fs25.closeSync(fd);
@@ -172631,7 +172706,12 @@ async function followLog(job, follow, write = (s2) => process.stdout.write(s2),
172631
172706
  drain();
172632
172707
  if (st.state !== "running") {
172633
172708
  drain();
172634
- return st.exitCode ?? (st.state === "lost" ? 1 : 0);
172709
+ if (carry) {
172710
+ const r2 = pretty ? renderJobLine(carry) : carry;
172711
+ if (r2)
172712
+ write(r2);
172713
+ }
172714
+ return st.exitCode ?? (st.state === "done" ? 0 : 1);
172635
172715
  }
172636
172716
  await new Promise((r2) => setTimeout(r2, 300));
172637
172717
  }
@@ -172883,13 +172963,13 @@ program2.command("logs <id>").description("Print a background job's output").opt
172883
172963
  }
172884
172964
  process.exit(await followLog(r2.job, !!opts.follow));
172885
172965
  });
172886
- program2.command("attach <id>").description("Follow a background job live (Ctrl+C detaches; the job keeps running)").action(async (id) => {
172966
+ program2.command("attach <id>").description("Watch a background job live, readable (tool calls, text, result). Ctrl+C detaches; the job keeps running").action(async (id) => {
172887
172967
  const r2 = resolveJob(id);
172888
172968
  if (!r2.ok) {
172889
172969
  console.error(r2.error);
172890
172970
  process.exit(1);
172891
172971
  }
172892
- process.exit(await followLog(r2.job, true));
172972
+ process.exit(await followLog(r2.job, true, void 0, void 0, true));
172893
172973
  });
172894
172974
  program2.command("kill <id>").description("Stop a background job").action((id) => {
172895
172975
  const r2 = resolveJob(id);
@@ -173100,24 +173180,6 @@ program2.option("-p, --pro", "Use Claude Opus 5.5 (most capable)").option("-t, -
173100
173180
  console.error("--strict-mcp-config needs --mcp-config.");
173101
173181
  process.exit(1);
173102
173182
  }
173103
- if (options.bg) {
173104
- if (!promptParts.length) {
173105
- console.error('--bg needs a prompt: nex --bg "your task"');
173106
- process.exit(1);
173107
- }
173108
- if (process.env.NEXRALL_BG_JOB) {
173109
- console.error("--bg cannot be nested inside a background job.");
173110
- process.exit(1);
173111
- }
173112
- const args = stripBgFlag(process.argv.slice(2));
173113
- if (!options.outputFormat)
173114
- args.push("--output-format", "stream-json");
173115
- const job = startJob({ script: process.argv[1], args, cwd: process.cwd(), prompt: promptParts.join(" ") });
173116
- console.log(`Started background job ${job.id}`);
173117
- console.log(` nex logs ${job.id} -f follow its output`);
173118
- console.log(` nex jobs list jobs \xB7 nex kill ${job.id} stop it`);
173119
- process.exit(0);
173120
- }
173121
173183
  const addDirs = parseAddDirs(options.addDir, process.cwd());
173122
173184
  if (!addDirs.ok) {
173123
173185
  console.error(addDirs.error);
@@ -173142,6 +173204,28 @@ program2.option("-p, --pro", "Use Claude Opus 5.5 (most capable)").option("-t, -
173142
173204
  console.error(`Invalid --input-format "${options.inputFormat}". Use: text | stream-json`);
173143
173205
  process.exit(1);
173144
173206
  }
173207
+ if (options.bg) {
173208
+ if (!promptParts.length) {
173209
+ console.error('--bg needs a prompt: nex --bg "your task"');
173210
+ process.exit(1);
173211
+ }
173212
+ if (inFmt === "stream-json") {
173213
+ console.error("--bg cannot read stream-json from stdin (a background job has no stdin). Pass the prompt as an argument.");
173214
+ process.exit(1);
173215
+ }
173216
+ if (process.env.NEXRALL_BG_JOB) {
173217
+ console.error("--bg cannot be nested inside a background job.");
173218
+ process.exit(1);
173219
+ }
173220
+ const args = stripBgFlag(process.argv.slice(2));
173221
+ if (!options.outputFormat)
173222
+ args.push("--output-format", "stream-json");
173223
+ const job = startJob({ script: process.argv[1], args, cwd: process.cwd(), prompt: promptParts.join(" ") });
173224
+ console.log(`Started background job ${job.id}`);
173225
+ console.log(` nex logs ${job.id} -f follow its output`);
173226
+ console.log(` nex jobs list jobs \xB7 nex kill ${job.id} stop it`);
173227
+ process.exit(0);
173228
+ }
173145
173229
  const resume = options.resume === true ? "last" : typeof options.resume === "string" ? options.resume : void 0;
173146
173230
  const worktree = options.worktree === true ? true : typeof options.worktree === "string" ? options.worktree : void 0;
173147
173231
  let stdinText;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexrall-code",
3
- "version": "0.5.159",
3
+ "version": "0.5.161",
4
4
  "description": "Nexrall Code — AI coding assistant for your terminal (headless agent for scripts, CI and automation)",
5
5
  "keywords": [
6
6
  "ai",