omnius 1.0.513 → 1.0.515

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -38536,29 +38536,29 @@ ${earlyError ? "\n" + earlyError : ""}${earlyOutput ? "\n" + earlyOutput : ""}`;
38536
38536
  });
38537
38537
  }
38538
38538
  const inferResult = parsed.result;
38539
- let responseText = "";
38539
+ let responseText2 = "";
38540
38540
  if (typeof inferResult === "string") {
38541
- responseText = inferResult;
38541
+ responseText2 = inferResult;
38542
38542
  } else if (inferResult) {
38543
38543
  const events = Array.isArray(inferResult) ? inferResult : [inferResult];
38544
38544
  for (const evt of events) {
38545
38545
  if (evt.event === "result" && evt.data) {
38546
38546
  try {
38547
38547
  const data = typeof evt.data === "string" ? JSON.parse(evt.data) : evt.data;
38548
- responseText = data.response || data.content || JSON.stringify(data);
38548
+ responseText2 = data.response || data.content || JSON.stringify(data);
38549
38549
  } catch {
38550
- responseText = String(evt.data);
38550
+ responseText2 = String(evt.data);
38551
38551
  }
38552
38552
  }
38553
38553
  }
38554
- if (!responseText) {
38555
- responseText = JSON.stringify(inferResult, null, 2);
38554
+ if (!responseText2) {
38555
+ responseText2 = JSON.stringify(inferResult, null, 2);
38556
38556
  }
38557
38557
  }
38558
38558
  const lines = [
38559
38559
  `Remote inference result (${model} via ${peerUsed.slice(0, 20)}...):`,
38560
38560
  ``,
38561
- responseText,
38561
+ responseText2,
38562
38562
  ``,
38563
38563
  `--- Metadata ---`,
38564
38564
  `Model: ${parsed.model || model}`,
@@ -254056,14 +254056,14 @@ async function fetchXML(url, init2) {
254056
254056
  if (contentType?.includes("/xml") !== true) {
254057
254057
  throw new Error(`Bad content type: ${contentType}`);
254058
254058
  }
254059
- const responseText = await response.text();
254060
- log8.trace("<-", responseText);
254059
+ const responseText2 = await response.text();
254060
+ log8.trace("<-", responseText2);
254061
254061
  const parser2 = new import_xml2js.default.Parser({
254062
254062
  explicitRoot: false,
254063
254063
  explicitArray: false,
254064
254064
  attrkey: "@"
254065
254065
  });
254066
- const responseBody = await parser2.parseStringPromise(responseText);
254066
+ const responseBody = await parser2.parseStringPromise(responseText2);
254067
254067
  if (!response.ok) {
254068
254068
  const soapns = getNamespace(responseBody, NS_SOAP);
254069
254069
  const body = responseBody[`${soapns}Body`];
@@ -576538,7 +576538,13 @@ function violatesDirective(directive, input, cwd4) {
576538
576538
  return false;
576539
576539
  return true;
576540
576540
  case "run_verification":
576541
- return input.toolName !== "shell";
576541
+ if (input.toolName === "shell")
576542
+ return false;
576543
+ if (isEvidenceGatheringTool(input.toolName) || input.isReadLike)
576544
+ return false;
576545
+ if (isEditTool(input.toolName))
576546
+ return false;
576547
+ return true;
576542
576548
  case "report_blocked":
576543
576549
  case "report_incomplete":
576544
576550
  return !isReportTool(input.toolName);
@@ -578108,8 +578114,8 @@ function extractSignificantNgrams(text2) {
578108
578114
  }
578109
578115
  return grams;
578110
578116
  }
578111
- function computeGroundedness(responseText, contextSpans, turn) {
578112
- const claims = extractClaims(responseText);
578117
+ function computeGroundedness(responseText2, contextSpans, turn) {
578118
+ const claims = extractClaims(responseText2);
578113
578119
  const total_claims = claims.length;
578114
578120
  if (total_claims === 0) {
578115
578121
  return {
@@ -579005,10 +579011,10 @@ The sub-agent works in its own small context; when it folds back, run the build
579005
579011
  * Compute per-turn groundedness for an assistant response.
579006
579012
  * Stores the result in an internal history and returns the report.
579007
579013
  */
579008
- computeGroundedness(responseText, messages2, turn) {
579014
+ computeGroundedness(responseText2, messages2, turn) {
579009
579015
  try {
579010
579016
  const contextSpans = extractContextSpansForGroundedness(messages2);
579011
- const report2 = computeGroundedness(responseText, contextSpans, turn);
579017
+ const report2 = computeGroundedness(responseText2, contextSpans, turn);
579012
579018
  this._groundednessHistory.push(report2);
579013
579019
  return report2;
579014
579020
  } catch {
@@ -582003,6 +582009,19 @@ function malformedToolArgsMessage(toolName, raw) {
582003
582009
  function looksLikeShellFileWrite(command) {
582004
582010
  return /\bcat\s+[^|;&\n]*>\s*[^&|;\n]+/.test(command) || /\b(?:tee|dd)\b[\s\S]*(?:\bof=|>\s*[^&|;\n]+)/.test(command) || /\b(?:echo|printf)\b[\s\S]*>\s*[^&|;\n]+/.test(command) || /\bpython(?:3)?\b[\s\S]*(?:write_text|open\([^)]*["']w["'])/.test(command) || /<<\s*['"]?\w+['"]?[\s\S]*>\s*[^&|;\n]+/.test(command);
582005
582011
  }
582012
+ function normalizeShellCommandForFingerprint(command) {
582013
+ let c10 = command.trim().replace(/\s+/g, " ");
582014
+ let prev = "";
582015
+ while (prev !== c10) {
582016
+ prev = c10;
582017
+ c10 = c10.replace(/^echo\s+(?:"[^"]*"|'[^']*')\s*(?:&&|;)\s*/i, "");
582018
+ }
582019
+ c10 = c10.replace(/\s*(?:;|&&)\s*echo\s+(?:"[^"]*\$\?[^"]*"|'[^']*\$\?[^']*'|\S*\$\?\S*)\s*$/i, "");
582020
+ c10 = c10.replace(/\s*\|\s*(?:head|tail)\s+(?:-n\s*)?-?\d+\s*$/i, "");
582021
+ c10 = c10.replace(/\s*\|\s*(?:head|tail)\s+-c\s*\d+\s*$/i, "");
582022
+ c10 = c10.replace(/\s*2>&1\s*$/, "");
582023
+ return c10.trim();
582024
+ }
582006
582025
  function normalizeProviderToolMessage(msg, model) {
582007
582026
  const rawContent2 = typeof msg.content === "string" ? msg.content : "";
582008
582027
  const profile = resolveModelProfile(model);
@@ -582940,9 +582959,13 @@ var init_agenticRunner = __esm({
582940
582959
  // of the same completion gate and terminate as incomplete_verification after a
582941
582960
  // small threshold so the run stops without falsely marking completion.
582942
582961
  // Reset whenever a completion is allowed.
582962
+ // `total` (REG-74) counts EVERY hold this run regardless of gate/summary key —
582963
+ // rotating gate codes or paraphrased summaries reset `count` but never
582964
+ // `total`, so the hard-escape below cannot be starved by variation.
582943
582965
  _completionHoldState = {
582944
582966
  count: 0,
582945
- lastKey: ""
582967
+ lastKey: "",
582968
+ total: 0
582946
582969
  };
582947
582970
  _completionIncompleteVerification = null;
582948
582971
  /**
@@ -586128,7 +586151,7 @@ ${shellLines.join("\n")}` : "Commands run: none"
586128
586151
  }
586129
586152
  if (!verdict)
586130
586153
  return { proceed: true };
586131
- if (verdict.resolved || verdict.confidence < 0.5) {
586154
+ if (verdict.resolved || verdict.confidence < 0.65) {
586132
586155
  this._resolutionGateRejections = 0;
586133
586156
  return { proceed: true };
586134
586157
  }
@@ -588980,6 +589003,11 @@ ${blob}
588980
589003
  }
588981
589004
  _buildToolFingerprint(name10, args) {
588982
589005
  const canonical = this.lookupRegisteredTool(name10)?.name ?? name10;
589006
+ if (canonical === "shell" && typeof args?.["command"] === "string") {
589007
+ const normalized = normalizeShellCommandForFingerprint(args["command"]);
589008
+ const rest = this._buildExactArgsKey({ ...args, command: normalized });
589009
+ return `${canonical}:${rest}`;
589010
+ }
588983
589011
  return `${canonical}:${this._buildExactArgsKey(args)}`;
588984
589012
  }
588985
589013
  // ── REG-71: region-aware read dedup ────────────────────────────────────────
@@ -590743,14 +590771,41 @@ TASK: ${scrubbedTask}` : scrubbedTask;
590743
590771
  const raw = Number(process.env["OMNIUS_COMPLETION_HOLD_MAX"]);
590744
590772
  return Number.isFinite(raw) && raw >= 1 ? Math.floor(raw) : 3;
590745
590773
  })();
590774
+ const completionHoldHardMax = (() => {
590775
+ const raw = Number(process.env["OMNIUS_COMPLETION_HOLD_HARD_MAX"]);
590776
+ if (Number.isFinite(raw) && raw >= 1)
590777
+ return Math.floor(raw);
590778
+ return completionHoldEscapeMax * 2;
590779
+ })();
590746
590780
  const holdTaskCompleteGates = (args, turn) => {
590781
+ if (this._completionHoldState.total >= completionHoldHardMax) {
590782
+ const caveat = [
590783
+ `[UNVERIFIED — completion accepted after ${this._completionHoldState.total} gate holds]`,
590784
+ lastCompletionGateReason ? `Last unresolved gate: ${lastCompletionGateReason.slice(0, 300)}` : ""
590785
+ ].filter(Boolean).join("\n");
590786
+ this._completionCaveat = this._completionCaveat ? `${this._completionCaveat}
590787
+ ${caveat}` : caveat;
590788
+ this.emit({
590789
+ type: "status",
590790
+ content: `Completion hold hard-escape: allowing task_complete after ${this._completionHoldState.total} total holds (caveat recorded)`,
590791
+ turn,
590792
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
590793
+ });
590794
+ this._completionHoldState.count = 0;
590795
+ this._completionHoldState.lastKey = "";
590796
+ this._completionHoldState.total = 0;
590797
+ lastCompletionGateCode = "";
590798
+ return false;
590799
+ }
590747
590800
  const held = holdUnresolvedVerificationTaskComplete(turn) || holdNoProgressTaskComplete(args, turn) || holdProvenanceTaskComplete(args, turn);
590748
590801
  if (!held) {
590749
590802
  this._completionHoldState.count = 0;
590750
590803
  this._completionHoldState.lastKey = "";
590804
+ this._completionHoldState.total = 0;
590751
590805
  lastCompletionGateCode = "";
590752
590806
  return false;
590753
590807
  }
590808
+ this._completionHoldState.total += 1;
590754
590809
  this._focusSupervisor?.markCompletionBlocked({
590755
590810
  turn,
590756
590811
  reason: lastCompletionGateReason || "completion requested before required evidence was present",
@@ -596243,9 +596298,20 @@ Your most recent tool calls SUCCEEDED. If the task is complete, call task_comple
596243
596298
  });
596244
596299
  break;
596245
596300
  }
596246
- const codeBlockMatch = content.match(/```(?:bash|sh|shell|zsh)?\s*\n([\s\S]*?)```/);
596247
- if (codeBlockMatch && codeBlockMatch[1]?.trim()) {
596248
- const shellCommands = codeBlockMatch[1].trim().split("\n").filter((l2) => l2.trim() && !l2.trim().startsWith("#")).join(" && ");
596301
+ const codeBlockMatch = content.match(/```(?:bash|sh|shell|zsh)\s*\n([\s\S]*?)```/);
596302
+ const codeBlockLines = codeBlockMatch?.[1] ? codeBlockMatch[1].trim().split("\n").filter((l2) => l2.trim() && !l2.trim().startsWith("#")) : [];
596303
+ const everyLineLooksExecutable = codeBlockLines.length > 0 && codeBlockLines.every((l2) => {
596304
+ const t2 = l2.trim();
596305
+ if (/^\d+[:.]/.test(t2))
596306
+ return false;
596307
+ if (/^(\/\/|\/\*|\*|→|▶|✔|✖|[│├└╭╰|])/.test(t2))
596308
+ return false;
596309
+ if (/^[<>{}[\]]/.test(t2))
596310
+ return false;
596311
+ return /^[A-Za-z_./~"'$(]/.test(t2);
596312
+ });
596313
+ if (codeBlockMatch && everyLineLooksExecutable) {
596314
+ const shellCommands = codeBlockLines.join(" && ");
596249
596315
  if (shellCommands.length > 0 && shellCommands.length < 2e3) {
596250
596316
  if (looksLikeShellFileWrite(shellCommands)) {
596251
596317
  messages2.push({
@@ -603047,9 +603113,9 @@ ${description}`
603047
603113
  const choices = data.choices ?? [];
603048
603114
  const usage = data.usage;
603049
603115
  const firstChoice = choices[0];
603050
- const responseText = firstChoice ? String(firstChoice.message?.content ?? "") : "";
603051
- const outcome = this.recordThinkOutcome(responseText, effectiveThink === true);
603052
- const independentOutcome = effectiveThink !== true ? classifyThinkOutcome(responseText) : null;
603116
+ const responseText2 = firstChoice ? String(firstChoice.message?.content ?? "") : "";
603117
+ const outcome = this.recordThinkOutcome(responseText2, effectiveThink === true);
603118
+ const independentOutcome = effectiveThink !== true ? classifyThinkOutcome(responseText2) : null;
603053
603119
  const shouldRecoverFromEmpty = request.disableEmptyContentRecovery !== true && responseFormat !== void 0 && independentOutcome !== null && (independentOutcome === "empty_after_strip" || independentOutcome === "unclosed_think");
603054
603120
  const justSuppressed = this._thinkSuppressed && this._thinkFailStreak === _OllamaAgenticBackend._thinkFailThreshold;
603055
603121
  const shouldRetryThinkGuard = outcome !== null && effectiveThink === true && (justSuppressed || outcome === "empty_after_strip" || outcome === "unclosed_think");
@@ -617966,6 +618032,128 @@ var init_conversation_context = __esm({
617966
618032
  }
617967
618033
  });
617968
618034
 
