@thegitai/cli 1.0.0-preview.44 → 1.0.0-preview.45
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 +8 -2
- package/dist/src/help-text.js +12 -0
- package/dist/src/ui/tui/build-frame.js +8 -4
- package/dist/src/ui/tui/user-input.js +38 -13
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -78,12 +78,18 @@ The agent can pause its current turn to ask up to four related questions in one
|
|
|
78
78
|
form. Use **↑ / ↓**, the displayed option number, or **Enter** to choose, and
|
|
79
79
|
**← / →** to move between questions. **Something else / add details** is the
|
|
80
80
|
numbered final option; focus it and type, paste, or press **Enter** to add a
|
|
81
|
-
single-line note
|
|
82
|
-
|
|
81
|
+
single-line note; **Enter** commits it and moves on the way any other choice
|
|
82
|
+
does — to the next question, or to **Submit answers** on the last one — without
|
|
83
|
+
submitting the form. On single-select questions it is mutually exclusive with
|
|
84
|
+
the listed choices, and **↑ / ↓** leaves its editor when the note is empty.
|
|
83
85
|
Multi-select questions toggle choices. The last question has an explicit
|
|
84
86
|
**Submit answers** row. **Esc** closes an open note first and otherwise cancels
|
|
85
87
|
the form; **Ctrl+C** cancels the whole turn.
|
|
86
88
|
|
|
89
|
+
Only the option you are on shows its description, so the whole form — every
|
|
90
|
+
option, the note row, **Submit answers**, and the key hints — stays on screen
|
|
91
|
+
without scrolling. Move between options to read the others.
|
|
92
|
+
|
|
87
93
|
Answers return to the same turn, and completed question/answer records remain
|
|
88
94
|
readable when the session is resumed. Default, Bypass all permissions, and Plan
|
|
89
95
|
modes all support the form; Bypass all permissions does not choose answers for
|
package/dist/src/help-text.js
CHANGED
|
@@ -103,6 +103,18 @@ const HELP_MARKDOWN = [
|
|
|
103
103
|
? ['- On Mac laptops without dedicated keys, **Home/End** are `Fn+←` / `Fn+→`.']
|
|
104
104
|
: []),
|
|
105
105
|
'',
|
|
106
|
+
'## Questions',
|
|
107
|
+
'',
|
|
108
|
+
'- The agent can pause a turn to ask up to four questions in one form.',
|
|
109
|
+
' **↑/↓** moves, the option number or **Enter** chooses, **←/→** moves',
|
|
110
|
+
' between questions, and the last question has a **Submit answers** row.',
|
|
111
|
+
'- Only the option you are on shows its description, so the whole form fits',
|
|
112
|
+
' on screen. Move to an option to read what it means.',
|
|
113
|
+
'- **Something else / add details** is the numbered final option: focus it',
|
|
114
|
+
' and type. **Enter** commits the note and moves to the next question, or to',
|
|
115
|
+
' Submit on the last one — it never submits the form for you.',
|
|
116
|
+
'- **Esc** closes an open note first, and otherwise cancels the form.',
|
|
117
|
+
'',
|
|
106
118
|
'## Chat commands',
|
|
107
119
|
'',
|
|
108
120
|
'- `/help` — show this help',
|
|
@@ -44,6 +44,7 @@ export function footerNotificationHint(status) {
|
|
|
44
44
|
}
|
|
45
45
|
const FOOTER_CYCLE_HINT = ' (shift+tab to cycle)';
|
|
46
46
|
const OVERLAY_PANEL_MAX_WIDTH = 86;
|
|
47
|
+
const USER_INPUT_PANEL_MAX_WIDTH = 120;
|
|
47
48
|
const OVERLAY_PANEL_MARGIN_LINES = 2;
|
|
48
49
|
const OVERLAY_PANEL_MARGIN_MIN_ROWS = 30;
|
|
49
50
|
const OVERLAY_BORDER_COLOR = 'yellow';
|
|
@@ -817,8 +818,8 @@ function overlayPanelContentBudget(height) {
|
|
|
817
818
|
const margins = overlayPanelMarginLineCount(height) * 2;
|
|
818
819
|
return Math.max(1, Math.floor(height) - margins - 2);
|
|
819
820
|
}
|
|
820
|
-
function buildOverlayPanel(rows, width, color, height = Number.POSITIVE_INFINITY) {
|
|
821
|
-
const panelWidth = Math.max(24, Math.min(width,
|
|
821
|
+
function buildOverlayPanel(rows, width, color, height = Number.POSITIVE_INFINITY, maxWidth = OVERLAY_PANEL_MAX_WIDTH) {
|
|
822
|
+
const panelWidth = Math.max(24, Math.min(width, maxWidth));
|
|
822
823
|
const innerWidth = Math.max(1, panelWidth - 4);
|
|
823
824
|
const margin = Array.from({
|
|
824
825
|
length: overlayPanelMarginLineCount(height),
|
|
@@ -1104,6 +1105,9 @@ export function buildWorkingClockLine(state, elapsedSeconds) {
|
|
|
1104
1105
|
export function approvalPanelInnerWidth(width) {
|
|
1105
1106
|
return Math.max(1, Math.max(24, Math.min(width, OVERLAY_PANEL_MAX_WIDTH)) - 4);
|
|
1106
1107
|
}
|
|
1108
|
+
export function userInputPanelInnerWidth(width) {
|
|
1109
|
+
return Math.max(1, Math.max(24, Math.min(width, USER_INPUT_PANEL_MAX_WIDTH)) - 4);
|
|
1110
|
+
}
|
|
1107
1111
|
export function approvalPaddingEnabled(height) {
|
|
1108
1112
|
return height >= APPROVAL_PADDING_MIN_ROWS;
|
|
1109
1113
|
}
|
|
@@ -1212,7 +1216,7 @@ function buildOverlayLines(state, width, height, nowMs) {
|
|
|
1212
1216
|
if (height < 3) {
|
|
1213
1217
|
return [];
|
|
1214
1218
|
}
|
|
1215
|
-
return buildOverlayPanel(buildUserInputOverlayLines(state.userInputPrompt,
|
|
1219
|
+
return buildOverlayPanel(buildUserInputOverlayLines(state.userInputPrompt, userInputPanelInnerWidth(width), overlayPanelContentBudget(height)), width, USER_INPUT_BORDER_COLOR, height, USER_INPUT_PANEL_MAX_WIDTH);
|
|
1216
1220
|
}
|
|
1217
1221
|
if (state.approvalPrompt) {
|
|
1218
1222
|
const prompt = state.approvalPrompt;
|
|
@@ -1337,7 +1341,7 @@ export function userInputViewportForFrame(state, cols, rows, spinnerFrame, elaps
|
|
|
1337
1341
|
const liveRows = buildLiveLines(state, contentWidth, spinnerFrame, elapsedSeconds, nowMs).length;
|
|
1338
1342
|
const overlayHeight = Math.max(0, rows - liveRows - composerFooterLines(state, contentWidth).length);
|
|
1339
1343
|
return {
|
|
1340
|
-
width:
|
|
1344
|
+
width: userInputPanelInnerWidth(contentWidth),
|
|
1341
1345
|
maxRows: overlayPanelContentBudget(overlayHeight),
|
|
1342
1346
|
};
|
|
1343
1347
|
}
|
|
@@ -139,9 +139,19 @@ function editOpenNote(state, event) {
|
|
|
139
139
|
const question = currentQuestion(state);
|
|
140
140
|
const current = state.customText[question.id] ?? '';
|
|
141
141
|
const cursor = Math.max(0, Math.min(state.noteCursor, current.length));
|
|
142
|
-
if (event.escape
|
|
142
|
+
if (event.escape) {
|
|
143
143
|
return { ...state, noteOpen: false };
|
|
144
144
|
}
|
|
145
|
+
if (event.returnKey) {
|
|
146
|
+
const closed = { ...state, noteOpen: false };
|
|
147
|
+
if (question.multiSelect || !current.trim()) {
|
|
148
|
+
return closed;
|
|
149
|
+
}
|
|
150
|
+
const index = questionIndex(closed);
|
|
151
|
+
return index < closed.questions.length - 1
|
|
152
|
+
? setQuestion(closed, index + 1)
|
|
153
|
+
: setCursor(closed, question, SUBMIT_CURSOR);
|
|
154
|
+
}
|
|
145
155
|
if (event.tab)
|
|
146
156
|
return state;
|
|
147
157
|
if ((event.upArrow || event.downArrow) && !current.trim()) {
|
|
@@ -433,8 +443,10 @@ function buildUserInputContent(state, width) {
|
|
|
433
443
|
}), ...(recommendation
|
|
434
444
|
? [span(recommendation, { color: 'green' })]
|
|
435
445
|
: [])));
|
|
436
|
-
|
|
437
|
-
|
|
446
|
+
if (focused) {
|
|
447
|
+
for (const description of wrapText(option.description, Math.max(8, width - 5))) {
|
|
448
|
+
lines.push(plainLine(` ${description}`, { color: 'gray' }));
|
|
449
|
+
}
|
|
438
450
|
}
|
|
439
451
|
if (state.contentScrollAnchor === option.id) {
|
|
440
452
|
anchorRange = { start: blockStart, end: lines.length - 1 };
|
|
@@ -490,23 +502,38 @@ function buildUserInputContent(state, width) {
|
|
|
490
502
|
if (state.validationMessage) {
|
|
491
503
|
lines.push(plainLine(state.validationMessage, { color: 'yellow' }));
|
|
492
504
|
}
|
|
493
|
-
|
|
494
|
-
? 'Type a single-line note • ↑/↓ moves when empty • Enter saves • Esc closes
|
|
505
|
+
const footer = plainLine(state.noteOpen
|
|
506
|
+
? 'Type a single-line note • ↑/↓ moves when empty • Enter saves • Esc closes'
|
|
495
507
|
: question.multiSelect
|
|
496
|
-
? `↑/↓ move • 1–${otherNumber} choose • Enter toggles/edits • ←/→ questions •
|
|
497
|
-
: `↑/↓ move • 1–${otherNumber} choose • Enter selects/edits • ←/→ questions •
|
|
508
|
+
? `↑/↓ move • 1–${otherNumber} choose • Enter toggles/edits • ←/→ questions • Esc cancels`
|
|
509
|
+
: `↑/↓ move • 1–${otherNumber} choose • Enter selects/edits • ←/→ questions • Esc cancels`, { color: 'gray' });
|
|
498
510
|
return {
|
|
499
511
|
anchorRange,
|
|
512
|
+
footer: clipLineToWidth(footer, width),
|
|
500
513
|
lines: lines.map((row) => clipLineToWidth(row, width)),
|
|
501
514
|
};
|
|
502
515
|
}
|
|
503
516
|
function buildUserInputWindow(state, width, maxRows) {
|
|
504
517
|
const content = buildUserInputContent(state, width);
|
|
505
|
-
if (!Number.isFinite(maxRows)
|
|
506
|
-
return {
|
|
518
|
+
if (!Number.isFinite(maxRows)) {
|
|
519
|
+
return {
|
|
520
|
+
lines: [...content.lines, content.footer],
|
|
521
|
+
maxOffset: 0,
|
|
522
|
+
offset: 0,
|
|
523
|
+
};
|
|
507
524
|
}
|
|
508
525
|
const rowBudget = Math.max(1, Math.floor(maxRows));
|
|
509
|
-
|
|
526
|
+
if (rowBudget === 1) {
|
|
527
|
+
return { lines: [content.footer], maxOffset: 0, offset: 0 };
|
|
528
|
+
}
|
|
529
|
+
if (content.lines.length <= rowBudget - 1) {
|
|
530
|
+
return {
|
|
531
|
+
lines: [...content.lines, content.footer],
|
|
532
|
+
maxOffset: 0,
|
|
533
|
+
offset: 0,
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
const visibleRowBudget = Math.max(1, rowBudget - 2);
|
|
510
537
|
const maxOffset = Math.max(0, content.lines.length - visibleRowBudget);
|
|
511
538
|
let offset = Math.max(0, Math.min(state.contentScrollOffset, maxOffset));
|
|
512
539
|
const range = content.anchorRange;
|
|
@@ -527,13 +554,11 @@ function buildUserInputWindow(state, width, maxRows) {
|
|
|
527
554
|
offset = Math.max(0, Math.min(offset, maxOffset));
|
|
528
555
|
}
|
|
529
556
|
const visible = content.lines.slice(offset, offset + visibleRowBudget);
|
|
530
|
-
if (rowBudget === 1) {
|
|
531
|
-
return { lines: visible, maxOffset, offset };
|
|
532
|
-
}
|
|
533
557
|
return {
|
|
534
558
|
lines: [
|
|
535
559
|
...visible,
|
|
536
560
|
plainLine(fitText(`Rows ${offset + 1}–${offset + visible.length} of ${content.lines.length} · PgUp/PgDn scroll`, width), { color: 'gray' }),
|
|
561
|
+
content.footer,
|
|
537
562
|
],
|
|
538
563
|
maxOffset,
|
|
539
564
|
offset,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thegitai/cli",
|
|
3
|
-
"version": "1.0.0-preview.
|
|
3
|
+
"version": "1.0.0-preview.45",
|
|
4
4
|
"description": "TheGitAI is an agentic AI coding tool for your terminal. It reads and searches your repository, writes and edits files, runs your tests, and verifies the change before handing it back.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agentic-ai",
|
|
@@ -44,11 +44,11 @@
|
|
|
44
44
|
"@lydell/node-pty-linux-x64": "1.1.0",
|
|
45
45
|
"@lydell/node-pty-win32-arm64": "1.1.0",
|
|
46
46
|
"@lydell/node-pty-win32-x64": "1.1.0",
|
|
47
|
-
"@thegitai/tui-darwin-arm64": "1.0.0-preview.
|
|
48
|
-
"@thegitai/tui-darwin-x64": "1.0.0-preview.
|
|
49
|
-
"@thegitai/tui-linux-arm64": "1.0.0-preview.
|
|
50
|
-
"@thegitai/tui-linux-x64": "1.0.0-preview.
|
|
51
|
-
"@thegitai/tui-win32-x64": "1.0.0-preview.
|
|
47
|
+
"@thegitai/tui-darwin-arm64": "1.0.0-preview.45",
|
|
48
|
+
"@thegitai/tui-darwin-x64": "1.0.0-preview.45",
|
|
49
|
+
"@thegitai/tui-linux-arm64": "1.0.0-preview.45",
|
|
50
|
+
"@thegitai/tui-linux-x64": "1.0.0-preview.45",
|
|
51
|
+
"@thegitai/tui-win32-x64": "1.0.0-preview.45",
|
|
52
52
|
"@vscode/ripgrep": "1.18.0"
|
|
53
53
|
},
|
|
54
54
|
"repository": {
|