@agents-ensemble/cli 0.6.5 → 0.7.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/README.md +36 -3
- package/config.example.yaml +13 -0
- package/dist/inline-markdown.d.ts +3 -1
- package/dist/inline-markdown.d.ts.map +1 -1
- package/dist/inline-markdown.js +232 -33
- package/dist/inline-markdown.js.map +1 -1
- package/dist/session-log-lines.d.ts.map +1 -1
- package/dist/session-log-lines.js +14 -1
- package/dist/session-log-lines.js.map +1 -1
- package/dist/tui/activity-log.d.ts +8 -0
- package/dist/tui/activity-log.d.ts.map +1 -1
- package/dist/tui/activity-log.js +16 -0
- package/dist/tui/activity-log.js.map +1 -1
- package/dist/tui/create-issue-session-tui-host.d.ts.map +1 -1
- package/dist/tui/create-issue-session-tui-host.js +27 -2
- package/dist/tui/create-issue-session-tui-host.js.map +1 -1
- package/dist/tui/issue-session-tui-stream.d.ts +4 -1
- package/dist/tui/issue-session-tui-stream.d.ts.map +1 -1
- package/dist/tui/issue-session-tui-stream.js +46 -10
- package/dist/tui/issue-session-tui-stream.js.map +1 -1
- package/dist/tui/issue-session-tui-stream.test.js +311 -2
- package/dist/tui/issue-session-tui-stream.test.js.map +1 -1
- package/dist/tui/issue-session-tui.d.ts +5 -3
- package/dist/tui/issue-session-tui.d.ts.map +1 -1
- package/dist/tui/issue-session-tui.js +29 -15
- package/dist/tui/issue-session-tui.js.map +1 -1
- package/dist/tui/issue-session-tui.test.js +147 -11
- package/dist/tui/issue-session-tui.test.js.map +1 -1
- package/dist/tui/open-questions-pane.d.ts.map +1 -1
- package/dist/tui/open-questions-pane.js +30 -12
- package/dist/tui/open-questions-pane.js.map +1 -1
- package/dist/tui/stream-scrollback.d.ts +29 -0
- package/dist/tui/stream-scrollback.d.ts.map +1 -0
- package/dist/tui/stream-scrollback.js +35 -0
- package/dist/tui/stream-scrollback.js.map +1 -0
- package/dist/tui/tui-layout-constants.d.ts +9 -4
- package/dist/tui/tui-layout-constants.d.ts.map +1 -1
- package/dist/tui/tui-layout-constants.js +9 -4
- package/dist/tui/tui-layout-constants.js.map +1 -1
- package/dist/tui/tui-resize-recovery.d.ts +24 -0
- package/dist/tui/tui-resize-recovery.d.ts.map +1 -0
- package/dist/tui/tui-resize-recovery.js +34 -0
- package/dist/tui/tui-resize-recovery.js.map +1 -0
- package/dist/tui/tui-terminal-size.d.ts +16 -5
- package/dist/tui/tui-terminal-size.d.ts.map +1 -1
- package/dist/tui/tui-terminal-size.js +40 -8
- package/dist/tui/tui-terminal-size.js.map +1 -1
- package/dist/tui/tui-view-model.d.ts +2 -0
- package/dist/tui/tui-view-model.d.ts.map +1 -1
- package/dist/tui/tui-view-model.js +7 -0
- package/dist/tui/tui-view-model.js.map +1 -1
- package/dist/tui/wrap-text-to-width.d.ts.map +1 -1
- package/dist/tui/wrap-text-to-width.js +4 -1
- package/dist/tui/wrap-text-to-width.js.map +1 -1
- package/docs/config.md +67 -3
- package/docs/settings.md +17 -4
- package/package.json +2 -2
|
@@ -8,7 +8,8 @@ import { createTuiTelemetrySink } from './create-tui-telemetry-sink.js';
|
|
|
8
8
|
import { trimBlankLinesOnly } from './operator-input-layout.js';
|
|
9
9
|
import { resolveTuiIssueLinkMode } from './format-operator-context.js';
|
|
10
10
|
import { resolveTuiLayoutMode } from './tui-layout-mode.js';
|
|
11
|
-
import { createTuiResizeController } from './tui-terminal-size.js';
|
|
11
|
+
import { createTuiResizeController, TUI_RESIZE_SETTLE_MS, } from './tui-terminal-size.js';
|
|
12
|
+
import { createTuiResizeRecovery } from './tui-resize-recovery.js';
|
|
12
13
|
import { resolveInitialOperatorMessage } from '../operator-message.js';
|
|
13
14
|
function createInkDisplayBackend(viewModel) {
|
|
14
15
|
return {
|
|
@@ -70,7 +71,28 @@ export function createIssueSessionTuiHost(issueUrl, options = {}) {
|
|
|
70
71
|
// existing bounded in-memory window; stream mode retains the scrollback.
|
|
71
72
|
activityLogWindowSize: layoutMode === 'stream' ? null : undefined,
|
|
72
73
|
});
|
|
73
|
-
const
|
|
74
|
+
const inkRef = {
|
|
75
|
+
current: undefined,
|
|
76
|
+
};
|
|
77
|
+
const recoveryRef = {
|
|
78
|
+
current: undefined,
|
|
79
|
+
};
|
|
80
|
+
const resizeController = createTuiResizeController(process.stdout, TUI_RESIZE_SETTLE_MS, (event) => {
|
|
81
|
+
recoveryRef.current?.recover(event);
|
|
82
|
+
});
|
|
83
|
+
const resizeRecovery = createTuiResizeRecovery({
|
|
84
|
+
enabled: layoutMode === 'stream',
|
|
85
|
+
clearInk: () => {
|
|
86
|
+
inkRef.current?.clear?.();
|
|
87
|
+
},
|
|
88
|
+
write: (data) => {
|
|
89
|
+
resizeController.stdout.write(data);
|
|
90
|
+
},
|
|
91
|
+
requestActivityLogReplay: () => {
|
|
92
|
+
viewModel.requestActivityLogReplay();
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
recoveryRef.current = resizeRecovery;
|
|
74
96
|
const onSubmitRef = {
|
|
75
97
|
current: undefined,
|
|
76
98
|
};
|
|
@@ -90,6 +112,7 @@ export function createIssueSessionTuiHost(issueUrl, options = {}) {
|
|
|
90
112
|
alternateScreen: false,
|
|
91
113
|
stdout: resizeController.stdout,
|
|
92
114
|
});
|
|
115
|
+
inkRef.current = ink;
|
|
93
116
|
const inkDisplayBackend = createInkDisplayBackend(viewModel);
|
|
94
117
|
const bindOperatorInput = createBindTuiOperatorInput(viewModel, onSubmitRef, apiRef, options.initialOperatorMessage);
|
|
95
118
|
const telemetrySink = createTuiTelemetrySink(viewModel);
|
|
@@ -110,7 +133,9 @@ export function createIssueSessionTuiHost(issueUrl, options = {}) {
|
|
|
110
133
|
}
|
|
111
134
|
},
|
|
112
135
|
dispose: () => {
|
|
136
|
+
resizeRecovery.dispose();
|
|
113
137
|
ink.unmount();
|
|
138
|
+
inkRef.current = undefined;
|
|
114
139
|
resizeController.dispose();
|
|
115
140
|
},
|
|
116
141
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-issue-session-tui-host.js","sourceRoot":"","sources":["../../src/tui/create-issue-session-tui-host.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAU7B,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,
|
|
1
|
+
{"version":3,"file":"create-issue-session-tui-host.js","sourceRoot":"","sources":["../../src/tui/create-issue-session-tui-host.tsx"],"names":[],"mappings":"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"}
|
|
@@ -2,12 +2,15 @@ import type { OperatorInputSubmitOptions } from '@agents-ensemble/core';
|
|
|
2
2
|
import { type TuiViewModel } from './tui-view-model.js';
|
|
3
3
|
import { type IssueLinkMode } from './format-operator-context.js';
|
|
4
4
|
import { type TuiTerminalSizeStore } from './tui-terminal-size.js';
|
|
5
|
+
import { type StreamScrollbackEvent } from './stream-scrollback.js';
|
|
5
6
|
export interface IssueSessionTuiStreamProps {
|
|
6
7
|
viewModel: TuiViewModel;
|
|
7
8
|
onSubmit: (text: string, options?: OperatorInputSubmitOptions) => void;
|
|
8
9
|
issueUrl?: string;
|
|
9
10
|
issueLinkMode?: IssueLinkMode;
|
|
10
11
|
terminalSizeStore?: TuiTerminalSizeStore;
|
|
12
|
+
/** Optional event injection point for a future terminal scrollback adapter. */
|
|
13
|
+
scrollbackEvent?: StreamScrollbackEvent;
|
|
11
14
|
}
|
|
12
|
-
export declare function IssueSessionTuiStream({ viewModel, onSubmit, issueUrl, issueLinkMode, terminalSizeStore, }: IssueSessionTuiStreamProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function IssueSessionTuiStream({ viewModel, onSubmit, issueUrl, issueLinkMode, terminalSizeStore, scrollbackEvent, }: IssueSessionTuiStreamProps): import("react/jsx-runtime").JSX.Element;
|
|
13
16
|
//# sourceMappingURL=issue-session-tui-stream.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-session-tui-stream.d.ts","sourceRoot":"","sources":["../../src/tui/issue-session-tui-stream.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AA0B7E,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,8BAA8B,CAAC;AAKtC,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,YAAY,CAAC;IACxB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"issue-session-tui-stream.d.ts","sourceRoot":"","sources":["../../src/tui/issue-session-tui-stream.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AA0B7E,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,8BAA8B,CAAC;AAKtC,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,YAAY,CAAC;IACxB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;IACzC,+EAA+E;IAC/E,eAAe,CAAC,EAAE,qBAAqB,CAAC;CACzC;AA0CD,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,aAAsB,EACtB,iBAAiB,EACjB,eAAe,GAChB,EAAE,0BAA0B,2CA0O5B"}
|
|
@@ -14,6 +14,7 @@ import { getPaneContentWidth, wrapTextToWidth } from './wrap-text-to-width.js';
|
|
|
14
14
|
import { resolveStreamPaneHeights } from './stream-layout.js';
|
|
15
15
|
import { TitledBorderPane } from './titled-border-pane.js';
|
|
16
16
|
import { useTuiTerminalSize, } from './tui-terminal-size.js';
|
|
17
|
+
import { createStreamScrollbackState, reduceStreamScrollback, } from './stream-scrollback.js';
|
|
17
18
|
function useStreamContentWidth(columns) {
|
|
18
19
|
return getPaneContentWidth({
|
|
19
20
|
columns,
|
|
@@ -24,14 +25,15 @@ function useStreamContentWidth(columns) {
|
|
|
24
25
|
function useStreamActivityLogWidth(columns) {
|
|
25
26
|
return Math.max(1, columns);
|
|
26
27
|
}
|
|
27
|
-
function StaticActivityLog({ activityLog, contentWidth, }) {
|
|
28
|
-
return (_jsx(Static, { items: activityLog, children: (entry, index) => (_jsx(Box, { flexDirection: "column", children: buildActivityLogDisplayLines([entry], contentWidth).map((line, lineIndex) => (_jsx(ActivityLogDisplayLineRow, { line: line }, `activity-line-${index}-${lineIndex}`))) }, `activity-log-${index}`)) }));
|
|
28
|
+
function StaticActivityLog({ activityLog, contentWidth, replayGeneration, issueLinkMode, }) {
|
|
29
|
+
return (_jsx(Static, { items: activityLog, children: (entry, index) => (_jsx(Box, { flexDirection: "column", children: buildActivityLogDisplayLines([entry], contentWidth).map((line, lineIndex) => (_jsx(ActivityLogDisplayLineRow, { line: line, issueLinkMode: issueLinkMode }, `activity-line-${index}-${lineIndex}`))) }, `activity-log-${index}`)) }, replayGeneration));
|
|
29
30
|
}
|
|
30
|
-
export function IssueSessionTuiStream({ viewModel, onSubmit, issueUrl, issueLinkMode = 'osc8', terminalSizeStore, }) {
|
|
31
|
+
export function IssueSessionTuiStream({ viewModel, onSubmit, issueUrl, issueLinkMode = 'osc8', terminalSizeStore, scrollbackEvent, }) {
|
|
31
32
|
const snapshot = useSyncExternalStore(viewModel.subscribe, viewModel.getSnapshot, viewModel.getSnapshot);
|
|
32
33
|
const [inputValue, setInputValue] = useState('');
|
|
33
34
|
const [inputDisplayLineCount, setInputDisplayLineCount] = useState(1);
|
|
34
35
|
const [selectedQuestionIndex, setSelectedQuestionIndex] = useState(0);
|
|
36
|
+
const [scrollbackState, setScrollbackState] = useState(() => createStreamScrollbackState(snapshot.activityLog.length));
|
|
35
37
|
const terminalSize = useTuiTerminalSize(terminalSizeStore);
|
|
36
38
|
const { columns: terminalColumns, rows: terminalRows } = terminalSize;
|
|
37
39
|
const contentWidth = useStreamContentWidth(terminalColumns);
|
|
@@ -58,7 +60,18 @@ export function IssueSessionTuiStream({ viewModel, onSubmit, issueUrl, issueLink
|
|
|
58
60
|
postLoopWaiting: snapshot.postLoopWaiting,
|
|
59
61
|
shuttingDown: snapshot.shuttingDown,
|
|
60
62
|
});
|
|
61
|
-
const
|
|
63
|
+
const committedActivityCount = Math.min(scrollbackState.detached
|
|
64
|
+
? scrollbackState.committedActivityCount
|
|
65
|
+
: snapshot.activityLog.length, snapshot.activityLog.length);
|
|
66
|
+
const pendingActivityCount = scrollbackState.detached
|
|
67
|
+
? Math.max(0, snapshot.activityLog.length - committedActivityCount)
|
|
68
|
+
: 0;
|
|
69
|
+
const scrollbackHint = pendingActivityCount > 0
|
|
70
|
+
? `${pendingActivityCount} 件の新着 · End で最新へ`
|
|
71
|
+
: undefined;
|
|
72
|
+
const contextHintLines = scrollbackHint
|
|
73
|
+
? [scrollbackHint, ...operatorInputDisplay.hintLines]
|
|
74
|
+
: operatorInputDisplay.hintLines;
|
|
62
75
|
const visibleInputDisplayLineCount = Math.min(inputDisplayLineCount, maxInputDisplayLines);
|
|
63
76
|
const hintLineCount = contextHintLines.reduce((lineCount, line) => lineCount + wrapTextToWidth(line, contentWidth).length, 0);
|
|
64
77
|
const desiredInputPaneHeight = computeInputPaneHeight({
|
|
@@ -88,16 +101,39 @@ export function IssueSessionTuiStream({ viewModel, onSubmit, issueUrl, issueLink
|
|
|
88
101
|
useEffect(() => {
|
|
89
102
|
setSelectedQuestionIndex((current) => clampOpenQuestionSelectionIndex(current, openQuestions.length));
|
|
90
103
|
}, [openQuestions]);
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (!scrollbackEvent) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// The prop is an edge-triggered event. A future adapter should replace it
|
|
109
|
+
// when it observes another viewport transition.
|
|
110
|
+
setScrollbackState((current) => reduceStreamScrollback(current, scrollbackEvent, snapshot.activityLog.length));
|
|
111
|
+
}, [scrollbackEvent]);
|
|
112
|
+
const dispatchScrollbackEvent = (event) => {
|
|
113
|
+
setScrollbackState((current) => reduceStreamScrollback(current, event, snapshot.activityLog.length));
|
|
114
|
+
};
|
|
91
115
|
useInput((_input, key) => {
|
|
92
|
-
if (openQuestions.length
|
|
116
|
+
if (openQuestions.length > 0 && key.shift) {
|
|
117
|
+
if (key.upArrow) {
|
|
118
|
+
setSelectedQuestionIndex((current) => advanceOpenQuestionSelection(current, 'up', openQuestions.length));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (key.downArrow) {
|
|
122
|
+
setSelectedQuestionIndex((current) => advanceOpenQuestionSelection(current, 'down', openQuestions.length));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const scrollWithModifier = key.ctrl;
|
|
127
|
+
const scrollWithoutModifier = inputValue.length === 0;
|
|
128
|
+
if (!scrollWithModifier && !scrollWithoutModifier) {
|
|
93
129
|
return;
|
|
94
130
|
}
|
|
95
|
-
if (key.
|
|
96
|
-
|
|
131
|
+
if (key.pageUp) {
|
|
132
|
+
dispatchScrollbackEvent({ type: 'detached', source: 'keyboard' });
|
|
97
133
|
return;
|
|
98
134
|
}
|
|
99
|
-
if (key.
|
|
100
|
-
|
|
135
|
+
if (key.end) {
|
|
136
|
+
dispatchScrollbackEvent({ type: 'follow', source: 'keyboard' });
|
|
101
137
|
}
|
|
102
138
|
});
|
|
103
139
|
const handleSubmit = (value) => {
|
|
@@ -114,6 +150,6 @@ export function IssueSessionTuiStream({ viewModel, onSubmit, issueUrl, issueLink
|
|
|
114
150
|
setInputValue('');
|
|
115
151
|
setInputDisplayLineCount(1);
|
|
116
152
|
};
|
|
117
|
-
return (_jsxs(_Fragment, { children: [_jsx(StaticActivityLog, { activityLog: snapshot.activityLog, contentWidth: activityLogContentWidth }), _jsxs(Box, { flexDirection: "column", width: terminalColumns, height: streamPaneHeights.dynamicFrameHeight, overflowX: "visible", overflowY: "hidden", children: [operatorInputDisplay.mode === 'withQuestions' ? (_jsx(OpenQuestionsPane, { layout: streamOpenQuestionsLayout, terminalColumns: terminalColumns })) : null, _jsxs(TitledBorderPane, { title: INPUT_PANE_TITLE, borderStyle: "single", borderColor: INPUT_PANE_BORDER_COLOR, paddingX: PANE_PADDING_X, height: streamPaneHeights.inputPaneHeight, terminalColumns: terminalColumns, children: [contextHintLines.map((line, index) => (_jsx(WrappedTextLines, { text: line, width: contentWidth, color: INPUT_PANE_HINT_COLOR }, `context-hint-${index}`))), _jsx(OperatorTextArea, { value: inputValue, onChange: setInputValue, onSubmit: handleSubmit, focus: !snapshot.shuttingDown, contentWidth: contentWidth, promptPrefix: operatorPrompt, maxDisplayLines: maxInputDisplayLines, onDisplayLineCountChange: handleDisplayLineCountChange, cursorStart: cursorStart })] }), _jsx(WorkerStatusPane, { workers: snapshot.displayState.workers, dispatchHold: snapshot.displayState.dispatchHold, height: streamPaneHeights.workerPaneHeight, terminalColumns: terminalColumns, issueUrl: issueUrl, issueLinkMode: issueLinkMode })] })] }));
|
|
153
|
+
return (_jsxs(_Fragment, { children: [_jsx(StaticActivityLog, { activityLog: snapshot.activityLog.slice(0, committedActivityCount), contentWidth: activityLogContentWidth, replayGeneration: snapshot.activityLogGeneration, issueLinkMode: issueLinkMode }), _jsxs(Box, { flexDirection: "column", width: terminalColumns, height: streamPaneHeights.dynamicFrameHeight, overflowX: "visible", overflowY: "hidden", children: [operatorInputDisplay.mode === 'withQuestions' ? (_jsx(OpenQuestionsPane, { layout: streamOpenQuestionsLayout, terminalColumns: terminalColumns, issueLinkMode: issueLinkMode })) : null, _jsxs(TitledBorderPane, { title: INPUT_PANE_TITLE, borderStyle: "single", borderColor: INPUT_PANE_BORDER_COLOR, paddingX: PANE_PADDING_X, height: streamPaneHeights.inputPaneHeight, terminalColumns: terminalColumns, children: [contextHintLines.map((line, index) => (_jsx(WrappedTextLines, { text: line, width: contentWidth, color: INPUT_PANE_HINT_COLOR }, `context-hint-${index}`))), _jsx(OperatorTextArea, { value: inputValue, onChange: setInputValue, onSubmit: handleSubmit, focus: !snapshot.shuttingDown, contentWidth: contentWidth, promptPrefix: operatorPrompt, maxDisplayLines: maxInputDisplayLines, onDisplayLineCountChange: handleDisplayLineCountChange, cursorStart: cursorStart })] }), _jsx(WorkerStatusPane, { workers: snapshot.displayState.workers, dispatchHold: snapshot.displayState.dispatchHold, height: streamPaneHeights.workerPaneHeight, terminalColumns: terminalColumns, issueUrl: issueUrl, issueLinkMode: issueLinkMode })] })] }));
|
|
118
154
|
}
|
|
119
155
|
//# sourceMappingURL=issue-session-tui-stream.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-session-tui-stream.js","sourceRoot":"","sources":["../../src/tui/issue-session-tui-stream.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EACL,WAAW,EACX,SAAS,EACT,OAAO,EACP,QAAQ,EACR,oBAAoB,GACrB,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,mBAAmB,EAAqB,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EACL,4BAA4B,EAC5B,+BAA+B,EAC/B,8BAA8B,GAC/B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,qBAAqB,EACrB,cAAc,EACd,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,iCAAiC,GAClC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC7F,OAAO,EACL,+BAA+B,GAEhC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,4BAA4B,EAAyB,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EACL,kBAAkB,GAEnB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"issue-session-tui-stream.js","sourceRoot":"","sources":["../../src/tui/issue-session-tui-stream.tsx"],"names":[],"mappings":"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"}
|
|
@@ -2,15 +2,41 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
3
|
vi.mock('./operator-text-area.js', () => import('./operator-text-area.test-double.js'));
|
|
4
4
|
import { EventEmitter } from 'node:events';
|
|
5
|
+
import { PassThrough } from 'node:stream';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { render as renderInk } from 'ink';
|
|
5
8
|
import { cleanup, render } from 'ink-testing-library';
|
|
6
9
|
import { IssueSessionTuiStream } from './issue-session-tui-stream.js';
|
|
7
10
|
import { createTuiViewModel } from './tui-view-model.js';
|
|
8
11
|
import { flushInkStdin, INK_TEST_KEYS } from './ink-test-keys.js';
|
|
9
|
-
import { createTuiTerminalSizeStore, TUI_RESIZE_SETTLE_MS, } from './tui-terminal-size.js';
|
|
12
|
+
import { createTuiResizeController, createTuiTerminalSizeStore, TUI_RESIZE_SETTLE_MS, TUI_RESIZE_SHRINK_COALESCE_MS, } from './tui-terminal-size.js';
|
|
13
|
+
import { createTuiResizeRecovery, TUI_FULL_REDRAW_SEQUENCE, } from './tui-resize-recovery.js';
|
|
10
14
|
class ResizeSource extends EventEmitter {
|
|
11
15
|
columns = 80;
|
|
12
16
|
rows = 24;
|
|
13
17
|
}
|
|
18
|
+
class FakeTtyStdout extends PassThrough {
|
|
19
|
+
isTTY = true;
|
|
20
|
+
columns = 120;
|
|
21
|
+
rows = 32;
|
|
22
|
+
}
|
|
23
|
+
class FakeTtyStdin extends PassThrough {
|
|
24
|
+
isTTY = true;
|
|
25
|
+
isRaw = false;
|
|
26
|
+
setRawMode(value) {
|
|
27
|
+
this.isRaw = value;
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
ref() {
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
unref() {
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function waitFor(milliseconds) {
|
|
38
|
+
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
39
|
+
}
|
|
14
40
|
function createOpenQuestion(overrides) {
|
|
15
41
|
return {
|
|
16
42
|
responseType: 'text',
|
|
@@ -63,6 +89,43 @@ describe('IssueSessionTuiStream', () => {
|
|
|
63
89
|
expect(frame).toContain('inq-1 (1/1) への回答');
|
|
64
90
|
expect(frame).not.toContain('任意のタイミングで入力 · /reconnect で再接続 · /exit で終了');
|
|
65
91
|
});
|
|
92
|
+
it('keeps compact rows visible when long selected detail reaches the cap', async () => {
|
|
93
|
+
const viewModel = createTuiViewModel();
|
|
94
|
+
viewModel.setDisplayState({
|
|
95
|
+
workers: {},
|
|
96
|
+
conductorOutput: null,
|
|
97
|
+
openQuestions: [
|
|
98
|
+
createOpenQuestion({
|
|
99
|
+
id: 'inq-long',
|
|
100
|
+
question: `question-start ${'word '.repeat(100)}`,
|
|
101
|
+
context: `first-detail-start ${'context '.repeat(80)}context-tail`,
|
|
102
|
+
}),
|
|
103
|
+
createOpenQuestion({
|
|
104
|
+
id: 'inq-compact-1',
|
|
105
|
+
question: 'Second question',
|
|
106
|
+
context: 'second-detail',
|
|
107
|
+
}),
|
|
108
|
+
createOpenQuestion({
|
|
109
|
+
id: 'inq-compact-2',
|
|
110
|
+
question: 'Third question',
|
|
111
|
+
}),
|
|
112
|
+
],
|
|
113
|
+
dispatchHold: { hold: false, heldEventCount: 0 },
|
|
114
|
+
});
|
|
115
|
+
const { stdin, lastFrame } = render(_jsx(IssueSessionTuiStream, { viewModel: viewModel, onSubmit: () => { } }));
|
|
116
|
+
const initialFrame = lastFrame() ?? '';
|
|
117
|
+
expect(initialFrame).toContain('first-detail-start');
|
|
118
|
+
expect(initialFrame).toContain('inq-compact-1');
|
|
119
|
+
expect(initialFrame).toContain('inq-compact-2');
|
|
120
|
+
stdin.write(INK_TEST_KEYS.shiftDownArrow);
|
|
121
|
+
await flushInkStdin();
|
|
122
|
+
const switchedFrame = lastFrame() ?? '';
|
|
123
|
+
expect(switchedFrame).toContain('▸ inq-compact-1');
|
|
124
|
+
expect(switchedFrame).toContain('second-detail');
|
|
125
|
+
expect(switchedFrame).toContain('inq-long');
|
|
126
|
+
expect(switchedFrame).toContain('inq-compact-2');
|
|
127
|
+
expect(switchedFrame).not.toContain('first-detail-start');
|
|
128
|
+
});
|
|
66
129
|
it('renders inline Markdown in static activity output', () => {
|
|
67
130
|
const viewModel = createTuiViewModel();
|
|
68
131
|
viewModel.appendActivityLog('conductor', 'Use **bold** and `code`.');
|
|
@@ -72,6 +135,34 @@ describe('IssueSessionTuiStream', () => {
|
|
|
72
135
|
expect(frame).not.toContain('**');
|
|
73
136
|
expect(frame).not.toContain('`');
|
|
74
137
|
});
|
|
138
|
+
it('renders nested Markdown links in stream activity and open questions', () => {
|
|
139
|
+
const viewModel = createTuiViewModel();
|
|
140
|
+
viewModel.setDisplayState({
|
|
141
|
+
workers: {},
|
|
142
|
+
conductorOutput: null,
|
|
143
|
+
openQuestions: [
|
|
144
|
+
createOpenQuestion({
|
|
145
|
+
id: 'inq-stream-link',
|
|
146
|
+
question: '- **choose** [this](https://example.com/question)',
|
|
147
|
+
context: 'Use `safe` [docs](https://example.com/context).',
|
|
148
|
+
}),
|
|
149
|
+
],
|
|
150
|
+
dispatchHold: { hold: false, heldEventCount: 0 },
|
|
151
|
+
});
|
|
152
|
+
viewModel.appendActivityLog('conductor', '- **bold** [activity](https://example.com/activity)\n - `nested`');
|
|
153
|
+
const { lastFrame } = render(_jsx(IssueSessionTuiStream, { viewModel: viewModel, issueLinkMode: "osc8", onSubmit: () => { } }));
|
|
154
|
+
const frame = lastFrame() ?? '';
|
|
155
|
+
const visibleFrame = frame.replace(/\u001b\]8;;[^\u0007]*\u0007/g, '');
|
|
156
|
+
expect(visibleFrame).toContain('[conductor]');
|
|
157
|
+
expect(visibleFrame).toContain('- bold activity');
|
|
158
|
+
expect(visibleFrame).toContain('▸ inq-stream-link [text] - choose this');
|
|
159
|
+
expect(visibleFrame).toContain(' Use safe docs.');
|
|
160
|
+
expect(frame).toContain('\u001b]8;;https://example.com/activity\u0007');
|
|
161
|
+
expect(frame).toContain('\u001b]8;;https://example.com/question\u0007');
|
|
162
|
+
expect(frame).toContain('\u001b]8;;https://example.com/context\u0007');
|
|
163
|
+
expect(frame).not.toContain('**');
|
|
164
|
+
expect(frame).not.toContain('`');
|
|
165
|
+
});
|
|
75
166
|
it('shows dispatch hold count in the Workers pane title', () => {
|
|
76
167
|
const viewModel = createTuiViewModel();
|
|
77
168
|
viewModel.setDisplayState({
|
|
@@ -299,6 +390,49 @@ describe('IssueSessionTuiStream', () => {
|
|
|
299
390
|
expect(frame).toContain('[harness] first');
|
|
300
391
|
expect(frame).toContain('[observation] second');
|
|
301
392
|
});
|
|
393
|
+
it('holds new activity while detached and flushes the pending suffix once on End', async () => {
|
|
394
|
+
const viewModel = createTuiViewModel({ activityLogWindowSize: null });
|
|
395
|
+
viewModel.appendActivityLog('harness', 'committed');
|
|
396
|
+
const { stdin, lastFrame } = render(_jsx(IssueSessionTuiStream, { viewModel: viewModel, onSubmit: () => { } }));
|
|
397
|
+
stdin.write(INK_TEST_KEYS.pageUp);
|
|
398
|
+
await flushInkStdin();
|
|
399
|
+
viewModel.appendActivityLog('harness', 'pending-one');
|
|
400
|
+
viewModel.appendActivityLog('harness', 'pending-two');
|
|
401
|
+
await flushInkStdin();
|
|
402
|
+
const detachedFrame = lastFrame() ?? '';
|
|
403
|
+
expect(detachedFrame).not.toContain('[harness] pending-one');
|
|
404
|
+
expect(detachedFrame).not.toContain('[harness] pending-two');
|
|
405
|
+
expect(detachedFrame).toContain('2 件の新着 · End で最新へ');
|
|
406
|
+
stdin.write(INK_TEST_KEYS.end);
|
|
407
|
+
await flushInkStdin();
|
|
408
|
+
const followedFrame = lastFrame() ?? '';
|
|
409
|
+
expect(followedFrame).toContain('[harness] pending-one');
|
|
410
|
+
expect(followedFrame).toContain('[harness] pending-two');
|
|
411
|
+
expect((followedFrame.match(/\[harness\] pending-one/g) ?? []).length).toBe(1);
|
|
412
|
+
expect((followedFrame.match(/\[harness\] pending-two/g) ?? []).length).toBe(1);
|
|
413
|
+
expect(followedFrame).not.toContain('2 件の新着 · End で最新へ');
|
|
414
|
+
});
|
|
415
|
+
it('requires Ctrl+PgUp while input has text, matching the pane key contract', async () => {
|
|
416
|
+
const viewModel = createTuiViewModel({ activityLogWindowSize: null });
|
|
417
|
+
viewModel.appendActivityLog('harness', 'committed');
|
|
418
|
+
const { stdin, lastFrame } = render(_jsx(IssueSessionTuiStream, { viewModel: viewModel, onSubmit: () => { } }));
|
|
419
|
+
stdin.write('typed');
|
|
420
|
+
await flushInkStdin();
|
|
421
|
+
stdin.write(INK_TEST_KEYS.pageUp);
|
|
422
|
+
await flushInkStdin();
|
|
423
|
+
viewModel.appendActivityLog('harness', 'plain-page-up-followed');
|
|
424
|
+
await flushInkStdin();
|
|
425
|
+
expect(lastFrame() ?? '').toContain('[harness] plain-page-up-followed');
|
|
426
|
+
expect(lastFrame() ?? '').not.toContain('新着 · End で最新へ');
|
|
427
|
+
stdin.write(INK_TEST_KEYS.ctrlPageUp);
|
|
428
|
+
await flushInkStdin();
|
|
429
|
+
viewModel.appendActivityLog('harness', 'ctrl-page-up-pending');
|
|
430
|
+
await flushInkStdin();
|
|
431
|
+
const detachedFrame = lastFrame() ?? '';
|
|
432
|
+
expect(detachedFrame).toContain('typed');
|
|
433
|
+
expect(detachedFrame).not.toContain('[harness] ctrl-page-up-pending');
|
|
434
|
+
expect(detachedFrame).toContain('1 件の新着 · End で最新へ');
|
|
435
|
+
});
|
|
302
436
|
it('settles the live frame without replaying stream Static history', async () => {
|
|
303
437
|
vi.useFakeTimers();
|
|
304
438
|
const source = new ResizeSource();
|
|
@@ -311,12 +445,187 @@ describe('IssueSessionTuiStream', () => {
|
|
|
311
445
|
source.columns = 40;
|
|
312
446
|
source.rows = 12;
|
|
313
447
|
source.emit('resize');
|
|
314
|
-
await vi.advanceTimersByTimeAsync(
|
|
448
|
+
await vi.advanceTimersByTimeAsync(TUI_RESIZE_SHRINK_COALESCE_MS);
|
|
315
449
|
const frame = lastFrame() ?? '';
|
|
316
450
|
expect(countHistory(frame)).toBe(1);
|
|
317
451
|
expect(Math.max(...frame.split('\n').map((line) => line.trimEnd().length))).toBeLessThanOrEqual(40);
|
|
318
452
|
terminalSizeStore.dispose();
|
|
319
453
|
});
|
|
454
|
+
it('coalesces staged same-row shrink before redrawing the stream frame', async () => {
|
|
455
|
+
vi.useFakeTimers();
|
|
456
|
+
const source = new ResizeSource();
|
|
457
|
+
source.columns = 120;
|
|
458
|
+
source.rows = 32;
|
|
459
|
+
const resizeController = createTuiResizeController(source);
|
|
460
|
+
const terminalSizeStore = resizeController.terminalSize;
|
|
461
|
+
const viewModel = createTuiViewModel();
|
|
462
|
+
viewModel.appendActivityLog('harness', 'before staged resize');
|
|
463
|
+
const { lastFrame } = render(_jsx(IssueSessionTuiStream, { viewModel: viewModel, terminalSizeStore: terminalSizeStore, onSubmit: () => { } }));
|
|
464
|
+
const initialFrame = lastFrame() ?? '';
|
|
465
|
+
const countHistory = (frame) => (frame.match(/\[harness\] before staged resize/g) ?? []).length;
|
|
466
|
+
const inkResizeNotifications = [];
|
|
467
|
+
const inkResizeListener = () => {
|
|
468
|
+
inkResizeNotifications.push({
|
|
469
|
+
terminalColumns: terminalSizeStore.getSnapshot().columns,
|
|
470
|
+
proxyColumns: resizeController.stdout.columns,
|
|
471
|
+
});
|
|
472
|
+
};
|
|
473
|
+
resizeController.stdout.on('resize', inkResizeListener);
|
|
474
|
+
const unsubscribe = terminalSizeStore.subscribe(() => {
|
|
475
|
+
expect(resizeController.stdout.columns).toBeGreaterThanOrEqual(terminalSizeStore.getSnapshot().columns);
|
|
476
|
+
});
|
|
477
|
+
try {
|
|
478
|
+
expect(countHistory(initialFrame)).toBe(1);
|
|
479
|
+
for (const columns of [110, 100, 90, 80, 70]) {
|
|
480
|
+
source.columns = columns;
|
|
481
|
+
source.rows = 32;
|
|
482
|
+
source.emit('resize');
|
|
483
|
+
await vi.advanceTimersByTimeAsync(TUI_RESIZE_SETTLE_MS);
|
|
484
|
+
expect(inkResizeNotifications).toEqual([]);
|
|
485
|
+
expect(lastFrame()).toBe(initialFrame);
|
|
486
|
+
expect(countHistory(lastFrame() ?? '')).toBe(1);
|
|
487
|
+
}
|
|
488
|
+
source.columns = 60;
|
|
489
|
+
source.rows = 32;
|
|
490
|
+
source.emit('resize');
|
|
491
|
+
await vi.advanceTimersByTimeAsync(TUI_RESIZE_SHRINK_COALESCE_MS);
|
|
492
|
+
const finalFrame = lastFrame() ?? '';
|
|
493
|
+
expect(inkResizeNotifications).toEqual([
|
|
494
|
+
{ terminalColumns: 60, proxyColumns: 120 },
|
|
495
|
+
]);
|
|
496
|
+
expect(finalFrame).not.toBe(initialFrame);
|
|
497
|
+
expect(countHistory(finalFrame)).toBe(1);
|
|
498
|
+
expect(Math.max(...finalFrame.split('\n').map((line) => line.trimEnd().length))).toBeLessThanOrEqual(60);
|
|
499
|
+
expect(finalFrame).toContain('Workers');
|
|
500
|
+
expect(finalFrame).toContain('operator>');
|
|
501
|
+
}
|
|
502
|
+
finally {
|
|
503
|
+
unsubscribe();
|
|
504
|
+
resizeController.dispose();
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
it('clears and replays retained stream history once per settled shrink', async () => {
|
|
508
|
+
const source = new FakeTtyStdout();
|
|
509
|
+
const stdin = new FakeTtyStdin();
|
|
510
|
+
const stderr = new PassThrough();
|
|
511
|
+
const output = [];
|
|
512
|
+
source.on('data', (chunk) => {
|
|
513
|
+
output.push(chunk.toString());
|
|
514
|
+
});
|
|
515
|
+
const viewModel = createTuiViewModel({ activityLogWindowSize: null });
|
|
516
|
+
viewModel.appendActivityLog('observation', 'before-resize');
|
|
517
|
+
let ink;
|
|
518
|
+
let recovery;
|
|
519
|
+
const resizeController = createTuiResizeController(source, TUI_RESIZE_SETTLE_MS, (event) => {
|
|
520
|
+
recovery?.recover(event);
|
|
521
|
+
});
|
|
522
|
+
recovery = createTuiResizeRecovery({
|
|
523
|
+
clearInk: () => {
|
|
524
|
+
ink?.clear();
|
|
525
|
+
},
|
|
526
|
+
write: (data) => {
|
|
527
|
+
resizeController.stdout.write(data);
|
|
528
|
+
},
|
|
529
|
+
requestActivityLogReplay: () => {
|
|
530
|
+
viewModel.requestActivityLogReplay();
|
|
531
|
+
},
|
|
532
|
+
});
|
|
533
|
+
ink = renderInk(React.createElement(IssueSessionTuiStream, {
|
|
534
|
+
viewModel,
|
|
535
|
+
terminalSizeStore: resizeController.terminalSize,
|
|
536
|
+
onSubmit: () => { },
|
|
537
|
+
}), {
|
|
538
|
+
stdout: resizeController.stdout,
|
|
539
|
+
stdin: stdin,
|
|
540
|
+
stderr: stderr,
|
|
541
|
+
alternateScreen: false,
|
|
542
|
+
interactive: true,
|
|
543
|
+
patchConsole: false,
|
|
544
|
+
maxFps: 60,
|
|
545
|
+
});
|
|
546
|
+
try {
|
|
547
|
+
await ink.waitUntilRenderFlush();
|
|
548
|
+
const firstOutputLength = output.join('').length;
|
|
549
|
+
source.columns = 60;
|
|
550
|
+
source.emit('resize');
|
|
551
|
+
await waitFor(TUI_RESIZE_SHRINK_COALESCE_MS + 80);
|
|
552
|
+
await ink.waitUntilRenderFlush();
|
|
553
|
+
const firstRecoveryOutput = output.join('').slice(firstOutputLength);
|
|
554
|
+
const firstResetIndex = firstRecoveryOutput.indexOf(TUI_FULL_REDRAW_SEQUENCE);
|
|
555
|
+
const firstMarkerIndex = firstRecoveryOutput.indexOf('[observation] before-resize');
|
|
556
|
+
expect(firstRecoveryOutput.split(TUI_FULL_REDRAW_SEQUENCE)).toHaveLength(2);
|
|
557
|
+
expect(firstResetIndex).toBeGreaterThanOrEqual(0);
|
|
558
|
+
expect(firstResetIndex).toBeLessThan(firstMarkerIndex);
|
|
559
|
+
expect(firstRecoveryOutput.match(/\[observation\] before-resize/g)).toHaveLength(1);
|
|
560
|
+
expect(viewModel.getSnapshot().activityLogGeneration).toBe(1);
|
|
561
|
+
viewModel.appendActivityLog('observation', 'after-resize');
|
|
562
|
+
await ink.waitUntilRenderFlush();
|
|
563
|
+
const secondOutputLength = output.join('').length;
|
|
564
|
+
source.columns = 40;
|
|
565
|
+
source.emit('resize');
|
|
566
|
+
await waitFor(TUI_RESIZE_SHRINK_COALESCE_MS + 80);
|
|
567
|
+
await ink.waitUntilRenderFlush();
|
|
568
|
+
const secondRecoveryOutput = output.join('').slice(secondOutputLength);
|
|
569
|
+
const secondResetIndex = secondRecoveryOutput.indexOf(TUI_FULL_REDRAW_SEQUENCE);
|
|
570
|
+
const secondMarkerIndex = secondRecoveryOutput.indexOf('[observation] before-resize');
|
|
571
|
+
expect(secondRecoveryOutput.split(TUI_FULL_REDRAW_SEQUENCE)).toHaveLength(2);
|
|
572
|
+
expect(secondResetIndex).toBeGreaterThanOrEqual(0);
|
|
573
|
+
expect(secondResetIndex).toBeLessThan(secondMarkerIndex);
|
|
574
|
+
expect(secondRecoveryOutput.match(/\[observation\] before-resize/g)).toHaveLength(1);
|
|
575
|
+
expect(secondRecoveryOutput.match(/\[observation\] after-resize/g)).toHaveLength(1);
|
|
576
|
+
expect(viewModel.getSnapshot().activityLogGeneration).toBe(2);
|
|
577
|
+
}
|
|
578
|
+
finally {
|
|
579
|
+
recovery.dispose();
|
|
580
|
+
ink.unmount();
|
|
581
|
+
await ink.waitUntilExit();
|
|
582
|
+
resizeController.dispose();
|
|
583
|
+
stdin.destroy();
|
|
584
|
+
stderr.destroy();
|
|
585
|
+
source.destroy();
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
it('applies a stream width increase after a pending shrink through the normal path', async () => {
|
|
589
|
+
vi.useFakeTimers();
|
|
590
|
+
const source = new ResizeSource();
|
|
591
|
+
source.columns = 120;
|
|
592
|
+
source.rows = 32;
|
|
593
|
+
const resizeController = createTuiResizeController(source);
|
|
594
|
+
const terminalSizeStore = resizeController.terminalSize;
|
|
595
|
+
const viewModel = createTuiViewModel();
|
|
596
|
+
const { lastFrame } = render(_jsx(IssueSessionTuiStream, { viewModel: viewModel, terminalSizeStore: terminalSizeStore, onSubmit: () => { } }));
|
|
597
|
+
const resizeNotifications = [];
|
|
598
|
+
resizeController.stdout.on('resize', () => {
|
|
599
|
+
resizeNotifications.push({
|
|
600
|
+
terminalColumns: terminalSizeStore.getSnapshot().columns,
|
|
601
|
+
proxyColumns: resizeController.stdout.columns,
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
try {
|
|
605
|
+
source.columns = 60;
|
|
606
|
+
source.rows = 32;
|
|
607
|
+
source.emit('resize');
|
|
608
|
+
await vi.advanceTimersByTimeAsync(TUI_RESIZE_SHRINK_COALESCE_MS);
|
|
609
|
+
const shrunkFrame = lastFrame() ?? '';
|
|
610
|
+
const shrunkWidth = Math.max(...shrunkFrame.split('\n').map((line) => line.trimEnd().length));
|
|
611
|
+
source.columns = 120;
|
|
612
|
+
source.rows = 32;
|
|
613
|
+
source.emit('resize');
|
|
614
|
+
await vi.advanceTimersByTimeAsync(TUI_RESIZE_SETTLE_MS);
|
|
615
|
+
const grownFrame = lastFrame() ?? '';
|
|
616
|
+
const grownWidth = Math.max(...grownFrame.split('\n').map((line) => line.trimEnd().length));
|
|
617
|
+
expect(terminalSizeStore.getSnapshot().columns).toBe(120);
|
|
618
|
+
expect(resizeNotifications).toEqual([
|
|
619
|
+
{ terminalColumns: 60, proxyColumns: 120 },
|
|
620
|
+
{ terminalColumns: 120, proxyColumns: 120 },
|
|
621
|
+
]);
|
|
622
|
+
expect(grownFrame).not.toBe(shrunkFrame);
|
|
623
|
+
expect(grownWidth).toBeGreaterThan(shrunkWidth);
|
|
624
|
+
}
|
|
625
|
+
finally {
|
|
626
|
+
resizeController.dispose();
|
|
627
|
+
}
|
|
628
|
+
});
|
|
320
629
|
it('submits input for the selected open question', async () => {
|
|
321
630
|
const viewModel = createTuiViewModel();
|
|
322
631
|
viewModel.setDisplayState({
|