618035
+ // packages/cli/src/tui/prompt-enhance.ts
618036
+ function stripThinkBlocks2(text2) {
618037
+ let out = text2.replace(/<think>[\s\S]*?<\/think>/gi, "");
618038
+ const open2 = out.search(/<think>/i);
618039
+ if (open2 >= 0) out = out.slice(0, open2);
618040
+ const close = out.search(/<\/think>/i);
618041
+ if (close >= 0) out = out.slice(close + "</think>".length);
618042
+ return out.trim();
618043
+ }
618044
+ function extractEnhancedPrompt(raw) {
618045
+ const text2 = stripThinkBlocks2(raw.trim());
618046
+ if (!text2) return null;
618047
+ const tryParse = (candidate) => {
618048
+ try {
618049
+ const obj = JSON.parse(candidate);
618050
+ const v = obj["enhancedPrompt"] ?? obj["enhanced_prompt"] ?? obj["prompt"] ?? obj["result"];
618051
+ return typeof v === "string" && v.trim() ? v : null;
618052
+ } catch {
618053
+ return null;
618054
+ }
618055
+ };
618056
+ const direct = tryParse(text2);
618057
+ if (direct) return direct;
618058
+ const fenced = text2.match(/```(?:json)?\s*([\s\S]*?)```/i);
618059
+ if (fenced?.[1]) {
618060
+ const f2 = tryParse(fenced[1].trim());
618061
+ if (f2) return f2;
618062
+ }
618063
+ const brace = text2.match(/\{[\s\S]*\}/);
618064
+ if (brace?.[0]) {
618065
+ const b = tryParse(brace[0]);
618066
+ if (b) return b;
618067
+ }
618068
+ const keyed = text2.match(/"enhanced_?[Pp]rompt"\s*:\s*"((?:[^"\\]|\\.)*)"/);
618069
+ if (keyed?.[1]) {
618070
+ try {
618071
+ return JSON.parse('"' + keyed[1] + '"');
618072
+ } catch {
618073
+ return keyed[1];
618074
+ }
618075
+ }
618076
+ if (!text2.startsWith("{") && !text2.startsWith("[")) return text2;
618077
+ return null;
618078
+ }
618079
+ function responseText(resp) {
618080
+ const msg = resp.choices?.[0]?.message;
618081
+ if (!msg) return "";
618082
+ const content = (msg.content ?? "").trim();
618083
+ if (content) return content;
618084
+ const reasoning = (msg.reasoning_content ?? msg.reasoning ?? "").trim();
618085
+ return reasoning;
618086
+ }
618087
+ function acceptableEnhancement(clean5, seedText) {
618088
+ if (!clean5) return false;
618089
+ if (clean5 === seedText) return false;
618090
+ if (/<think>/i.test(clean5)) return false;
618091
+ if (clean5.length > 12e3) return false;
618092
+ if (clean5.length < Math.min(24, seedText.length / 2)) return false;
618093
+ return true;
618094
+ }
618095
+ async function enhancePromptViaInference(seed, backend, ctx3) {
618096
+ const seedText = seed.trim();
618097
+ if (!seedText) return null;
618098
+ const recent = ctx3.recentHistory.filter((h) => h && h.trim()).slice(0, 5).map((h, i2) => ` ${i2 + 1}. ${h.trim().slice(0, 240)}`).join("\n");
618099
+ const runtimeCtx = ctx3.runtimeContext ?? "";
618100
+ const userPrompt = [
618101
+ "Expand the SEED PROMPT below into a comprehensive, precise, self-contained instruction set for an agentic coding assistant.",
618102
+ "Preserve the user's original intent exactly. Do NOT answer or solve it, do NOT invent unrelated scope.",
618103
+ "Clarify the goal, surface implied requirements, relevant constraints, edge cases, and concrete acceptance criteria.",
618104
+ "Fold in only the session context that is actually relevant. Keep it phrased as an instruction in the user's voice.",
618105
+ "Return no preamble and no meta-commentary about the prompt itself.",
618106
+ ctx3.activeGoal ? `
618107
+ Task currently in progress: ${ctx3.activeGoal.slice(0, 400)}` : "",
618108
+ recent ? `
618109
+ Recent prompts this session (newest first):
618110
+ ${recent}` : "",
618111
+ runtimeCtx ? `
618112
+ Session/runtime context:
618113
+ ${runtimeCtx}` : "",
618114
+ `
618115
+ SEED PROMPT:
618116
+ ${seedText}`
618117
+ ].filter(Boolean).join("\n");
618118
+ const jsonSystem = `You are a prompt-expansion engine. You rewrite a user's short seed prompt into a richer, unambiguous instruction that fully captures their intent. Return strict JSON only: {"enhancedPrompt": string}.`;
618119
+ const plainSystem = "You are a prompt-expansion engine. You rewrite a user's short seed prompt into a richer, unambiguous instruction that fully captures their intent. Return ONLY the rewritten prompt as plain text — no JSON, no preamble, no commentary.";
618120
+ const call = (system, withJsonMode) => backend.chatCompletion({
618121
+ messages: [
618122
+ { role: "system", content: system },
618123
+ { role: "user", content: userPrompt }
618124
+ ],
618125
+ tools: [],
618126
+ temperature: 0.4,
618127
+ maxTokens: 1400,
618128
+ timeoutMs: 9e4,
618129
+ think: false,
618130
+ ...withJsonMode ? { responseFormat: { type: "json_object" } } : {}
618131
+ });
618132
+ const attempt = async (system, withJsonMode) => {
618133
+ try {
618134
+ const resp = await call(system, withJsonMode);
618135
+ const raw = responseText(resp);
618136
+ if (!raw) return null;
618137
+ const enhanced = extractEnhancedPrompt(raw);
618138
+ if (!enhanced) return null;
618139
+ const clean5 = enhanced.trim();
618140
+ return acceptableEnhancement(clean5, seedText) ? clean5 : null;
618141
+ } catch {
618142
+ return null;
618143
+ }
618144
+ };
618145
+ const strict = await attempt(jsonSystem, true);
618146
+ if (strict) return strict;
618147
+ const loose = await attempt(jsonSystem, false);
618148
+ if (loose) return loose;
618149
+ return attempt(plainSystem, false);
618150
+ }
618151
+ var init_prompt_enhance = __esm({
618152
+ "packages/cli/src/tui/prompt-enhance.ts"() {
618153
+ "use strict";
618154
+ }
618155
+ });
618156
+
617969
618157
  // packages/cli/src/tui/generative-progress.ts
