@crazyhappyone/dsh-tui 0.1.0-alpha.46 → 0.1.0-alpha.48

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
@@ -28740,6 +28740,71 @@ function exitStatus(code2, signal) {
28740
28740
  return code2 ?? 1;
28741
28741
  }
28742
28742
 
28743
+ // packages/tui/tui/src/session-errors.ts
28744
+ var SESSION_WRITER_HELD_COPY = "\u5F53\u524D\u4F1A\u8BDD\u5DF2\u88AB\u5360\u7528\uFF0C\u53EF\u80FD\u662F\u5176\u4ED6\u6B63\u5728\u8FD0\u884C\u7684 DSH \u5BFC\u81F4\u7684\uFF08\u5982\u5176\u4ED6 dsh web\u3001\u684C\u9762\u7AEF\uFF09\uFF0C\u8BF7\u9000\u51FA\u5176\u4ED6\u6B63\u5728\u8FD0\u884C\u7684 DSH \u540E\u91CD\u8BD5\u3002";
28745
+ var SESSION_CHANGES_DISPOSED_COPY = "\u4F1A\u8BDD\u5DF2\u91CA\u653E\uFF0C\u65E0\u6CD5\u5BF9\u6BD4\u8BE5\u6587\u4EF6";
28746
+ function isRecord(value) {
28747
+ return typeof value === "object" && value !== null;
28748
+ }
28749
+ function isSessionWriterHeld(error51) {
28750
+ if (error51 instanceof AggregateError) {
28751
+ return error51.errors.some(isSessionWriterHeld);
28752
+ }
28753
+ if (!isRecord(error51)) return false;
28754
+ if (error51.name === "SessionAlreadyOwnedError") return true;
28755
+ if (error51.code === "session/writer-held") return true;
28756
+ if (error51.cause !== void 0 && isSessionWriterHeld(error51.cause)) return true;
28757
+ return false;
28758
+ }
28759
+ function userErrorReason(error51) {
28760
+ if (isSessionWriterHeld(error51)) return SESSION_WRITER_HELD_COPY;
28761
+ return error51 instanceof Error ? error51.message : String(error51);
28762
+ }
28763
+
28764
+ // packages/tui/tui/src/workspace-changes.ts
28765
+ function workspaceChangesCardFromSummary(seq, summary) {
28766
+ if (summary === void 0 || summary.files.length === 0) return void 0;
28767
+ return {
28768
+ seq,
28769
+ turn: summary.turn,
28770
+ files: summary.files.map(toFileView),
28771
+ total: summary.total,
28772
+ added: summary.added,
28773
+ deleted: summary.deleted
28774
+ };
28775
+ }
28776
+ function toFileView(file2) {
28777
+ return {
28778
+ path: file2.path,
28779
+ display: file2.display,
28780
+ added: file2.added,
28781
+ deleted: file2.deleted,
28782
+ ...file2.binary === true ? { binary: true } : {},
28783
+ ...file2.oversized === true ? { oversized: true } : {}
28784
+ };
28785
+ }
28786
+ function lookupWorkspaceChange(cards, needle) {
28787
+ for (const card of cards.values()) {
28788
+ const index2 = card.files.findIndex((file2) => file2.path === needle || file2.display === needle);
28789
+ if (index2 >= 0) return { seq: card.seq, index: index2 };
28790
+ }
28791
+ return void 0;
28792
+ }
28793
+ function formatWorkspaceChangeDiffPreview(diff2) {
28794
+ if (diff2 === void 0) return void 0;
28795
+ if (diff2.kind === "binary" || diff2.kind === "oversized") {
28796
+ return [`${diff2.display} \xB7 ${diff2.kind}`];
28797
+ }
28798
+ const lines = [
28799
+ `${diff2.display}${diff2.coarse ? " \xB7 coarse" : ""}`
28800
+ ];
28801
+ for (const hunk of diff2.hunks) {
28802
+ lines.push(`@@ -${String(hunk.oldStart)},${String(hunk.oldLines)} +${String(hunk.newStart)},${String(hunk.newLines)} @@`);
28803
+ lines.push(...hunk.lines);
28804
+ }
28805
+ return lines;
28806
+ }
28807
+
28743
28808
  // packages/tui/tui/src/external-editor.ts
