nolo-cli 0.49.0-alpha.1 → 0.51.0-alpha.1

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.
@@ -8,8 +8,8 @@ import {
8
8
  } from "./chunk-LYGNQHUW.js";
9
9
  import {
10
10
  runAgentCreateCommand
11
- } from "./chunk-QAG4ZQZ7.js";
12
- import "./chunk-33BBDA67.js";
11
+ } from "./chunk-IPIJNOJJ.js";
12
+ import "./chunk-BYFBW5FZ.js";
13
13
  import "./chunk-3YVCM5PE.js";
14
14
  import "./chunk-EADNWBAZ.js";
15
15
  import "./chunk-NI2BS6UD.js";
@@ -84,7 +84,7 @@ async function defaultExecuteCli(provider, prompt, options) {
84
84
  return executeCli(provider, prompt, options);
85
85
  }
86
86
  async function forwardConnectorRunMessage(machine, message, pushMessage, executeCli, env, fetchImpl) {
87
- const { handleConnectorRunMessage } = await import("./machineWsRunDispatch-KWWJ4HTI.js");
87
+ const { handleConnectorRunMessage } = await import("./machineWsRunDispatch-UB2KMAXY.js");
88
88
  return handleConnectorRunMessage(message, pushMessage, executeCli, env, fetchImpl);
89
89
  }
90
90
  async function detectLaunchableMachineInfo() {
@@ -2,8 +2,8 @@ import {
2
2
  runAgentCreateCommand,
3
3
  runAgentReadCommand,
4
4
  runAgentUpdateCommand
5
- } from "./chunk-QAG4ZQZ7.js";
6
- import "./chunk-33BBDA67.js";
5
+ } from "./chunk-IPIJNOJJ.js";
6
+ import "./chunk-BYFBW5FZ.js";
7
7
  import "./chunk-3YVCM5PE.js";
8
8
  import "./chunk-EADNWBAZ.js";
9
9
  import "./chunk-NI2BS6UD.js";
@@ -5,12 +5,12 @@ import {
5
5
  prependSubjectDialogMarker,
6
6
  resolveWorkflowReference,
7
7
  runAgentRunCommand
8
- } from "./chunk-VZGLZTG7.js";
8
+ } from "./chunk-RENO4QJU.js";
9
9
  import "./chunk-J3UALFHL.js";
10
10
  import {
11
11
  parseAgentRunArgs
12
12
  } from "./chunk-LYGNQHUW.js";
13
- import "./chunk-33BBDA67.js";
13
+ import "./chunk-BYFBW5FZ.js";
14
14
  import "./chunk-3YVCM5PE.js";
15
15
  import "./chunk-EADNWBAZ.js";
16
16
  import "./chunk-NI2BS6UD.js";
@@ -472,8 +472,8 @@ var STRINGS = {
472
472
  zh: "[nolo] \u5F53\u524D agent \u4F3C\u4E4E\u989D\u5EA6/\u901F\u7387\u53D7\u9650\uFF08429\uFF09\u3002\n\u53EF\u4EE5\u7528 /agent \u5207\u6362\u5230\u5176\u4ED6 agent \u540E\u7EE7\u7EED\uFF0C\u540C\u4E00\u5BF9\u8BDD\u4F1A\u4FDD\u7559\u4E0A\u4E0B\u6587\u3002"
473
473
  },
474
474
  balanceExhaustedHint: {
475
- en: '[nolo] Insufficient balance. Your message is saved in this dialog \u2014 top up, then send again or say "continue".',
476
- zh: "[nolo] \u4F59\u989D\u4E0D\u8DB3\u3002\u4F60\u521A\u53D1\u7684\u8BDD\u5DF2\u4FDD\u5B58\u5728\u5F53\u524D\u5BF9\u8BDD\u91CC\u2014\u2014\u5145\u503C\u540E\u76F4\u63A5\u518D\u8BF4\u4E00\u53E5\u6216\u8BF4\u300C\u7EE7\u7EED\u300D\u5373\u53EF\uFF0C\u4E0D\u4F1A\u4E22\u4E0A\u4E0B\u6587\u3002"
475
+ en: '[nolo] Your message is saved in this dialog \u2014 top up, then send again or say "continue" to pick up where you left off.',
476
+ zh: "[nolo] \u4F60\u521A\u53D1\u7684\u8BDD\u5DF2\u4FDD\u5B58\u5728\u5F53\u524D\u5BF9\u8BDD\u91CC\u2014\u2014\u5145\u503C\u540E\u76F4\u63A5\u518D\u8BF4\u4E00\u53E5\u6216\u8BF4\u300C\u7EE7\u7EED\u300D\u5373\u53EF\u63A5\u7740\u804A\uFF0C\u4E0D\u4F1A\u4E22\u4E0A\u4E0B\u6587\u3002"
477
477
  },
478
478
  dialogPreservedHint: {
479
479
  en: '[nolo] This turn failed, but the dialog is kept. Send another message (or say "continue") to keep going in the same conversation.',
@@ -912,10 +912,10 @@ var STRINGS = {
912
912
  runtimeUsage: { en: "Usage: /runtime <auto|local|server>", zh: "\u7528\u6CD5\uFF1A/runtime <auto|local|server>" },
913
913
  runtimeSet: { en: "Runtime: {0}", zh: "\u8FD0\u884C\u6A21\u5F0F\uFF1A{0}" },
914
914
  toolsCurrent: {
915
- en: "Tool display: {0} (hide | compact | verbose)",
916
- zh: "\u5DE5\u5177\u663E\u793A\uFF1A{0}\uFF08hide | compact | verbose\uFF09"
915
+ en: "Tool display: {0} (normal | pro | hide | verbose)",
916
+ zh: "\u5DE5\u5177\u663E\u793A\uFF1A{0}\uFF08\u666E\u901A normal | \u4E13\u4E1A pro | hide | verbose\uFF09"
917
917
  },
918
- toolsUsage: { en: "Usage: /tools <hide|compact|verbose>", zh: "\u7528\u6CD5\uFF1A/tools <hide|compact|verbose>" },
918
+ toolsUsage: { en: "Usage: /tools <normal|pro|hide|verbose>", zh: "\u7528\u6CD5\uFF1A/tools <normal|pro|hide|verbose>" },
919
919
  toolsSet: { en: "Tool display: {0}", zh: "\u5DE5\u5177\u663E\u793A\uFF1A{0}" },
920
920
  thinkingCurrent: {
921
921
  en: "Thinking display: {0} (show | hide)",
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  clearCliLocalRuntimePreparedAgentCache
3
- } from "./chunk-33BBDA67.js";
3
+ } from "./chunk-BYFBW5FZ.js";
4
4
  import {
5
5
  getReadableCliDb
6
6
  } from "./chunk-43CXXVJD.js";
@@ -19,7 +19,7 @@ import {
19
19
  parseAgentRunEvent,
20
20
  t,
21
21
  toolLabel
22
- } from "./chunk-33BBDA67.js";
22
+ } from "./chunk-BYFBW5FZ.js";
23
23
  import {
24
24
  getReadableCliDb
25
25
  } from "./chunk-43CXXVJD.js";
@@ -3717,7 +3717,7 @@ function tokenize(value, options) {
3717
3717
  }
