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

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
  }
@@ -59557,6 +59625,25 @@ function producedPathsForTurn(cards) {
59557
59625
  return paths;
59558
59626
  }
59559
59627
 
59628
+ // packages/tui/tui-render/src/workspace-changes-card.ts
59629
+ var WORKSPACE_CHANGES_CARD_PATH_LIMIT = 3;
59630
+ function workspaceChangeCountsLabel(file2) {
59631
+ if (file2.binary === true) return "binary";
59632
+ if (file2.oversized === true) return "oversized";
59633
+ return `+${String(file2.added)}/\u2212${String(file2.deleted)}`;
59634
+ }
59635
+ function formatWorkspaceChangesCard(card, pathLimit = WORKSPACE_CHANGES_CARD_PATH_LIMIT) {
59636
+ if (card.files.length === 0) return void 0;
59637
+ const shown = card.files.slice(0, Math.max(0, pathLimit));
59638
+ const lines = [
59639
+ `\u6539\u52A8 \xB7 ${String(card.total)} \u4E2A\u6587\u4EF6 +${String(card.added)}/\u2212${String(card.deleted)}`,
59640
+ ...shown.map((file2) => ` ${file2.display} ${workspaceChangeCountsLabel(file2)}`)
59641
+ ];
59642
+ const hidden = card.total - shown.length;
59643
+ if (hidden > 0) lines.push(` \u2026 +${String(hidden)} \u4E2A\u6587\u4EF6`);
59644
+ return lines;
59645
+ }
59646
+
59560
59647
  // packages/tui/tui-render/src/stream-view.tsx
59561
59648
  import { pathToFileURL as pathToFileURL2 } from "node:url";
59562
59649
  import { isAbsolute as isAbsolute3 } from "node:path";
@@ -74038,6 +74125,12 @@ function projectCompactionEntry(entry, scope) {
74038
74125
  }
74039
74126
  function projectTurnTailEntry(entry, scope) {
74040
74127
  const lines = [];
74128
+ const changeLines = entry.meta?.turnTailWorkspaceChanges === void 0 ? void 0 : formatWorkspaceChangesCard(entry.meta.turnTailWorkspaceChanges);
74129
+ if (changeLines !== void 0) {
74130
+ for (const text4 of changeLines) {
74131
+ lines.push(lineForText(escapeContent(text4), "fg", false, lines.length));
74132
+ }
74133
+ }
74041
74134
  const produced = entry.meta?.turnTailProduced ?? [];
74042
74135
  if (produced.length > 0) {
74043
74136
  const joined = produced.map(escapeContent).join(" \xB7 ");
@@ -75880,7 +75973,8 @@ function StreamView({
75880
75973
  );
75881
75974
  const produced = producedPathsForTurn(cards);
75882
75975
  return produced.length === 0 ? {} : { turnTailProduced: produced };
75883
- })()
75976
+ })(),
75977
+ ...row.message.workspaceChanges === void 0 ? {} : { turnTailWorkspaceChanges: row.message.workspaceChanges }
75884
75978
  };
75885
75979
  if (Object.keys(tailMeta).length > 0) {
75886
75980
  rows2.push(GAP_LINE);
@@ -76749,13 +76843,14 @@ function StreamView({
76749
76843
  (card) => presenterCache.present(presenters, card)
76750
76844
  );
76751
76845
  const produced = producedPathsForTurn(cards);
76846
+ const changeLines = message.workspaceChanges === void 0 ? void 0 : formatWorkspaceChangesCard(message.workspaceChanges);
76752
76847
  const stats = formatTurnTailStats({
76753
76848
  turnOrdinal: message.turnOrdinal,
76754
76849
  turnUsage: message.turnUsage,
76755
76850
  legacyOutputTokens: message.usageOutputTokens,
76756
76851
  elapsedMs: message.stepWallMs
76757
76852
  });
76758
- if (produced.length === 0 && stats === void 0 && !showCompletionBoundary) return void 0;
76853
+ if (produced.length === 0 && changeLines === void 0 && stats === void 0 && !showCompletionBoundary) return void 0;
76759
76854
  const producedRows = [];
76760
76855
  let rowRuns = [styled("\u4EA7\u7269 \xB7 ", "fg")];
76761
76856
  let rowWidth = displayWidth("\u4EA7\u7269 \xB7 ");
@@ -76779,6 +76874,7 @@ function StreamView({
76779
76874
  }
76780
76875
  if (pathsInRow > 0) producedRows.push(rowRuns);
76781
76876
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", width: "100%", children: [
76877
+ (changeLines ?? []).map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: paintRow([styled(escapeContent(line5), "fg")]) }, `changes-${String(index2)}`)),
76782
76878
  producedRows.map((runs, index2) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: paintRow(runs) }, `produced-${String(index2)}`)),
