@thegitai/cli 1.0.0-preview.42 → 1.0.0-preview.43

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.
@@ -77,6 +77,11 @@ const HELP_MARKDOWN = [
77
77
  ' back for editing and **Esc**/**Ctrl+C** discards it; both unlock the',
78
78
  ' composer for the next message. **Ctrl+V** pastes a screenshot onto the',
79
79
  ' queued message, and it is delivered into the running turn with the text.',
80
+ '- **Ctrl+G** turns desktop notifications on or off. One is raised when a turn',
81
+ ' ends and when a permission prompt or a question is waiting for you, but',
82
+ ' only while the terminal is in the background — if you are looking at the',
83
+ ' session you are told nothing. Coming back clears it. The choice is',
84
+ ' remembered between sessions.',
80
85
  `- **Paste** into the composer with your terminal's paste shortcut (\`${PASTE_SHORTCUT}\``,
81
86
  ' on this system) or by right-clicking the composer.',
82
87
  '- **Copy** from the transcript by dragging to select; double-click copies a',
@@ -101,6 +106,7 @@ const HELP_MARKDOWN = [
101
106
  ' is working; press it again or Esc to close without touching the turn',
102
107
  '- `/jobs output <id>` — print one job\'s full captured output',
103
108
  '- `/jobs kill <id>` — stop one background job',
109
+ '- `/notify` — turn desktop notifications on or off (same as Ctrl+G)',
104
110
  '- `/new` — start a new conversation; this session remains saved',
105
111
  '- `/logout` — sign out and quit',
106
112
  '- `/exit` — quit the session',
@@ -0,0 +1,39 @@
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { getClientStateDir } from './client-state.js';
4
+ export const DEFAULT_PREFERENCES = {
5
+ notifications: true,
6
+ };
7
+ export function getPreferencesPath(env = process.env) {
8
+ return path.join(getClientStateDir(env), 'prefs.json');
9
+ }
10
+ export function readPreferences(env = process.env) {
11
+ const filePath = getPreferencesPath(env);
12
+ if (!existsSync(filePath))
13
+ return { ...DEFAULT_PREFERENCES };
14
+ try {
15
+ const parsed = JSON.parse(readFileSync(filePath, 'utf8'));
16
+ return {
17
+ notifications: parsed.notifications === false ? false : DEFAULT_PREFERENCES.notifications,
18
+ };
19
+ }
20
+ catch {
21
+ return { ...DEFAULT_PREFERENCES };
22
+ }
23
+ }
24
+ export function writePreferences(preferences, env = process.env) {
25
+ const filePath = getPreferencesPath(env);
26
+ mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });
27
+ const tempPath = `${filePath}.${process.pid}.tmp`;
28
+ try {
29
+ writeFileSync(tempPath, `${JSON.stringify(preferences, null, 2)}\n`, {
30
+ encoding: 'utf8',
31
+ mode: 0o600,
32
+ });
33
+ renameSync(tempPath, filePath);
34
+ }
35
+ catch (error) {
36
+ rmSync(tempPath, { force: true });
37
+ throw error;
38
+ }
39
+ }
@@ -1,6 +1,10 @@
1
+ import { basename } from 'node:path';
1
2
  import { createRatatuiBridge } from './tui/bridge.js';
2
3
  import { bucketActionLabel, } from '../permissions.js';
3
4
  import { AGENT_MODE_LOCKED_STATUS, approvalScrollLimit, buildTuiFrame, formatJobElapsed, formatTodoProgress, pickThinkingFallbackPhrase, renderTranscriptEntryLines, THINKING_FALLBACK_PHRASES, userInputViewportForFrame, } from './tui/build-frame.js';
5
+ import { createAttentionController, INITIAL_TERMINAL_FOCUS, } from './tui/attention.js';
6
+ import { backendFor, createNotificationQueue, } from './tui/desktop-notification.js';
7
+ import { readPreferences, writePreferences } from '../preferences.js';
4
8
  import { createTerminalTitleController } from './tui/terminal-title.js';
