nolo-cli 0.109.0-alpha.2 → 0.110.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,7 +8,7 @@ import {
8
8
  resolveRunSettlementNote,
9
9
  resolveWorkflowReference,
10
10
  runAgentRunCommand
11
- } from "./chunk-DNAF7JC6.js";
11
+ } from "./chunk-2KNZCY53.js";
12
12
  import "./chunk-S7Z2HMCN.js";
13
13
  import {
14
14
  parseAgentRunArgs
@@ -9834,6 +9834,7 @@ ${this.text}
9834
9834
  // packages/cli/client/agentRunOutput.ts
9835
9835
  var IDENTITY_LABEL_SEPARATOR = " > ";
9836
9836
  var THINKING_PREVIEW_BUFFER_LIMIT = 512;
9837
+ var TUI_PROGRESS_BUFFER_LIMIT = 320;
9837
9838
  function appendThinkingPreview(current, chunk, limit = THINKING_PREVIEW_BUFFER_LIMIT) {
9838
9839
  if (limit <= 0) return "";
9839
9840
  const combined = current + chunk;
@@ -9895,6 +9896,15 @@ function formatToolJsonEvent(event) {
9895
9896
  })}
9896
9897
  `;
9897
9898
  }
9899
+ function shouldPromoteTuiNarration(text) {
9900
+ if (text.length >= TUI_PROGRESS_BUFFER_LIMIT) return true;
9901
+ if (/\n\s*\n/.test(text)) return true;
9902
+ return /(^|\n)\s*(?:#{1,3}\s|```|[-*+]\s|\d+[.)]\s)/.test(text);
9903
+ }
9904
+ function narrationActivityLabel(text) {
9905
+ const oneLine = stripAnsi2(text).replace(/[`*_#>]/g, "").replace(/\s+/g, " ").trim();
9906
+ return truncateThinkingHint(oneLine, 60);
9907
+ }
9898
9908
  function createCliTurnOutput(params) {
9899
9909
  const { options } = params;
9900
9910
  const workingLabel = params.workingLabel ?? `${options.agentName} -> working`;
@@ -9903,7 +9913,8 @@ function createCliTurnOutput(params) {
9903
9913
  tuiTrees: options.output.tuiTrees === true
9904
9914
  });
9905
9915
  const eventMode = resolveAgentEventMode(options);
9906
- const showThinking = options.showThinking !== false;
9916
+ const assistantLabelManaged = options.output.assistantLabelManaged === true;
9917
+ const showThinking = !assistantLabelManaged && options.showThinking !== false;
9907
9918
  let streamedAssistantText = false;
9908
9919
  let everStreamedAnyText = false;
9909
9920
  let printedAssistantLabel = false;
@@ -9940,7 +9951,6 @@ function createCliTurnOutput(params) {
9940
9951
  }
9941
9952
  };
9942
9953
  let compactionEvent = null;
9943
- const assistantLabelManaged = options.output.assistantLabelManaged === true;
9944
9954
  const writeToolOutput = (chunk) => {
9945
9955
  if (!chunk) return;
9946
9956
  if (typeof options.output.writeToolBlock === "function") {
@@ -9952,9 +9962,25 @@ function createCliTurnOutput(params) {
9952
9962
  const renderWriter = createRenderAwareStreamWriter({
9953
9963
  write: (chunk) => options.output.write(chunk)
9954
9964
  });
9965
+ let pendingTuiNarration = "";
9966
+ let tuiNarrationPromoted = false;
9967
+ const flushPendingTuiNarration = () => {
9968
+ if (!pendingTuiNarration) return;
9969
+ formatToolEvent.reset?.();
9970
+ renderWriter.push(pendingTuiNarration);
9971
+ pendingTuiNarration = "";
9972
+ tuiNarrationPromoted = true;
9973
+ streamedAssistantText = true;
9974
+ options.activityReporter?.(null);
9975
+ };
9976
+ const dropPendingTuiProgress = () => {
9977
+ pendingTuiNarration = "";
9978
+ tuiNarrationPromoted = false;
9979
+ options.activityReporter?.(null);
9980
+ };
9955
9981
  const writeVisibleAssistantChunk = (chunk) => {
9956
9982
  if (!chunk) return;
9957
- formatToolEvent.reset?.();
9983
+ if (!assistantLabelManaged) formatToolEvent.reset?.();
9958
9984
  const parsed = processThinkChunk(chunk, thinkState);
9959
9985
  thinkState = parsed.state;
9960
9986
  if (!parsed.content && !parsed.reasoning) return;
@@ -9970,8 +9996,23 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
9970
9996
  }
9971
9997
  printedAssistantLabel = true;
9972
9998
  }
9973
- streamedAssistantText = true;
9974
9999
  everStreamedAnyText = true;
10000
+ if (assistantLabelManaged) {
10001
+ if (tuiNarrationPromoted) {
10002
+ renderWriter.push(parsed.content);
10003
+ streamedAssistantText = true;
10004
+ return;
10005
+ }
10006
+ pendingTuiNarration += parsed.content;
10007
+ if (shouldPromoteTuiNarration(pendingTuiNarration)) {
10008
+ flushPendingTuiNarration();
10009
+ } else {
10010
+ const label = narrationActivityLabel(pendingTuiNarration);
10011
+ if (label) options.activityReporter?.(label);
10012
+ }
10013
+ return;
10014
+ }
10015
+ streamedAssistantText = true;
9975
10016
  renderWriter.push(parsed.content);
9976
10017
  };
9977
10018
  const handleToolEvent = (event) => {
@@ -9987,6 +10028,9 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
9987
10028
  return;
9988
10029
  }
9989
10030
  if (event.type === "tool-call") {
10031
+ if (assistantLabelManaged && pendingTuiNarration) {
10032
+ dropPendingTuiProgress();
10033
+ }
9990
10034
  renderWriter.flush();
9991
10035
  formatToolEvent(event);
9992
10036
  endThinkingPhase();
@@ -9994,6 +10038,7 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
9994
10038
  options.output.write("\n");
9995
10039
  streamedAssistantText = false;
9996
10040
  }
10041
+ if (assistantLabelManaged) tuiNarrationPromoted = false;
9997
10042
  const activeLabel = formatConservativeActiveToolLabel(event);
9998
10043
  spinner.show(activeLabel);
9999
10044
  options.activityReporter?.(activeLabel);
@@ -10017,6 +10062,26 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
10017
10062
  return {
10018
10063
  spinner,
10019
10064
  eventMode,
10065
+ /**
10066
+ * Terminal cleanup for abort/error paths that never reach `finish()`.
10067
+ *
10068
+ * A user abort discards the transient TUI progress buffer: the user stopped
10069
+ * on purpose and the dock already showed that text as activity. A genuine
10070
+ * failure must not swallow prose that never got the chance to be *proven*
10071
+ * durable (only a following tool call proves "progress"), so it promotes the
10072
+ * pending buffer and flushes what was already promoted — otherwise a short
10073
+ * final answer followed by a transport error disappears from the transcript.
10074
+ */
10075
+ cancel(cleanup) {
10076
+ if (assistantLabelManaged && cleanup?.preservePendingNarration) {
10077
+ flushPendingTuiNarration();
10078
+ if (streamedAssistantText) {
10079
+ renderWriter.flush();
10080
+ options.output.write("\n");
10081
+ }
10082
+ }
10083
+ dropPendingTuiProgress();
10084
+ },
10020
10085
  pushText(chunk) {
10021
10086
  writeVisibleAssistantChunk(chunk);
10022
10087
  },
@@ -10024,10 +10089,6 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
10024
10089
  markThinkingDelta(chunk);
10025
10090
  },
10026
10091
  handleToolEvent,
10027
- /** 记录一条 compaction 观测事件(TUI 在 turn 结束时渲染一行 dim 摘要)。
10028
- * 一轮内可能来多条(轮开始 + 每个 round),按显著性保留最高者:
10029
- * 失败 > 新生成摘要 > 投影复用 > 跳过,避免末尾的例行跳过事件
10030
- * 覆盖掉中途真正发生的压缩。 */
10031
10092
  recordCompaction(event) {
10032
10093
  const significance = (e) => e.failed ? 4 : e.summaryGenerated ? 3 : e.compressed ? 2 : 1;
10033
10094
  if (!compactionEvent || significance(event) >= significance(compactionEvent)) {
@@ -10045,6 +10106,7 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
10045
10106
  if (flushedThink.content) {
10046
10107
  writeVisibleAssistantChunk(flushedThink.content);
10047
10108
  }
10109
+ if (assistantLabelManaged) flushPendingTuiNarration();
10048
10110
  endThinkingPhase();
10049
10111
  spinner.stop();
10050
10112
  options.activityReporter?.(null);
@@ -10149,6 +10211,7 @@ async function readStreamingAgentRun(options, res, existingSpinner) {
10149
10211
  let content = "";
10150
10212
  let dialogId;
10151
10213
  let usage;
10214
+ let sawDone = false;
10152
10215
  const handlePayload = (payload) => {
10153
10216
  if (typeof payload?.dialogId === "string" && payload.dialogId.trim()) {
10154
10217
  dialogId = payload.dialogId;
@@ -10161,6 +10224,7 @@ async function readStreamingAgentRun(options, res, existingSpinner) {
10161
10224
  }
10162
10225
  if (payload?.type === "done") {
10163
10226
  usage = payload.usage;
10227
+ sawDone = true;
10164
10228
  return;
10165
10229
  }
10166
10230
  if (payload?.type === "dialog" || payload?.type === "status") {
@@ -10214,6 +10278,9 @@ async function readStreamingAgentRun(options, res, existingSpinner) {
10214
10278
  }
10215
10279
  } catch (error) {
10216
10280
  turnOutput.spinner.stop();
10281
+ turnOutput.cancel({
10282
+ preservePendingNarration: !options.abortSignal?.aborted
10283
+ });
10217
10284
  if (options.abortSignal?.aborted) {
10218
10285
  return {
10219
10286
  exitCode: 0,
@@ -10243,6 +10310,15 @@ ${describeClientVersionTooOldFailure(message, error)}`);
10243
10310
  `);
10244
10311
  return { exitCode: 1 };
10245
10312
  }
10313
+ if (options.abortSignal?.aborted && !sawDone) {
10314
+ turnOutput.spinner.stop();
10315
+ turnOutput.cancel();
10316
+ return {
10317
+ exitCode: 0,
10318
+ ...dialogId ? { dialogId } : {},
10319
+ streamInterrupted: true
10320
+ };
10321
+ }
10246
10322
  turnOutput.finish(content);
10247
10323
  const usageText = formatUsage(usage, dialogId);
10248
10324
  if (usageText && shouldShowUsage(options.env))
@@ -11286,6 +11362,9 @@ async function runLocalAgentTurnForCli(options, settings) {
11286
11362
  };
11287
11363
  } catch (error) {
11288
11364
  turnOutput.spinner.stop();
11365
+ turnOutput.cancel({
11366
+ preservePendingNarration: error?.code !== LOCAL_TURN_ABORTED_CODE && !options.abortSignal?.aborted
11367
+ });
11289
11368
  const savedDialogId = error?.dialogId;
11290
11369
  const abortedUsageRecords = error?.usageRecords;
11291
11370
  const abortedTurnCredits = sumPlatformCredits(abortedUsageRecords);
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-GMSUBYF6.js");
130
+ const { runAgentRunCommand } = await import("./agentRunCommand-WE72RU4J.js");
131
131
  return runAgentRunCommand(args2, {
132
132
  env: ctx.env,
133
133
  scriptDir: ctx.scriptDir,
@@ -892,7 +892,7 @@ async function runScript(script, forwardedArgs, env) {
892
892
  return proc.exited;
893
893
  }
894
894
  async function launchTuiWorkspace(args2) {
895
- const { startTuiWorkspace } = await import("./readlineWorkspace-2G3MDALM.js");
895
+ const { startTuiWorkspace } = await import("./readlineWorkspace-5GEDEDMU.js");
896
896
  const { createTuiSummaryLlmCaller } = await import("./tuiSummaryLlmCaller-UFGFOIIW.js");
897
897
  return startTuiWorkspace({
898
898
  ...args2,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nolo-cli",
3
- "version": "0.109.0-alpha.2",
3
+ "version": "0.110.0-alpha.1",
4
4
  "type": "module",
5
5
  "description": "Agent-first terminal workspace for Nolo",
6
6
  "bin": {
@@ -72,7 +72,7 @@ import {
72
72
  wrapTextToLines,
73
73
  wrapTranscriptLine,
74
74
  wrapTranscriptLineWithLayout
75
- } from "./chunk-DNAF7JC6.js";
75
+ } from "./chunk-2KNZCY53.js";
76
76
  import "./chunk-S7Z2HMCN.js";
77
77
  import "./chunk-V7E4PXQD.js";
78
78
  import "./chunk-ESHYE7WU.js";
@@ -3028,11 +3028,23 @@ function formatPanelDetail(snapshot) {
3028
3028
  if (!lines || lines.length === 0) return "";
3029
3029
  return lines[lines.length - 1]?.trim() ?? "";
3030
3030
  }
3031
+ var AUTO_IDENTITY_PATTERNS = [
3032
+ /^agent-[0-9a-f]{8,}-[a-z0-9]/i,
3033
+ /^agent-pub-[a-z0-9]{10,}$/i,
3034
+ /^run-\d{4}-\d{2}-\d{2}T[\d-]+Z-[a-z0-9]+$/i
3035
+ ];
3036
+ function isAutoGeneratedIdentity(raw) {
3037
+ return AUTO_IDENTITY_PATTERNS.some((pattern) => pattern.test(raw));
3038
+ }
3039
+ function displayAgentName(snapshot) {
3040
+ const raw = snapshot.agentName?.trim();
3041
+ if (!raw) return "Sub-agent";
3042
+ if (isAutoGeneratedIdentity(raw)) return "Sub-agent";
3043
+ return raw;
3044
+ }
3031
3045
  function formatAgentRunPanelLines(snapshot, colorEnabled, now = Date.now()) {
3032
3046
  const lines = [];
3033
- const name = snapshot.agentName || "sub-agent";
3034
- const short = shortRunId(snapshot.runId);
3035
- const runId = short ? ` (${short})` : "";
3047
+ const name = displayAgentName(snapshot);
3036
3048
  const status = snapshot.status || "running";
3037
3049
  const statusSymbol = getAgentRunStatusIcon(status);
3038
3050
  const statusColor = runStatusTone(status);
@@ -3045,19 +3057,18 @@ function formatAgentRunPanelLines(snapshot, colorEnabled, now = Date.now()) {
3045
3057
  const creditsPart = typeof snapshot.credits === "number" && Number.isFinite(snapshot.credits) ? ` \xB7 ${formatCreditsChip(snapshot.credits)}` : "";
3046
3058
  if (!colorEnabled) {
3047
3059
  lines.push(
3048
- `\u{1F916} Sub-Agent: ${name}${runId} \xB7 ${statusSymbol} ${status}${unassignedPart}${agePart}${progressPart}${creditsPart}${errPart}`
3060
+ `\u{1F916} ${name} \xB7 ${statusSymbol} ${status}${unassignedPart}${agePart}${progressPart}${creditsPart}${errPart}`
3049
3061
  );
3050
3062
  } else {
3051
3063
  const botIcon = themeText("\u{1F916}", "accent", true);
3052
- const labelText = themeText(" Sub-Agent: ", "muted", true);
3053
- const nameText = themeText(`${name}${runId}`, "chrome", true);
3064
+ const nameText = themeText(` ${name}`, "chrome", true);
3054
3065
  const statusText = themeText(` \xB7 ${statusSymbol} ${status}`, statusColor, true);
3055
3066
  const unassignedText = unassignedPart ? themeText(unassignedPart, "muted") : "";
3056
3067
  const ageText = agePart ? themeText(agePart, "chrome") : "";
3057
3068
  const progressText = progressPart ? themeText(progressPart, "chrome") : "";
3058
3069
  const creditsText = creditsPart ? themeText(creditsPart, "muted") : "";
3059
3070
  const errorText = errPart ? themeText(errPart, "danger") : "";
3060
- lines.push(`${botIcon}${labelText}${nameText}${statusText}${unassignedText}${ageText}${progressText}${creditsText}${errorText}`);
3071
+ lines.push(`${botIcon}${nameText}${statusText}${unassignedText}${ageText}${progressText}${creditsText}${errorText}`);
3061
3072
  }
3062
3073
  const detail = formatPanelDetail(snapshot);
3063
3074
  if (detail) {
@@ -3239,7 +3250,7 @@ function formatRunDockLines(snapshots, colorEnabled, now = Date.now(), maxRows =
3239
3250
  return lines;
3240
3251
  }
3241
3252
  function formatRunDockRow(snapshot, colorEnabled, now) {
3242
- const name = snapshot.agentName || "sub-agent";
3253
+ const name = displayAgentName(snapshot);
3243
3254
  const short = shortRunId(snapshot.runId);
3244
3255
  const icon = getAgentRunStatusIcon(snapshot.status);
3245
3256
  const terminal = isAgentRunTerminalStatus(snapshot.status);
@@ -6861,7 +6872,7 @@ function formatProcessTerminalWakeMessage(notices) {
6861
6872
  return [
6862
6873
  `<background_task_completion count="${notices.length}">`,
6863
6874
  ...notices.flatMap((notice) => [
6864
- formatProcessTerminalNoticeLine(notice),
6875
+ formatProcessTerminalWakeLine(notice),
6865
6876
  ...notice.resultCapsule ? formatProcessResultCapsuleLines(notice.resultCapsule) : []
6866
6877
  ]),
6867
6878
  `</background_task_completion>`
@@ -6895,12 +6906,21 @@ function formatProcessResultCapsuleLines(capsule) {
6895
6906
  ] : []
6896
6907
  ];
6897
6908
  }
6898
- function formatProcessTerminalNoticeLine(notice) {
6909
+ function formatProcessTerminalWakeLine(notice) {
6899
6910
  const informative = notice.label && notice.label.trim() !== "" && notice.label !== notice.command;
6900
6911
  const label = informative ? ` (label: "${notice.label.replace(/(["\\])/g, "\\$1")}")` : "";
