@thegitai/cli 1.0.0-preview.5 → 1.0.0-preview.51
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 +93 -4
- package/dist/bin/ai.js +142 -112
- package/dist/bin/browser-host.js +265 -0
- package/dist/src/agent-mode.js +32 -7
- package/dist/src/api/auth.js +10 -4
- package/dist/src/api/browser-login.js +149 -37
- package/dist/src/api/chat.js +680 -166
- package/dist/src/api/contracts.js +55 -1
- package/dist/src/api/default-host.js +1 -0
- package/dist/src/api/http.js +151 -7
- package/dist/src/api/models.js +29 -10
- package/dist/src/api/startup-handshake.js +36 -0
- package/dist/src/api/turn-recovery.js +189 -0
- package/dist/src/background-jobs.js +4 -2
- package/dist/src/browser/bridge.js +262 -0
- package/dist/src/browser/framing.js +42 -0
- package/dist/src/browser/native-host.js +219 -0
- package/dist/src/browser/protocol.js +46 -0
- package/dist/src/browser/session-bridge.js +130 -0
- package/dist/src/cli-args.js +19 -5
- package/dist/src/client-environment.js +2 -0
- package/dist/src/core/clipboard.js +7 -13
- package/dist/src/core/image-limits.js +56 -0
- package/dist/src/core/image-path-extractor.js +70 -3
- package/dist/src/core/session-image-store.js +246 -0
- package/dist/src/edit-journal.js +33 -2
- package/dist/src/executor.js +25 -3
- package/dist/src/help-text.js +112 -21
- package/dist/src/patcher.js +43 -4
- package/dist/src/permissions.js +288 -0
- package/dist/src/preferences.js +39 -0
- package/dist/src/quota-notice.js +35 -0
- package/dist/src/session-safety.js +0 -12
- package/dist/src/session-store.js +121 -20
- package/dist/src/session.js +19 -4
- package/dist/src/signin.js +58 -0
- package/dist/src/tool-executor.js +13 -46
- package/dist/src/tools/browser.js +641 -0
- package/dist/src/tools/delete-file.js +20 -4
- package/dist/src/tools/index.js +32 -10
- package/dist/src/tools/patch-file.js +12 -26
- package/dist/src/tools/read-file.js +5 -0
- package/dist/src/tools/read-image-file.js +85 -0
- package/dist/src/tools/replace-document-text.js +28 -18
- package/dist/src/tools/restore-checkpoint.js +0 -1
- package/dist/src/tools/run-command.js +14 -71
- package/dist/src/tools/run-node-script.js +12 -81
- package/dist/src/tools/save-generated-image.js +120 -0
- package/dist/src/tools/str-replace.js +12 -26
- package/dist/src/tools/undo-edit.js +1 -6
- package/dist/src/tools/write-file.js +67 -11
- package/dist/src/ui/prompt-history-store.js +1 -1
- package/dist/src/ui/repl.js +949 -279
- package/dist/src/ui/slash-commands.js +121 -0
- package/dist/src/ui/tui/attention.js +25 -0
- package/dist/src/ui/tui/bridge.js +38 -5
- package/dist/src/ui/tui/build-frame.js +686 -223
- package/dist/src/ui/tui/composer-layout.js +76 -0
- package/dist/src/ui/tui/desktop-notification.js +118 -0
- package/dist/src/ui/tui/markdown-render.js +11 -2
- package/dist/src/ui/tui/shell-input.js +256 -73
- package/dist/src/ui/tui/shortcuts.js +61 -0
- package/dist/src/ui/tui/terminal-theme.js +28 -0
- package/dist/src/ui/tui/user-input.js +593 -0
- package/dist/src/update-check.js +205 -0
- package/dist/src/usage.js +5 -2
- package/dist/src/utils.js +13 -0
- package/dist/src/version.js +52 -2
- package/package.json +22 -9
- package/dist/src/project-index.js +0 -233
- package/dist/src/tools/code-intel.js +0 -472
- package/dist/src/tools/find-symbol.js +0 -70
- package/dist/src/tools/hover-symbol.js +0 -95
- package/dist/src/tools/list-symbols.js +0 -55
- package/dist/src/tools/search-code.js +0 -37
- package/dist/src/tools/signature-help.js +0 -118
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export const COMPOSER_PROMPT_LABEL_IDLE = '❯ ';
|
|
2
|
+
export const COMPOSER_PROMPT_LABEL_BUSY = 'queue> ';
|
|
3
|
+
export function composerPromptLabel(state) {
|
|
4
|
+
return state.busy ? COMPOSER_PROMPT_LABEL_BUSY : COMPOSER_PROMPT_LABEL_IDLE;
|
|
5
|
+
}
|
|
6
|
+
export function frameContentWidth(cols) {
|
|
7
|
+
return Math.max(20, Math.floor(cols * 0.95) - 2);
|
|
8
|
+
}
|
|
9
|
+
export function composerInputWidth(cols, state) {
|
|
10
|
+
return Math.max(1, frameContentWidth(cols) - composerPromptLabel(state).length);
|
|
11
|
+
}
|
|
12
|
+
function buildComposerLayout(input, cursor, width) {
|
|
13
|
+
const safeWidth = Math.max(1, width);
|
|
14
|
+
const normalizedCursor = Math.min(Math.max(cursor, 0), input.length);
|
|
15
|
+
const rows = [{ cursorOffsets: [0], text: '' }];
|
|
16
|
+
let cursorRow = 0;
|
|
17
|
+
let cursorCol = 0;
|
|
18
|
+
let capturedCursor = false;
|
|
19
|
+
const currentRow = () => rows[rows.length - 1];
|
|
20
|
+
const addRow = (offset) => {
|
|
21
|
+
rows.push({ cursorOffsets: [offset], text: '' });
|
|
22
|
+
};
|
|
23
|
+
const captureCursor = () => {
|
|
24
|
+
if (capturedCursor)
|
|
25
|
+
return;
|
|
26
|
+
if (currentRow().text.length >= safeWidth) {
|
|
27
|
+
addRow(normalizedCursor);
|
|
28
|
+
}
|
|
29
|
+
cursorRow = rows.length - 1;
|
|
30
|
+
cursorCol = currentRow().text.length;
|
|
31
|
+
capturedCursor = true;
|
|
32
|
+
};
|
|
33
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
34
|
+
const char = input[index] ?? '';
|
|
35
|
+
if (char !== '\n' &&
|
|
36
|
+
char !== '\r' &&
|
|
37
|
+
currentRow().text.length >= safeWidth) {
|
|
38
|
+
addRow(index);
|
|
39
|
+
}
|
|
40
|
+
if (index === normalizedCursor) {
|
|
41
|
+
captureCursor();
|
|
42
|
+
}
|
|
43
|
+
if (char === '\r') {
|
|
44
|
+
currentRow().cursorOffsets[currentRow().text.length] = index + 1;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (char === '\n') {
|
|
48
|
+
currentRow().cursorOffsets[currentRow().text.length] =
|
|
49
|
+
input[index - 1] === '\r' ? index - 1 : index;
|
|
50
|
+
addRow(index + 1);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
currentRow().text += char;
|
|
54
|
+
currentRow().cursorOffsets.push(index + 1);
|
|
55
|
+
}
|
|
56
|
+
if (!capturedCursor) {
|
|
57
|
+
captureCursor();
|
|
58
|
+
}
|
|
59
|
+
return { cursorCol, cursorRow, rows };
|
|
60
|
+
}
|
|
61
|
+
export function splitComposerInput(input, cursor, width) {
|
|
62
|
+
const layout = buildComposerLayout(input, cursor, width);
|
|
63
|
+
return {
|
|
64
|
+
cursorCol: layout.cursorCol,
|
|
65
|
+
cursorRow: layout.cursorRow,
|
|
66
|
+
rows: layout.rows.map((row) => row.text),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export function moveComposerCursorVertically(input, cursor, width, direction) {
|
|
70
|
+
const layout = buildComposerLayout(input, cursor, width);
|
|
71
|
+
const targetRow = layout.rows[layout.cursorRow + direction];
|
|
72
|
+
if (!targetRow)
|
|
73
|
+
return null;
|
|
74
|
+
const targetCol = Math.min(layout.cursorCol, targetRow.text.length);
|
|
75
|
+
return targetRow.cursorOffsets[targetCol] ?? null;
|
|
76
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
function run(command, args, { capture = false } = {}) {
|
|
3
|
+
return new Promise((resolve) => {
|
|
4
|
+
let child;
|
|
5
|
+
try {
|
|
6
|
+
child = spawn(command, args, {
|
|
7
|
+
stdio: ['ignore', capture ? 'pipe' : 'ignore', 'ignore'],
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
resolve('');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
let out = '';
|
|
15
|
+
child.stdout?.on('data', (chunk) => {
|
|
16
|
+
out += chunk.toString('utf8');
|
|
17
|
+
});
|
|
18
|
+
child.on('error', () => resolve(''));
|
|
19
|
+
child.on('close', () => resolve(out.trim()));
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
const linuxBackend = {
|
|
23
|
+
canWithdraw: true,
|
|
24
|
+
async post(request, previous) {
|
|
25
|
+
const args = [
|
|
26
|
+
'--print-id',
|
|
27
|
+
'--app-name=TheGitAI',
|
|
28
|
+
'--icon=utilities-terminal',
|
|
29
|
+
'--urgency=normal',
|
|
30
|
+
];
|
|
31
|
+
if (previous)
|
|
32
|
+
args.push(`--replace-id=${previous}`);
|
|
33
|
+
args.push(request.title, request.body);
|
|
34
|
+
const id = await run('notify-send', args, { capture: true });
|
|
35
|
+
return /^\d+$/.test(id) ? id : null;
|
|
36
|
+
},
|
|
37
|
+
withdraw(handle) {
|
|
38
|
+
if (!handle)
|
|
39
|
+
return;
|
|
40
|
+
void run('gdbus', [
|
|
41
|
+
'call',
|
|
42
|
+
'--session',
|
|
43
|
+
'--dest',
|
|
44
|
+
'org.freedesktop.Notifications',
|
|
45
|
+
'--object-path',
|
|
46
|
+
'/org/freedesktop/Notifications',
|
|
47
|
+
'--method',
|
|
48
|
+
'org.freedesktop.Notifications.CloseNotification',
|
|
49
|
+
handle,
|
|
50
|
+
]);
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
function appleScriptString(value) {
|
|
54
|
+
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
55
|
+
}
|
|
56
|
+
const macBackend = {
|
|
57
|
+
canWithdraw: false,
|
|
58
|
+
async post(request) {
|
|
59
|
+
await run('osascript', [
|
|
60
|
+
'-e',
|
|
61
|
+
`display notification "${appleScriptString(request.body)}" with title "${appleScriptString(request.title)}"`,
|
|
62
|
+
]);
|
|
63
|
+
return null;
|
|
64
|
+
},
|
|
65
|
+
withdraw() {
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
function powerShellString(value) {
|
|
69
|
+
return value.replace(/'/g, "''");
|
|
70
|
+
}
|
|
71
|
+
const WINDOWS_AUMID = 'TheGitAI';
|
|
72
|
+
const WINDOWS_TAG = 'thegitai-attention';
|
|
73
|
+
const WINDOWS_GROUP = 'thegitai';
|
|
74
|
+
const windowsBackend = {
|
|
75
|
+
canWithdraw: true,
|
|
76
|
+
async post(request) {
|
|
77
|
+
const script = [
|
|
78
|
+
'[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType=WindowsRuntime] > $null',
|
|
79
|
+
'[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom, ContentType=WindowsRuntime] > $null',
|
|
80
|
+
'$t = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02)',
|
|
81
|
+
'$n = $t.GetElementsByTagName("text")',
|
|
82
|
+
`$n.Item(0).AppendChild($t.CreateTextNode('${powerShellString(request.title)}')) > $null`,
|
|
83
|
+
`$n.Item(1).AppendChild($t.CreateTextNode('${powerShellString(request.body)}')) > $null`,
|
|
84
|
+
'$toast = [Windows.UI.Notifications.ToastNotification]::new($t)',
|
|
85
|
+
`$toast.Tag = '${WINDOWS_TAG}'`,
|
|
86
|
+
`$toast.Group = '${WINDOWS_GROUP}'`,
|
|
87
|
+
`[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('${WINDOWS_AUMID}').Show($toast)`,
|
|
88
|
+
].join('; ');
|
|
89
|
+
await run('powershell', ['-NoProfile', '-NonInteractive', '-Command', script]);
|
|
90
|
+
return WINDOWS_TAG;
|
|
91
|
+
},
|
|
92
|
+
withdraw(handle) {
|
|
93
|
+
if (!handle)
|
|
94
|
+
return;
|
|
95
|
+
const script = [
|
|
96
|
+
'[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType=WindowsRuntime] > $null',
|
|
97
|
+
`[Windows.UI.Notifications.ToastNotificationManager]::History.Remove('${powerShellString(handle)}', '${WINDOWS_GROUP}', '${WINDOWS_AUMID}')`,
|
|
98
|
+
].join('; ');
|
|
99
|
+
void run('powershell', ['-NoProfile', '-NonInteractive', '-Command', script]);
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
export function createNotificationQueue() {
|
|
103
|
+
let tail = Promise.resolve();
|
|
104
|
+
return {
|
|
105
|
+
idle: () => tail,
|
|
106
|
+
run(step) {
|
|
107
|
+
tail = tail.then(step).catch(() => {
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
export function backendFor(platform = process.platform) {
|
|
113
|
+
if (platform === 'darwin')
|
|
114
|
+
return macBackend;
|
|
115
|
+
if (platform === 'win32')
|
|
116
|
+
return windowsBackend;
|
|
117
|
+
return linuxBackend;
|
|
118
|
+
}
|
|
@@ -275,9 +275,9 @@ function wrapInlineToLines(text, width, bodyColor, prefix = '') {
|
|
|
275
275
|
};
|
|
276
276
|
const appendSpan = (part) => {
|
|
277
277
|
let current = rows[rows.length - 1];
|
|
278
|
-
const limit = safeWidth - (rows.length === 1 && indent ? displayWidth(prefix) : 0);
|
|
279
278
|
let remaining = part.text;
|
|
280
279
|
while (remaining.length > 0) {
|
|
280
|
+
const limit = safeWidth - (rows.length === 1 && indent ? displayWidth(prefix) : 0);
|
|
281
281
|
const room = limit - rowWidth;
|
|
282
282
|
if (room <= 0) {
|
|
283
283
|
startRow();
|
|
@@ -291,8 +291,17 @@ function wrapInlineToLines(text, width, bodyColor, prefix = '') {
|
|
|
291
291
|
remaining = '';
|
|
292
292
|
break;
|
|
293
293
|
}
|
|
294
|
+
if (rowWidth > 0) {
|
|
295
|
+
if (/^\s+$/.test(remaining)) {
|
|
296
|
+
remaining = '';
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
startRow();
|
|
300
|
+
current = rows[rows.length - 1];
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
294
303
|
const head = sliceToWidth(remaining, room);
|
|
295
|
-
if (displayWidth(head) > room && current.length > 0) {
|
|
304
|
+
if (!head || (displayWidth(head) > room && current.length > 0)) {
|
|
296
305
|
startRow();
|
|
297
306
|
current = rows[rows.length - 1];
|
|
298
307
|
continue;
|