76783
76879
  stats === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: paintRow([styled(escapeContent(stats), "fgDim")]) }),
76784
76880
  showCompletionBoundary ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: paintRow([styled("\u2500\u2500 \u5DF2\u5B8C\u6210 \u2500\u2500", "fgDim")]) }) : null
@@ -77586,14 +77682,29 @@ function hubRow(row, selected) {
77586
77682
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintRow([styled(escapeContent(`\u5B50\u4F1A\u8BDD ID \xB7 ${row.id}`), "fgDim")]) })
77587
77683
  ] }, row.id);
77588
77684
  }
77685
+ function hubLimitsFootnote(liveContinuable, maxActiveSubagents, maxDepth) {
77686
+ if (maxActiveSubagents === void 0 && maxDepth === void 0) {
77687
+ return void 0;
77688
+ }
77689
+ const live = liveContinuable ?? 0;
77690
+ const max = maxActiveSubagents ?? 8;
77691
+ const depth = maxDepth ?? 1;
77692
+ const base = `\u53EF\u7EE7\u7EED ${String(live)}/${String(max)} live \xB7 \u6DF1\u5EA6 ${String(depth)}`;
77693
+ return live >= max ? `${base} \xB7 \u5DF2\u8FBE\u4E0A\u9650` : base;
77694
+ }
77589
77695
  function AgentHubPane({
77590
77696
  rows = [],
77591
77697
  selectedIndex = 0,
77592
77698
  view = "table",
77593
77699
  error: error51,
77594
77700
  transcript,
77595
- missing = false
77701
+ missing = false,
77702
+ liveContinuable,
77703
+ maxActiveSubagents,
77704
+ maxDepth,
77705
+ scrollOffset
77596
77706
  }) {
77707
+ const limits = hubLimitsFootnote(liveContinuable, maxActiveSubagents, maxDepth);
77597
77708
  if (missing) {
77598
77709
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
77599
77710
  OverlayShell,
@@ -77604,6 +77715,7 @@ function AgentHubPane({
77604
77715
  }
77605
77716
  );
77606
77717
  }
77718
+ const clamped = Math.min(Math.max(selectedIndex, 0), Math.max(0, rows.length - 1));
77607
77719
  if (view === "transcript") {
77608
77720
  if (error51 !== void 0 && error51 !== "") {
77609
77721
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
@@ -77616,7 +77728,39 @@ function AgentHubPane({
77616
77728
  );
77617
77729
  }
77618
77730
  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)) });
77731
+ const selectedRow = rows[clamped];
77732
+ const headerSegments = selectedRow === void 0 ? [] : [
77733
+ `[\u5B50\u4EE3\u7406] ${selectedRow.label}`,
77734
+ selectedRow.activity === "" ? void 0 : `\u72B6\u6001: ${selectedRow.activity}`,
77735
+ ...metricSegments(selectedRow)
77736
+ ].filter((s) => s !== void 0);
77737
+ const total = lines.length;
77738
+ const pageSize = 20;
77739
+ const start = Math.min(scrollOffset ?? 0, Math.max(0, total - 1));
77740
+ const slice = lines.slice(start, start + pageSize);
77741
+ const scrollInfo = total > pageSize ? ` (${String(start + 1)}-${String(Math.min(start + slice.length, total))}/${String(total)})` : "";
77742
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
77743
+ OverlayShell,
77744
+ {
77745
+ title: "\u5B50\u4EE3\u7406",
77746
+ footnote: `\u2191\u2193/jk \u6EDA\u52A8${scrollInfo} \xB7 Esc \u8FD4\u56DE`,
77747
+ children: [
77748
+ headerSegments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Box_default, { width: "100%", flexDirection: "column", marginY: 0, children: [
77749
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintRow([styled(escapeContent(headerSegments.join(" \xB7 ")), "accent", void 0, true)]) }),
77750
+ selectedRow?.id && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintRow([styled(escapeContent(`\u5B50\u4F1A\u8BDD ID \xB7 ${selectedRow.id}`), "fgDim")]) }),
77751
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintRow([styled(escapeContent("\u2500\u2500\u2500 \u6267\u884C\u60C5\u51B5 \u2500\u2500\u2500"), "fgDim")]) })
77752
+ ] }),
77753
+ slice.map((lineText, index2) => {
77754
+ const isUser = lineText.startsWith("> ");
77755
+ const isTool = lineText.startsWith("\u25B8 ");
77756
+ const isResult = lineText.startsWith(" \u2514\u2500 ") || lineText.startsWith("\u2514\u2500 ");
77757
+ const isTurn = lineText.startsWith("\u2500\u2500 ");
77758
+ const token = isUser ? "accent" : isTool ? "codeKeyword" : isResult ? "fgDim" : isTurn ? "fgDim" : "fg";
77759
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintRow([styled(escapeContent(lineText), token)]) }, start + index2);
77760
+ })
77761
+ ]
77762
+ }
77763
+ );
77620
77764
  }
