@kernlang/agon 0.1.6 → 0.1.8

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 (55) hide show
  1. package/dist/{chunk-XWHC6VAH.js → chunk-45YTXJWJ.js} +1 -1
  2. package/dist/chunk-45YTXJWJ.js.map +1 -0
  3. package/dist/{chunk-TMNHJOKU.js → chunk-BPKY4OF2.js} +74 -3
  4. package/dist/chunk-BPKY4OF2.js.map +1 -0
  5. package/dist/{chunk-7WZ2O5WZ.js → chunk-CQBQPSE4.js} +4 -4
  6. package/dist/chunk-CQBQPSE4.js.map +1 -0
  7. package/dist/{chunk-6IF2AV4Y.js → chunk-GHAMYNRC.js} +104 -47
  8. package/dist/chunk-GHAMYNRC.js.map +1 -0
  9. package/dist/{chunk-3PDYVGRS.js → chunk-GMVFKWQA.js} +173 -14
  10. package/dist/chunk-GMVFKWQA.js.map +1 -0
  11. package/dist/{chunk-NBV37VMW.js → chunk-I2PMSXJ3.js} +2 -2
  12. package/dist/chunk-I2PMSXJ3.js.map +1 -0
  13. package/dist/{chunk-PUNBDLQO.js → chunk-KPU23NS2.js} +42 -8
  14. package/dist/chunk-KPU23NS2.js.map +1 -0
  15. package/dist/{chunk-HSPQEDHX.js → chunk-SUT2HDOY.js} +1 -1
  16. package/dist/chunk-SUT2HDOY.js.map +1 -0
  17. package/dist/{dispatch-S3CR5HKX.js → dispatch-J4RSWLXM.js} +2 -2
  18. package/dist/dispatch-J4RSWLXM.js.map +1 -0
  19. package/dist/{forge-GUOEJ5DJ.js → forge-5QSRUNW6.js} +6 -6
  20. package/dist/forge-5QSRUNW6.js.map +1 -0
  21. package/dist/index.js +536 -103
  22. package/dist/index.js.map +1 -1
  23. package/dist/mcp/engines/agy.json +43 -0
  24. package/dist/mcp/engines/aider.json +40 -0
  25. package/dist/mcp/engines/claude.json +79 -0
  26. package/dist/mcp/engines/codex.json +77 -0
  27. package/dist/mcp/engines/minimax-coding-plan-minimax-m3.json +27 -0
  28. package/dist/mcp/engines/mistral.json +44 -0
  29. package/dist/mcp/engines/ollama.json +35 -0
  30. package/dist/mcp/engines/opencode.json +55 -0
  31. package/dist/mcp/engines/openrouter.json +54 -0
  32. package/dist/mcp/engines/qwen.json +40 -0
  33. package/dist/mcp/index.js +464 -0
  34. package/dist/mcp/index.js.map +1 -0
  35. package/dist/plan-mode-5IQ2SKIS.js +17 -0
  36. package/dist/plan-mode-5IQ2SKIS.js.map +1 -0
  37. package/dist/{src-3NWTITZM.js → src-253BUXEF.js} +5 -3
  38. package/dist/src-253BUXEF.js.map +1 -0
  39. package/dist/{update-H3LE4ZSI.js → update-WLRTYR77.js} +6 -6
  40. package/dist/update-WLRTYR77.js.map +1 -0
  41. package/package.json +3 -4
  42. package/dist/chunk-3PDYVGRS.js.map +0 -1
  43. package/dist/chunk-6IF2AV4Y.js.map +0 -1
  44. package/dist/chunk-7WZ2O5WZ.js.map +0 -1
  45. package/dist/chunk-HSPQEDHX.js.map +0 -1
  46. package/dist/chunk-NBV37VMW.js.map +0 -1
  47. package/dist/chunk-PUNBDLQO.js.map +0 -1
  48. package/dist/chunk-TMNHJOKU.js.map +0 -1
  49. package/dist/chunk-XWHC6VAH.js.map +0 -1
  50. package/dist/dispatch-S3CR5HKX.js.map +0 -1
  51. package/dist/forge-GUOEJ5DJ.js.map +0 -1
  52. package/dist/plan-mode-35BONR7S.js +0 -17
  53. package/dist/plan-mode-35BONR7S.js.map +0 -1
  54. package/dist/src-3NWTITZM.js.map +0 -1
  55. package/dist/update-H3LE4ZSI.js.map +0 -1
package/dist/index.js CHANGED
@@ -26,7 +26,7 @@ import {
26
26
  parseProseToRichLines,
27
27
  saveDismissedVersion,
28
28
  updateCommand
29
- } from "./chunk-6IF2AV4Y.js";
29
+ } from "./chunk-GHAMYNRC.js";
30
30
  import {
31
31
  buildAgentApprovalCallback,
32
32
  buildConsensus,
@@ -38,10 +38,10 @@ import {
38
38
  runAgentTeam,
39
39
  runReviewCore,
40
40
  selectReviewEngine
41
- } from "./chunk-PUNBDLQO.js";
41
+ } from "./chunk-KPU23NS2.js";
42
42
  import {
43
43
  parsePatchPreview
44
- } from "./chunk-HSPQEDHX.js";
44
+ } from "./chunk-SUT2HDOY.js";
45
45
  import {
46
46
  buildCheckpoint,
47
47
  createScoreboard,
@@ -54,7 +54,7 @@ import {
54
54
  renderScoreboard,
55
55
  scoreboardFailEngine,
56
56
  scoreboardFinishEngine
57
- } from "./chunk-7WZ2O5WZ.js";
57
+ } from "./chunk-CQBQPSE4.js";
58
58
  import {
59
59
  buildCesarSystemPrompt,
60
60
  buildOracleCheatPrompt,
@@ -65,8 +65,11 @@ import {
65
65
  codeBlockBuffer,
66
66
  deriveRoutingHints,
67
67
  filterDefaultOrchestrationEngines,
68
+ foldNarrationLines,
68
69
  formatCesarReliabilityLine,
69
70
  formatModeRationale,
71
+ getFoldedRaw,
72
+ getFoldedRawCount,
70
73
  goalDir,
71
74
  handleCesarBrain,
72
75
  handleOutputEvent,
@@ -105,7 +108,7 @@ import {
105
108
  synthesisRoutingAdvice,
106
109
  todosFromPlanSteps,
107
110
  yieldToInk
108
- } from "./chunk-3PDYVGRS.js";
111
+ } from "./chunk-GMVFKWQA.js";
109
112
  import {
110
113
  ENGINE_COLORS,
111
114
  bold,
@@ -127,7 +130,7 @@ import {
127
130
  truncateCodeLine,
128
131
  warn,
129
132
  yellow
130
- } from "./chunk-NBV37VMW.js";
133
+ } from "./chunk-I2PMSXJ3.js";
131
134
  import {
132
135
  AGON_HOME,
133
136
  CommandRegistry,
@@ -275,21 +278,23 @@ import {
275
278
  undoPatch,
276
279
  updateChatSummary,
277
280
  worktreeCreate,
281
+ worktreePruneAll,
282
+ worktreePruneOrphaned,
278
283
  worktreeRemoveBestEffort,
279
284
  writeProvenanceReport,
280
285
  writeRunStatus
281
- } from "./chunk-TMNHJOKU.js";
286
+ } from "./chunk-BPKY4OF2.js";
282
287
  import {
283
288
  apiDispatch,
284
289
  apiStreamDispatch
285
- } from "./chunk-XWHC6VAH.js";
290
+ } from "./chunk-45YTXJWJ.js";
286
291
 
287
292
  // src/index.ts
288
293
  import { defineCommand as defineCommand31, runMain } from "citty";
289
294
 
290
295
  // src/generated/commands/forge.ts
291
296
  import { defineCommand } from "citty";
292
- import { readFileSync } from "fs";
297
+ import { readFileSync as readFileSync2 } from "fs";
293
298
 
294
299
  // src/generated/lib/engines-dir.ts
295
300
  import { join, dirname } from "path";
@@ -313,9 +318,9 @@ import { writeFileSync, mkdirSync as mkdirSync2 } from "fs";
313
318
  import { join as join3, dirname as dirname3 } from "path";
314
319
 
315
320
  // ../adapter-cli/src/generated/adapter-helpers.ts
316
- import { statSync, mkdirSync, existsSync as existsSync2, copyFileSync, chmodSync, unlinkSync } from "fs";
321
+ import { statSync, mkdirSync, existsSync as existsSync2, copyFileSync, chmodSync, unlinkSync, readFileSync, mkdtempSync, rmSync } from "fs";
317
322
  import { join as join2, dirname as dirname2, basename } from "path";
