pi-cockpit 0.20.0 → 0.21.0
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/package.json +85 -85
- package/src/config.ts +2 -0
- package/src/index.ts +25 -15
- package/src/public/v1/events.ts +2 -0
- package/src/settings/cockpit-provider.ts +8 -2
- package/src/types.ts +3 -0
- package/src/viewport-stability.ts +12 -21
package/package.json
CHANGED
|
@@ -1,85 +1,85 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "pi-cockpit",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Responsive Maestro operations sidebar, fallback status widgets, and footer for Pi.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"keywords": [
|
|
7
|
-
"pi-package",
|
|
8
|
-
"pi",
|
|
9
|
-
"pi-extension",
|
|
10
|
-
"tui",
|
|
11
|
-
"teammate",
|
|
12
|
-
"todo"
|
|
13
|
-
],
|
|
14
|
-
"license": "MIT",
|
|
15
|
-
"files": [
|
|
16
|
-
"src/",
|
|
17
|
-
"themes/",
|
|
18
|
-
"README.md"
|
|
19
|
-
],
|
|
20
|
-
"scripts": {
|
|
21
|
-
"test": "node --test --experimental-transform-types tests/config.test.ts tests/public-events.test.ts tests/maestro-store.test.ts tests/split-pane.test.ts tests/editor-bottom.test.ts tests/sidebar-render.test.ts tests/sidebar-controller.test.ts tests/viewport-stability.test.ts tests/quiet-tools.test.ts tests/edit-guard.test.ts tests/agents-store.test.ts tests/endpoint-store.test.ts tests/session-ui-state.test.ts tests/session-tabs.test.ts tests/agent-bar.test.ts tests/supervision-store.test.ts tests/bash-bg-store.test.ts tests/bash-bg-widget.test.ts tests/bash-bg-overlay.test.ts tests/todo-overlay.test.ts tests/agent-overlay.test.ts tests/todo-store.test.ts tests/render.test.ts tests/agent-scroll.test.ts tests/session-bar.test.ts tests/session-detail.test.ts tests/footer.test.ts tests/extension-status.test.ts tests/teammate-message.test.ts tests/input-routing.test.ts tests/input-history-store.test.ts tests/unified-editor.test.ts tests/integration-contract.test.ts tests/stack-widget.test.ts tests/zen-render.test.ts tests/zen-browse.test.ts tests/zen-sheet.test.ts tests/settings-view.test.ts tests/thinking-fold.test.ts tests/thinking-timer.test.ts tests/tick-policy.test.ts tests/ambient.test.ts tests/viewport.test.ts tests/theme-picker.test.ts tests/model-picker.test.ts tests/title-gen.test.ts tests/title-llm.test.ts tests/settings-registry.test.ts tests/settings-coordinator.test.ts tests/settings-locale.test.ts tests/tui-i18n.test.ts tests/settings-shell.test.ts tests/settings-cockpit-provider.test.ts tests/settings-cross-package.test.ts tests/ui-primitives.test.ts tests/settings-shell-secret.test.ts tests/settings-shell-listcrud.test.ts tests/capturing-overlay.test.ts tests/claude-editor.test.ts tests/fullscreen-controller.test.ts tests/transcript-selection.test.ts tests/terminal-cleanup.test.ts tests/terminal-capability.test.ts tests/usage-core.test.ts tests/usage-extension.test.ts tests/usage-history.test.ts tests/usage-sparkline.test.ts",
|
|
22
|
-
"typecheck": "tsc --noEmit",
|
|
23
|
-
"prepack": "node ../../scripts/bundle-settings-core.mjs",
|
|
24
|
-
"postpack": "node ../../scripts/bundle-settings-core.mjs --clean"
|
|
25
|
-
},
|
|
26
|
-
"pi": {
|
|
27
|
-
"extensions": [
|
|
28
|
-
"./src/extension/index.ts"
|
|
29
|
-
],
|
|
30
|
-
"themes": [
|
|
31
|
-
"./themes"
|
|
32
|
-
]
|
|
33
|
-
},
|
|
34
|
-
"dependencies": {
|
|
35
|
-
"pi-maestro-settings-core": "0.2.1",
|
|
36
|
-
"proper-lockfile": "4.1.2"
|
|
37
|
-
},
|
|
38
|
-
"bundledDependencies": [
|
|
39
|
-
"pi-maestro-settings-core"
|
|
40
|
-
],
|
|
41
|
-
"peerDependencies": {
|
|
42
|
-
"@earendil-works/pi-agent-core": "*",
|
|
43
|
-
"@earendil-works/pi-ai": "*",
|
|
44
|
-
"@earendil-works/pi-coding-agent": "*",
|
|
45
|
-
"@earendil-works/pi-tui": "*",
|
|
46
|
-
"pi-maestro-teammate": "^2.
|
|
47
|
-
"typebox": "*"
|
|
48
|
-
},
|
|
49
|
-
"peerDependenciesMeta": {
|
|
50
|
-
"@earendil-works/pi-agent-core": {
|
|
51
|
-
"optional": true
|
|
52
|
-
},
|
|
53
|
-
"@earendil-works/pi-ai": {
|
|
54
|
-
"optional": true
|
|
55
|
-
},
|
|
56
|
-
"@earendil-works/pi-coding-agent": {
|
|
57
|
-
"optional": true
|
|
58
|
-
},
|
|
59
|
-
"@earendil-works/pi-tui": {
|
|
60
|
-
"optional": true
|
|
61
|
-
},
|
|
62
|
-
"pi-maestro-teammate": {
|
|
63
|
-
"optional": true
|
|
64
|
-
},
|
|
65
|
-
"typebox": {
|
|
66
|
-
"optional": true
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
"devDependencies": {
|
|
70
|
-
"@earendil-works/pi-agent-core": "0.84.4",
|
|
71
|
-
"@earendil-works/pi-ai": "0.84.4",
|
|
72
|
-
"@earendil-works/pi-coding-agent": "0.84.4",
|
|
73
|
-
"@earendil-works/pi-tui": "0.84.4",
|
|
74
|
-
"@types/node": "^22.0.0",
|
|
75
|
-
"pi-maestro-teammate": "2.
|
|
76
|
-
"typebox": "1.3.7",
|
|
77
|
-
"typescript": "^5.5.0"
|
|
78
|
-
},
|
|
79
|
-
"main": "./src/index.ts",
|
|
80
|
-
"exports": {
|
|
81
|
-
".": "./src/index.ts",
|
|
82
|
-
"./v1/events": "./src/public/v1/events.ts",
|
|
83
|
-
"./src/*": "./src/*"
|
|
84
|
-
}
|
|
85
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-cockpit",
|
|
3
|
+
"version": "0.21.0",
|
|
4
|
+
"description": "Responsive Maestro operations sidebar, fallback status widgets, and footer for Pi.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"pi-package",
|
|
8
|
+
"pi",
|
|
9
|
+
"pi-extension",
|
|
10
|
+
"tui",
|
|
11
|
+
"teammate",
|
|
12
|
+
"todo"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"files": [
|
|
16
|
+
"src/",
|
|
17
|
+
"themes/",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"test": "node --test --experimental-transform-types tests/config.test.ts tests/public-events.test.ts tests/maestro-store.test.ts tests/split-pane.test.ts tests/editor-bottom.test.ts tests/sidebar-render.test.ts tests/sidebar-controller.test.ts tests/viewport-stability.test.ts tests/quiet-tools.test.ts tests/edit-guard.test.ts tests/agents-store.test.ts tests/endpoint-store.test.ts tests/session-ui-state.test.ts tests/session-tabs.test.ts tests/agent-bar.test.ts tests/supervision-store.test.ts tests/bash-bg-store.test.ts tests/bash-bg-widget.test.ts tests/bash-bg-overlay.test.ts tests/todo-overlay.test.ts tests/agent-overlay.test.ts tests/todo-store.test.ts tests/render.test.ts tests/agent-scroll.test.ts tests/session-bar.test.ts tests/session-detail.test.ts tests/footer.test.ts tests/extension-status.test.ts tests/teammate-message.test.ts tests/input-routing.test.ts tests/input-history-store.test.ts tests/unified-editor.test.ts tests/integration-contract.test.ts tests/stack-widget.test.ts tests/zen-render.test.ts tests/zen-browse.test.ts tests/zen-sheet.test.ts tests/settings-view.test.ts tests/thinking-fold.test.ts tests/thinking-timer.test.ts tests/tick-policy.test.ts tests/ambient.test.ts tests/viewport.test.ts tests/theme-picker.test.ts tests/model-picker.test.ts tests/title-gen.test.ts tests/title-llm.test.ts tests/settings-registry.test.ts tests/settings-coordinator.test.ts tests/settings-locale.test.ts tests/tui-i18n.test.ts tests/settings-shell.test.ts tests/settings-cockpit-provider.test.ts tests/settings-cross-package.test.ts tests/ui-primitives.test.ts tests/settings-shell-secret.test.ts tests/settings-shell-listcrud.test.ts tests/capturing-overlay.test.ts tests/claude-editor.test.ts tests/fullscreen-controller.test.ts tests/transcript-selection.test.ts tests/terminal-cleanup.test.ts tests/terminal-capability.test.ts tests/usage-core.test.ts tests/usage-extension.test.ts tests/usage-history.test.ts tests/usage-sparkline.test.ts",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"prepack": "node ../../scripts/bundle-settings-core.mjs",
|
|
24
|
+
"postpack": "node ../../scripts/bundle-settings-core.mjs --clean"
|
|
25
|
+
},
|
|
26
|
+
"pi": {
|
|
27
|
+
"extensions": [
|
|
28
|
+
"./src/extension/index.ts"
|
|
29
|
+
],
|
|
30
|
+
"themes": [
|
|
31
|
+
"./themes"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"pi-maestro-settings-core": "0.2.1",
|
|
36
|
+
"proper-lockfile": "4.1.2"
|
|
37
|
+
},
|
|
38
|
+
"bundledDependencies": [
|
|
39
|
+
"pi-maestro-settings-core"
|
|
40
|
+
],
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@earendil-works/pi-agent-core": "*",
|
|
43
|
+
"@earendil-works/pi-ai": "*",
|
|
44
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
45
|
+
"@earendil-works/pi-tui": "*",
|
|
46
|
+
"pi-maestro-teammate": "^2.4.0",
|
|
47
|
+
"typebox": "*"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"@earendil-works/pi-agent-core": {
|
|
51
|
+
"optional": true
|
|
52
|
+
},
|
|
53
|
+
"@earendil-works/pi-ai": {
|
|
54
|
+
"optional": true
|
|
55
|
+
},
|
|
56
|
+
"@earendil-works/pi-coding-agent": {
|
|
57
|
+
"optional": true
|
|
58
|
+
},
|
|
59
|
+
"@earendil-works/pi-tui": {
|
|
60
|
+
"optional": true
|
|
61
|
+
},
|
|
62
|
+
"pi-maestro-teammate": {
|
|
63
|
+
"optional": true
|
|
64
|
+
},
|
|
65
|
+
"typebox": {
|
|
66
|
+
"optional": true
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@earendil-works/pi-agent-core": "0.84.4",
|
|
71
|
+
"@earendil-works/pi-ai": "0.84.4",
|
|
72
|
+
"@earendil-works/pi-coding-agent": "0.84.4",
|
|
73
|
+
"@earendil-works/pi-tui": "0.84.4",
|
|
74
|
+
"@types/node": "^22.0.0",
|
|
75
|
+
"pi-maestro-teammate": "2.4.0",
|
|
76
|
+
"typebox": "1.3.7",
|
|
77
|
+
"typescript": "^5.5.0"
|
|
78
|
+
},
|
|
79
|
+
"main": "./src/index.ts",
|
|
80
|
+
"exports": {
|
|
81
|
+
".": "./src/index.ts",
|
|
82
|
+
"./v1/events": "./src/public/v1/events.ts",
|
|
83
|
+
"./src/*": "./src/*"
|
|
84
|
+
}
|
|
85
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -76,6 +76,7 @@ const isCurrencyMode = (v: unknown): v is CurrencyMode => v === "usd" || v === "
|
|
|
76
76
|
agentsMode: isMode(o.agentsMode) ? o.agentsMode : base.agentsMode,
|
|
77
77
|
todoMode: isMode(o.todoMode) ? o.todoMode : base.todoMode,
|
|
78
78
|
todoExpanded: typeof o.todoExpanded === "boolean" ? o.todoExpanded : base.todoExpanded,
|
|
79
|
+
todoDurationChart: typeof o.todoDurationChart === "boolean" ? o.todoDurationChart : base.todoDurationChart,
|
|
79
80
|
stackStyle: isStackStyle(o.stackStyle) ? o.stackStyle : base.stackStyle,
|
|
80
81
|
hideNativeAgents: typeof o.hideNativeAgents === "boolean" ? o.hideNativeAgents : base.hideNativeAgents,
|
|
81
82
|
pinEditorBottom: typeof o.pinEditorBottom === "boolean" ? o.pinEditorBottom : base.pinEditorBottom,
|
|
@@ -168,6 +169,7 @@ export function mergeConfigDocument(raw: unknown, config: CockpitConfig): Record
|
|
|
168
169
|
agentsMode: config.agentsMode,
|
|
169
170
|
todoMode: config.todoMode,
|
|
170
171
|
todoExpanded: config.todoExpanded,
|
|
172
|
+
todoDurationChart: config.todoDurationChart,
|
|
171
173
|
stackStyle: config.stackStyle,
|
|
172
174
|
hideNativeAgents: config.hideNativeAgents,
|
|
173
175
|
pinEditorBottom: config.pinEditorBottom,
|
package/src/index.ts
CHANGED
|
@@ -357,6 +357,27 @@ export default function (pi: ExtensionAPI): void {
|
|
|
357
357
|
// thinking label / teammate tree still stream above the visible viewport.
|
|
358
358
|
let stabilityTui: TUI | undefined;
|
|
359
359
|
let viewportStabilityPatch: ViewportStabilityPatch | undefined;
|
|
360
|
+
const ensureViewportStability = (tui: TUI): void => {
|
|
361
|
+
// Native fullscreen owns a fixed application viewport and has no main-screen
|
|
362
|
+
// applyLineResets hook. Do not cache that expected miss: the same dynamic TUI
|
|
363
|
+
// reference can later dispatch to the regular renderer.
|
|
364
|
+
if (tui.mode === "fullscreen") return;
|
|
365
|
+
if (stabilityTui === tui && viewportStabilityPatch?.active) return;
|
|
366
|
+
viewportStabilityPatch?.detach();
|
|
367
|
+
const patch = attachViewportStability(tui);
|
|
368
|
+
viewportStabilityPatch = patch;
|
|
369
|
+
stabilityTui = patch.active ? tui : undefined;
|
|
370
|
+
};
|
|
371
|
+
const requestCapturedRender = (): void => {
|
|
372
|
+
try {
|
|
373
|
+
const tui = capturedTui;
|
|
374
|
+
if (!tui) return;
|
|
375
|
+
ensureViewportStability(tui);
|
|
376
|
+
tui.requestRender();
|
|
377
|
+
} catch {
|
|
378
|
+
// tui may be gone between sessions
|
|
379
|
+
}
|
|
380
|
+
};
|
|
360
381
|
// True while Cockpit owns a capturing overlay (bash jobs, theme picker,
|
|
361
382
|
// settings panel). Split-pane resize must yield to the overlay's focus and
|
|
362
383
|
// refuse to start while one is open; otherwise the resize listener — a
|
|
@@ -455,13 +476,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
455
476
|
// while the model thinks, then the settled duration. Pi owns the fold.
|
|
456
477
|
const thinkingTimer = new ThinkingFoldTimer({
|
|
457
478
|
getTui: () => capturedTui,
|
|
458
|
-
requestRender:
|
|
459
|
-
try {
|
|
460
|
-
capturedTui?.requestRender();
|
|
461
|
-
} catch {
|
|
462
|
-
// tui may be gone between sessions
|
|
463
|
-
}
|
|
464
|
-
},
|
|
479
|
+
requestRender: requestCapturedRender,
|
|
465
480
|
getBaseLabel: () => (config.quietMode ? quietThinkingLabel() : undefined),
|
|
466
481
|
getGlyphs: () => resolveGlyphs(config.icons.mode),
|
|
467
482
|
isThinkingHidden: () => (lastCtx ? readHideThinkingBlock(lastCtx.cwd) : false),
|
|
@@ -601,7 +616,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
601
616
|
if (refreshAmbientSurface) refreshAmbient(now);
|
|
602
617
|
if (agentPriorityChanged) publishUiOwnership();
|
|
603
618
|
try {
|
|
604
|
-
|
|
619
|
+
requestCapturedRender();
|
|
605
620
|
activeAgentOverlayRender?.();
|
|
606
621
|
sidebarController?.requestRender();
|
|
607
622
|
} catch {
|
|
@@ -691,6 +706,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
691
706
|
sidebar: ownsDock,
|
|
692
707
|
goal: ownsDock,
|
|
693
708
|
todoExpanded: effectiveTodoExpanded(),
|
|
709
|
+
todoDurationChart: config.todoDurationChart,
|
|
694
710
|
quiet: config.enabled && config.quietMode,
|
|
695
711
|
quietSymbols: config.quietSymbols,
|
|
696
712
|
static: config.staticMode,
|
|
@@ -747,13 +763,6 @@ export default function (pi: ExtensionAPI): void {
|
|
|
747
763
|
};
|
|
748
764
|
|
|
749
765
|
|
|
750
|
-
const ensureViewportStability = (tui: TUI): void => {
|
|
751
|
-
if (stabilityTui === tui) return;
|
|
752
|
-
viewportStabilityPatch?.detach();
|
|
753
|
-
viewportStabilityPatch = attachViewportStability(tui);
|
|
754
|
-
stabilityTui = tui;
|
|
755
|
-
};
|
|
756
|
-
|
|
757
766
|
const sessionListOverlayActive = (): boolean =>
|
|
758
767
|
capturingOverlayActive || ambientKeysShouldYield(capturedTui);
|
|
759
768
|
|
|
@@ -1916,6 +1925,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
1916
1925
|
sidebar: false,
|
|
1917
1926
|
goal: false,
|
|
1918
1927
|
todoExpanded: config.todoExpanded,
|
|
1928
|
+
todoDurationChart: config.todoDurationChart,
|
|
1919
1929
|
quiet: false,
|
|
1920
1930
|
quietSymbols: config.quietSymbols,
|
|
1921
1931
|
static: config.staticMode,
|
package/src/public/v1/events.ts
CHANGED
|
@@ -195,6 +195,8 @@ export interface CockpitUiOwnershipV1 {
|
|
|
195
195
|
/** True only while the dock renders Maestro Goal state. */
|
|
196
196
|
goal: boolean;
|
|
197
197
|
todoExpanded: boolean;
|
|
198
|
+
/** Whether Flow should render the duration chart after a terminal todo advance. */
|
|
199
|
+
todoDurationChart?: boolean;
|
|
198
200
|
quiet: boolean;
|
|
199
201
|
quietSymbols: "check" | "dot";
|
|
200
202
|
/** Static mode: per-second churn (elapsed ticks, spinners) is suppressed. */
|
|
@@ -68,6 +68,7 @@ const CONFIG_KEYS = [
|
|
|
68
68
|
"agentsMode",
|
|
69
69
|
"todoMode",
|
|
70
70
|
"todoExpanded",
|
|
71
|
+
"todoDurationChart",
|
|
71
72
|
"stackStyle",
|
|
72
73
|
"hideNativeAgents",
|
|
73
74
|
"toolPalette",
|
|
@@ -164,6 +165,8 @@ const CATALOGS = {
|
|
|
164
165
|
"cockpit.agentsMode": "Agent display",
|
|
165
166
|
"cockpit.todoMode": "Todo display",
|
|
166
167
|
"cockpit.todoExpanded": "Todo expanded",
|
|
168
|
+
"cockpit.todoDurationChart": "Advance duration chart",
|
|
169
|
+
"cockpit.todoDurationChart.description": "Show a task-duration chart after advance completes the entire Todo list.",
|
|
167
170
|
"cockpit.stackStyle": "Stack projection",
|
|
168
171
|
"cockpit.hideNativeAgents": "Hide native agent widget",
|
|
169
172
|
"cockpit.icons.mode": "Icon mode",
|
|
@@ -249,6 +252,8 @@ const CATALOGS = {
|
|
|
249
252
|
"cockpit.agentsMode": "Agent 显示",
|
|
250
253
|
"cockpit.todoMode": "Todo 显示",
|
|
251
254
|
"cockpit.todoExpanded": "展开 Todo",
|
|
255
|
+
"cockpit.todoDurationChart": "Advance 耗时图",
|
|
256
|
+
"cockpit.todoDurationChart.description": "当 advance 完成整个 Todo 列表后显示任务耗时统计图。",
|
|
252
257
|
"cockpit.stackStyle": "栈投影",
|
|
253
258
|
"cockpit.hideNativeAgents": "隐藏原生 Agent 面板",
|
|
254
259
|
"cockpit.icons.mode": "图标模式",
|
|
@@ -367,8 +372,9 @@ const DEFINITIONS: readonly SettingDefinition[] = [
|
|
|
367
372
|
enumDefinition("agentsMode", "cockpit.group.panels", 0, "cockpit.agentsMode", ["list", "compact"], "live"),
|
|
368
373
|
enumDefinition("todoMode", "cockpit.group.panels", 1, "cockpit.todoMode", ["list", "compact"], "live"),
|
|
369
374
|
booleanDefinition("todoExpanded", "cockpit.group.panels", 2, "cockpit.todoExpanded", "live"),
|
|
375
|
+
booleanDefinition("todoDurationChart", "cockpit.group.panels", 3, "cockpit.todoDurationChart", "live", "cockpit.todoDurationChart.description"),
|
|
370
376
|
enumDefinition("stackStyle", "cockpit.group.layout", 4, "cockpit.stackStyle", ["classic", "zen"], "live"),
|
|
371
|
-
booleanDefinition("hideNativeAgents", "cockpit.group.panels",
|
|
377
|
+
booleanDefinition("hideNativeAgents", "cockpit.group.panels", 4, "cockpit.hideNativeAgents", "live"),
|
|
372
378
|
enumDefinition("sidebar.mode", "cockpit.group.sidebar", 0, "cockpit.sidebar.mode", ["auto", "on", "off"], "live"),
|
|
373
379
|
{
|
|
374
380
|
key: "sidebar.width",
|
|
@@ -789,7 +795,7 @@ function setUsageValue(usage: CockpitConfig["usage"], field: string, value: Json
|
|
|
789
795
|
}
|
|
790
796
|
|
|
791
797
|
function validValue(key: CockpitSettingKey, value: JsonValue): boolean {
|
|
792
|
-
if (["enabled", "staticMode", "pinEditorBottom", "doubleEscapeClearInput", "fullscreenInput", "copyOnSelect", "historyEnabled", "quietMode", "todoExpanded", "hideNativeAgents"].includes(key)) return typeof value === "boolean";
|
|
798
|
+
if (["enabled", "staticMode", "pinEditorBottom", "doubleEscapeClearInput", "fullscreenInput", "copyOnSelect", "historyEnabled", "quietMode", "todoExpanded", "todoDurationChart", "hideNativeAgents"].includes(key)) return typeof value === "boolean";
|
|
793
799
|
if (key === "sidebar.width") return typeof value === "number" && Number.isSafeInteger(value) && value >= 32 && value <= 56;
|
|
794
800
|
if (key === "title.maxLength") return typeof value === "number" && Number.isSafeInteger(value) && value >= 20 && value <= 200;
|
|
795
801
|
if (key === "title.generationModel") return typeof value === "string";
|
package/src/types.ts
CHANGED
|
@@ -260,6 +260,8 @@ export interface CockpitConfig {
|
|
|
260
260
|
agentsMode: ViewMode;
|
|
261
261
|
todoMode: ViewMode;
|
|
262
262
|
todoExpanded: boolean;
|
|
263
|
+
/** Show the duration chart after a terminal todo advance. */
|
|
264
|
+
todoDurationChart: boolean;
|
|
263
265
|
/** Above-editor stack projection: classic Todo/Agents widgets or the unified Zen stack. */
|
|
264
266
|
stackStyle: StackStyle;
|
|
265
267
|
hideNativeAgents: boolean;
|
|
@@ -318,6 +320,7 @@ export const DEFAULT_CONFIG: CockpitConfig = {
|
|
|
318
320
|
agentsMode: "list",
|
|
319
321
|
todoMode: "list",
|
|
320
322
|
todoExpanded: false,
|
|
323
|
+
todoDurationChart: true,
|
|
321
324
|
stackStyle: "classic",
|
|
322
325
|
hideNativeAgents: true,
|
|
323
326
|
pinEditorBottom: false,
|
|
@@ -10,7 +10,8 @@ interface ViewportTuiInternals {
|
|
|
10
10
|
previousLines?: string[];
|
|
11
11
|
previousViewportTop?: number;
|
|
12
12
|
previousHeight?: number;
|
|
13
|
-
|
|
13
|
+
previousWidth?: number;
|
|
14
|
+
terminal?: { columns: number; rows: number };
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
interface ViewportStabilityMarker {
|
|
@@ -44,18 +45,6 @@ function markerOf(fn: ApplyLineResets): ViewportStabilityMarker | undefined {
|
|
|
44
45
|
return (fn as ApplyLineResets & Record<symbol, ViewportStabilityMarker | undefined>)[VIEWPORT_STABILITY_MARKER];
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
const ANSI_ESCAPE = /\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1b\\))/g;
|
|
48
|
-
const TRAILING_DURATION = /(\s(?:·\s*)?)(?:\d+(?:\.\d+)?s|\d+m\d{1,2}s)$/;
|
|
49
|
-
|
|
50
|
-
function differsOnlyByTrailingDuration(previous: string, next: string): boolean {
|
|
51
|
-
const previousPlain = previous.replace(ANSI_ESCAPE, "");
|
|
52
|
-
const nextPlain = next.replace(ANSI_ESCAPE, "");
|
|
53
|
-
if (previousPlain === nextPlain) return false;
|
|
54
|
-
if (!TRAILING_DURATION.test(previousPlain) || !TRAILING_DURATION.test(nextPlain)) return false;
|
|
55
|
-
return previousPlain.replace(TRAILING_DURATION, "$1<duration>")
|
|
56
|
-
=== nextPlain.replace(TRAILING_DURATION, "$1<duration>");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
48
|
function isKittyImageLine(line: string | undefined): boolean {
|
|
60
49
|
return typeof line === "string" && line.includes("\x1b_G");
|
|
61
50
|
}
|
|
@@ -110,13 +99,17 @@ function resolveApplyLineResetsSlot(internals: ViewportTuiInternals): ApplyLineR
|
|
|
110
99
|
}
|
|
111
100
|
|
|
112
101
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
102
|
+
* Treats the hidden viewport prefix as immutable scrollback while frame size is
|
|
103
|
+
* stable. The next frame keeps the terminal's actual hidden text, so visible
|
|
104
|
+
* changes can use pi-tui's differential path instead of clearing and replaying
|
|
105
|
+
* the screen. Structural, resize and image changes retain the native path.
|
|
117
106
|
*/
|
|
118
107
|
export function attachViewportStability(tui: TUI): ViewportStabilityPatch {
|
|
119
108
|
try {
|
|
109
|
+
// Native fullscreen has an application-owned fixed viewport. Its inherited
|
|
110
|
+
// applyLineResets method is not part of that renderer's diff path, so patching
|
|
111
|
+
// it would report a false-positive attachment on the shared TUI base class.
|
|
112
|
+
if (tui.mode === "fullscreen") return { active: false, detach() {} };
|
|
120
113
|
const internals = tui as unknown as ViewportTuiInternals;
|
|
121
114
|
const slot = resolveApplyLineResetsSlot(internals);
|
|
122
115
|
if (!slot) return { active: false, detach() {} };
|
|
@@ -137,6 +130,7 @@ export function attachViewportStability(tui: TUI): ViewportStabilityPatch {
|
|
|
137
130
|
&& Number.isFinite(viewportTop)
|
|
138
131
|
&& viewportTop > 0
|
|
139
132
|
&& this.previousHeight === this.terminal?.rows
|
|
133
|
+
&& this.previousWidth === this.terminal?.columns
|
|
140
134
|
) {
|
|
141
135
|
const hiddenEnd = Math.min(previousLines.length, Math.trunc(viewportTop));
|
|
142
136
|
const hiddenHasKittyImage = previousLines.slice(0, hiddenEnd).some(isKittyImageLine)
|
|
@@ -144,10 +138,7 @@ export function attachViewportStability(tui: TUI): ViewportStabilityPatch {
|
|
|
144
138
|
if (!hiddenHasKittyImage) {
|
|
145
139
|
for (let index = 0; index < hiddenEnd; index += 1) {
|
|
146
140
|
const previous = previousLines[index];
|
|
147
|
-
|
|
148
|
-
if (previous !== undefined && next !== undefined && differsOnlyByTrailingDuration(previous, next)) {
|
|
149
|
-
nextLines[index] = previous;
|
|
150
|
-
}
|
|
141
|
+
if (previous !== undefined) nextLines[index] = previous;
|
|
151
142
|
}
|
|
152
143
|
}
|
|
153
144
|
}
|