5
9
  import { captureTerminalWrites, releaseTerminalWrites, } from './tui/terminal-writes.js';
6
10
  export { getSlashCommandSuggestions } from './tui/build-frame.js';
@@ -135,6 +139,10 @@ export const SLASH_COMMANDS = [
135
139
  command: '/jobs',
136
140
  description: 'Background jobs: pick to view output or kill',
137
141
  },
142
+ {
143
+ command: '/notify',
144
+ description: 'Toggle desktop notifications when a turn ends (Ctrl+G)',
145
+ },
138
146
  {
139
147
  command: '/new',
140
148
  description: 'start a new conversation; this session remains saved',
@@ -1100,6 +1108,8 @@ function createInitialShellState(session, serverModels, debugUi) {
1100
1108
  exiting: false,
1101
1109
  input: '',
1102
1110
  maxToolSteps: session.maxToolSteps,
1111
+ notificationsEnabled: readPreferences(session.env).notifications,
1112
+ terminalFocused: INITIAL_TERMINAL_FOCUS,
1103
1113
  jobsPickerExpandedId: null,
1104
1114
  jobsPickerIndex: 0,
1105
1115
  jobsPickerOpen: false,
@@ -1557,11 +1567,42 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
1557
1567
  busy: state.busy,
1558
1568
  });
1559
1569
  };
1570
+ const notifier = backendFor();
1571
+ let notificationHandle = null;
1572
+ const projectLabel = basename(session.rootDir) || 'TheGitAI';
1573
+ const notifications = createNotificationQueue();
1574
+ const attention = createAttentionController({
1575
+ notify: (kind) => {
1576
+ notifications.run(async () => {
1577
+ notificationHandle = await notifier.post({
1578
+ title: projectLabel,
1579
+ body: kind === 'blocked'
1580
+ ? 'Waiting for your answer'
1581
+ : 'Finished \u2014 your turn',
1582
+ }, notificationHandle);
1583
+ });
1584
+ },
1585
+ withdraw: () => {
1586
+ notifications.run(async () => {
1587
+ notifier.withdraw(notificationHandle);
1588
+ notificationHandle = null;
1589
+ });
1590
+ },
1591
+ });
1592
+ const syncAttention = () => {
1593
+ const state = store.getState();
1594
+ attention.sync({
1595
+ awaitingAnswer: Boolean(state.approvalPrompt || state.sudoPrompt || state.userInputPrompt),
1596
+ busy: state.busy,
1597
+ focused: state.terminalFocused,
1598
+ }, state.notificationsEnabled);
1599
+ };
1560
1600
  const renderCurrentFrame = () => {
1561
1601
  if (!tuiReady)
1562
1602
  return;
1563
1603
  const state = store.getState();
1564
1604
  syncTerminalTitle();
1605
+ syncAttention();
1565
1606
  const elapsedSeconds = busyElapsedSeconds(state, Date.now());
1566
1607
  bridge.render(buildTuiFrame(state, terminalCols, terminalRows, spinnerFrame, elapsedSeconds, Date.now()));
1567
1608
  };
@@ -2107,6 +2148,16 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
2107
2148
  title: 'Model',
2108
2149
  });
2109
2150
  };
2151
+ const toggleNotifications = () => {
2152
+ const enabled = !store.getState().notificationsEnabled;
2153
+ store.update((current) => ({ ...current, notificationsEnabled: enabled }));
2154
+ try {
2155
+ writePreferences({ ...readPreferences(session.env), notifications: enabled }, session.env);
2156
+ }
2157
+ catch {
2158
+ }
2159
+ showTransientStatus(enabled ? 'Notifications on' : 'Notifications off');
2160
+ };
2110
2161
  const openJobsPicker = () => {
2111
2162
  if (store.getState().jobsPickerOpen)
2112
2163
  return;
@@ -2513,8 +2564,19 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
2513
2564
  openJobsPicker();
2514
2565
  return;
2515
2566
  }