318
- import { homedir } from "os";
323
+ import { homedir, tmpdir } from "os";
319
324
  function recordDispatchHealth(engineId, result) {
320
325
  const exitCode = result.exitCode ?? 0;
321
326
  if (exitCode === 0 && !result.timedOut) {
@@ -488,8 +493,8 @@ function buildCommand(engine, mode, prompt2, cwd, timeout, binaryPath, images) {
488
493
  }
489
494
  return { command: binaryPath, args };
490
495
  }
491
- function stripStreamJson(stdout) {
492
- const lines = stdout.split("\n");
496
+ function stripStreamJson(stdout2) {
497
+ const lines = stdout2.split("\n");
493
498
  const textParts = [];
494
499
  for (const line of lines) {
495
500
  const trimmed = line.trim();
@@ -543,6 +548,43 @@ ${systemPrompt}
543
548
  [User Message]
544
549
  ${prompt2}`;
545
550
  }
551
+ function answerChannelMode() {
552
+ const v = (process.env.AGON_CLAUDE_ANSWER_CHANNEL || "").trim().toLowerCase();
553
+ if (v === "off" || v === "0" || v === "false") return "off";
554
+ if (v === "mcp") return "mcp";
555
+ return "file";
556
+ }
557
+ function fileChannelInstruction(answerFile) {
558
+ return `
559
+
560
+ ---
561
+ [ANSWER DELIVERY \u2014 REQUIRED] After composing your COMPLETE final answer, use your Write tool to write that answer \u2014 markdown only, no preamble, no commentary, nothing but the answer itself \u2014 to this exact file path:
562
+ ${answerFile}
563
+ That file is the ONLY channel by which your answer is captured. Write it exactly once, at the very end. Do NOT skip it.`;
564
+ }
565
+ function readAnswerChannelFile(answerFile) {
566
+ try {
567
+ if (!existsSync2(answerFile)) return "";
568
+ const raw = readFileSync(answerFile, "utf-8");
569
+ if (!raw.trim()) return "";
570
+ const t = raw.trim();
571
+ if (t.startsWith("{")) {
572
+ try {
573
+ const parsed = JSON.parse(t);
574
+ if (parsed && typeof parsed.text === "string" && parsed.text.trim()) return parsed.text;
575
+ } catch {
576
+ }
577
+ }
578
+ return raw;
579
+ } catch {
580
+ return "";
581
+ }
582
+ }
583
+ function setupFileAnswerChannel(composed) {
584
+ const dir = mkdtempSync(join2(tmpdir(), "agon-ac-"));
585
+ const answerFile = join2(dir, "answer.md");
586
+ return { prompt: composed + fileChannelInstruction(answerFile), answerFile, dir };
587
+ }
546
588
  async function runClaudePtyDispatch(prompt2, timeoutSec, signal, mode, cwd, systemPrompt, env, extraArgv) {
547
589
  const start = Date.now();
548
590
  try {
@@ -587,18 +629,36 @@ async function runClaudePtyDispatch(prompt2, timeoutSec, signal, mode, cwd, syst
587
629
  }
588
630
  signal.addEventListener("abort", onAbort, { once: true });
589
631
  }
632
+ const useFileChannel = (mode ?? "exec") === "exec" && answerChannelMode() === "file";
633
+ let channelDir = "";
590
634
  try {
591
- const composed = composeClaudePtyPrompt(prompt2, systemPrompt);
592
- const text = await session.ask(composed, timeoutSec * 1e3);
635
+ let composed = composeClaudePtyPrompt(prompt2, systemPrompt);
636
+ let answerFile = "";
637
+ if (useFileChannel) {
638
+ const ch = setupFileAnswerChannel(composed);
639
+ composed = ch.prompt;
640
+ answerFile = ch.answerFile;
641
+ channelDir = ch.dir;
642
+ }
643
+ const scraped = await session.ask(composed, timeoutSec * 1e3);
644
+ const channelText = useFileChannel ? readAnswerChannelFile(answerFile) : "";
645
+ if (useFileChannel && process.env.AGON_DEBUG) console.error(`[agon] answer-channel(file): ${channelText ? "hit " + channelText.length + "ch" : "miss \u2192 scrape fallback"}`);
646
+ const text = channelText || scraped;
593
647
  return {
594
648
  exitCode: 0,
595
649
  stdout: text,
596
- stderr: "",
650
+ stderr: channelText ? "" : useFileChannel ? "answer-channel: file empty, used scrape fallback" : "",
597
651
  durationMs: Date.now() - start,
598
652
  timedOut: false
599
653
  };
600
654
  } catch (e) {
601
655
  const isTimeout = e?.kind === "timeout" || e?.name === "ClaudeSessionTimeout";
656
+ if (useFileChannel && channelDir) {
657
+ const salvaged = readAnswerChannelFile(join2(channelDir, "answer.md"));
658
+ if (salvaged) {
659
+ return { exitCode: 0, stdout: salvaged, stderr: "answer-channel: salvaged from file after ask error", durationMs: Date.now() - start, timedOut: false };
660
+ }
661
+ }
602
662
  return {
603
663
  exitCode: isTimeout ? 124 : 1,
604
664
  stdout: "",
@@ -609,6 +669,12 @@ async function runClaudePtyDispatch(prompt2, timeoutSec, signal, mode, cwd, syst
609
669
  } finally {
610
670
  if (signal) signal.removeEventListener("abort", onAbort);
611
671
  await session.close().catch(() => void 0);
672
+ if (channelDir) {
673
+ try {
674
+ rmSync(channelDir, { recursive: true, force: true });
675
+ } catch {
676
+ }
677
+ }
612
678
  }
613
679
  } catch (e) {
614
680
  return {
@@ -665,18 +731,29 @@ async function* runClaudePtyStreamDispatch(prompt2, timeoutSec, signal, mode, cw
665
731
  }
666
732
  signal.addEventListener("abort", onAbort, { once: true });
667
733
  }
734
+ const useFileChannel = (mode ?? "exec") === "exec" && answerChannelMode() === "file";
735
+ let channelDir = "";
668
736
  const collected = [];
669
737
  try {
670
- const composed = composeClaudePtyPrompt(prompt2, systemPrompt);
738
+ let composed = composeClaudePtyPrompt(prompt2, systemPrompt);
739
+ let answerFile = "";
740
+ if (useFileChannel) {
741
+ const ch = setupFileAnswerChannel(composed);
742
+ composed = ch.prompt;
743
+ answerFile = ch.answerFile;
744
+ channelDir = ch.dir;
745
+ }
671
746
  const gen = session.askStream(composed, timeoutSec * 1e3);
672
747
  while (true) {
673
748
  const next = await gen.next();
674
749
  if (next.done) {
675
- const text = typeof next.value === "string" && next.value ? next.value : collected.join("");
750
+ const scraped = typeof next.value === "string" && next.value ? next.value : collected.join("");
751
+ const channelText = useFileChannel ? readAnswerChannelFile(answerFile) : "";
752
+ if (useFileChannel && process.env.AGON_DEBUG) console.error(`[agon] answer-channel(file): ${channelText ? "hit " + channelText.length + "ch" : "miss \u2192 scrape fallback"}`);
676
753
  return {
677
754
  exitCode: 0,
678
- stdout: text,
679
- stderr: "",
755
+ stdout: channelText || scraped,
756
+ stderr: channelText ? "" : useFileChannel ? "answer-channel: file empty, used scrape fallback" : "",
680
757
  durationMs: Date.now() - start,
681
758
  timedOut: false
682
759
  };
@@ -686,6 +763,10 @@ async function* runClaudePtyStreamDispatch(prompt2, timeoutSec, signal, mode, cw
686
763
  }
687
764
  } catch (e) {
688
765
  const isTimeout = e?.kind === "timeout" || e?.name === "ClaudeSessionTimeout";
766
+ const salvaged = useFileChannel && channelDir ? readAnswerChannelFile(join2(channelDir, "answer.md")) : "";
767
+ if (salvaged) {
768
+ return { exitCode: 0, stdout: salvaged, stderr: "answer-channel: salvaged from file after ask error", durationMs: Date.now() - start, timedOut: false };
769
+ }
689
770
  return {
690
771
  exitCode: isTimeout ? 124 : 1,
691
772
  stdout: collected.join(""),
@@ -696,6 +777,12 @@ async function* runClaudePtyStreamDispatch(prompt2, timeoutSec, signal, mode, cw
696
777
  } finally {
697
778
  if (signal) signal.removeEventListener("abort", onAbort);
698
779
  await session.close().catch(() => void 0);
780
+ if (channelDir) {
781
+ try {
782
+ rmSync(channelDir, { recursive: true, force: true });
783
+ } catch {
784
+ }
785
+ }
699
786
  }
700
787
  } catch (e) {
701
788
  try {
@@ -725,7 +812,15 @@ var CliAdapter = class {
725
812
  this.isAvailable = this.isAvailable.bind(this);
726
813
  this.getVersion = this.getVersion.bind(this);
727
814
  }
815
+ withEngineTimeout(options) {
816
+ const declared = Number(options.engine?.timeout ?? 0);
817
+ if (declared > Number(options.timeout ?? 0)) {
818
+ return { ...options, timeout: declared };
819
+ }
820
+ return options;
821
+ }
728
822
  async dispatch(options) {
823
+ options = this.withEngineTimeout(options);
729
824
  const binaryPath = options.engine.binary ? this.registry.findBinary(options.engine) : null;
730
825
  if (!binaryPath) {
731
826
  if (options.engine.api) {
@@ -808,6 +903,7 @@ ${options.prompt}`;
808
903
  return result;
809
904
  }
810
905
  async *dispatchStream(options) {
906
+ options = this.withEngineTimeout(options);
811
907
  const iso = computeEngineIsolation(options.engine, { isolation: options.isolation, cwd: options.cwd });
812
908
  if (shouldUseClaudePty(options.engine)) {
813
909
  const gen2 = runClaudePtyStreamDispatch(options.prompt, options.timeout, options.signal, "exec", options.cwd, options.systemPrompt, iso.env, resolveClaudePtyExtraArgs(options.engine, options.cwd));
@@ -898,6 +994,7 @@ ${options.prompt}`;
898
994
  return result;
899
995
  }
900
996
  async dispatchAgent(options) {
997
+ options = this.withEngineTimeout(options);
901
998
  const iso = computeEngineIsolation(options.engine, { isolation: options.isolation, cwd: options.cwd });
902
999
  if (shouldUseClaudePty(options.engine)) {
903
1000
  const ptyStart = Date.now();
@@ -1042,6 +1139,7 @@ ${options.prompt}`;
1042
1139
  return { ...result, diff, diffLines: lines, filesChanged: files };
1043
1140
  }
1044
1141
  async *dispatchAgentStream(options) {
1142
+ options = this.withEngineTimeout(options);
1045
1143
  const iso = computeEngineIsolation(options.engine, { isolation: options.isolation, cwd: options.cwd });
1046
1144
  if (shouldUseClaudePty(options.engine)) {
1047
1145
  const baselineDiff2 = readOnlyDiff(options.cwd);
@@ -1458,7 +1556,7 @@ var forgeCommand = defineCommand({
1458
1556
  const patchPath = manifest.patches[manifest.winner];
1459
1557
  let winnerDiff = "";
1460
1558
  try {
1461
- winnerDiff = patchPath ? readFileSync(patchPath, "utf-8") : "";
1559
+ winnerDiff = patchPath ? readFileSync2(patchPath, "utf-8") : "";
1462
1560
  } catch (err) {
1463
1561
  warn(`Judge: could not read winner patch (${err instanceof Error ? err.message : String(err)})`);
1464
1562
  }
@@ -2315,7 +2413,7 @@ var leaderboardCommand = defineCommand8({
2315
2413
 
2316
2414
  // src/generated/commands/history.ts
2317
2415
  import { defineCommand as defineCommand9 } from "citty";
2318
- import { readdirSync, readFileSync as readFileSync2 } from "fs";
2416
+ import { readdirSync, readFileSync as readFileSync3 } from "fs";
2319
2417
  import { join as join7 } from "path";
2320
2418
  function showRunDetail(id) {
2321
2419
  let files;
@@ -2330,7 +2428,7 @@ function showRunDetail(id) {
2330
2428
  return;
2331
2429
  }
2332
2430
  const manifest = JSON.parse(
2333
- readFileSync2(join7(RUNS_DIR, files[0]), "utf-8")
2431
+ readFileSync3(join7(RUNS_DIR, files[0]), "utf-8")
2334
2432
  );
2335
2433
  header(`Forge Run: ${manifest.forgeId.slice(0, 8)}`);
2336
2434
  console.log(` Task: ${manifest.task}`);
@@ -2411,7 +2509,7 @@ var historyCommand = defineCommand9({
2411
2509
  for (const file of filesToLoad) {
2412
2510
  try {
2413
2511
  const manifest = JSON.parse(
2414
- readFileSync2(join7(RUNS_DIR, file), "utf-8")
2512
+ readFileSync3(join7(RUNS_DIR, file), "utf-8")
2415
2513
  );
2416
2514
  if (typeof manifest?.forgeId !== "string" || typeof manifest?.task !== "string" || typeof manifest?.timestamp !== "string") {
2417
2515
  throw new Error("manifest missing forgeId/task/timestamp");
@@ -2809,7 +2907,7 @@ ${transcript}`;
2809
2907
 
2810
2908
  // src/generated/commands/provenance.ts
2811
2909
  import { defineCommand as defineCommand11 } from "citty";
2812
- import { readdirSync as readdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
2910
+ import { readdirSync as readdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
2813
2911
  import { join as join8 } from "path";
2814
2912
  var provenanceCommand = defineCommand11({
2815
2913
  meta: {
@@ -2870,7 +2968,7 @@ var provenanceCommand = defineCommand11({
2870
2968
  const manifestPath = join8(RUNS_DIR, file);
2871
2969
  let manifest;
2872
2970
  try {
2873
- manifest = JSON.parse(readFileSync3(manifestPath, "utf-8"));
2971
+ manifest = JSON.parse(readFileSync4(manifestPath, "utf-8"));
2874
2972
  } catch (e) {
2875
2973
  info(`Could not read run ${file}: ${e instanceof Error ? e.message : String(e)}`);
2876
2974
  return;
@@ -3077,8 +3175,8 @@ var engineCommand = defineCommand12({
3077
3175
  // src/generated/commands/doctor.ts
3078
3176
  import { defineCommand as defineCommand13 } from "citty";
3079
3177
  import { spawnSync } from "child_process";
3080
- import { mkdtempSync, rmSync, writeFileSync as writeFileSync3, existsSync as existsSync3 } from "fs";
3081
- import { tmpdir, homedir as homedir2 } from "os";
3178
+ import { mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync3, existsSync as existsSync3 } from "fs";
3179
+ import { tmpdir as tmpdir2, homedir as homedir2 } from "os";
3082
3180
  import { join as join10, basename as basename3 } from "path";
3083
3181
  import "url";
3084
3182
  function shellQuoteForDoctor(value) {
@@ -3237,7 +3335,7 @@ function checkDoctorWorktree(cwd) {
3237
3335
  try {
3238
3336
  root = repoRoot(cwd);
3239
3337
  const sha = headSha(cwd);
3240
- tempDir = mkdtempSync(join10(tmpdir(), "agon-doctor-"));
3338
+ tempDir = mkdtempSync2(join10(tmpdir2(), "agon-doctor-"));
3241
3339
  worktreePath = join10(tempDir, "worktree");
3242
3340
  worktreeCreate(root, worktreePath, sha);
3243
3341
  writeFileSync3(join10(worktreePath, ".agon-doctor-write-test"), "ok\n");
@@ -3262,7 +3360,7 @@ function checkDoctorWorktree(cwd) {
3262
3360
  }
3263
3361
  if (tempDir) {
3264
3362
  try {
3265
- rmSync(tempDir, { recursive: true, force: true });
3363
+ rmSync2(tempDir, { recursive: true, force: true });
3266
3364
  } catch {
3267
3365
  }
3268
3366
  }
@@ -3540,7 +3638,7 @@ var doctorCommand = defineCommand13({
3540
3638
 
3541
3639
  // src/generated/commands/last.ts
3542
3640
  import { defineCommand as defineCommand14 } from "citty";
3543
- import { readFileSync as readFileSync4, existsSync as existsSync4 } from "fs";
3641
+ import { readFileSync as readFileSync5, existsSync as existsSync4 } from "fs";
3544
3642
  import { join as join11 } from "path";
3545
3643
  var lastCommand = defineCommand14({
3546
3644
  meta: {
@@ -3589,7 +3687,7 @@ var lastCommand = defineCommand14({
3589
3687
  return;
3590
3688
  }
3591
3689
  try {
3592
- process.stdout.write(readFileSync4(statusPath, "utf-8"));
3690
+ process.stdout.write(readFileSync5(statusPath, "utf-8"));
3593
3691
  } catch (err) {
3594
3692
  process.stderr.write(`agon last: failed to read ${statusPath}: ${err instanceof Error ? err.message : String(err)}
3595
3693
  `);
@@ -3902,7 +4000,7 @@ var configCommand = defineCommand16({
3902
4000
 
3903
4001
  // src/commands/provider.ts
3904
4002
  import { defineCommand as defineCommand17 } from "citty";
3905
- import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync6, unlinkSync as unlinkSync2, readdirSync as readdirSync3, readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
4003
+ import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync6, unlinkSync as unlinkSync2, readdirSync as readdirSync3, readFileSync as readFileSync6, existsSync as existsSync5 } from "fs";
3906
4004
  import { join as join13 } from "path";
3907
4005
  import { homedir as homedir3 } from "os";
3908
4006
  import { createInterface } from "readline";
@@ -4229,7 +4327,7 @@ var providerCommand = defineCommand17({
4229
4327
  const rows = [];
4230
4328
  for (const file of files) {
4231
4329
  try {
4232
- const def = JSON.parse(readFileSync5(join13(dir, file), "utf-8"));
4330
+ const def = JSON.parse(readFileSync6(join13(dir, file), "utf-8"));
4233
4331
  if (def.api) {
4234
4332
  const hasKey = !!getAuthKey(def.api.apiKeyEnv);
4235
4333
  rows.push([
@@ -4359,6 +4457,7 @@ var reviewCommand = defineCommand18({
4359
4457
  const concurrencyNote = requested.length > 1 ? maxParallel >= requested.length ? "all in parallel" : `${maxParallel} at a time` : "single engine";
4360
4458
  if (!quiet) {
4361
4459
  header(`Review: ${target.label}`);
4460
+ info(`Repo: ${cwd}`);
4362
4461
  info(`Engines: ${requested.join(", ")} (${concurrencyNote})`);
4363
4462
  info(`Per-engine timeout: ${timeoutSec}s (auto-cancel, others unaffected)`);
4364
4463
  }
@@ -4399,7 +4498,7 @@ var reviewCommand = defineCommand18({
4399
4498
  ${body.join("\n")}`);
4400
4499
  };
4401
4500
  try {
4402
- const result = await runReviewCore(target.diff, target.label, engineId, ctx, controller.signal);
4501
+ const result = await runReviewCore(target.diff, target.label, engineId, ctx, controller.signal, void 0, cwd);
4403
4502
  const rawResponse = result.response ?? "";
4404
4503
  writeOutput(rawResponse);
4405
4504
  if (timedOut) {
@@ -5192,7 +5291,7 @@ var installAgentPromptsCommand = defineCommand21({
5192
5291
 
5193
5292
  // src/generated/commands/goal.ts
5194
5293
  import { defineCommand as defineCommand22 } from "citty";
5195
- import { readFileSync as readFileSync6, readdirSync as readdirSync4, existsSync as existsSync7, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
5294
+ import { readFileSync as readFileSync7, readdirSync as readdirSync4, existsSync as existsSync7, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
5196
5295
  import { resolve } from "path";
5197
5296
  var goalCommand = (() => {
5198
5297
  const slug = (s) => String(s ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 128);
@@ -5218,12 +5317,12 @@ var goalCommand = (() => {
5218
5317
  });
5219
5318
  }
5220
5319
  if (abs.endsWith(".json")) {
5221
- const parsed = JSON.parse(readFileSync6(abs, "utf-8"));
5320
+ const parsed = JSON.parse(readFileSync7(abs, "utf-8"));
5222
5321
  const arr = Array.isArray(parsed) ? parsed : parsed && Array.isArray(parsed.tasks) ? parsed.tasks : [parsed];
5223
5322
  return arr.map((o, i) => toTask(o, i));
5224
5323
  }
5225
5324
  if (abs.endsWith(".jsonl")) {
5226
- return readFileSync6(abs, "utf-8").split("\n").map((l) => l.trim()).filter(Boolean).map((line, i) => {
5325
+ return readFileSync7(abs, "utf-8").split("\n").map((l) => l.trim()).filter(Boolean).map((line, i) => {
5227
5326
  try {
5228
5327
  return toTask(JSON.parse(line), i);
5229
5328
  } catch (e) {
@@ -5601,7 +5700,7 @@ Return ONLY a JSON array of the engine ids that should COMPETE on this task \u20
5601
5700
  const patches = manifest.patches;
5602
5701
  const readPatchPath = (p) => {
5603
5702
  try {
5604
- return p ? readFileSync6(p, "utf-8") : "";
5703
+ return p ? readFileSync7(p, "utf-8") : "";
5605
5704
  } catch {
5606
5705
  return "";
5607
5706
  }
@@ -5859,6 +5958,10 @@ judge ${judge} errored (${e instanceof Error ? e.message : String(e)}); ${consen
5859
5958
  }
5860
5959
  } finally {
5861
5960
  process.removeListener("SIGINT", onSig);
5961
+ try {
5962
+ worktreePruneOrphaned(repoRoot2);
5963
+ } catch (e) {
5964
+ }
5862
5965
  }
5863
5966
  }
5864
5967
  });
@@ -7019,9 +7122,20 @@ var worktreeCommand = defineCommand29({
7019
7122
  if (removed.length === 0) {
7020
7123
  info(`No session worktrees older than ${olderThan} (dirty worktrees are skipped unless --force).`);
7021
7124
  } else if (dryRun) {
7022
- info(`Would prune ${removed.length}: ${removed.join(", ")}`);
7125
+ info(`Would prune ${removed.length} session worktree(s): ${removed.join(", ")}`);
7023
7126
  } else {
7024
- success(`Pruned ${removed.length}: ${removed.join(", ")}`);
7127
+ success(`Pruned ${removed.length} session worktree(s): ${removed.join(", ")}`);
7128
+ }
7129
+ if (!dryRun) {
7130
+ try {
7131
+ worktreePruneAll(root, ms);
7132
+ worktreePruneOrphaned(root);
7133
+ success(`Pruned stale agent/competition worktrees and cleaned up registry.`);
7134
+ } catch (e) {
7135
+ warn(`Failed to prune agent/competition worktrees: ${e instanceof Error ? e.message : String(e)}`);
7136
+ }
7137
+ } else {
7138
+ info(`Would prune stale agent/competition worktrees older than ${olderThan}`);
7025
7139
  }
7026
7140
  break;
7027
7141
  }
@@ -7165,7 +7279,7 @@ import { Box as Box9, Static, Text as Text9, render } from "ink";
7165
7279
  import { ScrollBox, AlternateScreen } from "@kernlang/terminal/runtime";
7166
7280
 
7167
7281
  // src/generated/signals/intent.ts
7168
- var SLASH_COMMANDS = [{ cmd: "/forge", desc: "<task> test with <cmd> [--hardened] \u2014 competitive code generation" }, { cmd: "/brainstorm", desc: "<question> \u2014 confidence-bidding answers" }, { cmd: "/tribunal", desc: "[mode] <question> \u2014 debate (adversarial|socratic|red-team|steelman|synthesis|postmortem)" }, { cmd: "/campfire", desc: "<topic> \u2014 think together, no competition" }, { cmd: "/think", desc: "<problem> [--strategy reflexion] [--steps 8] \u2014 sequential thinking, one engine" }, { cmd: "/council", desc: "<decision> \u2014 roundtable: every engine a role, top-rated chairs" }, { cmd: "/synthesis", desc: "<task> [--swaps 2] \u2014 engines draft, swap, improve; judge picks winner" }, { cmd: "/workspace", desc: "add|remove|list|switch \u2014 manage project repos" }, { cmd: "/ws", desc: " \u2014 list workspaces (shortcut)" }, { cmd: "/cesar", desc: "<engine> \u2014 set Cesar brain engine (e.g. /cesar codex)" }, { cmd: "/models", desc: " \u2014 browse & add provider models + CLI models" }, { cmd: "/tokens", desc: " \u2014 show token usage & costs" }, { cmd: "/engines", desc: " \u2014 select active engines" }, { cmd: "/leaderboard", desc: " \u2014 Glicko rankings" }, { cmd: "/cesar-report", desc: " \u2014 Cesar routing calibration report" }, { cmd: "/cesar-hints", desc: "<task> \u2014 inspect Cesar routing hints for a prompt" }, { cmd: "/history", desc: "[id] \u2014 past forge runs" }, { cmd: "/config", desc: "[list|get|set] \u2014 settings" }, { cmd: "/plan", desc: "<task> or no args \u2014 plan mode or show plan" }, { cmd: "/auto", desc: "[on|off|toggle|status] or <task> \u2014 autonomous mode control" }, { cmd: "/plans", desc: " \u2014 list recent plans" }, { cmd: "/approve", desc: " \u2014 approve current plan" }, { cmd: "/retry", desc: " \u2014 retry failed plan step" }, { cmd: "/cancel", desc: " \u2014 cancel current plan" }, { cmd: "/apply", desc: "[path] [--force] \u2014 apply winning forge patch" }, { cmd: "/cp", desc: "[N] \u2014 copy code block N to clipboard" }, { cmd: "/img", desc: "<path> \u2014 attach image to next prompt" }, { cmd: "/flow", desc: " \u2014 log this session" }, { cmd: "/flows", desc: " \u2014 flow analytics dashboard" }, { cmd: "/chats", desc: "[id|resume <id>] \u2014 chat history or resume session" }, { cmd: "/build", desc: "<task> \u2014 agent builds in cwd (reads/edits/tests)" }, { cmd: "/goal", desc: '<intent> --queue <dir> --gate "<cmd>" [--push] \u2014 autonomous queue: build\u2192review(all)\u2192judge\u2192fix\u2192commit\u2192push per task (background job)' }, { cmd: "/conquer", desc: '<task> --gate "<cmd>" [--builder X] [-e a,b] \u2014 supervised-autonomous build: Cesar drives a builder CLI, convenes nero/tribunal/council on forks, stops at a human merge gate (background job)' }, { cmd: "/agent", desc: "<task> \u2014 autonomous agent loop (solo or shadow, auto-routed)" }, { cmd: "/agent-solo", desc: "<task> \u2014 force solo agent mode, no shadow worker" }, { cmd: "/speculate", desc: "<task> \u2014 parallel speculation: N engines race in worktrees, winner applied" }, { cmd: "/team-forge", desc: "[2v2|3v3] <task> test with <cmd> \u2014 team code competition" }, { cmd: "/team-tribunal", desc: "[2v2|3v3] [mode] <question> \u2014 team debate" }, { cmd: "/team-brainstorm", desc: "[2v2|3v3] <question> \u2014 team ideation" }, { cmd: "/pipeline", desc: "<task> [test with <cmd>] \u2014 build\u2192review\u2192fix loop" }, { cmd: "/review", desc: "[with <engine>] [<target>] \u2014 code review (uncommitted|branch:NAME|commit:SHA)" }, { cmd: "/provider", desc: "add|remove|list|key \u2014 providers & keys (key set/clear/list)" }, { cmd: "/run", desc: "<cmd> \u2014 run shell command inline" }, { cmd: "/commit", desc: "[message] \u2014 stage & commit with auto-generated message" }, { cmd: "/status", desc: " \u2014 live engine telemetry snapshot" }, { cmd: "/doctor", desc: "[engines|harness] \u2014 diagnose engines, worktree, or Cesar harness" }, { cmd: "/harness-replay", desc: "[turnId] \u2014 replay Cesar tool timeline + approval ledger" }, { cmd: "/undo", desc: " \u2014 revert last patch or Cesar checkpoint" }, { cmd: "/checkpoints", desc: " \u2014 list recent file checkpoints" }, { cmd: "/jobs", desc: " \u2014 list running/completed jobs" }, { cmd: "/focus", desc: "<id> \u2014 switch to background job output" }, { cmd: "/explore", desc: " \u2014 toggle exploration mode (read-only)" }, { cmd: "/nero", desc: "[<decision>] \u2014 toggle Nero mode, or challenge a decision (top-rated critic)" }, { cmd: "/btw", desc: "<question> \u2014 ask something while engines work (side-channel)" }, { cmd: "/compact", desc: " \u2014 shrink Cesar context without clearing transcript" }, { cmd: "/mcp", desc: "connect <name|url> | disconnect <name> | list \u2014 manage session MCP servers" }, { cmd: "/init", desc: " \u2014 create AGON.md config wizard" }, { cmd: "/create-skill", desc: "<name> \u2014 scaffold a new skill (.agon/skills/)" }, { cmd: "/clear", desc: " \u2014 reset session (saves chat, clears brain)" }, { cmd: "/clean", desc: " \u2014 alias for /clear" }, { cmd: "/extensions", desc: " \u2014 list installed extensions" }, { cmd: "/help", desc: " \u2014 show this help" }, { cmd: "/exit", desc: " \u2014 quit" }];
7282
+ var SLASH_COMMANDS = [{ cmd: "/forge", desc: "<task> test with <cmd> [--hardened] \u2014 competitive code generation" }, { cmd: "/brainstorm", desc: "<question> \u2014 confidence-bidding answers" }, { cmd: "/tribunal", desc: "[mode] <question> \u2014 debate (adversarial|socratic|red-team|steelman|synthesis|postmortem)" }, { cmd: "/campfire", desc: "<topic> \u2014 think together, no competition" }, { cmd: "/think", desc: "<problem> [--strategy reflexion] [--steps 8] \u2014 sequential thinking, one engine" }, { cmd: "/council", desc: "<decision> \u2014 roundtable: every engine a role, top-rated chairs" }, { cmd: "/synthesis", desc: "<task> [--swaps 2] \u2014 engines draft, swap, improve; judge picks winner" }, { cmd: "/workspace", desc: "add|remove|list|switch \u2014 manage project repos" }, { cmd: "/ws", desc: " \u2014 list workspaces (shortcut)" }, { cmd: "/cesar", desc: "<engine> \u2014 set Cesar brain engine (e.g. /cesar codex)" }, { cmd: "/models", desc: " \u2014 browse & add provider models + CLI models" }, { cmd: "/tokens", desc: " \u2014 show token usage & costs" }, { cmd: "/raw", desc: " \u2014 reprint last folded engine output (unfolded)" }, { cmd: "/engines", desc: " \u2014 select active engines" }, { cmd: "/leaderboard", desc: " \u2014 Glicko rankings" }, { cmd: "/cesar-report", desc: " \u2014 Cesar routing calibration report" }, { cmd: "/cesar-hints", desc: "<task> \u2014 inspect Cesar routing hints for a prompt" }, { cmd: "/history", desc: "[id] \u2014 past forge runs" }, { cmd: "/config", desc: "[list|get|set] \u2014 settings" }, { cmd: "/plan", desc: "<task> or no args \u2014 plan mode or show plan" }, { cmd: "/auto", desc: "[on|off|toggle|status] or <task> \u2014 autonomous mode control" }, { cmd: "/plans", desc: " \u2014 list recent plans" }, { cmd: "/approve", desc: " \u2014 approve current plan" }, { cmd: "/retry", desc: " \u2014 retry failed plan step" }, { cmd: "/cancel", desc: " \u2014 cancel current plan" }, { cmd: "/apply", desc: "[path] [--force] \u2014 apply winning forge patch" }, { cmd: "/cp", desc: "[N] \u2014 copy code block N to clipboard" }, { cmd: "/img", desc: "<path> \u2014 attach image to next prompt" }, { cmd: "/flow", desc: " \u2014 log this session" }, { cmd: "/flows", desc: " \u2014 flow analytics dashboard" }, { cmd: "/chats", desc: "[id|resume <id>] \u2014 chat history or resume session" }, { cmd: "/build", desc: "<task> \u2014 agent builds in cwd (reads/edits/tests)" }, { cmd: "/goal", desc: '<intent> --queue <dir> --gate "<cmd>" [--push] \u2014 autonomous queue: build\u2192review(all)\u2192judge\u2192fix\u2192commit\u2192push per task (background job)' }, { cmd: "/conquer", desc: '<task> --gate "<cmd>" [--builder X] [-e a,b] \u2014 supervised-autonomous build: Cesar drives a builder CLI, convenes nero/tribunal/council on forks, stops at a human merge gate (background job)' }, { cmd: "/agent", desc: "<task> \u2014 autonomous agent loop (solo or shadow, auto-routed)" }, { cmd: "/agent-solo", desc: "<task> \u2014 force solo agent mode, no shadow worker" }, { cmd: "/speculate", desc: "<task> \u2014 parallel speculation: N engines race in worktrees, winner applied" }, { cmd: "/team-forge", desc: "[2v2|3v3] <task> test with <cmd> \u2014 team code competition" }, { cmd: "/team-tribunal", desc: "[2v2|3v3] [mode] <question> \u2014 team debate" }, { cmd: "/team-brainstorm", desc: "[2v2|3v3] <question> \u2014 team ideation" }, { cmd: "/pipeline", desc: "<task> [test with <cmd>] \u2014 build\u2192review\u2192fix loop" }, { cmd: "/review", desc: "[with <engine>] [<target>] \u2014 code review (uncommitted|branch:NAME|commit:SHA)" }, { cmd: "/provider", desc: "add|remove|list|key \u2014 providers & keys (key set/clear/list)" }, { cmd: "/run", desc: "<cmd> \u2014 run shell command inline" }, { cmd: "/commit", desc: "[message] \u2014 stage & commit with auto-generated message" }, { cmd: "/status", desc: " \u2014 live engine telemetry snapshot" }, { cmd: "/doctor", desc: "[engines|harness] \u2014 diagnose engines, worktree, or Cesar harness" }, { cmd: "/harness-replay", desc: "[turnId] \u2014 replay Cesar tool timeline + approval ledger" }, { cmd: "/undo", desc: " \u2014 revert last patch or Cesar checkpoint" }, { cmd: "/checkpoints", desc: " \u2014 list recent file checkpoints" }, { cmd: "/jobs", desc: " \u2014 list running/completed jobs" }, { cmd: "/focus", desc: "<id> \u2014 switch to background job output" }, { cmd: "/explore", desc: " \u2014 toggle exploration mode (read-only)" }, { cmd: "/nero", desc: "[<decision>] \u2014 toggle Nero mode, or challenge a decision (top-rated critic)" }, { cmd: "/btw", desc: "<question> \u2014 ask something while engines work (side-channel)" }, { cmd: "/compact", desc: " \u2014 shrink Cesar context without clearing transcript" }, { cmd: "/mcp", desc: "connect <name|url> | disconnect <name> | list \u2014 manage session MCP servers" }, { cmd: "/init", desc: " \u2014 create AGON.md config wizard" }, { cmd: "/create-skill", desc: "<name> \u2014 scaffold a new skill (.agon/skills/)" }, { cmd: "/clear", desc: " \u2014 reset session (saves chat, clears brain)" }, { cmd: "/clean", desc: " \u2014 alias for /clear" }, { cmd: "/extensions", desc: " \u2014 list installed extensions" }, { cmd: "/help", desc: " \u2014 show this help" }, { cmd: "/exit", desc: " \u2014 quit" }];
7169
7283
  var FITNESS_PATTERN = /\b(?:test with|test:|--test|fitness:)\s+(.+)/i;
7170
7284
  var LEADERBOARD_KEYWORDS = /\b(leaderboard|elo|rankings?)\b/i;
7171
7285
  var HISTORY_KEYWORDS = /\b(history|last runs?|recent)\b/i;
@@ -7180,6 +7294,7 @@ var CODE_ARTIFACT_PATTERN = /(?:at \w+.*:\d+|\.[tj]sx?\b|\.[a-z]{2,4}:\d+|^[+-]{
7180
7294
  var AGENT_TRIGGER_PATTERN = /^(?:agent(?:\s+mode)?|autonomous(?:\s+agent)?|run\s+agent)\s+([\s\S]+)$/i;
7181
7295
  var AUTOCREDIT_OFF_KEYWORDS = /\b(?:schalt(?:e|)?\s+(?:das|es|autoCredit)\s+ab|mach(?:e|)?\s+(?:das|es|autoCredit)\s+(?:aus|weg)|das\s+nervt|(?:autoCredit|co[\s-]?authored?|contributor)\s+(?:aus|ab|weg|nervt))\b/i;
7182
7296
  var AUTOCREDIT_ON_KEYWORDS = /\b(?:schalt(?:e|)?\s+(?:das|es|autoCredit)\s+an|mach(?:e|)?\s+(?:das|es|autoCredit)\s+an|(?:autoCredit|co[\s-]?authored?|contributor)\s+an)\b/i;
7297
+ var KNOWN_COLLAB_ENGINE_IDS = /* @__PURE__ */ new Set(["claude", "codex", "agy", "antigravity", "qwen", "kimi", "opencode", "open-code", "minimax", "zai", "aider", "cursor", "gpt", "openai"]);
7183
7298
  function classifyTask(input) {
7184
7299
  if (QUESTION_PATTERN.test(input)) {
7185
7300
  return "question";
@@ -7212,6 +7327,62 @@ function parseAgentShortcut(input) {
7212
7327
  }
7213
7328
  return { type: "agent", input: task };
7214
7329
  }
7330
+ function normalizeEngineToken(part) {
7331
+ const cleaned = part.trim().toLowerCase().replace(/^@+/, "").replace(/^[^\w-]+|[^\w-]+$/g, "");
7332
+ if (!cleaned) {
7333
+ return null;
7334
+ }
7335
+ if (cleaned === "antigravity") {
7336
+ return "agy";
7337
+ }
7338
+ if (KNOWN_COLLAB_ENGINE_IDS.has(cleaned)) {
7339
+ return cleaned;
7340
+ }
7341
+ if (/^(?:claude|codex|agy|antigravity|qwen|kimi|opencode|open-code|minimax|zai|aider|cursor|gpt|openai)[\w.-]*$/i.test(cleaned)) {
7342
+ return cleaned;
7343
+ }
7344
+ return null;
7345
+ }
7346
+ function parseExplicitEngineIds(input) {
7347
+ const engineIds = [];
7348
+ const add = (value) => {
7349
+ if (value && !engineIds.includes(value)) engineIds.push(value);
7350
+ };
7351
+ const collect = (segment) => {
7352
+ segment.split(/(?:,|\s+and\s+|\s+or\s+|\s+plus\s+|\s+with\s+|\s+)/i).map((part) => normalizeEngineToken(part)).forEach(add);
7353
+ };
7354
+ const withMatch = input.match(/\bwith\s+([a-z0-9@_.-]+(?:(?:\s*,\s*|\s+and\s+|\s+or\s+|\s+plus\s+|\s+)[a-z0-9@_.-]+)*)/i);
7355
+ if (withMatch) collect(withMatch[1]);
7356
+ const askMatch = input.match(/\b(?:ask|have|get)\s+([a-z0-9@_.-]+(?:\s*(?:,|and|or|plus)\s*[a-z0-9@_.-]+)*)\s+(?:to\s+)?(?:review|check|audit|look|inspect|compare|weigh|think|debate)\b/i);
7357
+ if (askMatch) collect(askMatch[1]);
7358
+ return engineIds;
7359
+ }
7360
+ function parseSemanticReviewShortcut(input) {
7361
+ const lower = input.toLowerCase();
7362
+ const reviewVerb = /\b(?:review|check|audit|inspect|look\s+over)\b/i.test(input);
7363
+ if (!reviewVerb) {
7364
+ return null;
7365
+ }
7366
+ const hasDelegationShape = /\bwith\s+[a-z0-9@_.-]+/i.test(input) || /\b(?:ask|have|get)\s+[a-z0-9@_.-]+(?:\s*(?:,|and|or|plus)\s*[a-z0-9@_.-]+)*\s+(?:to\s+)?(?:review|check|audit|look|inspect)\b/i.test(input);
7367
+ if (!hasDelegationShape) {
7368
+ return null;
7369
+ }
7370
+ if (/\breview\b[\s\S]*\b(?:fix|address|resolve|apply|patch)\b/i.test(input) || /\b(?:fix|address|resolve|apply|patch)\b[\s\S]*\b(?:review|findings?|issues?)\b/i.test(input)) {
7371
+ return null;
7372
+ }
7373
+ const IMPLEMENTATION_LEAD_RE = /^(?:fix(?:e[sd]|ing)?|add(?:ed|ing|s)?|implement(?:ed|ing|s)?|build(?:ing|s)?|built|creat(?:e[sd]?|ing)|refactor(?:ed|ing|s)?|rewrit(?:e|es|ing|ten)|migrat(?:e[sd]?|ing)|wir(?:e[sd]?|ing)|chang(?:e[sd]?|ing)|updat(?:e[sd]?|ing)|optimi[sz](?:e[sd]?|ing)|remov(?:e[sd]?|ing)|delet(?:e[sd]?|ing)|patch(?:ed|ing|es)?)\b/i;
7374
+ const normalized = input.trim().replace(/^(?:can\s+you\s+|could\s+you\s+|please\s+)?/i, "");
7375
+ if (IMPLEMENTATION_LEAD_RE.test(normalized)) {
7376
+ return null;
7377
+ }
7378
+ const engineIds = parseExplicitEngineIds(input);
7379
+ if (engineIds.length === 0) {
7380
+ return null;
7381
+ }
7382
+ const targetMatch = lower.match(/\b(uncommitted|branch:[\w./-]+|commit:[a-f0-9]{4,40})\b/i);
7383
+ const target = targetMatch ? targetMatch[1] : void 0;
7384
+ return { type: "review", engineId: engineIds[0], engineIds, target };
7385
+ }
7215
7386
  function parseSemanticDelegationShortcut(input) {
7216
7387
  return null;
7217
7388
  }
@@ -7456,6 +7627,10 @@ function parseSlashCommand(input, commandRegistry) {
7456
7627
  case "usage":
7457
7628
  case "cost":
7458
7629
  return { type: "tokens" };
7630
+ case "raw": {
7631
+ const rawN = parseInt(rest.trim(), 10);
7632
+ return { type: "raw", index: Number.isFinite(rawN) && rawN > 0 ? rawN : void 0 };
7633
+ }
7459
7634
  case "doctor":
7460
7635
  return { type: "doctor", scope: rest || "engines" };
7461
7636
  case "harness-replay":
@@ -7655,6 +7830,10 @@ function detectIntent(raw, commandRegistry) {
7655
7830
  if (delegationShortcut) {
7656
7831
  return delegationShortcut;
7657
7832
  }
7833
+ const reviewShortcut = parseSemanticReviewShortcut(input);
7834
+ if (reviewShortcut) {
7835
+ return reviewShortcut;
7836
+ }
7658
7837
  if (AUTOCREDIT_OFF_KEYWORDS.test(input)) {
7659
7838
  return { type: "toggleAutoCredit", autoCredit: false, input };
7660
7839
  }
@@ -9130,7 +9309,7 @@ ${projectCtx}` : question;
9130
9309
  }
9131
9310
 
9132
9311
  // src/generated/handlers/info.ts
9133
- import { readdirSync as readdirSync5, readFileSync as readFileSync7, existsSync as existsSync9, rmSync as rmSync2 } from "fs";
9312
+ import { readdirSync as readdirSync5, readFileSync as readFileSync8, existsSync as existsSync9, rmSync as rmSync3 } from "fs";
9134
9313
  import { join as join23 } from "path";
9135
9314
  function handleLeaderboard(dispatch) {
9136
9315
  const ratings = getRatings();
@@ -9164,7 +9343,7 @@ function handleCesarReport(dispatch) {
9164
9343
  }
9165
9344
  let raw = "";
9166
9345
  try {
9167
- raw = readFileSync7(reportPath, "utf-8");
9346
+ raw = readFileSync8(reportPath, "utf-8");
9168
9347
  } catch (err) {
9169
9348
  dispatch({ type: "error", message: `Failed to read Cesar report: ${err instanceof Error ? err.message : String(err)}` });
9170
9349
  return;
@@ -9342,7 +9521,7 @@ function showRunDetail2(dispatch, id) {
9342
9521
  dispatch({ type: "info", message: `Run "${id}" not found` });
9343
9522
  return;
9344
9523
  }
9345
- const manifest = JSON.parse(readFileSync7(join23(RUNS_DIR, files[0]), "utf-8"));
9524
+ const manifest = JSON.parse(readFileSync8(join23(RUNS_DIR, files[0]), "utf-8"));
9346
9525
  dispatch({ type: "header", title: `Forge Run: ${manifest.forgeId.slice(0, 8)}` });
9347
9526
  dispatch({ type: "text", content: `Task: ${manifest.task}
9348
9527
  Fitness: ${manifest.fitnessCmd}
@@ -9384,7 +9563,7 @@ function handleHistory(dispatch, id) {
9384
9563
  const rows = [];
9385
9564
  for (const file of recent) {
9386
9565
  try {
9387
- const manifest = JSON.parse(readFileSync7(join23(RUNS_DIR, file), "utf-8"));
9566
+ const manifest = JSON.parse(readFileSync8(join23(RUNS_DIR, file), "utf-8"));
9388
9567
  const date = new Date(manifest.timestamp).toLocaleString();
9389
9568
  const taskStr = manifest.task.length > 40 ? manifest.task.slice(0, 40) + "..." : manifest.task;
9390
9569
  const winner = manifest.winner ?? "none";
@@ -9447,7 +9626,7 @@ async function handleEngines(dispatch, ctx, intent) {
9447
9626
  let removedUserConfig = false;
9448
9627
  const userConfigPath = join23(getAgonHome(), "engines", `${id}.json`);
9449
9628
  if (existsSync9(userConfigPath)) {
9450
- rmSync2(userConfigPath, { force: true });
9629
+ rmSync3(userConfigPath, { force: true });
9451
9630
  try {
9452
9631
  ctx.registry.unregister?.(id);
9453
9632
  } catch {
@@ -9714,6 +9893,21 @@ function handleCesar(engineId, dispatch, ctx) {
9714
9893
  dispatch({ type: "success", message: `Cesar brain set to: ${id} (backend: ${backend})` });
9715
9894
  dispatch({ type: "info", message: "Conversation context + memory preserved. Forge/tribunal engines unchanged \u2014 use /use to change those." });
9716
9895
  }
9896
+ function handleRaw(dispatch, index) {
9897
+ const count = getFoldedRawCount();
9898
+ if (count === 0) {
9899
+ dispatch({ type: "info", message: "Nothing folded yet \u2014 /raw reprints the full text of a recently folded engine block." });
9900
+ return;
9901
+ }
9902
+ const n = index && index > 0 ? Math.floor(index) : 1;
9903
+ const raw = getFoldedRaw(n) ?? "";
9904
+ if (!raw.trim()) {
9905
+ dispatch({ type: "info", message: `No folded block #${n} \u2014 ${count} recent fold${count === 1 ? "" : "s"} kept (try /raw 1..${count}).` });
9906
+ return;
9907
+ }
9908
+ dispatch({ type: "header", title: count > 1 ? `Raw engine output (unfolded) \u2014 ${n} of ${count} recent` : "Raw engine output (unfolded)" });
9909
+ dispatch({ type: "engine-block", engineId: "raw", color: 244, content: raw, foldedSteps: 0 });
9910
+ }
9717
9911
  function handleTokens(dispatch) {
9718
9912
  const stats = tracker.getStats();
9719
9913
  dispatch({ type: "header", title: "Token Usage \u2014 This Session" });
@@ -9882,7 +10076,7 @@ async function handlePlanShow(dispatch, ctx, planId) {
9882
10076
  savePlan(approved);
9883
10077
  dispatch({ type: "success", message: "Plan approved." });
9884
10078
  if (approved.action.type === "forge") {
9885
- const { handleForge: handleForge2 } = await import("./forge-GUOEJ5DJ.js");
10079
+ const { handleForge: handleForge2 } = await import("./forge-5QSRUNW6.js");
9886
10080
  await handleForge2(approved.action.task, approved.action.fitnessCmd ?? null, dispatch, ctx, approved, approved.action.hardened);
9887
10081
  } else {
9888
10082
  dispatch({ type: "info", message: "Run the build again to execute." });
@@ -9908,7 +10102,7 @@ async function handleApprove(dispatch, ctx) {
9908
10102
  savePlan(plan);
9909
10103
  dispatch({ type: "success", message: "Plan approved." });
9910
10104
  if (plan.action.type === "forge") {
9911
- const { handleForge: handleForge2 } = await import("./forge-GUOEJ5DJ.js");
10105
+ const { handleForge: handleForge2 } = await import("./forge-5QSRUNW6.js");
9912
10106
  await handleForge2(plan.action.task, plan.action.fitnessCmd ?? null, dispatch, ctx, plan, plan.action.hardened);
9913
10107
  } else {
9914
10108
  dispatch({ type: "info", message: "Run the build again to execute." });
@@ -9936,7 +10130,7 @@ async function handleRetry(dispatch, ctx) {
9936
10130
  plan = startPlan(plan);
9937
10131
  ctx.setCurrentPlan(plan);
9938
10132
  savePlan(plan);
9939
- const { handleForge: handleForge2 } = await import("./forge-GUOEJ5DJ.js");
10133
+ const { handleForge: handleForge2 } = await import("./forge-5QSRUNW6.js");
9940
10134
  await handleForge2(plan.action.task, plan.action.fitnessCmd ?? null, dispatch, ctx, plan, plan.action.hardened);
9941
10135
  } else {
9942
10136
  dispatch({ type: "info", message: "Plan reset to approved. Run the build again to execute." });
@@ -10051,7 +10245,7 @@ ${listing}` });
10051
10245
 
10052
10246
  // src/generated/handlers/build.ts
10053
10247
  import { join as join25 } from "path";
10054
- import { mkdirSync as mkdirSync13, readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
10248
+ import { mkdirSync as mkdirSync13, readFileSync as readFileSync9, existsSync as existsSync10 } from "fs";
10055
10249
  function injectFileReferences(input, cwd) {
10056
10250
  const FILE_REF = /(?:^|\s)([\w./-]+\.\w{1,10})\b/g;
10057
10251
  let result = input;
@@ -10064,7 +10258,7 @@ function injectFileReferences(input, cwd) {
10064
10258
  const fullPath = join25(cwd, ref);
10065
10259
  if (existsSync10(fullPath)) {
10066
10260
  try {
10067
- const content = readFileSync8(fullPath, "utf-8");
10261
+ const content = readFileSync9(fullPath, "utf-8");
10068
10262
  if (content.length < 5e4) {
10069
10263
  result += `
10070
10264
 
@@ -10314,7 +10508,7 @@ async function handleRun(command, dispatch, ctx) {
10314
10508
  }
10315
10509
 
10316
10510
  // src/generated/cesar/orchestration.ts
10317
- import { tmpdir as tmpdir2 } from "os";
10511
+ import { tmpdir as tmpdir3 } from "os";
10318
10512
 
10319
10513
  // src/generated/handlers/pipeline.ts
10320
10514
  import { join as join26 } from "path";
@@ -10679,7 +10873,7 @@ ${diffStat}
10679
10873
  return;
10680
10874
  }
10681
10875
  for (const f of modifiedFiles) {
10682
- gitExec(`git add "${f}"`, cwd);
10876
+ execFileSync2("git", ["add", f], { cwd, encoding: "utf-8", timeout: 1e4, stdio: ["ignore", "pipe", "pipe"] });
10683
10877
  }
10684
10878
  dispatch({ type: "success", message: `Staged ${modifiedFiles.length} file(s)` });
10685
10879
  }
@@ -11409,7 +11603,7 @@ Beta: ${String(subB?.finalOutput ?? "").slice(0, 500)}`,
11409
11603
 
11410
11604
  // src/generated/handlers/team-forge.ts
11411
11605
  import { join as join33 } from "path";
11412
- import { mkdirSync as mkdirSync21, readFileSync as readFileSync9 } from "fs";
11606
+ import { mkdirSync as mkdirSync21, readFileSync as readFileSync10 } from "fs";
11413
11607
  async function handleTeamForge(task, fitnessCmd, dispatch, ctx, membersPerSide) {
11414
11608
  const teamAbort = new AbortController();
11415
11609
  try {
@@ -11503,7 +11697,7 @@ async function handleTeamForge(task, fitnessCmd, dispatch, ctx, membersPerSide)
11503
11697
  const patchPath = winnerOutput?.patchPath;
11504
11698
  if (patchPath) {
11505
11699
  try {
11506
- const patchContent = readFileSync9(patchPath, "utf-8");
11700
+ const patchContent = readFileSync10(patchPath, "utf-8");
11507
11701
  dispatch({ type: "patch-review", winnerId: `team:${result.winnerTeamId}`, patchPath, patchContent });
11508
11702
  } catch (err) {
11509
11703
  dispatch({ type: "info", message: `Winning patch: ${patchPath} (use git apply to apply manually)` });
@@ -12108,7 +12302,7 @@ function shouldEmitCesarRecap(event) {
12108
12302
  // src/generated/signals/file-tracker.ts
12109
12303
  import { relative, isAbsolute, resolve as resolve2, dirname as dirname6 } from "path";
12110
12304
  import { spawnSync as spawnSync3 } from "child_process";
12111
- import { existsSync as existsSync11, readFileSync as readFileSync10, statSync as statSync3 } from "fs";
12305
+ import { existsSync as existsSync11, readFileSync as readFileSync11, statSync as statSync3 } from "fs";
12112
12306
  var EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit", "AgonEdit", "AgonWrite", "apply_patch", "applypatch", "ApplyPatch"]);
12113
12307
  var READ_TOOLS = /* @__PURE__ */ new Set(["Read", "Glob", "Grep"]);
12114
12308
  function extractFilePaths(tool, input) {
@@ -12210,7 +12404,7 @@ function getFileDiff(absPath, maxLines) {
12210
12404
  if (!st.isFile()) {
12211
12405
  return "";
12212
12406
  }
12213
- const content = readFileSync10(absPath, "utf8");
12407
+ const content = readFileSync11(absPath, "utf8");
12214
12408
  const contentLines = content.split("\n");
12215
12409
  const shown = contentLines.slice(0, Math.max(1, cap - 1)).map((line) => `+${line}`);
12216
12410
  const omitted = Math.max(0, contentLines.length - shown.length);
@@ -12909,7 +13103,7 @@ async function runCesarBrainFallback(input, cb, crashDel, priorDeterministic) {
12909
13103
  const cesarEngine = cesarEngineDef ?? cb.ctx.registry.get(cesarId);
12910
13104
  const { join: join47 } = await import("path");
12911
13105
  const { mkdirSync: mkdirSync30 } = await import("fs");
12912
- const { resolveWorkingDir: resolveWorkingDir3, RUNS_DIR: RUNS_DIR3, appendMessage: appendMessage3 } = await import("./src-3NWTITZM.js");
13106
+ const { resolveWorkingDir: resolveWorkingDir3, RUNS_DIR: RUNS_DIR3, appendMessage: appendMessage3 } = await import("./src-253BUXEF.js");
12913
13107
  const outDir = join47(RUNS_DIR3, `cesar-fallback-${Date.now()}`);
12914
13108
  mkdirSync30(outDir, { recursive: true });
12915
13109
  if (!_silentMode) cb.dispatch({ type: "warning", message: formatCesarRecoveryStatus("retry", cesarId, `log: ${outDir}`) });
@@ -13090,18 +13284,19 @@ ${historyContext}
13090
13284
  ` : ""}## USER MESSAGE
13091
13285
  ${input}`;
13092
13286
  try {
13093
- const { resolveWorkingDir: resolveWorkingDir3, RUNS_DIR: RUNS_DIR3, appendMessage: appendMessage3 } = await import("./src-3NWTITZM.js");
13287
+ const { resolveWorkingDir: resolveWorkingDir3, RUNS_DIR: RUNS_DIR3, appendMessage: appendMessage3 } = await import("./src-253BUXEF.js");
13094
13288
  const { join: join47 } = await import("path");
13095
13289
  const { mkdirSync: mkdirSync30 } = await import("fs");
13096
13290
  const actingEngine = cb.ctx.registry.get(actingCesar);
13097
13291
  const outDir = join47(RUNS_DIR3, `acting-cesar-${Date.now()}`);
13098
13292
  mkdirSync30(outDir, { recursive: true });
13099
13293
  if (!_silentMode) cb.dispatch({ type: "info", message: formatCesarRecoveryStatus("acting", actingCesar, `log: ${outDir}`) });
13294
+ const actingMode = actingEngine?.agent ? "agent" : "exec";
13100
13295
  const actingResult = await cb.ctx.adapter.dispatch({
13101
13296
  engine: actingEngine,
13102
13297
  prompt: actingPrompt,
13103
13298
  cwd: resolveWorkingDir3(),
13104
- mode: "exec",
13299
+ mode: actingMode,
13105
13300
  timeout: cesarConfig.timeout ?? 120,
13106
13301
  outputDir: outDir,
13107
13302
  systemPrompt: buildCesarSystemPrompt(cb.ctx)
@@ -13647,7 +13842,7 @@ ${result.winner?.slice(0, 500) ?? ""}` });
13647
13842
  import "path";
13648
13843
 
13649
13844
  // src/generated/handlers/provider.ts
13650
- import { writeFileSync as writeFileSync9, mkdirSync as mkdirSync24, unlinkSync as unlinkSync3, readdirSync as readdirSync6, readFileSync as readFileSync11, existsSync as existsSync12 } from "fs";
13845
+ import { writeFileSync as writeFileSync9, mkdirSync as mkdirSync24, unlinkSync as unlinkSync3, readdirSync as readdirSync6, readFileSync as readFileSync12, existsSync as existsSync12 } from "fs";
13651
13846
  import { join as join38, resolve as resolve3 } from "path";
13652
13847
  import { homedir as homedir5 } from "os";
13653
13848
  function parseProviderKeyArgs(args) {
@@ -13733,7 +13928,7 @@ function handleProviderList(dispatch) {
13733
13928
  const rows = [];
13734
13929
  for (const file of files) {
13735
13930
  try {
13736
- const def = JSON.parse(readFileSync11(join38(dir, file), "utf-8"));
13931
+ const def = JSON.parse(readFileSync12(join38(dir, file), "utf-8"));
13737
13932
  if (def.api) {
13738
13933
  const hasKey = !!process.env[def.api.apiKeyEnv];
13739
13934
  rows.push([def.id, def.api.model, def.api.baseUrl, hasKey ? "ready" : "no key"]);
@@ -14016,13 +14211,16 @@ async function dispatchSessionInfoIntent(intent, input, cb) {
14016
14211
  case "tokens":
14017
14212
  handleTokens(cb.dispatch);
14018
14213
  break;
14214
+ case "raw":
14215
+ handleRaw(cb.dispatch, intent.index);
14216
+ break;
14019
14217
  case "models": {
14020
14218
  cb.setModelPickerTargetEngine?.(null);
14021
14219
  cb.setModelPickerInitialFilter?.("");
14022
14220
  cb.setModelPickerTitle?.("Select model");
14023
14221
  cb.setModelPickerLoading(true);
14024
14222
  cb.setModelPickerOpen(true);
14025
- import("./src-3NWTITZM.js").then(({ fetchModelsRegistry: fetchModelsRegistry2, buildModelEntries: buildModelEntries2, buildCliGroupsImmediate, refreshCliGroup, refreshCliGroupVersion }) => {
14223
+ import("./src-253BUXEF.js").then(({ fetchModelsRegistry: fetchModelsRegistry2, buildModelEntries: buildModelEntries2, buildCliGroupsImmediate, refreshCliGroup, refreshCliGroupVersion }) => {
14026
14224
  let cliGroups = buildCliGroupsImmediate();
14027
14225
  cb.setModelPickerCliGroups?.(cliGroups);
14028
14226
  for (const g of cliGroups) {
@@ -14080,7 +14278,7 @@ async function dispatchSessionInfoIntent(intent, input, cb) {
14080
14278
  await handlePlanShow(cb.dispatch, cb.ctx, intent.planId);
14081
14279
  break;
14082
14280
  case "plan-task": {
14083
- const { createCesarPlan } = await import("./src-3NWTITZM.js");
14281
+ const { createCesarPlan } = await import("./src-253BUXEF.js");
14084
14282
  const cesarPlan = createCesarPlan(intent.task, []);
14085
14283
  cb.setActivePlan(cesarPlan);
14086
14284
  if (!cb.ctx.cesar) {
@@ -14713,7 +14911,7 @@ async function dispatchInitIntent(intent, input, cb) {
14713
14911
 
14714
14912
  // src/generated/signals/dispatch/intent-skills.ts
14715
14913
  import { join as join42 } from "path";
14716
- import { readFileSync as readFileSync13 } from "fs";
14914
+ import { readFileSync as readFileSync14 } from "fs";
14717
14915
  async function dispatchSkillsUiIntent(intent, input, cb) {
14718
14916
  switch (intent.type) {
14719
14917
  case "create-skill": {
@@ -14811,7 +15009,7 @@ ${lines}` });
14811
15009
  let found = null;
14812
15010
  for (const configPath of [join42(resolveWorkingDir(), ".mcp.json"), join42(getAgonHome(), "mcp.json")]) {
14813
15011
  try {
14814
- const raw = JSON.parse(readFileSync13(configPath, "utf-8"));
15012
+ const raw = JSON.parse(readFileSync14(configPath, "utf-8"));
14815
15013
  const servers = raw.mcpServers ?? raw.servers ?? raw;
14816
15014
  if (servers[serverInput]) {
14817
15015
  found = { name: serverInput, ...servers[serverInput] };
@@ -15517,15 +15715,20 @@ function resolveKeyboardInput(ctx) {
15517
15715
  }
15518
15716
  if (hasCtrlSignal && normalizedCtrlInput === "l") return { type: "submit", value: "/clear" };
15519
15717
  if (ctx.activePlanState === "awaiting_approval" && ctx.inputValue === "" && !hasCtrlSignal && !key.escape && !key.tab && !ctx.slashPickerOpen && !ctx.enginePickerOpen && !ctx.reviewEventOpen && !ctx.toolDetailOpen && !ctx.questionState) {
15520
- const pcur = (ctx.planApprovalIndex ?? 0) === 1 ? 1 : 0;
15521
- if (key.upArrow || key.downArrow) return { type: "movePlanApproval", index: pcur === 0 ? 1 : 0 };
15718
+ const pcur = Math.max(0, Math.min(2, ctx.planApprovalIndex ?? 0));
15719
+ const next = pcur === 2 ? 0 : pcur + 1;
15720
+ const prev = pcur === 0 ? 2 : pcur - 1;
15721
+ if (key.downArrow) return { type: "movePlanApproval", index: next };
15722
+ if (key.upArrow) return { type: "movePlanApproval", index: prev };
15522
15723
  if (key.return || input === "\r" || input === "\n") {
15523
- return { type: "planControl", action: pcur === 1 ? "cancel" : "approve" };
15724
+ const action = pcur === 1 ? "revise" : pcur === 2 ? "cancel" : "approve";
15725
+ return { type: "planControl", action };
15524
15726
  }
15525
15727
  if (typeof input === "string" && input.length === 1) {
15526
15728
  const lowered = input.toLowerCase();
15527
15729
  if (lowered === "y" || lowered === "1") return { type: "movePlanApproval", index: 0 };
15528
- if (lowered === "n" || lowered === "2") return { type: "movePlanApproval", index: 1 };
15730
+ if (lowered === "o" || lowered === "2") return { type: "movePlanApproval", index: 1 };
15731
+ if (lowered === "n" || lowered === "3") return { type: "movePlanApproval", index: 2 };
15529
15732
  }
15530
15733
  }
15531
15734
  if (ctx.fileRailFocused) {
@@ -18404,8 +18607,98 @@ function ToolDetailBlock({ title, subtitle, accentColor, rows, maxVisibleRows, o
18404
18607
  ] });
18405
18608
  }
18406
18609
  var StreamingView = React7.memo(function StreamingView2({ streamingText, mode, liveProgress, liveToolStreams, liveToolTailFrozen }) {
18407
- const toolStreams = Object.values(liveToolStreams ?? {});
18408
18610
  const frozenToolOutputRef = useRef3({});
18611
+ const narrationPolicy = useMemo4(() => {
18612
+ try {
18613
+ return String(loadConfig().narrationFold ?? "safe");
18614
+ } catch {
18615
+ return "safe";
18616
+ }
18617
+ }, []);
18618
+ const [renderedText, setRenderedText] = useState4(null);
18619
+ const textRef = useRef3(null);
18620
+ textRef.current = streamingText;
18621
+ useEffect5(() => {
18622
+ if (!streamingText) {
18623
+ setRenderedText(null);
18624
+ return;
18625
+ }
18626
+ let lastHash = "";
18627
+ let frameTimer = null;
18628
+ const updateTick = () => {
18629
+ const current = textRef.current;
18630
+ if (!current) {
18631
+ setRenderedText(null);
18632
+ return;
18633
+ }
18634
+ const content = current.content;
18635
+ const hash = `${current.engineId}:${content.length}:${content.slice(-20)}`;
18636
+ if (hash !== lastHash) {
18637
+ lastHash = hash;
18638
+ if (process.stdout.cork) {
18639
+ process.stdout.cork();
18640
+ }
18641
+ setRenderedText(current);
18642
+ if (process.stdout.uncork) {
18643
+ process.nextTick(() => {
18644
+ process.stdout.uncork();
18645
+ });
18646
+ }
18647
+ }
18648
+ frameTimer = setTimeout(updateTick, 42);
18649
+ };
18650
+ updateTick();
18651
+ return () => {
18652
+ if (frameTimer) {
18653
+ clearTimeout(frameTimer);
18654
+ }
18655
+ };
18656
+ }, [streamingText ? streamingText.engineId : null]);
18657
+ const [renderedToolStreams, setRenderedToolStreams] = useState4({});
18658
+ const toolRef = useRef3({});
18659
+ toolRef.current = liveToolStreams ?? {};
18660
+ useEffect5(() => {
18661
+ if (!liveToolStreams || Object.keys(liveToolStreams).length === 0) {
18662
+ setRenderedToolStreams({});
18663
+ return;
18664
+ }
18665
+ let lastHash = "";
18666
+ let frameTimer = null;
18667
+ const updateTick = () => {
18668
+ const current = toolRef.current;
18669
+ if (!current || Object.keys(current).length === 0) {
18670
+ setRenderedToolStreams({});
18671
+ return;
18672
+ }
18673
+ let hash = "";
18674
+ const keys = Object.keys(current).sort();
18675
+ for (const key of keys) {
18676
+ const entry = current[key];
18677
+ const output = String(entry.output ?? "");
18678
+ hash += `|${key}:${entry.engineId}:${entry.tool}:${output.length}:${output.slice(-20)}`;
18679
+ }
18680
+ if (hash !== lastHash) {
18681
+ lastHash = hash;
18682
+ if (process.stdout.cork) {
18683
+ process.stdout.cork();
18684
+ }
18685
+ setRenderedToolStreams(current);
18686
+ if (process.stdout.uncork) {
18687
+ process.nextTick(() => {
18688
+ process.stdout.uncork();
18689
+ });
18690
+ }
18691
+ }
18692
+ frameTimer = setTimeout(updateTick, 50);
18693
+ };
18694
+ updateTick();
18695
+ return () => {
18696
+ if (frameTimer) {
18697
+ clearTimeout(frameTimer);
18698
+ }
18699
+ };
18700
+ }, [liveToolStreams ? Object.keys(liveToolStreams).join(",") : null]);
18701
+ const toolStreams = Object.values(renderedToolStreams ?? {});
18409
18702
  useEffect5(() => {
18410
18703
  const activeIds = new Set(Object.keys(liveToolStreams ?? {}));
18411
18704
  for (const id of Object.keys(frozenToolOutputRef.current)) {
@@ -18415,37 +18708,54 @@ var StreamingView = React7.memo(function StreamingView2({ streamingText, mode, l
18415
18708
  }
18416
18709
  }, [liveToolStreams, liveToolTailFrozen]);
18417
18710
  return /* @__PURE__ */ jsxs7(Fragment3, { children: [
18418
- streamingText && (() => {
18419
- const c = engineColor(streamingText.engineId);
18420
- const rawStream = streamingText.content;
18421
- const slicedStream = rawStream.length > 6e3 ? rawStream.slice(-6e3) : rawStream;
18422
- const firstNl = rawStream.length > 6e3 ? slicedStream.indexOf("\n") : -1;
18711
+ renderedText && (() => {
18712
+ const c = engineColor(renderedText.engineId);
18713
+ const rawStream = renderedText.content;
18714
+ const rawTailLen = 6e3;
18715
+ const slicedStream = rawStream.length > rawTailLen ? rawStream.slice(-rawTailLen) : rawStream;
18716
+ const firstNl = rawStream.length > rawTailLen ? slicedStream.indexOf("\n") : -1;
18423
18717
  const windowed = firstNl >= 0 ? slicedStream.slice(firstNl + 1) : slicedStream;
18424
18718
  const cleaned = cleanEngineOutput(windowed);
18425
18719
  const wrapWidth = contentWidth(mode === "chat" ? 6 : 8);
18426
18720
  if (mode === "chat") {
18427
18721
  const lines = cleaned.split("\n").filter((line) => line.trim());
18428
18722
  const lastLine = lines.length > 0 ? lines[lines.length - 1].trim() : "";
18429
- const previewLimit = Math.max(24, wrapWidth - streamingText.engineId.length - 6);
18723
+ const previewLimit = Math.max(24, wrapWidth - renderedText.engineId.length - 6);
18430
18724
  const preview = lastLine.length > previewLimit ? lastLine.slice(0, previewLimit - 1) + "\u2026" : lastLine;
18431
18725
  return /* @__PURE__ */ jsxs7(Box7, { marginY: 1, paddingLeft: 1, children: [
18432
18726
  /* @__PURE__ */ jsxs7(Text7, { color: c, bold: true, children: [
18433
18727
  icons().dotOn + " ",
18434
- streamingText.engineId
18728
+ renderedText.engineId
18435
18729
  ] }),
18436
18730
  /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: preview ? ` ${preview}` : " thinking\u2026" })
18437
18731
  ] });
18438
18732
  }
18439
18733
  const allLines = cleaned.split("\n");
18440
18734
  const tailLines = allLines.length > 24 ? allLines.slice(-24).join("\n") : cleaned;
18441
- const segments = parseMarkdownBlocks(tailLines);
18735
+ const live = foldNarrationLines(tailLines, narrationPolicy);
18736
+ const foldedTail = live.visible;
18737
+ const cleanedPrefix = allLines.length > 24 ? allLines.slice(0, -24).join("\n") + "\n" : "";
18738
+ const contextualized = contextualizeSlicedMarkdown(cleanedPrefix, foldedTail);
18739
+ const segments = parseMarkdownBlocks(contextualized);
18740
+ const stepLimit = Math.max(16, wrapWidth - 14);
18741
+ const stepHint = live.lastStep.length > stepLimit ? live.lastStep.slice(0, stepLimit - 1) + "\u2026" : live.lastStep;
18442
18742
  return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginY: 1, paddingLeft: 2, children: [
18443
18743
  /* @__PURE__ */ jsxs7(Text7, { color: c, bold: true, children: [
18444
18744
  "\u250C\u2500\u2500 ",
18445
- streamingText.engineId
18745
+ renderedText.engineId
18446
18746
  ] }),
18747
+ live.foldedSteps > 0 ? /* @__PURE__ */ jsxs7(Text7, { color: c, children: [
18748
+ "\u2502 ",
18749
+ /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
18750
+ "\u25B8 ",
18751
+ String(live.foldedSteps),
18752
+ " step",
18753
+ live.foldedSteps === 1 ? "" : "s",
18754
+ stepHint ? ` \xB7 ${stepHint}` : ""
18755
+ ] })
18756
+ ] }) : null,
18447
18757
  /* @__PURE__ */ jsx7(Text7, { color: c, children: "\u2502" }),
18448
- /* @__PURE__ */ jsx7(RenderedSegments, { segments, borderColor: c, wrapWidth })
18758
+ foldedTail.trim() ? /* @__PURE__ */ jsx7(RenderedSegments, { segments, borderColor: c, wrapWidth }) : null
18449
18759
  ] });
18450
18760
  })(),
18451
18761
  toolStreams.length > 0 && /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", paddingLeft: mode === "chat" ? 1 : 2, children: toolStreams.map((entry) => {
@@ -18462,13 +18772,16 @@ var StreamingView = React7.memo(function StreamingView2({ streamingText, mode, l
18462
18772
  const nonEmptyLines = displayOutput.split("\n").filter((line) => line.trim());
18463
18773
  const previewOutput = nonEmptyLines.slice(-2).join(" ");
18464
18774
  const preview = previewOutput.length > 96 ? previewOutput.slice(0, 95) + "\u2026" : previewOutput;
18465
- const rawTail = displayOutput.length > 6e3 ? displayOutput.slice(-6e3) : displayOutput;
18466
- const firstNl = displayOutput.length > 6e3 ? rawTail.indexOf("\n") : -1;
18775
+ const rawTailLen = 6e3;
18776
+ const rawTail = displayOutput.length > rawTailLen ? displayOutput.slice(-rawTailLen) : displayOutput;
18777
+ const firstNl = displayOutput.length > rawTailLen ? rawTail.indexOf("\n") : -1;
18467
18778
  const windowedTail = firstNl >= 0 ? rawTail.slice(firstNl + 1) : rawTail;
18468
18779
  const cleanedTail = cleanEngineOutput(windowedTail);
18469
18780
  const tailLines = cleanedTail.split("\n");
18470
18781
  const boundedTail = tailLines.length > 12 ? tailLines.slice(-12).join("\n") : cleanedTail;
18471
- const segments = parseMarkdownBlocks(boundedTail);
18782
+ const cleanedPrefix = tailLines.length > 12 ? tailLines.slice(0, -12).join("\n") + "\n" : "";
18783
+ const contextualized = contextualizeSlicedMarkdown(cleanedPrefix, boundedTail);
18784
+ const segments = parseMarkdownBlocks(contextualized);
18472
18785
  const wrapWidth = contentWidth(mode === "chat" ? 8 : 10);
18473
18786
  return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 1, children: [
18474
18787
  /* @__PURE__ */ jsxs7(Text7, { children: [
@@ -18544,6 +18857,17 @@ function buildPlanChromeSummary(activePlan, activePlanState, planModeQueued, aut
18544
18857
  const failed = Number(gauge.failed ?? 0);
18545
18858
  return { visible: true, label, color: gauge.visible ? gauge.color : "#c084fc", shortId: gauge.shortId ?? "", bar: gauge.bar ?? "", pct: Number(gauge.pct ?? 0), stepLabel: gauge.label ?? "", current: gauge.current ?? "", failed, action };
18546
18859
  }
18860
+ function contextualizeSlicedMarkdown(prefix, slicedText) {
18861
+ const parts = prefix.split("```");
18862
+ if (parts.length % 2 === 0) {
18863
+ const lastPart = parts[parts.length - 1];
18864
+ const firstLine = lastPart.split("\n")[0].trim();
18865
+ const lang = /^[a-zA-Z0-9_\-]+$/.test(firstLine) ? firstLine : "";
18866
+ return `\`\`\`${lang}
18867
+ ${slicedText}`;
18868
+ }
18869
+ return slicedText;
18870
+ }
18547
18871
 
18548
18872
  // src/generated/blocks/file-rail.tsx
18549
18873
  import React8 from "react";
@@ -18682,7 +19006,7 @@ function formatRelativeTime(ms) {
18682
19006
  import { join as join46 } from "path";
18683
19007
  import "url";
18684
19008
  import { writeFileSync as writeFileSync13, mkdirSync as mkdirSync29, unlinkSync as unlinkSync4, statSync as statSync4 } from "fs";
18685
- import { tmpdir as tmpdir3 } from "os";
19009
+ import { tmpdir as tmpdir4 } from "os";
18686
19010
  import { spawnSync as spawnSync6 } from "child_process";
18687
19011
 
18688
19012
  // src/generated/blocks/results-formatter.ts
@@ -18948,16 +19272,37 @@ function formatSessionResults(results) {
18948
19272
  return sections.join("\n");
18949
19273
  }
18950
19274
 
19275
+ // src/generated/lib/terminal-notify.ts
19276
+ import { stdout } from "process";
19277
+ function bell() {
19278
+ if (!stdout.isTTY) {
19279
+ return;
19280
+ }
19281
+ if (process.env.AGON_NO_BELL) {
19282
+ return;
19283
+ }
19284
+ stdout.write("\x07");
19285
+ }
19286
+ function setWindowTitle(label) {
19287
+ if (!stdout.isTTY) {
19288
+ return;
19289
+ }
19290
+ if (process.env.AGON_NO_TITLE) {
19291
+ return;
19292
+ }
19293
+ stdout.write("\x1B]0;" + label + "\x07");
19294
+ }
19295
+
18951
19296
  // src/generated/surfaces/app-composer.ts
18952
19297
  import { join as join45 } from "path";
18953
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "fs";
19298
+ import { readFileSync as readFileSync15, writeFileSync as writeFileSync12 } from "fs";
18954
19299
  var COMPOSER_HISTORY_LIMIT = 200;
18955
19300
  function composerHistoryPath() {
18956
19301
  return join45(getAgonHome(), "composer-history.json");
18957
19302
  }
18958
19303
  function loadComposerInputHistory() {
18959
19304
  try {
18960
- const parsed = JSON.parse(readFileSync14(composerHistoryPath(), "utf-8"));
19305
+ const parsed = JSON.parse(readFileSync15(composerHistoryPath(), "utf-8"));
18961
19306
  if (!Array.isArray(parsed)) {
18962
19307
  return [];
18963
19308
  }
@@ -19603,8 +19948,27 @@ function parseMarkdownToRows(baseKey, text, wrapWidth, paddingLeft, borderColor)
19603
19948
  if (segment.type === "table") {
19604
19949
  const headers = segment.headers ?? [];
19605
19950
  const tableRows = segment.rows ?? [];
19606
- const headerLine = headers.join(" \u2502 ");
19607
- const ruleWidth = Math.max(12, Math.min(wrapWidth, headerLine.length));
19951
+ const alignments = segment.alignments ?? [];
19952
+ const colWidths = headers.map((h, i) => {
19953
+ let max = h.length;
19954
+ for (const row of tableRows) {
19955
+ if (row[i] && row[i].length > max) max = row[i].length;
19956
+ }
19957
+ return max;
19958
+ });
19959
+ const padCell = (text2, colIdx) => {
19960
+ const w = colWidths[colIdx] ?? text2.length;
19961
+ const align = alignments[colIdx] ?? "left";
19962
+ if (align === "right") return text2.padStart(w);
19963
+ if (align === "center") {
19964
+ const pad = w - text2.length;
19965
+ const left = Math.floor(pad / 2);
19966
+ return " ".repeat(left) + text2 + " ".repeat(pad - left);
19967
+ }
19968
+ return text2.padEnd(w);
19969
+ };
19970
+ const headerLine = headers.map((h, i) => padCell(h, i)).join(" \u2502 ");
19971
+ const sepLine = colWidths.map((w) => "\u2500".repeat(w)).join("\u2500\u253C\u2500");
19608
19972
  rows.push({
19609
19973
  key: `${baseKey}-table-head-${rowIndex++}`,
19610
19974
  kind: "segments",
@@ -19617,15 +19981,16 @@ function parseMarkdownToRows(baseKey, text, wrapWidth, paddingLeft, borderColor)
19617
19981
  kind: "segments",
19618
19982
  paddingLeft,
19619
19983
  borderColor,
19620
- segments: [{ text: "\u2500".repeat(ruleWidth), dimColor: true }]
19984
+ segments: [{ text: sepLine, dimColor: true }]
19621
19985
  });
19622
19986
  tableRows.forEach((tableRow, index) => {
19987
+ const rowLine = tableRow.map((cell, i) => padCell(cell, i)).join(" \u2502 ");
19623
19988
  rows.push({
19624
19989
  key: `${baseKey}-table-row-${rowIndex++}-${index}`,
19625
19990
  kind: "segments",
19626
19991
  paddingLeft,
19627
19992
  borderColor,
19628
- segments: [{ text: tableRow.join(" \u2502 ") }]
19993
+ segments: [{ text: rowLine }]
19629
19994
  });
19630
19995
  });
19631
19996
  }
@@ -20059,7 +20424,15 @@ function cachedMarkdownRows(baseKey, text, wrapWidth, paddingLeft, borderColor)
20059
20424
  const hit = _mdRowCache.get(key);
20060
20425
  if (hit) return hit;
20061
20426
  const rows = parseMarkdownToRows(baseKey, text, wrapWidth, paddingLeft, borderColor);
20062
- if (_mdRowCache.size >= _MD_ROW_CACHE_MAX) _mdRowCache.clear();
20427
+ if (_mdRowCache.size >= _MD_ROW_CACHE_MAX) {
20428
+ const evictCount = Math.floor(_MD_ROW_CACHE_MAX * 0.2);
20429
+ const it = _mdRowCache.keys();
20430
+ for (let i = 0; i < evictCount; i++) {
20431
+ const oldest = it.next().value;
20432
+ if (oldest === void 0) break;
20433
+ _mdRowCache.delete(oldest);
20434
+ }
20435
+ }
20063
20436
  _mdRowCache.set(key, rows);
20064
20437
  return rows;
20065
20438
  }
@@ -20122,8 +20495,10 @@ function buildTranscriptRows(blocks, mode, toolOutputExpanded, thinkingExpanded)
20122
20495
  if (!cleaned.trim()) return;
20123
20496
  const accentColor = color256toHex(event.color ?? (ENGINE_COLORS[event.engineId] ?? 124));
20124
20497
  if (rows.length > 0) pushSpacer(`${baseKey}-gap`);
20498
+ const foldNote = event.foldedSteps && event.foldedSteps > 0 ? `\u25B8 ${event.foldedSteps} reasoning steps folded \xB7 /raw to inspect` : "";
20125
20499
  if (mode === "chat") {
20126
20500
  pushSegmentsRow(`${baseKey}-chat-head`, 1, [{ text: `${icons().dotOn} ${event.engineId}`, color: accentColor, bold: true }]);
20501
+ if (foldNote) pushSegmentsRow(`${baseKey}-chat-fold`, 1, [{ text: foldNote, dimColor: true }]);
20127
20502
  pushSpacer(`${baseKey}-chat-space`);
20128
20503
  rows.push(...cachedMarkdownRows(baseKey, cleaned, chatWidth, 1, ""));
20129
20504
  return;
@@ -20132,6 +20507,12 @@ function buildTranscriptRows(blocks, mode, toolOutputExpanded, thinkingExpanded)
20132
20507
  { text: "\u250C\u2500\u2500 ", color: accentColor },
20133
20508
  { text: event.engineId, color: accentColor, bold: true }
20134
20509
  ]);
20510
+ if (foldNote) {
20511
+ pushSegmentsRow(`${baseKey}-engine-fold`, 2, [
20512
+ { text: "\u2502 ", color: accentColor },
20513
+ { text: foldNote, dimColor: true }
20514
+ ]);
20515
+ }
20135
20516
  pushSegmentsRow(`${baseKey}-engine-rule`, 2, [{ text: "\u2502", color: accentColor }]);
20136
20517
  rows.push(...cachedMarkdownRows(baseKey, cleaned, engineWidth, 2, accentColor));
20137
20518
  pushSegmentsRow(`${baseKey}-engine-foot`, 2, [{ text: "\u2514\u2500\u2500", color: accentColor }]);
@@ -21446,6 +21827,8 @@ function App() {
21446
21827
  const activeAbortRef = useRef4(null);
21447
21828
  const activeTurnRef = useRef4(null);
21448
21829
  const lastActivityTimeRef = useRef4(Date.now());
21830
+ const pendingBellRef = useRef4(false);
21831
+ const awaitingPlanAnnouncedRef = useRef4("");
21449
21832
  const blockArchivePathRef = useRef4(makeBlockArchivePath(Date.now()));
21450
21833
  const nestedCtrlShortcutRef = useRef4({ key: "", at: 0 });
21451
21834
  const displayRowCountRef = useRef4(0);
@@ -21698,12 +22081,20 @@ function App() {
21698
22081
  const transition = useCallback((fn) => {
21699
22082
  setReplState((prev) => {
21700
22083
  try {
21701
- return fn({ state: prev }).state;
22084
+ const next = fn({ state: prev }).state;
22085
+ if (next === "idle" && prev !== "idle") {
22086
+ if (!pendingBellRef.current) {
22087
+ bell();
22088
+ pendingBellRef.current = true;
22089
+ }
22090
+ setWindowTitle("agon");
22091
+ }
22092
+ return next;
21702
22093
  } catch {
21703
22094
  return prev;
21704
22095
  }
21705
22096
  });
21706
- }, []);
22097
+ }, [bell, setWindowTitle, pendingBellRef]);
21707
22098
  const trackAbort = useCallback((abort) => {
21708
22099
  if (activeAbortRef.current) {
21709
22100
  _activeAborts.delete(activeAbortRef.current);
@@ -21825,6 +22216,11 @@ function App() {
21825
22216
  dispatch({ type: "warning", message });
21826
22217
  }
21827
22218
  setReplState((prev) => prev === "idle" ? prev : cancelReplState({ state: prev }).state);
22219
+ if (!pendingBellRef.current) {
22220
+ bell();
22221
+ pendingBellRef.current = true;
22222
+ }
22223
+ setWindowTitle("agon");
21828
22224
  }
21829
22225
  if (clearChat) {
21830
22226
  dispatch({ type: "clear" });
@@ -21885,6 +22281,8 @@ function App() {
21885
22281
  }, []);
21886
22282
  const handleInputChange = useCallback((value) => {
21887
22283
  keyT0Ref.current = perfNow();
22284
+ pendingBellRef.current = false;
22285
+ awaitingPlanAnnouncedRef.current = "";
21888
22286
  if (questionState && questionState.choices) {
21889
22287
  return;
21890
22288
  }
@@ -21931,7 +22329,7 @@ function App() {
21931
22329
  const updatedValue = nextValue.slice(0, change.start) + replacement + nextValue.slice(change.start + change.inserted.length);
21932
22330
  inputValueRef.current = updatedValue;
21933
22331
  setInputValue(updatedValue);
21934
- }, [slashPickerOpen, enginePickerOpen, modelPickerOpen, questionState, planModeQueued, autoModeQueued, livePaneVisible]);
22332
+ }, [slashPickerOpen, enginePickerOpen, modelPickerOpen, questionState, planModeQueued, autoModeQueued, livePaneVisible, pendingBellRef]);
21935
22333
  const sendBtwMessage = useCallback((question) => {
21936
22334
  const q = (question ?? "").trim();
21937
22335
  if (!q) return;
@@ -22017,6 +22415,8 @@ function App() {
22017
22415
  const handleSubmit = useCallback(async (value) => {
22018
22416
  inputEpochRef.current += 1;
22019
22417
  let input = cleanSubmitValue(value);
22418
+ pendingBellRef.current = false;
22419
+ awaitingPlanAnnouncedRef.current = "";
22020
22420
  if (!input) return;
22021
22421
  if (input === "/") {
22022
22422
  if (planModeQueued) setPlanModeQueued(false);
@@ -22102,6 +22502,8 @@ function App() {
22102
22502
  const autoModeForTurn = autoModeQueued && input.trim() && !input.startsWith("/");
22103
22503
  if (planModeQueued) setPlanModeQueued(false);
22104
22504
  transition(startCommandReplState);
22505
+ pendingBellRef.current = false;
22506
+ setWindowTitle("\u25CF agon \u2014 running");
22105
22507
  dispatch({ type: "separator" });
22106
22508
  dispatch({ type: "user-message", content: input });
22107
22509
  const { text: cleanInput, images: detectedImages } = extractImagesFromInput(input, resolveWorkingDir());
@@ -22133,10 +22535,14 @@ function App() {
22133
22535
  fn().then(() => {
22134
22536
  jobManager.complete(job.id);
22135
22537
  setJobList([...jobManager.list()]);
22538
+ bell();
22539
+ setWindowTitle("agon");
22136
22540
  }).catch((err) => {
22137
22541
  jobManager.fail(job.id, err instanceof Error ? err.message : String(err));
22138
22542
  setJobList([...jobManager.list()]);
22139
22543
  dispatch({ type: "error", message: err instanceof Error ? err.message : String(err) });
22544
+ bell();
22545
+ setWindowTitle("agon");
22140
22546
  });
22141
22547
  },
22142
22548
  setMode,
@@ -22194,9 +22600,9 @@ function App() {
22194
22600
  dispatch({ type: "error", message: err instanceof Error ? err.message : String(err) });
22195
22601
  } finally {
22196
22602
  if (activeTurnRef.current?.input === input) activeTurnRef.current = null;
22197
- setReplState((prev) => prev === "idle" ? prev : finishReplState({ state: prev }).state);
22603
+ transition(finishReplState);
22198
22604
  }
22199
- }, [replState, dispatch, buildContext, mode, pendingImages, jobManager, loadedExtensions, extensionSkills, commandRegistry, eventBus, planModeQueued, autoModeQueued, setPersistentAutoMode, setActivePlanWrapped, outputBlocks, btwPanel, sendBtwMessage]);
22605
+ }, [replState, dispatch, buildContext, mode, pendingImages, jobManager, loadedExtensions, extensionSkills, commandRegistry, eventBus, planModeQueued, autoModeQueued, setPersistentAutoMode, setActivePlanWrapped, outputBlocks, btwPanel, sendBtwMessage, pendingBellRef, awaitingPlanAnnouncedRef]);
22200
22606
  const handleReviewActionCb = useCallback((action) => {
22201
22607
  if (!reviewEvent) {
22202
22608
  return;
@@ -22235,7 +22641,7 @@ function App() {
22235
22641
  setEnginePickerOpen(false);
22236
22642
  setModelPickerOpen(true);
22237
22643
  setModelPickerCliGroups([]);
22238
- import("./src-3NWTITZM.js").then(({ fetchModelsRegistry: fetchModelsRegistry2, buildModelEntries: buildModelEntries2, buildCliGroupsImmediate, refreshCliGroup, refreshCliGroupVersion }) => {
22644
+ import("./src-253BUXEF.js").then(({ fetchModelsRegistry: fetchModelsRegistry2, buildModelEntries: buildModelEntries2, buildCliGroupsImmediate, refreshCliGroup, refreshCliGroupVersion }) => {
22239
22645
  let cliGroups = buildCliGroupsImmediate();
22240
22646
  setModelPickerCliGroups(cliGroups);
22241
22647
  for (const g of cliGroups) {
@@ -22287,14 +22693,14 @@ function App() {
22287
22693
  return;
22288
22694
  }
22289
22695
  content = formatChatTranscript(chatSession);
22290
- tmpFile = join46(tmpdir3(), `agon-chat-${Date.now()}.txt`);
22696
+ tmpFile = join46(tmpdir4(), `agon-chat-${Date.now()}.txt`);
22291
22697
  } else {
22292
22698
  if (!sessionResultStore.hasResults()) {
22293
22699
  dispatch({ type: "info", message: "No results yet \u2014 run /brainstorm, /campfire, /tribunal, or /forge first" });
22294
22700
  return;
22295
22701
  }
22296
22702
  content = formatSessionResults(sessionResultStore.getResults());
22297
- tmpFile = join46(tmpdir3(), `agon-results-${Date.now()}.txt`);
22703
+ tmpFile = join46(tmpdir4(), `agon-results-${Date.now()}.txt`);
22298
22704
  }
22299
22705
  try {
22300
22706
  writeFileSync13(tmpFile, content, "utf-8");
@@ -22396,7 +22802,7 @@ function App() {
22396
22802
  if (ans === "later") return;
22397
22803
  if (ans === "update") {
22398
22804
  setUpdateInfo(null);
22399
- import("./update-H3LE4ZSI.js").then((m) => m.runUpdate(latest)).catch((err) => {
22805
+ import("./update-WLRTYR77.js").then((m) => m.runUpdate(latest)).catch((err) => {
22400
22806
  console.error("[agon] failed to launch update:", err && err.message ? err.message : String(err));
22401
22807
  });
22402
22808
  return;
@@ -22678,6 +23084,12 @@ function App() {
22678
23084
  case "planControl":
22679
23085
  ctrlKeyHandledRef.current = true;
22680
23086
  setPlanApprovalIndex(0);
23087
+ if (action.action === "revise") {
23088
+ setPendingPlanProposal(null);
23089
+ setInputValue("Revise the plan: ");
23090
+ dispatch({ type: "info", message: "Type your revision and press Enter (Esc clears)." });
23091
+ return;
23092
+ }
22681
23093
  handleSubmit(action.action === "approve" ? "/approve" : "/cancel");
22682
23094
  return;
22683
23095
  case "movePlanApproval":
@@ -22814,6 +23226,27 @@ function App() {
22814
23226
  useEffect6(() => {
22815
23227
  modeRef.current = mode;
22816
23228
  }, [mode]);
23229
+ useEffect6(() => {
23230
+ const planState = String(activePlan?.state ?? "");
23231
+ const planAwaiting = planState === "awaiting_approval";
23232
+ const planId = String(activePlan?.id ?? "");
23233
+ if (questionState || planAwaiting) {
23234
+ const freshPlan = planAwaiting && planId && planId !== awaitingPlanAnnouncedRef.current;
23235
+ if (!pendingBellRef.current || freshPlan) {
23236
+ bell();
23237
+ pendingBellRef.current = true;
23238
+ }
23239
+ if (freshPlan) awaitingPlanAnnouncedRef.current = planId;
23240
+ setWindowTitle("\u25CF agon \u2014 input needed");
23241
+ } else if (replState === "idle") {
23242
+ setWindowTitle("agon");
23243
+ } else {
23244
+ setWindowTitle("\u25CF agon \u2014 running");
23245
+ }
23246
+ if (!planAwaiting) {
23247
+ awaitingPlanAnnouncedRef.current = "";
23248
+ }
23249
+ }, [questionState, activePlan, replState, bell, setWindowTitle, pendingBellRef, awaitingPlanAnnouncedRef]);
22817
23250
  useEffect6(() => {
22818
23251
  mouseSelectionRef.current = mouseSelection;
22819
23252
  }, [mouseSelection]);
@@ -23902,7 +24335,7 @@ maybeNotifyIsolationMigration();
23902
24335
  var main = defineCommand31({
23903
24336
  meta: {
23904
24337
  name: "agon",
23905
- version: "0.1.6",
24338
+ version: "0.1.8",
23906
24339
  description: "Any AI can join. They compete. You ship."
23907
24340
  },
23908
24341
  subCommands: {