28744
28809
  import {
28745
28810
  chmod,
@@ -30458,8 +30523,9 @@ var LoggerService = class _LoggerService {
30458
30523
  */
30459
30524
  exporter(exporter) {
30460
30525
  return this.ctx.effect(() => {
30461
- this.exporters.set(++this._snExporter, exporter);
30462
- return () => this.exporters.delete(this._snExporter);
30526
+ const id = ++this._snExporter;
30527
+ this.exporters.set(id, exporter);
30528
+ return () => this.exporters.delete(id);
30463
30529
  }, "ctx.logger.exporter()");
30464
30530
  }
30465
30531
  _resolveConfig() {
@@ -32734,7 +32800,8 @@ var LlmRuntime = class extends (_a = TypertRemoteService, _listProviders_dec = [
32734
32800
  id: model.id,
32735
32801
  ...model.name === void 0 ? {} : { name: model.name },
32736
32802
  ...model.contextWindow === void 0 ? {} : { contextWindow: model.contextWindow },
32737
- ...model.maxTokens === void 0 ? {} : { maxTokens: model.maxTokens }
32803
+ ...model.maxTokens === void 0 ? {} : { maxTokens: model.maxTokens },
32804
+ ...model.inputModalities === void 0 ? {} : { inputModalities: [...model.inputModalities] }
32738
32805
  });
32739
32806
  }
32740
32807
  return models;
@@ -33313,7 +33380,8 @@ var KNOWN_SESSION_EVENT_TYPES = /* @__PURE__ */ new Set([
33313
33380
  "turn/end",
33314
33381
  "turn/start",
33315
33382
  "user/message",
33316
- "web/deepseek-search-llm-request"
33383
+ "web/deepseek-search-llm-request",
33384
+ "workspace/changes"
33317
33385
  ]);
33318
33386
  var MESSAGE_PROJECTION_EVENT_TYPES = /* @__PURE__ */ new Set([
33319
33387
  "image/offload"
@@ -33361,30 +33429,30 @@ function deriveEventMessage(event, projectedMessages) {
33361
33429
  return null;
33362
33430
  }
33363
33431
  }
33364
- function isRecord(value) {
33432
+ function isRecord2(value) {
33365
33433
  return typeof value === "object" && value !== null && !Array.isArray(value);
33366
33434
  }
33367
33435
  function validateSessionEventData(event, subject) {
33368
33436
  const data = event.data;
33369
33437
  if (event.type === "request/header") {
33370
- if (!isRecord(data)) throw new Error(`${subject} data must be an object`);
33438
+ if (!isRecord2(data)) throw new Error(`${subject} data must be an object`);
33371
33439
  const header = data["header"];
33372
- if (!isRecord(header)) throw new Error(`${subject} header must be an object`);
33440
+ if (!isRecord2(header)) throw new Error(`${subject} header must be an object`);
33373
33441
  if (Object.hasOwn(header, "system")) throw new Error(`${subject} must omit header.system; use system/message`);
33374
33442
  if (Array.isArray(header["tools"]) && header["tools"].length === 0) {
33375
33443
  throw new Error(`${subject} must omit empty tools`);
33376
33444
  }
33377
33445
  const defaults = header["adapterDefaults"];
33378
- if (isRecord(defaults) && Object.keys(defaults).length === 0) {
33446
+ if (isRecord2(defaults) && Object.keys(defaults).length === 0) {
33379
33447
  throw new Error(`${subject} must omit empty adapterDefaults`);
33380
33448
  }
33381
33449
  } else if (event.type === "tool/result") {
33382
- if (!isRecord(data)) throw new Error(`${subject} data must be an object`);
33450
+ if (!isRecord2(data)) throw new Error(`${subject} data must be an object`);
33383
33451
  if (data["error"] === void 0) return;
33384
33452
  const message = data["message"];
33385
- const content3 = isRecord(message) ? message["content"] : void 0;
33453
+ const content3 = isRecord2(message) ? message["content"] : void 0;
33386
33454
  const block = Array.isArray(content3) ? content3[0] : void 0;
33387
- if (!isRecord(block) || block["isError"] !== true) {
33455
+ if (!isRecord2(block) || block["isError"] !== true) {
33388
33456
  throw new Error(`${subject} error requires message content[0].isError === true`);
33389
33457
  }
33390
33458
  }
@@ -58767,7 +58835,7 @@ function escapeContent(text4) {
58767
58835
  (char) => `\\x${char.charCodeAt(0).toString(16).padStart(2, "0")}`
58768
58836
  ).replace(/\u001B/g, "\\x1b");
58769
58837
  }
58770
- var WIDE_SYMBOLS_OR_EMOJIS = /[\u26A0\u2699\u2139\u23F1\u2328\u2709\u270F\u2712\u2702\u26C8\u2764]/gu;
58838
+ var EMOJI_OR_PICTOGRAPHIC = /\p{Extended_Pictographic}/u;
58771
58839
  function displayWidth(text4) {
58772
58840
  if (text4 === "") return 0;
58773
58841
  let cols = 0;
@@ -58785,16 +58853,15 @@ function displayWidth(text4) {
58785
58853
  }
58786
58854
  if (simple) return cols;
58787
58855
  const base = stringWidth(text4);
58788
- if (!/[\u26A0\u2699\u2139\u23F1\u2328\u2709\u270F\u2712\u2702\u26C8\u2764]/u.test(text4)) {
58856
+ if (!/[\u{1F300}-\u{1FAFF}\u2000-\u2BFF]/u.test(text4)) {
58789
58857
  return base;
58790
58858
  }
58791
58859
  let extra2 = 0;
58792
- for (const match of text4.matchAll(WIDE_SYMBOLS_OR_EMOJIS)) {
58793
- const nextCode = text4.charCodeAt(match.index + 1);
58794
- if (nextCode === 65039 || nextCode === 65038) {
58795
- continue;
58860
+ for (const { segment: segment2 } of GRAPHEME.segment(text4)) {
58861
+ if (segment2.includes("\uFE0E")) continue;
58862
+ if (EMOJI_OR_PICTOGRAPHIC.test(segment2) && stringWidth(segment2) === 1) {
58863
+ extra2 += 1;
58796
58864
  }
58797
- extra2 += 1;
58798
58865
  }
58799
58866
  return base + extra2;
58800
58867
  }
@@ -58849,7 +58916,7 @@ function formatSymbolSpacing(text4) {
58849
58916
  "$1 $2"
58850
58917
  );
58851
58918
  res = res.replace(
58852
- /([\u4E00-\u9FFF\u3400-\u4DBF\u3000-\u303F\uFF01-\uFF60])([\u{1F300}-\u{1FAFF}\u2600-\u27BF])/gu,
58919
+ /([\u4E00-\u9FFF\u3400-\u4DBF\u3000-\u303F\uFF01-\uFF60])([\u{1F300}-\u{1FAFF}\u2600-\u27BF][\uFE0E\uFE0F]?)/gu,
58853
58920
  "$1 $2"
58854
58921
  );
58855
58922
  return res;
@@ -59557,6 +59624,25 @@ function producedPathsForTurn(cards) {
59557
59624
  return paths;
59558
59625
  }
59559
59626
 
59627
+ // packages/tui/tui-render/src/workspace-changes-card.ts
59628
+ var WORKSPACE_CHANGES_CARD_PATH_LIMIT = 3;
59629
+ function workspaceChangeCountsLabel(file2) {
59630
+ if (file2.binary === true) return "binary";
59631
+ if (file2.oversized === true) return "oversized";
59632
+ return `+${String(file2.added)}/\u2212${String(file2.deleted)}`;
59633
+ }
59634
+ function formatWorkspaceChangesCard(card, pathLimit = WORKSPACE_CHANGES_CARD_PATH_LIMIT) {
59635
+ if (card.files.length === 0) return void 0;
59636
+ const shown = card.files.slice(0, Math.max(0, pathLimit));
59637
+ const lines = [
59638
+ `\u6539\u52A8 \xB7 ${String(card.total)} \u4E2A\u6587\u4EF6 +${String(card.added)}/\u2212${String(card.deleted)}`,
59639
+ ...shown.map((file2) => ` ${file2.display} ${workspaceChangeCountsLabel(file2)}`)
59640
+ ];
59641
+ const hidden = card.total - shown.length;
59642
+ if (hidden > 0) lines.push(` \u2026 +${String(hidden)} \u4E2A\u6587\u4EF6`);
59643
+ return lines;
59644
+ }
59645
+
59560
59646
  // packages/tui/tui-render/src/stream-view.tsx
59561
59647
  import { pathToFileURL as pathToFileURL2 } from "node:url";
59562
59648
  import { isAbsolute as isAbsolute3 } from "node:path";
@@ -69247,7 +69333,10 @@ function wrapRow(row, widths, header) {
69247
69333
  const cells = row.map((cell, col) => {
69248
69334
  const linesForCell = wrapped[col];
69249
69335
  const lineText = linesForCell[lineIndex] ?? "";
69250
- const text4 = padDisplayEnd(lineText, widths[col]);
69336
+ const colWidth = widths[col];
69337
+ const padded = padDisplayEnd(lineText, colWidth);
69338
+ const fitted = displayWidth(padded) > colWidth ? wcwidthSafeSlice(padded, colWidth) : padded;
69339
+ const text4 = padDisplayEnd(fitted, colWidth);
69251
69340
  return { text: text4, width: displayWidth(text4), column: cell.column, row: cell.row };
69252
69341
  });
69253
69342
  out.push({ kind: "row", header, cells });
@@ -69494,15 +69583,32 @@ function renderBlockquote(children, width, rowOffset, sourceStart, hyperlinks2)
69494
69583
  return freezeLine(buffer, rowOffset + index2, index2 === 0 ? sourceStart : -1);
69495
69584
  });
69496
69585
  }
69497
- function renderList(list2, width, rowOffset, sourceStart, hyperlinks2) {
69586
+ function renderList(list2, width, rowOffset, sourceStart, hyperlinks2, depth = 0) {
69498
69587
  const lines = [];
69499
69588
  const ordered = list2.ordered === true;
69589
+ const indent2 = " ".repeat(depth);
69500
69590
  list2.children.forEach((item, index2) => {
69501
- const marker = ordered ? `${(list2.start ?? 1) + index2}. ` : "- ";
69591
+ const marker = `${indent2}${ordered ? `${String((list2.start ?? 1) + index2)}. ` : "- "}`;
69502
69592
  const segments = [{ text: marker, token: "fg", bold: false }];
69503
- const children = item.children;
69504
- for (const child of children) segments.push(...inlineToSegments(child, hyperlinks2));
69505
- lines.push(...wrapInlineSegments(segments, width, rowOffset + lines.length, index2 === 0 ? sourceStart : -1));
69593
+ for (const child of item.children) {
69594
+ if (child.type === "list") {
69595
+ if (segments.length > 1) {
69596
+ lines.push(...wrapInlineSegments(segments, width, rowOffset + lines.length, index2 === 0 ? sourceStart : -1));
69597
+ segments.length = 0;
69598
+ }
69599
+ lines.push(...renderList(child, width, rowOffset + lines.length, -1, hyperlinks2, depth + 1));
69600
+ } else if ("children" in child && Array.isArray(child.children)) {
69601
+ const phrasingChildren = child.children;
69602
+ for (const grandchild of phrasingChildren) {
69603
+ segments.push(...inlineToSegments(grandchild, hyperlinks2));
69604
+ }
69605
+ } else {
69606
+ segments.push(...inlineToSegments(child, hyperlinks2));
69607
+ }
69608
+ }
69609
+ if (segments.length > 1 || segments.length === 1 && segments[0]?.text !== marker) {
69610
+ lines.push(...wrapInlineSegments(segments, width, rowOffset + lines.length, index2 === 0 ? sourceStart : -1));
69611
+ }
69506
69612
  });
69507
69613
  return lines;
69508
69614
  }
@@ -69783,8 +69889,11 @@ function renderGridRow(row, widths, header, rowOffset, sourceStart) {
69783
69889
  for (let column = 0; column < widths.length; column += 1) {
69784
69890
  if (column > 0) appendSegment(buffer, { text: " \u2502 ", token: "fgDim", bold: false });
69785
69891
  const text4 = wrapped[column]?.[lineIndex] ?? "";
69892
+ const cellWidth = widths[column];
69893
+ const padded = padDisplayEnd(text4, cellWidth);
69894
+ const fitted = displayWidth(padded) > cellWidth ? wcwidthSafeSlice(padded, cellWidth) : padded;
69786
69895
  appendSegment(buffer, {
69787
- text: padDisplayEnd(text4, widths[column]),
69896
+ text: padDisplayEnd(fitted, cellWidth),
69788
69897
  token: header ? "accentText" : "fg",
69789
69898
  bold: header
69790
69899
  });
@@ -74038,6 +74147,12 @@ function projectCompactionEntry(entry, scope) {
74038
74147
  }
74039
74148
  function projectTurnTailEntry(entry, scope) {
74040
74149
  const lines = [];
74150
+ const changeLines = entry.meta?.turnTailWorkspaceChanges === void 0 ? void 0 : formatWorkspaceChangesCard(entry.meta.turnTailWorkspaceChanges);
74151
+ if (changeLines !== void 0) {
74152
+ for (const text4 of changeLines) {
74153
+ lines.push(lineForText(escapeContent(text4), "fg", false, lines.length));
74154
+ }
74155
+ }
74041
74156
  const produced = entry.meta?.turnTailProduced ?? [];
74042
74157
  if (produced.length > 0) {
74043
74158
  const joined = produced.map(escapeContent).join(" \xB7 ");
@@ -75880,7 +75995,8 @@ function StreamView({
75880
75995
  );
75881
75996
  const produced = producedPathsForTurn(cards);
75882
75997
  return produced.length === 0 ? {} : { turnTailProduced: produced };
75883
- })()
75998
+ })(),
75999
+ ...row.message.workspaceChanges === void 0 ? {} : { turnTailWorkspaceChanges: row.message.workspaceChanges }
75884
76000
  };
75885
76001
  if (Object.keys(tailMeta).length > 0) {
75886
76002
  rows2.push(GAP_LINE);
@@ -76749,13 +76865,14 @@ function StreamView({
76749
76865
  (card) => presenterCache.present(presenters, card)
76750
76866
  );
76751
76867
  const produced = producedPathsForTurn(cards);
76868
+ const changeLines = message.workspaceChanges === void 0 ? void 0 : formatWorkspaceChangesCard(message.workspaceChanges);
76752
76869
  const stats = formatTurnTailStats({
76753
76870
  turnOrdinal: message.turnOrdinal,
76754
76871
  turnUsage: message.turnUsage,
76755
76872
  legacyOutputTokens: message.usageOutputTokens,
76756
76873
  elapsedMs: message.stepWallMs
76757
76874
  });
76758
- if (produced.length === 0 && stats === void 0 && !showCompletionBoundary) return void 0;
76875
+ if (produced.length === 0 && changeLines === void 0 && stats === void 0 && !showCompletionBoundary) return void 0;
76759
76876
  const producedRows = [];
76760
76877
  let rowRuns = [styled("\u4EA7\u7269 \xB7 ", "fg")];
76761
76878
  let rowWidth = displayWidth("\u4EA7\u7269 \xB7 ");
@@ -76779,6 +76896,7 @@ function StreamView({
76779
76896
  }
76780
76897
  if (pathsInRow > 0) producedRows.push(rowRuns);
76781
76898
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", width: "100%", children: [
76899
+ (changeLines ?? []).map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: paintRow([styled(escapeContent(line5), "fg")]) }, `changes-${String(index2)}`)),
76782
76900
  producedRows.map((runs, index2) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: paintRow(runs) }, `produced-${String(index2)}`)),
76783
76901
  stats === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: paintRow([styled(escapeContent(stats), "fgDim")]) }),
76784
76902
  showCompletionBoundary ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: paintRow([styled("\u2500\u2500 \u5DF2\u5B8C\u6210 \u2500\u2500", "fgDim")]) }) : null
@@ -77586,14 +77704,29 @@ function hubRow(row, selected) {
77586
77704
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintRow([styled(escapeContent(`\u5B50\u4F1A\u8BDD ID \xB7 ${row.id}`), "fgDim")]) })
77587
77705
  ] }, row.id);