3718
3718
 
3719
3719
  // packages/cli/client/toolOutput.ts
3720
- function normalizeToolDisplayMode(raw, fallback = "compact") {
3720
+ function normalizeToolDisplayMode(raw, fallback = "normal") {
3721
3721
  const normalized = asTrimmedLowercaseString(raw);
3722
3722
  if (normalized === "hide" || normalized === "off" || normalized === "false" || normalized === "0") {
3723
3723
  return "hide";
@@ -3725,8 +3725,11 @@ function normalizeToolDisplayMode(raw, fallback = "compact") {
3725
3725
  if (normalized === "verbose" || normalized === "debug" || normalized === "trace" || normalized === "full") {
3726
3726
  return "verbose";
3727
3727
  }
3728
- if (normalized === "compact" || normalized === "minimal" || normalized === "short") {
3729
- return "compact";
3728
+ if (normalized === "normal" || normalized === "summary" || normalized === "on") {
3729
+ return "normal";
3730
+ }
3731
+ if (normalized === "pro" || normalized === "compact" || normalized === "minimal" || normalized === "short") {
3732
+ return "pro";
3730
3733
  }
3731
3734
  return fallback;
3732
3735
  }
@@ -3738,7 +3741,7 @@ function resolveToolDisplayMode(env = process.env) {
3738
3741
  if (legacyTrace === "verbose" || legacyTrace === "full") {
3739
3742
  return "verbose";
3740
3743
  }
3741
- return normalizeToolDisplayMode(env.NOLO_CLI_TOOLS ?? env.NOLO_TOOLS, "compact");
3744
+ return normalizeToolDisplayMode(env.NOLO_CLI_TOOLS ?? env.NOLO_TOOLS, "normal");
3742
3745
  }
3743
3746
  function shouldEmitToolEvents(mode) {
3744
3747
  return mode !== "hide";
@@ -3752,6 +3755,9 @@ function formatActiveToolLabel(event) {
3752
3755
  const label = toolLabel(toolName);
3753
3756
  return args ? `${label} ${args}` : label;
3754
3757
  }
3758
+ function formatConservativeActiveToolLabel(event) {
3759
+ return toolLabel(event.toolName || "tool");
3760
+ }
3755
3761
  function compactResultHint(event) {
3756
3762
  const gate = readActionGate(event.metadata?.actionGate);
3757
3763
  if (gate) {
@@ -4160,6 +4166,36 @@ function formatVerboseToolEvent(event, colorEnabled) {
4160
4166
  colorEnabled
4161
4167
  );
4162
4168
  }
4169
+ function formatNormalToolLine(event, pending, colorEnabled) {
4170
+ if (event.type === "tool-call") return "";
4171
+ const toolName = event.toolName || pending?.toolName || "tool";
4172
+ const todoBlock = formatTodoListForCli(event, colorEnabled);
4173
+ if (todoBlock) return todoBlock;
4174
+ if (event.type === "tool-result" && (event.toolName === "ask_user" || event.metadata?.uiAskChoice)) {
4175
+ const block = formatUiAskChoiceBlock(event, colorEnabled);
4176
+ if (block) return block;
4177
+ }
4178
+ if (event.type === "tool-result" && (toolName === "listAgents" || toolName === "startAgentRun" || toolName === "controlAgentRun")) {
4179
+ return formatOrchestrationCardBlock(event, toolName, colorEnabled);
4180
+ }
4181
+ if (event.type === "tool-result" && toolName === "loadSkill") {
4182
+ return formatLoadSkillBlock(event, colorEnabled) ?? "";
4183
+ }
4184
+ const label = toolLabel(toolName);
4185
+ if (readActionGate(event.metadata?.actionGate)) {
4186
+ return formatToolTraceLine(`\u25B8 ${label} ! ${t("toolNeedsAction")}`, colorEnabled, "error");
4187
+ }
4188
+ if (event.type === "tool-error") {
4189
+ return formatToolTraceLine(`\u25B8 ${label} \u2717 ${t("toolFailed")}`, colorEnabled, "error");
4190
+ }
4191
+ if (event.metadata?.timedOut) {
4192
+ return formatToolTraceLine(`\u25B8 ${label} \u2717 ${t("toolTimedOut")}`, colorEnabled, "error");
4193
+ }
4194
+ if (isFailedToolResult(event)) {
4195
+ return formatToolTraceLine(`\u25B8 ${label} \u2717 ${t("toolFailed")}`, colorEnabled, "error");
4196
+ }
4197
+ return formatToolTraceLine(`\u25B8 ${label} \u2713`, colorEnabled);
4198
+ }
4163
4199
  function isReadToolName(name) {
4164
4200
  if (!name) return false;
4165
4201
  return name === "read" || name === "readFile" || name === "read_file" || name === "readWorkspaceFile";
@@ -4346,6 +4382,26 @@ function formatTodoListForCli(event, colorEnabled) {
4346
4382
  const text = [`\u2611 Todo (${todos.length})`, ...lines].join("\n") + "\n";
4347
4383
  return colorEnabled ? themeText(text, "chrome") : text;
4348
4384
  }
4385
+ function formatLoadSkillBlock(event, colorEnabled) {
4386
+ if (event.type !== "tool-result" || event.toolName !== "loadSkill") return null;
4387
+ const skillName = resolveLoadSkillName(event);
4388
+ const content = typeof event.content === "string" ? event.content : "";
4389
+ const failed = /^Skill\s+"[^"]*"\s+not found/.test(content) || isFailedToolResult(event);
4390
+ const labelText = t("usedSkillLabel");
4391
+ if (failed) {
4392
+ const message = clip(content.split("\n")[0] || t("toolFailed"), 96);
4393
+ return formatToolTraceLine(`\u25B8 ${labelText} (${skillName}) \u2717 ${message}`, colorEnabled, "error");
4394
+ }
4395
+ if (!colorEnabled) {
4396
+ return `\u2726 ${labelText}: ${skillName}
4397
+ `;
4398
+ }
4399
+ const star = themeText("\u2726", "success", true);
4400
+ const labelPart = themeText(labelText, "muted", true);
4401
+ const namePart = themeText(skillName, "chrome", true);
4402
+ return `${star} ${labelPart}: ${namePart}
4403
+ `;
4404
+ }
4349
4405
  function formatCompactToolLine(event, pending, colorEnabled) {
4350
4406
  const toolName = event.toolName || pending?.toolName || "tool";
4351
4407
  const todoBlock = formatTodoListForCli(event, colorEnabled);
@@ -4376,25 +4432,8 @@ function formatCompactToolLine(event, pending, colorEnabled) {
4376
4432
  const message = clip(event.message ?? t("toolFailed"), 96);
4377
4433
  return formatToolTraceLine(`\u25B8 ${label} \u2717 ${message}`, colorEnabled, "error");
4378
4434
  }
4379
- if (event.type === "tool-result" && toolName === "loadSkill") {
4380
- const skillName = resolveLoadSkillName(event);
4381
- const content = typeof event.content === "string" ? event.content : "";
4382
- const failed2 = /^Skill\s+"[^"]*"\s+not found/.test(content) || isFailedToolResult(event);
4383
- const labelText = t("usedSkillLabel");
4384
- if (failed2) {
4385
- const message = clip(content.split("\n")[0] || t("toolFailed"), 96);
4386
- return formatToolTraceLine(`\u25B8 ${labelText} (${skillName}) \u2717 ${message}`, colorEnabled, "error");
4387
- }
4388
- if (!colorEnabled) {
4389
- return `\u2726 ${labelText}: ${skillName}
4390
- `;
4391
- }
4392
- const star = themeText("\u2726", "success", true);
4393
- const labelPart = themeText(labelText, "muted", true);
4394
- const namePart = themeText(skillName, "chrome", true);
4395
- return `${star} ${labelPart}: ${namePart}
4396
- `;
4397
- }
4435
+ const loadSkillBlock = formatLoadSkillBlock(event, colorEnabled);
4436
+ if (loadSkillBlock) return loadSkillBlock;
4398
4437
  if (event.type === "tool-result" && (toolName === "listAgents" || toolName === "startAgentRun" || toolName === "controlAgentRun")) {
4399
4438
  return formatOrchestrationCardBlock(event, toolName, colorEnabled);
4400
4439
  }
@@ -4561,6 +4600,18 @@ function createToolEventFormatter(mode, colorEnabled = resolveCliColorEnabled(),
4561
4600
  const formatter = (event) => {
4562
4601
  if (mode === "hide") return "";
4563
4602
  if (mode === "verbose") return formatVerboseToolEvent(event, colorEnabled);
4603
+ if (mode === "normal") {
4604
+ if (event.type === "tool-call") {
4605
+ pending.set(event.toolCallId, {
4606
+ toolName: event.toolName,
4607
+ argumentsPreview: event.argumentsPreview
4608
+ });
4609
+ return "";
4610
+ }
4611
+ const call2 = pending.get(event.toolCallId);
4612
+ pending.delete(event.toolCallId);
4613
+ return formatNormalToolLine(event, call2, colorEnabled);
4614
+ }
4564
4615
  if (event.toolName === "controlAgentRun") {
4565
4616
  if (event.type === "tool-call") {
4566
4617
  pending.set(event.toolCallId, {
@@ -4837,6 +4888,7 @@ ${this.text}
4837
4888
  };
4838
4889
 
4839
4890
  // packages/cli/client/agentRunOutput.ts
4891
+ var IDENTITY_LABEL_SEPARATOR = " > ";
4840
4892
  function formatCompactionSummaryLine(event) {
4841
4893
  if (!event) return "";
4842
4894
  const action = event.reason === "tool_stub" ? "stub \u5DE5\u5177\u8F93\u51FA" : "\u751F\u6210\u5386\u53F2\u6458\u8981";
@@ -4899,6 +4951,15 @@ function createCliTurnOutput(params) {
4899
4951
  let printedAssistantLabel = false;
4900
4952
  let thinkState = createThinkParserState();
4901
4953
  let compactionEvent = null;
4954
+ const assistantLabelManaged = options.output.assistantLabelManaged === true;
4955
+ const writeToolOutput = (chunk) => {
4956
+ if (!chunk) return;
4957
+ if (typeof options.output.writeToolBlock === "function") {
4958
+ options.output.writeToolBlock(chunk);
4959
+ } else {
4960
+ options.output.write(chunk);
4961
+ }
4962
+ };
4902
4963
  const renderWriter = createRenderAwareStreamWriter({
4903
4964
  write: (chunk) => options.output.write(chunk)
4904
4965
  });
@@ -4914,8 +4975,10 @@ function createCliTurnOutput(params) {
4914
4975
  spinner.stop();
4915
4976
  options.activityReporter?.(null);
4916
4977
  if (!printedAssistantLabel) {
4917
- options.output.write(`
4918
- ${options.agentName} > `);
4978
+ if (!assistantLabelManaged) {
4979
+ options.output.write(`
4980
+ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
4981
+ }
4919
4982
  printedAssistantLabel = true;
4920
4983
  }
4921
4984
  streamedAssistantText = true;
@@ -4939,10 +5002,10 @@ ${options.agentName} > `);
4939
5002
  streamedAssistantText = false;
4940
5003
  }
4941
5004
  if (chunk) {
4942
- options.output.write(chunk);
5005
+ writeToolOutput(chunk);
4943
5006
  }
4944
- if (toolDisplayMode === "compact" && event.type === "tool-call") {
4945
- const activeLabel = formatActiveToolLabel(event);
5007
+ if ((toolDisplayMode === "compact" || toolDisplayMode === "pro" || toolDisplayMode === "normal") && event.type === "tool-call") {
5008
+ const activeLabel = toolDisplayMode === "normal" ? formatConservativeActiveToolLabel(event) : formatActiveToolLabel(event);
4946
5009
  spinner.show(activeLabel);
4947
5010
  options.activityReporter?.(activeLabel);
4948
5011
  }
@@ -4962,7 +5025,7 @@ ${options.agentName} > `);
4962
5025
  if (eventMode !== "jsonl" && formatToolEvent.flush) {
4963
5026
  const pendingToolOutput = formatToolEvent.flush();
4964
5027
  if (pendingToolOutput) {
4965
- options.output.write(pendingToolOutput);
5028
+ writeToolOutput(pendingToolOutput);
4966
5029
  }
4967
5030
  }
4968
5031
  writeVisibleAssistantChunk(chunk);
@@ -4990,7 +5053,7 @@ ${options.agentName} > `);
4990
5053
  }
4991
5054
  const pendingToolOutput = formatToolEvent.flush ? formatToolEvent.flush() : "";
4992
5055
  if (pendingToolOutput) {
4993
- options.output.write(pendingToolOutput);
5056
+ writeToolOutput(pendingToolOutput);
4994
5057
  }
4995
5058
  if (streamedAssistantText) {
4996
5059
  renderWriter.flush();
@@ -5000,13 +5063,18 @@ ${options.agentName} > `);
5000
5063
  } else {
5001
5064
  const content = fallbackContent ? formatAssistantResponseForCli(fallbackContent.trim()) : "";
5002
5065
  if (content) {
5003
- options.output.write(`
5004
- ${options.agentName} > ${content}
5005
- `);
5066
+ options.output.write(
5067
+ assistantLabelManaged ? `${content}
5068
+ ` : `
5069
+ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}${content}
5070
+ `
5071
+ );
5006
5072
  } else {
5007
- options.output.write(`
5008
- ${options.agentName} > (no text response)
5009
- `);
5073
+ options.output.write(
5074
+ assistantLabelManaged ? "(no text response)\n" : `
5075
+ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}(no text response)
5076
+ `
5077
+ );
5010
5078
  }
5011
5079
  }
5012
5080
  const compactionLine = formatCompactionSummaryLine(compactionEvent);
@@ -5447,6 +5515,19 @@ async function loadRunLocalAgentTurn() {
5447
5515
  const { runLocalAgentTurn } = await import("./agentRuntimeLocal-SIQYQGSK.js");
5448
5516
  return runLocalAgentTurn;
5449
5517
  }
5518
+ var stripDebugNoise = (s) => s.replace(/\s*raw="[\s\S]*"/g, "").replace(/\s*raw=\S+/g, "").replace(/\s*headers=\[[^\]]*\]/g, "").replace(/\s*headers=\S+/g, "").trim();
5519
+ function extractEmbeddedErrorMessage(message) {
5520
+ const match = /"message"\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(message);
5521
+ if (!match) return void 0;
5522
+ try {
5523
+ const decoded = JSON.parse(`"${match[1]}"`);
5524
+ if (typeof decoded !== "string" || !decoded.trim()) return void 0;
5525
+ const cleaned = decoded.replace(/[\u0000-\u001f\u007f]/g, "");
5526
+ return cleaned.trim() ? cleaned : void 0;
5527
+ } catch {
5528
+ return void 0;
5529
+ }
5530
+ }
5450
5531
  async function resolveCurrentMachineId(options) {
5451
5532
  return options.currentMachineIdResolver ? options.currentMachineIdResolver(options.env) : detectCurrentMachineId(options.env);
5452
5533
  }
@@ -5677,7 +5758,6 @@ function describeLocalRunFailure(message, rawError) {
5677
5758
  busyDetail = rawError.detail.trim();
5678
5759
  }
5679
5760
  if (/PLATFORM_LLM_BUSY|服务器紧张/.test(message)) {
5680
- const stripDebugNoise = (s) => s.replace(/\s*raw=".*"/g, "").replace(/\s*raw=\S+/g, "").replace(/\s*headers=\[[^\]]*\]/g, "").replace(/\s*headers=\S+/g, "").trim();
5681
5761
  const shown = stripDebugNoise(
5682
5762
  message.replace(/\s*\(PLATFORM_LLM_BUSY\)\s*$/, "")
5683
5763
  );
@@ -5688,7 +5768,13 @@ function describeLocalRunFailure(message, rawError) {
5688
5768
  if (/UPSTREAM_402|Insufficient Balance|余额不足|insufficient\s+balance/i.test(
5689
5769
  message
5690
5770
  )) {
5691
- return `${RUN_UNAVAILABLE_PREFIX} (${message}). ${NO_FALLBACK} Top up your balance, then send again (or say "\u7EE7\u7EED") \u2014 if a dialog was kept, context is preserved.
5771
+ const cleanedMessage = stripDebugNoise(message);
5772
+ const fallback = cleanedMessage.replace(
5773
+ /^[^:]*provider failed: HTTP \d{3}\s*/,
5774
+ ""
5775
+ );
5776
+ const shownMessage = extractEmbeddedErrorMessage(cleanedMessage) ?? fallback;
5777
+ return `[nolo] ${shownMessage}
5692
5778
  `;
5693
5779
  }
5694
5780
  const cls = classifyLocalRunError(message);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createCliLocalRuntimeAdapter,
3
3
  summarizeEndpoint
4
- } from "./chunk-33BBDA67.js";
4
+ } from "./chunk-BYFBW5FZ.js";
5
5
  import {
6
6
  clipMultilineText
7
7
  } from "./chunk-72COHDZR.js";
package/index.js CHANGED
@@ -127,7 +127,7 @@ function createDaemonShortcutCommand(path, description, command2) {
127
127
  // packages/cli/agentInternalCommandEntries.ts
128
128
  function getAgentInternalCommandEntries() {
129
129
  const createAgentRunCommand = (path, description) => createContextCommand(path, description, async (args2, ctx) => {
130
- const { runAgentRunCommand } = await import("./agentRunCommand-FINKBYUN.js");
130
+ const { runAgentRunCommand } = await import("./agentRunCommand-LK7BER3O.js");
131
131
  return runAgentRunCommand(args2, {
132
132
  env: ctx.env,
133
133
  scriptDir: ctx.scriptDir,
@@ -143,7 +143,7 @@ function getAgentInternalCommandEntries() {
143
143
  return runAgentListCommand(args2, deps);
144
144
  }),
145
145
  createEnvCommand(["agent", "create"], "Create a new agent", async (args2, deps) => {
146
- const { runAgentCreateCommand } = await import("./agentRecordCommands-OWKWVY3Y.js");
146
+ const { runAgentCreateCommand } = await import("./agentRecordCommands-J4ENRTN4.js");
147
147
  return runAgentCreateCommand(args2, deps);
148
148
  }),
149
149
  createEnvCommand(["agent", "models"], "List models available on an OpenAI-compatible provider", async (args2, deps) => {
@@ -155,7 +155,7 @@ function getAgentInternalCommandEntries() {
155
155
  return runAgentPullCommand(args2, deps);
156
156
  }),
157
157
  createEnvCommand(["agent", "read"], "Read a single agent", async (args2, deps) => {
158
- const { runAgentReadCommand } = await import("./agentRecordCommands-OWKWVY3Y.js");
158
+ const { runAgentReadCommand } = await import("./agentRecordCommands-J4ENRTN4.js");
159
159
  return runAgentReadCommand(args2, deps);
160
160
  }),
161
161
  createAgentRunCommand(["agent", "run"], "Run an agent"),
@@ -193,26 +193,26 @@ function getAgentInternalCommandEntries() {
193
193
  return runSetupOfflineMarxistsAgentCommand(args2, deps);
194
194
  }),
195
195
  createEnvCommand(["agent", "update"], "Update agent fields", async (args2, deps) => {
196
- const { runAgentUpdateCommand } = await import("./agentRecordCommands-OWKWVY3Y.js");
196
+ const { runAgentUpdateCommand } = await import("./agentRecordCommands-J4ENRTN4.js");
197
197
  return runAgentUpdateCommand(args2, deps);
198
198
  }),
199
199
  createEnvCommand(["agent", "email", "provision"], "Provision a controlled inbox for an agent", async (args2, deps) => {
200
- const { runAgentEmailProvisionCommand } = await import("./agentEmailCommands-C33KPOFP.js");
200
+ const { runAgentEmailProvisionCommand } = await import("./agentEmailCommands-FHBQ5QPA.js");
201
201
  return runAgentEmailProvisionCommand(args2, deps);
202
202
  }),
203
203
  createEnvCommand(["agent", "email", "bind"], "Bind an existing email address to an agent", async (args2, deps) => {
204
- const { runAgentEmailBindCommand } = await import("./agentEmailCommands-C33KPOFP.js");
204
+ const { runAgentEmailBindCommand } = await import("./agentEmailCommands-FHBQ5QPA.js");
205
205
  return runAgentEmailBindCommand(args2, deps);
206
206
  }),
207
207
  createEnvCommand(["agent", "email", "transfer"], "Transfer an email identity from one agent to another (cross-account)", async (args2, deps) => {
208
- const { runAgentEmailTransferCommand } = await import("./agentEmailCommands-C33KPOFP.js");
208
+ const { runAgentEmailTransferCommand } = await import("./agentEmailCommands-FHBQ5QPA.js");
209
209
  return runAgentEmailTransferCommand(args2, deps);
210
210
  }),
211
211
  createEnvCommand(
212
212
  ["agent", "email", "create-and-provision"],
213
213
  "Create an agent and provision its controlled inbox",
214
214
  async (args2, deps) => {
215
- const { runAgentEmailCreateAndProvisionCommand } = await import("./agentEmailCommands-C33KPOFP.js");
215
+ const { runAgentEmailCreateAndProvisionCommand } = await import("./agentEmailCommands-FHBQ5QPA.js");
216
216
  return runAgentEmailCreateAndProvisionCommand(args2, deps);
217
217
  }
218
218
  ),
@@ -233,15 +233,15 @@ function getAgentInternalCommandEntries() {
233
233
  return runAgentRevokeGrantCommand(args2, deps);
234
234
  }),
235
235
  createEnvCommand(["agent", "bind-current"], "Bind an agent to this machine", async (args2, deps) => {
236
- const { runAgentBindCurrentCommand } = await import("./agentMachineCommands-ICOLSVID.js");
236
+ const { runAgentBindCurrentCommand } = await import("./agentMachineCommands-LJ36TKS6.js");
237
237
  return runAgentBindCurrentCommand(args2, deps);
238
238
  }),
239
239
  createEnvCommand(["agent", "smoke-current"], "Smoke test a bound agent through this machine", async (args2, deps) => {
240
- const { runAgentSmokeCurrentCommand } = await import("./agentMachineCommands-ICOLSVID.js");
240
+ const { runAgentSmokeCurrentCommand } = await import("./agentMachineCommands-LJ36TKS6.js");
241
241
  return runAgentSmokeCurrentCommand(args2, deps);
242
242
  }),
243
243
  createEnvCommand(["agent", "runtime-doctor"], "Diagnose current machine runtime compatibility", async (args2, deps) => {
244
- const { runAgentRuntimeDoctorCommand } = await import("./agentMachineCommands-ICOLSVID.js");
244
+ const { runAgentRuntimeDoctorCommand } = await import("./agentMachineCommands-LJ36TKS6.js");
245
245
  return runAgentRuntimeDoctorCommand(args2, deps);
246
246
  }),
247
247
  createAgentRunCommand(["agent", "chat"], "Chat with an agent")
@@ -426,15 +426,15 @@ function getSystemInternalCommandEntries(renderHelpText2) {
426
426
  return runWhoamiCommand({ args: args2, env: ctx.env });
427
427
  }),
428
428
  createEntrypointEnvCommand(["connect"], "Send machine heartbeats or hold a connector websocket", async (args2, deps) => {
429
- const { runMachineConnectCommand } = await import("./machineCommands-X7YMGFMB.js");
429
+ const { runMachineConnectCommand } = await import("./machineCommands-KYKZPZ4Q.js");
430
430
  return runMachineConnectCommand(args2, deps);
431
431
  }),
432
432
  createDaemonShortcutCommand(["daemon"], "Run the connector daemon shortcut", async (args2, deps) => {
433
- const { runMachineConnectCommand } = await import("./machineCommands-X7YMGFMB.js");
433
+ const { runMachineConnectCommand } = await import("./machineCommands-KYKZPZ4Q.js");
434
434
  return runMachineConnectCommand(args2, deps);
435
435
  }),
436
436
  createEnvCommand(["machine", "status"], "List machines registered to the current profile", async (args2, deps) => {
437
- const { runMachineStatusCommand } = await import("./machineCommands-X7YMGFMB.js");
437
+ const { runMachineStatusCommand } = await import("./machineCommands-KYKZPZ4Q.js");
438
438
  return runMachineStatusCommand(args2, deps);
439
439
  }),
440
440
  createEnvCommand(["doctor", "runtime"], "Diagnose local-first agent runtime selection", async (args2, deps) => {
@@ -824,7 +824,7 @@ async function runScript(script, forwardedArgs, env) {
824
824
  return proc.exited;
825
825
  }
826
826
  async function launchTuiWorkspace(args2) {
827
- const { startTuiWorkspace } = await import("./readlineWorkspace-GEZVQ7IM.js");
827
+ const { startTuiWorkspace } = await import("./readlineWorkspace-D7UQATEL.js");
828
828
  const { createTuiSummaryLlmCaller } = await import("./tuiSummaryLlmCaller-U4EGD2SX.js");
829
829
  return startTuiWorkspace({
830
830
  ...args2,
@@ -2,13 +2,13 @@ import {
2
2
  buildMachinePermissionPromptBlock,
3
3
  handleConnectorRunMessage,
4
4
  resolveMachineRunPermissionPolicy
5
- } from "./chunk-7GRFFW7R.js";
5
+ } from "./chunk-VVZUMVYH.js";
6
6
  import {
7
7
  isConnectorWebSocketAuthError,
8
8
  isConnectorWebSocketRetryableError,
9
9
  resolveConnectorWebSocketTarget
10
10
  } from "./chunk-ALXHV7NK.js";
11
- import "./chunk-33BBDA67.js";
11
+ import "./chunk-BYFBW5FZ.js";
12
12
  import "./chunk-3YVCM5PE.js";
13
13
  import "./chunk-EADNWBAZ.js";
14
14
  import "./chunk-NI2BS6UD.js";
@@ -11,8 +11,8 @@ import {
11
11
  runtimeWorkspacePermissionPolicy,
12
12
  scopePermissionPolicyToRuntimeWorkspace,
13
13
  summarizeAgentConfigForLogs
14
- } from "./chunk-7GRFFW7R.js";
15
- import "./chunk-33BBDA67.js";
14
+ } from "./chunk-VVZUMVYH.js";
15
+ import "./chunk-BYFBW5FZ.js";
16
16
  import "./chunk-3YVCM5PE.js";
17
17
  import "./chunk-EADNWBAZ.js";
18
18
  import "./chunk-NI2BS6UD.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nolo-cli",
3
- "version": "0.49.0-alpha.1",
3
+ "version": "0.51.0-alpha.1",
4
4
  "type": "module",
5
5
  "description": "Agent-first terminal workspace for Nolo",
6
6
  "bin": {
@@ -64,7 +64,7 @@ import {
64
64
  wrapTextToLines,
65
65
  wrapTranscriptLine,
66
66
  wrapTranscriptLineWithLayout
67
- } from "./chunk-VZGLZTG7.js";
67
+ } from "./chunk-RENO4QJU.js";
68
68
  import {
69
69
  listFavoriteAgentIdsAcrossServers,
70
70
  listLocalCachedAgents,
@@ -86,7 +86,7 @@ import {
86
86
  readTimestamp,
87
87
  setCliLocale,
88
88
  t
89
- } from "./chunk-33BBDA67.js";
89
+ } from "./chunk-BYFBW5FZ.js";
90
90
  import "./chunk-3YVCM5PE.js";
91
91
  import "./chunk-EADNWBAZ.js";
92
92
  import "./chunk-NI2BS6UD.js";
@@ -1166,6 +1166,7 @@ function createTurnHistory() {
1166
1166
  turns: [],
1167
1167
  currentRole: null,
1168
1168
  currentContent: "",
1169
+ currentBlocks: [],
1169
1170
  scrollTop: 0,
1170
1171
  followBottom: true
1171
1172
  };
@@ -1176,19 +1177,40 @@ function startTurn(history, role) {
1176
1177
  }
1177
1178
  history.currentRole = role;
1178
1179
  history.currentContent = "";
1180
+ history.currentBlocks = [];
1179
1181
  resetStreamingTurnCache();
1180
1182
  }
1181
1183
  function appendToCurrentTurn(history, chunk) {
1182
1184
  history.currentContent += chunk;
1185
+ appendCurrentBlock(history, "assistant", chunk);
1186
+ }
1187
+ function appendCurrentBlock(history, kind, chunk) {
1188
+ if (!chunk) return;
1189
+ const last = history.currentBlocks.at(-1);
1190
+ if (last?.kind === kind) {
1191
+ last.content = applyTerminalOutputToText(last.content, chunk);
1192
+ } else {
1193
+ history.currentBlocks.push({
1194
+ kind,
1195
+ content: applyTerminalOutputToText("", chunk)
1196
+ });
1197
+ }
1183
1198
  }
1184
1199
  function finalizeCurrentTurn(history) {
1185
1200
  if (history.currentRole !== null) {
1186
1201
  history.turns.push({
1187
1202
  role: history.currentRole,
1188
- content: compactTurnContent(history.currentContent)
1203
+ content: compactTurnContent(history.currentContent),
1204
+ ...history.currentRole === "assistant" && history.currentBlocks.length > 0 ? {
1205
+ blocks: history.currentBlocks.map((block) => ({
1206
+ ...block,
1207
+ content: compactTurnContent(block.content)
1208
+ })).filter((block) => block.content.length > 0)
1209
+ } : {}
1189
1210
  });
1190
1211
  history.currentRole = null;
1191
1212
  history.currentContent = "";
1213
+ history.currentBlocks = [];
1192
1214
  resetStreamingTurnCache();
1193
1215
  trimHistoryToBudget(history);
1194
1216
  }
@@ -1203,17 +1225,20 @@ function appendLocalTurn(history, command, output) {
1203
1225
  trimHistoryToBudget(history);
1204
1226
  resetStreamingTurnCache();
1205
1227
  }
1206
- function applyOutputChunkToCurrentTurn(history, chunk) {
1228
+ function applyOutputChunkToCurrentTurn(history, chunk, kind = "assistant") {
1207
1229
  const next = applyTerminalOutputToText(history.currentContent, chunk);
1208
1230
  if (next === history.currentContent) return false;
1209
1231
  history.currentContent = next;
1232
+ appendCurrentBlock(history, kind, chunk);
1210
1233
  return true;
1211
1234
  }
1212
1235
  function styleAssistantTurn(content, colorEnabled) {
1213
1236
  const highlighted = colorEnabled ? formatAssistantDisplay(content, { trimEdges: false }) : stripAnsi(formatAssistantDisplay(content, { trimEdges: false }));
1214
1237
  const rawLines = highlighted.split("\n");
1215
- const styledLines = rawLines.map((line, idx) => {
1216
- if (idx === 0 && !line.startsWith("[nolo]")) {
1238
+ let anchored = false;
1239
+ const styledLines = rawLines.map((line) => {
1240
+ if (!anchored && line.trim().length > 0 && !line.startsWith("[nolo]")) {
1241
+ anchored = true;
1217
1242
  const anchorPrefix = colorEnabled ? `${themeColorSequence("chrome")}\u25C8\x1B[39m ` : "\u25C8 ";
1218
1243
  return `${anchorPrefix}${line}`;
1219
1244
  }
@@ -1324,9 +1349,11 @@ function layoutTurnRows(role, content, contentWidth, colorEnabled, command) {
1324
1349
  let rawIdx = 0;
1325
1350
  let rawOffset = 0;
1326
1351
  const rows = [];
1352
+ let anchored = false;
1327
1353
  for (let i = 0; i < styledLines.length; i++) {
1328
1354
  const styledLine = styledLines[i];
1329
- const isFirstLine = i === 0 && !styledLine.startsWith("[nolo]");
1355
+ const isFirstLine = !anchored && styledLine.trim().length > 0 && !styledLine.startsWith("[nolo]");
1356
+ if (isFirstLine) anchored = true;
1330
1357
  const anchorPrefix = isFirstLine ? colorEnabled ? `${themeColorSequence("chrome")}\u25C8\x1B[39m ` : "\u25C8 " : "";
1331
1358
  const prefixWidth = isFirstLine ? 2 : 0;
1332
1359
  const prefixCharCount = anchorPrefix.length;
@@ -1387,15 +1414,7 @@ function renderPrefixTurnBlock(role, content, contentWidth, colorEnabled) {
1387
1414
  if (role === "user") {
1388
1415
  return renderTurnBlock(role, content, contentWidth, colorEnabled);
1389
1416
  }
1390
- const highlighted = colorEnabled ? formatAssistantDisplay(content, { trimEdges: false }) : stripAnsi(formatAssistantDisplay(content, { trimEdges: false }));
1391
- const rawLines = highlighted.split("\n");
1392
- const styledLines = rawLines.map((line, idx) => {
1393
- if (idx === 0 && !line.startsWith("[nolo]")) {
1394
- const anchorPrefix = colorEnabled ? `${themeColorSequence("chrome")}\u25C8\x1B[39m ` : "\u25C8 ";
1395
- return `${anchorPrefix}${line}`;
1396
- }
1397
- return line.startsWith("[nolo]") && colorEnabled ? themeText(line, "chrome", true) : line;
1398
- });
1417
+ const styledLines = styleAssistantTurn(content, colorEnabled).split("\n");
1399
1418
  const lines = [];
1400
1419
  for (const logicalLine of styledLines) {
1401
1420
  lines.push(...wrapTranscriptLine(logicalLine, contentWidth));
@@ -1728,16 +1747,23 @@ function renderHistory(output, history, inputLines, selection) {
1728
1747
  }
1729
1748
  }
1730
1749
  function createHistoryOutputStream(history, onUpdate) {
1731
- return {
1750
+ const stream = {
1732
1751
  isTTY: true,
1752
+ assistantLabelManaged: true,
1733
1753
  write(chunk) {
1734
1754
  const text = typeof chunk === "string" ? chunk : chunk.toString();
1735
1755
  if (applyOutputChunkToCurrentTurn(history, text)) {
1736
1756
  onUpdate();
1737
1757
  }
1738
1758
  return true;
1759
+ },
1760
+ writeToolBlock(chunk) {
1761
+ if (applyOutputChunkToCurrentTurn(history, chunk, "tool")) {
1762
+ onUpdate();
1763
+ }
1739
1764
  }
1740
1765
  };
1766
+ return stream;
1741
1767
  }
1742
1768
  function applyScrollAction(history, action, output, inputLines) {
1743
1769
  const tty = output;
@@ -1830,6 +1856,10 @@ function activeInFlight(snapshot) {
1830
1856
  if (isAgentRunTerminalStatus(snapshot.status)) return null;
1831
1857
  return snapshot.inFlight ?? null;
1832
1858
  }
1859
+ function formatTerminalRunAge(snapshot, now) {
1860
+ if (!isAgentRunTerminalStatus(snapshot.status)) return null;
1861
+ return formatRunAge(snapshot, now);
1862
+ }
1833
1863
  function formatUnassignedFact(snapshot) {
1834
1864
  return snapshot.unassigned ? "parent: ?" : null;
1835
1865
  }
@@ -1868,7 +1898,7 @@ function formatAgentRunPanelLines(snapshot, colorEnabled, now = Date.now()) {
1868
1898
  const unassignedFact = formatUnassignedFact(snapshot);
1869
1899
  const unassignedPart = unassignedFact ? ` \xB7 ${unassignedFact}` : "";
1870
1900
  const progressPart = formatPanelProgress(snapshot, now);
1871
- const age = formatRunAge(snapshot, now);
1901
+ const age = formatTerminalRunAge(snapshot, now);
1872
1902
  const agePart = age ? ` \xB7 ${age}` : "";
1873
1903
  if (!colorEnabled) {
1874
1904
  lines.push(
@@ -2070,7 +2100,7 @@ function formatRunDockRow(snapshot, colorEnabled, now) {
2070
2100
  const terminal = isAgentRunTerminalStatus(snapshot.status);
2071
2101
  const statusColor = runStatusTone(snapshot.status);
2072
2102
  const facts = [];
2073
- const age = formatRunAge(snapshot, now);
2103
+ const age = formatTerminalRunAge(snapshot, now);
2074
2104
  if (terminal) facts.push(age ? `${snapshot.status} ${age}` : snapshot.status);
2075
2105
  else if (age) facts.push(age);
2076
2106
  const unassigned = formatUnassignedFact(snapshot);
@@ -2241,25 +2271,6 @@ var RUN_POLL_INTERVAL_MS = 1e3;
2241
2271
  var DISCOVERY_EVERY_TICKS = 5;
2242
2272
  var DISCOVERY_TERMINAL_LINGER_MS = 6e4;
2243
2273
  var RUN_RECONCILE_SILENCE_MS = 15e3;
2244
- var RUNNING_AGENT_COUNT_CACHE_TTL_MS = 1e3;
2245
- var cachedRunningAgentCount = 0;
2246
- var lastRunningAgentCountScannedAt = 0;
2247
- function getCachedRunningAgentCount(options) {
2248
- const now = options?.now ?? Date.now();
2249
- if (!options?.force && lastRunningAgentCountScannedAt > 0 && now - lastRunningAgentCountScannedAt < RUNNING_AGENT_COUNT_CACHE_TTL_MS) {
2250
- return cachedRunningAgentCount;
2251
- }
2252
- const readFn = options?.reader ?? listRunRecords;
2253
- try {
2254
- const records = readFn();
2255
- cachedRunningAgentCount = records.filter(
2256
- (r) => !isAgentRunTerminalStatus(r.status)
2257
- ).length;
2258
- lastRunningAgentCountScannedAt = now;
2259
- } catch {
2260
- }
2261
- return cachedRunningAgentCount;
2262
- }
2263
2274
  function snapshotFromRunRecord(record, now) {
2264
2275
  const label = resolveRunLabel(record);
2265
2276
  const startedAt = readTimestamp(record.startedAt);
@@ -2343,18 +2354,18 @@ function createRunRegistryPoller(deps) {
2343
2354
  }
2344
2355
  const discovered = discoveredRecords;
2345
2356
  const currentDialogId = deps.getCurrentDialogId?.();
2357
+ const belongsToCurrentDialog = (record) => !deps.getCurrentDialogId || currentDialogId !== null && record.parentDialogId === currentDialogId;
2346
2358
  const discoveredActive = discovered.filter(
2347
- (record) => record.runId && !dockedIds.has(record.runId) && !retiredRunIds.has(record.runId) && !isAgentRunTerminalStatus(record.status) && (!deps.getCurrentDialogId || currentDialogId !== void 0 && (record.parentDialogId === currentDialogId || !record.parentDialogId))
2359
+ (record) => record.runId && !dockedIds.has(record.runId) && !retiredRunIds.has(record.runId) && !isAgentRunTerminalStatus(record.status) && belongsToCurrentDialog(record)
2348
2360
  );
2349
2361
  const discoveredTerminal = discovered.filter((record) => {
2350
2362
  if (!record.runId || dockedIds.has(record.runId) || retiredRunIds.has(record.runId)) return false;
2351
- if (!isAgentRunTerminalStatus(record.status)) return false;
2352
- if (deps.getCurrentDialogId && (currentDialogId === void 0 || !(record.parentDialogId === currentDialogId || !record.parentDialogId))) return false;
2363
+ if (!isAgentRunTerminalStatus(record.status) || !belongsToCurrentDialog(record)) return false;
2353
2364
  const endedAt = readTimestamp(record.endedAt);
2354
2365
  return endedAt !== void 0 && at - endedAt <= DISCOVERY_TERMINAL_LINGER_MS;
2355
2366
  });
2356
2367
  for (const record of discovered) {
2357
- if (record.runId && isAgentRunTerminalStatus(record.status) && !discoveredTerminal.includes(record)) {
2368
+ if (record.runId && isAgentRunTerminalStatus(record.status) && belongsToCurrentDialog(record) && !discoveredTerminal.includes(record)) {
2358
2369
  retiredRunIds.add(record.runId);
2359
2370
  }
2360
2371
  }
@@ -2378,6 +2389,7 @@ function createRunRegistryPoller(deps) {
2378
2389
  continue;
2379
2390
  }
2380
2391
  if (!record) continue;
2392
+ if (deps.getCurrentDialogId && !belongsToCurrentDialog(record)) continue;
2381
2393
  polled.push(record);
2382
2394
  const snapshot = snapshotFromRunRecord(record, at);
2383
2395
  const mark = fingerprint(snapshot);
@@ -3623,7 +3635,7 @@ function renderComposerTokenChip(tokens, fallbackContextWindow, estimatedContext
3623
3635
  const pctText = pct > 0 && pct < 10 ? pct.toFixed(1) : Math.round(pct).toString();
3624
3636
  return `context: ${pctText}% (${formatTokenCount(used)}/${formatTokenCount(cw)})`;
3625
3637
  }
3626
- function renderStatusLine(state) {
3638
+ function renderStatusLine(state, maxWidth) {
3627
3639
  const colorEnabled = resolveCliColorEnabled();
3628
3640
  const sep = themeText(" \xB7 ", "chrome", colorEnabled);
3629
3641
  const agentDisplayName = state.agentName;
@@ -3652,25 +3664,65 @@ function renderStatusLine(state) {
3652
3664
  );
3653
3665
  parts.push(tokenSegment);
3654
3666
  const runningTaskCount = getProcessRegistry().listBackground().filter((p) => p.status === "running").length;
3655
- const runningAgentCount = getCachedRunningAgentCount();
3656
- const runningParts = [];
3657
3667
  if (runningTaskCount > 0) {
3658
- runningParts.push(`${runningTaskCount} running`);
3659
- }
3660
- if (runningAgentCount > 0) {
3661
- runningParts.push(`${runningAgentCount} ${runningAgentCount === 1 ? "agent" : "agents"}`);
3662
- }
3663
- if (runningParts.length > 0) {
3664
- parts.push(themeText(`\u2699 ${runningParts.join(" \xB7 ")}`, "info", colorEnabled));
3668
+ parts.push(themeText(`\u2699 ${runningTaskCount} running`, "info", colorEnabled));
3665
3669
  }
3666
3670
  if (state.autoConfirm === true) {
3667
3671
  parts.push(themeText("\u23F5 auto", "warning", colorEnabled));
3668
3672
  }
3669
- const body = parts.join(sep);
3673
+ let visibleParts = parts;
3674
+ if (maxWidth && maxWidth > 0) {
3675
+ const widthOf = (segments) => displayWidth(stripAnsi(segments.join(" \xB7 "))) + 2;
3676
+ for (const optional of [tokenSegment, cwdSegment, agentSegment]) {
3677
+ if (widthOf(visibleParts) <= maxWidth) break;
3678
+ visibleParts = visibleParts.filter((part) => part !== optional);
3679
+ }
3680
+ if (widthOf(visibleParts) > maxWidth && state.gitStatus) {
3681
+ const gitIndex = visibleParts.findIndex((part) => stripAnsi(part).startsWith("\u2442 "));
3682
+ if (gitIndex >= 0) {
3683
+ const { modified, untracked } = state.gitStatus;
3684
+ const compactDirty = themeText(
3685
+ `\u2442${modified > 0 ? ` *${modified}` : ""}${untracked > 0 ? ` ?${untracked}` : ""}`,
3686
+ "warning",
3687
+ colorEnabled
3688
+ );
3689
+ visibleParts = visibleParts.with(gitIndex, compactDirty);
3690
+ }
3691
+ }
3692
+ if (widthOf(visibleParts) > maxWidth) {
3693
+ const emergency = [];
3694
+ if (state.autoConfirm === true) {
3695
+ emergency.push(themeText("\u23F5", "warning", colorEnabled));
3696
+ }
3697
+ const runningTotal = runningTaskCount + runningAgentCount;
3698
+ if (runningTotal > 0) {
3699
+ emergency.push(themeText(`\u2699${runningTotal}`, "info", colorEnabled));
3700
+ }
3701
+ if (state.gitStatus) {
3702
+ const { modified, untracked } = state.gitStatus;
3703
+ emergency.push(themeText(
3704
+ `\u2442${modified > 0 ? `*${modified}` : ""}${untracked > 0 ? `?${untracked}` : ""}`,
3705
+ "warning",
3706
+ colorEnabled
3707
+ ));
3708
+ }
3709
+ visibleParts = [emergency.join(" ")];
3710
+ }
3711
+ }
3712
+ const body = visibleParts.join(sep);
3670
3713
  const surface = colorEnabled ? surfaceBackgroundSequence() : "";
3671
3714
  if (!surface) return body;
3672
3715
  return `${surface} ${body} \x1B[49m`;
3673
3716
  }
3717
+ function composeStatusLineWithQueue(state, queueSuffix, maxWidth) {
3718
+ const hasBudget = typeof maxWidth === "number" && maxWidth > 0;
3719
+ const queueWidth = queueSuffix ? visibleWidth(queueSuffix) : 0;
3720
+ const budget = hasBudget ? Math.max(1, maxWidth - queueWidth) : void 0;
3721
+ const base = renderStatusLine(state, budget);
3722
+ if (!queueSuffix) return base;
3723
+ if (!hasBudget) return base + queueSuffix;
3724
+ return visibleWidth(base) + queueWidth <= maxWidth ? base + queueSuffix : base;
3725
+ }
3674
3726
  function buildPlainScene(isDark, frame = 0, maxFrames = 0) {
3675
3727
  let skyLine = ` ${isDark ? "\u{1F319}" : "\u2600"}`;
3676
3728
  if (isDark) {
@@ -4328,7 +4380,7 @@ function createInitialTuiState(env = process.env) {
4328
4380
  modeLabel: asOptionalTrimmedString(env.NOLO_CLI_STATUS_MODE) ?? runtimeMode,
4329
4381
  userLanguage: asOptionalTrimmedString(env.NOLO_LANG),
4330
4382
  gitStatus: void 0,
4331
- toolDisplay: normalizeToolDisplayMode(env.NOLO_CLI_TOOLS ?? env.NOLO_TOOLS, "compact"),
4383
+ toolDisplay: normalizeToolDisplayMode(env.NOLO_CLI_TOOLS ?? env.NOLO_TOOLS, "normal"),
4332
4384
  thinkingDisplay: "show",
4333
4385
  contextWindow: resolveAgentContextWindow({ agentKey, agentName }),
4334
4386
  estimatedContextTokens: estimateDefaultCliContextTokens({
@@ -4498,7 +4550,7 @@ function handleTuiInput(input, state) {
4498
4550
  };
4499
4551
  }
4500
4552
  const normalizedArg = asTrimmedLowercaseString(argText);
4501
- if (!["hide", "compact", "verbose", "on", "off"].includes(normalizedArg)) {
4553
+ if (!["normal", "pro", "hide", "compact", "verbose", "on", "off"].includes(normalizedArg)) {
4502
4554
  return {
4503
4555
  nextState: state,
4504
4556
  output: t("toolsUsage")
@@ -6942,7 +6994,7 @@ function createFixedInput(output, config) {
6942
6994
  if (titleLine) {
6943
6995
  sections.push(fitAnsiLine(titleLine.replace(/\r?\n/g, " "), cols));
6944
6996
  }
6945
- sections.push(fitAnsiLine(config.getStatusLine(), cols));
6997
+ sections.push(fitAnsiLine(config.getStatusLine(cols), cols));
6946
6998
  const queueLines = config.getQueueLines?.() ?? [];
6947
6999
  for (const line of queueLines) {
6948
7000
  sections.push(fitAnsiLine(line.replace(/\r?\n/g, " "), cols));
@@ -8036,7 +8088,7 @@ async function runTuiWorkspace(options) {
8036
8088
  // 与 reconcile 的调用点也是同样写法。
8037
8089
  readRecord: (runId) => readRunRecord(runId, { env: effectiveEnv }),
8038
8090
  discoverRuns: () => listRunRecords({ env: effectiveEnv }),
8039
- getCurrentDialogId: () => state.dialogId,
8091
+ getCurrentDialogId: () => state.dialogId ?? null,
8040
8092
  reconcile: (runId) => checkStaleRun(runId, { env: effectiveEnv }),
8041
8093
  onRecordsPolled: (records) => runCompletionWatcher.observe(records)
8042
8094
  });
@@ -8303,15 +8355,12 @@ async function runTuiWorkspace(options) {
8303
8355
  let done = false;
8304
8356
  let resolveDone = null;
8305
8357
  const baseFixedInput = createFixedInput(output, {
8306
- getStatusLine: () => {
8307
- let base = renderStatusLine(state);
8308
- if (chatQueueBinding && chatQueueBinding.queueLength() > 0) {
8309
- base += dimCliText(
8310
- ` \xB7 ${chatQueueBinding.queueLength()} ${t("queuedHint")}`,
8311
- resolveCliColorEnabled()
8312
- );
8313
- }
8314
- return base;
8358
+ getStatusLine: (maxWidth) => {
8359
+ const queueSuffix = chatQueueBinding && chatQueueBinding.queueLength() > 0 ? dimCliText(
8360
+ ` \xB7 ${chatQueueBinding.queueLength()} ${t("queuedHint")}`,
8361
+ resolveCliColorEnabled()
8362
+ ) : "";
8363
+ return composeStatusLineWithQueue(state, queueSuffix, maxWidth);
8315
8364
  },
8316
8365
  getActivityLines: () => activityIndicator.getActivityLines(resolveCliColorEnabled()),
8317
8366
  getQueueLines: () => {