@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.
Files changed (76) hide show
  1. package/README.md +93 -4
  2. package/dist/bin/ai.js +142 -112
  3. package/dist/bin/browser-host.js +265 -0
  4. package/dist/src/agent-mode.js +32 -7
  5. package/dist/src/api/auth.js +10 -4
  6. package/dist/src/api/browser-login.js +149 -37
  7. package/dist/src/api/chat.js +680 -166
  8. package/dist/src/api/contracts.js +55 -1
  9. package/dist/src/api/default-host.js +1 -0
  10. package/dist/src/api/http.js +151 -7
  11. package/dist/src/api/models.js +29 -10
  12. package/dist/src/api/startup-handshake.js +36 -0
  13. package/dist/src/api/turn-recovery.js +189 -0
  14. package/dist/src/background-jobs.js +4 -2
  15. package/dist/src/browser/bridge.js +262 -0
  16. package/dist/src/browser/framing.js +42 -0
  17. package/dist/src/browser/native-host.js +219 -0
  18. package/dist/src/browser/protocol.js +46 -0
  19. package/dist/src/browser/session-bridge.js +130 -0
  20. package/dist/src/cli-args.js +19 -5
  21. package/dist/src/client-environment.js +2 -0
  22. package/dist/src/core/clipboard.js +7 -13
  23. package/dist/src/core/image-limits.js +56 -0
  24. package/dist/src/core/image-path-extractor.js +70 -3
  25. package/dist/src/core/session-image-store.js +246 -0
  26. package/dist/src/edit-journal.js +33 -2
  27. package/dist/src/executor.js +25 -3
  28. package/dist/src/help-text.js +112 -21
  29. package/dist/src/patcher.js +43 -4
  30. package/dist/src/permissions.js +288 -0
  31. package/dist/src/preferences.js +39 -0
  32. package/dist/src/quota-notice.js +35 -0
  33. package/dist/src/session-safety.js +0 -12
  34. package/dist/src/session-store.js +121 -20
  35. package/dist/src/session.js +19 -4
  36. package/dist/src/signin.js +58 -0
  37. package/dist/src/tool-executor.js +13 -46
  38. package/dist/src/tools/browser.js +641 -0
  39. package/dist/src/tools/delete-file.js +20 -4
  40. package/dist/src/tools/index.js +32 -10
  41. package/dist/src/tools/patch-file.js +12 -26
  42. package/dist/src/tools/read-file.js +5 -0
  43. package/dist/src/tools/read-image-file.js +85 -0
  44. package/dist/src/tools/replace-document-text.js +28 -18
  45. package/dist/src/tools/restore-checkpoint.js +0 -1
  46. package/dist/src/tools/run-command.js +14 -71
  47. package/dist/src/tools/run-node-script.js +12 -81
  48. package/dist/src/tools/save-generated-image.js +120 -0
  49. package/dist/src/tools/str-replace.js +12 -26
  50. package/dist/src/tools/undo-edit.js +1 -6
  51. package/dist/src/tools/write-file.js +67 -11
  52. package/dist/src/ui/prompt-history-store.js +1 -1
  53. package/dist/src/ui/repl.js +949 -279
  54. package/dist/src/ui/slash-commands.js +121 -0
  55. package/dist/src/ui/tui/attention.js +25 -0
  56. package/dist/src/ui/tui/bridge.js +38 -5
  57. package/dist/src/ui/tui/build-frame.js +686 -223
  58. package/dist/src/ui/tui/composer-layout.js +76 -0
  59. package/dist/src/ui/tui/desktop-notification.js +118 -0
  60. package/dist/src/ui/tui/markdown-render.js +11 -2
  61. package/dist/src/ui/tui/shell-input.js +256 -73
  62. package/dist/src/ui/tui/shortcuts.js +61 -0
  63. package/dist/src/ui/tui/terminal-theme.js +28 -0
  64. package/dist/src/ui/tui/user-input.js +593 -0
  65. package/dist/src/update-check.js +205 -0
  66. package/dist/src/usage.js +5 -2
  67. package/dist/src/utils.js +13 -0
  68. package/dist/src/version.js +52 -2
  69. package/package.json +22 -9
  70. package/dist/src/project-index.js +0 -233
  71. package/dist/src/tools/code-intel.js +0 -472
  72. package/dist/src/tools/find-symbol.js +0 -70
  73. package/dist/src/tools/hover-symbol.js +0 -95
  74. package/dist/src/tools/list-symbols.js +0 -55
  75. package/dist/src/tools/search-code.js +0 -37
  76. 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;