77588
77706
  }
77707
+ function hubLimitsFootnote(liveContinuable, maxActiveSubagents, maxDepth) {
77708
+ if (maxActiveSubagents === void 0 && maxDepth === void 0) {
77709
+ return void 0;
77710
+ }
77711
+ const live = liveContinuable ?? 0;
77712
+ const max = maxActiveSubagents ?? 8;
77713
+ const depth = maxDepth ?? 1;
77714
+ const base = `\u53EF\u7EE7\u7EED ${String(live)}/${String(max)} live \xB7 \u6DF1\u5EA6 ${String(depth)}`;
77715
+ return live >= max ? `${base} \xB7 \u5DF2\u8FBE\u4E0A\u9650` : base;
77716
+ }
77589
77717
  function AgentHubPane({
77590
77718
  rows = [],
77591
77719
  selectedIndex = 0,
77592
77720
  view = "table",
77593
77721
  error: error51,
77594
77722
  transcript,
77595
- missing = false
77723
+ missing = false,
77724
+ liveContinuable,
77725
+ maxActiveSubagents,
77726
+ maxDepth,
77727
+ scrollOffset
77596
77728
  }) {
77729
+ const limits = hubLimitsFootnote(liveContinuable, maxActiveSubagents, maxDepth);
77597
77730
  if (missing) {
77598
77731
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
77599
77732
  OverlayShell,
@@ -77604,6 +77737,7 @@ function AgentHubPane({
77604
77737
  }
77605
77738
  );
77606
77739
  }
77740
+ const clamped = Math.min(Math.max(selectedIndex, 0), Math.max(0, rows.length - 1));
77607
77741
  if (view === "transcript") {
77608
77742
  if (error51 !== void 0 && error51 !== "") {
77609
77743
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
@@ -77616,7 +77750,39 @@ function AgentHubPane({
77616
77750
  );
77617
77751
  }
77618
77752
  const lines = (transcript ?? "").split("\n").filter((line5) => line5 !== "");
77619
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(OverlayShell, { title: "\u5B50\u4EE3\u7406", footnote: "Esc \u8FD4\u56DE", children: lines.map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintRow([styled(escapeContent(line5), "fg")]) }, index2)) });
77753
+ const selectedRow = rows[clamped];
77754
+ const headerSegments = selectedRow === void 0 ? [] : [
77755
+ `[\u5B50\u4EE3\u7406] ${selectedRow.label}`,
77756
+ selectedRow.activity === "" ? void 0 : `\u72B6\u6001: ${selectedRow.activity}`,
77757
+ ...metricSegments(selectedRow)
77758
+ ].filter((s) => s !== void 0);
77759
+ const total = lines.length;
77760
+ const pageSize = 20;
77761
+ const start = Math.min(scrollOffset ?? 0, Math.max(0, total - 1));
77762
+ const slice = lines.slice(start, start + pageSize);
77763
+ const scrollInfo = total > pageSize ? ` (${String(start + 1)}-${String(Math.min(start + slice.length, total))}/${String(total)})` : "";
77764
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
77765
+ OverlayShell,
77766
+ {
77767
+ title: "\u5B50\u4EE3\u7406",
77768
+ footnote: `\u2191\u2193/jk \u6EDA\u52A8${scrollInfo} \xB7 Esc \u8FD4\u56DE`,
77769
+ children: [
77770
+ headerSegments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Box_default, { width: "100%", flexDirection: "column", marginY: 0, children: [
77771
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintRow([styled(escapeContent(headerSegments.join(" \xB7 ")), "accent", void 0, true)]) }),
77772
+ selectedRow?.id && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintRow([styled(escapeContent(`\u5B50\u4F1A\u8BDD ID \xB7 ${selectedRow.id}`), "fgDim")]) }),
77773
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintRow([styled(escapeContent("\u2500\u2500\u2500 \u6267\u884C\u60C5\u51B5 \u2500\u2500\u2500"), "fgDim")]) })
77774
+ ] }),
77775
+ slice.map((lineText, index2) => {
77776
+ const isUser = lineText.startsWith("> ");
77777
+ const isTool = lineText.startsWith("\u25B8 ");
77778
+ const isResult = lineText.startsWith(" \u2514\u2500 ") || lineText.startsWith("\u2514\u2500 ");
77779
+ const isTurn = lineText.startsWith("\u2500\u2500 ");
77780
+ const token = isUser ? "accent" : isTool ? "codeKeyword" : isResult ? "fgDim" : isTurn ? "fgDim" : "fg";
77781
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintRow([styled(escapeContent(lineText), token)]) }, start + index2);
77782
+ })
77783
+ ]
77784
+ }
77785
+ );
77620
77786
  }