617970
618158
  function generationKindForToolName(toolName) {
617971
618159
  if (toolName === "generate_image") return "image";
@@ -625466,6 +625654,67 @@ function toolColorSeq(code8, bold = false) {
625466
625654
  function toolResetSeq() {
625467
625655
  return _colorsEnabled && stdoutIsTTY() ? RESET2 : "";
625468
625656
  }
625657
+ function truecolorOk() {
625658
+ if (_truecolorCache !== null) return _truecolorCache;
625659
+ const ct = process.env.COLORTERM;
625660
+ _truecolorCache = ct === "truecolor" || ct === "24bit" || /-256color$|-truecolor$|kitty|wezterm|alacritty|ghostty|rio|contour/.test(
625661
+ process.env.TERM ?? ""
625662
+ );
625663
+ return _truecolorCache;
625664
+ }
625665
+ function xterm256ToRgb(idx) {
625666
+ if (idx >= 16 && idx <= 231) {
625667
+ const n2 = idx - 16;
625668
+ const lv = [0, 95, 135, 175, 215, 255];
625669
+ return [lv[Math.floor(n2 / 36)], lv[Math.floor(n2 / 6) % 6], lv[n2 % 6]];
625670
+ }
625671
+ if (idx >= 232 && idx <= 255) {
625672
+ const v = 8 + 10 * (idx - 232);
625673
+ return [v, v, v];
625674
+ }
625675
+ const basic = [
625676
+ [0, 0, 0],
625677
+ [205, 49, 49],
625678
+ [13, 188, 121],
625679
+ [229, 229, 16],
625680
+ [36, 114, 200],
625681
+ [188, 63, 188],
625682
+ [17, 168, 205],
625683
+ [229, 229, 229],
625684
+ [102, 102, 102],
625685
+ [241, 76, 76],
625686
+ [35, 209, 139],
625687
+ [245, 245, 67],
625688
+ [59, 142, 234],
625689
+ [214, 112, 214],
625690
+ [41, 184, 219],
625691
+ [255, 255, 255]
625692
+ ];
625693
+ return basic[Math.max(0, Math.min(15, idx))] ?? [200, 200, 200];
625694
+ }
625695
+ function toolGradSeq(colorCode, frac) {
625696
+ if (!_colorsEnabled || !stdoutIsTTY()) return "";
625697
+ if (!truecolorOk()) return toolColorSeq(colorCode);
625698
+ const [r2, g, b] = xterm256ToRgb(colorCode);
625699
+ const f2 = Math.max(0, Math.min(1, frac));
625700
+ const scale = 0.78 + 0.36 * f2;
625701
+ const cl = (v) => Math.max(0, Math.min(255, Math.round(v * scale)));
625702
+ return `\x1B[38;2;${cl(r2)};${cl(g)};${cl(b)}m`;
625703
+ }
625704
+ function paintToolBorder(glyphs, startCol, totalWidth, colorCode) {
625705
+ if (glyphs.length === 0) return "";
625706
+ if (!_colorsEnabled || !stdoutIsTTY() || !truecolorOk()) {
625707
+ return `${toolColorSeq(colorCode)}${glyphs}`;
625708
+ }
625709
+ const SEG = 6;
625710
+ const denom = Math.max(1, totalWidth - 1);
625711
+ let out = "";
625712
+ for (let i2 = 0; i2 < glyphs.length; i2 += SEG) {
625713
+ out += toolGradSeq(colorCode, (startCol + i2) / denom);
625714
+ out += glyphs.slice(i2, i2 + SEG);
625715
+ }
625716
+ return out;
625717
+ }
625469
625718
  function charWidth2(ch) {
625470
625719
  const cp2 = ch.codePointAt(0);
625471
625720
  if (cp2 >= 4352 && cp2 <= 4447 || // Hangul Jamo
@@ -625600,45 +625849,86 @@ function buildToolTopBorder(title, metrics2, width, colorCode, metricsColorCode
625600
625849
  const titleSpan = titleChip.length + 2;
625601
625850
  const metricsChip = metricsVisible ? ` ${metricsVisible} ` : "";
625602
625851
  const metricsSpan = metricsChip ? metricsChip.length + 2 : 0;
625603
- let titleSegment;
625604
- let metricsSegment = "";
625852
+ void border;
625853
+ let col = 0;
625854
+ const grad = (glyphs) => {
625855
+ const s2 = paintToolBorder(glyphs, col, width, colorCode);
625856
+ col += glyphs.length;
625857
+ return s2;
625858
+ };
625859
+ let effTitleChip = titleChip;
625860
+ let metricsIncluded = false;
625605
625861
  let fillerWidth;
625606
625862
  if (titleSpan + metricsSpan + 4 <= inner) {
625607
- titleSegment = `${border}┤${titleColor}${titleChip}${reset}${border}├`;
625608
- metricsSegment = metricsChip ? `${border}┤${metricColor}${metricsChip}${reset}${border}├` : "";
625863
+ metricsIncluded = !!metricsChip;
625609
625864
  fillerWidth = inner - titleSpan - metricsSpan - 2;
625610
625865
  } else if (titleSpan + 4 <= inner) {
625611
- titleSegment = `${border}┤${titleColor}${titleChip}${reset}${border}├`;
625612
625866
  fillerWidth = inner - titleSpan - 2;
625613
625867
  } else {
625614
625868
  const room = Math.max(3, inner - 8);
625615
625869
  const truncated = titleVisible.length > room ? titleVisible.slice(0, Math.max(1, room - 1)) + "…" : titleVisible;
625616
- titleSegment = `${border}┤${titleColor} ${truncated} ${reset}${border}├`;
625870
+ effTitleChip = ` ${truncated} `;
625617
625871
  fillerWidth = Math.max(0, inner - (truncated.length + 4) - 2);
625618
625872
  }
625619
- return `${border}${BOX_TL2}${BOX_H2}${titleSegment}${BOX_H2.repeat(Math.max(0, fillerWidth))}${metricsSegment}${BOX_H2}${BOX_TR2}${reset}`;
625873
+ let out = grad(`${BOX_TL2}${BOX_H2}`);
625874
+ out += grad("┤");
625875
+ out += `${titleColor}${effTitleChip}${reset}`;
625876
+ col += effTitleChip.length;
625877
+ out += grad("├");
625878
+ out += grad(BOX_H2.repeat(Math.max(0, fillerWidth)));
625879
+ if (metricsIncluded) {
625880
+ out += grad("┤");
625881
+ out += `${metricColor}${metricsChip}${reset}`;
625882
+ col += metricsChip.length;
625883
+ out += grad("├");
625884
+ }
625885
+ out += grad(`${BOX_H2}${BOX_TR2}`);
625886
+ return out + reset;
625620
625887
  }
625621
625888
  function buildToolDivider(width, colorCode) {
625622
- const border = toolColorSeq(colorCode);
625623
- return `${border}${BOX_TJ_L2}${BOX_H2.repeat(Math.max(0, width - 2))}${BOX_TJ_R2}${toolResetSeq()}`;
625889
+ return paintToolBorder(
625890
+ `${BOX_TJ_L2}${BOX_H2.repeat(Math.max(0, width - 2))}${BOX_TJ_R2}`,
625891
+ 0,
625892
+ width,
625893
+ colorCode
625894
+ ) + toolResetSeq();
625624
625895
  }
625625
625896
  function buildRoutingHeader(title, _metrics, width, colorCode, _metricsColorCode = 222) {
625626
625897
  const border = toolColorSeq(colorCode);
625627
625898
  const titleColor = toolColorSeq(colorCode, true);
625628
625899
  const reset = toolResetSeq();
625629
625900
  const w = Math.max(40, width);
625901
+ void border;
625630
625902
  const titleVisible = stripAnsi(title);
625631
625903
  const titleChip = ` ${titleVisible} `;
625632
625904
  const shortBoxWidth = titleChip.length + 7;
625633
- const line1 = `${border}${BOX_TL2}${BOX_H2}${border}${BOX_TJ_L2}${titleColor}${titleChip}${reset}${border}${BOX_TJ_R2}${BOX_H2}${BOX_H2}${BOX_TR2}${reset}`;
625905
+ let col = 0;
625906
+ const grad1 = (glyphs) => {
625907
+ const s2 = paintToolBorder(glyphs, col, w, colorCode);
625908
+ col += glyphs.length;
625909
+ return s2;
625910
+ };
625911
+ let line1 = grad1(`${BOX_TL2}${BOX_H2}${BOX_TJ_L2}`);
625912
+ line1 += `${titleColor}${titleChip}${reset}`;
625913
+ col += titleChip.length;
625914
+ line1 += grad1(`${BOX_TJ_R2}${BOX_H2}${BOX_H2}${BOX_TR2}`) + reset;
625634
625915
  const gap = Math.max(0, shortBoxWidth - 1);
625635
625916
  const dashCount = Math.max(0, w - shortBoxWidth - 2);
625636
- const line2 = `${border}${BOX_TJ_L2}${reset}` + " ".repeat(gap) + `${border}╰${BOX_H2.repeat(dashCount)}${BOX_TJ_R2}${reset}`;
625917
+ const line2 = `${paintToolBorder(BOX_TJ_L2, 0, w, colorCode)}${reset}` + " ".repeat(gap) + paintToolBorder(
625918
+ `╰${BOX_H2.repeat(dashCount)}${BOX_TJ_R2}`,
625919
+ gap + 1,
625920
+ w,
625921
+ colorCode
625922
+ ) + reset;
625637
625923
  return [line1, line2];
625638
625924
  }
625639
625925
  function buildToolBottom(width, colorCode) {
625640
- const border = toolColorSeq(colorCode);
625641
- return `${border}${BOX_BL2}${BOX_H2.repeat(Math.max(0, width - 2))}${BOX_BR2}${toolResetSeq()}`;
625926
+ return paintToolBorder(
625927
+ `${BOX_BL2}${BOX_H2.repeat(Math.max(0, width - 2))}${BOX_BR2}`,
625928
+ 0,
625929
+ width,
625930
+ colorCode
625931
+ ) + toolResetSeq();
625642
625932
  }
625643
625933
  function dimSeqOrEmpty() {
625644
625934
  return _colorsEnabled && stdoutIsTTY() ? "\x1B[2m" : "";
@@ -625749,14 +626039,15 @@ function renderPersistedDynamicBlockSpec(spec, width, id2) {
625749
626039
  }
625750
626040
  }
625751
626041
  function buildToolContentRow(content, width, colorCode) {
625752
- const border = toolColorSeq(colorCode);
625753
626042
  const reset = toolResetSeq();
625754
626043
  const innerWidth = Math.max(1, width - 4);
625755
626044
  content = sanitizeToolBoxContent(content);
625756
626045
  let padded = visibleLen(content) > innerWidth ? truncateAnsiToWidth(content, innerWidth) : content;
625757
626046
  const visible = visibleLen(padded);
625758
626047
  if (visible < innerWidth) padded += " ".repeat(innerWidth - visible);
625759
- return `${border}${BOX_V2}${reset} ${padded} ${border}${BOX_V2}${reset}`;
626048
+ const left = truecolorOk() ? toolGradSeq(colorCode, 0) : toolColorSeq(colorCode);
626049
+ const right = truecolorOk() ? toolGradSeq(colorCode, 1) : toolColorSeq(colorCode);
626050
+ return `${left}${BOX_V2}${reset} ${padded} ${right}${BOX_V2}${reset}`;
625760
626051
  }
625761
626052
  function formatToolBoxLine(line, kind) {
625762
626053
  line = sanitizeToolBoxContent(line);
@@ -627036,7 +627327,7 @@ function formatDuration4(ms) {
627036
627327
  const secs = Math.floor(totalSecs % 60);
627037
627328
  return `${mins}m ${secs}s`;
627038
627329
  }
627039
- var c3, ui, pastel, _emojisEnabled, _colorsEnabled, MD, TOOL_LABELS, TOOL_COLOR_CODES, TOOL_ERROR_COLOR_CODE, BOX_TL2, BOX_TR2, BOX_BL2, BOX_BR2, BOX_H2, BOX_V2, BOX_TJ_L2, BOX_TJ_R2, RESET2, _telegramCoalesce, _pendingToolCall, _voiceChatCoalesce, VOICECHAT_VISIBLE_ROWS, VOICECHAT_EXPAND_LABEL, VOICECHAT_COLLAPSE_LABEL, DIFF_LINE_RE, _contentWriteHook, HINTS, TOOL_NAMES, COMMAND_NAMES, SLASH_COMMANDS2;
627330
+ var c3, ui, pastel, _emojisEnabled, _colorsEnabled, MD, TOOL_LABELS, TOOL_COLOR_CODES, TOOL_ERROR_COLOR_CODE, BOX_TL2, BOX_TR2, BOX_BL2, BOX_BR2, BOX_H2, BOX_V2, BOX_TJ_L2, BOX_TJ_R2, RESET2, _truecolorCache, _telegramCoalesce, _pendingToolCall, _voiceChatCoalesce, VOICECHAT_VISIBLE_ROWS, VOICECHAT_EXPAND_LABEL, VOICECHAT_COLLAPSE_LABEL, DIFF_LINE_RE, _contentWriteHook, HINTS, TOOL_NAMES, COMMAND_NAMES, SLASH_COMMANDS2;
627040
627331
  var init_render = __esm({
627041
627332
  "packages/cli/src/tui/render.ts"() {
627042
627333
  "use strict";
@@ -627195,6 +627486,7 @@ var init_render = __esm({
627195
627486
  BOX_TJ_L2 = "├";
627196
627487
  BOX_TJ_R2 = "┤";
627197
627488
  RESET2 = "\x1B[0m";
627489
+ _truecolorCache = null;
627198
627490
  _telegramCoalesce = null;
627199
627491
  _pendingToolCall = null;
627200
627492
  _voiceChatCoalesce = null;
@@ -635555,6 +635847,19 @@ var init_dist9 = __esm({
635555
635847
  });
635556
635848
 
635557
635849
  // packages/cli/src/tui/stageIndicator.ts
635850
+ function tri360(x) {
635851
+ const t2 = (x % 360 + 360) % 360;
635852
+ return t2 < 180 ? t2 / 90 - 1 : 3 - t2 / 90;
635853
+ }
635854
+ function stageHueAt(stage2, col, phase) {
635855
+ const meta = STAGE_META[stage2];
635856
+ const wave = tri360(col * 9 + phase);
635857
+ const hue = meta.baseHue + wave * STAGE_HUE_SPAN;
635858
+ return (Math.round(hue) % 360 + 360) % 360;
635859
+ }
635860
+ function stageGradientRgb(stage2, col, phase) {
635861
+ return HUE_LUT[stageHueAt(stage2, col, phase)] ?? HUE_LUT[0];
635862
+ }
635558
635863
  function supportsTruecolor() {
635559
635864
  const colorterm = process.env.COLORTERM;
635560
635865
  if (colorterm === "truecolor" || colorterm === "24bit") return true;
@@ -635566,6 +635871,12 @@ function supportsTruecolor() {
635566
635871
  function isSweepingStage(stage2) {
635567
635872
  return SWEEPING_STAGES.has(stage2);
635568
635873
  }
635874
+ function stageBlockNeededWidth(stage2, detail) {
635875
+ const meta = STAGE_META[stage2];
635876
+ let body = meta.label;
635877
+ if (detail && detail.length > 0) body += ` ${detail}`;
635878
+ return 2 + body.length + 1;
635879
+ }
635569
635880
  function stageBlockText(stage2, detail, width) {
635570
635881
  const meta = STAGE_META[stage2];
635571
635882
  const lead = "▌ ";
@@ -635596,8 +635907,7 @@ function renderStageBlock(stage2, detail, width, phase, truecolor) {
635596
635907
  out += " ";
635597
635908
  continue;
635598
635909
  }
635599
- const hue = sweeping ? (meta.baseHue + i2 * 4 + normPhase) % 360 : meta.baseHue;
635600
- const [r2, g, b] = HUE_LUT[hue] ?? HUE_LUT[0];
635910
+ const [r2, g, b] = sweeping ? stageGradientRgb(stage2, i2, normPhase) : HUE_LUT[meta.baseHue] ?? HUE_LUT[0];
635601
635911
  out += `\x1B[38;2;${r2};${g};${b}m${ch}`;
635602
635912
  }
635603
635913
  out += "\x1B[0m";
@@ -635652,7 +635962,14 @@ function setStage(stage2, detail) {
635652
635962
  function getStage() {
635653
635963
  return { stage: _currentStage, detail: _currentDetail };
635654
635964
  }
635655
- var STAGE_META, SWEEPING_STAGES, MAX_GRADIENT_COLS, HUE_LUT, _currentStage, _currentDetail, _subscribers;
635965
+ function onStageChange(cb) {
635966
+ _subscribers.push(cb);
635967
+ return () => {
635968
+ const i2 = _subscribers.indexOf(cb);
635969
+ if (i2 >= 0) _subscribers.splice(i2, 1);
635970
+ };
635971
+ }
635972
+ var STAGE_META, SWEEPING_STAGES, MAX_GRADIENT_COLS, STAGE_HUE_SPAN, HUE_LUT, _currentStage, _currentDetail, _subscribers;
635656
635973
  var init_stageIndicator = __esm({
635657
635974
  "packages/cli/src/tui/stageIndicator.ts"() {
635658
635975
  "use strict";
@@ -635691,6 +636008,7 @@ var init_stageIndicator = __esm({
635691
636008
  "failed"
635692
636009
  ]);
635693
636010
  MAX_GRADIENT_COLS = 120;
636011
+ STAGE_HUE_SPAN = 28;
635694
636012
  HUE_LUT = (() => {
635695
636013
  const lut = [];
635696
636014
  for (let h = 0; h < 360; h++) {
@@ -635703,6 +636021,595 @@ var init_stageIndicator = __esm({
635703
636021
  }
635704
636022
  });
635705
636023
 
636024
+ // packages/cli/src/tui/tui-tasks-renderer.ts
636025
+ var tui_tasks_renderer_exports = {};
636026
+ __export(tui_tasks_renderer_exports, {
636027
+ __testOrderTodosForDisplay: () => __testOrderTodosForDisplay,
636028
+ __testSelectPanelTodoRows: () => __testSelectPanelTodoRows,
636029
+ getTuiTasksScope: () => getTuiTasksScope,
636030
+ handleTuiTasksClick: () => handleTuiTasksClick,
636031
+ isTuiTasksExpanded: () => isTuiTasksExpanded,
636032
+ onTuiTasksHeightChange: () => onTuiTasksHeightChange,
636033
+ refreshTuiTasks: () => refreshTuiTasks,
636034
+ refreshTuiTasksSync: () => refreshTuiTasksSync,
636035
+ refreshTuiTasksThemeVars: () => refreshTuiTasksThemeVars,
636036
+ setTasksRendererWriter: () => setTasksRendererWriter,
636037
+ setTuiTasksEnabled: () => setTuiTasksEnabled,
636038
+ setTuiTasksScope: () => setTuiTasksScope,
636039
+ setTuiTasksSession: () => setTuiTasksSession,
636040
+ teardownTuiTasks: () => teardownTuiTasks
636041
+ });
636042
+ import { existsSync as existsSync126, readFileSync as readFileSync105, watch as fsWatch3 } from "node:fs";
636043
+ import { join as join140 } from "node:path";
636044
+ import { homedir as homedir44 } from "node:os";
636045
+ function setTasksRendererWriter(writer) {
636046
+ chromeWrite = writer;
636047
+ }
636048
+ function expandedRowCap() {
636049
+ const rows = termRows();
636050
+ return Math.max(MAX_VISIBLE_ROWS, Math.min(64, rows - 8 - 8));
636051
+ }
636052
+ function paintActiveRowGradient(text2) {
636053
+ const { stage: stage2 } = getStage();
636054
+ if (!supportsTruecolor() || !isSweepingStage(stage2)) return null;
636055
+ let out = "";
636056
+ const SEG = 2;
636057
+ for (let i2 = 0; i2 < text2.length; i2 += SEG) {
636058
+ const [r2, g, b] = stageGradientRgb(stage2, Math.floor(i2 / SEG), _gradPhase);
636059
+ out += `\x1B[38;2;${r2};${g};${b}m${text2.slice(i2, i2 + SEG)}`;
636060
+ }
636061
+ return out + RESET3;
636062
+ }
636063
+ function panelEffectivelyVisible() {
636064
+ return _enabled && !_scopeOverlayActive && !_scopeNeovimActive && !_scopePagerActive && _scopeMainViewActive;
636065
+ }
636066
+ function todoDir2() {
636067
+ return join140(homedir44(), ".omnius", "todos");
636068
+ }
636069
+ function todoPath2(sessionId) {
636070
+ const safe = sessionId.replace(/[^a-zA-Z0-9_.-]/g, "_");
636071
+ return join140(todoDir2(), `${safe}.json`);
636072
+ }
636073
+ function setTuiTasksSession(sessionId) {
636074
+ if (sessionId === _activeSessionId) return;
636075
+ _activeSessionId = sessionId || null;
636076
+ if (_watcher) {
636077
+ try {
636078
+ _watcher.close();
636079
+ } catch {
636080
+ }
636081
+ _watcher = null;
636082
+ }
636083
+ if (!_activeSessionId) {
636084
+ _lastTodos = [];
636085
+ applyHeightChange(0);
636086
+ return;
636087
+ }
636088
+ loadTodos();
636089
+ installWatcher();
636090
+ scheduleRedraw();
636091
+ }
636092
+ function onTuiTasksHeightChange(cb) {
636093
+ _onResizeChange = cb;
636094
+ }
636095
+ function setTuiTasksEnabled(enabled2) {
636096
+ _enabled = enabled2;
636097
+ scheduleRedraw();
636098
+ }
636099
+ function setTuiTasksScope(scope) {
636100
+ let changed = false;
636101
+ if (scope.overlayActive !== void 0 && scope.overlayActive !== _scopeOverlayActive) {
636102
+ _scopeOverlayActive = scope.overlayActive;
636103
+ changed = true;
636104
+ }
636105
+ if (scope.mainViewActive !== void 0 && scope.mainViewActive !== _scopeMainViewActive) {
636106
+ _scopeMainViewActive = scope.mainViewActive;
636107
+ changed = true;
636108
+ }
636109
+ if (scope.neovimActive !== void 0 && scope.neovimActive !== _scopeNeovimActive) {
636110
+ _scopeNeovimActive = scope.neovimActive;
636111
+ changed = true;
636112
+ }
636113
+ if (scope.pagerActive !== void 0 && scope.pagerActive !== _scopePagerActive) {
636114
+ _scopePagerActive = scope.pagerActive;
636115
+ changed = true;
636116
+ }
636117
+ if (changed) {
636118
+ if (!panelEffectivelyVisible()) {
636119
+ clearLastPaintedRows();
636120
+ applyHeightChange(0);
636121
+ } else {
636122
+ scheduleRedraw();
636123
+ }
636124
+ }
636125
+ }
636126
+ function getTuiTasksScope() {
636127
+ return {
636128
+ enabled: _enabled,
636129
+ overlayActive: _scopeOverlayActive,
636130
+ mainViewActive: _scopeMainViewActive,
636131
+ neovimActive: _scopeNeovimActive,
636132
+ pagerActive: _scopePagerActive,
636133
+ visible: panelEffectivelyVisible()
636134
+ };
636135
+ }
636136
+ function refreshTuiTasks() {
636137
+ if (!_activeSessionId) return;
636138
+ loadTodos();
636139
+ scheduleRedraw();
636140
+ }
636141
+ function refreshTuiTasksSync() {
636142
+ if (!_activeSessionId) return;
636143
+ loadTodos();
636144
+ if (!_enabled) return;
636145
+ _redrawScheduled = false;
636146
+ render();
636147
+ }
636148
+ function teardownTuiTasks() {
636149
+ if (_watcher) {
636150
+ try {
636151
+ _watcher.close();
636152
+ } catch {
636153
+ }
636154
+ _watcher = null;
636155
+ }
636156
+ _activeSessionId = null;
636157
+ _lastTodos = [];
636158
+ _expanded = false;
636159
+ _toggleRowAbs = -1;
636160
+ applyHeightChange(0);
636161
+ }
636162
+ function installWatcher() {
636163
+ if (!_activeSessionId) return;
636164
+ try {
636165
+ _watcher = fsWatch3(todoDir2(), { persistent: false }, (_evt, fname) => {
636166
+ if (!fname || !_activeSessionId) return;
636167
+ const expected = `${_activeSessionId.replace(/[^a-zA-Z0-9_.-]/g, "_")}.json`;
636168
+ if (fname !== expected) return;
636169
+ loadTodos();
636170
+ scheduleRedraw();
636171
+ });
636172
+ } catch {
636173
+ }
636174
+ }
636175
+ function loadTodos() {
636176
+ if (!_activeSessionId) {
636177
+ _lastTodos = [];
636178
+ return;
636179
+ }
636180
+ try {
636181
+ const fp = todoPath2(_activeSessionId);
636182
+ if (!existsSync126(fp)) {
636183
+ _lastTodos = [];
636184
+ return;
636185
+ }
636186
+ const parsed = JSON.parse(readFileSync105(fp, "utf-8"));
636187
+ _lastTodos = Array.isArray(parsed) ? parsed : [];
636188
+ } catch {
636189
+ _lastTodos = [];
636190
+ }
636191
+ }
636192
+ function scheduleRedraw() {
636193
+ if (_redrawScheduled || !_enabled) return;
636194
+ _redrawScheduled = true;
636195
+ setImmediate(() => {
636196
+ _redrawScheduled = false;
636197
+ render();
636198
+ });
636199
+ }
636200
+ function computeTargetHeight() {
636201
+ if (!panelEffectivelyVisible()) return 0;
636202
+ if (!_lastTodos || _lastTodos.length === 0) return 0;
636203
+ const allDone = _lastTodos.every((t2) => t2 && t2.status === "completed");
636204
+ if (allDone) return 0;
636205
+ const itemRows = _expanded ? selectExpandedTodoRows(_lastTodos, expandedRowCap() - 1).rowCount : selectPanelTodoRows(_lastTodos, MAX_VISIBLE_ROWS - 1).rowCount;
636206
+ return 1 + itemRows;
636207
+ }
636208
+ function applyHeightChange(nextHeight) {
636209
+ const changed = setTasksHeight(nextHeight);
636210
+ if (changed) {
636211
+ notifyLayoutResize();
636212
+ }
636213
+ if (_onResizeChange) {
636214
+ try {
636215
+ _onResizeChange(nextHeight);
636216
+ } catch {
636217
+ }
636218
+ }
636219
+ }
636220
+ function fg2562(idx, fallback = -1) {
636221
+ const n2 = idx < 0 ? fallback : idx;
636222
+ return n2 < 0 ? "\x1B[39m" : `\x1B[38;5;${n2}m`;
636223
+ }
636224
+ function refreshTuiTasksThemeVars() {
636225
+ BG = tuiBgSeq();
636226
+ DIM_LABEL = fg2562(tuiTextDim(), 240);
636227
+ ACCENT = tuiAccentFg();
636228
+ DONE2 = fg2562(tuiTextDim(), 240);
636229
+ PENDING = fg2562(tuiTextDim(), 240);
636230
+ }
636231
+ function statusToAnsi(status) {
636232
+ switch (status) {
636233
+ case "completed":
636234
+ return { mark: "◉", color: DONE2 };
636235
+ case "in_progress":
636236
+ return { mark: "◐", color: ACCENT };
636237
+ case "blocked":
636238
+ return { mark: "◍", color: BLOCKED };
636239
+ default:
636240
+ return { mark: "○", color: PENDING };
636241
+ }
636242
+ }
636243
+ function truncate2(s2, max) {
636244
+ if (s2.length <= max) return s2.padEnd(max, " ");
636245
+ return s2.slice(0, Math.max(0, max - 1)) + "…";
636246
+ }
636247
+ function stripAnsi2(s2) {
636248
+ return s2.replace(/\x1B\[[0-9;]*[A-Za-z]/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B[()][A-Z0-9]/g, "").replace(/\x1B\[?\??[0-9;]*[a-zA-Z]/g, "").replace(/\x1B/g, "");
636249
+ }
636250
+ function visualLen(s2) {
636251
+ return stripAnsi2(s2).length;
636252
+ }
636253
+ function buildTodoProgressBar(todos, maxWidth) {
636254
+ if (maxWidth <= 0 || todos.length === 0) return "";
636255
+ let cells = Math.min(todos.length, maxWidth);
636256
+ const truncated = cells < todos.length;
636257
+ const inIdx = todos.findIndex((t2) => t2.status === "in_progress");
636258
+ let nextIdx = -1;
636259
+ if (inIdx >= 0) {
636260
+ nextIdx = todos.findIndex((t2, i2) => i2 > inIdx && t2.status !== "completed");
636261
+ }
636262
+ if (nextIdx < 0) nextIdx = todos.findIndex((t2) => t2.status === "pending");
636263
+ const PEND = DIM_LABEL;
636264
+ const INPROG = ACCENT;
636265
+ const NEXT = ACCENT;
636266
+ const DONE_Y = ACCENT;
636267
+ let out = "";
636268
+ for (let i2 = 0; i2 < cells; i2++) {
636269
+ const t2 = todos[i2];
636270
+ if (t2.status === "completed") {
636271
+ out += `\x1B[1m${DONE_Y}█${RESET3}`;
636272
+ } else if (i2 === inIdx) {
636273
+ out += `${INPROG}▒${RESET3}`;
636274
+ } else if (i2 === nextIdx && inIdx >= 0) {
636275
+ out += `${NEXT}▒${RESET3}`;
636276
+ } else {
636277
+ out += `${PEND}░${RESET3}`;
636278
+ }
636279
+ }
636280
+ if (truncated && maxWidth > 0) out += `${DIM_LABEL}…${RESET3}`;
636281
+ return out;
636282
+ }
636283
+ function buildTodoTreeIndex(todos) {
636284
+ const byParent = /* @__PURE__ */ new Map();
636285
+ const byId = new Map(todos.map((t2) => [t2.id, t2]));
636286
+ const roots = [];
636287
+ for (const todo of todos) {
636288
+ if (todo.parentId && byId.has(todo.parentId)) {
636289
+ const arr = byParent.get(todo.parentId) ?? [];
636290
+ arr.push(todo);
636291
+ byParent.set(todo.parentId, arr);
636292
+ } else {
636293
+ roots.push(todo);
636294
+ }
636295
+ }
636296
+ return { byId, byParent, roots };
636297
+ }
636298
+ function childLeafStats(todo, index) {
636299
+ const children2 = index.byParent.get(todo.id) ?? [];
636300
+ if (children2.length === 0) return void 0;
636301
+ let completed = 0;
636302
+ let total = 0;
636303
+ const seen = /* @__PURE__ */ new Set();
636304
+ const visit = (node) => {
636305
+ if (seen.has(node.id)) return;
636306
+ seen.add(node.id);
636307
+ const nested = index.byParent.get(node.id) ?? [];
636308
+ if (nested.length === 0) {
636309
+ total++;
636310
+ if (node.status === "completed") completed++;
636311
+ return;
636312
+ }
636313
+ for (const child of nested) visit(child);
636314
+ };
636315
+ for (const child of children2) visit(child);
636316
+ return { completed, total };
636317
+ }
636318
+ function displayStatusFor(todo, index, seen = /* @__PURE__ */ new Set()) {
636319
+ if (seen.has(todo.id)) return todo.status;
636320
+ seen.add(todo.id);
636321
+ const children2 = index.byParent.get(todo.id) ?? [];
636322
+ if (children2.length === 0) return todo.status;
636323
+ const childStatuses = children2.map((child) => displayStatusFor(child, index, new Set(seen)));
636324
+ if (childStatuses.some((status) => status === "blocked")) return "blocked";
636325
+ if (childStatuses.some((status) => status === "in_progress")) return "in_progress";
636326
+ if (childStatuses.every((status) => status === "completed")) return "completed";
636327
+ if (todo.status === "completed") return "in_progress";
636328
+ return todo.status;
636329
+ }
636330
+ function toDisplayTodo(todo, depth, index) {
636331
+ return {
636332
+ ...todo,
636333
+ depth: Math.min(depth, 4),
636334
+ displayStatus: displayStatusFor(todo, index),
636335
+ childSummary: childLeafStats(todo, index)
636336
+ };
636337
+ }
636338
+ function orderTodosForDisplay(todos) {
636339
+ const index = buildTodoTreeIndex(todos);
636340
+ const out = [];
636341
+ const seen = /* @__PURE__ */ new Set();
636342
+ const visit = (todo, depth) => {
636343
+ if (seen.has(todo.id)) return;
636344
+ seen.add(todo.id);
636345
+ out.push(toDisplayTodo(todo, depth, index));
636346
+ for (const child of index.byParent.get(todo.id) ?? []) {
636347
+ visit(child, depth + 1);
636348
+ }
636349
+ };
636350
+ for (const root of index.roots) visit(root, 0);
636351
+ for (const todo of todos) visit(todo, 0);
636352
+ return out;
636353
+ }
636354
+ function leafTodosForProgress(todos) {
636355
+ const index = buildTodoTreeIndex(todos);
636356
+ const leaves = todos.filter((todo) => (index.byParent.get(todo.id) ?? []).length === 0);
636357
+ return leaves.length > 0 ? leaves : todos;
636358
+ }
636359
+ function activeDisplayIndex(displayTodos) {
636360
+ const inProgressLeaf = displayTodos.findIndex(
636361
+ (todo, index, all2) => todo.status === "in_progress" && !all2.some((candidate) => candidate.parentId === todo.id)
636362
+ );
636363
+ if (inProgressLeaf >= 0) return inProgressLeaf;
636364
+ const inProgress = displayTodos.findIndex((todo) => todo.displayStatus === "in_progress");
636365
+ if (inProgress >= 0) return inProgress;
636366
+ const blocked = displayTodos.findIndex((todo) => todo.displayStatus === "blocked");
636367
+ if (blocked >= 0) return blocked;
636368
+ return displayTodos.findIndex((todo) => todo.displayStatus === "pending");
636369
+ }
636370
+ function selectFocusedTodoItems(todos, maxItems) {
636371
+ const displayTodos = orderTodosForDisplay(todos);
636372
+ if (maxItems <= 0) return [];
636373
+ if (displayTodos.length <= maxItems) return displayTodos;
636374
+ const activeIndex = activeDisplayIndex(displayTodos);
636375
+ if (activeIndex < 0 || activeIndex < maxItems) return displayTodos.slice(0, maxItems);
636376
+ const rawIndex = buildTodoTreeIndex(todos);
636377
+ const displayById = new Map(displayTodos.map((todo) => [todo.id, todo]));
636378
+ const selected = [];
636379
+ const seen = /* @__PURE__ */ new Set();
636380
+ const add3 = (todo) => {
636381
+ if (!todo || selected.length >= maxItems || seen.has(todo.id)) return;
636382
+ selected.push(todo);
636383
+ seen.add(todo.id);
636384
+ };
636385
+ const active = displayTodos[activeIndex];
636386
+ const ancestors = [];
636387
+ let cursor = active;
636388
+ while (cursor?.parentId && rawIndex.byId.has(cursor.parentId)) {
636389
+ const parent = rawIndex.byId.get(cursor.parentId);
636390
+ if (!parent) break;
636391
+ const displayParent = displayById.get(parent.id);
636392
+ if (displayParent) ancestors.unshift(displayParent);
636393
+ cursor = parent;
636394
+ }
636395
+ for (const ancestor of ancestors) add3(ancestor);
636396
+ const siblings = active.parentId ? rawIndex.byParent.get(active.parentId) ?? [] : rawIndex.roots;
636397
+ const activeSiblingIndex = siblings.findIndex((todo) => todo.id === active.id);
636398
+ if (activeSiblingIndex > 0) add3(displayById.get(siblings[activeSiblingIndex - 1].id));
636399
+ add3(active);
636400
+ const descendants = [];
636401
+ const walkDescendants = (id2) => {
636402
+ for (const child of rawIndex.byParent.get(id2) ?? []) {
636403
+ const d2 = displayById.get(child.id);
636404
+ if (d2) descendants.push(d2);
636405
+ walkDescendants(child.id);
636406
+ }
636407
+ };
636408
+ walkDescendants(active.id);
636409
+ for (const d2 of descendants) add3(d2);
636410
+ for (let i2 = activeSiblingIndex + 1; i2 < siblings.length && selected.length < maxItems; i2++) {
636411
+ add3(displayById.get(siblings[i2].id));
636412
+ }
636413
+ for (let i2 = activeIndex + 1; i2 < displayTodos.length && selected.length < maxItems; i2++) {
636414
+ add3(displayTodos[i2]);
636415
+ }
636416
+ for (let i2 = activeIndex - 1; i2 >= 0 && selected.length < maxItems; i2--) {
636417
+ add3(displayTodos[i2]);
636418
+ }
636419
+ return selected;
636420
+ }
636421
+ function selectPanelTodoRows(todos, maxRows) {
636422
+ const displayTodos = orderTodosForDisplay(todos);
636423
+ if (maxRows <= 0 || displayTodos.length === 0) {
636424
+ return { items: [], omitted: displayTodos.length, rowCount: 0 };
636425
+ }
636426
+ if (displayTodos.length <= maxRows) {
636427
+ return { items: displayTodos, omitted: 0, rowCount: displayTodos.length };
636428
+ }
636429
+ const itemBudget = Math.max(1, maxRows - 1);
636430
+ const items = selectFocusedTodoItems(todos, itemBudget);
636431
+ const omitted = Math.max(0, displayTodos.length - items.length);
636432
+ return {
636433
+ items,
636434
+ omitted,
636435
+ rowCount: Math.min(maxRows, items.length + (omitted > 0 ? 1 : 0))
636436
+ };
636437
+ }
636438
+ function selectExpandedTodoRows(todos, maxRows) {
636439
+ const displayTodos = orderTodosForDisplay(todos);
636440
+ if (maxRows <= 1 || displayTodos.length === 0) {
636441
+ return { items: [], omitted: displayTodos.length, rowCount: 0 };
636442
+ }
636443
+ const items = displayTodos.slice(0, maxRows - 1);
636444
+ const omitted = Math.max(0, displayTodos.length - items.length);
636445
+ return { items, omitted, rowCount: items.length + 1 };
636446
+ }
636447
+ function __testOrderTodosForDisplay(todos) {
636448
+ return orderTodosForDisplay(todos);
636449
+ }
636450
+ function __testSelectPanelTodoRows(todos, maxRows) {
636451
+ return selectPanelTodoRows(todos, maxRows);
636452
+ }
636453
+ function render() {
636454
+ if (!_enabled) return;
636455
+ if (!panelEffectivelyVisible()) {
636456
+ clearLastPaintedRows();
636457
+ applyHeightChange(0);
636458
+ return;
636459
+ }
636460
+ const target = computeTargetHeight();
636461
+ applyHeightChange(target);
636462
+ if (target === 0) {
636463
+ clearLastPaintedRows();
636464
+ return;
636465
+ }
636466
+ const L = layout();
636467
+ const cols = Math.max(20, termCols());
636468
+ const progressTodos = leafTodosForProgress(_lastTodos);
636469
+ const completed = progressTodos.filter((t2) => t2.status === "completed").length;
636470
+ const total = progressTodos.length;
636471
+ const headerColor = ACCENT;
636472
+ const lines = [];
636473
+ const headerPrefix = `tasks ${headerColor}${completed}/${total}${RESET3} `;
636474
+ const headerPrefixWidth = visualLen(headerPrefix);
636475
+ const maxBarWidth = Math.max(0, cols - 2 - headerPrefixWidth);
636476
+ const progressBar = buildTodoProgressBar(progressTodos, maxBarWidth);
636477
+ const headerText = `${headerPrefix}${progressBar}`;
636478
+ lines.push(headerText);
636479
+ const selection = _expanded ? selectExpandedTodoRows(_lastTodos, expandedRowCap() - 1) : selectPanelTodoRows(_lastTodos, MAX_VISIBLE_ROWS - 1);
636480
+ const visible = selection.items;
636481
+ _gradPhase = (_gradPhase + 10) % 360;
636482
+ const displayAll = orderTodosForDisplay(_lastTodos);
636483
+ const activeIdx = activeDisplayIndex(displayAll);
636484
+ const activeId = activeIdx >= 0 ? displayAll[activeIdx].id : null;
636485
+ let toggleLineIdx = -1;
636486
+ for (const t2 of visible) {
636487
+ const { mark, color } = statusToAnsi(t2.displayStatus);
636488
+ const contentWidth = Math.max(4, cols - 8);
636489
+ const indent2 = t2.depth > 0 ? `${" ".repeat(t2.depth)}- ` : "";
636490
+ const childSummary = t2.childSummary && t2.childSummary.total > 0 ? ` [${t2.childSummary.completed}/${t2.childSummary.total}]` : "";
636491
+ const contentText = indent2 + t2.content + childSummary + (t2.blocker ? ` (blocked: ${t2.blocker})` : "");
636492
+ const truncated = truncate2(contentText, contentWidth);
636493
+ if (activeId && t2.id === activeId) {
636494
+ const grad = paintActiveRowGradient(truncated);
636495
+ if (grad) {
636496
+ lines.push(`${color}${mark}${RESET3} ${grad}`);
636497
+ continue;
636498
+ }
636499
+ }
636500
+ lines.push(`${color}${mark}${RESET3} ${color}${truncated}${RESET3}`);
636501
+ }
636502
+ if (_expanded) {
636503
+ toggleLineIdx = lines.length;
636504
+ const omittedNote = selection.omitted > 0 ? ` (+${selection.omitted} clipped)` : "";
636505
+ lines.push(`${ACCENT}▴ show active stages${RESET3}${DIM_LABEL}${omittedNote}${RESET3}`);
636506
+ } else if (selection.omitted > 0) {
636507
+ toggleLineIdx = lines.length;
636508
+ lines.push(`${DIM_LABEL}… +${selection.omitted} more tasks ${RESET3}${ACCENT}▸${RESET3}`);
636509
+ }
636510
+ let out = HIDE + SAVE;
636511
+ const newTop = L.tasksTop;
636512
+ const newBottom = Math.min(L.tasksBottom, L.tasksTop + lines.length - 1);
636513
+ const safeClearTop = L.headerBottom + 1;
636514
+ const safeClearBottom = L.contentBottom;
636515
+ if (_lastPaintedTop >= 0 && _lastPaintedBottom >= _lastPaintedTop) {
636516
+ for (let row = _lastPaintedTop; row <= _lastPaintedBottom; row++) {
636517
+ if (row >= newTop && row <= newBottom) continue;
636518
+ if (row < safeClearTop || row > safeClearBottom) continue;
636519
+ out += `\x1B[${row};1H${CLEAR_LINE}`;
636520
+ }
636521
+ }
636522
+ for (let i2 = 0; i2 < lines.length; i2++) {
636523
+ const row = L.tasksTop + i2;
636524
+ if (row > L.tasksBottom) break;
636525
+ out += `\x1B[${row};1H${CLEAR_LINE}${BG}${" ".repeat(cols)}\x1B[${row};2H${lines[i2]}${RESET3}`;
636526
+ }
636527
+ out += RESTORE + SHOW;
636528
+ try {
636529
+ chromeWrite(out);
636530
+ } catch {
636531
+ }
636532
+ _lastPaintedTop = newTop;
636533
+ _lastPaintedBottom = newBottom;
636534
+ _toggleRowAbs = toggleLineIdx >= 0 && L.tasksTop + toggleLineIdx <= L.tasksBottom ? L.tasksTop + toggleLineIdx : -1;
636535
+ }
636536
+ function handleTuiTasksClick(row) {
636537
+ if (!panelEffectivelyVisible()) return false;
636538
+ if (_toggleRowAbs < 0 || row !== _toggleRowAbs) return false;
636539
+ _expanded = !_expanded;
636540
+ loadTodos();
636541
+ render();
636542
+ return true;
636543
+ }
636544
+ function isTuiTasksExpanded() {
636545
+ return _expanded;
636546
+ }
636547
+ function clearLastPaintedRows() {
636548
+ if (_lastPaintedTop < 0 || _lastPaintedBottom < _lastPaintedTop) return;
636549
+ const L = layout();
636550
+ const safeTop = L.headerBottom + 1;
636551
+ const safeBottom = Math.max(L.contentBottom, safeTop - 1);
636552
+ let out = HIDE + SAVE;
636553
+ for (let row = _lastPaintedTop; row <= _lastPaintedBottom; row++) {
636554
+ if (row < safeTop || row > safeBottom) continue;
636555
+ out += `\x1B[${row};1H${CLEAR_LINE}`;
636556
+ }
636557
+ out += RESTORE + SHOW;
636558
+ try {
636559
+ chromeWrite(out);
636560
+ } catch {
636561
+ }
636562
+ _lastPaintedTop = -1;
636563
+ _lastPaintedBottom = -1;
636564
+ }
636565
+ var chromeWrite, _activeSessionId, _watcher, _lastTodos, _enabled, _redrawScheduled, _onResizeChange, _scopeOverlayActive, _scopeMainViewActive, _scopeNeovimActive, _scopePagerActive, _lastPaintedTop, _lastPaintedBottom, MAX_VISIBLE_ROWS, _expanded, _toggleRowAbs, _gradPhase, SAVE, RESTORE, HIDE, SHOW, CLEAR_LINE, RESET3, BG, DIM_LABEL, ACCENT, DONE2, PENDING, BLOCKED;
636566
+ var init_tui_tasks_renderer = __esm({
636567
+ "packages/cli/src/tui/tui-tasks-renderer.ts"() {
636568
+ "use strict";
636569
+ init_layout2();
636570
+ init_theme();
636571
+ init_stageIndicator();
636572
+ chromeWrite = ((data) => {
636573
+ process.stdout.write(data);
636574
+ });
636575
+ _activeSessionId = null;
636576
+ _watcher = null;
636577
+ _lastTodos = [];
636578
+ _enabled = true;
636579
+ _redrawScheduled = false;
636580
+ _onResizeChange = null;
636581
+ _scopeOverlayActive = false;
636582
+ _scopeMainViewActive = true;
636583
+ _scopeNeovimActive = false;
636584
+ _scopePagerActive = false;
636585
+ _lastPaintedTop = -1;
636586
+ _lastPaintedBottom = -1;
636587
+ MAX_VISIBLE_ROWS = 8;
636588
+ _expanded = false;
636589
+ _toggleRowAbs = -1;
636590
+ _gradPhase = 0;
636591
+ SAVE = "\x1B[s";
636592
+ RESTORE = "\x1B[u";
636593
+ HIDE = "\x1B[?25l";
636594
+ SHOW = "\x1B[?25h";
636595
+ CLEAR_LINE = "\x1B[2K";
636596
+ RESET3 = "\x1B[0m";
636597
+ BG = tuiBgSeq();
636598
+ DIM_LABEL = "";
636599
+ ACCENT = "";
636600
+ DONE2 = "";
636601
+ PENDING = "";
636602
+ BLOCKED = "\x1B[38;5;196m";
636603
+ refreshTuiTasksThemeVars();
636604
+ onStageChange(() => {
636605
+ if (!panelEffectivelyVisible()) return;
636606
+ if (_lastTodos.length === 0) return;
636607
+ if (!_lastTodos.some((t2) => t2.status === "in_progress")) return;
636608
+ scheduleRedraw();
636609
+ });
636610
+ }
636611
+ });
636612
+
635706
636613
  // packages/cli/src/tui/braille-spinner.ts
635707
636614
  function buildColorRamp(ramp) {
635708
636615
  return [...ramp, ...ramp.slice(1, -1).reverse()];
@@ -636000,9 +636907,9 @@ var init_braille_spinner = __esm({
636000
636907
  });
636001
636908
 
636002
636909
  // packages/cli/src/tui/project-context.ts
636003
- import { existsSync as existsSync126, readFileSync as readFileSync105, readdirSync as readdirSync42, mkdirSync as mkdirSync78, statSync as statSync50, writeFileSync as writeFileSync66 } from "node:fs";
636004
- import { dirname as dirname43, join as join140, basename as basename28, resolve as resolve60 } from "node:path";
636005
- import { homedir as homedir44 } from "node:os";
636910
+ import { existsSync as existsSync127, readFileSync as readFileSync106, readdirSync as readdirSync42, mkdirSync as mkdirSync78, statSync as statSync50, writeFileSync as writeFileSync66 } from "node:fs";
636911
+ import { dirname as dirname43, join as join141, basename as basename28, resolve as resolve60 } from "node:path";
636912
+ import { homedir as homedir45 } from "node:os";
636006
636913
  function projectContextUrlSpanAt(text2, index) {
636007
636914
  PROJECT_CONTEXT_URL_RE.lastIndex = 0;
636008
636915
  for (const match of text2.matchAll(PROJECT_CONTEXT_URL_RE)) {
@@ -636048,10 +636955,10 @@ function loadProjectMap(repoRoot) {
636048
636955
  if (!hasOmniusDirectory(repoRoot)) {
636049
636956
  initOmniusDirectory(repoRoot);
636050
636957
  }
636051
- const mapPath2 = join140(repoRoot, OMNIUS_DIR, "context", "project-map.md");
636052
- if (existsSync126(mapPath2)) {
636958
+ const mapPath2 = join141(repoRoot, OMNIUS_DIR, "context", "project-map.md");
636959
+ if (existsSync127(mapPath2)) {
636053
636960
  try {
636054
- const content = readFileSync105(mapPath2, "utf-8");
636961
+ const content = readFileSync106(mapPath2, "utf-8");
636055
636962
  return content;
636056
636963
  } catch {
636057
636964
  }
@@ -636061,10 +636968,10 @@ function loadProjectMap(repoRoot) {
636061
636968
  function findGitDir(repoRoot) {
636062
636969
  let dir = resolve60(repoRoot);
636063
636970
  for (; ; ) {
636064
- const gitPath = join140(dir, ".git");
636065
- if (existsSync126(gitPath)) {
636971
+ const gitPath = join141(dir, ".git");
636972
+ if (existsSync127(gitPath)) {
636066
636973
  try {
636067
- const raw = readFileSync105(gitPath, "utf8").trim();
636974
+ const raw = readFileSync106(gitPath, "utf8").trim();
636068
636975
  const match = raw.match(/^gitdir:\s*(.+)$/i);
636069
636976
  if (match?.[1]) {
636070
636977
  return resolve60(dir, match[1]);
@@ -636084,12 +636991,12 @@ function getGitInfo(repoRoot) {
636084
636991
  if (!gitDir) return "";
636085
636992
  const lines = [];
636086
636993
  try {
636087
- const head = readFileSync105(join140(gitDir, "HEAD"), "utf-8").trim();
636994
+ const head = readFileSync106(join141(gitDir, "HEAD"), "utf-8").trim();
636088
636995
  const refMatch = head.match(/^ref:\s+refs\/heads\/(.+)$/);
636089
636996
  if (refMatch?.[1]) {
636090
636997
  lines.push(`Branch: ${refMatch[1]}`);
636091
636998
  try {
636092
- const refHash = readFileSync105(join140(gitDir, "refs", "heads", refMatch[1]), "utf-8").trim();
636999
+ const refHash = readFileSync106(join141(gitDir, "refs", "heads", refMatch[1]), "utf-8").trim();
636093
637000
  if (refHash) lines.push(`HEAD: ${refHash.slice(0, 12)}`);
636094
637001
  } catch {
636095
637002
  }
@@ -636099,8 +637006,8 @@ function getGitInfo(repoRoot) {
636099
637006
  } catch {
636100
637007
  }
636101
637008
  try {
636102
- const indexPath = join140(gitDir, "index");
636103
- if (existsSync126(indexPath)) lines.push("Working tree: status not probed during prompt assembly");
637009
+ const indexPath = join141(gitDir, "index");
637010
+ if (existsSync127(indexPath)) lines.push("Working tree: status not probed during prompt assembly");
636104
637011
  } catch {
636105
637012
  }
636106
637013
  return lines.join("\n");
@@ -636109,7 +637016,7 @@ function emptyMemoryContextBundle() {
636109
637016
  return { text: "", memoryPrefix: "", prefixHash: "" };
636110
637017
  }
636111
637018
  function countJsonMemoryEntries(dir) {
636112
- if (!existsSync126(dir)) return { topics: 0, entries: 0 };
637019
+ if (!existsSync127(dir)) return { topics: 0, entries: 0 };
636113
637020
  let topics = 0;
636114
637021
  let entries = 0;
636115
637022
  try {
@@ -636117,7 +637024,7 @@ function countJsonMemoryEntries(dir) {
636117
637024
  if (!file.endsWith(".json")) continue;
636118
637025
  topics++;
636119
637026
  try {
636120
- const parsed = JSON.parse(readFileSync105(join140(dir, file), "utf8"));
637027
+ const parsed = JSON.parse(readFileSync106(join141(dir, file), "utf8"));
636121
637028
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
636122
637029
  entries += Object.keys(parsed).length;
636123
637030
  }
@@ -636130,35 +637037,35 @@ function countJsonMemoryEntries(dir) {
636130
637037
  return { topics, entries };
636131
637038
  }
636132
637039
  function countReflectionBuffer(repoRoot) {
636133
- const path15 = join140(repoRoot, OMNIUS_DIR, "memory", "reflections.json");
636134
- if (!existsSync126(path15)) return 0;
637040
+ const path15 = join141(repoRoot, OMNIUS_DIR, "memory", "reflections.json");
637041
+ if (!existsSync127(path15)) return 0;
636135
637042
  try {
636136
- const parsed = JSON.parse(readFileSync105(path15, "utf8"));
637043
+ const parsed = JSON.parse(readFileSync106(path15, "utf8"));
636137
637044
  return Array.isArray(parsed.reflections) ? parsed.reflections.length : 0;
636138
637045
  } catch {
636139
637046
  return 0;
636140
637047
  }
636141
637048
  }
636142
637049
  function countJsonlLines(path15, maxBytes = 1e6) {
636143
- if (!existsSync126(path15)) return 0;
637050
+ if (!existsSync127(path15)) return 0;
636144
637051
  try {
636145
- const text2 = readFileSync105(path15, "utf8").slice(-maxBytes);
637052
+ const text2 = readFileSync106(path15, "utf8").slice(-maxBytes);
636146
637053
  return text2.split(/\r?\n/).filter((line) => line.trim()).length;
636147
637054
  } catch {
636148
637055
  return 0;
636149
637056
  }
636150
637057
  }
636151
637058
  function buildWorkspaceMemorySubstrateCensus(repoRoot) {
636152
- const projectMemoryDir = join140(repoRoot, OMNIUS_DIR, "memory");
636153
- const legacyMemoryDir = join140(repoRoot, ".omnius", "memory");
637059
+ const projectMemoryDir = join141(repoRoot, OMNIUS_DIR, "memory");
637060
+ const legacyMemoryDir = join141(repoRoot, ".omnius", "memory");
636154
637061
  const projectMemory = countJsonMemoryEntries(projectMemoryDir);
636155
637062
  const legacyMemory = legacyMemoryDir === projectMemoryDir ? { topics: 0, entries: 0 } : countJsonMemoryEntries(legacyMemoryDir);
636156
- const globalMemory = countJsonMemoryEntries(join140(homedir44(), ".omnius", "memory"));
637063
+ const globalMemory = countJsonMemoryEntries(join141(homedir45(), ".omnius", "memory"));
636157
637064
  const reflectionCount = countReflectionBuffer(repoRoot);
636158
- const evidenceCount = countJsonlLines(join140(repoRoot, ".omnius", "evidence", "events.jsonl"));
636159
- const unifiedPresent = existsSync126(join140(repoRoot, OMNIUS_DIR, "unified-memory.db"));
636160
- const episodesPresent = existsSync126(join140(repoRoot, OMNIUS_DIR, "episodes.db"));
636161
- const knowledgePresent = existsSync126(join140(repoRoot, OMNIUS_DIR, "knowledge.db"));
637065
+ const evidenceCount = countJsonlLines(join141(repoRoot, ".omnius", "evidence", "events.jsonl"));
637066
+ const unifiedPresent = existsSync127(join141(repoRoot, OMNIUS_DIR, "unified-memory.db"));
637067
+ const episodesPresent = existsSync127(join141(repoRoot, OMNIUS_DIR, "episodes.db"));
637068
+ const knowledgePresent = existsSync127(join141(repoRoot, OMNIUS_DIR, "knowledge.db"));
636162
637069
  const topicCount = projectMemory.topics + legacyMemory.topics + globalMemory.topics;
636163
637070
  const entryCount = projectMemory.entries + legacyMemory.entries + globalMemory.entries;
636164
637071
  const hasMemory = topicCount + entryCount + reflectionCount + evidenceCount > 0 || unifiedPresent || episodesPresent || knowledgePresent;
@@ -636181,12 +637088,12 @@ function loadMemoryContextBundle(repoRoot, task = "", taskEmbedding) {
636181
637088
  if (unified.text) return unified;
636182
637089
  const all2 = [];
636183
637090
  const collect = (dir, scope) => {
636184
- if (!existsSync126(dir)) return;
637091
+ if (!existsSync127(dir)) return;
636185
637092
  try {
636186
637093
  const files = readdirSync42(dir).filter((f2) => f2.endsWith(".json"));
636187
637094
  for (const file of files.slice(0, 10)) {
636188
637095
  try {
636189
- const raw = readFileSync105(join140(dir, file), "utf-8");
637096
+ const raw = readFileSync106(join141(dir, file), "utf-8");
636190
637097
  const entries = JSON.parse(raw);
636191
637098
  const topic = basename28(file, ".json");
636192
637099
  for (const [k, v] of Object.entries(entries)) {
@@ -636207,11 +637114,11 @@ function loadMemoryContextBundle(repoRoot, task = "", taskEmbedding) {
636207
637114
  } catch {
636208
637115
  }
636209
637116
  };
636210
- const omniusMemDir = join140(repoRoot, OMNIUS_DIR, "memory");
637117
+ const omniusMemDir = join141(repoRoot, OMNIUS_DIR, "memory");
636211
637118
  collect(omniusMemDir, "project");
636212
- const legacyMemDir = join140(repoRoot, ".omnius", "memory");
637119
+ const legacyMemDir = join141(repoRoot, ".omnius", "memory");
636213
637120
  if (legacyMemDir !== omniusMemDir) collect(legacyMemDir, "project");
636214
- const globalMemDir = join140(homedir44(), ".omnius", "memory");
637121
+ const globalMemDir = join141(homedir45(), ".omnius", "memory");
636215
637122
  collect(globalMemDir, "global");
636216
637123
  const seen = /* @__PURE__ */ new Set();
636217
637124
  const deduped = [];
@@ -636292,8 +637199,8 @@ function loadMemoryContextBundle(repoRoot, task = "", taskEmbedding) {
636292
637199
  };
636293
637200
  }
636294
637201
  function loadUnifiedMemoryContextBundle(repoRoot, task = "", taskEmbedding) {
636295
- const dbPath = join140(repoRoot, OMNIUS_DIR, "unified-memory.db");
636296
- if (!existsSync126(dbPath)) return emptyMemoryContextBundle();
637202
+ const dbPath = join141(repoRoot, OMNIUS_DIR, "unified-memory.db");
637203
+ if (!existsSync127(dbPath)) return emptyMemoryContextBundle();
636297
637204
  let db = null;
636298
637205
  try {
636299
637206
  db = initDb(dbPath);
@@ -636610,11 +637517,11 @@ function buildPythonBootstrapContext(repoRoot, task = "") {
636610
637517
  }
636611
637518
  function inspectPythonBootstrap(repoRoot, task = "") {
636612
637519
  const rootEntries = safeReadDir(repoRoot);
636613
- const scriptsEntries = safeReadDir(join140(repoRoot, "scripts"));
636614
- const binEntries = safeReadDir(join140(repoRoot, "bin"));
636615
- const relExists = (rel) => existsSync126(join140(repoRoot, rel));
636616
- const venvs = [".venv", "venv", "env"].filter((rel) => isDirectory2(join140(repoRoot, rel))).filter(
636617
- (rel) => existsSync126(join140(repoRoot, rel, process.platform === "win32" ? "Scripts" : "bin")) || existsSync126(join140(repoRoot, rel, "pyvenv.cfg"))
637520
+ const scriptsEntries = safeReadDir(join141(repoRoot, "scripts"));
637521
+ const binEntries = safeReadDir(join141(repoRoot, "bin"));
637522
+ const relExists = (rel) => existsSync127(join141(repoRoot, rel));
637523
+ const venvs = [".venv", "venv", "env"].filter((rel) => isDirectory2(join141(repoRoot, rel))).filter(
637524
+ (rel) => existsSync127(join141(repoRoot, rel, process.platform === "win32" ? "Scripts" : "bin")) || existsSync127(join141(repoRoot, rel, "pyvenv.cfg"))
636618
637525
  );
636619
637526
  const requirements = rootEntries.filter((name10) => /^requirements(?:[-_.][A-Za-z0-9_-]+)?\.txt$/.test(name10)).sort();
636620
637527
  const managers2 = [
@@ -636638,7 +637545,7 @@ function inspectPythonBootstrap(repoRoot, task = "") {
636638
637545
  ...findBootstrapEntries(binEntries, "bin")
636639
637546
  ].slice(0, 8);
636640
637547
  const makeTargets = extractMakeBootstrapTargets(repoRoot).slice(0, 6);
636641
- const hasPythonSource = rootEntries.some((name10) => name10.endsWith(".py")) || scriptsEntries.some((name10) => name10.endsWith(".py")) || relExists("src") && safeReadDir(join140(repoRoot, "src")).some((name10) => name10.endsWith(".py"));
637548
+ const hasPythonSource = rootEntries.some((name10) => name10.endsWith(".py")) || scriptsEntries.some((name10) => name10.endsWith(".py")) || relExists("src") && safeReadDir(join141(repoRoot, "src")).some((name10) => name10.endsWith(".py"));
636642
637549
  const taskNeedsPython = /\b(?:python|pip|pip3|venv|virtualenv|pytest|pyproject|requirements|uv|poetry|pdm|pipenv|conda)\b/i.test(task);
636643
637550
  const hasPyproject = relExists("pyproject.toml");
636644
637551
  const hasAnchors = venvs.length > 0 || bootstrapFiles.length > 0 || managers2.length > 0 || makeTargets.length > 0 || hasPythonSource;
@@ -636673,10 +637580,10 @@ function findBootstrapEntries(entries, prefix) {
636673
637580
  ).map((name10) => prefix ? `${prefix}/${name10}` : name10).sort();
636674
637581
  }
636675
637582
  function extractMakeBootstrapTargets(repoRoot) {
636676
- const makefile = ["Makefile", "makefile"].find((name10) => existsSync126(join140(repoRoot, name10)));
637583
+ const makefile = ["Makefile", "makefile"].find((name10) => existsSync127(join141(repoRoot, name10)));
636677
637584
  if (!makefile) return [];
636678
637585
  try {
636679
- const text2 = readFileSync105(join140(repoRoot, makefile), "utf8");
637586
+ const text2 = readFileSync106(join141(repoRoot, makefile), "utf8");
636680
637587
  const targets = [];
636681
637588
  for (const line of text2.split(/\r?\n/)) {
636682
637589
  const match = line.match(/^([A-Za-z0-9_.-]+)\s*:(?![=])/);
@@ -636886,10 +637793,10 @@ function sanitizeToolName(value2) {
636886
637793
  }
636887
637794
  function loadCustomToolsContext(repoRoot) {
636888
637795
  try {
636889
- const registryPath = join140(repoRoot, ".omnius", "tools", "registry.json");
636890
- const indexPath = join140(repoRoot, ".omnius", "tools", "README.md");
636891
- if (!existsSync126(registryPath)) return "";
636892
- const registry4 = JSON.parse(readFileSync105(registryPath, "utf-8"));
637796
+ const registryPath = join141(repoRoot, ".omnius", "tools", "registry.json");
637797
+ const indexPath = join141(repoRoot, ".omnius", "tools", "README.md");
637798
+ if (!existsSync127(registryPath)) return "";
637799
+ const registry4 = JSON.parse(readFileSync106(registryPath, "utf-8"));
636893
637800
  const tools = (registry4.tools ?? []).filter((tool) => tool.qualityGate?.lastTest?.status === "passed").sort((a2, b) => {
636894
637801
  const byRate = (b.analytics?.successRate ?? 0) - (a2.analytics?.successRate ?? 0);
636895
637802
  if (byRate !== 0) return byRate;
@@ -636904,7 +637811,7 @@ function loadCustomToolsContext(repoRoot) {
636904
637811
  const bits = [
636905
637812
  `- ${tool.name} v${tool.version ?? 1}: ${truncateProjectContextText(String(tool.description ?? ""), 140, "")}`,
636906
637813
  `docs=${tool.docsPath ?? "missing"}`,
636907
- existsSync126(indexPath) ? `index=${indexPath}` : "",
637814
+ existsSync127(indexPath) ? `index=${indexPath}` : "",
636908
637815
  `test=${tested}${schema ? `, schema=${schema}` : ""}`,
636909
637816
  `success=${successRate}`,
636910
637817
  example?.args ? `example=${tool.name}(${JSON.stringify(example.args)})` : "",
@@ -636948,7 +637855,7 @@ function buildProjectContext(repoRoot, stores, task = "", taskEmbedding) {
636948
637855
  }
636949
637856
  function writeCompressedSkillsArtifact(repoRoot, skills) {
636950
637857
  try {
636951
- const contextDir = join140(repoRoot, OMNIUS_DIR, "context");
637858
+ const contextDir = join141(repoRoot, OMNIUS_DIR, "context");
636952
637859
  mkdirSync78(contextDir, { recursive: true });
636953
637860
  const bySource = /* @__PURE__ */ new Map();
636954
637861
  for (const skill of skills) bySource.set(skill.source, (bySource.get(skill.source) ?? 0) + 1);
@@ -636959,7 +637866,7 @@ function writeCompressedSkillsArtifact(repoRoot, skills) {
636959
637866
  triggers: skill.triggers.slice(0, 4)
636960
637867
  }));
636961
637868
  writeFileSync66(
636962
- join140(contextDir, "skills-compressed.json"),
637869
+ join141(contextDir, "skills-compressed.json"),
636963
637870
  JSON.stringify(
636964
637871
  {
636965
637872
  schema: "omnius.skills-compressed.v1",
@@ -637806,520 +638713,6 @@ var init_overlay_lock = __esm({
637806
638713
  }
637807
638714
  });
637808
638715
 
637809
- // packages/cli/src/tui/tui-tasks-renderer.ts
637810
- var tui_tasks_renderer_exports = {};
637811
- __export(tui_tasks_renderer_exports, {
637812
- __testOrderTodosForDisplay: () => __testOrderTodosForDisplay,
637813
- __testSelectPanelTodoRows: () => __testSelectPanelTodoRows,
637814
- getTuiTasksScope: () => getTuiTasksScope,
637815
- onTuiTasksHeightChange: () => onTuiTasksHeightChange,
637816
- refreshTuiTasks: () => refreshTuiTasks,
637817
- refreshTuiTasksSync: () => refreshTuiTasksSync,
637818
- refreshTuiTasksThemeVars: () => refreshTuiTasksThemeVars,
637819
- setTasksRendererWriter: () => setTasksRendererWriter,
637820
- setTuiTasksEnabled: () => setTuiTasksEnabled,
637821
- setTuiTasksScope: () => setTuiTasksScope,
637822
- setTuiTasksSession: () => setTuiTasksSession,
637823
- teardownTuiTasks: () => teardownTuiTasks
637824
- });
637825
- import { existsSync as existsSync127, readFileSync as readFileSync106, watch as fsWatch3 } from "node:fs";
637826
- import { join as join141 } from "node:path";
637827
- import { homedir as homedir45 } from "node:os";
637828
- function setTasksRendererWriter(writer) {
637829
- chromeWrite = writer;
637830
- }
637831
- function panelEffectivelyVisible() {
637832
- return _enabled && !_scopeOverlayActive && !_scopeNeovimActive && !_scopePagerActive && _scopeMainViewActive;
637833
- }
637834
- function todoDir2() {
637835
- return join141(homedir45(), ".omnius", "todos");
637836
- }
637837
- function todoPath2(sessionId) {
637838
- const safe = sessionId.replace(/[^a-zA-Z0-9_.-]/g, "_");
637839
- return join141(todoDir2(), `${safe}.json`);
637840
- }
637841
- function setTuiTasksSession(sessionId) {
637842
- if (sessionId === _activeSessionId) return;
637843
- _activeSessionId = sessionId || null;
637844
- if (_watcher) {
637845
- try {
637846
- _watcher.close();
637847
- } catch {
637848
- }
637849
- _watcher = null;
637850
- }
637851
- if (!_activeSessionId) {
637852
- _lastTodos = [];
637853
- applyHeightChange(0);
637854
- return;
637855
- }
637856
- loadTodos();
637857
- installWatcher();
637858
- scheduleRedraw();
637859
- }
637860
- function onTuiTasksHeightChange(cb) {
637861
- _onResizeChange = cb;
637862
- }
637863
- function setTuiTasksEnabled(enabled2) {
637864
- _enabled = enabled2;
637865
- scheduleRedraw();
637866
- }
637867
- function setTuiTasksScope(scope) {
637868
- let changed = false;
637869
- if (scope.overlayActive !== void 0 && scope.overlayActive !== _scopeOverlayActive) {
637870
- _scopeOverlayActive = scope.overlayActive;
637871
- changed = true;
637872
- }
637873
- if (scope.mainViewActive !== void 0 && scope.mainViewActive !== _scopeMainViewActive) {
637874
- _scopeMainViewActive = scope.mainViewActive;
637875
- changed = true;
637876
- }
637877
- if (scope.neovimActive !== void 0 && scope.neovimActive !== _scopeNeovimActive) {
637878
- _scopeNeovimActive = scope.neovimActive;
637879
- changed = true;
637880
- }
637881
- if (scope.pagerActive !== void 0 && scope.pagerActive !== _scopePagerActive) {
637882
- _scopePagerActive = scope.pagerActive;
637883
- changed = true;
637884
- }
637885
- if (changed) {
637886
- if (!panelEffectivelyVisible()) {
637887
- clearLastPaintedRows();
637888
- applyHeightChange(0);
637889
- } else {
637890
- scheduleRedraw();
637891
- }
637892
- }
637893
- }
637894
- function getTuiTasksScope() {
637895
- return {
637896
- enabled: _enabled,
637897
- overlayActive: _scopeOverlayActive,
637898
- mainViewActive: _scopeMainViewActive,
637899
- neovimActive: _scopeNeovimActive,
637900
- pagerActive: _scopePagerActive,
637901
- visible: panelEffectivelyVisible()
637902
- };
637903
- }
637904
- function refreshTuiTasks() {
637905
- if (!_activeSessionId) return;
637906
- loadTodos();
637907
- scheduleRedraw();
637908
- }
637909
- function refreshTuiTasksSync() {
637910
- if (!_activeSessionId) return;
637911
- loadTodos();
637912
- if (!_enabled) return;
637913
- _redrawScheduled = false;
637914
- render();
637915
- }
637916
- function teardownTuiTasks() {
637917
- if (_watcher) {
637918
- try {
637919
- _watcher.close();
637920
- } catch {
637921
- }
637922
- _watcher = null;
637923
- }
637924
- _activeSessionId = null;
637925
- _lastTodos = [];
637926
- applyHeightChange(0);
637927
- }
637928
- function installWatcher() {
637929
- if (!_activeSessionId) return;
637930
- try {
637931
- _watcher = fsWatch3(todoDir2(), { persistent: false }, (_evt, fname) => {
637932
- if (!fname || !_activeSessionId) return;
637933
- const expected = `${_activeSessionId.replace(/[^a-zA-Z0-9_.-]/g, "_")}.json`;
637934
- if (fname !== expected) return;
637935
- loadTodos();
637936
- scheduleRedraw();
637937
- });
637938
- } catch {
637939
- }
637940
- }
637941
- function loadTodos() {
637942
- if (!_activeSessionId) {
637943
- _lastTodos = [];
637944
- return;
637945
- }
637946
- try {
637947
- const fp = todoPath2(_activeSessionId);
637948
- if (!existsSync127(fp)) {
637949
- _lastTodos = [];
637950
- return;
637951
- }
637952
- const parsed = JSON.parse(readFileSync106(fp, "utf-8"));
637953
- _lastTodos = Array.isArray(parsed) ? parsed : [];
637954
- } catch {
637955
- _lastTodos = [];
637956
- }
637957
- }
637958
- function scheduleRedraw() {
637959
- if (_redrawScheduled || !_enabled) return;
637960
- _redrawScheduled = true;
637961
- setImmediate(() => {
637962
- _redrawScheduled = false;
637963
- render();
637964
- });
637965
- }
637966
- function computeTargetHeight() {
637967
- if (!panelEffectivelyVisible()) return 0;
637968
- if (!_lastTodos || _lastTodos.length === 0) return 0;
637969
- const allDone = _lastTodos.every((t2) => t2 && t2.status === "completed");
637970
- if (allDone) return 0;
637971
- const itemRows = selectPanelTodoRows(_lastTodos, MAX_VISIBLE_ROWS - 1).rowCount;
637972
- return 1 + itemRows;
637973
- }
637974
- function applyHeightChange(nextHeight) {
637975
- const changed = setTasksHeight(nextHeight);
637976
- if (changed) {
637977
- notifyLayoutResize();
637978
- }
637979
- if (_onResizeChange) {
637980
- try {
637981
- _onResizeChange(nextHeight);
637982
- } catch {
637983
- }
637984
- }
637985
- }
637986
- function fg2562(idx, fallback = -1) {
637987
- const n2 = idx < 0 ? fallback : idx;
637988
- return n2 < 0 ? "\x1B[39m" : `\x1B[38;5;${n2}m`;
637989
- }
637990
- function refreshTuiTasksThemeVars() {
637991
- BG = tuiBgSeq();
637992
- DIM_LABEL = fg2562(tuiTextDim(), 240);
637993
- ACCENT = tuiAccentFg();
637994
- DONE2 = fg2562(tuiTextDim(), 240);
637995
- PENDING = fg2562(tuiTextDim(), 240);
637996
- }
637997
- function statusToAnsi(status) {
637998
- switch (status) {
637999
- case "completed":
638000
- return { mark: "◉", color: DONE2 };
638001
- case "in_progress":
638002
- return { mark: "◐", color: ACCENT };
638003
- case "blocked":
638004
- return { mark: "◍", color: BLOCKED };
638005
- default:
638006
- return { mark: "○", color: PENDING };
638007
- }
638008
- }
638009
- function truncate2(s2, max) {
638010
- if (s2.length <= max) return s2.padEnd(max, " ");
638011
- return s2.slice(0, Math.max(0, max - 1)) + "…";
638012
- }
638013
- function stripAnsi2(s2) {
638014
- return s2.replace(/\x1B\[[0-9;]*[A-Za-z]/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B[()][A-Z0-9]/g, "").replace(/\x1B\[?\??[0-9;]*[a-zA-Z]/g, "").replace(/\x1B/g, "");
638015
- }
638016
- function visualLen(s2) {
638017
- return stripAnsi2(s2).length;
638018
- }
638019
- function buildTodoProgressBar(todos, maxWidth) {
638020
- if (maxWidth <= 0 || todos.length === 0) return "";
638021
- let cells = Math.min(todos.length, maxWidth);
638022
- const truncated = cells < todos.length;
638023
- const inIdx = todos.findIndex((t2) => t2.status === "in_progress");
638024
- let nextIdx = -1;
638025
- if (inIdx >= 0) {
638026
- nextIdx = todos.findIndex((t2, i2) => i2 > inIdx && t2.status !== "completed");
638027
- }
638028
- if (nextIdx < 0) nextIdx = todos.findIndex((t2) => t2.status === "pending");
638029
- const PEND = DIM_LABEL;
638030
- const INPROG = ACCENT;
638031
- const NEXT = ACCENT;
638032
- const DONE_Y = ACCENT;
638033
- let out = "";
638034
- for (let i2 = 0; i2 < cells; i2++) {
638035
- const t2 = todos[i2];
638036
- if (t2.status === "completed") {
638037
- out += `\x1B[1m${DONE_Y}█${RESET3}`;
638038
- } else if (i2 === inIdx) {
638039
- out += `${INPROG}▒${RESET3}`;
638040
- } else if (i2 === nextIdx && inIdx >= 0) {
638041
- out += `${NEXT}▒${RESET3}`;
638042
- } else {
638043
- out += `${PEND}░${RESET3}`;
638044
- }
638045
- }
638046
- if (truncated && maxWidth > 0) out += `${DIM_LABEL}…${RESET3}`;
638047
- return out;
638048
- }
638049
- function buildTodoTreeIndex(todos) {
638050
- const byParent = /* @__PURE__ */ new Map();
638051
- const byId = new Map(todos.map((t2) => [t2.id, t2]));
638052
- const roots = [];
638053
- for (const todo of todos) {
638054
- if (todo.parentId && byId.has(todo.parentId)) {
638055
- const arr = byParent.get(todo.parentId) ?? [];
638056
- arr.push(todo);
638057
- byParent.set(todo.parentId, arr);
638058
- } else {
638059
- roots.push(todo);
638060
- }
638061
- }
638062
- return { byId, byParent, roots };
638063
- }
638064
- function childLeafStats(todo, index) {
638065
- const children2 = index.byParent.get(todo.id) ?? [];
638066
- if (children2.length === 0) return void 0;
638067
- let completed = 0;
638068
- let total = 0;
638069
- const seen = /* @__PURE__ */ new Set();
638070
- const visit = (node) => {
638071
- if (seen.has(node.id)) return;
638072
- seen.add(node.id);
638073
- const nested = index.byParent.get(node.id) ?? [];
638074
- if (nested.length === 0) {
638075
- total++;
638076
- if (node.status === "completed") completed++;
638077
- return;
638078
- }
638079
- for (const child of nested) visit(child);
638080
- };
638081
- for (const child of children2) visit(child);
638082
- return { completed, total };
638083
- }
638084
- function displayStatusFor(todo, index, seen = /* @__PURE__ */ new Set()) {
638085
- if (seen.has(todo.id)) return todo.status;
638086
- seen.add(todo.id);
638087
- const children2 = index.byParent.get(todo.id) ?? [];
638088
- if (children2.length === 0) return todo.status;
638089
- const childStatuses = children2.map((child) => displayStatusFor(child, index, new Set(seen)));
638090
- if (childStatuses.some((status) => status === "blocked")) return "blocked";
638091
- if (childStatuses.some((status) => status === "in_progress")) return "in_progress";
638092
- if (childStatuses.every((status) => status === "completed")) return "completed";
638093
- if (todo.status === "completed") return "in_progress";
638094
- return todo.status;
638095
- }
638096
- function toDisplayTodo(todo, depth, index) {
638097
- return {
638098
- ...todo,
638099
- depth: Math.min(depth, 4),
638100
- displayStatus: displayStatusFor(todo, index),
638101
- childSummary: childLeafStats(todo, index)
638102
- };
638103
- }
638104
- function orderTodosForDisplay(todos) {
638105
- const index = buildTodoTreeIndex(todos);
638106
- const out = [];
638107
- const seen = /* @__PURE__ */ new Set();
638108
- const visit = (todo, depth) => {
638109
- if (seen.has(todo.id)) return;
638110
- seen.add(todo.id);
638111
- out.push(toDisplayTodo(todo, depth, index));
638112
- for (const child of index.byParent.get(todo.id) ?? []) {
638113
- visit(child, depth + 1);
638114
- }
638115
- };
638116
- for (const root of index.roots) visit(root, 0);
638117
- for (const todo of todos) visit(todo, 0);
638118
- return out;
638119
- }
638120
- function leafTodosForProgress(todos) {
638121
- const index = buildTodoTreeIndex(todos);
638122
- const leaves = todos.filter((todo) => (index.byParent.get(todo.id) ?? []).length === 0);
638123
- return leaves.length > 0 ? leaves : todos;
638124
- }
638125
- function activeDisplayIndex(displayTodos) {
638126
- const inProgressLeaf = displayTodos.findIndex(
638127
- (todo, index, all2) => todo.status === "in_progress" && !all2.some((candidate) => candidate.parentId === todo.id)
638128
- );
638129
- if (inProgressLeaf >= 0) return inProgressLeaf;
638130
- const inProgress = displayTodos.findIndex((todo) => todo.displayStatus === "in_progress");
638131
- if (inProgress >= 0) return inProgress;
638132
- const blocked = displayTodos.findIndex((todo) => todo.displayStatus === "blocked");
638133
- if (blocked >= 0) return blocked;
638134
- return displayTodos.findIndex((todo) => todo.displayStatus === "pending");
638135
- }
638136
- function selectFocusedTodoItems(todos, maxItems) {
638137
- const displayTodos = orderTodosForDisplay(todos);
638138
- if (maxItems <= 0) return [];
638139
- if (displayTodos.length <= maxItems) return displayTodos;
638140
- const activeIndex = activeDisplayIndex(displayTodos);
638141
- if (activeIndex < 0 || activeIndex < maxItems) return displayTodos.slice(0, maxItems);
638142
- const rawIndex = buildTodoTreeIndex(todos);
638143
- const displayById = new Map(displayTodos.map((todo) => [todo.id, todo]));
638144
- const selected = [];
638145
- const seen = /* @__PURE__ */ new Set();
638146
- const add3 = (todo) => {
638147
- if (!todo || selected.length >= maxItems || seen.has(todo.id)) return;
638148
- selected.push(todo);
638149
- seen.add(todo.id);
638150
- };
638151
- const active = displayTodos[activeIndex];
638152
- const ancestors = [];
638153
- let cursor = active;
638154
- while (cursor?.parentId && rawIndex.byId.has(cursor.parentId)) {
638155
- const parent = rawIndex.byId.get(cursor.parentId);
638156
- if (!parent) break;
638157
- const displayParent = displayById.get(parent.id);
638158
- if (displayParent) ancestors.unshift(displayParent);
638159
- cursor = parent;
638160
- }
638161
- for (const ancestor of ancestors) add3(ancestor);
638162
- const siblings = active.parentId ? rawIndex.byParent.get(active.parentId) ?? [] : rawIndex.roots;
638163
- const activeSiblingIndex = siblings.findIndex((todo) => todo.id === active.id);
638164
- if (activeSiblingIndex > 0) add3(displayById.get(siblings[activeSiblingIndex - 1].id));
638165
- add3(active);
638166
- for (let i2 = activeSiblingIndex + 1; i2 < siblings.length && selected.length < maxItems; i2++) {
638167
- add3(displayById.get(siblings[i2].id));
638168
- }
638169
- const activeChildren = rawIndex.byParent.get(active.id) ?? [];
638170
- for (const child of activeChildren) add3(displayById.get(child.id));
638171
- for (let i2 = activeIndex + 1; i2 < displayTodos.length && selected.length < maxItems; i2++) {
638172
- add3(displayTodos[i2]);
638173
- }
638174
- for (let i2 = activeIndex - 1; i2 >= 0 && selected.length < maxItems; i2--) {
638175
- add3(displayTodos[i2]);
638176
- }
638177
- return selected;
638178
- }
638179
- function selectPanelTodoRows(todos, maxRows) {
638180
- const displayTodos = orderTodosForDisplay(todos);
638181
- if (maxRows <= 0 || displayTodos.length === 0) {
638182
- return { items: [], omitted: displayTodos.length, rowCount: 0 };
638183
- }
638184
- if (displayTodos.length <= maxRows) {
638185
- return { items: displayTodos, omitted: 0, rowCount: displayTodos.length };
638186
- }
638187
- const itemBudget = Math.max(1, maxRows - 1);
638188
- const items = selectFocusedTodoItems(todos, itemBudget);
638189
- const omitted = Math.max(0, displayTodos.length - items.length);
638190
- return {
638191
- items,
638192
- omitted,
638193
- rowCount: Math.min(maxRows, items.length + (omitted > 0 ? 1 : 0))
638194
- };
638195
- }
638196
- function __testOrderTodosForDisplay(todos) {
638197
- return orderTodosForDisplay(todos);
638198
- }
638199
- function __testSelectPanelTodoRows(todos, maxRows) {
638200
- return selectPanelTodoRows(todos, maxRows);
638201
- }
638202
- function render() {
638203
- if (!_enabled) return;
638204
- if (!panelEffectivelyVisible()) {
638205
- clearLastPaintedRows();
638206
- applyHeightChange(0);
638207
- return;
638208
- }
638209
- const target = computeTargetHeight();
638210
- applyHeightChange(target);
638211
- if (target === 0) {
638212
- clearLastPaintedRows();
638213
- return;
638214
- }
638215
- const L = layout();
638216
- const cols = Math.max(20, termCols());
638217
- const progressTodos = leafTodosForProgress(_lastTodos);
638218
- const completed = progressTodos.filter((t2) => t2.status === "completed").length;
638219
- const total = progressTodos.length;
638220
- const headerColor = ACCENT;
638221
- const lines = [];
638222
- const headerPrefix = `tasks ${headerColor}${completed}/${total}${RESET3} `;
638223
- const headerPrefixWidth = visualLen(headerPrefix);
638224
- const maxBarWidth = Math.max(0, cols - 2 - headerPrefixWidth);
638225
- const progressBar = buildTodoProgressBar(progressTodos, maxBarWidth);
638226
- const headerText = `${headerPrefix}${progressBar}`;
638227
- lines.push(headerText);
638228
- const selection = selectPanelTodoRows(_lastTodos, MAX_VISIBLE_ROWS - 1);
638229
- const visible = selection.items;
638230
- for (const t2 of visible) {
638231
- const { mark, color } = statusToAnsi(t2.displayStatus);
638232
- const contentWidth = Math.max(4, cols - 8);
638233
- const indent2 = t2.depth > 0 ? `${" ".repeat(t2.depth)}- ` : "";
638234
- const childSummary = t2.childSummary && t2.childSummary.total > 0 ? ` [${t2.childSummary.completed}/${t2.childSummary.total}]` : "";
638235
- const contentText = indent2 + t2.content + childSummary + (t2.blocker ? ` (blocked: ${t2.blocker})` : "");
638236
- const truncated = truncate2(contentText, contentWidth);
638237
- lines.push(`${color}${mark}${RESET3} ${color}${truncated}${RESET3}`);
638238
- }
638239
- if (selection.omitted > 0) {
638240
- lines.push(`${DIM_LABEL}… +${selection.omitted} more${RESET3}`);
638241
- }
638242
- let out = HIDE + SAVE;
638243
- const newTop = L.tasksTop;
638244
- const newBottom = Math.min(L.tasksBottom, L.tasksTop + lines.length - 1);
638245
- const safeClearTop = L.headerBottom + 1;
638246
- const safeClearBottom = L.contentBottom;
638247
- if (_lastPaintedTop >= 0 && _lastPaintedBottom >= _lastPaintedTop) {
638248
- for (let row = _lastPaintedTop; row <= _lastPaintedBottom; row++) {
638249
- if (row >= newTop && row <= newBottom) continue;
638250
- if (row < safeClearTop || row > safeClearBottom) continue;
638251
- out += `\x1B[${row};1H${CLEAR_LINE}`;
638252
- }
638253
- }
638254
- for (let i2 = 0; i2 < lines.length; i2++) {
638255
- const row = L.tasksTop + i2;
638256
- if (row > L.tasksBottom) break;
638257
- out += `\x1B[${row};1H${CLEAR_LINE}${BG}${" ".repeat(cols)}\x1B[${row};2H${lines[i2]}${RESET3}`;
638258
- }
638259
- out += RESTORE + SHOW;
638260
- try {
638261
- chromeWrite(out);
638262
- } catch {
638263
- }
638264
- _lastPaintedTop = newTop;
638265
- _lastPaintedBottom = newBottom;
638266
- }
638267
- function clearLastPaintedRows() {
638268
- if (_lastPaintedTop < 0 || _lastPaintedBottom < _lastPaintedTop) return;
638269
- const L = layout();
638270
- const safeTop = L.headerBottom + 1;
638271
- const safeBottom = Math.max(L.contentBottom, safeTop - 1);
638272
- let out = HIDE + SAVE;
638273
- for (let row = _lastPaintedTop; row <= _lastPaintedBottom; row++) {
638274
- if (row < safeTop || row > safeBottom) continue;
638275
- out += `\x1B[${row};1H${CLEAR_LINE}`;
638276
- }
638277
- out += RESTORE + SHOW;
638278
- try {
638279
- chromeWrite(out);
638280
- } catch {
638281
- }
638282
- _lastPaintedTop = -1;
638283
- _lastPaintedBottom = -1;
638284
- }
638285
- var chromeWrite, _activeSessionId, _watcher, _lastTodos, _enabled, _redrawScheduled, _onResizeChange, _scopeOverlayActive, _scopeMainViewActive, _scopeNeovimActive, _scopePagerActive, _lastPaintedTop, _lastPaintedBottom, MAX_VISIBLE_ROWS, SAVE, RESTORE, HIDE, SHOW, CLEAR_LINE, RESET3, BG, DIM_LABEL, ACCENT, DONE2, PENDING, BLOCKED;
638286
- var init_tui_tasks_renderer = __esm({
638287
- "packages/cli/src/tui/tui-tasks-renderer.ts"() {
638288
- "use strict";
638289
- init_layout2();
638290
- init_theme();
638291
- chromeWrite = ((data) => {
638292
- process.stdout.write(data);
638293
- });
638294
- _activeSessionId = null;
638295
- _watcher = null;
638296
- _lastTodos = [];
638297
- _enabled = true;
638298
- _redrawScheduled = false;
638299
- _onResizeChange = null;
638300
- _scopeOverlayActive = false;
638301
- _scopeMainViewActive = true;
638302
- _scopeNeovimActive = false;
638303
- _scopePagerActive = false;
638304
- _lastPaintedTop = -1;
638305
- _lastPaintedBottom = -1;
638306
- MAX_VISIBLE_ROWS = 8;
638307
- SAVE = "\x1B[s";
638308
- RESTORE = "\x1B[u";
638309
- HIDE = "\x1B[?25l";
638310
- SHOW = "\x1B[?25h";
638311
- CLEAR_LINE = "\x1B[2K";
638312
- RESET3 = "\x1B[0m";
638313
- BG = tuiBgSeq();
638314
- DIM_LABEL = "";
638315
- ACCENT = "";
638316
- DONE2 = "";
638317
- PENDING = "";
638318
- BLOCKED = "\x1B[38;5;196m";
638319
- refreshTuiTasksThemeVars();
638320
- }
638321
- });
638322
-
638323
638716
  // packages/cli/src/tui/status-bar.ts
638324
638717
  var status_bar_exports = {};
638325
638718
  __export(status_bar_exports, {
@@ -638355,7 +638748,7 @@ function stripSubAgentPrefix(label) {
638355
638748
  const stripped = label.replace(/^\s*sub[-\s]?agents?\b[\s:_–—-]*/i, "").trim();
638356
638749
  return stripped.length > 0 ? stripped : label.trim();
638357
638750
  }
638358
- function xterm256ToRgb(i2) {
638751
+ function xterm256ToRgb2(i2) {
638359
638752
  if (i2 >= 232) {
638360
638753
  const v = 8 + (i2 - 232) * 10;
638361
638754
  return [v, v, v];
@@ -638390,7 +638783,7 @@ function xterm256ToRgb(i2) {
638390
638783
  return base3[i2] ?? [0, 0, 0];
638391
638784
  }
638392
638785
  function contrastTextColor(colorIndex) {
638393
- const [r2, g, b] = xterm256ToRgb(colorIndex);
638786
+ const [r2, g, b] = xterm256ToRgb2(colorIndex);
638394
638787
  const luma = 0.299 * r2 + 0.587 * g + 0.114 * b;
638395
638788
  return luma >= 140 ? 16 : 231;
638396
638789
  }
@@ -638451,6 +638844,7 @@ var init_status_bar = __esm({
638451
638844
  "use strict";
638452
638845
  init_render();
638453
638846
  init_stageIndicator();
638847
+ init_tui_tasks_renderer();
638454
638848
  init_braille_spinner();
638455
638849
  init_project_context();
638456
638850
  init_dist8();
@@ -640896,6 +641290,17 @@ var init_status_bar = __esm({
640896
641290
  if (viewId) this.switchToView(viewId);
640897
641291
  return;
640898
641292
  }
641293
+ if (type === "press") {
641294
+ const Lt = layout();
641295
+ if (Lt.tasksTop > 0 && row >= Lt.tasksTop && row <= Lt.tasksBottom) {
641296
+ let consumed = false;
641297
+ try {
641298
+ consumed = handleTuiTasksClick(row);
641299
+ } catch {
641300
+ }
641301
+ if (consumed) return;
641302
+ }
641303
+ }
640899
641304
  if (type === "press" && this.handleFooterInputClick(row, col)) return;
640900
641305
  const L = layout();
640901
641306
  const inContent = row >= this.scrollRegionTop && row <= L.contentBottom;
@@ -641181,8 +641586,8 @@ var init_status_bar = __esm({
641181
641586
  const prefix = i2 === 0 ? this.promptText : " ".repeat(this.promptWidth);
641182
641587
  const lineContent = `${prefix}${inputWrap.lines[i2]}`;
641183
641588
  buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K`;
641184
- buf += `${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}${lineContent}`;
641185
- buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
641589
+ buf += `${this.borderVSeq(1)}${BOX_V3}${RESET4}${PANEL_BG_SEQ}${lineContent}`;
641590
+ buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${this.borderVSeq(w)}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
641186
641591
  }
641187
641592
  buf += this.buildEnhanceSegment(
641188
641593
  w,
@@ -642201,11 +642606,11 @@ ${CONTENT_BG_SEQ}`);
642201
642606
  * on the metrics row, beside the scroll-down / copy-tui controls. The block
642202
642607
  * is a fixed-width cell so it never bleeds into the metrics sections.
642203
642608
  */
642204
- buildStageBlock() {
642609
+ buildStageBlock(maxWidth) {
642205
642610
  const { stage: stage2, detail } = getStage();
642206
- const termWidth = getTermWidth();
642611
+ const needed = stageBlockNeededWidth(stage2, detail);
642207
642612
  const reserved = clampGradientWidth(
642208
- Math.min(28, Math.max(12, Math.floor(termWidth * 0.22)))
642613
+ Math.max(12, Math.min(needed, maxWidth))
642209
642614
  );
642210
642615
  const truecolor = supportsTruecolor();
642211
642616
  this._stagePhase = (this._stagePhase + 6) % 360;
@@ -642221,7 +642626,6 @@ ${CONTENT_BG_SEQ}`);
642221
642626
  ) + " ";
642222
642627
  }
642223
642628
  buildMetricsLine() {
642224
- const stageBlock = this.buildStageBlock();
642225
642629
  const m2 = this.metrics;
642226
642630
  const termWidth = getTermWidth();
642227
642631
  const uptime2 = this.formatUptime();
@@ -642300,8 +642704,11 @@ ${CONTENT_BG_SEQ}`);
642300
642704
  const pageIdx = this._debugPanelPage + 2;
642301
642705
  const indicator = `\x1B[38;5;240m[${pageIdx > 5 ? 1 : pageIdx}/${pageTotal}]\x1B[0m `;
642302
642706
  const fullRight = pageLabel + rightSide + indicator + arrow;
642303
- const stageW = stripAnsi(stageBlock).length;
642304
642707
  const rightW = stripAnsi(fullRight).length;
642708
+ const stageBlock = this.buildStageBlock(
642709
+ Math.max(12, termWidth - rightW - 2)
642710
+ );
642711
+ const stageW = stripAnsi(stageBlock).length;
642305
642712
  const padNeeded = termWidth - stageW - rightW - 1;
642306
642713
  const gap = padNeeded > 0 ? " ".repeat(padNeeded) : " ";
642307
642714
  return (stageBlock + gap + fullRight).replace(
@@ -642371,23 +642778,70 @@ ${CONTENT_BG_SEQ}`);
642371
642778
  const seg = this.enhanceSegEnabled(w) ? ENHANCE_SEG_INNER + 1 : 0;
642372
642779
  return Math.max(1, w - this.promptWidth - 2 - seg);
642373
642780
  }
642781
+ // ── stage-matched border gradient ────────────────────────────────────
642782
+ /** True when the input-box border should flow with the stage gradient:
642783
+ * a run is active (sweeping stage) and the terminal supports truecolor. */
642784
+ stageBorderActive() {
642785
+ return supportsTruecolor() && isSweepingStage(getStage().stage);
642786
+ }
642787
+ /** Paint a raw run of border glyphs with the current stage's gradient band
642788
+ * (same hue range as the stage indicator block, so the box edges match
642789
+ * the stage color). Colors in 4-column segments to keep the footer hot
642790
+ * path cheap. Falls back to plain BOX_FG when idle / no truecolor. */
642791
+ paintInputBorder(glyphs, startCol = 0) {
642792
+ if (!this.stageBorderActive()) {
642793
+ return `${BOX_FG}${glyphs}${RESET4}`;
642794
+ }
642795
+ const { stage: stage2 } = getStage();
642796
+ const SEG = 4;
642797
+ let out = "";
642798
+ for (let i2 = 0; i2 < glyphs.length; i2 += SEG) {
642799
+ const [r2, g, b] = stageGradientRgb(
642800
+ stage2,
642801
+ Math.floor((startCol + i2) / SEG),
642802
+ this._stagePhase
642803
+ );
642804
+ out += `\x1B[38;2;${r2};${g};${b}m${glyphs.slice(i2, i2 + SEG)}`;
642805
+ }
642806
+ return out + RESET4;
642807
+ }
642808
+ /** Color sequence for a single vertical border bar at absolute column
642809
+ * `col` (1-based) — matches what paintInputBorder gives that column. */
642810
+ borderVSeq(col) {
642811
+ if (!this.stageBorderActive()) return BOX_FG;
642812
+ const { stage: stage2 } = getStage();
642813
+ const [r2, g, b] = stageGradientRgb(
642814
+ stage2,
642815
+ Math.floor(Math.max(0, col - 1) / 4),
642816
+ this._stagePhase
642817
+ );
642818
+ return `\x1B[38;2;${r2};${g};${b}m`;
642819
+ }
642374
642820
  /** Box top border with an optional ┬ carving out the enhance segment. */
642375
642821
  buildInputBoxTop(w) {
642376
642822
  if (!this.enhanceSegEnabled(w)) {
642377
- return `${BOX_FG}${BOX_TL3}${BOX_H3.repeat(Math.max(0, w - 2))}${BOX_TR3}${RESET4}`;
642823
+ return this.paintInputBorder(
642824
+ `${BOX_TL3}${BOX_H3.repeat(Math.max(0, w - 2))}${BOX_TR3}`
642825
+ );
642378
642826
  }
642379
642827
  const dividerCol = this.enhanceDividerCol(w);
642380
642828
  const leftDashes = Math.max(0, dividerCol - 2);
642381
- return `${BOX_FG}${BOX_TL3}${BOX_H3.repeat(leftDashes)}${BOX_TJ}${BOX_H3.repeat(ENHANCE_SEG_INNER)}${BOX_TR3}${RESET4}`;
642829
+ return this.paintInputBorder(
642830
+ `${BOX_TL3}${BOX_H3.repeat(leftDashes)}${BOX_TJ}${BOX_H3.repeat(ENHANCE_SEG_INNER)}${BOX_TR3}`
642831
+ );
642382
642832
  }
642383
642833
  /** Box bottom border with an optional ┴ closing the enhance segment. */
642384
642834
  buildInputBoxBottom(w) {
642385
642835
  if (!this.enhanceSegEnabled(w)) {
642386
- return `${BOX_FG}${BOX_BL3}${BOX_H3.repeat(Math.max(0, w - 2))}${BOX_BR3}${RESET4}`;
642836
+ return this.paintInputBorder(
642837
+ `${BOX_BL3}${BOX_H3.repeat(Math.max(0, w - 2))}${BOX_BR3}`
642838
+ );
642387
642839
  }
642388
642840
  const dividerCol = this.enhanceDividerCol(w);
642389
642841
  const leftDashes = Math.max(0, dividerCol - 2);
642390
- return `${BOX_FG}${BOX_BL3}${BOX_H3.repeat(leftDashes)}${BOX_BJ}${BOX_H3.repeat(ENHANCE_SEG_INNER)}${BOX_BR3}${RESET4}`;
642842
+ return this.paintInputBorder(
642843
+ `${BOX_BL3}${BOX_H3.repeat(leftDashes)}${BOX_BJ}${BOX_H3.repeat(ENHANCE_SEG_INNER)}${BOX_BR3}`
642844
+ );
642391
642845
  }
642392
642846
  /**
642393
642847
  * Draw the │ divider down each input row plus the enhance/confirm button in
@@ -642407,7 +642861,7 @@ ${CONTENT_BG_SEQ}`);
642407
642861
  let buf = "";
642408
642862
  for (let i2 = 0; i2 < rowCount; i2++) {
642409
642863
  const row = firstInputRow + i2;
642410
- buf += `\x1B[${row};${dividerCol}H${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
642864
+ buf += `\x1B[${row};${dividerCol}H${this.borderVSeq(dividerCol)}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
642411
642865
  if (i2 > 0) {
642412
642866
  buf += `\x1B[${row};${cellStart}H${PANEL_BG_SEQ}${" ".repeat(ENHANCE_SEG_INNER)}`;
642413
642867
  }
@@ -642862,9 +643316,9 @@ ${CONTENT_BG_SEQ}`);
642862
643316
  const prefix = i2 === 0 ? this.promptText : " ".repeat(this.promptWidth);
642863
643317
  const lineContent = `${prefix}${inputWrap.lines[i2]}`;
642864
643318
  buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K`;
642865
- buf += `${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}${lineContent}`;
643319
+ buf += `${this.borderVSeq(1)}${BOX_V3}${RESET4}${PANEL_BG_SEQ}${lineContent}`;
642866
643320
  buf += `${PANEL_BG_SEQ}\x1B[K`;
642867
- buf += `\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
643321
+ buf += `\x1B[${row};${w}H${this.borderVSeq(w)}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
642868
643322
  }
642869
643323
  buf += this.buildEnhanceSegment(
642870
643324
  w,
@@ -642881,10 +643335,10 @@ ${CONTENT_BG_SEQ}`);
642881
643335
  const fg2 = isHighlighted ? `\x1B[1;38;5;${TEXT_PRIMARY}m` : `\x1B[38;5;${TEXT_PRIMARY}m`;
642882
643336
  const slash = isHighlighted ? `\x1B[38;5;245m` : `\x1B[38;5;${TEXT_DIM}m`;
642883
643337
  const marker = isHighlighted ? `\x1B[38;5;${TEXT_PRIMARY}m› ` : " ";
642884
- buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
643338
+ buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${this.borderVSeq(1)}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
642885
643339
  buf += `${bg} ${marker}${slash}/${fg2}${cmd}`;
642886
643340
  buf += `${PANEL_BG_SEQ}\x1B[K`;
642887
- buf += `\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
643341
+ buf += `\x1B[${row};${w}H${this.borderVSeq(w)}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
642888
643342
  }
642889
643343
  const suggestBottomRow = pos.suggestStartRow + this._suggestions.length;
642890
643344
  buf += `\x1B[${suggestBottomRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxBottom(w)}${PANEL_BG_SEQ}`;
@@ -642936,8 +643390,8 @@ ${CONTENT_BG_SEQ}`);
642936
643390
  const isHl = si === this._suggestIndex;
642937
643391
  const fg2 = isHl ? `\x1B[1;38;5;${TEXT_PRIMARY}m` : `\x1B[38;5;${TEXT_PRIMARY}m`;
642938
643392
  const marker = isHl ? `\x1B[38;5;${TEXT_PRIMARY}m› ` : " ";
642939
- buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ} ${marker}\x1B[38;5;${TEXT_DIM}m/${fg2}${cmd}`;
642940
- buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}`;
643393
+ buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${this.borderVSeq(1)}${BOX_V3}${RESET4}${PANEL_BG_SEQ} ${marker}\x1B[38;5;${TEXT_DIM}m/${fg2}${cmd}`;
643394
+ buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${this.borderVSeq(w)}${BOX_V3}${RESET4}`;
642941
643395
  }
642942
643396
  buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxBottom(w)}`;
642943
643397
  } else {
@@ -643000,7 +643454,7 @@ ${CONTENT_BG_SEQ}`);
643000
643454
  const row = pos.inputStartRow + 1 + i2;
643001
643455
  const prefix = i2 === 0 ? this.promptText : " ".repeat(this.promptWidth);
643002
643456
  const lineContent = `${prefix}${inputWrap.lines[i2]}`;
643003
- buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}${lineContent}${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}`;
643457
+ buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${this.borderVSeq(1)}${BOX_V3}${RESET4}${PANEL_BG_SEQ}${lineContent}${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${this.borderVSeq(w)}${BOX_V3}${RESET4}`;
643004
643458
  }
643005
643459
  buf += this.buildEnhanceSegment(
643006
643460
  w,
@@ -643015,9 +643469,9 @@ ${CONTENT_BG_SEQ}`);
643015
643469
  const bg = isHl ? `\x1B[48;5;235m` : PANEL_BG_SEQ;
643016
643470
  const fg2 = isHl ? `\x1B[1;38;5;${TEXT_PRIMARY}m` : `\x1B[38;5;${TEXT_PRIMARY}m`;
643017
643471
  const marker = isHl ? `\x1B[38;5;${TEXT_PRIMARY}m› ` : " ";
643018
- buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
643472
+ buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${this.borderVSeq(1)}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
643019
643473
  buf += `${bg} ${marker}\x1B[38;5;${TEXT_DIM}m/${fg2}${cmd}`;
643020
- buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}`;
643474
+ buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${this.borderVSeq(w)}${BOX_V3}${RESET4}`;
643021
643475
  }
643022
643476
  }
643023
643477
  buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxBottom(w)}`;
@@ -643043,9 +643497,9 @@ ${CONTENT_BG_SEQ}`);
643043
643497
  const prefix = i2 === 0 ? this.promptText : " ".repeat(this.promptWidth);
643044
643498
  const lineContent = `${prefix}${inputWrap.lines[i2]}`;
643045
643499
  buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K`;
643046
- buf += `${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}${lineContent}`;
643500
+ buf += `${this.borderVSeq(1)}${BOX_V3}${RESET4}${PANEL_BG_SEQ}${lineContent}`;
643047
643501
  buf += `${PANEL_BG_SEQ}\x1B[K`;
643048
- buf += `\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
643502
+ buf += `\x1B[${row};${w}H${this.borderVSeq(w)}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
643049
643503
  }
643050
643504
  buf += this.buildEnhanceSegment(
643051
643505
  w,
@@ -643060,9 +643514,9 @@ ${CONTENT_BG_SEQ}`);
643060
643514
  const bg = isHl ? `\x1B[48;5;235m` : PANEL_BG_SEQ;
643061
643515
  const fg2 = isHl ? `\x1B[1;38;5;${TEXT_PRIMARY}m` : `\x1B[38;5;${TEXT_PRIMARY}m`;
643062
643516
  const marker = isHl ? `\x1B[38;5;${TEXT_PRIMARY}m› ` : " ";
643063
- buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
643517
+ buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${this.borderVSeq(1)}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
643064
643518
  buf += `${bg} ${marker}\x1B[38;5;${TEXT_DIM}m/${fg2}${cmd}`;
643065
- buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
643519
+ buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${this.borderVSeq(w)}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
643066
643520
  }
643067
643521
  }
643068
643522
  buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxBottom(w)}${PANEL_BG_SEQ}`;
@@ -734786,11 +735240,11 @@ ${task}` : task,
734786
735240
  return;
734787
735241
  }
734788
735242
  const j = JSON.parse(result2.body);
734789
- const responseText = j?.choices?.[0]?.text ?? "";
735243
+ const responseText2 = j?.choices?.[0]?.text ?? "";
734790
735244
  jsonResponse(res, 200, {
734791
735245
  model: model.replace(/^[a-z]+\//, ""),
734792
735246
  created_at: createdAt,
734793
- response: responseText,
735247
+ response: responseText2,
734794
735248
  done: true,
734795
735249
  done_reason: "stop"
734796
735250
  });
@@ -746299,107 +746753,19 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
746299
746753
  }
746300
746754
  };
746301
746755
  }
746302
- function extractEnhancedPrompt(raw) {
746303
- const text2 = raw.trim();
746304
- if (!text2) return null;
746305
- const tryParse = (candidate) => {
746306
- try {
746307
- const obj = JSON.parse(candidate);
746308
- const v = obj["enhancedPrompt"] ?? obj["enhanced_prompt"] ?? obj["prompt"] ?? obj["result"];
746309
- return typeof v === "string" && v.trim() ? v : null;
746310
- } catch {
746311
- return null;
746312
- }
746313
- };
746314
- const direct = tryParse(text2);
746315
- if (direct) return direct;
746316
- const fenced = text2.match(/```(?:json)?\s*([\s\S]*?)```/i);
746317
- if (fenced?.[1]) {
746318
- const f2 = tryParse(fenced[1].trim());
746319
- if (f2) return f2;
746320
- }
746321
- const brace = text2.match(/\{[\s\S]*\}/);
746322
- if (brace?.[0]) {
746323
- const b = tryParse(brace[0]);
746324
- if (b) return b;
746325
- }
746326
- const keyed = text2.match(/"enhanced_?[Pp]rompt"\s*:\s*"((?:[^"\\]|\\.)*)"/);
746327
- if (keyed?.[1]) {
746328
- try {
746329
- return JSON.parse('"' + keyed[1] + '"');
746330
- } catch {
746331
- return keyed[1];
746332
- }
746333
- }
746334
- if (!text2.startsWith("{") && !text2.startsWith("[")) return text2;
746335
- return null;
746336
- }
746337
- async function enhancePromptViaInference(seed, backend, ctx3) {
746338
- const seedText = seed.trim();
746339
- if (!seedText) return null;
746340
- const recent = ctx3.recentHistory.filter((h) => h && h.trim()).slice(0, 5).map((h, i2) => ` ${i2 + 1}. ${h.trim().slice(0, 240)}`).join("\n");
746756
+ async function enhancePromptViaInference2(seed, backend, ctx3) {
746341
746757
  let runtimeCtx = "";
746342
746758
  try {
746343
746759
  runtimeCtx = buildConversationRuntimeContext(/* @__PURE__ */ new Date(), ctx3.repoRoot);
746344
746760
  } catch {
746345
746761
  runtimeCtx = "";
746346
746762
  }
746347
- const userPrompt = [
746348
- "Expand the SEED PROMPT below into a comprehensive, precise, self-contained instruction set for an agentic coding assistant.",
746349
- "Preserve the user's original intent exactly. Do NOT answer or solve it, do NOT invent unrelated scope.",
746350
- "Clarify the goal, surface implied requirements, relevant constraints, edge cases, and concrete acceptance criteria.",
746351
- "Fold in only the session context that is actually relevant. Keep it phrased as an instruction in the user's voice.",
746352
- "Return no preamble and no meta-commentary about the prompt itself.",
746353
- ctx3.activeGoal ? `
746354
- Task currently in progress: ${ctx3.activeGoal.slice(0, 400)}` : "",
746355
- recent ? `
746356
- Recent prompts this session (newest first):
746357
- ${recent}` : "",
746358
- runtimeCtx ? `
746359
- Session/runtime context:
746360
- ${runtimeCtx}` : "",
746361
- `
746362
- SEED PROMPT:
746363
- ${seedText}`
746364
- ].filter(Boolean).join("\n");
746365
- try {
746366
- const messages2 = [
746367
- {
746368
- role: "system",
746369
- content: `You are a prompt-expansion engine. You rewrite a user's short seed prompt into a richer, unambiguous instruction that fully captures their intent. Return strict JSON only: {"enhancedPrompt": string}.`
746370
- },
746371
- { role: "user", content: userPrompt }
746372
- ];
746373
- let resp;
746374
- try {
746375
- resp = await backend.chatCompletion({
746376
- messages: messages2,
746377
- tools: [],
746378
- temperature: 0.4,
746379
- maxTokens: 1400,
746380
- timeoutMs: 6e4,
746381
- think: false,
746382
- responseFormat: { type: "json_object" }
746383
- });
746384
- } catch {
746385
- resp = await backend.chatCompletion({
746386
- messages: messages2,
746387
- tools: [],
746388
- temperature: 0.4,
746389
- maxTokens: 1400,
746390
- timeoutMs: 6e4,
746391
- think: false
746392
- });
746393
- }
746394
- const rawContent2 = resp.choices?.[0]?.message?.content ?? "";
746395
- if (!rawContent2) return null;
746396
- const enhanced = extractEnhancedPrompt(rawContent2);
746397
- if (!enhanced) return null;
746398
- const clean5 = enhanced.trim();
746399
- return clean5 && clean5 !== seedText ? clean5 : null;
746400
- } catch {
746401
- return null;
746402
- }
746763
+ return enhancePromptViaInference(seed, backend, {
746764
+ repoRoot: ctx3.repoRoot,
746765
+ recentHistory: ctx3.recentHistory,
746766
+ activeGoal: ctx3.activeGoal,
746767
+ runtimeContext: runtimeCtx
746768
+ });
746403
746769
  }
746404
746770
  async function startInteractive(config, repoPath2) {
746405
746771
  const repoRoot = resolve74(repoPath2 ?? cwd());
@@ -747998,7 +748364,7 @@ This is an independent background session started from /background.`
747998
748364
  } catch {
747999
748365
  return null;
748000
748366
  }
748001
- return enhancePromptViaInference(seedPrompt, enhanceBackend, {
748367
+ return enhancePromptViaInference2(seedPrompt, enhanceBackend, {
748002
748368
  repoRoot,
748003
748369
  recentHistory: savedHistory,
748004
748370
  activeGoal: activeTask ? lastSubmittedPrompt : void 0
@@ -753029,6 +753395,7 @@ var init_interactive = __esm({
753029
753395
  init_visual_sensor_guidance();
753030
753396
  init_live_sensors();
753031
753397
  init_conversation_context();
753398
+ init_prompt_enhance();
753032
753399
  init_dist8();
753033
753400
  init_dist8();
753034
753401
  init_dist8();
@@ -753091,6 +753458,7 @@ var init_interactive = __esm({
753091
753458
  init_neovim_mode();
753092
753459
  init_task_manager_singleton();
753093
753460
  init_tui_tasks_renderer();
753461
+ init_prompt_enhance();
753094
753462
  NEXUS_DIRECTORY_ORIGIN3 = (process.env["OMNIUS_NEXUS_DIRECTORY_ORIGIN"] || process.env["OMNIUS_NEXUS_SIGNALING_SERVER"] || "https://openagents.nexus").replace(/\/+$/, "");
753095
753463
  NEXUS_AGENT_DIRECTORY_URL = `${NEXUS_DIRECTORY_ORIGIN3}/api/v1/directory`;
753096
753464
  localOllamaModelCache = null;