77621
77765
  if (error51 !== void 0 && error51 !== "") {
77622
77766
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
@@ -77624,7 +77768,7 @@ function AgentHubPane({
77624
77768
  {
77625
77769
  title: "\u5B50\u4EE3\u7406",
77626
77770
  error: error51,
77627
- footnote: "Esc \u5173\u95ED \xB7 \u53EF\u91CD\u8BD5"
77771
+ footnote: limits === void 0 ? "Esc \u5173\u95ED \xB7 \u53EF\u91CD\u8BD5" : `${limits} \xB7 Esc \u5173\u95ED \xB7 \u53EF\u91CD\u8BD5`
77628
77772
  }
77629
77773
  );
77630
77774
  }
@@ -77634,16 +77778,15 @@ function AgentHubPane({
77634
77778
  {
77635
77779
  title: "\u5B50\u4EE3\u7406",
77636
77780
  body: "\u6682\u65E0\u5B50\u4EE3\u7406",
77637
- footnote: "Esc \u5173\u95ED \xB7 \u6709\u8FD0\u884C\u4E2D\u7684\u5B50\u4EE3\u7406\u65F6\u518D\u6253\u5F00"
77781
+ 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
77782
  }
77639
77783
  );
77640
77784
  }
77641
- const clamped = Math.min(Math.max(selectedIndex, 0), rows.length - 1);
77642
77785
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
77643
77786
  OverlayShell,
77644
77787
  {
77645
77788
  title: "\u5B50\u4EE3\u7406",
77646
- footnote: "j/k \u9009\u62E9 \xB7 Enter \u67E5\u770B \xB7 Esc \u5173\u95ED",
77789
+ 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
77790
  children: [
77648
77791
  rows.map((row, index2) => hubRow(row, index2 === clamped)),
77649
77792
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintRow([styled(escapeContent(aggregateLine(rows)), "fgDim")]) })
@@ -80794,7 +80937,11 @@ function TuiLoop({
80794
80937
  view: agentHubPane.view,
80795
80938
  error: agentHubPane.error,
80796
80939
  transcript: agentHubPane.transcript,
80797
- missing: agentHubPane.missing
80940
+ missing: agentHubPane.missing,
80941
+ liveContinuable: agentHubPane.liveContinuable,
80942
+ maxActiveSubagents: agentHubPane.maxActiveSubagents,
80943
+ maxDepth: agentHubPane.maxDepth,
80944
+ scrollOffset: agentHubPane.scrollOffset
80798
80945
  });
80799
80946
  } else if (planDirectoryPane.open) {
80800
80947
  content3 = (0, import_react39.createElement)(PlanDirectoryPane, {
@@ -81220,14 +81367,26 @@ function formatTurnError(error51) {
81220
81367
  if (code2 === "MISSING_CREDENTIAL" || rawMessage.includes("DEEPSEEK_API_KEY") || rawMessage.includes("MISSING_CREDENTIAL") || rawMessage.includes("no API key")) {
81221
81368
  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
81369
  }
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`;
81370
+ if (rawMessage.includes("reading 'prepare'") || rawMessage.includes('reading "prepare"')) {
81371
+ 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`;
81225
81372
  }
81226
- if (status === 429 || code2 === "RATE_LIMIT" || rawMessage.includes("429") || rawMessage.toLowerCase().includes("quota") || rawMessage.toLowerCase().includes("rate limit")) {
81373
+ const lowered = rawMessage.toLowerCase();
81374
+ const antigravity = lowered.includes("antigravity") || rawMessage.includes("/anti");
81375
+ if (code2 === "TIMEOUT" || lowered.includes("timed out") || lowered.includes("timeout") || lowered.includes("stalled") || rawMessage.includes("ETIMEDOUT")) {
81376
+ 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`;
81377
+ }
81378
+ if (status === 429 || code2 === "RATE_LIMIT" || rawMessage.includes("429") || lowered.includes("quota") || lowered.includes("rate limit")) {
81227
81379
  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
81380
  }
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`;
81381
+ 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")) {
81382
+ 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`;
81383
+ }
81384
+ if (antigravity) {
81385
+ 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;
81386
+ 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`;
81387
+ }
81388
+ if (status === 401 || code2 === "AUTH" || rawMessage.includes("401") || lowered.includes("authentication fails") || lowered.includes("invalid api key") || lowered.includes("unauthorized")) {
81389
+ 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
81390
  }
81232
81391
  return `\u26A0\uFE0F **\u6A21\u578B\u8BF7\u6C42\u5931\u8D25**\uFF1A${rawMessage}`;
81233
81392
  }
@@ -81476,14 +81635,27 @@ ${formattedError}` });
81476
81635
  status = "idle";
81477
81636
  return;
81478
81637
  }
81479
- default:
81638
+ default: {
81639
+ if (event.type === "workspace/changes") {
81640
+ const turn = event.data.turn;
81641
+ if (typeof turn === "number") {
81642
+ for (let i = history.length - 1; i >= 0; i--) {
81643
+ const row = history[i];
81644
+ if (row !== void 0 && row.kind === "assistant" && row.turnOrdinal === turn) {
81645
+ history[i] = { ...row, workspaceChangesSeq: event.seq };
81646
+ break;
81647
+ }
81648
+ }
81649
+ }
81650
+ }
81480
81651
  return;
81652
+ }
81481
81653
  }
81482
81654
  }
81483
81655
  return {
81484
81656
  push: push3,
81485
81657
  seed(events) {
81486
- if (!events || typeof events[Symbol.iterator] !== "function") return;
81658
+ if (!events || !Array.isArray(events)) return;
81487
81659
  for (const event of events) push3(event);
81488
81660
  },
81489
81661
  snapshot() {
@@ -81764,7 +81936,8 @@ var LEADING_NAMESPACES = [
81764
81936
  "llm-deepseek",
81765
81937
  "llm-openai",
81766
81938
  "llm-anthropic",
81767
- "llm-pi-ai"
81939
+ "llm-pi-ai",
81940
+ "subagent"
81768
81941
  ];
81769
81942
  var BRAND_ANIMATION_LABELS = {
81770
81943
  auto: "\u81EA\u52A8",
@@ -82501,6 +82674,9 @@ function transitionStatusText(state) {
82501
82674
  function errorReason(error51) {
82502
82675
  return error51 instanceof Error ? error51.message : String(error51);
82503
82676
  }
82677
+ function terminalErrorReason(error51) {
82678
+ return userErrorReason(error51);
82679
+ }
82504
82680
  function fieldOf(section, field) {
82505
82681
  if (typeof section !== "object" || section === null || Array.isArray(section)) {
82506
82682
  return void 0;
@@ -82606,6 +82782,18 @@ function hubTranscriptOf(events) {
82606
82782
  if (text5 !== "") lines.push(`> ${text5}`);
82607
82783
  continue;
82608
82784
  }
82785
+ if (event.type === "tool/call") {
82786
+ const args = typeof event.data.arguments === "string" ? event.data.arguments : JSON.stringify(event.data.arguments);
82787
+ const shortArgs = args.length > 80 ? `${args.slice(0, 77)}...` : args;
82788
+ lines.push(`\u25B8 ${event.data.name} ${shortArgs}`);
82789
+ continue;
82790
+ }
82791
+ if (event.type === "tool/result") {
82792
+ const text5 = joinTextBlocks(event.data.message.content, "");
82793
+ const shortText = text5.length > 80 ? `${text5.slice(0, 77).replace(/\n/g, " ")}...` : text5.replace(/\n/g, " ");
82794
+ if (shortText !== "") lines.push(` \u2514\u2500 ${shortText}`);
82795
+ continue;
82796
+ }
82609
82797
  if (event.type !== "assistant/message") continue;
82610
82798
  const text4 = joinTextBlocks(event.data.message.content, "");
82611
82799
  if (text4 !== "") lines.push(`\u25CF ${text4}`);
@@ -82649,6 +82837,10 @@ var RuntimeController = class _RuntimeController {
82649
82837
  this.disposeSessionEvents = ctx.on("session/event", (session, event) => {
82650
82838
  if (session !== this.liveHandle?.agent.session) return;
82651
82839
  this.projector.push(event);
82840
+ if (event.type === "workspace/changes") this.cacheWorkspaceChange(event.seq);
82841
+ if (this.agentHubOpen && (event.type === "subagent/catalog" || event.type === "subagent/descriptor")) {
82842
+ this.ownWork(this.refreshAgentHub(), "agent hub list");
82843
+ }
82652
82844
  if (event.type === "turn/start") {
82653
82845
  this.reduce({ kind: "turn-started" }, void 0, void 0);
82654
82846
  } else if (event.type === "llm/retry") {
@@ -82801,12 +82993,17 @@ var RuntimeController = class _RuntimeController {
82801
82993
  /** Idempotent quiescent controller teardown. */
82802
82994
  disposeInFlight;
82803
82995
  closed = false;
82996
+ isClosed() {
82997
+ return this.closed;
82998
+ }
82804
82999
  machine = "idle";
82805
83000
  /** Durable retry wait currently visible in the footer. */
82806
83001
  retryFooter;
82807
83002
  /** Single bounded refresh timer while {@link retryFooter} is visible. */
82808
83003
  retryFooterTimer;
82809
83004
  projector = createProjector();
83005
+ /** Host `workspace/changes` cards keyed by announcing event sequence. */
83006
+ workspaceChangeCards = /* @__PURE__ */ new Map();
82810
83007
  presentationOverrides = /* @__PURE__ */ new Map();
82811
83008
  presentationWrites = Promise.resolve();
82812
83009
  toolCardsExpanded = false;
@@ -82891,6 +83088,7 @@ var RuntimeController = class _RuntimeController {
82891
83088
  agentHubView = "table";
82892
83089
  agentHubError;
82893
83090
  agentHubTranscript;
83091
+ agentHubScrollOffset = 0;
82894
83092
  /** Monotonic listing/inspect id: only the newest Hub request may land. */
82895
83093
  agentHubSeq = 0;
82896
83094
  /** Cancellation owner for the newest Hub list, fold, expansion, or inspect. */
@@ -83091,6 +83289,7 @@ var RuntimeController = class _RuntimeController {
83091
83289
  const model = this.projector.snapshot();
83092
83290
  this.modelSnapshot = {
83093
83291
  ...model,
83292
+ history: this.decorateWorkspaceChanges(model.history),
83094
83293
  reasoningExpanded: this.presentationFlag("reasoning"),
83095
83294
  toolCardsExpanded: this.toolCardsExpanded,
83096
83295
  expandedCompactionId: this.expandedCompactionId,
@@ -83099,6 +83298,55 @@ var RuntimeController = class _RuntimeController {
83099
83298
  }
83100
83299
  return this.modelSnapshot;
83101
83300
  }
83301
+ /**
83302
+ * Attach cached Host summaries onto frozen assistant turns.
83303
+ * @param history - projector history.
83304
+ * @returns history with `workspaceChanges` filled when a card exists.
83305
+ */
83306
+ decorateWorkspaceChanges(history) {
83307
+ if (this.workspaceChangeCards.size === 0) return history;
83308
+ return history.map((row) => {
83309
+ if (row.kind !== "assistant" || row.workspaceChangesSeq === void 0) return row;
83310
+ const card = this.workspaceChangeCards.get(row.workspaceChangesSeq);
83311
+ return card === void 0 ? row : { ...row, workspaceChanges: card };
83312
+ });
83313
+ }
83314
+ /**
83315
+ * Read one announcing event's Host summary into the transcript card cache.
83316
+ * Empty or abandoned records drop any earlier card for that sequence.
83317
+ * @param seq - `workspace/changes` event sequence.
83318
+ */
83319
+ cacheWorkspaceChange(seq) {
83320
+ const sessionId = this.session?.id;
83321
+ const service = this.ctx.get("workspaceChanges");
83322
+ const summary = sessionId === void 0 || service === void 0 ? void 0 : service.summary(sessionId, seq);
83323
+ const card = workspaceChangesCardFromSummary(seq, summary);
83324
+ if (card === void 0) this.workspaceChangeCards.delete(seq);
83325
+ else this.workspaceChangeCards.set(seq, card);
83326
+ }
83327
+ /** Replay Host summaries for every `workspace/changes` event on the bound Session. */
83328
+ hydrateWorkspaceChangeCards() {
83329
+ this.workspaceChangeCards.clear();
83330
+ const session = this.session;
83331
+ if (session === void 0) return;
83332
+ for (const event of getSessionEvents(session)) {
83333
+ if (event.type === "workspace/changes") this.cacheWorkspaceChange(event.seq);
83334
+ }
83335
+ }
83336
+ /**
83337
+ * Continuable defaults from live settings, never a stale Hub cache.
83338
+ * @returns max live children (8) and max depth (1) unless the user raised them.
83339
+ */
83340
+ subagentLimits() {
83341
+ const settings = this.ctx.get("settings");
83342
+ const section = settings === void 0 ? void 0 : settings.get("subagent");
83343
+ const maxActive = fieldOf(section, "maxActiveSubagents");
83344
+ const maxDepth = fieldOf(section, "maxDepth");
83345
+ return {
83346
+ maxActiveSubagents: typeof maxActive === "number" ? maxActive : 8,
83347
+ maxDepth: typeof maxDepth === "number" ? maxDepth : 1
83348
+ };
83349
+ }
83102
83350
  /**
83103
83351
  * Return the interaction state.
83104
83352
  * @returns the current interaction state.
@@ -83346,17 +83594,25 @@ var RuntimeController = class _RuntimeController {
83346
83594
  */
83347
83595
  getAgentHubPane() {
83348
83596
  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
- };
83597
+ const limits = this.subagentLimits();
83598
+ const liveContinuable = this.agentHubRows.filter((row) => row.activity === "running").length;
83599
+ const cached2 = this.agentHubPaneSnapshot;
83600
+ 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) {
83601
+ return cached2;
83359
83602
  }
83603
+ this.agentHubPaneSnapshot = {
83604
+ open: true,
83605
+ rows: this.agentHubRows,
83606
+ selectedIndex: this.agentHubSelectedIndex,
83607
+ view: this.agentHubView,
83608
+ missing: this.ctx.get("subagents") === void 0,
83609
+ liveContinuable,
83610
+ scrollOffset: this.agentHubScrollOffset,
83611
+ maxActiveSubagents: limits.maxActiveSubagents,
83612
+ maxDepth: limits.maxDepth,
83613
+ ...this.agentHubError === void 0 ? {} : { error: this.agentHubError },
83614
+ ...this.agentHubTranscript === void 0 ? {} : { transcript: this.agentHubTranscript }
83615
+ };
83360
83616
  return this.agentHubPaneSnapshot;
83361
83617
  }
83362
83618
  /**
@@ -83496,6 +83752,34 @@ var RuntimeController = class _RuntimeController {
83496
83752
  if (fs3 === void 0) return;
83497
83753
  const seq = this.workspaceSeq;
83498
83754
  try {
83755
+ const change = lookupWorkspaceChange(
83756
+ this.workspaceChangeCards,
83757
+ row.target.displayPath
83758
+ ) ?? lookupWorkspaceChange(this.workspaceChangeCards, row.name);
83759
+ if (change !== void 0) {
83760
+ const sessionId = this.session?.id;
83761
+ const service = this.ctx.get("workspaceChanges");
83762
+ if (sessionId === void 0 || service === void 0) {
83763
+ this.setFeedback(`\u2717 ${SESSION_CHANGES_DISPOSED_COPY}`);
83764
+ return;
83765
+ }
83766
+ const diff2 = await service.diff(sessionId, change.seq, change.index, this.lifecycleAbort.signal);
83767
+ if (seq !== this.workspaceSeq || !this.workspaceOpen) return;
83768
+ const preview = formatWorkspaceChangeDiffPreview(diff2);
83769
+ if (preview === void 0) {
83770
+ this.setFeedback(`\u2717 ${SESSION_CHANGES_DISPOSED_COPY}`);
83771
+ return;
83772
+ }
83773
+ this.workspacePreview = {
83774
+ path: row.target.displayPath,
83775
+ name: row.name,
83776
+ lines: [...preview],
83777
+ scrollOffset: 0
83778
+ };
83779
+ this.workspacePaneSnapshot = void 0;
83780
+ this.emit();
83781
+ return;
83782
+ }
83499
83783
  const text4 = await fs3.readText(row.target);
83500
83784
  if (seq !== this.workspaceSeq || !this.workspaceOpen) return;
83501
83785
  const lines = text4.split(/\r?\n/u);
@@ -84048,7 +84332,9 @@ var RuntimeController = class _RuntimeController {
84048
84332
  this.agentHubView = "table";
84049
84333
  this.agentHubError = void 0;
84050
84334
  this.agentHubTranscript = void 0;
84335
+ this.agentHubScrollOffset = 0;
84051
84336
  this.agentHubSeq += 1;
84337
+ this.agentHubPaneSnapshot = void 0;
84052
84338
  }
84053
84339
  /**
84054
84340
  * Cancel the prior Hub read and start one request tied to controller teardown.
@@ -84075,6 +84361,7 @@ var RuntimeController = class _RuntimeController {
84075
84361
  this.agentHubError = void 0;
84076
84362
  this.agentHubRows = [];
84077
84363
  this.agentHubSelectedIndex = 0;
84364
+ this.agentHubPaneSnapshot = void 0;
84078
84365
  this.emit();
84079
84366
  const subagents = this.ctx.get("subagents");
84080
84367
  if (subagents === void 0 || this.session === void 0) return;
@@ -84084,11 +84371,14 @@ var RuntimeController = class _RuntimeController {
84084
84371
  if (!this.agentHubOpen || seq !== this.agentHubSeq) return;
84085
84372
  this.agentHubRows = rows;
84086
84373
  this.agentHubError = void 0;
84374
+ this.agentHubPaneSnapshot = void 0;
84375
+ this.agentHubError = void 0;
84087
84376
  this.emit();
84088
84377
  } catch (error51) {
84089
84378
  if (!this.agentHubOpen || seq !== this.agentHubSeq) return;
84090
84379
  this.agentHubRows = [];
84091
84380
  this.agentHubError = `\u65E0\u6CD5\u5217\u51FA\u5B50\u4EE3\u7406\uFF1A${errorReason(error51)}`;
84381
+ this.agentHubPaneSnapshot = void 0;
84092
84382
  this.emit();
84093
84383
  }
84094
84384
  }
@@ -84107,10 +84397,12 @@ var RuntimeController = class _RuntimeController {
84107
84397
  this.agentHubRows = rows;
84108
84398
  this.agentHubSelectedIndex = 0;
84109
84399
  this.agentHubError = void 0;
84400
+ this.agentHubPaneSnapshot = void 0;
84110
84401
  this.emit();
84111
84402
  } catch (error51) {
84112
84403
  if (!this.agentHubOpen || seq !== this.agentHubSeq) return;
84113
84404
  this.agentHubError = `\u65E0\u6CD5\u5217\u51FA\u5B50\u4EE3\u7406\uFF1A${errorReason(error51)}`;
84405
+ this.agentHubPaneSnapshot = void 0;
84114
84406
  this.emit();
84115
84407
  }
84116
84408
  }
@@ -84198,6 +84490,8 @@ var RuntimeController = class _RuntimeController {
84198
84490
  this.agentHubView = "transcript";
84199
84491
  this.agentHubTranscript = void 0;
84200
84492
  this.agentHubError = void 0;
84493
+ this.agentHubScrollOffset = 0;
84494
+ this.agentHubPaneSnapshot = void 0;
84201
84495
  this.emit();
84202
84496
  const persistence = this.ctx.get("sessionPersistence");
84203
84497
  if (persistence === void 0) {
@@ -84222,10 +84516,13 @@ var RuntimeController = class _RuntimeController {
84222
84516
  if (!this.agentHubOpen || seq !== this.agentHubSeq) return;
84223
84517
  this.agentHubTranscript = hubTranscriptOf(events);
84224
84518
  this.agentHubError = void 0;
84519
+ this.agentHubPaneSnapshot = void 0;
84520
+ this.agentHubError = void 0;
84225
84521
  this.emit();
84226
84522
  } catch (error51) {
84227
84523
  if (!this.agentHubOpen || seq !== this.agentHubSeq) return;
84228
84524
  this.agentHubError = `\u65E0\u6CD5\u8BFB\u53D6\u5B50\u4F1A\u8BDD\uFF1A${errorReason(error51)}`;
84525
+ this.agentHubPaneSnapshot = void 0;
84229
84526
  this.emit();
84230
84527
  }
84231
84528
  }
@@ -84541,6 +84838,8 @@ var RuntimeController = class _RuntimeController {
84541
84838
  this.agentHubView = "table";
84542
84839
  this.agentHubTranscript = void 0;
84543
84840
  this.agentHubError = void 0;
84841
+ this.agentHubScrollOffset = 0;
84842
+ this.agentHubPaneSnapshot = void 0;
84544
84843
  this.emit();
84545
84844
  return;
84546
84845
  }
@@ -84549,12 +84848,19 @@ var RuntimeController = class _RuntimeController {
84549
84848
  this.emit();
84550
84849
  return;
84551
84850
  case "agent-hub-move":
84552
- if (!this.agentHubOpen || this.agentHubView !== "table") return;
84851
+ if (!this.agentHubOpen) return;
84852
+ if (this.agentHubView === "transcript") {
84853
+ this.agentHubScrollOffset = Math.max(0, this.agentHubScrollOffset + action.delta);
84854
+ this.agentHubPaneSnapshot = void 0;
84855
+ this.emit();
84856
+ return;
84857
+ }
84553
84858
  if (this.agentHubRows.length === 0) return;
84554
84859
  this.agentHubSelectedIndex = Math.min(
84555
84860
  this.agentHubRows.length - 1,
84556
84861
  Math.max(0, this.agentHubSelectedIndex + action.delta)
84557
84862
  );
84863
+ this.agentHubPaneSnapshot = void 0;
84558
84864
  this.emit();
84559
84865
  return;
84560
84866
  case "agent-hub-enter":
@@ -85334,7 +85640,7 @@ var RuntimeController = class _RuntimeController {
85334
85640
  } catch (error51) {
85335
85641
  fail(
85336
85642
  this.io,
85337
- new Error(`cannot resume session "${resumeId}": ${errorReason(error51)}`)
85643
+ new Error(`cannot resume session "${resumeId}": ${terminalErrorReason(error51)}`)
85338
85644
  );
85339
85645
  }
85340
85646
  }
@@ -85411,9 +85717,13 @@ var RuntimeController = class _RuntimeController {
85411
85717
  this.ctx.logger.warn(
85412
85718
  `session ${request.intent} failed: ${errorReason(primaryError)}`
85413
85719
  );
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
- );
85720
+ if (request.intent === "create") {
85721
+ this.setFeedback(
85722
+ 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"
85723
+ );
85724
+ } else {
85725
+ this.setFeedback(`\u2717 \u5207\u6362\u5931\u8D25\uFF1A${terminalErrorReason(primaryError)}\uFF08\u5F53\u524D\u4F1A\u8BDD\u4FDD\u6301\u53EF\u7528\uFF09`);
85726
+ }
85417
85727
  return;
85418
85728
  }
85419
85729
  if (previous3.liveHandle !== void 0) {
@@ -85426,17 +85736,6 @@ var RuntimeController = class _RuntimeController {
85426
85736
  }
85427
85737
  }
85428
85738
  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
85739
  this.sessionRowCache.delete(previous3.session.id);
85441
85740
  }
85442
85741
  if (this.session !== void 0) {
@@ -85530,6 +85829,7 @@ var RuntimeController = class _RuntimeController {
85530
85829
  };
85531
85830
  this.session = agent.session;
85532
85831
  this.projector = candidate.projector;
85832
+ this.hydrateWorkspaceChangeCards();
85533
85833
  this.modelSelectionRef = candidate.modelSelectionRef;
85534
85834
  this.badge = candidate.badge;
85535
85835
  this.machine = "idle";
@@ -86872,7 +87172,7 @@ var RuntimeController = class _RuntimeController {
86872
87172
  if (uncached.length > 0) {
86873
87173
  const BATCH_SIZE = 16;
86874
87174
  for (let i = 0; i < uncached.length; i += BATCH_SIZE) {
86875
- if (this.closed) return;
87175
+ if (this.isClosed()) return;
86876
87176
  const batch = uncached.slice(i, i + BATCH_SIZE);
86877
87177
  const fetched = await Promise.all(
86878
87178
  batch.map(async ({ id, revision }) => {
@@ -86883,7 +87183,7 @@ var RuntimeController = class _RuntimeController {
86883
87183
  for (const entry of fetched) {
86884
87184
  this.sessionRowCache.set(entry.id, { row: entry.row, revision: entry.revision, isEmpty: entry.isEmpty });
86885
87185
  }
86886
- if (!this.closed) {
87186
+ if (!this.isClosed()) {
86887
87187
  const updatedRows = [];
86888
87188
  for (const item of interactiveItems) {
86889
87189
  const header = item.header ?? item;
@@ -86971,7 +87271,7 @@ var RuntimeController = class _RuntimeController {
86971
87271
  id,
86972
87272
  title: listTitleOf(events),
86973
87273
  updatedAt: events.at(-1)?.time ?? createdAt,
86974
- isEmpty: isSessionEmpty(events)
87274
+ isEmpty: isSessionEmpty(events, id)
86975
87275
  };
86976
87276
  } catch {
86977
87277
  return { id, title: id, updatedAt: 0, isEmpty: true };
@@ -87479,10 +87779,11 @@ function isBootstrapOnlySession(events) {
87479
87779
  if (!Array.isArray(events) || events.length === 0) return false;
87480
87780
  return events.every((event) => typeof event.type === "string" && BOOTSTRAP_ONLY_TYPES.has(event.type));
87481
87781
  }
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;
87782
+ function isSessionEmpty(events, id) {
87783
+ if (id !== void 0 && id.includes("probe")) {
87784
+ return isBootstrapOnlySession(events);
87785
+ }
87786
+ return false;
87486
87787
  }
87487
87788
  function planReviewOf(questions) {
87488
87789
  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.47",
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