@dungle-scrubs/tallow 0.8.28 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +2 -9
- package/dist/install.js.map +1 -1
- package/dist/interactive-mode-patch.d.ts +1 -0
- package/dist/interactive-mode-patch.d.ts.map +1 -1
- package/dist/interactive-mode-patch.js +44 -9
- package/dist/interactive-mode-patch.js.map +1 -1
- package/extensions/_icons/__tests__/icons.test.ts +0 -1
- package/extensions/_icons/index.ts +0 -2
- package/extensions/context-fork/__tests__/context-fork.test.ts +9 -0
- package/extensions/health/index.ts +1 -1
- package/extensions/render-stabilizer/__tests__/render-stabilizer.test.ts +42 -0
- package/extensions/render-stabilizer/extension.json +5 -0
- package/extensions/render-stabilizer/index.ts +66 -0
- package/extensions/subagent-tool/__tests__/auto-cheap-model.test.ts +66 -6
- package/extensions/subagent-tool/__tests__/model-router-explicit-resolution.test.ts +79 -5
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts +2 -0
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js +17 -6
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts +47 -0
- package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/tui.js +139 -5
- package/node_modules/@mariozechner/pi-tui/dist/tui.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/src/__tests__/settings-list.test.ts +49 -0
- package/node_modules/@mariozechner/pi-tui/src/components/settings-list.ts +17 -5
- package/node_modules/@mariozechner/pi-tui/src/tui.ts +142 -5
- package/package.json +1 -1
- package/schemas/settings.schema.json +0 -5
- package/extensions/plan-mode-tool/__tests__/e2e.mjs +0 -350
- package/extensions/plan-mode-tool/__tests__/index.test.ts +0 -213
- package/extensions/plan-mode-tool/__tests__/utils.test.ts +0 -381
- package/extensions/plan-mode-tool/extension.json +0 -22
- package/extensions/plan-mode-tool/index.ts +0 -583
- package/extensions/plan-mode-tool/utils.ts +0 -257
|
@@ -39,14 +39,74 @@ const mockModels = [
|
|
|
39
39
|
];
|
|
40
40
|
|
|
41
41
|
const mockScope = createMockScope(import.meta.url);
|
|
42
|
-
mockScope.module("@
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
mockScope.module("@dungle-scrubs/synapse", () => ({
|
|
43
|
+
listAvailableModels: () => mockModels.map((model) => `${model.provider}/${model.id}`),
|
|
44
|
+
parseModelMatrixOverrides: () => undefined,
|
|
45
|
+
resolveModelCandidates: (query: string) => {
|
|
46
|
+
const normalized = query.toLowerCase().trim();
|
|
47
|
+
return mockModels
|
|
48
|
+
.filter(
|
|
49
|
+
(model) =>
|
|
50
|
+
model.id.toLowerCase() === normalized ||
|
|
51
|
+
model.name.toLowerCase().includes(normalized) ||
|
|
52
|
+
`${model.provider}/${model.id}`.toLowerCase() === normalized
|
|
53
|
+
)
|
|
54
|
+
.map((model) => ({
|
|
55
|
+
displayName: `${model.provider}/${model.id}`,
|
|
56
|
+
id: model.id,
|
|
57
|
+
provider: model.provider,
|
|
58
|
+
}));
|
|
59
|
+
},
|
|
60
|
+
resolveModelFuzzy: (
|
|
61
|
+
query: string,
|
|
62
|
+
source?: () => Array<{ id: string; name: string; provider: string }>,
|
|
63
|
+
preferredProviders?: string[]
|
|
64
|
+
) => {
|
|
65
|
+
const normalized = query.toLowerCase().trim();
|
|
66
|
+
const candidates = source
|
|
67
|
+
? source().map((model) => ({
|
|
68
|
+
id: model.id,
|
|
69
|
+
name: model.name,
|
|
70
|
+
provider: model.provider,
|
|
71
|
+
}))
|
|
72
|
+
: mockModels;
|
|
73
|
+
const matches = candidates.filter(
|
|
74
|
+
(model) =>
|
|
75
|
+
model.id.toLowerCase() === normalized ||
|
|
76
|
+
model.name.toLowerCase().includes(normalized) ||
|
|
77
|
+
`${model.provider}/${model.id}`.toLowerCase() === normalized
|
|
78
|
+
);
|
|
79
|
+
const ordered = preferredProviders?.length
|
|
80
|
+
? [...matches].sort((left, right) => {
|
|
81
|
+
const leftIndex = preferredProviders.indexOf(left.provider);
|
|
82
|
+
const rightIndex = preferredProviders.indexOf(right.provider);
|
|
83
|
+
const safeLeft = leftIndex === -1 ? Number.MAX_SAFE_INTEGER : leftIndex;
|
|
84
|
+
const safeRight = rightIndex === -1 ? Number.MAX_SAFE_INTEGER : rightIndex;
|
|
85
|
+
return safeLeft - safeRight;
|
|
86
|
+
})
|
|
87
|
+
: matches;
|
|
88
|
+
const selected = ordered[0];
|
|
89
|
+
return selected
|
|
90
|
+
? {
|
|
91
|
+
displayName: `${selected.provider}/${selected.id}`,
|
|
92
|
+
id: selected.id,
|
|
93
|
+
provider: selected.provider,
|
|
94
|
+
}
|
|
95
|
+
: undefined;
|
|
96
|
+
},
|
|
97
|
+
selectModels: (_classification: unknown, costPreference: string) => {
|
|
98
|
+
const ordered =
|
|
99
|
+
costPreference === "premium"
|
|
100
|
+
? [mockModels[0], mockModels[1], mockModels[2], mockModels[3]]
|
|
101
|
+
: [mockModels[3], mockModels[2], mockModels[1], mockModels[0]];
|
|
102
|
+
return ordered.map((model) => ({
|
|
103
|
+
displayName: `${model.provider}/${model.id}`,
|
|
104
|
+
id: model.id,
|
|
105
|
+
provider: model.provider,
|
|
106
|
+
}));
|
|
107
|
+
},
|
|
45
108
|
}));
|
|
46
109
|
|
|
47
|
-
// NOTE: Do NOT mock ../model-resolver.js — it leaks across test files in bun.
|
|
48
|
-
// The pi-ai mock above provides model data that resolveModelFuzzy uses.
|
|
49
|
-
|
|
50
110
|
mockScope.module("../task-classifier.js", () => ({
|
|
51
111
|
classifyTask: async (_task: string, primaryType: string) => ({
|
|
52
112
|
type: primaryType,
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "bun:test";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
2
5
|
import { createMockScope } from "../../../test-utils/mock-scope.js";
|
|
3
6
|
|
|
4
7
|
const mockModels = [
|
|
@@ -35,9 +38,62 @@ const mockModels = [
|
|
|
35
38
|
];
|
|
36
39
|
|
|
37
40
|
const mockScope = createMockScope(import.meta.url);
|
|
38
|
-
mockScope.module("@
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
mockScope.module("@dungle-scrubs/synapse", () => ({
|
|
42
|
+
listAvailableModels: () => mockModels.map((model) => `${model.provider}/${model.id}`),
|
|
43
|
+
parseModelMatrixOverrides: () => undefined,
|
|
44
|
+
resolveModelCandidates: (query: string) => {
|
|
45
|
+
const normalized = query.toLowerCase().trim();
|
|
46
|
+
return mockModels
|
|
47
|
+
.filter(
|
|
48
|
+
(model) =>
|
|
49
|
+
model.id.toLowerCase() === normalized ||
|
|
50
|
+
model.name.toLowerCase().includes(normalized) ||
|
|
51
|
+
`${model.provider}/${model.id}`.toLowerCase() === normalized
|
|
52
|
+
)
|
|
53
|
+
.map((model) => ({
|
|
54
|
+
displayName: `${model.provider}/${model.id}`,
|
|
55
|
+
id: model.id,
|
|
56
|
+
provider: model.provider,
|
|
57
|
+
}));
|
|
58
|
+
},
|
|
59
|
+
resolveModelFuzzy: (
|
|
60
|
+
query: string,
|
|
61
|
+
source?: () => Array<{ id: string; name: string; provider: string }>,
|
|
62
|
+
preferredProviders?: string[]
|
|
63
|
+
) => {
|
|
64
|
+
const normalized = query.toLowerCase().trim();
|
|
65
|
+
const candidates = source
|
|
66
|
+
? source().map((model) => ({
|
|
67
|
+
id: model.id,
|
|
68
|
+
name: model.name,
|
|
69
|
+
provider: model.provider,
|
|
70
|
+
}))
|
|
71
|
+
: mockModels;
|
|
72
|
+
const matches = candidates.filter(
|
|
73
|
+
(model) =>
|
|
74
|
+
model.id.toLowerCase() === normalized ||
|
|
75
|
+
model.name.toLowerCase().includes(normalized) ||
|
|
76
|
+
`${model.provider}/${model.id}`.toLowerCase() === normalized
|
|
77
|
+
);
|
|
78
|
+
const ordered = preferredProviders?.length
|
|
79
|
+
? [...matches].sort((left, right) => {
|
|
80
|
+
const leftIndex = preferredProviders.indexOf(left.provider);
|
|
81
|
+
const rightIndex = preferredProviders.indexOf(right.provider);
|
|
82
|
+
const safeLeft = leftIndex === -1 ? Number.MAX_SAFE_INTEGER : leftIndex;
|
|
83
|
+
const safeRight = rightIndex === -1 ? Number.MAX_SAFE_INTEGER : rightIndex;
|
|
84
|
+
return safeLeft - safeRight;
|
|
85
|
+
})
|
|
86
|
+
: matches;
|
|
87
|
+
const selected = ordered[0];
|
|
88
|
+
return selected
|
|
89
|
+
? {
|
|
90
|
+
displayName: `${selected.provider}/${selected.id}`,
|
|
91
|
+
id: selected.id,
|
|
92
|
+
provider: selected.provider,
|
|
93
|
+
}
|
|
94
|
+
: undefined;
|
|
95
|
+
},
|
|
96
|
+
selectModels: () => [],
|
|
41
97
|
}));
|
|
42
98
|
|
|
43
99
|
mockScope.module("../task-classifier.js", () => ({
|
|
@@ -48,7 +104,23 @@ mockScope.module("../task-classifier.js", () => ({
|
|
|
48
104
|
let routeModel!: typeof import("../model-router.js").routeModel;
|
|
49
105
|
|
|
50
106
|
const ORIGINAL_ENV: Record<string, string | undefined> = {};
|
|
51
|
-
const ENV_KEYS = [
|
|
107
|
+
const ENV_KEYS = [
|
|
108
|
+
"ANTHROPIC_API_KEY",
|
|
109
|
+
"GEMINI_API_KEY",
|
|
110
|
+
"GOOGLE_API_KEY",
|
|
111
|
+
"MINIMAX_API_KEY",
|
|
112
|
+
"MINIMAX_CN_API_KEY",
|
|
113
|
+
"OPENCODE_API_KEY",
|
|
114
|
+
"OPENAI_API_KEY",
|
|
115
|
+
"OPENROUTER_API_KEY",
|
|
116
|
+
"TALLOW_CODING_AGENT_DIR",
|
|
117
|
+
"VERCEL_AI_GATEWAY_API_KEY",
|
|
118
|
+
"VERCEL_API_KEY",
|
|
119
|
+
"XAI_API_KEY",
|
|
120
|
+
"ZAI_API_KEY",
|
|
121
|
+
] as const;
|
|
122
|
+
|
|
123
|
+
let isolatedTallowHome: string;
|
|
52
124
|
|
|
53
125
|
beforeAll(async () => {
|
|
54
126
|
mockScope.install();
|
|
@@ -65,6 +137,8 @@ beforeEach(() => {
|
|
|
65
137
|
ORIGINAL_ENV[key] = process.env[key];
|
|
66
138
|
delete process.env[key];
|
|
67
139
|
}
|
|
140
|
+
isolatedTallowHome = mkdtempSync(join(tmpdir(), "subagent-router-explicit-"));
|
|
141
|
+
process.env.TALLOW_CODING_AGENT_DIR = isolatedTallowHome;
|
|
68
142
|
});
|
|
69
143
|
|
|
70
144
|
afterEach(() => {
|
|
@@ -72,8 +146,8 @@ afterEach(() => {
|
|
|
72
146
|
if (ORIGINAL_ENV[key] === undefined) delete process.env[key];
|
|
73
147
|
else process.env[key] = ORIGINAL_ENV[key];
|
|
74
148
|
}
|
|
149
|
+
rmSync(isolatedTallowHome, { force: true, recursive: true });
|
|
75
150
|
});
|
|
76
|
-
|
|
77
151
|
describe("routeModel explicit model resolution", () => {
|
|
78
152
|
it("honors explicit provider/model choices without auto-routing", async () => {
|
|
79
153
|
const result = await routeModel(
|
|
@@ -35,6 +35,8 @@ export declare class SettingsList implements Component {
|
|
|
35
35
|
private searchEnabled;
|
|
36
36
|
private submenuComponent;
|
|
37
37
|
private submenuItemIndex;
|
|
38
|
+
private lastRenderLineCount;
|
|
39
|
+
private nextMinLineCount;
|
|
38
40
|
constructor(items: SettingItem[], maxVisible: number, theme: SettingsListTheme, onChange: (id: string, newValue: string) => void, onCancel: () => void, options?: SettingsListOptions);
|
|
39
41
|
/** Update an item's currentValue */
|
|
40
42
|
updateValue(id: string, newValue: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-list.d.ts","sourceRoot":"","sources":["../../src/components/settings-list.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAI3C,MAAM,WAAW,WAAW;IAC3B,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,uFAAuF;IACvF,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,KAAK,IAAI,KAAK,SAAS,CAAC;CACtF;AAED,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC;IACnD,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC;IACnD,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IACnC,YAAY,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,qBAAa,YAAa,YAAW,SAAS;IAC7C,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,WAAW,CAAC,CAAQ;IAC5B,OAAO,CAAC,aAAa,CAAU;IAG/B,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,gBAAgB,CAAuB;
|
|
1
|
+
{"version":3,"file":"settings-list.d.ts","sourceRoot":"","sources":["../../src/components/settings-list.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAI3C,MAAM,WAAW,WAAW;IAC3B,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,uFAAuF;IACvF,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,KAAK,IAAI,KAAK,SAAS,CAAC;CACtF;AAED,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC;IACnD,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC;IACnD,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IACnC,YAAY,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,qBAAa,YAAa,YAAW,SAAS;IAC7C,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,WAAW,CAAC,CAAQ;IAC5B,OAAO,CAAC,aAAa,CAAU;IAG/B,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,gBAAgB,CAAK;gBAG5B,KAAK,EAAE,WAAW,EAAE,EACpB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,iBAAiB,EACxB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,EAChD,QAAQ,EAAE,MAAM,IAAI,EACpB,OAAO,GAAE,mBAAwB;IAclC,oCAAoC;IACpC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAO/C,UAAU,IAAI,IAAI;IAIlB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAc/B,OAAO,CAAC,cAAc;IAwFtB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAiC/B,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,WAAW;CAanB"}
|
|
@@ -15,6 +15,8 @@ export class SettingsList {
|
|
|
15
15
|
// Submenu state
|
|
16
16
|
submenuComponent = null;
|
|
17
17
|
submenuItemIndex = null;
|
|
18
|
+
lastRenderLineCount = 0;
|
|
19
|
+
nextMinLineCount = 0;
|
|
18
20
|
constructor(items, maxVisible, theme, onChange, onCancel, options = {}) {
|
|
19
21
|
this.items = items;
|
|
20
22
|
this.filteredItems = items;
|
|
@@ -38,11 +40,15 @@ export class SettingsList {
|
|
|
38
40
|
this.submenuComponent?.invalidate?.();
|
|
39
41
|
}
|
|
40
42
|
render(width) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
const lines = this.submenuComponent
|
|
44
|
+
? this.submenuComponent.render(width)
|
|
45
|
+
: this.renderMainList(width);
|
|
46
|
+
if (this.nextMinLineCount > lines.length) {
|
|
47
|
+
lines.push(...Array.from({ length: this.nextMinLineCount - lines.length }, () => ""));
|
|
48
|
+
}
|
|
49
|
+
this.nextMinLineCount = 0;
|
|
50
|
+
this.lastRenderLineCount = lines.length;
|
|
51
|
+
return lines;
|
|
46
52
|
}
|
|
47
53
|
renderMainList(width) {
|
|
48
54
|
const lines = [];
|
|
@@ -148,7 +154,9 @@ export class SettingsList {
|
|
|
148
154
|
if (!item)
|
|
149
155
|
return;
|
|
150
156
|
if (item.submenu) {
|
|
151
|
-
//
|
|
157
|
+
// Preserve height for the first submenu frame so the TUI doesn't treat
|
|
158
|
+
// the editor→submenu swap as a destructive shrink/expand transition.
|
|
159
|
+
this.nextMinLineCount = this.lastRenderLineCount;
|
|
152
160
|
this.submenuItemIndex = this.selectedIndex;
|
|
153
161
|
this.submenuComponent = item.submenu(item.currentValue, (selectedValue) => {
|
|
154
162
|
if (selectedValue !== undefined) {
|
|
@@ -168,6 +176,9 @@ export class SettingsList {
|
|
|
168
176
|
}
|
|
169
177
|
}
|
|
170
178
|
closeSubmenu() {
|
|
179
|
+
// Preserve one frame of the submenu height so the transition back to the
|
|
180
|
+
// main settings list doesn't trigger a screen-clearing shrink redraw.
|
|
181
|
+
this.nextMinLineCount = this.lastRenderLineCount;
|
|
171
182
|
this.submenuComponent = null;
|
|
172
183
|
// Restore selection to the item that opened the submenu
|
|
173
184
|
if (this.submenuItemIndex !== null) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-list.js","sourceRoot":"","sources":["../../src/components/settings-list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AA6BnC,MAAM,OAAO,YAAY;IAChB,KAAK,CAAgB;IACrB,aAAa,CAAgB;IAC7B,KAAK,CAAoB;IACzB,aAAa,GAAG,CAAC,CAAC;IAClB,UAAU,CAAS;IACnB,QAAQ,CAAyC;IACjD,QAAQ,CAAa;IACrB,WAAW,CAAS;IACpB,aAAa,CAAU;IAE/B,gBAAgB;IACR,gBAAgB,GAAqB,IAAI,CAAC;IAC1C,gBAAgB,GAAkB,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"settings-list.js","sourceRoot":"","sources":["../../src/components/settings-list.ts"],"names":[],"mappings":"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"}
|
|
@@ -159,6 +159,16 @@ export declare class TUI extends Container {
|
|
|
159
159
|
* When false, empty rows remain (reduces redraws on slower terminals).
|
|
160
160
|
*/
|
|
161
161
|
setClearOnShrink(enabled: boolean): void;
|
|
162
|
+
/**
|
|
163
|
+
* Reset the startup grace period timer, suppressing screen-clearing full
|
|
164
|
+
* redraws for another {@link STARTUP_GRACE_MS} milliseconds.
|
|
165
|
+
*
|
|
166
|
+
* Call this at the start of a session switch so the chatContainer.clear()
|
|
167
|
+
* → renderInitialMessages() transition doesn't cause visible flicker.
|
|
168
|
+
*
|
|
169
|
+
* @returns {void}
|
|
170
|
+
*/
|
|
171
|
+
resetRenderGrace(): void;
|
|
162
172
|
/**
|
|
163
173
|
* Request that the next full render clears the terminal scrollback buffer.
|
|
164
174
|
*
|
|
@@ -186,9 +196,46 @@ export declare class TUI extends Container {
|
|
|
186
196
|
/** Find the topmost visible overlay, if any */
|
|
187
197
|
private getTopmostVisibleOverlay;
|
|
188
198
|
invalidate(): void;
|
|
199
|
+
/**
|
|
200
|
+
* Timestamp when `start()` was called.
|
|
201
|
+
* Used by startup grace period to suppress screen-clearing full redraws.
|
|
202
|
+
*/
|
|
203
|
+
private startedAtMs;
|
|
204
|
+
/**
|
|
205
|
+
* Duration (ms) after `start()` during which shrink-triggered full redraws
|
|
206
|
+
* use a gentler line-by-line overwrite instead of screen clear.
|
|
207
|
+
*
|
|
208
|
+
* This prevents the visual flicker that occurs when session resume causes
|
|
209
|
+
* rapid content height changes (extension hooks, widget adds/removes) before
|
|
210
|
+
* the full message history is rendered.
|
|
211
|
+
*/
|
|
212
|
+
private static readonly STARTUP_GRACE_MS;
|
|
189
213
|
start(): void;
|
|
190
214
|
private queryCellSize;
|
|
191
215
|
stop(): void;
|
|
216
|
+
/** When >0, scheduled renders are deferred until the batch completes. */
|
|
217
|
+
private renderBatchDepth;
|
|
218
|
+
/** Whether a render was requested while batching was active. */
|
|
219
|
+
private renderDeferredDuringBatch;
|
|
220
|
+
/** Whether a forced render was requested while batching was active. */
|
|
221
|
+
private renderForceDeferredDuringBatch;
|
|
222
|
+
/**
|
|
223
|
+
* Begin a render batch — all `requestRender()` calls are coalesced and
|
|
224
|
+
* deferred until the matching `endRenderBatch()`. Nestable.
|
|
225
|
+
*
|
|
226
|
+
* Use to prevent intermediate renders (and the screen clears they cause)
|
|
227
|
+
* during multi-step UI mutations such as session resume.
|
|
228
|
+
*
|
|
229
|
+
* @returns {void}
|
|
230
|
+
*/
|
|
231
|
+
beginRenderBatch(): void;
|
|
232
|
+
/**
|
|
233
|
+
* End a render batch. When the outermost batch ends, a single render is
|
|
234
|
+
* scheduled if any were deferred.
|
|
235
|
+
*
|
|
236
|
+
* @returns {void}
|
|
237
|
+
*/
|
|
238
|
+
endRenderBatch(): void;
|
|
192
239
|
requestRender(force?: boolean): void;
|
|
193
240
|
/**
|
|
194
241
|
* Schedule a single coalesced render in the check phase.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAGN,KAAK,UAAU,EAGf,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAKN,YAAY,EACZ,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,MAAM,WAAW,SAAS;IACzB;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAEhC;;OAEG;IACH,WAAW,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAEjC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,UAAU,IAAI,IAAI,CAAC;CACnB;AAED;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACzB,oFAAoF;IACpF,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,8DAA8D;AAC9D,wBAAgB,WAAW,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,IAAI,SAAS,GAAG,SAAS,CAE3F;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,sBAAkB,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB;;GAEG;AACH,MAAM,MAAM,aAAa,GACtB,QAAQ,GACR,UAAU,GACV,WAAW,GACX,aAAa,GACb,cAAc,GACd,YAAY,GACZ,eAAe,GACf,aAAa,GACb,cAAc,CAAC;AAElB;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,4EAA4E;AAC5E,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC;AAc9C;;;GAGG;AACH,MAAM,WAAW,cAAc;IAE9B,sEAAsE;IACtE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,SAAS,CAAC;IAGtB,uDAAuD;IACvD,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,gFAAgF;IAChF,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,4FAA4F;IAC5F,GAAG,CAAC,EAAE,SAAS,CAAC;IAGhB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;IAGhC;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;CAC7D;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,6DAA6D;IAC7D,IAAI,IAAI,IAAI,CAAC;IACb,2CAA2C;IAC3C,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,6CAA6C;IAC7C,QAAQ,IAAI,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,SAAU,YAAW,SAAS;IAC1C,QAAQ,EAAE,SAAS,EAAE,CAAM;IAE3B,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAIpC,WAAW,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAOvC,KAAK,IAAI,IAAI;IAIb,UAAU,IAAI,IAAI;IAMlB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAO/B;AAED;;GAEG;AACH,qBAAa,GAAI,SAAQ,SAAS;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IAC1B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,gBAAgB,CAA0B;IAElD,2GAA2G;IACpG,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B;;;;;OAKG;IACI,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC7C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,mBAAmB,CAAC,CAAgC;IAC5D,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,kBAAkB,CAA0C;IACpE,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,sBAAsB,CAAS;IAGvC,OAAO,CAAC,YAAY,CAKX;gBAEG,QAAQ,EAAE,QAAQ,EAAE,kBAAkB,CAAC,EAAE,OAAO;IAQ5D,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,qBAAqB,IAAI,OAAO;IAIhC,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAS7C,gBAAgB,IAAI,OAAO;IAI3B;;;;OAIG;IACH,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAIxC;;;;;;;;OAQG;IACH,gBAAgB,IAAI,IAAI;IAIxB;;;;;;;;;;OAUG;IACH,sBAAsB,IAAI,IAAI;IAI9B,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI;IAc3C;;;OAGG;IACH,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa;IA+C1E,2DAA2D;IAC3D,WAAW,IAAI,IAAI;IAUnB,8CAA8C;IAC9C,UAAU,IAAI,OAAO;IAIrB,qDAAqD;IACrD,OAAO,CAAC,gBAAgB;IAQxB,+CAA+C;IAC/C,OAAO,CAAC,wBAAwB;IASvB,UAAU,IAAI,IAAI;IAK3B;;;OAGG;IACH,OAAO,CAAC,WAAW,CAAK;IAExB;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;IAEhD,KAAK,IAAI,IAAI;IAYb,OAAO,CAAC,aAAa;IAiBrB,IAAI,IAAI,IAAI;IAuBZ,yEAAyE;IACzE,OAAO,CAAC,gBAAgB,CAAK;IAE7B,gEAAgE;IAChE,OAAO,CAAC,yBAAyB,CAAS;IAE1C,uEAAuE;IACvE,OAAO,CAAC,8BAA8B,CAAS;IAE/C;;;;;;;;OAQG;IACH,gBAAgB,IAAI,IAAI;IAIxB;;;;;OAKG;IACH,cAAc,IAAI,IAAI;IAWtB,aAAa,CAAC,KAAK,UAAQ,GAAG,IAAI;IAmBlC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,cAAc;IAUtB,qFAAqF;IACrF,OAAO,CAAC,cAAc,CAElB;IAEJ;;;;;;OAMG;IACH,gBAAgB,CACf,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,GAC1E,MAAM,IAAI;IAOb;;;;OAIG;IACH,mBAAmB,CAClB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,GAC1E,IAAI;IAIP,OAAO,CAAC,WAAW;IAkFnB,OAAO,CAAC,qBAAqB;IA0C7B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAqG5B,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,gBAAgB;IAsBxB,kFAAkF;IAClF,OAAO,CAAC,iBAAiB;IAmFzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAyB;IAE9D,OAAO,CAAC,eAAe;IAWvB,2FAA2F;IAC3F,OAAO,CAAC,eAAe;IAkDvB;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;IAuB7B,OAAO,CAAC,QAAQ;IAidhB;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;CAmC9B"}
|
|
@@ -128,6 +128,18 @@ export class TUI extends Container {
|
|
|
128
128
|
setClearOnShrink(enabled) {
|
|
129
129
|
this.clearOnShrink = enabled;
|
|
130
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Reset the startup grace period timer, suppressing screen-clearing full
|
|
133
|
+
* redraws for another {@link STARTUP_GRACE_MS} milliseconds.
|
|
134
|
+
*
|
|
135
|
+
* Call this at the start of a session switch so the chatContainer.clear()
|
|
136
|
+
* → renderInitialMessages() transition doesn't cause visible flicker.
|
|
137
|
+
*
|
|
138
|
+
* @returns {void}
|
|
139
|
+
*/
|
|
140
|
+
resetRenderGrace() {
|
|
141
|
+
this.startedAtMs = Date.now();
|
|
142
|
+
}
|
|
131
143
|
/**
|
|
132
144
|
* Request that the next full render clears the terminal scrollback buffer.
|
|
133
145
|
*
|
|
@@ -244,8 +256,23 @@ export class TUI extends Container {
|
|
|
244
256
|
for (const overlay of this.overlayStack)
|
|
245
257
|
overlay.component.invalidate?.();
|
|
246
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Timestamp when `start()` was called.
|
|
261
|
+
* Used by startup grace period to suppress screen-clearing full redraws.
|
|
262
|
+
*/
|
|
263
|
+
startedAtMs = 0;
|
|
264
|
+
/**
|
|
265
|
+
* Duration (ms) after `start()` during which shrink-triggered full redraws
|
|
266
|
+
* use a gentler line-by-line overwrite instead of screen clear.
|
|
267
|
+
*
|
|
268
|
+
* This prevents the visual flicker that occurs when session resume causes
|
|
269
|
+
* rapid content height changes (extension hooks, widget adds/removes) before
|
|
270
|
+
* the full message history is rendered.
|
|
271
|
+
*/
|
|
272
|
+
static STARTUP_GRACE_MS = 3000;
|
|
247
273
|
start() {
|
|
248
274
|
this.stopped = false;
|
|
275
|
+
this.startedAtMs = Date.now();
|
|
249
276
|
this.terminal.start((data) => this.handleInput(data), () => this.requestRender());
|
|
250
277
|
this.terminal.hideCursor();
|
|
251
278
|
this.queryCellSize();
|
|
@@ -289,6 +316,41 @@ export class TUI extends Container {
|
|
|
289
316
|
this.terminal.showCursor();
|
|
290
317
|
this.terminal.stop();
|
|
291
318
|
}
|
|
319
|
+
/** When >0, scheduled renders are deferred until the batch completes. */
|
|
320
|
+
renderBatchDepth = 0;
|
|
321
|
+
/** Whether a render was requested while batching was active. */
|
|
322
|
+
renderDeferredDuringBatch = false;
|
|
323
|
+
/** Whether a forced render was requested while batching was active. */
|
|
324
|
+
renderForceDeferredDuringBatch = false;
|
|
325
|
+
/**
|
|
326
|
+
* Begin a render batch — all `requestRender()` calls are coalesced and
|
|
327
|
+
* deferred until the matching `endRenderBatch()`. Nestable.
|
|
328
|
+
*
|
|
329
|
+
* Use to prevent intermediate renders (and the screen clears they cause)
|
|
330
|
+
* during multi-step UI mutations such as session resume.
|
|
331
|
+
*
|
|
332
|
+
* @returns {void}
|
|
333
|
+
*/
|
|
334
|
+
beginRenderBatch() {
|
|
335
|
+
this.renderBatchDepth++;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* End a render batch. When the outermost batch ends, a single render is
|
|
339
|
+
* scheduled if any were deferred.
|
|
340
|
+
*
|
|
341
|
+
* @returns {void}
|
|
342
|
+
*/
|
|
343
|
+
endRenderBatch() {
|
|
344
|
+
if (this.renderBatchDepth <= 0)
|
|
345
|
+
return;
|
|
346
|
+
this.renderBatchDepth--;
|
|
347
|
+
if (this.renderBatchDepth === 0 && this.renderDeferredDuringBatch) {
|
|
348
|
+
const wasForce = this.renderForceDeferredDuringBatch;
|
|
349
|
+
this.renderDeferredDuringBatch = false;
|
|
350
|
+
this.renderForceDeferredDuringBatch = false;
|
|
351
|
+
this.requestRender(wasForce);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
292
354
|
requestRender(force = false) {
|
|
293
355
|
if (force) {
|
|
294
356
|
this.previousLines = [];
|
|
@@ -299,6 +361,12 @@ export class TUI extends Container {
|
|
|
299
361
|
this.previousViewportTop = 0;
|
|
300
362
|
this.rollingShrinkPeak = 0;
|
|
301
363
|
}
|
|
364
|
+
if (this.renderBatchDepth > 0) {
|
|
365
|
+
this.renderDeferredDuringBatch = true;
|
|
366
|
+
if (force)
|
|
367
|
+
this.renderForceDeferredDuringBatch = true;
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
302
370
|
if (this.renderRequested)
|
|
303
371
|
return;
|
|
304
372
|
this.scheduleRender();
|
|
@@ -747,6 +815,9 @@ export class TUI extends Container {
|
|
|
747
815
|
newLines = this.applyLineResets(newLines);
|
|
748
816
|
// Width changed - need full re-render (line wrapping changes)
|
|
749
817
|
const widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;
|
|
818
|
+
// Whether we are within the startup grace period where screen-clearing
|
|
819
|
+
// full redraws are softened to prevent flicker during session resume.
|
|
820
|
+
const inStartupGrace = this.startedAtMs > 0 && Date.now() - this.startedAtMs < TUI.STARTUP_GRACE_MS;
|
|
750
821
|
// Helper to clear viewport (and optionally scrollback) and render all new lines
|
|
751
822
|
const fullRender = (clear) => {
|
|
752
823
|
this.fullRedrawCount += 1;
|
|
@@ -780,6 +851,44 @@ export class TUI extends Container {
|
|
|
780
851
|
this.previousLines = newLines;
|
|
781
852
|
this.previousWidth = width;
|
|
782
853
|
};
|
|
854
|
+
/**
|
|
855
|
+
* Gentle full redraw: home cursor + overwrite each line + clear below.
|
|
856
|
+
*
|
|
857
|
+
* Used during the startup grace period instead of fullRender(true) for
|
|
858
|
+
* shrink-triggered redraws. Avoids the visible blank frame caused by
|
|
859
|
+
* `\x1b[2J` (clear screen), which makes messages appear to flash in and
|
|
860
|
+
* out when session resume triggers rapid content height changes.
|
|
861
|
+
*
|
|
862
|
+
* Unlike fullRender(true), this never clears the screen — it writes each
|
|
863
|
+
* line with a preceding `\x1b[2K` (clear line) so stale content is
|
|
864
|
+
* overwritten without a blank frame. Lines below the new content are
|
|
865
|
+
* individually erased.
|
|
866
|
+
*/
|
|
867
|
+
const gentleFullRender = () => {
|
|
868
|
+
this.fullRedrawCount += 1;
|
|
869
|
+
let buffer = "\x1b[?2026h\x1b[H"; // Begin synchronized output + home cursor
|
|
870
|
+
for (let i = 0; i < newLines.length; i++) {
|
|
871
|
+
buffer += "\x1b[2K"; // Clear current line
|
|
872
|
+
buffer += newLines[i];
|
|
873
|
+
if (i < newLines.length - 1)
|
|
874
|
+
buffer += "\r\n";
|
|
875
|
+
}
|
|
876
|
+
// Erase lines that were previously rendered but are no longer needed
|
|
877
|
+
const staleLines = Math.max(0, this.maxLinesRendered - newLines.length);
|
|
878
|
+
for (let i = 0; i < staleLines; i++) {
|
|
879
|
+
buffer += "\r\n\x1b[2K";
|
|
880
|
+
}
|
|
881
|
+
buffer += "\x1b[?2026l"; // End synchronized output
|
|
882
|
+
this.terminal.write(buffer);
|
|
883
|
+
this.cursorRow = Math.max(0, newLines.length + staleLines - 1);
|
|
884
|
+
this.hardwareCursorRow = this.cursorRow;
|
|
885
|
+
this.maxLinesRendered = newLines.length;
|
|
886
|
+
this.previousViewportTop = Math.max(0, this.maxLinesRendered - height);
|
|
887
|
+
this.rollingShrinkPeak = newLines.length;
|
|
888
|
+
this.positionHardwareCursor(cursorPos, newLines.length);
|
|
889
|
+
this.previousLines = newLines;
|
|
890
|
+
this.previousWidth = width;
|
|
891
|
+
};
|
|
783
892
|
const debugRedraw = process.env.PI_DEBUG_REDRAW === "1";
|
|
784
893
|
const logRedraw = (reason) => {
|
|
785
894
|
if (!debugRedraw)
|
|
@@ -807,7 +916,12 @@ export class TUI extends Container {
|
|
|
807
916
|
newLines.length < this.maxLinesRendered &&
|
|
808
917
|
this.overlayStack.length === 0) {
|
|
809
918
|
logRedraw(`clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);
|
|
810
|
-
|
|
919
|
+
if (inStartupGrace) {
|
|
920
|
+
gentleFullRender();
|
|
921
|
+
}
|
|
922
|
+
else {
|
|
923
|
+
fullRender(true);
|
|
924
|
+
}
|
|
811
925
|
return;
|
|
812
926
|
}
|
|
813
927
|
// Large content shrinks (e.g., tool output collapse) are hard to partially redraw
|
|
@@ -817,7 +931,12 @@ export class TUI extends Container {
|
|
|
817
931
|
const shrinkDelta = this.previousLines.length - newLines.length;
|
|
818
932
|
if (shrinkDelta > 5 && this.overlayStack.length === 0) {
|
|
819
933
|
logRedraw(`large shrink (${shrinkDelta} lines)`);
|
|
820
|
-
|
|
934
|
+
if (inStartupGrace) {
|
|
935
|
+
gentleFullRender();
|
|
936
|
+
}
|
|
937
|
+
else {
|
|
938
|
+
fullRender(true);
|
|
939
|
+
}
|
|
821
940
|
return;
|
|
822
941
|
}
|
|
823
942
|
// Rolling shrink detection: catches gradual shrinks where each individual
|
|
@@ -830,7 +949,12 @@ export class TUI extends Container {
|
|
|
830
949
|
}
|
|
831
950
|
else if (this.overlayStack.length === 0 && this.rollingShrinkPeak - newLines.length > 5) {
|
|
832
951
|
logRedraw(`rolling shrink (peak=${this.rollingShrinkPeak}, now=${newLines.length}, delta=${this.rollingShrinkPeak - newLines.length})`);
|
|
833
|
-
|
|
952
|
+
if (inStartupGrace) {
|
|
953
|
+
gentleFullRender();
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
fullRender(true);
|
|
957
|
+
}
|
|
834
958
|
return;
|
|
835
959
|
}
|
|
836
960
|
const previousContentViewportTop = Math.max(0, this.previousLines.length - height);
|
|
@@ -899,7 +1023,12 @@ export class TUI extends Container {
|
|
|
899
1023
|
const extraLines = this.previousLines.length - newLines.length;
|
|
900
1024
|
if (extraLines > height) {
|
|
901
1025
|
logRedraw(`extraLines > height (${extraLines} > ${height})`);
|
|
902
|
-
|
|
1026
|
+
if (inStartupGrace) {
|
|
1027
|
+
gentleFullRender();
|
|
1028
|
+
}
|
|
1029
|
+
else {
|
|
1030
|
+
fullRender(true);
|
|
1031
|
+
}
|
|
903
1032
|
return;
|
|
904
1033
|
}
|
|
905
1034
|
if (extraLines > 0) {
|
|
@@ -927,7 +1056,12 @@ export class TUI extends Container {
|
|
|
927
1056
|
// If first changed line is above the current viewport basis, partial redraw is unsafe.
|
|
928
1057
|
if (firstChanged < prevViewportTop) {
|
|
929
1058
|
logRedraw(`firstChanged < viewportTop (${firstChanged} < ${prevViewportTop})`);
|
|
930
|
-
|
|
1059
|
+
if (inStartupGrace) {
|
|
1060
|
+
gentleFullRender();
|
|
1061
|
+
}
|
|
1062
|
+
else {
|
|
1063
|
+
fullRender(true);
|
|
1064
|
+
}
|
|
931
1065
|
return;
|
|
932
1066
|
}
|
|
933
1067
|
// Render from first changed line to end
|