moderado 0.4.10 → 0.4.26
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 +38 -13
- package/dist/args.d.ts +1 -1
- package/dist/args.d.ts.map +1 -1
- package/dist/args.js +8 -1
- package/dist/args.js.map +1 -1
- package/dist/commands/chat.d.ts +1 -2
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +42 -20
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/skills.js +2 -2
- package/dist/commands/skills.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/self_update.d.ts +53 -0
- package/dist/self_update.d.ts.map +1 -0
- package/dist/self_update.js +515 -0
- package/dist/self_update.js.map +1 -0
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +16 -8
- package/dist/skills.js.map +1 -1
- package/dist/ui/help_modal.js +1 -1
- package/dist/ui/help_modal.js.map +1 -1
- package/dist/ui/provider_connect.d.ts.map +1 -1
- package/dist/ui/provider_connect.js +82 -55
- package/dist/ui/provider_connect.js.map +1 -1
- package/dist/ui/renderer.d.ts +6 -0
- package/dist/ui/renderer.d.ts.map +1 -1
- package/dist/ui/renderer.js +23 -4
- package/dist/ui/renderer.js.map +1 -1
- package/dist/ui/welcome.d.ts +30 -7
- package/dist/ui/welcome.d.ts.map +1 -1
- package/dist/ui/welcome.js +157 -59
- package/dist/ui/welcome.js.map +1 -1
- package/package.json +1 -1
package/dist/ui/welcome.d.ts
CHANGED
|
@@ -9,11 +9,14 @@ export interface WelcomeLayoutOptions {
|
|
|
9
9
|
mode: 'Plan' | 'Execute';
|
|
10
10
|
autoApprove: boolean;
|
|
11
11
|
input?: string;
|
|
12
|
+
inputCaret?: number;
|
|
12
13
|
width?: number;
|
|
13
14
|
/** When set, render the full chat window (question row 1 + answer) instead of the logo header. */
|
|
14
15
|
chatQuestion?: string;
|
|
15
16
|
chatAnswer?: string;
|
|
16
17
|
chatThoughtTime?: number;
|
|
18
|
+
/** Settled turn completed successfully — render the "✔ Done" status marker. */
|
|
19
|
+
chatTaskDone?: boolean;
|
|
17
20
|
/** Generated completion tokens per second for the preceding response. */
|
|
18
21
|
outputTokenRate?: number;
|
|
19
22
|
tokenUsage?: UsageEvent;
|
|
@@ -31,6 +34,18 @@ export declare function stripAnsi(str: string): string;
|
|
|
31
34
|
export declare function getWelcomeCardWidth(width?: number): number;
|
|
32
35
|
/** Left indent that centers a block of `blockWidth` visible columns on the terminal. */
|
|
33
36
|
export declare function getWelcomeIndent(blockWidth: number, width?: number): number;
|
|
37
|
+
/**
|
|
38
|
+
* Geometry of the answer area: it occupies the same columns as the composer
|
|
39
|
+
* card, so the question row, the streamed answer, and the input box all share
|
|
40
|
+
* one width instead of stretching across a wide terminal.
|
|
41
|
+
*/
|
|
42
|
+
export declare function getChatAnswerArea(width?: number): {
|
|
43
|
+
indent: number;
|
|
44
|
+
cardWidth: number;
|
|
45
|
+
textWidth: number;
|
|
46
|
+
startColumn: number;
|
|
47
|
+
wrapWidth: number;
|
|
48
|
+
};
|
|
34
49
|
export declare function renderQueuedCommandsBox(commands: readonly string[], width: number): string[];
|
|
35
50
|
export declare function renderWelcomeCard(options: WelcomeLayoutOptions): string;
|
|
36
51
|
export interface SlashCommand {
|
|
@@ -40,10 +55,10 @@ export interface SlashCommand {
|
|
|
40
55
|
export declare const SLASH_COMMANDS: SlashCommand[];
|
|
41
56
|
export declare function getMatchingCommands(input: string): SlashCommand[];
|
|
42
57
|
export declare function selectCommandCandidate(input: string, currentIndex: number, direction: number): SlashCommand | undefined;
|
|
43
|
-
export declare function renderSuggestionsBox(commands: SlashCommand[], width?: number): string[];
|
|
44
|
-
export declare function renderMentionSuggestionsBox(files: string[], selectedIndex?: number): string[];
|
|
45
|
-
export declare function renderModeradoHeader(): string;
|
|
46
|
-
/** Word-wrap plain text to `maxWidth` visible columns. */
|
|
58
|
+
export declare function renderSuggestionsBox(commands: SlashCommand[], width?: number, selectedIndex?: number): string[];
|
|
59
|
+
export declare function renderMentionSuggestionsBox(files: string[], selectedIndex?: number, width?: number): string[];
|
|
60
|
+
export declare function renderModeradoHeader(width?: number): string;
|
|
61
|
+
/** Word-wrap plain text to `maxWidth` visible columns, hard-breaking long words. */
|
|
47
62
|
export declare function wrapText(text: string, maxWidth: number): string[];
|
|
48
63
|
/**
|
|
49
64
|
* Full chat window (after a question is submitted): no logo — the question is
|
|
@@ -59,13 +74,20 @@ export declare function navigateQuestionHistory(history: string[], direction: -1
|
|
|
59
74
|
draft: string;
|
|
60
75
|
};
|
|
61
76
|
/** Update the fixed chat elapsed-time row without repainting the terminal. */
|
|
62
|
-
export declare function renderChatThoughtTimeUpdate(thoughtTime: number
|
|
77
|
+
export declare function renderChatThoughtTimeUpdate(thoughtTime: number, taskStep?: {
|
|
78
|
+
step: number;
|
|
79
|
+
maxSteps: number;
|
|
80
|
+
}, width?: number): string;
|
|
63
81
|
export interface ChatAnswerPosition {
|
|
64
82
|
row: number;
|
|
65
83
|
column: number;
|
|
66
84
|
}
|
|
67
|
-
/**
|
|
68
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Write one streamed fragment into the answer area without repainting the chat
|
|
87
|
+
* frame. Wrapped lines return to `startColumn` so the answer keeps the same
|
|
88
|
+
* columns as the composer card instead of stretching across the terminal.
|
|
89
|
+
*/
|
|
90
|
+
export declare function renderChatAnswerDelta(delta: string, start: ChatAnswerPosition, width: number, startColumn?: number): ChatAnswerPosition & {
|
|
69
91
|
sequence: string;
|
|
70
92
|
};
|
|
71
93
|
export declare function renderFullWelcomeScreen(options: WelcomeLayoutOptions, height?: number): string;
|
|
@@ -107,6 +129,7 @@ export interface PromptInteractiveTurnOptions {
|
|
|
107
129
|
chatQuestion?: string;
|
|
108
130
|
chatAnswer?: string;
|
|
109
131
|
chatThoughtTime?: number;
|
|
132
|
+
chatTaskDone?: boolean;
|
|
110
133
|
outputTokenRate?: number;
|
|
111
134
|
tokenUsage?: UsageEvent;
|
|
112
135
|
questionHistory?: string[];
|
package/dist/ui/welcome.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"welcome.d.ts","sourceRoot":"","sources":["../../src/ui/welcome.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAI1E,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kGAAkG;IAClG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,eAAO,MAAM,mBAAmB,UAM/B,CAAC;AAEF,eAAO,MAAM,YAAY,yIACmG,CAAC;AAE7H,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C;
|
|
1
|
+
{"version":3,"file":"welcome.d.ts","sourceRoot":"","sources":["../../src/ui/welcome.ts"],"names":[],"mappings":"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"}
|
package/dist/ui/welcome.js
CHANGED
|
@@ -16,6 +16,11 @@ export function stripAnsi(str) {
|
|
|
16
16
|
function visibleLen(str) {
|
|
17
17
|
return stripAnsi(str).length;
|
|
18
18
|
}
|
|
19
|
+
function composerInputWindow(input, caret, width) {
|
|
20
|
+
const capacity = Math.max(1, width - 3);
|
|
21
|
+
const start = Math.max(0, Math.min(caret, input.length - capacity));
|
|
22
|
+
return { text: input.slice(start, start + capacity), caretColumn: caret - start };
|
|
23
|
+
}
|
|
19
24
|
/** Card width: nearly full terminal width, like OpenCode/Cline. */
|
|
20
25
|
export function getWelcomeCardWidth(width) {
|
|
21
26
|
const terminalWidth = width ?? (process.stdout.columns || 80);
|
|
@@ -26,13 +31,28 @@ export function getWelcomeIndent(blockWidth, width) {
|
|
|
26
31
|
const terminalWidth = width ?? (process.stdout.columns || 80);
|
|
27
32
|
return Math.max(0, Math.floor((terminalWidth - blockWidth) / 2));
|
|
28
33
|
}
|
|
29
|
-
/** Center each line of a block
|
|
34
|
+
/** Center each line of a block inside the input card's columns (used for the ASCII logo / hints). */
|
|
30
35
|
function centerBlock(lines, width) {
|
|
36
|
+
const terminalWidth = width ?? (process.stdout.columns || 80);
|
|
37
|
+
const cardWidth = getWelcomeCardWidth(terminalWidth);
|
|
38
|
+
const cardIndent = getWelcomeIndent(cardWidth, terminalWidth);
|
|
31
39
|
return lines.map((line) => {
|
|
32
|
-
const pad =
|
|
33
|
-
return ' '.repeat(pad) + line;
|
|
40
|
+
const pad = Math.max(0, Math.floor((cardWidth - visibleLen(line)) / 2));
|
|
41
|
+
return ' '.repeat(cardIndent + pad) + line;
|
|
34
42
|
});
|
|
35
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Geometry of the answer area: it occupies the same columns as the composer
|
|
46
|
+
* card, so the question row, the streamed answer, and the input box all share
|
|
47
|
+
* one width instead of stretching across a wide terminal.
|
|
48
|
+
*/
|
|
49
|
+
export function getChatAnswerArea(width) {
|
|
50
|
+
const terminalWidth = width ?? (process.stdout.columns || 80);
|
|
51
|
+
const cardWidth = getWelcomeCardWidth(terminalWidth);
|
|
52
|
+
const indent = getWelcomeIndent(cardWidth, terminalWidth);
|
|
53
|
+
const textWidth = Math.max(20, cardWidth - 2);
|
|
54
|
+
return { indent, cardWidth, textWidth, startColumn: indent + 1, wrapWidth: indent + textWidth };
|
|
55
|
+
}
|
|
36
56
|
export function renderQueuedCommandsBox(commands, width) {
|
|
37
57
|
if (!commands || commands.length === 0)
|
|
38
58
|
return [];
|
|
@@ -63,7 +83,7 @@ export function renderWelcomeCard(options) {
|
|
|
63
83
|
const width = getWelcomeCardWidth(options.width);
|
|
64
84
|
const indent = ' '.repeat(getWelcomeIndent(width, options.width));
|
|
65
85
|
const displayInput = options.input && options.input.length > 0
|
|
66
|
-
? options.input
|
|
86
|
+
? composerInputWindow(options.input, options.inputCaret ?? options.input.length, width).text
|
|
67
87
|
: '\x1b[38;5;242mAsk anything, I am all ears...\x1b[0m';
|
|
68
88
|
const promptMarker = '\x1b[1;38;5;75m' + String.fromCodePoint(0x276F) + '\x1b[0;48;5;236m';
|
|
69
89
|
const textBox = `${promptMarker} ${displayInput}`;
|
|
@@ -93,18 +113,21 @@ export function renderWelcomeCard(options) {
|
|
|
93
113
|
const spaces4Count = Math.max(1, width - visibleLen(left4) - right4Raw.length);
|
|
94
114
|
const line4 = left4 + ' '.repeat(spaces4Count) + right4;
|
|
95
115
|
// Line 5: Working directory (left) ... model and Auto-approve (right)
|
|
96
|
-
const
|
|
97
|
-
? '
|
|
116
|
+
const approvalLabelRaw = options.autoApprove
|
|
117
|
+
? 'Auto-approve enabled (Shift+Tab)'
|
|
118
|
+
: 'Auto-approve off (Shift+Tab)';
|
|
119
|
+
const modelSpace = Math.max(8, width - approvalLabelRaw.length - 10);
|
|
120
|
+
const shortModel = options.model.length > modelSpace ? '...' + options.model.slice(-(modelSpace - 3)) : options.model;
|
|
121
|
+
const workspaceSpace = Math.max(3, width - approvalLabelRaw.length - shortModel.length - 2);
|
|
122
|
+
const shortWs = options.workspace.length > workspaceSpace
|
|
123
|
+
? '...' + options.workspace.slice(-(workspaceSpace - 3))
|
|
98
124
|
: options.workspace;
|
|
99
125
|
const left5 = `\x1b[38;5;245m${shortWs}\x1b[0m`;
|
|
100
126
|
const approvalLabel = options.autoApprove
|
|
101
127
|
? '\x1b[38;5;114mAuto-approve enabled (Shift+Tab)\x1b[0m'
|
|
102
128
|
: '\x1b[38;5;242mAuto-approve off (Shift+Tab)\x1b[0m';
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
: 'Auto-approve off (Shift+Tab)';
|
|
106
|
-
const modelLabel = `\x1b[38;5;180m${options.model}\x1b[0m`;
|
|
107
|
-
const spaces5Count = Math.max(1, width - shortWs.length - options.model.length - approvalLabelRaw.length - 2);
|
|
129
|
+
const modelLabel = `\x1b[38;5;180m${shortModel}\x1b[0m`;
|
|
130
|
+
const spaces5Count = Math.max(1, width - shortWs.length - shortModel.length - approvalLabelRaw.length - 1);
|
|
108
131
|
const line5 = left5 + ' '.repeat(spaces5Count) + modelLabel + ' ' + approvalLabel;
|
|
109
132
|
const cardLines = [];
|
|
110
133
|
const queuedBox = renderQueuedCommandsBox(options.queuedCommands ?? [], width);
|
|
@@ -115,11 +138,11 @@ export function renderWelcomeCard(options) {
|
|
|
115
138
|
if (!options.mentionFiles?.length && options.input?.startsWith('/')) {
|
|
116
139
|
const matching = getMatchingCommands(options.input);
|
|
117
140
|
if (matching.length)
|
|
118
|
-
cardLines.push(...renderSuggestionsBox(matching, width).map(line => indent + line));
|
|
141
|
+
cardLines.push(...renderSuggestionsBox(matching, width, options.commandSelection ?? 0).map(line => indent + line));
|
|
119
142
|
}
|
|
120
143
|
cardLines.push(indent + surfaceLine(), indent + surfaceLine(textBox), indent + surfaceLine(), indent + line4, indent + line5);
|
|
121
144
|
if (options.mentionFiles && options.mentionFiles.length > 0) {
|
|
122
|
-
cardLines.push(...renderMentionSuggestionsBox(options.mentionFiles, options.mentionSelection ?? 0).map((line) => indent + line));
|
|
145
|
+
cardLines.push(...renderMentionSuggestionsBox(options.mentionFiles, options.mentionSelection ?? 0, width).map((line) => indent + line));
|
|
123
146
|
}
|
|
124
147
|
return cardLines.join('\n');
|
|
125
148
|
}
|
|
@@ -153,60 +176,88 @@ export function selectCommandCandidate(input, currentIndex, direction) {
|
|
|
153
176
|
const index = ((currentIndex + direction) % commands.length + commands.length) % commands.length;
|
|
154
177
|
return commands[index];
|
|
155
178
|
}
|
|
156
|
-
export function renderSuggestionsBox(commands, width) {
|
|
179
|
+
export function renderSuggestionsBox(commands, width, selectedIndex = 0) {
|
|
157
180
|
if (commands.length === 0)
|
|
158
181
|
return [];
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const boxWidth =
|
|
182
|
+
// Exactly the card width so the box shares the composer's columns instead of
|
|
183
|
+
// forcing its own (previously a 78–82 fixed width that escaped narrow cards).
|
|
184
|
+
const boxWidth = width ?? getWelcomeCardWidth(process.stdout?.columns || 80);
|
|
162
185
|
const innerW = boxWidth - 4;
|
|
163
|
-
const title = 'Commands (
|
|
186
|
+
const title = 'Commands (↑↓ browse, Tab to insert)';
|
|
164
187
|
const remainingDashes = Math.max(0, boxWidth - title.length - 5);
|
|
165
188
|
const nameColWidth = 10;
|
|
166
189
|
const availDescWidth = Math.max(20, innerW - nameColWidth - 2);
|
|
167
190
|
const lines = [];
|
|
168
191
|
lines.push('\x1b[38;5;240m╭─ \x1b[1;38;5;75m' + title + '\x1b[0;38;5;240m ' + '─'.repeat(remainingDashes) + '╮\x1b[0m');
|
|
169
|
-
for (const cmd of commands) {
|
|
170
|
-
const
|
|
192
|
+
for (const [index, cmd] of commands.entries()) {
|
|
193
|
+
const isSelected = index === selectedIndex;
|
|
171
194
|
let desc = cmd.desc;
|
|
172
195
|
if (desc.length > availDescWidth) {
|
|
173
196
|
desc = desc.slice(0, availDescWidth - 1) + '…';
|
|
174
197
|
}
|
|
175
|
-
const
|
|
176
|
-
|
|
198
|
+
const nameCell = cmd.name.padEnd(nameColWidth);
|
|
199
|
+
const descCell = desc.padEnd(availDescWidth);
|
|
200
|
+
if (isSelected) {
|
|
201
|
+
// Highlight bar matches the app's list popups: a ❯ cursor plus a dark
|
|
202
|
+
// background across the whole row, so the arrow-key selection is visible.
|
|
203
|
+
lines.push('\x1b[38;5;240m│\x1b[0m' +
|
|
204
|
+
'\x1b[48;5;236m\x1b[1;38;5;75m❯ ' + nameCell +
|
|
205
|
+
'\x1b[0;48;5;236;38;5;253m ' + descCell + '\x1b[0m' +
|
|
206
|
+
'\x1b[38;5;240m│\x1b[0m');
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
lines.push('\x1b[38;5;240m│\x1b[0m' +
|
|
210
|
+
' ' + `\x1b[1;38;5;75m${nameCell}\x1b[0m` + ' ' +
|
|
211
|
+
`\x1b[38;5;244m${descCell}\x1b[0m` +
|
|
212
|
+
'\x1b[38;5;240m│\x1b[0m');
|
|
213
|
+
}
|
|
177
214
|
}
|
|
178
215
|
lines.push('\x1b[38;5;240m╰' + '─'.repeat(boxWidth - 2) + '╯\x1b[0m');
|
|
179
216
|
return lines;
|
|
180
217
|
}
|
|
181
|
-
export function renderMentionSuggestionsBox(files, selectedIndex = 0) {
|
|
218
|
+
export function renderMentionSuggestionsBox(files, selectedIndex = 0, width) {
|
|
182
219
|
if (files.length === 0)
|
|
183
220
|
return [];
|
|
221
|
+
// Sized to the composer card (like the queued/commands boxes) so it never
|
|
222
|
+
// breaks the card's left/right boundary.
|
|
223
|
+
const boxWidth = width ?? getWelcomeCardWidth(process.stdout?.columns || 80);
|
|
224
|
+
const title = 'Files (@ to mention, Tab to insert)';
|
|
184
225
|
const lines = [];
|
|
185
|
-
|
|
226
|
+
const remainingDashes = Math.max(0, boxWidth - title.length - 5);
|
|
227
|
+
lines.push('\x1b[38;5;240m╭─ \x1b[1;38;5;75m' + title + '\x1b[0;38;5;240m ' + '─'.repeat(remainingDashes) + '╮\x1b[0m');
|
|
186
228
|
for (let i = 0; i < files.length; i++) {
|
|
187
229
|
const file = files[i];
|
|
188
230
|
const isSelected = i === selectedIndex;
|
|
189
231
|
const marker = isSelected ? '\x1b[1;38;5;75m❯ \x1b[0m' : ' ';
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
232
|
+
// Visible budget: │ + space + marker(2) + label + pad + │ = boxWidth.
|
|
233
|
+
const labelCapacity = Math.max(4, boxWidth - 5);
|
|
234
|
+
let label = `@${file}`;
|
|
235
|
+
if (label.length > labelCapacity)
|
|
236
|
+
label = `@${file.slice(0, Math.max(1, labelCapacity - 4))}...`;
|
|
237
|
+
const nameStr = isSelected ? `\x1b[1;38;5;75m${label}\x1b[0m` : `\x1b[38;5;250m${label}\x1b[0m`;
|
|
238
|
+
const pad = Math.max(0, boxWidth - 5 - label.length);
|
|
239
|
+
lines.push(`\x1b[38;5;240m│\x1b[0m ${marker}${nameStr}${' '.repeat(pad)}\x1b[38;5;240m│\x1b[0m`);
|
|
195
240
|
}
|
|
196
|
-
lines.push('\x1b[38;5;240m
|
|
241
|
+
lines.push('\x1b[38;5;240m╰' + '─'.repeat(Math.max(0, boxWidth - 2)) + '╯\x1b[0m');
|
|
197
242
|
return lines;
|
|
198
243
|
}
|
|
199
|
-
export function renderModeradoHeader() {
|
|
244
|
+
export function renderModeradoHeader(width) {
|
|
200
245
|
return [
|
|
201
246
|
'',
|
|
202
|
-
...centerBlock(MODERADO_ASCII_LOGO),
|
|
247
|
+
...centerBlock(MODERADO_ASCII_LOGO, width),
|
|
203
248
|
'',
|
|
204
|
-
...centerBlock([COMMAND_HINT]),
|
|
249
|
+
...centerBlock([COMMAND_HINT], width),
|
|
205
250
|
].join('\n');
|
|
206
251
|
}
|
|
207
|
-
/** Word-wrap plain text to `maxWidth` visible columns. */
|
|
252
|
+
/** Word-wrap plain text to `maxWidth` visible columns, hard-breaking long words. */
|
|
208
253
|
export function wrapText(text, maxWidth) {
|
|
209
254
|
const out = [];
|
|
255
|
+
const pushWrapped = (word) => {
|
|
256
|
+
// A single word longer than the column budget is split so no line overflows.
|
|
257
|
+
for (let start = 0; start < word.length; start += maxWidth) {
|
|
258
|
+
out.push(word.slice(start, start + maxWidth));
|
|
259
|
+
}
|
|
260
|
+
};
|
|
210
261
|
for (const rawLine of text.split('\n')) {
|
|
211
262
|
if (rawLine.length <= maxWidth) {
|
|
212
263
|
out.push(rawLine);
|
|
@@ -214,6 +265,14 @@ export function wrapText(text, maxWidth) {
|
|
|
214
265
|
}
|
|
215
266
|
let current = '';
|
|
216
267
|
for (const word of rawLine.split(' ')) {
|
|
268
|
+
if (word.length > maxWidth) {
|
|
269
|
+
if (current.length > 0) {
|
|
270
|
+
out.push(current);
|
|
271
|
+
current = '';
|
|
272
|
+
}
|
|
273
|
+
pushWrapped(word);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
217
276
|
if (current.length === 0) {
|
|
218
277
|
current = word;
|
|
219
278
|
}
|
|
@@ -238,27 +297,35 @@ export function wrapText(text, maxWidth) {
|
|
|
238
297
|
export function renderChatScreen(options, height) {
|
|
239
298
|
const terminalWidth = options.width ?? (process.stdout.columns || 80);
|
|
240
299
|
const terminalHeight = height ?? process.stdout.rows ?? 24;
|
|
241
|
-
const
|
|
242
|
-
const
|
|
300
|
+
const area = getChatAnswerArea(terminalWidth);
|
|
301
|
+
const indent = ' '.repeat(area.indent);
|
|
243
302
|
const lines = [];
|
|
244
|
-
lines.push(...renderModeradoHeader().split('\n'));
|
|
303
|
+
lines.push(...renderModeradoHeader(terminalWidth).split('\n'));
|
|
245
304
|
lines.push('');
|
|
246
|
-
// Row 1: the user's question
|
|
305
|
+
// Row 1: the user's question, wrapped onto the same columns as the composer card.
|
|
247
306
|
const questionMarker = '\x1b[1;38;5;75m' + String.fromCodePoint(0x276F) + '\x1b[0;48;5;236m';
|
|
248
|
-
const
|
|
249
|
-
|
|
307
|
+
for (const [index, questionLine] of wrapText(options.chatQuestion ?? '', area.textWidth - 2).entries()) {
|
|
308
|
+
const questionText = `${index === 0 ? questionMarker : ' '} ${questionLine}`;
|
|
309
|
+
lines.push(indent + String.fromCharCode(27) + '[48;5;236m' + questionText + ' '.repeat(Math.max(0, area.cardWidth - visibleLen(questionText))) + String.fromCharCode(27) + '[0m');
|
|
310
|
+
}
|
|
250
311
|
const thoughtTime = options.chatThoughtTime ?? 0;
|
|
251
312
|
const thoughtTimeLabel = thoughtTime > 0 && thoughtTime < 1 ? '<1s' : `${Math.round(thoughtTime)}s`;
|
|
252
|
-
const chatStatus = !options.
|
|
253
|
-
|
|
313
|
+
const chatStatus = !options.chatAnswer?.trim()
|
|
314
|
+
? ''
|
|
315
|
+
: options.chatTaskDone
|
|
316
|
+
? `✔ Done · Thought for ${thoughtTimeLabel}`
|
|
317
|
+
: options.tokenUsage
|
|
318
|
+
? ''
|
|
319
|
+
: `Thought for ${thoughtTimeLabel}`;
|
|
320
|
+
lines.push(chatStatus ? indent + `\x1b[38;5;244m${chatStatus.slice(0, Math.max(0, area.cardWidth - 1))}\x1b[0m` : '');
|
|
254
321
|
// Answer section: multi-line model answer
|
|
255
322
|
if (options.chatAnswer && options.chatAnswer.trim().length > 0) {
|
|
256
323
|
lines.push('');
|
|
257
|
-
for (const answerLine of wrapText(options.chatAnswer.trim(),
|
|
324
|
+
for (const answerLine of wrapText(options.chatAnswer.trim(), area.textWidth)) {
|
|
258
325
|
const heading = answerLine.match(/^\s*(?:#{1,6}\s+([^#]+?)|\*\*(.+?)\*\*)\s*$/);
|
|
259
|
-
lines.push(heading
|
|
326
|
+
lines.push(indent + (heading
|
|
260
327
|
? `\x1b[1;38;5;25m${(heading[1] ?? heading[2]).trim()}\x1b[0m`
|
|
261
|
-
: `\x1b[38;5;253m${answerLine}\x1b[0m`);
|
|
328
|
+
: `\x1b[38;5;253m${answerLine}\x1b[0m`));
|
|
262
329
|
}
|
|
263
330
|
}
|
|
264
331
|
const composer = renderWelcomeCard(options).split('\n');
|
|
@@ -268,7 +335,8 @@ export function renderChatScreen(options, height) {
|
|
|
268
335
|
}
|
|
269
336
|
/** Place the terminal cursor on the first row of the bottom composer. */
|
|
270
337
|
export function renderChatComposerCursor(options, inputLength) {
|
|
271
|
-
const
|
|
338
|
+
const width = getWelcomeCardWidth(options.width);
|
|
339
|
+
const column = getWelcomeIndent(width, options.width) + 2 + Math.min(inputLength, width - 3);
|
|
272
340
|
return `\x1b[1 q\x1b[?25h\x1b[4A\r\x1b[${column}C`;
|
|
273
341
|
}
|
|
274
342
|
export function navigateQuestionHistory(history, direction, index, draft) {
|
|
@@ -276,34 +344,57 @@ export function navigateQuestionHistory(history, direction, index, draft) {
|
|
|
276
344
|
return { input: nextIndex === history.length ? draft : history[nextIndex], index: nextIndex, draft };
|
|
277
345
|
}
|
|
278
346
|
/** Update the fixed chat elapsed-time row without repainting the terminal. */
|
|
279
|
-
export function renderChatThoughtTimeUpdate(thoughtTime) {
|
|
347
|
+
export function renderChatThoughtTimeUpdate(thoughtTime, taskStep, width) {
|
|
348
|
+
const area = getChatAnswerArea(width);
|
|
280
349
|
const label = thoughtTime > 0 && thoughtTime < 1 ? '<1s' : `${Math.round(thoughtTime)}s`;
|
|
281
|
-
|
|
350
|
+
const status = (taskStep && taskStep.maxSteps > 0 && taskStep.step >= 0
|
|
351
|
+
? `Processing task… Step ${taskStep.step}/${taskStep.maxSteps} · ${label}`
|
|
352
|
+
: `Thought for ${label}`).slice(0, area.cardWidth);
|
|
353
|
+
return `\x1b7\x1b[13;${area.startColumn}H\x1b[K\x1b[38;5;244m${status}\x1b[0m\x1b8`;
|
|
282
354
|
}
|
|
283
|
-
/**
|
|
284
|
-
|
|
355
|
+
/**
|
|
356
|
+
* Write one streamed fragment into the answer area without repainting the chat
|
|
357
|
+
* frame. Wrapped lines return to `startColumn` so the answer keeps the same
|
|
358
|
+
* columns as the composer card instead of stretching across the terminal.
|
|
359
|
+
*/
|
|
360
|
+
export function renderChatAnswerDelta(delta, start, width, startColumn = 1) {
|
|
285
361
|
let row = start.row;
|
|
286
362
|
let column = start.column;
|
|
363
|
+
let writeColumn = start.column;
|
|
364
|
+
let sequence = '';
|
|
365
|
+
let line = '';
|
|
366
|
+
const flush = () => {
|
|
367
|
+
if (line.length === 0)
|
|
368
|
+
return;
|
|
369
|
+
sequence += `\x1b[${row};${writeColumn}H\x1b[38;5;253m${line}\x1b[0m`;
|
|
370
|
+
line = '';
|
|
371
|
+
};
|
|
287
372
|
for (const character of delta) {
|
|
288
373
|
if (character === '\n') {
|
|
374
|
+
flush();
|
|
289
375
|
row++;
|
|
290
|
-
column =
|
|
376
|
+
column = startColumn;
|
|
377
|
+
writeColumn = startColumn;
|
|
291
378
|
continue;
|
|
292
379
|
}
|
|
380
|
+
line += character;
|
|
293
381
|
column++;
|
|
294
382
|
if (column > width) {
|
|
383
|
+
flush();
|
|
295
384
|
row++;
|
|
296
|
-
column =
|
|
385
|
+
column = startColumn;
|
|
386
|
+
writeColumn = startColumn;
|
|
297
387
|
}
|
|
298
388
|
}
|
|
299
|
-
|
|
389
|
+
flush();
|
|
390
|
+
return { sequence, row, column };
|
|
300
391
|
}
|
|
301
392
|
export function renderFullWelcomeScreen(options, height) {
|
|
302
393
|
if (options.chatQuestion !== undefined) {
|
|
303
394
|
return renderChatScreen(options, height);
|
|
304
395
|
}
|
|
305
396
|
return [
|
|
306
|
-
renderModeradoHeader(),
|
|
397
|
+
renderModeradoHeader(options.width),
|
|
307
398
|
'',
|
|
308
399
|
renderWelcomeCard(options),
|
|
309
400
|
].join('\n') + '\n';
|
|
@@ -368,6 +459,7 @@ export function renderHelpPopupBox(version, workspace, width) {
|
|
|
368
459
|
'\x1b[1mCtrl+C\x1b[0m Cancel active inference or exit session',
|
|
369
460
|
'\x1b[1mEsc\x1b[0m Stop the active task',
|
|
370
461
|
'\x1b[1mLeft/Right\x1b[0m Move the caret inside the bottom input line',
|
|
462
|
+
' \x1b[1mUp/Down\x1b[0m Browse slash commands after "/", else recall history',
|
|
371
463
|
'\x1b[1mMouse click\x1b[0m Place the caret on the input line',
|
|
372
464
|
'',
|
|
373
465
|
`\x1b[38;5;245mWorkspace:\x1b[0m \x1b[38;5;253m${shortWs}\x1b[0m`,
|
|
@@ -485,9 +577,12 @@ export async function promptInteractiveTurn(options) {
|
|
|
485
577
|
mode: currentMode,
|
|
486
578
|
autoApprove: currentAutoApprove,
|
|
487
579
|
input,
|
|
580
|
+
inputCaret: caret,
|
|
581
|
+
commandSelection,
|
|
488
582
|
chatQuestion: options.chatQuestion,
|
|
489
583
|
chatAnswer: options.chatAnswer,
|
|
490
584
|
chatThoughtTime: options.chatThoughtTime,
|
|
585
|
+
chatTaskDone: options.chatTaskDone,
|
|
491
586
|
outputTokenRate: options.outputTokenRate,
|
|
492
587
|
tokenUsage: options.tokenUsage,
|
|
493
588
|
queuedCommands: options.queuedCommands,
|
|
@@ -527,7 +622,8 @@ export async function promptInteractiveTurn(options) {
|
|
|
527
622
|
*/
|
|
528
623
|
const positionCursorOnInput = () => {
|
|
529
624
|
const { row, column } = getComposerAnchor();
|
|
530
|
-
|
|
625
|
+
const { caretColumn } = composerInputWindow(input, caret, getWelcomeCardWidth());
|
|
626
|
+
stdout.write(`\x1b[1 q\x1b[?25h\x1b[${row};${column + caretColumn}H`);
|
|
531
627
|
};
|
|
532
628
|
/** Full-screen redraw: clear everything, repaint welcome TUI, reposition cursor. */
|
|
533
629
|
const redrawFull = () => {
|
|
@@ -1014,11 +1110,12 @@ export function formatTokenUsage(event) {
|
|
|
1014
1110
|
}
|
|
1015
1111
|
/** Update only the chat status row, preserving the answer/composer cursor. */
|
|
1016
1112
|
export function renderChatUsageUpdate(event, width = process.stdout.columns || 80, budgetStatus, usageDetails, terminalHeight = process.stdout.rows || 24, mode) {
|
|
1113
|
+
const area = getChatAnswerArea(width);
|
|
1017
1114
|
const usageText = formatTokenUsage(event);
|
|
1018
1115
|
const suffix = `${usageDetails ? ` | ${usageDetails}` : ''}${budgetStatus ? ` | ${budgetStatus}` : ''}`;
|
|
1019
1116
|
const modeLabel = mode === 'Plan' ? '\x1b[1;38;5;75m[Plan]\x1b[0m / Execute (Tab)' : 'Plan / \x1b[1;38;5;75m[Execute]\x1b[0m (Tab)';
|
|
1020
1117
|
const modeText = mode === 'Plan' ? '[Plan] / Execute (Tab)' : 'Plan / [Execute] (Tab)';
|
|
1021
|
-
const rowWidth =
|
|
1118
|
+
const rowWidth = area.cardWidth;
|
|
1022
1119
|
const textLimit = Math.max(0, rowWidth - (mode ? modeText.length + 1 : 0));
|
|
1023
1120
|
const usageLimit = Math.max(0, textLimit - suffix.length);
|
|
1024
1121
|
const clippedUsage = mode && usageText.length > usageLimit
|
|
@@ -1026,14 +1123,15 @@ export function renderChatUsageUpdate(event, width = process.stdout.columns || 8
|
|
|
1026
1123
|
: usageText;
|
|
1027
1124
|
const text = `${clippedUsage}${suffix}`.slice(0, textLimit);
|
|
1028
1125
|
const row = Math.max(1, terminalHeight - 2);
|
|
1029
|
-
return `\x1b7\x1b[${row}
|
|
1126
|
+
return `\x1b7\x1b[${row};${area.startColumn}H\x1b[K\x1b[38;5;244m${text}\x1b[0m${mode ? `${' '.repeat(Math.max(1, rowWidth - text.length - modeText.length))}${modeLabel}` : ''}\x1b8`;
|
|
1030
1127
|
}
|
|
1031
1128
|
/** Show trusted, schema-validated Gateway route changes without provider supplied prose. */
|
|
1032
1129
|
export function renderGatewayFallbackUpdate(event, width = process.stdout.columns || 80) {
|
|
1130
|
+
const area = getChatAnswerArea(width);
|
|
1033
1131
|
const destination = event.toProvider ? `${event.toProvider}/${event.toModel}` : event.toModel;
|
|
1034
1132
|
const reason = event.reason === 'rate_limited_or_unavailable' ? 'after an upstream route was rate limited or unavailable' : 'after a fallback';
|
|
1035
|
-
const text = `Gateway route changed to ${destination} ${reason}`.slice(0,
|
|
1133
|
+
const text = `Gateway route changed to ${destination} ${reason}`.slice(0, area.cardWidth);
|
|
1036
1134
|
const row = renderModeradoHeader().split('\n').length + 3;
|
|
1037
|
-
return `\x1b7\x1b[${row}
|
|
1135
|
+
return `\x1b7\x1b[${row};${area.startColumn}H\x1b[K\x1b[38;5;244m${text}\x1b[0m\x1b8`;
|
|
1038
1136
|
}
|
|
1039
1137
|
//# sourceMappingURL=welcome.js.map
|