tmux-ide 2.9.0-beta.36 → 2.9.0-beta.37
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/bin/cli.js +1 -1
- package/package.json +1 -1
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-workspace.jsx +5 -0
- package/packages/daemon/dist/tui/mirror/runtime/application-transient-note-owner.js +2 -1
- package/packages/daemon/dist/tui/mirror/shell-chrome.js +9 -3
- package/packages/daemon/src/tui/mirror/__snapshots__/shell-chrome-renderer.test.tsx.snap +6 -6
- package/packages/daemon/src/tui/mirror/runtime/__snapshots__/application-shell-view-renderer.test.tsx.snap +10 -10
- package/packages/daemon/src/tui/mirror/runtime/application-shell-view.tsx +12 -6
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-workspace.tsx +7 -0
- package/packages/daemon/src/tui/mirror/runtime/application-transient-note-owner.ts +7 -1
- package/packages/daemon/src/tui/mirror/shell-chrome-view.tsx +40 -24
- package/packages/daemon/src/tui/mirror/shell-chrome.ts +14 -3
- package/packages/daemon/src/tui/mirror/workspace/__snapshots__/application-shell-renderer.test.tsx.snap +3 -3
- package/packages/daemon/src/tui/mirror/workspace/application-shell-view.tsx +2 -0
package/bin/cli.js
CHANGED
|
@@ -11279,7 +11279,7 @@ var require_package = __commonJS({
|
|
|
11279
11279
|
"package.json"(exports, module) {
|
|
11280
11280
|
module.exports = {
|
|
11281
11281
|
name: "tmux-ide",
|
|
11282
|
-
version: "2.9.0-beta.
|
|
11282
|
+
version: "2.9.0-beta.37",
|
|
11283
11283
|
description: "A visual, agent-aware IDE for any tmux session, with optional workspace presets",
|
|
11284
11284
|
type: "module",
|
|
11285
11285
|
bin: {
|
package/package.json
CHANGED
|
@@ -91,6 +91,11 @@ export function ApplicationTerminalWorkspace(props) {
|
|
|
91
91
|
? clampTerminalViewportOrigin(snapshot, { cols: frame.width, rows: frame.contentHeight }, origin, snapshot.history.length)
|
|
92
92
|
: origin;
|
|
93
93
|
}, (paneId) => props.adapter.retainPaneView?.(paneId) ?? null);
|
|
94
|
+
createEffect(() => {
|
|
95
|
+
const paneId = props.focusedPane;
|
|
96
|
+
props.onScrollbackChange?.(paneId !== null && scrollback.offset(paneId) > 0);
|
|
97
|
+
});
|
|
98
|
+
onCleanup(() => props.onScrollbackChange?.(false));
|
|
94
99
|
const selectionViewport = (paneId, frame) => props.adapter.renderSource.supportsViewportOrigin
|
|
95
100
|
? {
|
|
96
101
|
cols: frame.width,
|
|
@@ -16,7 +16,8 @@ export function createApplicationTransientNoteOwner(options) {
|
|
|
16
16
|
publish(note) {
|
|
17
17
|
clear();
|
|
18
18
|
options.write(note);
|
|
19
|
-
if (!note
|
|
19
|
+
if (!note ||
|
|
20
|
+
/\b(?:failed|failure|error|unavailable|disconnected|reconnecting|recovering|read.only|denied)\b/iu.test(note))
|
|
20
21
|
return;
|
|
21
22
|
timer = clock.setTimeout(() => {
|
|
22
23
|
timer = null;
|
|
@@ -222,9 +222,10 @@ export function shellStatusLine(variant, input, width) {
|
|
|
222
222
|
}
|
|
223
223
|
return `${out}…`;
|
|
224
224
|
}
|
|
225
|
-
function meaningfulStatusMessage(message) {
|
|
225
|
+
export function meaningfulStatusMessage(message) {
|
|
226
226
|
const value = message?.trim();
|
|
227
|
-
if (!value ||
|
|
227
|
+
if (!value ||
|
|
228
|
+
/^(?:ready|live|connected|live tmux sessions? discovered|\d+ sessions? live)$/iu.test(value))
|
|
228
229
|
return null;
|
|
229
230
|
return value;
|
|
230
231
|
}
|
|
@@ -264,7 +265,12 @@ export function contextStatusPresentation(input) {
|
|
|
264
265
|
: input.connectionState === "recovering"
|
|
265
266
|
? "Recovering"
|
|
266
267
|
: "Disconnected";
|
|
267
|
-
const
|
|
268
|
+
const persistentProblem = notification && contextStatusTone(notification, "connected").tone === "blocked";
|
|
269
|
+
const activityLabel = input.connectionState !== "connected"
|
|
270
|
+
? (notification ?? connectionLabel)
|
|
271
|
+
: persistentProblem
|
|
272
|
+
? notification
|
|
273
|
+
: (transient ?? notification ?? connectionLabel);
|
|
268
274
|
const activityTone = contextStatusTone(activityLabel, input.connectionState);
|
|
269
275
|
const location = input.variant === "wide"
|
|
270
276
|
? [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots
|
|
2
2
|
|
|
3
3
|
exports[`ShellChrome OpenTUI renderer renders deterministic %sx%s compact shell chrome 1`] = `
|
|
4
|
-
" ⌂ !❯ ▤ ± ◆
|
|
4
|
+
" ⌂ !❯ ▤ ± ◆ ⧉ web !blocked F5 palette
|
|
5
5
|
tmux ┌──────────────────────────────────────────────────────────┐
|
|
6
6
|
● web │ › compact workspace │
|
|
7
7
|
○ api │● Active view and keyboard focus are selected terminal│
|
|
@@ -24,11 +24,11 @@ exports[`ShellChrome OpenTUI renderer renders deterministic %sx%s compact shell
|
|
|
24
24
|
│ │
|
|
25
25
|
│ │
|
|
26
26
|
└──────────────────────────────────────────────────────────┘
|
|
27
|
-
F5 · ^q quit F6 Sessions F7 Attention
|
|
27
|
+
F5 · ^q quit F6 Sessions F7 Attention F10 Sidebar F5 Commands"
|
|
28
28
|
`;
|
|
29
29
|
|
|
30
30
|
exports[`ShellChrome OpenTUI renderer renders deterministic %sx%s standard shell chrome 1`] = `
|
|
31
|
-
" ▸ tmux-ide ⌂ Home !❯ Terminal ▤ Files ± Diff ◆ Missions
|
|
31
|
+
" ▸ tmux-ide ⌂ Home !❯ Terminal ▤ Files ± Diff ◆ Missions ⧉ web !blocked F5 palette
|
|
32
32
|
tmux-ide ┌──────────────────────────────────────────────────────────────────────────────────────────┐
|
|
33
33
|
● web │ › standard workspace │
|
|
34
34
|
○ api │● Active view and keyboard focus are selected terminal│
|
|
@@ -67,11 +67,11 @@ exports[`ShellChrome OpenTUI renderer renders deterministic %sx%s standard shell
|
|
|
67
67
|
│ │
|
|
68
68
|
│ │
|
|
69
69
|
└──────────────────────────────────────────────────────────────────────────────────────────┘
|
|
70
|
-
F5 palette · ^q quit F6 Sessions F7 Attention
|
|
70
|
+
F5 palette · ^q quit F6 Sessions F7 Attention F10 Sidebar F5 Commands"
|
|
71
71
|
`;
|
|
72
72
|
|
|
73
73
|
exports[`ShellChrome OpenTUI renderer renders deterministic %sx%s wide shell chrome 1`] = `
|
|
74
|
-
" ▸ tmux-ide F1 ⌂ Home F2 !❯ Terminal F3 ▤ Files F4 ± Diff F6 ◆ Missions
|
|
74
|
+
" ▸ tmux-ide F1 ⌂ Home F2 !❯ Terminal F3 ▤ Files F4 ± Diff F6 ◆ Missions ⧉ web !blocked F5 palette
|
|
75
75
|
tmux-ide ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
|
76
76
|
● web │ › wide workspace │
|
|
77
77
|
○ api │● Active view and keyboard focus are selected terminal│
|
|
@@ -130,5 +130,5 @@ exports[`ShellChrome OpenTUI renderer renders deterministic %sx%s wide shell chr
|
|
|
130
130
|
│ │
|
|
131
131
|
│ │
|
|
132
132
|
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
133
|
-
F5 palette · ^q quit F6 Sessions F7 Attention
|
|
133
|
+
F5 palette · ^q quit F6 Sessions F7 Attention F10 Sidebar F5 Commands"
|
|
134
134
|
`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots
|
|
2
2
|
|
|
3
3
|
exports[`production ApplicationShellView retains shell, window strip, pane chrome, and canvas at %sx%s 1`] = `
|
|
4
|
-
" ⌂ ●❯
|
|
4
|
+
" ⌂ ●❯ Local · main
|
|
5
5
|
tmux ● main ● workin… +
|
|
6
6
|
● main ● Codex ● working ⋯
|
|
7
7
|
○ website CANONICAL-CELL
|
|
@@ -13,11 +13,11 @@ exports[`production ApplicationShellView retains shell, window strip, pane chrom
|
|
|
13
13
|
|
|
14
14
|
…
|
|
15
15
|
|
|
16
|
-
F6 Sessions F7 Attention
|
|
16
|
+
F6 Sessions F7 Attention F10 Sidebar F5 Commands"
|
|
17
17
|
`;
|
|
18
18
|
|
|
19
19
|
exports[`production ApplicationShellView retains shell, window strip, pane chrome, and canvas at %sx%s 2`] = `
|
|
20
|
-
" tmux-ide ⌂ Home ●❯ Terminals
|
|
20
|
+
" tmux-ide ⌂ Home ●❯ Terminals Local · main
|
|
21
21
|
tmux-ide ● main ● workin… + New window
|
|
22
22
|
● main ● Codex ● working ⋯
|
|
23
23
|
○ website CANONICAL-CELL
|
|
@@ -29,11 +29,11 @@ exports[`production ApplicationShellView retains shell, window strip, pane chrom
|
|
|
29
29
|
|
|
30
30
|
…
|
|
31
31
|
|
|
32
|
-
F6 Sessions F7 Attention
|
|
32
|
+
F6 Sessions F7 Attention F10 Sidebar F5 Commands"
|
|
33
33
|
`;
|
|
34
34
|
|
|
35
35
|
exports[`production ApplicationShellView retains shell, window strip, pane chrome, and canvas at %sx%s 3`] = `
|
|
36
|
-
" tmux-ide F1 ⌂ Home F2 ●❯ Terminals
|
|
36
|
+
" tmux-ide F1 ⌂ Home F2 ●❯ Terminals Local · main
|
|
37
37
|
tmux-ide ● main ● workin… + New window
|
|
38
38
|
● main ● Codex ● working ⋯
|
|
39
39
|
○ website CANONICAL-CELL
|
|
@@ -45,11 +45,11 @@ exports[`production ApplicationShellView retains shell, window strip, pane chrom
|
|
|
45
45
|
|
|
46
46
|
…
|
|
47
47
|
|
|
48
|
-
F6 Sessions F7 Attention
|
|
48
|
+
F6 Sessions F7 Attention F10 Sidebar F5 Commands"
|
|
49
49
|
`;
|
|
50
50
|
|
|
51
51
|
exports[`production ApplicationShellView reacts palette geometry through narrow live resizes 1`] = `
|
|
52
|
-
" ⌂ ●❯
|
|
52
|
+
" ⌂ ●❯
|
|
53
53
|
t Command palette esc
|
|
54
54
|
m Search commands…
|
|
55
55
|
2 Home F1
|
|
@@ -61,7 +61,7 @@ exports[`production ApplicationShellView reacts palette geometry through narrow
|
|
|
61
61
|
`;
|
|
62
62
|
|
|
63
63
|
exports[`production ApplicationShellView reacts palette geometry through narrow live resizes 2`] = `
|
|
64
|
-
" ⌂ ●❯
|
|
64
|
+
" ⌂ ●❯
|
|
65
65
|
tCommand palette
|
|
66
66
|
m …rch commands…
|
|
67
67
|
2 Home F1w
|
|
@@ -71,7 +71,7 @@ exports[`production ApplicationShellView reacts palette geometry through narrow
|
|
|
71
71
|
`;
|
|
72
72
|
|
|
73
73
|
exports[`production ApplicationShellView preserves canonical attention while prioritizing mixed window activity 1`] = `
|
|
74
|
-
" tmux-ide ⌂ Home ●❯ Terminals
|
|
74
|
+
" tmux-ide ⌂ Home ●❯ Terminals Local · main
|
|
75
75
|
tmux-ide ! main ! workin… + New window
|
|
76
76
|
● main ● Codex ● working ⋯ ! Scout ! idle ⋯
|
|
77
77
|
CANONICAL-CELL CANONICAL-CELL
|
|
@@ -83,5 +83,5 @@ exports[`production ApplicationShellView preserves canonical attention while pri
|
|
|
83
83
|
|
|
84
84
|
…
|
|
85
85
|
|
|
86
|
-
F6 Sessions F7 Attention
|
|
86
|
+
F6 Sessions F7 Attention F10 Sidebar F5 Commands"
|
|
87
87
|
`;
|
|
@@ -10,7 +10,7 @@ import type { ApplicationAppearanceOwner } from "./application-appearance-owner.
|
|
|
10
10
|
/* @jsxImportSource @opentui/solid */
|
|
11
11
|
import type { ApplicationShellProjectionV1 } from "@tmux-ide/contracts";
|
|
12
12
|
import type { Accessor, ComponentProps, JSX } from "solid-js";
|
|
13
|
-
import { Show, createMemo } from "solid-js";
|
|
13
|
+
import { Show, createMemo, createSignal } from "solid-js";
|
|
14
14
|
|
|
15
15
|
import { friendlySessionLabel } from "../terminal-text.ts";
|
|
16
16
|
import { ApplicationShell } from "../workspace/application-shell-view.tsx";
|
|
@@ -163,6 +163,7 @@ export interface ApplicationShellViewProps {
|
|
|
163
163
|
|
|
164
164
|
/** Pure Solid composition over the WorkspaceClient semantic projection. */
|
|
165
165
|
export function ApplicationShellView(props: ApplicationShellViewProps): JSX.Element {
|
|
166
|
+
const [scrollback, setScrollback] = createSignal(false);
|
|
166
167
|
const projection = createMemo(() => {
|
|
167
168
|
const semantic = props.semantic();
|
|
168
169
|
if (!semantic) return null;
|
|
@@ -395,14 +396,13 @@ export function ApplicationShellView(props: ApplicationShellViewProps): JSX.Elem
|
|
|
395
396
|
>
|
|
396
397
|
<ApplicationShell
|
|
397
398
|
footerContext={props.surface() === "home" ? "home" : "terminals"}
|
|
399
|
+
scrollback={props.surface() === "terminals" && scrollback()}
|
|
398
400
|
rightChips={
|
|
399
|
-
props.
|
|
401
|
+
props.surface() === "terminals" && props.dimensions().width >= 60
|
|
400
402
|
? [
|
|
401
403
|
{
|
|
402
|
-
id: "
|
|
403
|
-
label: `
|
|
404
|
-
context: true,
|
|
405
|
-
textColor: props.machineColor,
|
|
404
|
+
id: "workspace-context",
|
|
405
|
+
label: ` ${props.machineLabel ?? "Local"} · ${friendlySessionLabel(shell.activeSession)} `,
|
|
406
406
|
},
|
|
407
407
|
]
|
|
408
408
|
: undefined
|
|
@@ -413,6 +413,11 @@ export function ApplicationShellView(props: ApplicationShellViewProps): JSX.Elem
|
|
|
413
413
|
onHelp={() => props.onSetPaletteOpen(true, "mouse")}
|
|
414
414
|
note={
|
|
415
415
|
props.bootstrapNote() ??
|
|
416
|
+
(props.copyFeedback
|
|
417
|
+
? props.copyFeedback.copied
|
|
418
|
+
? "Copied"
|
|
419
|
+
: "Copy unavailable"
|
|
420
|
+
: null) ??
|
|
416
421
|
(props.generationStatus() === "read-only"
|
|
417
422
|
? `Read-only input · select a pane to request control · shared tmux ${props.layout().current?.cols ?? "?"}×${props.layout().current?.rows ?? "?"}`
|
|
418
423
|
: props.generationStatus())
|
|
@@ -517,6 +522,7 @@ export function ApplicationShellView(props: ApplicationShellViewProps): JSX.Elem
|
|
|
517
522
|
>
|
|
518
523
|
{(source) => (
|
|
519
524
|
<ApplicationTerminalWorkspace
|
|
525
|
+
onScrollbackChange={setScrollback}
|
|
520
526
|
layout={props.layout}
|
|
521
527
|
adapter={source.adapter}
|
|
522
528
|
rendererEpoch={source.rendererEpoch}
|
|
@@ -148,6 +148,7 @@ export function beginApplicationMouseIngress(
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
export interface ApplicationTerminalWorkspaceProps {
|
|
151
|
+
readonly onScrollbackChange?: (active: boolean) => void;
|
|
151
152
|
readonly paneInteractions?: Accessor<ReadonlyMap<string, PaneInteractionProjection>>;
|
|
152
153
|
readonly layout: Accessor<OpenTuiWorkspaceLayoutSnapshot>;
|
|
153
154
|
readonly adapter: PaneScopedTerminalAdapter;
|
|
@@ -318,6 +319,12 @@ export function ApplicationTerminalWorkspace(props: ApplicationTerminalWorkspace
|
|
|
318
319
|
},
|
|
319
320
|
(paneId) => props.adapter.retainPaneView?.(paneId) ?? null,
|
|
320
321
|
);
|
|
322
|
+
|
|
323
|
+
createEffect(() => {
|
|
324
|
+
const paneId = props.focusedPane;
|
|
325
|
+
props.onScrollbackChange?.(paneId !== null && scrollback.offset(paneId) > 0);
|
|
326
|
+
});
|
|
327
|
+
onCleanup(() => props.onScrollbackChange?.(false));
|
|
321
328
|
const selectionViewport = (paneId: string, frame: OpenTuiPaneFrame) =>
|
|
322
329
|
props.adapter.renderSource.supportsViewportOrigin
|
|
323
330
|
? {
|
|
@@ -31,7 +31,13 @@ export function createApplicationTransientNoteOwner(options: {
|
|
|
31
31
|
publish(note) {
|
|
32
32
|
clear();
|
|
33
33
|
options.write(note);
|
|
34
|
-
if (
|
|
34
|
+
if (
|
|
35
|
+
!note ||
|
|
36
|
+
/\b(?:failed|failure|error|unavailable|disconnected|reconnecting|recovering|read.only|denied)\b/iu.test(
|
|
37
|
+
note,
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
return;
|
|
35
41
|
timer = clock.setTimeout(() => {
|
|
36
42
|
timer = null;
|
|
37
43
|
if (options.read() === note) options.write(null);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { For, Show } from "solid-js";
|
|
3
3
|
import {
|
|
4
4
|
contextStatusPresentation,
|
|
5
|
+
meaningfulStatusMessage,
|
|
5
6
|
developmentChromeLabel,
|
|
6
7
|
shellNavigationPresentation,
|
|
7
8
|
shellSurfaceTabs,
|
|
@@ -106,7 +107,14 @@ export function ShellTabBar(props: ShellTabBarProps) {
|
|
|
106
107
|
/>
|
|
107
108
|
)}
|
|
108
109
|
</For>
|
|
109
|
-
<For
|
|
110
|
+
<For
|
|
111
|
+
each={
|
|
112
|
+
meaningfulStatusMessage(props.note) &&
|
|
113
|
+
/read.only|reconnect|disconnect|recover|unavailable|failed/iu.test(props.note ?? "")
|
|
114
|
+
? [props.note!]
|
|
115
|
+
: []
|
|
116
|
+
}
|
|
117
|
+
>
|
|
110
118
|
{(note) => (
|
|
111
119
|
<Badge
|
|
112
120
|
theme={props.theme}
|
|
@@ -117,24 +125,28 @@ export function ShellTabBar(props: ShellTabBarProps) {
|
|
|
117
125
|
1,
|
|
118
126
|
Math.min(Math.floor(props.width / 3), terminalDisplayWidth(note) + 1),
|
|
119
127
|
)}
|
|
120
|
-
tone="
|
|
128
|
+
tone="warning"
|
|
121
129
|
/>
|
|
122
130
|
)}
|
|
123
131
|
</For>
|
|
124
132
|
<For each={props.rightChips ?? []}>
|
|
125
133
|
{(chip) => (
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
<text
|
|
135
|
+
width={Math.min(
|
|
136
|
+
Math.max(1, Math.floor(props.width / 3)),
|
|
137
|
+
terminalDisplayWidth(chip.label),
|
|
138
|
+
)}
|
|
139
|
+
flexShrink={0}
|
|
140
|
+
fg={
|
|
141
|
+
chip.attention
|
|
142
|
+
? props.theme.roles.statusTone.warning
|
|
143
|
+
: (chip.textColor ?? props.theme.roles.text.muted)
|
|
144
|
+
}
|
|
145
|
+
bg={props.theme.roles.surfaces.panel}
|
|
146
|
+
overflow="hidden"
|
|
147
|
+
>
|
|
148
|
+
{clipTerminal(chip.label, Math.max(1, Math.floor(props.width / 3)))}
|
|
149
|
+
</text>
|
|
138
150
|
)}
|
|
139
151
|
</For>
|
|
140
152
|
</Surface>
|
|
@@ -152,6 +164,7 @@ export interface ShellStatusStripProps {
|
|
|
152
164
|
tool?: string | null;
|
|
153
165
|
dockMode?: string | null;
|
|
154
166
|
focus?: string | null;
|
|
167
|
+
scrollback?: boolean;
|
|
155
168
|
notification: string | null;
|
|
156
169
|
transient?: string | null;
|
|
157
170
|
connectionState?: "connected" | "reconnecting" | "disconnected" | "recovering";
|
|
@@ -178,16 +191,19 @@ export function ContextStatusBar(props: ShellStatusStripProps) {
|
|
|
178
191
|
const activity = () => presentation().activity;
|
|
179
192
|
const showMessage = () => !/^(?:Live|\d+ sessions? live)$/iu.test(activity().label);
|
|
180
193
|
const hints = () => {
|
|
181
|
-
const candidates =
|
|
182
|
-
? [
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
194
|
+
const candidates = props.scrollback
|
|
195
|
+
? [{ keys: "Esc", label: "Back to live" }]
|
|
196
|
+
: /^home$/iu.test(props.mode)
|
|
197
|
+
? [
|
|
198
|
+
{ keys: "↑↓", label: "Select" },
|
|
199
|
+
{ keys: "Enter", label: "Open" },
|
|
200
|
+
{ keys: "/", label: "Search" },
|
|
201
|
+
]
|
|
202
|
+
: [
|
|
203
|
+
{ keys: "F6", label: "Sessions" },
|
|
204
|
+
{ keys: "F7", label: "Attention" },
|
|
205
|
+
{ keys: "F10", label: "Sidebar" },
|
|
206
|
+
];
|
|
191
207
|
let remaining = available();
|
|
192
208
|
return candidates.filter((hint) => {
|
|
193
209
|
const width = terminalDisplayWidth(`${hint.keys} ${hint.label}`) + 2;
|
|
@@ -385,9 +385,13 @@ export interface ContextStatusPresentation {
|
|
|
385
385
|
readonly hints: readonly ContextStatusHint[];
|
|
386
386
|
}
|
|
387
387
|
|
|
388
|
-
function meaningfulStatusMessage(message: string | null | undefined): string | null {
|
|
388
|
+
export function meaningfulStatusMessage(message: string | null | undefined): string | null {
|
|
389
389
|
const value = message?.trim();
|
|
390
|
-
if (
|
|
390
|
+
if (
|
|
391
|
+
!value ||
|
|
392
|
+
/^(?:ready|live|connected|live tmux sessions? discovered|\d+ sessions? live)$/iu.test(value)
|
|
393
|
+
)
|
|
394
|
+
return null;
|
|
391
395
|
return value;
|
|
392
396
|
}
|
|
393
397
|
|
|
@@ -445,7 +449,14 @@ export function contextStatusPresentation(input: {
|
|
|
445
449
|
: input.connectionState === "recovering"
|
|
446
450
|
? "Recovering"
|
|
447
451
|
: "Disconnected";
|
|
448
|
-
const
|
|
452
|
+
const persistentProblem =
|
|
453
|
+
notification && contextStatusTone(notification, "connected").tone === "blocked";
|
|
454
|
+
const activityLabel =
|
|
455
|
+
input.connectionState !== "connected"
|
|
456
|
+
? (notification ?? connectionLabel)
|
|
457
|
+
: persistentProblem
|
|
458
|
+
? notification
|
|
459
|
+
: (transient ?? notification ?? connectionLabel);
|
|
449
460
|
const activityTone = contextStatusTone(activityLabel, input.connectionState);
|
|
450
461
|
const location: ContextStatusLocationSegment[] =
|
|
451
462
|
input.variant === "wide"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots
|
|
2
2
|
|
|
3
3
|
exports[`production ApplicationShell → WorkbenchShell OpenTUI renderer records the %sx%s collapsed dock acceptance baseline 1`] = `
|
|
4
|
-
" ⌂ ●❯
|
|
4
|
+
" ⌂ ●❯
|
|
5
5
|
tmux ▌› Native terminal canvas terminals · canvas
|
|
6
6
|
● main
|
|
7
7
|
○ website
|
|
@@ -28,7 +28,7 @@ exports[`production ApplicationShell → WorkbenchShell OpenTUI renderer records
|
|
|
28
28
|
`;
|
|
29
29
|
|
|
30
30
|
exports[`production ApplicationShell → WorkbenchShell OpenTUI renderer records the %sx%s open dock acceptance baseline 1`] = `
|
|
31
|
-
" tmux-ide ⌂ Home ●❯ Terminals
|
|
31
|
+
" tmux-ide ⌂ Home ●❯ Terminals
|
|
32
32
|
tmux-ide ▌› Native terminal canvas terminals · canvas
|
|
33
33
|
● main
|
|
34
34
|
○ website
|
|
@@ -71,7 +71,7 @@ exports[`production ApplicationShell → WorkbenchShell OpenTUI renderer records
|
|
|
71
71
|
`;
|
|
72
72
|
|
|
73
73
|
exports[`production ApplicationShell → WorkbenchShell OpenTUI renderer records the %sx%s maximized dock acceptance baseline 1`] = `
|
|
74
|
-
" tmux-ide F1 ⌂ Home F2 ●❯ Terminals
|
|
74
|
+
" tmux-ide F1 ⌂ Home F2 ●❯ Terminals
|
|
75
75
|
tmux-ide ▸ tools F3 ▤ Files F4 ± Changes F6 ●◆ Missions F9 ◷ Activity ▾ close ▣ restore
|
|
76
76
|
● main ▌○ Native Missions surface maximized
|
|
77
77
|
○ website
|
|
@@ -11,6 +11,7 @@ import type { SemanticThemeSnapshot } from "../theme.ts";
|
|
|
11
11
|
import type { ApplicationShellProjection } from "./application-shell.ts";
|
|
12
12
|
|
|
13
13
|
export interface ApplicationShellProps {
|
|
14
|
+
scrollback?: boolean;
|
|
14
15
|
footerContext?: "home" | "terminals";
|
|
15
16
|
theme: SemanticThemeSnapshot;
|
|
16
17
|
projection: ApplicationShellProjection;
|
|
@@ -144,6 +145,7 @@ export function ApplicationShell(props: ApplicationShellProps) {
|
|
|
144
145
|
props.showToolStatus === false ? null : props.projection.semantic.bottomDock.mode
|
|
145
146
|
}
|
|
146
147
|
focus={props.focusLabel ?? applicationShellFocusLabel(props.projection)}
|
|
148
|
+
scrollback={props.scrollback}
|
|
147
149
|
notification={props.projection.semantic.statusStrip.message}
|
|
148
150
|
transient={props.note}
|
|
149
151
|
connectionState={props.projection.semantic.statusStrip.state}
|