77621
77787
  if (error51 !== void 0 && error51 !== "") {
77622
77788
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
@@ -77624,7 +77790,7 @@ function AgentHubPane({
77624
77790
  {
77625
77791
  title: "\u5B50\u4EE3\u7406",
77626
77792
  error: error51,
77627
- footnote: "Esc \u5173\u95ED \xB7 \u53EF\u91CD\u8BD5"
77793
+ footnote: limits === void 0 ? "Esc \u5173\u95ED \xB7 \u53EF\u91CD\u8BD5" : `${limits} \xB7 Esc \u5173\u95ED \xB7 \u53EF\u91CD\u8BD5`
77628
77794
  }
77629
77795
  );
77630
77796
  }
@@ -77634,16 +77800,15 @@ function AgentHubPane({
77634
77800
  {
77635
77801
  title: "\u5B50\u4EE3\u7406",
77636
77802
  body: "\u6682\u65E0\u5B50\u4EE3\u7406",
77637
- footnote: "Esc \u5173\u95ED \xB7 \u6709\u8FD0\u884C\u4E2D\u7684\u5B50\u4EE3\u7406\u65F6\u518D\u6253\u5F00"
77803
+ footnote: limits === void 0 ? "Esc \u5173\u95ED \xB7 \u6709\u8FD0\u884C\u4E2D\u7684\u5B50\u4EE3\u7406\u65F6\u518D\u6253\u5F00" : `${limits} \xB7 Esc \u5173\u95ED`
77638
77804
  }
77639
77805
  );
77640
77806
  }
77641
- const clamped = Math.min(Math.max(selectedIndex, 0), rows.length - 1);
77642
77807
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
77643
77808
  OverlayShell,
77644
77809
  {
77645
77810
  title: "\u5B50\u4EE3\u7406",
77646
- footnote: "j/k \u9009\u62E9 \xB7 Enter \u67E5\u770B \xB7 Esc \u5173\u95ED",
77811
+ footnote: limits === void 0 ? "j/k \u9009\u62E9 \xB7 Enter \u67E5\u770B \xB7 Esc \u5173\u95ED" : `${limits} \xB7 j/k \u9009\u62E9 \xB7 Enter \u67E5\u770B \xB7 Esc \u5173\u95ED`,
77647
77812
  children: [
77648
77813
  rows.map((row, index2) => hubRow(row, index2 === clamped)),
77649
77814
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintRow([styled(escapeContent(aggregateLine(rows)), "fgDim")]) })
@@ -80794,7 +80959,11 @@ function TuiLoop({
80794
80959
  view: agentHubPane.view,
80795
80960
  error: agentHubPane.error,
80796
80961
  transcript: agentHubPane.transcript,
80797
- missing: agentHubPane.missing
80962
+ missing: agentHubPane.missing,
80963
+ liveContinuable: agentHubPane.liveContinuable,
80964
+ maxActiveSubagents: agentHubPane.maxActiveSubagents,
80965
+ maxDepth: agentHubPane.maxDepth,
80966
+ scrollOffset: agentHubPane.scrollOffset
80798
80967
  });
80799
80968
  } else if (planDirectoryPane.open) {
80800
80969
  content3 = (0, import_react39.createElement)(PlanDirectoryPane, {
@@ -81220,14 +81389,29 @@ function formatTurnError(error51) {
81220
81389
  if (code2 === "MISSING_CREDENTIAL" || rawMessage.includes("DEEPSEEK_API_KEY") || rawMessage.includes("MISSING_CREDENTIAL") || rawMessage.includes("no API key")) {
81221
81390
  return '\u26A0\uFE0F **API \u5BC6\u94A5\u7F3A\u5931**\uFF1A\u672A\u68C0\u6D4B\u5230\u6709\u6548\u5BC6\u94A5\u3002\u8BF7\u5728\u7EC8\u7AEF\u6267\u884C `export DEEPSEEK_API_KEY="sk-..."` \u6216\u8F93\u5165 `/key` \u547D\u4EE4\u8FDB\u884C\u914D\u7F6E\u3002';
81222
81391
  }
81223
- if (status === 401 || code2 === "AUTH" || rawMessage.includes("401") || rawMessage.toLowerCase().includes("authentication fails") || rawMessage.toLowerCase().includes("invalid api key") || rawMessage.toLowerCase().includes("unauthorized")) {
81224
- return `\u26A0\uFE0F **API \u8BA4\u8BC1\u5931\u8D25\uFF08HTTP 401\uFF09**\uFF1AAPI Key \u65E0\u6548\u6216\u672A\u6388\u6743\uFF08${rawMessage}\uFF09\u3002\u8BF7\u68C0\u67E5\u5BC6\u94A5\u662F\u5426\u6B63\u786E\uFF0C\u6216\u4F7F\u7528 \`/key\` \u91CD\u65B0\u914D\u7F6E\u3002`;
81392
+ if (rawMessage.includes("reading 'prepare'") || rawMessage.includes('reading "prepare"')) {
81393
+ return `\u26A0\uFE0F **\u5DE5\u5177\u8C03\u5EA6\u5931\u8D25**\uFF1A${rawMessage}\u3002\u8BF7\u65B0\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u540E\u518D\u8BD5\uFF1B\u4E0D\u8981\u5728\u8BA4\u8BC1\u5931\u8D25\u7684\u540C\u4E00\u56DE\u5408\u91CC\u7528\u300C\u7EE7\u7EED\u300D\u63A5\u7740\u8DD1\u5DE5\u5177\u3002`;
81394
+ }
81395
+ const lowered = rawMessage.toLowerCase();
81396
+ const antigravity = lowered.includes("antigravity") || rawMessage.includes("/anti");
81397
+ if (code2 === "CANCELLED" || lowered.includes("cancelled") || lowered.includes("canceled")) {
81398
+ return antigravity ? `\u26A0\uFE0F **Antigravity \u5DF2\u505C\u6B62**\uFF1A${rawMessage}\u3002\u8FD9\u662F\u7528\u6237\u4E2D\u65AD\uFF0C\u4E0D\u662F\u767B\u5F55\u5931\u6548\u3002\u76F4\u63A5\u518D\u53D1\u4E00\u6761\u5373\u53EF\uFF1B\u4E0D\u5FC5\u6267\u884C \`/anti login\`\uFF0C\u4E5F\u4E0D\u8981\u4F7F\u7528 \`/key\`\u3002` : `\u26A0\uFE0F **\u5DF2\u505C\u6B62\u751F\u6210**\uFF1A${rawMessage}\u3002\u53EF\u4EE5\u76F4\u63A5\u518D\u53D1\u4E00\u6761\u3002`;
81399
+ }
81400
+ if (code2 === "TIMEOUT" || lowered.includes("timed out") || lowered.includes("timeout") || lowered.includes("stalled") || rawMessage.includes("ETIMEDOUT")) {
81401
+ return antigravity ? `\u26A0\uFE0F **Antigravity \u8BF7\u6C42\u8D85\u65F6**\uFF1A${rawMessage}\u3002\u8FD9\u662F\u94FE\u8DEF\u6216\u6D41\u8D85\u65F6\uFF0C\u4E0D\u662F\u767B\u5F55\u5931\u6548\u3002\u8BF7\u7A0D\u540E\u91CD\u8BD5\uFF1B\u4E0D\u5FC5\u6267\u884C \`/anti login\`\uFF0C\u4E5F\u4E0D\u8981\u4F7F\u7528 \`/key\`\u3002` : `\u26A0\uFE0F **\u7F51\u7EDC\u8FDE\u63A5\u5931\u8D25**\uFF1A\u65E0\u6CD5\u8FDE\u63A5\u5230\u6A21\u578B\u670D\u52A1\uFF08${rawMessage}\uFF09\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u6216\u4EE3\u7406\u914D\u7F6E\u3002`;
81225
81402
  }
81226
- if (status === 429 || code2 === "RATE_LIMIT" || rawMessage.includes("429") || rawMessage.toLowerCase().includes("quota") || rawMessage.toLowerCase().includes("rate limit")) {
81403
+ if (status === 429 || code2 === "RATE_LIMIT" || rawMessage.includes("429") || lowered.includes("quota") || lowered.includes("rate limit")) {
81227
81404
  return `\u26A0\uFE0F **\u8BF7\u6C42\u53D7\u9650\uFF08HTTP 429\uFF09**\uFF1A\u8BF7\u6C42\u9891\u7387\u8D85\u9650\u6216\u8D26\u6237\u4F59\u989D\u4E0D\u8DB3\uFF08${rawMessage}\uFF09\u3002\u8BF7\u7A0D\u540E\u91CD\u8BD5\u6216\u68C0\u67E5\u8D26\u6237\u989D\u5EA6\u3002`;
81228
81405
  }
81229
- if (rawMessage.includes("ECONNREFUSED") || rawMessage.includes("ETIMEDOUT") || rawMessage.includes("ENOTFOUND") || rawMessage.includes("fetch failed")) {
81230
- return `\u26A0\uFE0F **\u7F51\u7EDC\u8FDE\u63A5\u5931\u8D25**\uFF1A\u65E0\u6CD5\u8FDE\u63A5\u5230\u6A21\u578B\u670D\u52A1\uFF08${rawMessage}\uFF09\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u6216\u4EE3\u7406\u914D\u7F6E\u3002`;
81406
+ if (code2 === "NETWORK" || code2 === "TRANSPORT" || lowered.includes("could not be reached") || lowered.includes("proxy rejected") || rawMessage.includes("ECONNREFUSED") || rawMessage.includes("ENOTFOUND") || rawMessage.includes("fetch failed")) {
81407
+ return antigravity ? `\u26A0\uFE0F **Antigravity \u7F51\u7EDC\u4E0D\u53EF\u8FBE**\uFF1A${rawMessage}\u3002\u8FD9\u662F\u79C1\u6709\u7AEF\u70B9\u6216 HTTPS_PROXY \u8FDE\u4E0D\u4E0A\uFF0C\u4E0D\u662F\u767B\u5F55\u5931\u6548\u3002\u8BF7\u68C0\u67E5\u672C\u673A\u4EE3\u7406\u540E\u91CD\u8BD5\uFF1B\u4E0D\u5FC5\u6267\u884C \`/anti login\`\uFF0C\u4E5F\u4E0D\u8981\u4F7F\u7528 \`/key\`\u3002` : `\u26A0\uFE0F **\u7F51\u7EDC\u8FDE\u63A5\u5931\u8D25**\uFF1A\u65E0\u6CD5\u8FDE\u63A5\u5230\u6A21\u578B\u670D\u52A1\uFF08${rawMessage}\uFF09\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u6216\u4EE3\u7406\u914D\u7F6E\u3002`;
81408
+ }
81409
+ if (antigravity) {
81410
+ const authFailure = code2 === "AUTH" || lowered.includes("login is required") || lowered.includes("invalid grant") || lowered.includes("refresh token is invalid") || lowered.includes("no usable access token") || status === 401;
81411
+ return authFailure ? `\u26A0\uFE0F **Antigravity \u8BA4\u8BC1\u5931\u8D25**\uFF1A${rawMessage}\u3002\u8BF7\u4F7F\u7528 \`/anti status\` \u786E\u8BA4\u767B\u5F55\uFF0C\u5FC5\u8981\u65F6\u6267\u884C \`/anti login\` \u91CD\u65B0\u767B\u5F55\u3002Antigravity \u4F7F\u7528 Google OAuth\uFF0C\u4E0D\u662F API Key\uFF0C\u4E0D\u8981\u4F7F\u7528 \`/key\`\u3002` : `\u26A0\uFE0F **Antigravity \u8BF7\u6C42\u5931\u8D25**\uFF1A${rawMessage}\u3002\u82E5 \`/anti status\` \u663E\u793A\u5DF2\u767B\u5F55\uFF0C\u76F4\u63A5\u91CD\u8BD5\u5373\u53EF\uFF1B\u4E0D\u8981\u4F7F\u7528 \`/key\`\u3002`;
81412
+ }
81413
+ if (status === 401 || code2 === "AUTH" || rawMessage.includes("401") || lowered.includes("authentication fails") || lowered.includes("invalid api key") || lowered.includes("unauthorized")) {
81414
+ return `\u26A0\uFE0F **API \u8BA4\u8BC1\u5931\u8D25\uFF08HTTP 401\uFF09**\uFF1AAPI Key \u65E0\u6548\u6216\u672A\u6388\u6743\uFF08${rawMessage}\uFF09\u3002\u8BF7\u68C0\u67E5\u5BC6\u94A5\u662F\u5426\u6B63\u786E\uFF0C\u6216\u4F7F\u7528 \`/key\` \u91CD\u65B0\u914D\u7F6E\u3002`;
81231
81415
  }
81232
81416
  return `\u26A0\uFE0F **\u6A21\u578B\u8BF7\u6C42\u5931\u8D25**\uFF1A${rawMessage}`;
81233
81417
  }
@@ -81476,14 +81660,27 @@ ${formattedError}` });
81476
81660
  status = "idle";
81477
81661
  return;
81478
81662
  }
81479
- default:
81663
+ default: {
81664
+ if (event.type === "workspace/changes") {
81665
+ const turn = event.data.turn;
81666
+ if (typeof turn === "number") {
81667
+ for (let i = history.length - 1; i >= 0; i--) {
81668
+ const row = history[i];
81669
+ if (row !== void 0 && row.kind === "assistant" && row.turnOrdinal === turn) {
81670
+ history[i] = { ...row, workspaceChangesSeq: event.seq };
81671
+ break;
81672
+ }
81673
+ }
81674
+ }
81675
+ }
81480
81676
  return;
81677
+ }
81481
81678
  }
81482
81679
  }
81483
81680
  return {
81484
81681
  push: push3,
81485
81682
  seed(events) {
81486
- if (!events || typeof events[Symbol.iterator] !== "function") return;
81683
+ if (!events || !Array.isArray(events)) return;
81487
81684
  for (const event of events) push3(event);
81488
81685
  },
81489
81686
  snapshot() {
@@ -81764,7 +81961,8 @@ var LEADING_NAMESPACES = [
81764
81961
  "llm-deepseek",
81765
81962
  "llm-openai",
81766
81963
  "llm-anthropic",
81767
- "llm-pi-ai"
81964
+ "llm-pi-ai",
81965
+ "subagent"
81768
81966
  ];
81769
81967
  var BRAND_ANIMATION_LABELS = {
81770
81968
  auto: "\u81EA\u52A8",
@@ -82501,6 +82699,9 @@ function transitionStatusText(state) {
82501
82699
  function errorReason(error51) {
82502
82700
  return error51 instanceof Error ? error51.message : String(error51);
82503
82701
  }
82702
+ function terminalErrorReason(error51) {
82703
+ return userErrorReason(error51);
82704
+ }
82504
82705
  function fieldOf(section, field) {
82505
82706
  if (typeof section !== "object" || section === null || Array.isArray(section)) {
82506
82707
  return void 0;
@@ -82606,6 +82807,18 @@ function hubTranscriptOf(events) {
82606
82807
  if (text5 !== "") lines.push(`> ${text5}`);
82607
82808
  continue;
82608
82809
  }
82810
+ if (event.type === "tool/call") {
82811
+ const args = typeof event.data.arguments === "string" ? event.data.arguments : JSON.stringify(event.data.arguments);
82812
+ const shortArgs = args.length > 80 ? `${args.slice(0, 77)}...` : args;
82813
+ lines.push(`\u25B8 ${event.data.name} ${shortArgs}`);
82814
+ continue;
82815
+ }
82816
+ if (event.type === "tool/result") {
82817
+ const text5 = joinTextBlocks(event.data.message.content, "");
82818
+ const shortText = text5.length > 80 ? `${text5.slice(0, 77).replace(/\n/g, " ")}...` : text5.replace(/\n/g, " ");
82819
+ if (shortText !== "") lines.push(` \u2514\u2500 ${shortText}`);
82820
+ continue;
82821
+ }
82609
82822
  if (event.type !== "assistant/message") continue;
82610
82823
  const text4 = joinTextBlocks(event.data.message.content, "");
82611
82824
  if (text4 !== "") lines.push(`\u25CF ${text4}`);
@@ -82649,6 +82862,10 @@ var RuntimeController = class _RuntimeController {
82649
82862
  this.disposeSessionEvents = ctx.on("session/event", (session, event) => {
82650
82863
  if (session !== this.liveHandle?.agent.session) return;
82651
82864
  this.projector.push(event);
82865
+ if (event.type === "workspace/changes") this.cacheWorkspaceChange(event.seq);
82866
+ if (this.agentHubOpen && (event.type === "subagent/catalog" || event.type === "subagent/descriptor")) {
82867
+ this.ownWork(this.refreshAgentHub(), "agent hub list");
82868
+ }
82652
82869
  if (event.type === "turn/start") {
82653
82870
  this.reduce({ kind: "turn-started" }, void 0, void 0);
82654
82871
  } else if (event.type === "llm/retry") {
@@ -82801,12 +83018,17 @@ var RuntimeController = class _RuntimeController {
82801
83018
  /** Idempotent quiescent controller teardown. */
82802
83019
  disposeInFlight;
82803
83020
  closed = false;
83021
+ isClosed() {
83022
+ return this.closed;
83023
+ }
82804
83024
  machine = "idle";
82805
83025
  /** Durable retry wait currently visible in the footer. */
82806
83026
  retryFooter;
82807
83027
  /** Single bounded refresh timer while {@link retryFooter} is visible. */
82808
83028
  retryFooterTimer;
82809
83029
  projector = createProjector();
83030
+ /** Host `workspace/changes` cards keyed by announcing event sequence. */
83031
+ workspaceChangeCards = /* @__PURE__ */ new Map();
82810
83032
  presentationOverrides = /* @__PURE__ */ new Map();
82811
83033
  presentationWrites = Promise.resolve();
82812
83034
  toolCardsExpanded = false;
@@ -82891,6 +83113,7 @@ var RuntimeController = class _RuntimeController {
82891
83113
  agentHubView = "table";
82892
83114
  agentHubError;
82893
83115
  agentHubTranscript;
83116
+ agentHubScrollOffset = 0;
82894
83117
  /** Monotonic listing/inspect id: only the newest Hub request may land. */
82895
83118
  agentHubSeq = 0;
82896
83119
  /** Cancellation owner for the newest Hub list, fold, expansion, or inspect. */
@@ -83091,6 +83314,7 @@ var RuntimeController = class _RuntimeController {
83091
83314
  const model = this.projector.snapshot();
83092
83315
  this.modelSnapshot = {
83093
83316
  ...model,
83317
+ history: this.decorateWorkspaceChanges(model.history),
83094
83318
  reasoningExpanded: this.presentationFlag("reasoning"),
83095
83319
  toolCardsExpanded: this.toolCardsExpanded,
83096
83320
  expandedCompactionId: this.expandedCompactionId,
@@ -83099,6 +83323,55 @@ var RuntimeController = class _RuntimeController {
83099
83323
  }
83100
83324
  return this.modelSnapshot;
83101
83325
  }
83326
+ /**
83327
+ * Attach cached Host summaries onto frozen assistant turns.
83328
+ * @param history - projector history.
83329
+ * @returns history with `workspaceChanges` filled when a card exists.
83330
+ */
83331
+ decorateWorkspaceChanges(history) {
83332
+ if (this.workspaceChangeCards.size === 0) return history;
83333
+ return history.map((row) => {
83334
+ if (row.kind !== "assistant" || row.workspaceChangesSeq === void 0) return row;
83335
+ const card = this.workspaceChangeCards.get(row.workspaceChangesSeq);
83336
+ return card === void 0 ? row : { ...row, workspaceChanges: card };
83337
+ });
83338
+ }
83339
+ /**
83340
+ * Read one announcing event's Host summary into the transcript card cache.
83341
+ * Empty or abandoned records drop any earlier card for that sequence.
83342
+ * @param seq - `workspace/changes` event sequence.
83343
+ */
83344
+ cacheWorkspaceChange(seq) {
83345
+ const sessionId = this.session?.id;
83346
+ const service = this.ctx.get("workspaceChanges");
83347
+ const summary = sessionId === void 0 || service === void 0 ? void 0 : service.summary(sessionId, seq);
83348
+ const card = workspaceChangesCardFromSummary(seq, summary);
83349
+ if (card === void 0) this.workspaceChangeCards.delete(seq);
83350
+ else this.workspaceChangeCards.set(seq, card);
83351
+ }
83352
+ /** Replay Host summaries for every `workspace/changes` event on the bound Session. */
83353
+ hydrateWorkspaceChangeCards() {
83354
+ this.workspaceChangeCards.clear();
83355
+ const session = this.session;
83356
+ if (session === void 0) return;
83357
+ for (const event of getSessionEvents(session)) {
83358
+ if (event.type === "workspace/changes") this.cacheWorkspaceChange(event.seq);
83359
+ }
83360
+ }
83361
+ /**
83362
+ * Continuable defaults from live settings, never a stale Hub cache.
83363
+ * @returns max live children (8) and max depth (1) unless the user raised them.
83364
+ */
83365
+ subagentLimits() {
83366
+ const settings = this.ctx.get("settings");
83367
+ const section = settings === void 0 ? void 0 : settings.get("subagent");
83368
+ const maxActive = fieldOf(section, "maxActiveSubagents");
83369
+ const maxDepth = fieldOf(section, "maxDepth");
83370
+ return {
83371
+ maxActiveSubagents: typeof maxActive === "number" ? maxActive : 8,
83372
+ maxDepth: typeof maxDepth === "number" ? maxDepth : 1
83373
+ };
83374
+ }
83102
83375
  /**
83103
83376
  * Return the interaction state.
83104
83377
  * @returns the current interaction state.
@@ -83346,17 +83619,25 @@ var RuntimeController = class _RuntimeController {
83346
83619
  */
83347
83620
  getAgentHubPane() {
83348
83621
  if (!this.agentHubOpen) return EMPTY_OVERLAY_PANE;
83349
- if (this.agentHubPaneSnapshot === void 0) {
83350
- this.agentHubPaneSnapshot = {
83351
- open: true,
83352
- rows: this.agentHubRows,
83353
- selectedIndex: this.agentHubSelectedIndex,
83354
- view: this.agentHubView,
83355
- missing: this.ctx.get("subagents") === void 0,
83356
- ...this.agentHubError === void 0 ? {} : { error: this.agentHubError },
83357
- ...this.agentHubTranscript === void 0 ? {} : { transcript: this.agentHubTranscript }
83358
- };
83622
+ const limits = this.subagentLimits();
83623
+ const liveContinuable = this.agentHubRows.filter((row) => row.activity === "running").length;
83624
+ const cached2 = this.agentHubPaneSnapshot;
83625
+ if (cached2 !== void 0 && cached2.rows === this.agentHubRows && cached2.selectedIndex === this.agentHubSelectedIndex && cached2.view === this.agentHubView && cached2.error === this.agentHubError && cached2.transcript === this.agentHubTranscript && cached2.scrollOffset === this.agentHubScrollOffset && cached2.liveContinuable === liveContinuable && cached2.maxActiveSubagents === limits.maxActiveSubagents && cached2.maxDepth === limits.maxDepth) {
83626
+ return cached2;
83359
83627
  }
83628
+ this.agentHubPaneSnapshot = {
83629
+ open: true,
83630
+ rows: this.agentHubRows,
83631
+ selectedIndex: this.agentHubSelectedIndex,
83632
+ view: this.agentHubView,
83633
+ missing: this.ctx.get("subagents") === void 0,
83634
+ liveContinuable,
83635
+ scrollOffset: this.agentHubScrollOffset,
83636
+ maxActiveSubagents: limits.maxActiveSubagents,
83637
+ maxDepth: limits.maxDepth,
83638
+ ...this.agentHubError === void 0 ? {} : { error: this.agentHubError },
83639
+ ...this.agentHubTranscript === void 0 ? {} : { transcript: this.agentHubTranscript }
83640
+ };
83360
83641
  return this.agentHubPaneSnapshot;
83361
83642
  }
83362
83643
  /**
@@ -83496,6 +83777,34 @@ var RuntimeController = class _RuntimeController {
83496
83777
  if (fs3 === void 0) return;
83497
83778
  const seq = this.workspaceSeq;
83498
83779
  try {
83780
+ const change = lookupWorkspaceChange(
83781
+ this.workspaceChangeCards,
83782
+ row.target.displayPath
83783
+ ) ?? lookupWorkspaceChange(this.workspaceChangeCards, row.name);
83784
+ if (change !== void 0) {
83785
+ const sessionId = this.session?.id;
83786
+ const service = this.ctx.get("workspaceChanges");
83787
+ if (sessionId === void 0 || service === void 0) {
83788
+ this.setFeedback(`\u2717 ${SESSION_CHANGES_DISPOSED_COPY}`);
83789
+ return;
83790
+ }
83791
+ const diff2 = await service.diff(sessionId, change.seq, change.index, this.lifecycleAbort.signal);
83792
+ if (seq !== this.workspaceSeq || !this.workspaceOpen) return;
83793
+ const preview = formatWorkspaceChangeDiffPreview(diff2);
83794
+ if (preview === void 0) {
83795
+ this.setFeedback(`\u2717 ${SESSION_CHANGES_DISPOSED_COPY}`);
83796
+ return;
83797
+ }
83798
+ this.workspacePreview = {
83799
+ path: row.target.displayPath,
83800
+ name: row.name,
83801
+ lines: [...preview],
83802
+ scrollOffset: 0
83803
+ };
83804
+ this.workspacePaneSnapshot = void 0;
83805
+ this.emit();
83806
+ return;
83807
+ }
83499
83808
  const text4 = await fs3.readText(row.target);
83500
83809
  if (seq !== this.workspaceSeq || !this.workspaceOpen) return;
83501
83810
  const lines = text4.split(/\r?\n/u);
@@ -84048,7 +84357,9 @@ var RuntimeController = class _RuntimeController {
84048
84357
  this.agentHubView = "table";
84049
84358
  this.agentHubError = void 0;
84050
84359
  this.agentHubTranscript = void 0;
84360
+ this.agentHubScrollOffset = 0;
84051
84361
  this.agentHubSeq += 1;
84362
+ this.agentHubPaneSnapshot = void 0;
84052
84363
  }
84053
84364
  /**
84054
84365
  * Cancel the prior Hub read and start one request tied to controller teardown.
@@ -84075,6 +84386,7 @@ var RuntimeController = class _RuntimeController {
84075
84386
  this.agentHubError = void 0;
84076
84387
  this.agentHubRows = [];
84077
84388
  this.agentHubSelectedIndex = 0;
84389
+ this.agentHubPaneSnapshot = void 0;
84078
84390
  this.emit();
84079
84391
  const subagents = this.ctx.get("subagents");
84080
84392
  if (subagents === void 0 || this.session === void 0) return;
@@ -84084,11 +84396,14 @@ var RuntimeController = class _RuntimeController {
84084
84396
  if (!this.agentHubOpen || seq !== this.agentHubSeq) return;
84085
84397
  this.agentHubRows = rows;
84086
84398
  this.agentHubError = void 0;
84399
+ this.agentHubPaneSnapshot = void 0;
84400
+ this.agentHubError = void 0;
84087
84401
  this.emit();
84088
84402
  } catch (error51) {
84089
84403
  if (!this.agentHubOpen || seq !== this.agentHubSeq) return;
84090
84404
  this.agentHubRows = [];
84091
84405
  this.agentHubError = `\u65E0\u6CD5\u5217\u51FA\u5B50\u4EE3\u7406\uFF1A${errorReason(error51)}`;
84406
+ this.agentHubPaneSnapshot = void 0;
84092
84407
  this.emit();
84093
84408
  }
84094
84409
  }
@@ -84107,10 +84422,12 @@ var RuntimeController = class _RuntimeController {
84107
84422
  this.agentHubRows = rows;
84108
84423
  this.agentHubSelectedIndex = 0;
84109
84424
  this.agentHubError = void 0;
84425
+ this.agentHubPaneSnapshot = void 0;
84110
84426
  this.emit();
84111
84427
  } catch (error51) {
84112
84428
  if (!this.agentHubOpen || seq !== this.agentHubSeq) return;
84113
84429
  this.agentHubError = `\u65E0\u6CD5\u5217\u51FA\u5B50\u4EE3\u7406\uFF1A${errorReason(error51)}`;
84430
+ this.agentHubPaneSnapshot = void 0;
84114
84431
  this.emit();
84115
84432
  }
84116
84433
  }
@@ -84198,6 +84515,8 @@ var RuntimeController = class _RuntimeController {
84198
84515
  this.agentHubView = "transcript";
84199
84516
  this.agentHubTranscript = void 0;
84200
84517
  this.agentHubError = void 0;
84518
+ this.agentHubScrollOffset = 0;
84519
+ this.agentHubPaneSnapshot = void 0;
84201
84520
  this.emit();
84202
84521
  const persistence = this.ctx.get("sessionPersistence");
84203
84522
  if (persistence === void 0) {
@@ -84222,10 +84541,13 @@ var RuntimeController = class _RuntimeController {
84222
84541
  if (!this.agentHubOpen || seq !== this.agentHubSeq) return;
84223
84542
  this.agentHubTranscript = hubTranscriptOf(events);
84224
84543
  this.agentHubError = void 0;
84544
+ this.agentHubPaneSnapshot = void 0;
84545
+ this.agentHubError = void 0;
84225
84546
  this.emit();
84226
84547
  } catch (error51) {
84227
84548
  if (!this.agentHubOpen || seq !== this.agentHubSeq) return;
84228
84549
  this.agentHubError = `\u65E0\u6CD5\u8BFB\u53D6\u5B50\u4F1A\u8BDD\uFF1A${errorReason(error51)}`;
84550
+ this.agentHubPaneSnapshot = void 0;
84229
84551
  this.emit();
84230
84552
  }
84231
84553
  }
@@ -84541,6 +84863,8 @@ var RuntimeController = class _RuntimeController {
84541
84863
  this.agentHubView = "table";
84542
84864
  this.agentHubTranscript = void 0;
84543
84865
  this.agentHubError = void 0;
84866
+ this.agentHubScrollOffset = 0;
84867
+ this.agentHubPaneSnapshot = void 0;
84544
84868
  this.emit();
84545
84869
  return;
84546
84870
  }
@@ -84549,12 +84873,19 @@ var RuntimeController = class _RuntimeController {
84549
84873
  this.emit();
84550
84874
  return;
84551
84875
  case "agent-hub-move":
84552
- if (!this.agentHubOpen || this.agentHubView !== "table") return;
84876
+ if (!this.agentHubOpen) return;
84877
+ if (this.agentHubView === "transcript") {
84878
+ this.agentHubScrollOffset = Math.max(0, this.agentHubScrollOffset + action.delta);
84879
+ this.agentHubPaneSnapshot = void 0;
84880
+ this.emit();
84881
+ return;
84882
+ }
84553
84883
  if (this.agentHubRows.length === 0) return;
84554
84884
  this.agentHubSelectedIndex = Math.min(
84555
84885
  this.agentHubRows.length - 1,
84556
84886
  Math.max(0, this.agentHubSelectedIndex + action.delta)
84557
84887
  );
84888
+ this.agentHubPaneSnapshot = void 0;
84558
84889
  this.emit();
84559
84890
  return;
84560
84891
  case "agent-hub-enter":
@@ -85334,7 +85665,7 @@ var RuntimeController = class _RuntimeController {
85334
85665
  } catch (error51) {
85335
85666
  fail(
85336
85667
  this.io,
85337
- new Error(`cannot resume session "${resumeId}": ${errorReason(error51)}`)
85668
+ new Error(`cannot resume session "${resumeId}": ${terminalErrorReason(error51)}`)
85338
85669
  );
85339
85670
  }
85340
85671
  }
@@ -85411,9 +85742,13 @@ var RuntimeController = class _RuntimeController {
85411
85742
  this.ctx.logger.warn(
85412
85743
  `session ${request.intent} failed: ${errorReason(primaryError)}`
85413
85744
  );
85414
- this.setFeedback(
85415
- request.intent === "create" ? "\u2717 \u65B0\u5EFA\u4F1A\u8BDD\u5931\u8D25\uFF08\u5F53\u524D\u4F1A\u8BDD\u4FDD\u6301\u53EF\u7528\uFF09" : `\u2717 \u5207\u6362\u5931\u8D25\uFF1A${errorReason(primaryError)}\uFF08\u5F53\u524D\u4F1A\u8BDD\u4FDD\u6301\u53EF\u7528\uFF09`
85416
- );
85745
+ if (request.intent === "create") {
85746
+ this.setFeedback(
85747
+ isSessionWriterHeld(primaryError) ? `\u2717 \u65B0\u5EFA\u4F1A\u8BDD\u5931\u8D25\uFF1A${SESSION_WRITER_HELD_COPY}\uFF08\u5F53\u524D\u4F1A\u8BDD\u4FDD\u6301\u53EF\u7528\uFF09` : "\u2717 \u65B0\u5EFA\u4F1A\u8BDD\u5931\u8D25\uFF08\u5F53\u524D\u4F1A\u8BDD\u4FDD\u6301\u53EF\u7528\uFF09"
85748
+ );
85749
+ } else {
85750
+ this.setFeedback(`\u2717 \u5207\u6362\u5931\u8D25\uFF1A${terminalErrorReason(primaryError)}\uFF08\u5F53\u524D\u4F1A\u8BDD\u4FDD\u6301\u53EF\u7528\uFF09`);
85751
+ }
85417
85752
  return;
85418
85753
  }
85419
85754
  if (previous3.liveHandle !== void 0) {
@@ -85426,17 +85761,6 @@ var RuntimeController = class _RuntimeController {
85426
85761
  }
85427
85762
  }
85428
85763
  if (previous3.session !== void 0) {
85429
- const events = getSessionEvents(previous3.session);
85430
- if (isSessionEmpty(events)) {
85431
- const persistence = this.ctx.get("sessionPersistence");
85432
- if (persistence !== void 0 && typeof persistence.delete === "function") {
85433
- try {
85434
- await persistence.delete(previous3.session.id);
85435
- } catch (error51) {
85436
- this.ctx.logger.warn(`failed to delete empty session "${previous3.session.id}": ${errorReason(error51)}`);
85437
- }
85438
- }
85439
- }
85440
85764
  this.sessionRowCache.delete(previous3.session.id);
85441
85765
  }
85442
85766
  if (this.session !== void 0) {
@@ -85530,6 +85854,7 @@ var RuntimeController = class _RuntimeController {
85530
85854
  };
85531
85855
  this.session = agent.session;
85532
85856
  this.projector = candidate.projector;
85857
+ this.hydrateWorkspaceChangeCards();
85533
85858
  this.modelSelectionRef = candidate.modelSelectionRef;
85534
85859
  this.badge = candidate.badge;
85535
85860
  this.machine = "idle";
@@ -86872,7 +87197,7 @@ var RuntimeController = class _RuntimeController {
86872
87197
  if (uncached.length > 0) {
86873
87198
  const BATCH_SIZE = 16;
86874
87199
  for (let i = 0; i < uncached.length; i += BATCH_SIZE) {
86875
- if (this.closed) return;
87200
+ if (this.isClosed()) return;
86876
87201
  const batch = uncached.slice(i, i + BATCH_SIZE);
86877
87202
  const fetched = await Promise.all(
86878
87203
  batch.map(async ({ id, revision }) => {
@@ -86883,7 +87208,7 @@ var RuntimeController = class _RuntimeController {
86883
87208
  for (const entry of fetched) {
86884
87209
  this.sessionRowCache.set(entry.id, { row: entry.row, revision: entry.revision, isEmpty: entry.isEmpty });
86885
87210
  }
86886
- if (!this.closed) {
87211
+ if (!this.isClosed()) {
86887
87212
  const updatedRows = [];
86888
87213
  for (const item of interactiveItems) {
86889
87214
  const header = item.header ?? item;
@@ -86971,7 +87296,7 @@ var RuntimeController = class _RuntimeController {
86971
87296
  id,
86972
87297
  title: listTitleOf(events),
86973
87298
  updatedAt: events.at(-1)?.time ?? createdAt,
86974
- isEmpty: isSessionEmpty(events)
87299
+ isEmpty: isSessionEmpty(events, id)
86975
87300
  };
86976
87301
  } catch {
86977
87302
  return { id, title: id, updatedAt: 0, isEmpty: true };
@@ -87479,10 +87804,11 @@ function isBootstrapOnlySession(events) {
87479
87804
  if (!Array.isArray(events) || events.length === 0) return false;
87480
87805
  return events.every((event) => typeof event.type === "string" && BOOTSTRAP_ONLY_TYPES.has(event.type));
87481
87806
  }
87482
- function isSessionEmpty(events) {
87483
- if (!Array.isArray(events) || events.length === 0) return false;
87484
- if (isBootstrapOnlySession(events)) return true;
87485
- return !events.some(isHumanUserMessage) && foldTitle(events) === void 0;
87807
+ function isSessionEmpty(events, id) {
87808
+ if (id !== void 0 && id.includes("probe")) {
87809
+ return isBootstrapOnlySession(events);
87810
+ }
87811
+ return false;
87486
87812
  }
87487
87813
  function planReviewOf(questions) {
87488
87814
  if (questions.length !== 1) return void 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crazyhappyone/dsh-tui",
3
- "version": "0.1.0-alpha.46",
3
+ "version": "0.1.0-alpha.48",
4
4
  "description": "Source-runtime launcher for the DeepSeek Harness terminal interface",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -5,7 +5,9 @@
5
5
  # terminal driver creates an Agent through the core registry and prints its
6
6
  # durable result. Unlike the web surface, the agent plane stays process-wide:
7
7
  # dsh-base keeps tool-bash/tool-fs/tool-todo and friends because the TUI is
8
- # single-session and composes its agent process-wide.
8
+ # single-session and composes its agent process-wide. Insert and config rows
9
+ # resolve through the 0.1.6-alpha.2 runtime Loader; this file is not a
10
+ # compile-time plugin graph.
9
11
 
10
12
  - id: system-prompt
11
13
  config:
@@ -42,43 +44,25 @@
42
44
  path: ':memory:'
43
45
  openAt: first-search
44
46
 
47
+ # Inherit the 0.1.6-alpha.2 llm-deepseek DEFAULT_MODELS catalog
48
+ # (`deepseek-flash`, `deepseek-v4-pro`). Do not re-list removed V4 Flash
49
+ # / V4 Flash Vision Exp ids here. Protocol stays Messages unless a PTY
50
+ # snapshot sets DSH_LLM_PROTOCOL=chat-completions for the mock server.
45
51
  - id: llm-deepseek
46
52
  config:
47
- models:
48
- - id: deepseek-v4-flash
49
- name: DeepSeek-V4-Flash
50
- description: >-
51
- Fast, efficient, and economical; suited to focused, routine,
52
- or parallel tasks.
53
- contextWindow: 1000000
54
- - id: deepseek-v4-pro
55
- name: DeepSeek-V4-Pro
56
- description: >-
57
- Stronger agentic coding, knowledge, and difficult reasoning;
58
- suited to complex or quality-critical tasks at higher cost.
59
- contextWindow: 1000000
60
- - id: deepseek-v4-flash-vision-exp
61
- name: DeepSeek-V4-Flash-Vision-Exp
62
- contextWindow: 1000000
63
- inputModalities: [text, image]
64
- - id: deepseek-v4.1-flash-expires-on-0910
65
- name: DeepSeek-V4.1-Flash
66
- description: >-
67
- DeepSeek V4.1 Flash intermediate beta with native multimodal
68
- support, higher capability, faster speed, and lower cost.
69
- contextWindow: 1000000
70
- inputModalities: [text, image]
53
+ # pi-lens-ignore: YAML:0
54
+ protocol: !!js "process.env.DSH_LLM_PROTOCOL ?? 'messages'"
71
55
 
72
56
  - id: agent-default-model
73
57
  config:
74
58
  # pi-lens-ignore: YAML:0
75
59
  provider: deepseek-official
76
60
  # pi-lens-ignore: YAML:0
77
- model: !!js "process.env.DSH_MODEL ?? 'deepseek-v4-flash'"
61
+ model: !!js "process.env.DSH_MODEL ?? 'deepseek-flash'"
78
62
 
79
63
  # pi-lens-ignore: YAML:0
80
64
  - id: session-title-llm
81
- name: "@deepseek-ai/dsh-session-title-all-prompts-llm"
65
+ name: "@deepseek-ai/dsh-session-title-first-prompt-llm"
82
66
  config:
83
67
  targetWords: 5
84
68
  targetCjkCharacters: 10
@@ -125,6 +109,18 @@
125
109
  host: 127.0.0.1
126
110
  port: 4097
127
111
 
112
+ # Records each top-level turn's changed files from git working-tree
113
+ # snapshots; the TUI projects a bounded transcript card from Host
114
+ # summaries. Bounds match the plugin Config defaults.
115
+ - id: workspace-changes
116
+ name: '@deepseek-ai/dsh-workspace-changes'
117
+ config:
118
+ timeoutMs: 30000
119
+ outputMaxBytes: 8388608
120
+ maxFiles: 500
121
+ maxFileBytes: 2097152
122
+ diffTimeoutMs: 100
123
+
128
124
  # Reads its task from the ordinary tuiStartup provider.
129
125
  - id: tui-runtime
130
126
  # pi-lens-ignore: YAML:0