2567
+ if (input === '/notify') {
2568
+ store.update((current) => ({
2569
+ ...current,
2570
+ cursor: 0,
2571
+ input: '',
2572
+ pastedChunks: [],
2573
+ }));
2574
+ toggleNotifications();
2575
+ return;
2576
+ }
2516
2577
  appendTurnAwareEntry({
2517
- body: "Slash commands can't be queued while a turn is running. Ctrl+B opens background jobs.",
2578
+ body: "Slash commands can't be queued while a turn is running. " +
2579
+ 'Ctrl+B opens background jobs, Ctrl+G toggles notifications.',
2518
2580
  kind: 'system',
2519
2581
  title: 'Queued',
2520
2582
  });
@@ -2599,6 +2661,10 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
2599
2661
  appendStaticEntries(buildReportTranscriptEntries(opened));
2600
2662
  return;
2601
2663
  }
2664
+ if (input === '/notify') {
2665
+ toggleNotifications();
2666
+ return;
2667
+ }
2602
2668
  if (input === '/jobs' || input.startsWith('/jobs ')) {
2603
2669
  const jobsArgs = input.slice('/jobs'.length).trim();
2604
2670
  if (!jobsArgs) {
@@ -3124,6 +3190,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
3124
3190
  onSelectionCopy: handleAppSelectionCopy,
3125
3191
  onSelectModel: handleInlineModelSelection,
3126
3192
  onOpenJobsPicker: openJobsPicker,
3193
+ onToggleNotifications: toggleNotifications,
3127
3194
  onJobsPickerOutput: handleJobsPickerOutput,
3128
3195
  onJobsPickerKill: handleJobsPickerKill,
3129
3196
  onSudoPasswordInput: handleSudoPasswordInput,
@@ -3167,6 +3234,13 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
3167
3234
  return;
3168
3235
  }
3169
3236
  if (message.op === 'event') {
3237
+ if (message.kind === 'focus') {
3238
+ store.update((current) => current.terminalFocused === message.focused
3239
+ ? current
3240
+ : { ...current, terminalFocused: message.focused });
3241
+ renderCurrentFrame();
3242
+ return;
3243
+ }
3170
3244
  if (message.kind === 'resize') {
3171
3245
  terminalCols = message.cols;
3172
3246
  terminalRows = message.rows;
@@ -0,0 +1,25 @@
1
+ export const INITIAL_TERMINAL_FOCUS = true;
2
+ export function createAttentionController(options) {
3
+ let previous = null;
4
+ let outstanding = false;
5
+ return {
6
+ sync(state, enabled) {
7
+ const last = previous;
8
+ previous = { ...state };
9
+ if (last && !last.focused && state.focused && outstanding) {
10
+ outstanding = false;
11
+ options.withdraw();
12
+ }
13
+ if (!last || !enabled)
14
+ return;
15
+ if (state.focused)
16
+ return;
17
+ const turnFinished = last.busy && !state.busy;
18
+ const nowBlocked = !last.awaitingAnswer && state.awaitingAnswer;
19
+ if (nowBlocked || turnFinished) {
20
+ outstanding = true;
21
+ options.notify(nowBlocked ? 'blocked' : 'finished');
22
+ }
23
+ },
24
+ };
25
+ }
@@ -1,6 +1,6 @@
1
1
  import { spawn } from 'node:child_process';
2
2
  import { createInterface } from 'node:readline';
3
- import { existsSync } from 'node:fs';
3
+ import { existsSync, statSync } from 'node:fs';
4
4
  import { createRequire } from 'node:module';
5
5
  import path from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
@@ -51,6 +51,9 @@ function normalizeChildMessage(raw) {
51
51
  url: String(raw.url ?? ''),
52
52
  };
53
53
  }
54
+ if (raw.kind === 'focus') {
55
+ return { op: 'event', kind: 'focus', focused: raw.focused === true };
56
+ }
54
57
  if (raw.kind === 'contextMenu') {
55
58
  return { op: 'event', kind: 'contextMenu' };
56
59
  }
@@ -95,13 +98,18 @@ function normalizeChildMessage(raw) {
95
98
  pageDown: bool(raw.pageDown ?? raw.page_down),
96
99
  };
97
100
  }
101
+ function isRepoCheckout(moduleDir) {
102
+ return [
103
+ path.join(moduleDir, '../../../../thegitai-tui/Cargo.toml'),
104
+ path.join(moduleDir, '../../../../../thegitai-tui/Cargo.toml'),
105
+ ].some((candidate) => existsSync(candidate));
106
+ }
98
107
  export function resolveTuiBinaryPath() {
99
108
  const binaryName = process.platform === 'win32' ? 'thegitai-tui.exe' : 'thegitai-tui';
100
109
  const platformPackage = `@thegitai/tui-${process.platform}-${process.arch}`;
101
- try {
102
- return requireFromHere.resolve(`${platformPackage}/${binaryName}`);
103
- }
104
- catch {
110
+ const override = String(process.env.THEGITAI_TUI_BINARY ?? '').trim();
111
+ if (override && existsSync(override)) {
112
+ return override;
105
113
  }
106
114
  const moduleDir = path.dirname(fileURLToPath(import.meta.url));
107
115
  const devCandidates = [
@@ -109,6 +117,24 @@ export function resolveTuiBinaryPath() {
109
117
  path.join(moduleDir, '../../../../bin', binaryName),
110
118
  ];
111
119
  const devBinary = devCandidates.find((candidate) => existsSync(candidate));
120
+ let publishedBinary = null;
121
+ try {
122
+ publishedBinary = requireFromHere.resolve(`${platformPackage}/${binaryName}`);
123
+ }
124
+ catch {
125
+ }
126
+ if (publishedBinary && devBinary && isRepoCheckout(moduleDir)) {
127
+ try {
128
+ if (statSync(devBinary).mtimeMs > statSync(publishedBinary).mtimeMs) {
129
+ return devBinary;
130
+ }
131
+ }
132
+ catch {
133
+ }
134
+ }
135
+ if (publishedBinary) {
136
+ return publishedBinary;
137
+ }
112
138
  if (devBinary) {
113
139
  return devBinary;
114
140
  }
@@ -32,6 +32,16 @@ const COMPOSER_INPUT_MAX_ROWS = 6;
32
32
  const FOOTER_HINT_MIN_GAP = 2;
33
33
  const FOOTER_HELP_HINT = '? for shortcuts';
34
34
  const FOOTER_CANCEL_HINT = 'esc cancels turn';
35
+ const FOOTER_NOTIFICATIONS_ON = 'Notifications ON';
36
+ const FOOTER_NOTIFICATIONS_OFF = 'Notifications OFF';
37
+ export function footerNotificationHint(status) {
38
+ const text = String(status ?? '').trim();
39
+ if (text === 'Notifications on')
40
+ return FOOTER_NOTIFICATIONS_ON;
41
+ if (text === 'Notifications off')
42
+ return FOOTER_NOTIFICATIONS_OFF;
43
+ return '';
44
+ }
35
45
  const FOOTER_CYCLE_HINT = ' (shift+tab to cycle)';
36
46
  const OVERLAY_PANEL_MAX_WIDTH = 86;
37
47
  const OVERLAY_PANEL_MARGIN_LINES = 2;
@@ -180,10 +190,12 @@ export function formatPromptSessionIdLabel(showSessionId, sessionId) {
180
190
  }
181
191
  const CLIENT_SLASH_COMMANDS = [
182
192
  { command: '/help', description: 'Show available chat commands' },
193
+ { command: '/about', description: 'Show version and platform info' },
183
194
  { command: '/usage', description: 'Show account usage percentage and reset times' },
184
195
  { command: '/model', description: 'Switch the active model' },
185
196
  { command: '/resume', description: 'Open the session picker to resume a previous session' },
186
197
  { command: '/jobs', description: 'Background jobs: pick to view output or kill' },
198
+ { command: '/notify', description: 'Toggle desktop notifications when a turn ends (Ctrl+G)' },
187
199
  { command: '/report', description: 'Report a bug privately on the TheGitAI website' },
188
200
  { command: '/new', description: 'start a new conversation; this session remains saved' },
189
201
  { command: '/logout', description: 'Sign out and quit' },
@@ -491,7 +503,15 @@ function composerFooterRightHints(state) {
491
503
  ? FOOTER_CANCEL_HINT
492
504
  : '';
493
505
  const helpHint = shortcutsPanelAvailable(state) ? FOOTER_HELP_HINT : '';
506
+ const notifyHint = footerNotificationHint(state.transientStatus);
507
+ const join = (...parts) => parts.filter(Boolean).join(' · ');
494
508
  const tiers = [];
509
+ if (notifyHint) {
510
+ tiers.push(join(cancelHint, notifyHint, helpHint));
511
+ tiers.push(join(notifyHint, helpHint));
512
+ tiers.push(join(cancelHint, notifyHint));
513
+ tiers.push(notifyHint);
514
+ }
495
515
  if (cancelHint && helpHint)
496
516
  tiers.push(`${cancelHint} · ${helpHint}`);
497
517
  if (cancelHint)
@@ -499,7 +519,7 @@ function composerFooterRightHints(state) {
499
519
  if (helpHint)
500
520
  tiers.push(helpHint);
501
521
  tiers.push('');
502
- return tiers;
522
+ return tiers.filter((tier, index) => tiers.indexOf(tier) === index);
503
523
  }
504
524
  export function fitComposerFooterRow({ modeLabels, modeLabelFallback, cycleHint, rightHints, leadWidth, tailWidth, contentWidth, }) {
505
525
  const candidates = rightHints.flatMap((rightHint) => (cycleHint ? [cycleHint, ''] : ['']).flatMap((cycle) => modeLabels.map((modeLabel) => ({ modeLabel, cycleHint: cycle, rightHint }))));
@@ -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
+ }
@@ -429,6 +429,10 @@ export function handleShellKeyEvent(store, handlers, event) {
429
429
  }
430
430
  return;
431
431
  }
432
+ if (key.ctrl && key.input === 'g' && !key.meta && !key.shift) {
433
+ handlers.onToggleNotifications?.();
434
+ return;
435
+ }
432
436
  if (key.input === '?' && !key.ctrl && !key.meta && shortcutsPanelAvailable(state)) {
433
437
  handlers.onLiveFrameShapeChange();
434
438
  store.update((current) => ({ ...current, shortcutsOpen: true }));
@@ -26,6 +26,7 @@ export function buildShortcutGroups(platform = process.platform) {
26
26
  { keys: '↑ / ↓', description: 'Earlier prompts' },
27
27
  { keys: 'Esc', description: 'Clear the composer' },
28
28
  { keys: 'Ctrl+C', description: 'Clear the composer, or quit when empty' },
29
+ { keys: 'Ctrl+G', description: 'Desktop notifications — toggle on or off' },
29
30
  ],
30
31
  },
31
32
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thegitai/cli",
3
- "version": "1.0.0-preview.42",
3
+ "version": "1.0.0-preview.43",
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.42",
48
- "@thegitai/tui-darwin-x64": "1.0.0-preview.42",
49
- "@thegitai/tui-linux-arm64": "1.0.0-preview.42",
50
- "@thegitai/tui-linux-x64": "1.0.0-preview.42",
51
- "@thegitai/tui-win32-x64": "1.0.0-preview.42",
47
+ "@thegitai/tui-darwin-arm64": "1.0.0-preview.43",
48
+ "@thegitai/tui-darwin-x64": "1.0.0-preview.43",
49
+ "@thegitai/tui-linux-arm64": "1.0.0-preview.43",
50
+ "@thegitai/tui-linux-x64": "1.0.0-preview.43",
51
+ "@thegitai/tui-win32-x64": "1.0.0-preview.43",
52
52
  "@vscode/ripgrep": "1.18.0"
53
53
  },
54
54
  "repository": {