6901
6912
  const exit = notice.exitCode !== void 0 ? ` exitCode=${notice.exitCode}` : "";
6902
6913
  return `[Background task ${notice.taskId}${label} finished: status=${notice.status}${exit}]`;
6903
6914
  }
6915
+ function formatProcessTerminalNoticeLine(notice) {
6916
+ const informative = notice.label && notice.label.trim() !== "" && notice.label !== notice.command;
6917
+ const label = informative ? notice.label.trim() : "background task";
6918
+ const ok = notice.status === "exited" && (notice.exitCode === void 0 || notice.exitCode === 0);
6919
+ if (ok) return `\u2713 ${label}`;
6920
+ if (notice.status === "stopped") return `\u25A0 ${label} \xB7 stopped`;
6921
+ const exit = notice.exitCode !== void 0 ? ` \xB7 exit ${notice.exitCode}` : "";
6922
+ return `\u2717 ${label}${exit}`;
6923
+ }
6904
6924
  function buildProcessTerminalTurnMessage(notices) {
6905
6925
  if (notices.length === 0) return "";
6906
6926
  return formatProcessTerminalWakeMessage(notices);
@@ -6917,7 +6937,7 @@ function buildProcessTaskCompletedTurnEvent(notice) {
6917
6937
  }
6918
6938
  var PENDING_NOTICE_PREFIX = "process-notice-v1:";
6919
6939
  function serializePendingProcessNotice(notice) {
6920
- return notice.resultCapsule ? `${PENDING_NOTICE_PREFIX}${JSON.stringify(notice)}` : formatProcessTerminalNoticeLine(notice);
6940
+ return notice.resultCapsule ? `${PENDING_NOTICE_PREFIX}${JSON.stringify(notice)}` : formatProcessTerminalWakeLine(notice);
6921
6941
  }
6922
6942
  function parsePendingProcessNoticeLine(line) {
6923
6943
  if (line.startsWith(PENDING_NOTICE_PREFIX)) {