@xmoon76/dsh-pi-tui 0.4.5 → 0.4.6
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/README.en.md +1 -1
- package/README.md +1 -1
- package/dist/builtins.mjs +1 -1
- package/dist/extensions.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-B65x1oP2.mjs → src-DNscMTdx.mjs} +383 -96
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -54,7 +54,7 @@ next compatibility range, and fallback paths.
|
|
|
54
54
|
|
|
55
55
|
| TUI package line | Official DSH tags for the pairing | Notes |
|
|
56
56
|
|---|---|---|
|
|
57
|
-
| `0.4.
|
|
57
|
+
| `0.4.6` (published `@latest`) | `dsh-v0.1.5-rc.1`, `dsh-v0.1.5-rc.2` | Current stable line; rc.1 minimum, rc.2 compatible |
|
|
58
58
|
| Current `next` npm line (this checkout; version `0.4.5`) | `dsh-v0.1.5-rc.1`, `dsh-v0.1.5-rc.2` | Current next line |
|
|
59
59
|
|
|
60
60
|
Do not mix the stable and `next` lines. The current `next` checkout declares
|
package/README.md
CHANGED
|
@@ -52,7 +52,7 @@ pnpm compat:dsh:npm
|
|
|
52
52
|
|
|
53
53
|
| TUI 包版本 | 对应的官方 DSH tags | 说明 |
|
|
54
54
|
|---|---|---|
|
|
55
|
-
| `0.4.
|
|
55
|
+
| `0.4.6`(已发布 `@latest`) | `dsh-v0.1.5-rc.1`、`dsh-v0.1.5-rc.2` | 当前稳定版;最低 rc.1,兼容 rc.2 |
|
|
56
56
|
| 当前 `next` npm 线(本 checkout;版本 `0.4.5`) | `dsh-v0.1.5-rc.1`、`dsh-v0.1.5-rc.2` | 当前 next 线 |
|
|
57
57
|
|
|
58
58
|
不要把稳定线与 `next` 线混装。当前 `next` checkout 的 peer floor 是
|
package/dist/builtins.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { W as PI_TUI_EXTENSIONS_SERVICE, z as dshVersion } from "./src-
|
|
1
|
+
import { W as PI_TUI_EXTENSIONS_SERVICE, z as dshVersion } from "./src-DNscMTdx.mjs";
|
|
2
2
|
import { TUI_STARTUP_SERVICE } from "./startup.mjs";
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
package/dist/extensions.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { G as API_VERSION, H as inject, K as describeKey, U as name, V as apply, W as PI_TUI_EXTENSIONS_SERVICE } from "./src-
|
|
1
|
+
import { G as API_VERSION, H as inject, K as describeKey, U as name, V as apply, W as PI_TUI_EXTENSIONS_SERVICE } from "./src-DNscMTdx.mjs";
|
|
2
2
|
import "./startup.mjs";
|
|
3
3
|
export { API_VERSION, PI_TUI_EXTENSIONS_SERVICE, apply, describeKey, inject, name };
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { A as resumeCommand, B as forkSeed, C as matchPendingSubagentCall, D as recordedPreset, E as recomposeBlank, F as subagentJobViewHint, I as subagentNoticeIsFailure, L as teardownViewerForSessionSwap, M as settleCompactionSurface, N as shouldConsumeAdvertisedMiss, O as resolveInitialCatalog, P as subagentJobTranscriptId, R as viewerActionCapability, S as isUserQueueInput, T as normalizeSkillInvocation, _ as interruptAgent, a as apply, b as isPlainExitPrompt, c as commandRejectsImages, d as contextRefreshKind, f as createViewerOpenToken, g as inject, h as foldQueueRows, i as SESSIONLESS_COMMANDS, j as runningProfile, k as resolveSubmitDelivery, l as compactingFromLog, m as foldCompactionEvent, n as HOST_COMMAND_CATALOG, o as busyAfterTurnBoundary, p as dangerCommand, r as LOCAL_COMMANDS, s as commandIsLocalForAttachments, t as Config, u as composeAgent, v as isBareCommandLine, w as name, x as isSubagentSettlementNotice, y as isLocalCommandLine } from "./src-
|
|
1
|
+
import { A as resumeCommand, B as forkSeed, C as matchPendingSubagentCall, D as recordedPreset, E as recomposeBlank, F as subagentJobViewHint, I as subagentNoticeIsFailure, L as teardownViewerForSessionSwap, M as settleCompactionSurface, N as shouldConsumeAdvertisedMiss, O as resolveInitialCatalog, P as subagentJobTranscriptId, R as viewerActionCapability, S as isUserQueueInput, T as normalizeSkillInvocation, _ as interruptAgent, a as apply, b as isPlainExitPrompt, c as commandRejectsImages, d as contextRefreshKind, f as createViewerOpenToken, g as inject, h as foldQueueRows, i as SESSIONLESS_COMMANDS, j as runningProfile, k as resolveSubmitDelivery, l as compactingFromLog, m as foldCompactionEvent, n as HOST_COMMAND_CATALOG, o as busyAfterTurnBoundary, p as dangerCommand, r as LOCAL_COMMANDS, s as commandIsLocalForAttachments, t as Config, u as composeAgent, v as isBareCommandLine, w as name, x as isSubagentSettlementNotice, y as isLocalCommandLine } from "./src-DNscMTdx.mjs";
|
|
2
2
|
import "./startup.mjs";
|
|
3
3
|
export { Config, HOST_COMMAND_CATALOG, LOCAL_COMMANDS, SESSIONLESS_COMMANDS, apply, busyAfterTurnBoundary, commandIsLocalForAttachments, commandRejectsImages, compactingFromLog, composeAgent, contextRefreshKind, createViewerOpenToken, dangerCommand, foldCompactionEvent, foldQueueRows, forkSeed, inject, interruptAgent, isBareCommandLine, isLocalCommandLine, isPlainExitPrompt, isSubagentSettlementNotice, isUserQueueInput, matchPendingSubagentCall, name, normalizeSkillInvocation, recomposeBlank, recordedPreset, resolveInitialCatalog, resolveSubmitDelivery, resumeCommand, runningProfile, settleCompactionSurface, shouldConsumeAdvertisedMiss, subagentJobTranscriptId, subagentJobViewHint, subagentNoticeIsFailure, teardownViewerForSessionSwap, viewerActionCapability };
|
|
@@ -813,6 +813,25 @@ function listAgentsCallPresentation(argsRaw) {
|
|
|
813
813
|
if (scope === void 0) return { scope: "children" };
|
|
814
814
|
return scope === "children" || scope === "descendants" ? { scope } : void 0;
|
|
815
815
|
}
|
|
816
|
+
/** Parse the display-only file declarations from a `present` call. */
|
|
817
|
+
function presentCallPresentation(argsRaw) {
|
|
818
|
+
const parsed = parseArgs(argsRaw);
|
|
819
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return void 0;
|
|
820
|
+
const files = parsed.files;
|
|
821
|
+
if (!Array.isArray(files)) return void 0;
|
|
822
|
+
const presented = [];
|
|
823
|
+
for (const file of files) {
|
|
824
|
+
if (typeof file !== "object" || file === null || Array.isArray(file)) return void 0;
|
|
825
|
+
const value = file;
|
|
826
|
+
if (typeof value.path !== "string" || value.path.trim() === "") return void 0;
|
|
827
|
+
if (value.description !== void 0 && typeof value.description !== "string") return void 0;
|
|
828
|
+
presented.push({
|
|
829
|
+
path: value.path,
|
|
830
|
+
...value.description === void 0 ? {} : { description: value.description }
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
return { files: presented };
|
|
834
|
+
}
|
|
816
835
|
/** Count one structured list_agents snapshot. */
|
|
817
836
|
function summarizeAgentEntries(entries) {
|
|
818
837
|
let running = 0;
|
|
@@ -998,6 +1017,16 @@ function actionResultSummary(kind, text) {
|
|
|
998
1017
|
* the TUI, while replay remains deterministic and registry-independent.
|
|
999
1018
|
*/
|
|
1000
1019
|
function compactToolPresentation(name, argsRaw, result = "", options = {}) {
|
|
1020
|
+
if (name === "present") {
|
|
1021
|
+
const call = presentCallPresentation(argsRaw);
|
|
1022
|
+
const resultText = options.isError === true || options.error !== void 0 ? actionErrorResult(result, options) : void 0;
|
|
1023
|
+
const count = call === void 0 ? void 0 : `${call.files.length} ${call.files.length === 1 ? "file" : "files"}`;
|
|
1024
|
+
return {
|
|
1025
|
+
title: "Present files",
|
|
1026
|
+
...count === void 0 ? {} : { summary: count },
|
|
1027
|
+
...resultText === void 0 ? {} : { result: resultText }
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1001
1030
|
const send = name === "send_message" ? sendMessageCallPresentation(argsRaw) : void 0;
|
|
1002
1031
|
if (send !== void 0) {
|
|
1003
1032
|
const resultText = options.isError === true || options.error !== void 0 ? actionErrorResult(result, options) : actionResultSummary("send_message", result);
|
|
@@ -1048,6 +1077,11 @@ function isCompactActionTool(name, argsRaw) {
|
|
|
1048
1077
|
function compactToolExpandedLines(name, argsRaw, result = "", options = {}) {
|
|
1049
1078
|
const presentation = compactToolPresentation(name, argsRaw, result, options);
|
|
1050
1079
|
if (presentation === void 0) return void 0;
|
|
1080
|
+
if (name === "present") {
|
|
1081
|
+
const lines = presentCallPresentation(argsRaw)?.files.map((file) => file.description === void 0 || file.description === "" ? file.path : `${file.path} — ${file.description}`) ?? [];
|
|
1082
|
+
if (presentation.result !== void 0) lines.push(presentation.result);
|
|
1083
|
+
return lines;
|
|
1084
|
+
}
|
|
1051
1085
|
if (name === "list_agents" && options.isError !== true && options.error === void 0) {
|
|
1052
1086
|
const parsed = parseJsonValue(result);
|
|
1053
1087
|
if (Array.isArray(parsed)) return JSON.stringify(parsed, null, 2).split("\n");
|
|
@@ -2668,6 +2702,7 @@ function transcriptSearchText(message, depth = 0) {
|
|
|
2668
2702
|
}
|
|
2669
2703
|
return `workflow ${message.name} ${message.status} ${[...phases].join(" ")} ${members.join(" ")}`;
|
|
2670
2704
|
}
|
|
2705
|
+
if (message.kind === "assistant" && message.deliverables !== void 0 && message.deliverables.length > 0) return `${message.text} ${message.deliverables.map((file) => [file.path, file.description ?? ""].join(" ")).join(" ")}`;
|
|
2671
2706
|
return message.text ?? "";
|
|
2672
2707
|
}
|
|
2673
2708
|
/** Normalize search text exactly like the legacy query path did (JS String
|
|
@@ -2975,6 +3010,7 @@ function assistantDisplayBlocksHaveInterruptionEvidence(blocks) {
|
|
|
2975
3010
|
}
|
|
2976
3011
|
/** Use the semantic or display-only projection for entry visibility. */
|
|
2977
3012
|
function assistantEntryVisibleNow(entry) {
|
|
3013
|
+
if (entry.deliverables !== void 0 && entry.deliverables.length > 0) return true;
|
|
2978
3014
|
return entry.displayBlocks === void 0 ? assistantBlocksVisibleNow(assistantEntryBlocks(entry)) : assistantDisplayBlocksVisibleNow(entry.displayBlocks);
|
|
2979
3015
|
}
|
|
2980
3016
|
/** Use the semantic or display-only projection for attempt evidence. */
|
|
@@ -3068,6 +3104,11 @@ var TranscriptFolder = class TranscriptFolder {
|
|
|
3068
3104
|
claimedNextStepTurns = /* @__PURE__ */ new Map();
|
|
3069
3105
|
/** The assistant message object per (turn, step); streaming text lands in place. */
|
|
3070
3106
|
assistantEntries = /* @__PURE__ */ new Map();
|
|
3107
|
+
/** Durable delivery declarations retained with their event sequence until
|
|
3108
|
+
* the turn's closing assistant selects the valid prefix. */
|
|
3109
|
+
deliverableDeclarationsByTurn = /* @__PURE__ */ new Map();
|
|
3110
|
+
/** Durable assistant/message sequence per step, used as the closing boundary. */
|
|
3111
|
+
assistantSettlementSeqs = /* @__PURE__ */ new Map();
|
|
3071
3112
|
/** In-flight live block state keyed by logical step. This is required for
|
|
3072
3113
|
* authoritative block-end replacement: deltas may be partial, while a
|
|
3073
3114
|
* completed block replaces the entire indexed state without duplication. */
|
|
@@ -4807,12 +4848,72 @@ var TranscriptFolder = class TranscriptFolder {
|
|
|
4807
4848
|
if (compactionId !== void 0) this.compacting.delete(compactionId);
|
|
4808
4849
|
}
|
|
4809
4850
|
}
|
|
4851
|
+
/** Fold the structural durable payload emitted by the present tool. The
|
|
4852
|
+
* event is the only source of delivery facts; tool-result text is never
|
|
4853
|
+
* reverse-parsed. Invalid file entries are ignored at this event boundary,
|
|
4854
|
+
* while valid entries retain their event sequence and source order. */
|
|
4855
|
+
applyPresentedEvent(event) {
|
|
4856
|
+
const data = event.data;
|
|
4857
|
+
if (typeof data !== "object" || data === null || Array.isArray(data)) return;
|
|
4858
|
+
const value = data;
|
|
4859
|
+
if (typeof value.turn !== "number" || !Number.isSafeInteger(value.turn) || value.turn < 1) return;
|
|
4860
|
+
if (typeof value.callId !== "string" || value.callId.length === 0 || !Array.isArray(value.files)) return;
|
|
4861
|
+
if (this.activityByTurn.get(value.turn)?.completed === true) return;
|
|
4862
|
+
const declarations = this.deliverableDeclarationsByTurn.get(value.turn) ?? [];
|
|
4863
|
+
const seq = Number(event.seq);
|
|
4864
|
+
if (!Number.isSafeInteger(seq) || seq < 0) return;
|
|
4865
|
+
for (const file of value.files) {
|
|
4866
|
+
if (typeof file !== "object" || file === null || Array.isArray(file)) continue;
|
|
4867
|
+
const entry = file;
|
|
4868
|
+
if (typeof entry.path !== "string" || entry.path.trim() === "") continue;
|
|
4869
|
+
if (entry.description !== void 0 && typeof entry.description !== "string") continue;
|
|
4870
|
+
declarations.push({
|
|
4871
|
+
path: entry.path,
|
|
4872
|
+
...entry.description === void 0 ? {} : { description: entry.description },
|
|
4873
|
+
seq
|
|
4874
|
+
});
|
|
4875
|
+
}
|
|
4876
|
+
if (declarations.length > 0) this.deliverableDeclarationsByTurn.set(value.turn, declarations);
|
|
4877
|
+
}
|
|
4878
|
+
/** Attach declarations before the closing assistant's durable sequence,
|
|
4879
|
+
* preserving first-seen path order while letting the latest valid
|
|
4880
|
+
* declaration replace its description. */
|
|
4881
|
+
attachDeliverablesToClosingAssistant(turn) {
|
|
4882
|
+
const activity = this.activityByTurn.get(turn);
|
|
4883
|
+
const step = activity?.lastAssistantStep;
|
|
4884
|
+
if (step === void 0) return;
|
|
4885
|
+
const key = stepKey$1(turn, step);
|
|
4886
|
+
const assistant = this.assistantEntries.get(key);
|
|
4887
|
+
const closingSeq = this.assistantSettlementSeqs.get(key);
|
|
4888
|
+
if (assistant === void 0 || closingSeq === void 0) return;
|
|
4889
|
+
const declarations = this.deliverableDeclarationsByTurn.get(turn);
|
|
4890
|
+
if (declarations === void 0) return;
|
|
4891
|
+
const files = /* @__PURE__ */ new Map();
|
|
4892
|
+
for (const declaration of declarations) {
|
|
4893
|
+
if (declaration.seq >= closingSeq) continue;
|
|
4894
|
+
files.set(declaration.path, {
|
|
4895
|
+
path: declaration.path,
|
|
4896
|
+
...declaration.description === void 0 ? {} : { description: declaration.description }
|
|
4897
|
+
});
|
|
4898
|
+
}
|
|
4899
|
+
if (files.size === 0) return;
|
|
4900
|
+
const wasVisible = this.isVisible(assistant);
|
|
4901
|
+
assistant.deliverables = [...files.values()];
|
|
4902
|
+
bumpAssistantPresentationRevision(assistant);
|
|
4903
|
+
this.markStreamingEntryDirty(`assistant:${key}`);
|
|
4904
|
+
this.syncAssistantVisibility(turn, step, assistant, wasVisible, false);
|
|
4905
|
+
if (activity !== void 0) activity.lastAssistantVisible = true;
|
|
4906
|
+
}
|
|
4810
4907
|
applyEvent(event) {
|
|
4811
4908
|
if (isReplacementSurfaceEvent(event)) {
|
|
4812
4909
|
if (event.type === "user/message") this.claimedNextStepTurns.delete(event.data.id);
|
|
4813
4910
|
return;
|
|
4814
4911
|
}
|
|
4815
4912
|
const kind = event.type;
|
|
4913
|
+
if (kind === "deliverables/presented") {
|
|
4914
|
+
this.applyPresentedEvent(event);
|
|
4915
|
+
return;
|
|
4916
|
+
}
|
|
4816
4917
|
if (kind === "agent/inbox/spliced") {
|
|
4817
4918
|
const data = event.data;
|
|
4818
4919
|
const inserted = data.inserted.map((message) => ({
|
|
@@ -4945,6 +5046,7 @@ var TranscriptFolder = class TranscriptFolder {
|
|
|
4945
5046
|
const activity = this.activityFor(event.data.turn);
|
|
4946
5047
|
if (activity.completed) break;
|
|
4947
5048
|
const key = stepKey$1(event.data.turn, event.data.step);
|
|
5049
|
+
this.assistantSettlementSeqs.set(key, Number(event.seq));
|
|
4948
5050
|
const priorLast = activity.lastAssistantStep ?? -1;
|
|
4949
5051
|
const entry = this.assistantEntries.get(key);
|
|
4950
5052
|
this.liveAssistantBlocks.delete(key);
|
|
@@ -5173,6 +5275,8 @@ var TranscriptFolder = class TranscriptFolder {
|
|
|
5173
5275
|
} }
|
|
5174
5276
|
};
|
|
5175
5277
|
this.resolveMessageAtTurnEnd(activity);
|
|
5278
|
+
this.attachDeliverablesToClosingAssistant(event.data.turn);
|
|
5279
|
+
this.deliverableDeclarationsByTurn.delete(event.data.turn);
|
|
5176
5280
|
this.usage.onTurnEnd(event.data.turn);
|
|
5177
5281
|
this.syncUsage(activity);
|
|
5178
5282
|
activity.revision += 1;
|
|
@@ -34278,19 +34382,22 @@ function thoughtLeadBoundary(group) {
|
|
|
34278
34382
|
if (firstInitialUserIndex >= 0) return firstInitialUserIndex + 1;
|
|
34279
34383
|
return leadingInjectedContextPrefixEnd(group);
|
|
34280
34384
|
}
|
|
34281
|
-
/** Whether one Assistant entry has semantic/finalized content
|
|
34282
|
-
* display-only open-opaque rows remain transcript
|
|
34283
|
-
* completed/max-token final; finalized generic
|
|
34385
|
+
/** Whether one Assistant entry has semantic/finalized content or an explicit
|
|
34386
|
+
* delivered-file tail. Pending display-only open-opaque rows remain transcript
|
|
34387
|
+
* evidence but cannot become a completed/max-token final; finalized generic
|
|
34388
|
+
* blocks stay eligible. */
|
|
34284
34389
|
function assistantRenderable(assistant) {
|
|
34285
34390
|
if (assistant.displayBlocks?.some((block) => block.kind === "open-opaque") === true) return false;
|
|
34391
|
+
if (assistant.deliverables !== void 0 && assistant.deliverables.length > 0) return true;
|
|
34286
34392
|
if (assistant.content !== void 0) return assistantBlocksVisibleNow(assistant.content);
|
|
34287
34393
|
return assistant.text.trim() !== "";
|
|
34288
34394
|
}
|
|
34289
34395
|
/** The turn's final assistant selection: only after the authoritative
|
|
34290
34396
|
* turn/end, only for a reason the system presents output (completed /
|
|
34291
34397
|
* max-tokens), and only when the Assistant owning the structural latest step
|
|
34292
|
-
* has semantic/finalized content. An empty or
|
|
34293
|
-
* final — never an earlier assistant
|
|
34398
|
+
* has semantic/finalized content or explicit delivered files. An empty or
|
|
34399
|
+
* pending latest step without either yields NO final — never an earlier assistant
|
|
34400
|
+
* (review fix). The max-tokens final carries
|
|
34294
34401
|
* the truncated marker (plan §13.8). */
|
|
34295
34402
|
function finalAssistantSelection(activity, group) {
|
|
34296
34403
|
if (activity === void 0 || !activity.completed) return void 0;
|
|
@@ -39692,6 +39799,25 @@ var TranscriptGutterComponent = class {
|
|
|
39692
39799
|
}
|
|
39693
39800
|
};
|
|
39694
39801
|
/**
|
|
39802
|
+
* Layout-only rows that keep a running Focus turn's live height from
|
|
39803
|
+
* shrinking after a transient presentation reflow. It owns no semantic row;
|
|
39804
|
+
* its height is supplied by TuiApp's current render measurement and it is
|
|
39805
|
+
* hidden outside the fullscreen Focus presentation epoch.
|
|
39806
|
+
*/
|
|
39807
|
+
var FocusLivePaddingComponent = class {
|
|
39808
|
+
rows;
|
|
39809
|
+
enabled;
|
|
39810
|
+
constructor(rows, enabled) {
|
|
39811
|
+
this.rows = rows;
|
|
39812
|
+
this.enabled = enabled;
|
|
39813
|
+
}
|
|
39814
|
+
invalidate() {}
|
|
39815
|
+
render(_width) {
|
|
39816
|
+
if (!this.enabled()) return [];
|
|
39817
|
+
return Array.from({ length: Math.max(0, Math.floor(this.rows())) }, () => "");
|
|
39818
|
+
}
|
|
39819
|
+
};
|
|
39820
|
+
/**
|
|
39695
39821
|
* Bullet + continuation-indent wrapper that keeps its child LIVE, so a
|
|
39696
39822
|
* terminal resize re-renders the child at the new width instead of
|
|
39697
39823
|
* re-wrapping a frozen render (the 5a76526 regression: assistant/user
|
|
@@ -39844,6 +39970,41 @@ var UserBubbleComponent = class {
|
|
|
39844
39970
|
return this.cached;
|
|
39845
39971
|
}
|
|
39846
39972
|
};
|
|
39973
|
+
/** Host-owned tail for explicit files delivered by the present tool. Paths
|
|
39974
|
+
* are always shown first; the folded view caps entries while an expanded
|
|
39975
|
+
* transcript view re-renders the complete declaration list. */
|
|
39976
|
+
var DeliveredFilesComponent = class DeliveredFilesComponent {
|
|
39977
|
+
static FOLDED_LIMIT = 4;
|
|
39978
|
+
files;
|
|
39979
|
+
workspaceRoot;
|
|
39980
|
+
expanded;
|
|
39981
|
+
cached = /* @__PURE__ */ new Map();
|
|
39982
|
+
constructor(files, workspaceRoot, expanded) {
|
|
39983
|
+
this.files = files;
|
|
39984
|
+
this.workspaceRoot = workspaceRoot;
|
|
39985
|
+
this.expanded = expanded;
|
|
39986
|
+
}
|
|
39987
|
+
invalidate() {
|
|
39988
|
+
this.cached.clear();
|
|
39989
|
+
}
|
|
39990
|
+
render(width) {
|
|
39991
|
+
const safeWidth = Math.max(1, Math.floor(width));
|
|
39992
|
+
const previous = this.cached.get(safeWidth);
|
|
39993
|
+
if (previous !== void 0) return previous;
|
|
39994
|
+
const shown = this.expanded ? this.files : this.files.slice(0, DeliveredFilesComponent.FOLDED_LIMIT);
|
|
39995
|
+
const rows = [truncateToWidth(color.textDim(`Delivered files · ${this.files.length}`), safeWidth, "…")];
|
|
39996
|
+
for (const file of shown) {
|
|
39997
|
+
const path = relativizeToCwd(file.path, this.workspaceRoot).replace(/\r\n|\r|\n/g, " ");
|
|
39998
|
+
rows.push(truncateToWidth(color.textDim(` ${path}`), safeWidth, "…"));
|
|
39999
|
+
if (file.description === void 0 || file.description === "") continue;
|
|
40000
|
+
const descriptionWidth = Math.max(1, safeWidth - 4);
|
|
40001
|
+
for (const line of wrapTextWithAnsi(file.description, descriptionWidth)) rows.push(truncateToWidth(color.textDim(` ${line}`), safeWidth, "…"));
|
|
40002
|
+
}
|
|
40003
|
+
if (!this.expanded && this.files.length > shown.length) rows.push(truncateToWidth(color.textDim(` … +${this.files.length - shown.length}`), safeWidth, "…"));
|
|
40004
|
+
this.cached.set(safeWidth, rows);
|
|
40005
|
+
return rows;
|
|
40006
|
+
}
|
|
40007
|
+
};
|
|
39847
40008
|
/**
|
|
39848
40009
|
* Longest prefix of `text` whose WRAPPED height fits `budget` rows at
|
|
39849
40010
|
* `width`, with an ellipsis marking a cut — the approval dialog's height
|
|
@@ -40301,6 +40462,8 @@ var TuiApp = class TuiApp {
|
|
|
40301
40462
|
}
|
|
40302
40463
|
/** Set the Ctrl+O expansion master switch and repaint. */
|
|
40303
40464
|
setToolOutputExpanded(expanded) {
|
|
40465
|
+
if (this.toolOutputExpanded === expanded) return;
|
|
40466
|
+
this.clearFocusLiveHeightState();
|
|
40304
40467
|
this.toolOutputExpanded = expanded;
|
|
40305
40468
|
this.rebuildMessages();
|
|
40306
40469
|
}
|
|
@@ -40610,6 +40773,16 @@ var TuiApp = class TuiApp {
|
|
|
40610
40773
|
* rows carry the activity (the whole collapsed Thought block — and the
|
|
40611
40774
|
* expanded header — is the toggle hit area, plan §17.1). */
|
|
40612
40775
|
messageRows = [];
|
|
40776
|
+
/** High-water presentation heights for running Focus turns. This is
|
|
40777
|
+
* presentation-only state: it is never folded into TranscriptFolder or the
|
|
40778
|
+
* session log; compatible floors remain active during historical browsing
|
|
40779
|
+
* and release only at explicit lifecycle or structural boundaries. */
|
|
40780
|
+
focusLiveHeightStates = /* @__PURE__ */ new Map();
|
|
40781
|
+
/** The currently measured inert padding after a Focus turn's boundary
|
|
40782
|
+
* spacer. Padding components read this map at paint time, retaining the
|
|
40783
|
+
* compatible floor while historical and releasing it with the same explicit
|
|
40784
|
+
* lifecycle or structural boundaries. */
|
|
40785
|
+
focusLivePaddingRows = /* @__PURE__ */ new Map();
|
|
40613
40786
|
/** The terminal geometry of the LAST PAINTED frame (fullscreen only):
|
|
40614
40787
|
* a zero-row probe rides the fullscreen layout root, and the fork
|
|
40615
40788
|
* renders every layout child on EVERY frame, so these fields record
|
|
@@ -41033,6 +41206,7 @@ var TuiApp = class TuiApp {
|
|
|
41033
41206
|
this.cancelSaveLocationPrompt();
|
|
41034
41207
|
for (const dispose of this.schemeDisposers) dispose();
|
|
41035
41208
|
this.schemeDisposers = [];
|
|
41209
|
+
this.clearFocusLiveHeightState();
|
|
41036
41210
|
this.tui.stop();
|
|
41037
41211
|
this.fullscreen?.stop();
|
|
41038
41212
|
this.fullscreen = void 0;
|
|
@@ -41886,6 +42060,7 @@ var TuiApp = class TuiApp {
|
|
|
41886
42060
|
*/
|
|
41887
42061
|
pushLocalMessage(message) {
|
|
41888
42062
|
this.localMessages.push(message);
|
|
42063
|
+
this.clearFocusLiveHeightState();
|
|
41889
42064
|
this.rebuildMessages();
|
|
41890
42065
|
return message;
|
|
41891
42066
|
}
|
|
@@ -41910,6 +42085,7 @@ var TuiApp = class TuiApp {
|
|
|
41910
42085
|
const token = this.identityTokens.get(message);
|
|
41911
42086
|
if (token !== void 0) this.identityTokens.set(next, token);
|
|
41912
42087
|
this.localMessages[index] = next;
|
|
42088
|
+
this.clearFocusLiveHeightState();
|
|
41913
42089
|
this.rebuildMessages();
|
|
41914
42090
|
return next;
|
|
41915
42091
|
}
|
|
@@ -41920,12 +42096,14 @@ var TuiApp = class TuiApp {
|
|
|
41920
42096
|
const token = this.identityTokens.get(this.localMessages[index]);
|
|
41921
42097
|
if (token !== void 0) this.identityTokens.set(message, token);
|
|
41922
42098
|
this.localMessages[index] = message;
|
|
42099
|
+
this.clearFocusLiveHeightState();
|
|
41923
42100
|
this.rebuildMessages();
|
|
41924
42101
|
}
|
|
41925
42102
|
/** Drop all local cards (session switch). */
|
|
41926
42103
|
clearLocalMessages() {
|
|
41927
42104
|
if (this.localMessages.length === 0) return;
|
|
41928
42105
|
this.localMessages.length = 0;
|
|
42106
|
+
this.clearFocusLiveHeightState();
|
|
41929
42107
|
this.rebuildMessages();
|
|
41930
42108
|
}
|
|
41931
42109
|
/**
|
|
@@ -41940,6 +42118,7 @@ var TuiApp = class TuiApp {
|
|
|
41940
42118
|
if (running.length === this.localMessages.length) return;
|
|
41941
42119
|
this.localMessages.length = 0;
|
|
41942
42120
|
this.localMessages.push(...running);
|
|
42121
|
+
this.clearFocusLiveHeightState();
|
|
41943
42122
|
this.rebuildMessages();
|
|
41944
42123
|
}
|
|
41945
42124
|
/**
|
|
@@ -41984,6 +42163,7 @@ var TuiApp = class TuiApp {
|
|
|
41984
42163
|
this.clearExitConfirmation();
|
|
41985
42164
|
this.keybindings.cancelLeader();
|
|
41986
42165
|
if (enabled === (this.fullscreen !== void 0)) return;
|
|
42166
|
+
this.clearFocusLiveHeightState();
|
|
41987
42167
|
const pending = this.activeApproval;
|
|
41988
42168
|
const history = this.historyPanel;
|
|
41989
42169
|
pending?.handle?.hide();
|
|
@@ -42236,18 +42416,22 @@ var TuiApp = class TuiApp {
|
|
|
42236
42416
|
* presentation owner; omitted by legacy callers and never persisted.
|
|
42237
42417
|
*/
|
|
42238
42418
|
setTranscript(messages, activities, window, streamingToolPreviews) {
|
|
42419
|
+
const previousWindow = this.transcriptWindow;
|
|
42420
|
+
const windowChanged = previousWindow?.mode !== window?.mode || previousWindow?.endTurn !== window?.endTurn;
|
|
42421
|
+
if (activities !== void 0 && activities !== this.turnActivities || windowChanged) this.clearFocusLiveHeightState();
|
|
42239
42422
|
this.messages = messages;
|
|
42240
42423
|
if (activities !== void 0) this.turnActivities = activities;
|
|
42241
42424
|
this.streamingToolPreviews = [...streamingToolPreviews ?? []];
|
|
42242
42425
|
this.transcriptWindow = window;
|
|
42243
42426
|
this.refreshTranscriptWindowHint();
|
|
42244
|
-
this.updateWorkflowDisclosure(messages);
|
|
42427
|
+
if (this.updateWorkflowDisclosure(messages)) this.clearFocusLiveHeightState();
|
|
42245
42428
|
this.rebuildMessages();
|
|
42246
42429
|
}
|
|
42247
42430
|
/** Replace ONLY the turn activities (the messages stay). The runner
|
|
42248
42431
|
* prefers the combined {@link setTranscript} snapshot — this setter is
|
|
42249
42432
|
* for callers that repaint messages separately. */
|
|
42250
42433
|
setTurnActivities(activities) {
|
|
42434
|
+
this.clearFocusLiveHeightState();
|
|
42251
42435
|
this.turnActivities = activities;
|
|
42252
42436
|
this.rebuildMessages();
|
|
42253
42437
|
}
|
|
@@ -42261,6 +42445,7 @@ var TuiApp = class TuiApp {
|
|
|
42261
42445
|
* immediately; the expansion set is kept but not consulted (plan §16.4). */
|
|
42262
42446
|
setFocusMode(enabled) {
|
|
42263
42447
|
if (this.focusModeEnabled === enabled) return;
|
|
42448
|
+
this.clearFocusLiveHeightState();
|
|
42264
42449
|
this.focusModeEnabled = enabled;
|
|
42265
42450
|
this.projectStatus({ interaction: { focusMode: enabled } });
|
|
42266
42451
|
this.rebuildMessages();
|
|
@@ -42275,6 +42460,7 @@ var TuiApp = class TuiApp {
|
|
|
42275
42460
|
* value) — same policy as theme/focus. */
|
|
42276
42461
|
setIconStyle(style) {
|
|
42277
42462
|
if (this.iconStyle === style) return;
|
|
42463
|
+
this.clearFocusLiveHeightState();
|
|
42278
42464
|
this.iconStyle = style;
|
|
42279
42465
|
this.working.setIconStyleFrames(workingFramesFor(style));
|
|
42280
42466
|
this.rebuildMessages();
|
|
@@ -42328,7 +42514,10 @@ var TuiApp = class TuiApp {
|
|
|
42328
42514
|
revealSearchMatch(message) {
|
|
42329
42515
|
const turn = "turn" in message ? message.turn : void 0;
|
|
42330
42516
|
if (turn !== void 0 && this.focusModeEnabled) this.setFocusTurnExpanded(turn, true);
|
|
42331
|
-
if (isFocusSecondaryDisclosure(message))
|
|
42517
|
+
if (isFocusSecondaryDisclosure(message)) {
|
|
42518
|
+
if (this.expandedOverride.get(message) !== true) this.clearFocusLiveHeightState();
|
|
42519
|
+
this.expandedOverride.set(message, true);
|
|
42520
|
+
}
|
|
42332
42521
|
this.rebuildMessages();
|
|
42333
42522
|
}
|
|
42334
42523
|
/** Clear every secondary expansion of one turn (the root Collapse All
|
|
@@ -42564,6 +42753,7 @@ var TuiApp = class TuiApp {
|
|
|
42564
42753
|
* (pushing the live set itself would hand the stack the object this
|
|
42565
42754
|
* method then empties). */
|
|
42566
42755
|
enterFocusViewerScope() {
|
|
42756
|
+
this.clearFocusLiveHeightState();
|
|
42567
42757
|
this.focusExpansionsStack.push(new Set(this.focusExpandedTurns));
|
|
42568
42758
|
this.focusExpandedTurns.clear();
|
|
42569
42759
|
this.rebuildMessages();
|
|
@@ -42572,6 +42762,7 @@ var TuiApp = class TuiApp {
|
|
|
42572
42762
|
exitFocusViewerScope() {
|
|
42573
42763
|
const restored = this.focusExpansionsStack.pop();
|
|
42574
42764
|
if (restored === void 0) return;
|
|
42765
|
+
this.clearFocusLiveHeightState();
|
|
42575
42766
|
this.focusExpandedTurns.clear();
|
|
42576
42767
|
for (const turn of restored) this.focusExpandedTurns.add(turn);
|
|
42577
42768
|
this.rebuildMessages();
|
|
@@ -42584,6 +42775,7 @@ var TuiApp = class TuiApp {
|
|
|
42584
42775
|
* teardown's intent explicit and stays correct even if that ordering
|
|
42585
42776
|
* ever changes. */
|
|
42586
42777
|
discardFocusViewerScope() {
|
|
42778
|
+
this.clearFocusLiveHeightState();
|
|
42587
42779
|
this.focusExpansionsStack.pop();
|
|
42588
42780
|
}
|
|
42589
42781
|
/**
|
|
@@ -42776,17 +42968,11 @@ var TuiApp = class TuiApp {
|
|
|
42776
42968
|
transcriptRenderWidth() {
|
|
42777
42969
|
return transcriptContentWidth(this.terminal.columns);
|
|
42778
42970
|
}
|
|
42779
|
-
/**
|
|
42780
|
-
|
|
42781
|
-
|
|
42782
|
-
this.pruneMessageComponents(projectionExpanded);
|
|
42783
|
-
this.messagesView.clear();
|
|
42784
|
-
this.messagesView.addChild(this.welcomeCard);
|
|
42971
|
+
/** Render every projected transcript block once for this rebuild. The same
|
|
42972
|
+
* metadata feeds the mounted component tree and the fullscreen row map. */
|
|
42973
|
+
renderTranscriptBlocks(projectionExpanded, width) {
|
|
42785
42974
|
const boundary = this.expandBoundary();
|
|
42786
|
-
|
|
42787
|
-
const rows = [];
|
|
42788
|
-
const blocks = this.transcriptBlocks(projectionExpanded);
|
|
42789
|
-
blocks.forEach((block, index) => {
|
|
42975
|
+
return this.transcriptBlocks(projectionExpanded).map((block) => {
|
|
42790
42976
|
let component;
|
|
42791
42977
|
let rendered;
|
|
42792
42978
|
let truncatedMarker = false;
|
|
@@ -42816,32 +43002,145 @@ var TuiApp = class TuiApp {
|
|
|
42816
43002
|
top: hit.top + rendered.length - workflowInfo.total
|
|
42817
43003
|
}));
|
|
42818
43004
|
}
|
|
42819
|
-
|
|
43005
|
+
return {
|
|
43006
|
+
block,
|
|
43007
|
+
component,
|
|
43008
|
+
rendered,
|
|
43009
|
+
truncatedMarker,
|
|
43010
|
+
attachments,
|
|
43011
|
+
...collapseFocusOwnerOnClick === void 0 ? {} : { collapseFocusOwnerOnClick },
|
|
43012
|
+
...subCallHits === void 0 ? {} : { subCallHits },
|
|
43013
|
+
...workflowHits === void 0 ? {} : { workflowHits }
|
|
43014
|
+
};
|
|
43015
|
+
});
|
|
43016
|
+
}
|
|
43017
|
+
/** The semantic turn owner of a rendered block. Do not use the Focus
|
|
43018
|
+
* collapse owner here: that marker is an interaction target, not turn
|
|
43019
|
+
* membership, and final assistant rows deliberately have no marker. */
|
|
43020
|
+
focusLiveTurnOf(block) {
|
|
43021
|
+
if (block.kind === "activity") return block.activity.turn;
|
|
43022
|
+
if (block.kind === "streaming-tool-previews") return block.turn;
|
|
43023
|
+
return "turn" in block.message ? block.message.turn : void 0;
|
|
43024
|
+
}
|
|
43025
|
+
/** The normal physical height charged to one rendered block, preserving the
|
|
43026
|
+
* existing zero-row and original-index Spacer rules exactly. */
|
|
43027
|
+
normalTranscriptBlockHeight(entry, index, total) {
|
|
43028
|
+
if (entry.rendered.length === 0 && !entry.truncatedMarker) return 0;
|
|
43029
|
+
return entry.rendered.length + (entry.truncatedMarker ? 1 : 0) + (index < total - 1 ? 1 : 0);
|
|
43030
|
+
}
|
|
43031
|
+
/** Drop presentation floors and their measured padding. */
|
|
43032
|
+
clearFocusLiveHeightState() {
|
|
43033
|
+
this.focusLiveHeightStates.clear();
|
|
43034
|
+
this.focusLivePaddingRows.clear();
|
|
43035
|
+
}
|
|
43036
|
+
/** Whether the current render still owns a fullscreen Focus presentation
|
|
43037
|
+
* epoch. Leaving history keeps the existing floor active; explicit lifecycle
|
|
43038
|
+
* and structural boundaries release it. */
|
|
43039
|
+
focusLivePaddingEnabled() {
|
|
43040
|
+
const enabled = this.focusModeEnabled && this.fullscreen !== void 0 && this.fullscreenScroll !== void 0;
|
|
43041
|
+
if (!enabled) this.clearFocusLiveHeightState();
|
|
43042
|
+
return enabled;
|
|
43043
|
+
}
|
|
43044
|
+
/** Measure the current normal turn spans and update their running high-water
|
|
43045
|
+
* floors. Padding is kept in separate inert row entries after the existing
|
|
43046
|
+
* turn-boundary Spacer, so semantic block heights and click ownership stay
|
|
43047
|
+
* unchanged. */
|
|
43048
|
+
focusLivePaddingFor(renderedBlocks, projectionExpanded, width) {
|
|
43049
|
+
this.focusLivePaddingRows.clear();
|
|
43050
|
+
const scroll = this.fullscreenScroll;
|
|
43051
|
+
if (!this.focusLivePaddingEnabled() || scroll === void 0) return this.focusLivePaddingRows;
|
|
43052
|
+
const heights = renderedBlocks.map((entry, index) => this.normalTranscriptBlockHeight(entry, index, renderedBlocks.length));
|
|
43053
|
+
const groups = /* @__PURE__ */ new Map();
|
|
43054
|
+
for (let index = 0; index < renderedBlocks.length; index += 1) {
|
|
43055
|
+
const turn = this.focusLiveTurnOf(renderedBlocks[index].block);
|
|
43056
|
+
if (turn === void 0) continue;
|
|
43057
|
+
let group = groups.get(turn);
|
|
43058
|
+
if (group === void 0) {
|
|
43059
|
+
group = { indices: [] };
|
|
43060
|
+
groups.set(turn, group);
|
|
43061
|
+
}
|
|
43062
|
+
group.indices.push(index);
|
|
43063
|
+
const block = renderedBlocks[index].block;
|
|
43064
|
+
if (block.kind === "activity") group.activity = block.activity;
|
|
43065
|
+
}
|
|
43066
|
+
for (const turn of this.focusLiveHeightStates.keys()) if (!groups.has(turn)) this.focusLiveHeightStates.delete(turn);
|
|
43067
|
+
for (const [turn, group] of groups) {
|
|
43068
|
+
const activity = group.activity;
|
|
43069
|
+
if (activity === void 0 || activity.completed) {
|
|
43070
|
+
this.focusLiveHeightStates.delete(turn);
|
|
43071
|
+
continue;
|
|
43072
|
+
}
|
|
43073
|
+
const normalHeight = group.indices.reduce((sum, index) => sum + heights[index], 0);
|
|
43074
|
+
const expanded = projectionExpanded.has(turn);
|
|
43075
|
+
const previous = this.focusLiveHeightStates.get(turn);
|
|
43076
|
+
if (previous !== void 0 && (previous.activity !== activity || previous.expanded !== expanded || previous.width !== width)) this.focusLiveHeightStates.delete(turn);
|
|
43077
|
+
let state = this.focusLiveHeightStates.get(turn);
|
|
43078
|
+
if (state === void 0) {
|
|
43079
|
+
state = {
|
|
43080
|
+
activity,
|
|
43081
|
+
expanded,
|
|
43082
|
+
width,
|
|
43083
|
+
height: normalHeight
|
|
43084
|
+
};
|
|
43085
|
+
this.focusLiveHeightStates.set(turn, state);
|
|
43086
|
+
} else if (normalHeight > state.height) state.height = normalHeight;
|
|
43087
|
+
const padding = state.height - normalHeight;
|
|
43088
|
+
if (padding <= 0) continue;
|
|
43089
|
+
for (let index = group.indices.length - 1; index >= 0; index -= 1) {
|
|
43090
|
+
const blockIndex = group.indices[index];
|
|
43091
|
+
if (heights[blockIndex] > 0) {
|
|
43092
|
+
this.focusLivePaddingRows.set(blockIndex, padding);
|
|
43093
|
+
break;
|
|
43094
|
+
}
|
|
43095
|
+
}
|
|
43096
|
+
}
|
|
43097
|
+
return this.focusLivePaddingRows;
|
|
43098
|
+
}
|
|
43099
|
+
/** Build one row-map entry from the shared rendered metadata. */
|
|
43100
|
+
fullscreenRowEntry(entry, height, hasTrailingSpacer) {
|
|
43101
|
+
const block = entry.block;
|
|
43102
|
+
return {
|
|
43103
|
+
...block.kind === "message" ? { message: block.message } : block.kind === "activity" ? { activity: block.activity } : {},
|
|
43104
|
+
...entry.collapseFocusOwnerOnClick === void 0 ? {} : { collapseFocusOwnerOnClick: entry.collapseFocusOwnerOnClick },
|
|
43105
|
+
height,
|
|
43106
|
+
attachments: entry.attachments,
|
|
43107
|
+
...entry.subCallHits === void 0 ? {} : { subCallHits: entry.subCallHits },
|
|
43108
|
+
...entry.workflowHits === void 0 ? {} : { workflowHits: entry.workflowHits },
|
|
43109
|
+
hasTrailingSpacer
|
|
43110
|
+
};
|
|
43111
|
+
}
|
|
43112
|
+
/** Rebuild the message component tree from the current transcript state. */
|
|
43113
|
+
rebuildMessages() {
|
|
43114
|
+
const projectionExpanded = this.focusProjectionExpandedTurns();
|
|
43115
|
+
this.pruneMessageComponents(projectionExpanded);
|
|
43116
|
+
this.messagesView.clear();
|
|
43117
|
+
this.messagesView.addChild(this.welcomeCard);
|
|
43118
|
+
const width = this.transcriptRenderWidth();
|
|
43119
|
+
const renderedBlocks = this.renderTranscriptBlocks(projectionExpanded, width);
|
|
43120
|
+
const paddingRows = this.focusLivePaddingFor(renderedBlocks, projectionExpanded, width);
|
|
43121
|
+
const rows = [];
|
|
43122
|
+
renderedBlocks.forEach((entry, index) => {
|
|
43123
|
+
const height = this.normalTranscriptBlockHeight(entry, index, renderedBlocks.length);
|
|
43124
|
+
if (height === 0) rows.push(this.fullscreenRowEntry(entry, 0, false));
|
|
43125
|
+
else {
|
|
43126
|
+
this.messagesView.addChild(new TranscriptGutterComponent(entry.component));
|
|
43127
|
+
if (entry.truncatedMarker) {
|
|
43128
|
+
const marker = truncateToWidth(color.textMuted(" (output may be truncated)"), width, "…");
|
|
43129
|
+
this.messagesView.addChild(new TranscriptGutterComponent(new Text(marker, 0, 0)));
|
|
43130
|
+
}
|
|
43131
|
+
const hasTrailingSpacer = index < renderedBlocks.length - 1;
|
|
43132
|
+
rows.push(this.fullscreenRowEntry(entry, height, hasTrailingSpacer));
|
|
43133
|
+
if (hasTrailingSpacer) this.messagesView.addChild(new Spacer());
|
|
43134
|
+
}
|
|
43135
|
+
const padding = paddingRows.get(index) ?? 0;
|
|
43136
|
+
if (padding > 0) {
|
|
43137
|
+
this.messagesView.addChild(new FocusLivePaddingComponent(() => this.focusLivePaddingRows.get(index) ?? 0, () => this.focusLivePaddingEnabled()));
|
|
42820
43138
|
rows.push({
|
|
42821
|
-
|
|
42822
|
-
...collapseFocusOwnerOnClick !== void 0 ? { collapseFocusOwnerOnClick } : {},
|
|
42823
|
-
height: 0,
|
|
43139
|
+
height: padding,
|
|
42824
43140
|
attachments: [],
|
|
42825
43141
|
hasTrailingSpacer: false
|
|
42826
43142
|
});
|
|
42827
|
-
return;
|
|
42828
43143
|
}
|
|
42829
|
-
this.messagesView.addChild(new TranscriptGutterComponent(component));
|
|
42830
|
-
if (truncatedMarker) {
|
|
42831
|
-
const marker = truncateToWidth(color.textMuted(" (output may be truncated)"), width, "…");
|
|
42832
|
-
this.messagesView.addChild(new TranscriptGutterComponent(new Text(marker, 0, 0)));
|
|
42833
|
-
}
|
|
42834
|
-
const height = rendered.length + (truncatedMarker ? 1 : 0) + (index < blocks.length - 1 ? 1 : 0);
|
|
42835
|
-
rows.push({
|
|
42836
|
-
...block.kind === "message" ? { message: block.message } : block.kind === "activity" ? { activity: block.activity } : {},
|
|
42837
|
-
...collapseFocusOwnerOnClick !== void 0 ? { collapseFocusOwnerOnClick } : {},
|
|
42838
|
-
height,
|
|
42839
|
-
attachments,
|
|
42840
|
-
...subCallHits === void 0 ? {} : { subCallHits },
|
|
42841
|
-
...workflowHits === void 0 ? {} : { workflowHits },
|
|
42842
|
-
hasTrailingSpacer: index < blocks.length - 1
|
|
42843
|
-
});
|
|
42844
|
-
if (index < blocks.length - 1) this.messagesView.addChild(new Spacer());
|
|
42845
43144
|
});
|
|
42846
43145
|
if (this.transcriptWindowHint !== "") this.messagesView.addChild(new TranscriptGutterComponent(new Text(color.textDim(this.transcriptWindowHint), 0, 0)));
|
|
42847
43146
|
if (this.notifyText !== "") {
|
|
@@ -42926,61 +43225,21 @@ var TuiApp = class TuiApp {
|
|
|
42926
43225
|
* (the gutter contract), or the hit map drifts from the layout. */
|
|
42927
43226
|
refreshMessageRows() {
|
|
42928
43227
|
const width = this.transcriptRenderWidth();
|
|
42929
|
-
const boundary = this.expandBoundary();
|
|
42930
43228
|
const projectionExpanded = this.focusProjectionExpandedTurns();
|
|
42931
|
-
const
|
|
43229
|
+
const renderedBlocks = this.renderTranscriptBlocks(projectionExpanded, width);
|
|
43230
|
+
const paddingRows = this.focusLivePaddingFor(renderedBlocks, projectionExpanded, width);
|
|
42932
43231
|
const rows = [];
|
|
42933
|
-
|
|
42934
|
-
|
|
42935
|
-
|
|
42936
|
-
|
|
42937
|
-
|
|
42938
|
-
|
|
42939
|
-
|
|
42940
|
-
|
|
42941
|
-
|
|
42942
|
-
component = this.focusActivityComponentFor(block.activity, projectionExpanded.has(block.activity.turn), this.focusToolDisplayFor(block.activity), this.focusModeEnabled && !projectionExpanded.has(block.activity.turn) ? focusPreparingSummary(this.streamingToolPreviewsForTurn(block.activity.turn)) : void 0);
|
|
42943
|
-
rendered = component.render(width);
|
|
42944
|
-
} else if (block.kind === "streaming-tool-previews") {
|
|
42945
|
-
component = this.streamingToolPreviewComponent(block.previews, width);
|
|
42946
|
-
rendered = component.render(width);
|
|
42947
|
-
} else {
|
|
42948
|
-
component = this.componentForMessage(block.message, boundary, width);
|
|
42949
|
-
rendered = component.render(width);
|
|
42950
|
-
truncatedMarker = block.truncated === true;
|
|
42951
|
-
attachments = this.attachmentRangesOf(component, width);
|
|
42952
|
-
const subCallInfo = this.subCallHitsByMessage.get(block.message);
|
|
42953
|
-
subCallHits = subCallInfo === void 0 ? void 0 : subCallInfo.hits.map((hit) => ({
|
|
42954
|
-
...hit,
|
|
42955
|
-
top: hit.top + rendered.length - subCallInfo.total
|
|
42956
|
-
}));
|
|
42957
|
-
const workflowInfo = this.workflowHitsByMessage.get(block.message);
|
|
42958
|
-
workflowHits = workflowInfo === void 0 ? void 0 : workflowInfo.hits.map((hit) => ({
|
|
42959
|
-
...hit,
|
|
42960
|
-
top: hit.top + rendered.length - workflowInfo.total
|
|
42961
|
-
}));
|
|
42962
|
-
}
|
|
42963
|
-
if (rendered.length === 0 && !truncatedMarker) {
|
|
42964
|
-
rows.push({
|
|
42965
|
-
...block.kind === "message" ? { message: block.message } : block.kind === "activity" ? { activity: block.activity } : {},
|
|
42966
|
-
...collapseFocusOwnerOnClick !== void 0 ? { collapseFocusOwnerOnClick } : {},
|
|
42967
|
-
height: 0,
|
|
42968
|
-
attachments: [],
|
|
42969
|
-
hasTrailingSpacer: false
|
|
42970
|
-
});
|
|
42971
|
-
return;
|
|
42972
|
-
}
|
|
42973
|
-
const height = rendered.length + (truncatedMarker ? 1 : 0) + (index < blocks.length - 1 ? 1 : 0);
|
|
42974
|
-
rows.push({
|
|
42975
|
-
...block.kind === "message" ? { message: block.message } : block.kind === "activity" ? { activity: block.activity } : {},
|
|
42976
|
-
...collapseFocusOwnerOnClick !== void 0 ? { collapseFocusOwnerOnClick } : {},
|
|
42977
|
-
height,
|
|
42978
|
-
attachments,
|
|
42979
|
-
...subCallHits === void 0 ? {} : { subCallHits },
|
|
42980
|
-
...workflowHits === void 0 ? {} : { workflowHits },
|
|
42981
|
-
hasTrailingSpacer: index < blocks.length - 1
|
|
43232
|
+
for (let index = 0; index < renderedBlocks.length; index += 1) {
|
|
43233
|
+
const entry = renderedBlocks[index];
|
|
43234
|
+
const height = this.normalTranscriptBlockHeight(entry, index, renderedBlocks.length);
|
|
43235
|
+
rows.push(this.fullscreenRowEntry(entry, height, height > 0 && index < renderedBlocks.length - 1));
|
|
43236
|
+
const padding = paddingRows.get(index) ?? 0;
|
|
43237
|
+
if (padding > 0) rows.push({
|
|
43238
|
+
height: padding,
|
|
43239
|
+
attachments: [],
|
|
43240
|
+
hasTrailingSpacer: false
|
|
42982
43241
|
});
|
|
42983
|
-
}
|
|
43242
|
+
}
|
|
42984
43243
|
this.messageRows = rows;
|
|
42985
43244
|
}
|
|
42986
43245
|
/** The live collapse flag for ONE image-block occurrence (message object
|
|
@@ -43000,6 +43259,7 @@ var TuiApp = class TuiApp {
|
|
|
43000
43259
|
}
|
|
43001
43260
|
if (indices.has(imageIndex)) indices.delete(imageIndex);
|
|
43002
43261
|
else indices.add(imageIndex);
|
|
43262
|
+
this.clearFocusLiveHeightState();
|
|
43003
43263
|
this.rebuildMessages();
|
|
43004
43264
|
}
|
|
43005
43265
|
/**
|
|
@@ -43622,6 +43882,7 @@ var TuiApp = class TuiApp {
|
|
|
43622
43882
|
} else this.expandedOverride.set(message, true);
|
|
43623
43883
|
} else if (this.expandedOverride.get(message) === true) this.expandedOverride.delete(message);
|
|
43624
43884
|
else this.expandedOverride.set(message, true);
|
|
43885
|
+
this.clearFocusLiveHeightState();
|
|
43625
43886
|
this.rebuildMessages();
|
|
43626
43887
|
}
|
|
43627
43888
|
/** The effective Run disclosure of one Workflow card: the user's explicit
|
|
@@ -43654,6 +43915,7 @@ var TuiApp = class TuiApp {
|
|
|
43654
43915
|
if (message === void 0) return;
|
|
43655
43916
|
state.userOpen = !(state.userOpen ?? this.workflowRunOpen(message));
|
|
43656
43917
|
this.workflowDisclosureRevision += 1;
|
|
43918
|
+
this.clearFocusLiveHeightState();
|
|
43657
43919
|
this.rebuildMessages();
|
|
43658
43920
|
}
|
|
43659
43921
|
/** Toggle one Workflow Phase disclosure (click on the phase header). The
|
|
@@ -43668,6 +43930,7 @@ var TuiApp = class TuiApp {
|
|
|
43668
43930
|
if (phase === void 0) return;
|
|
43669
43931
|
state.userOpen = !(state.userOpen ?? this.workflowPhaseOpen(runId, phaseKey, phase));
|
|
43670
43932
|
this.workflowDisclosureRevision += 1;
|
|
43933
|
+
this.clearFocusLiveHeightState();
|
|
43671
43934
|
this.rebuildMessages();
|
|
43672
43935
|
}
|
|
43673
43936
|
/** Advance the Workflow disclosure state for one changed run (PR2 plan
|
|
@@ -43762,16 +44025,19 @@ var TuiApp = class TuiApp {
|
|
|
43762
44025
|
* snapshot is compared against the last-seen one, and only a real
|
|
43763
44026
|
* change (members array reference or run status) advances the state. */
|
|
43764
44027
|
updateWorkflowDisclosure(messages) {
|
|
44028
|
+
let snapshotChanged = false;
|
|
43765
44029
|
for (const message of messages) {
|
|
43766
44030
|
if (message.kind !== "workflow") continue;
|
|
43767
44031
|
const previous = this.workflowSeen.get(message.runId);
|
|
43768
44032
|
if (previous !== void 0 && previous.members === message.members && previous.status === message.status) continue;
|
|
44033
|
+
snapshotChanged = true;
|
|
43769
44034
|
this.workflowSeen.set(message.runId, {
|
|
43770
44035
|
members: message.members,
|
|
43771
44036
|
status: message.status
|
|
43772
44037
|
});
|
|
43773
44038
|
this.advanceWorkflowDisclosure(message);
|
|
43774
44039
|
}
|
|
44040
|
+
return snapshotChanged;
|
|
43775
44041
|
}
|
|
43776
44042
|
/** Dispatch one Workflow card hit (PR2 plan §12.4/§12.5): run/phase
|
|
43777
44043
|
* headers toggle their disclosure; a running inline member and the
|
|
@@ -43834,6 +44100,7 @@ var TuiApp = class TuiApp {
|
|
|
43834
44100
|
/** Drop all per-message expansion overrides (session-scoped state: a
|
|
43835
44101
|
* session switch must not leak the old session's click toggles). */
|
|
43836
44102
|
clearSessionOverrides() {
|
|
44103
|
+
this.clearFocusLiveHeightState();
|
|
43837
44104
|
this.expandedOverride.clear();
|
|
43838
44105
|
this.fullscreenCellGesture = void 0;
|
|
43839
44106
|
this.todoClickCoalesceUntil = 0;
|
|
@@ -44221,6 +44488,10 @@ var TuiApp = class TuiApp {
|
|
|
44221
44488
|
* @param facts - directory, session id, model, version, and the optional agent preset to display.
|
|
44222
44489
|
*/
|
|
44223
44490
|
setWelcomeCard(facts) {
|
|
44491
|
+
if (this.workspaceRoot !== facts.cwd) {
|
|
44492
|
+
this.workspaceRoot = facts.cwd;
|
|
44493
|
+
this.disposeMessageComponents();
|
|
44494
|
+
}
|
|
44224
44495
|
this.welcomeCard.setFacts(facts);
|
|
44225
44496
|
this.rebuildMessages();
|
|
44226
44497
|
this.extensionHost?.updateSession({
|
|
@@ -45215,6 +45486,7 @@ var TuiApp = class TuiApp {
|
|
|
45215
45486
|
* context keeps the existing rule. */
|
|
45216
45487
|
effectiveMessageExpanded(message, boundary) {
|
|
45217
45488
|
if (message.kind === "thinking") return this.effectiveThinkingExpanded(message);
|
|
45489
|
+
if (message.kind === "assistant" && message.deliverables !== void 0) return message.turn >= boundary || this.expandedOverride.get(message) === true;
|
|
45218
45490
|
if ("turn" in message && this.isInsideExpandedFocus(message, boundary) && isFocusSecondaryDisclosure(message)) {
|
|
45219
45491
|
if (this.fullscreen !== void 0) return this.expandedOverride.get(message) === true;
|
|
45220
45492
|
return true;
|
|
@@ -45331,7 +45603,7 @@ var TuiApp = class TuiApp {
|
|
|
45331
45603
|
this.workflowHitsByMessage.delete(message);
|
|
45332
45604
|
}
|
|
45333
45605
|
return {
|
|
45334
|
-
component: hostBuilt ? this.renderMessage(message, state.expanded, state.expandHint, state.fullReveal, width) : rendered.component,
|
|
45606
|
+
component: hostBuilt ? this.renderMessage(message, state.expanded, state.expandHint, state.fullReveal, width) : this.withDeliveredFiles(rendered.component, message, state.expanded),
|
|
45335
45607
|
boundary,
|
|
45336
45608
|
builtWidth: hostBuilt && this.bakesFoldedWidth(message, state.expanded) ? width : void 0,
|
|
45337
45609
|
themeRev: this.themeRevision,
|
|
@@ -45515,6 +45787,14 @@ var TuiApp = class TuiApp {
|
|
|
45515
45787
|
* renderer, so a throwing renderer is invoked exactly once per build
|
|
45516
45788
|
* and the host fallback is single-path).
|
|
45517
45789
|
*/
|
|
45790
|
+
withDeliveredFiles(body, message, expanded) {
|
|
45791
|
+
if (message.kind !== "assistant" || message.deliverables === void 0 || message.deliverables.length === 0) return body;
|
|
45792
|
+
const result = new Container();
|
|
45793
|
+
result.addChild(body);
|
|
45794
|
+
result.addChild(new Text("", 0, 0));
|
|
45795
|
+
result.addChild(new DeliveredFilesComponent(message.deliverables, this.workspaceRoot, expanded));
|
|
45796
|
+
return result;
|
|
45797
|
+
}
|
|
45518
45798
|
renderMessage(message, expanded, expandHint, fullReveal, width) {
|
|
45519
45799
|
if (message.kind === "user") {
|
|
45520
45800
|
if (message.content !== void 0 && message.content.some((block) => block.type !== "text")) return this.renderUserBlocks(message.content, message);
|
|
@@ -45524,11 +45804,14 @@ var TuiApp = class TuiApp {
|
|
|
45524
45804
|
const bullet = color.primary(iconPrefix("assistant-bullet", this.iconStyle));
|
|
45525
45805
|
const makeAssistantText = (text) => new BulletedComponent(new Markdown(text, 0, 0, markdownTheme, void 0, HOST_MARKDOWN_OPTIONS), bullet);
|
|
45526
45806
|
const body = message.displayBlocks !== void 0 ? this.renderAssistantDisplaySequence(message.displayBlocks, makeAssistantText, message) : message.content !== void 0 && message.content.some((block) => block.type !== "text") ? this.renderBlockSequence(message.content, makeAssistantText, message) : makeAssistantText(message.text);
|
|
45527
|
-
|
|
45528
|
-
|
|
45529
|
-
|
|
45530
|
-
|
|
45531
|
-
|
|
45807
|
+
let bodyWithStatus = body;
|
|
45808
|
+
if (message.interrupted) {
|
|
45809
|
+
const interrupted = new Container();
|
|
45810
|
+
interrupted.addChild(body);
|
|
45811
|
+
interrupted.addChild(new Text(color.textDimItalic(" (interrupted)"), 0, 0));
|
|
45812
|
+
bodyWithStatus = interrupted;
|
|
45813
|
+
}
|
|
45814
|
+
return this.withDeliveredFiles(bodyWithStatus, message, expanded);
|
|
45532
45815
|
}
|
|
45533
45816
|
if (message.kind === "thinking") {
|
|
45534
45817
|
if (!expanded) return new ThinkingCompactComponent(message, this.expandHint(expandHint), this.iconStyle);
|
|
@@ -45726,6 +46009,7 @@ var TuiApp = class TuiApp {
|
|
|
45726
46009
|
if (this.subCallExpanded.has(subCallId)) this.subCallExpanded.delete(subCallId);
|
|
45727
46010
|
else this.subCallExpanded.add(subCallId);
|
|
45728
46011
|
this.subCallExpandedRevision += 1;
|
|
46012
|
+
this.clearFocusLiveHeightState();
|
|
45729
46013
|
this.rebuildMessages();
|
|
45730
46014
|
}
|
|
45731
46015
|
/**
|
|
@@ -46271,6 +46555,7 @@ var TuiApp = class TuiApp {
|
|
|
46271
46555
|
const revision = this.renderers.revisionOf();
|
|
46272
46556
|
if (revision !== this.lastRendererRevision) {
|
|
46273
46557
|
this.lastRendererRevision = revision;
|
|
46558
|
+
this.clearFocusLiveHeightState();
|
|
46274
46559
|
this.rebuildMessages();
|
|
46275
46560
|
}
|
|
46276
46561
|
}
|
|
@@ -46514,6 +46799,7 @@ var TuiApp = class TuiApp {
|
|
|
46514
46799
|
setThinkingExpanded(expanded) {
|
|
46515
46800
|
const hadOverrides = this.clearThinkingExpansionOverrides();
|
|
46516
46801
|
if (this.thinkingExpanded === expanded && !hadOverrides) return;
|
|
46802
|
+
this.clearFocusLiveHeightState();
|
|
46517
46803
|
this.thinkingExpanded = expanded;
|
|
46518
46804
|
this.rebuildMessages();
|
|
46519
46805
|
}
|
|
@@ -46544,6 +46830,7 @@ var TuiApp = class TuiApp {
|
|
|
46544
46830
|
* ALL Thinking compact (plan §9). */
|
|
46545
46831
|
toggleThinkingExpanded() {
|
|
46546
46832
|
this.clearThinkingExpansionOverrides();
|
|
46833
|
+
this.clearFocusLiveHeightState();
|
|
46547
46834
|
this.thinkingExpanded = !this.thinkingExpanded;
|
|
46548
46835
|
this.rebuildMessages();
|
|
46549
46836
|
return this.thinkingExpanded;
|
package/package.json
CHANGED