@thegitai/cli 1.0.0-preview.47 → 1.0.0-preview.48

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.
@@ -91,13 +91,12 @@ export function browserAvailability(options) {
91
91
  selected: status.selected,
92
92
  };
93
93
  }
94
- const hint = status.registrationErrors.length
95
- ? `TheGitAI could not register its browser bridge with Chrome: ${status.registrationErrors[0]}`
96
- : status.everConnected
97
- ? 'The browser was connected to this session and dropped. Nothing needs reinstalling — it reconnects on its own, usually within a second or two. If it does not, open the TheGitAI icon in Chrome.'
98
- : chromiumProcessRunning()
99
- ? 'Chrome is running but the TheGitAI extension has not connected. Install or enable the extension, then reload it from chrome://extensions.'
100
- : 'Chrome does not appear to be running. Open Chrome with the TheGitAI extension installed.';
94
+ const hint = connectionHint({
95
+ registrationError: status.registrationErrors[0] ?? null,
96
+ everConnected: status.everConnected,
97
+ chromeRunning: () => chromiumProcessRunning(),
98
+ extensionSeen: () => browserExtensionSeen(options.env),
99
+ });
101
100
  return {
102
101
  connected: false,
103
102
  everConnected: status.everConnected,
@@ -106,6 +105,21 @@ export function browserAvailability(options) {
106
105
  hint,
107
106
  };
108
107
  }
108
+ export function connectionHint(state) {
109
+ if (state.registrationError) {
110
+ return `TheGitAI could not register its browser bridge with Chrome: ${state.registrationError}`;
111
+ }
112
+ if (state.everConnected) {
113
+ return 'The browser was connected to this session but is disconnected now. Check Chrome and the connection status shown by the TheGitAI extension.';
114
+ }
115
+ if (!state.chromeRunning()) {
116
+ return 'Chrome does not appear to be running. Open Chrome with the TheGitAI extension enabled and check its connection status.';
117
+ }
118
+ if (state.extensionSeen()) {
119
+ return 'The TheGitAI extension has connected on this machine before, but has not connected to this session yet. Check the connection status shown by the extension.';
120
+ }
121
+ return 'Chrome is running, but no browser connection reached this session. Check that the TheGitAI extension is installed and enabled, and inspect its connection status.';
122
+ }
109
123
  export function resyncBrowserBridge(options) {
110
124
  try {
111
125
  return ensureBrowserBridge(options).resync();
@@ -8,8 +8,7 @@ import { ensurePermission, originForUrl } from '../permissions.js';
8
8
  const READ_TIMEOUT_MS = 20000;
9
9
  const NAVIGATE_TIMEOUT_MS = 45000;
10
10
  const MAX_UPLOAD_BYTES = 10 * 1024 * 1024;
11
- const RECONNECT_GRACE_MS = 2500;
12
- const SCAN_GRACE_MS = 1200;
11
+ const DISCOVERY_TIMEOUT_MS = 2500;
13
12
  export const READ_ONLY_BROWSER_TOOLS = new Set([
14
13
  'browser',
15
14
  'browser_tabs',
@@ -35,38 +34,31 @@ function missing(argument, tool) {
35
34
  }
36
35
  async function waitForBrowser(options, timeoutMs) {
37
36
  const deadline = Date.now() + timeoutMs;
38
- let availability = browserAvailability(options);
39
- while (!availability.connected && Date.now() < deadline) {
37
+ const bridge = ensureBrowserBridge(options);
38
+ while (!bridge.status().connected && Date.now() < deadline) {
40
39
  await new Promise((resolve) => setTimeout(resolve, 100));
41
- availability = browserAvailability(options);
42
40
  }
43
- return availability;
41
+ return browserAvailability(options);
44
42
  }
45
43
  async function notConnected(context) {
46
44
  const options = { cwd: context.rootDir, env: context.env };
47
- let availability = browserAvailability(options);
45
+ const status = ensureBrowserBridge(options).status();
46
+ if (status.connected)
47
+ return { ok: true };
48
+ if (status.everConnected)
49
+ resyncBrowserBridge(options);
50
+ const availability = await waitForBrowser(options, DISCOVERY_TIMEOUT_MS);
48
51
  if (availability.connected)
49
52
  return { ok: true };
50
- if (availability.everConnected) {
51
- const grace = resyncBrowserBridge(options) ? RECONNECT_GRACE_MS : SCAN_GRACE_MS;
52
- availability = await waitForBrowser(options, grace);
53
- if (availability.connected)
54
- return { ok: true };
55
- }
56
53
  return {
57
54
  ok: false,
55
+ connected: false,
56
+ browserErrorCode: 'not_connected',
58
57
  error: `TheGitAI is not connected to a browser. ${availability.hint ?? ''}`.trim(),
59
58
  failureCategory: 'external_service',
60
- failureDetails: {
61
- category: 'external_service',
62
- tool: 'browser',
63
- action: availability.everConnected
64
- ? 'The link to a browser that was working dropped and did not come back. Nothing is missing and nothing needs installing, so do not send the user to reinstall anything. Say what happened, and that reopening the TheGitAI icon in Chrome restores it. Do not retry in a loop.'
65
- : 'Report the connection instructions. The extension is a separate installation. Do not retry in a loop or invent a download URL.',
66
- },
67
59
  };
68
60
  }
69
- function bridgeFailure(error, tool) {
61
+ function bridgeFailure(error) {
70
62
  const code = error instanceof BrowserBridgeError ? error.code : 'browser_error';
71
63
  const message = String(error?.message ?? error);
72
64
  return {
@@ -74,15 +66,6 @@ function bridgeFailure(error, tool) {
74
66
  error: message,
75
67
  failureCategory: code === 'not_connected' ? 'external_service' : 'tool_exception',
76
68
  browserErrorCode: code,
77
- failureDetails: {
78
- category: code === 'not_connected' ? 'external_service' : 'tool_exception',
79
- tool,
80
- action: code === 'timeout' || code === 'disconnected'
81
- ? 'The outcome is unknown. Read the page before repeating anything that submits, sends, buys, or deletes.'
82
- : code === 'stale_refs' || code === 'unknown_ref'
83
- ? 'Re-read the page and use the references from that read.'
84
- : 'Report what failed. Do not retry the same call more than once.',
85
- },
86
69
  };
87
70
  }
88
71
  async function call(context, op, args = {}, timeoutMs = READ_TIMEOUT_MS) {
@@ -152,7 +135,7 @@ export async function browserTabs(context, args) {
152
135
  return attachEvents({ ok: true, ...result });
153
136
  }
154
137
  catch (error) {
155
- return bridgeFailure(error, 'browser_tabs');
138
+ return bridgeFailure(error);
156
139
  }
157
140
  }
158
141
  export async function browserTabNew(context) {
@@ -164,7 +147,7 @@ export async function browserTabNew(context) {
164
147
  return attachEvents({ ok: true, ...result });
165
148
  }
166
149
  catch (error) {
167
- return bridgeFailure(error, 'browser_tab_new');
150
+ return bridgeFailure(error);
168
151
  }
169
152
  }
170
153
  export async function browserTabClose(context, args) {
@@ -179,7 +162,7 @@ export async function browserTabClose(context, args) {
179
162
  return attachEvents({ ok: true, ...result });
180
163
  }
181
164
  catch (error) {
182
- return bridgeFailure(error, 'browser_tab_close');
165
+ return bridgeFailure(error);
183
166
  }
184
167
  }
185
168
  export async function browserNavigate(context, args) {
@@ -212,7 +195,7 @@ export async function browserNavigate(context, args) {
212
195
  return attachEvents({ ok: true, ...result });
213
196
  }
214
197
  catch (error) {
215
- return bridgeFailure(error, 'browser_navigate');
198
+ return bridgeFailure(error);
216
199
  }
217
200
  }
218
201
  async function gatedTabCall(context, { tool, op, args, summary, timeoutMs = READ_TIMEOUT_MS, }) {
@@ -249,7 +232,7 @@ async function gatedTabCall(context, { tool, op, args, summary, timeoutMs = READ
249
232
  return attachEvents({ ok: true, tabId, url: tab.url, ...result });
250
233
  }
251
234
  catch (error) {
252
- return bridgeFailure(error, tool);
235
+ return bridgeFailure(error);
253
236
  }
254
237
  }
255
238
  export function browserReadPage(context, args) {
@@ -557,7 +540,7 @@ export async function browserFileUpload(context, args) {
557
540
  return attachEvents({ ok: true, ...result, files: files.map((file) => file.name) });
558
541
  }
559
542
  catch (error) {
560
- return bridgeFailure(error, 'browser_file_upload');
543
+ return bridgeFailure(error);
561
544
  }
562
545
  }
563
546
  function guessMimeType(file) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thegitai/cli",
3
- "version": "1.0.0-preview.47",
3
+ "version": "1.0.0-preview.48",
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.47",
48
- "@thegitai/tui-darwin-x64": "1.0.0-preview.47",
49
- "@thegitai/tui-linux-arm64": "1.0.0-preview.47",
50
- "@thegitai/tui-linux-x64": "1.0.0-preview.47",
51
- "@thegitai/tui-win32-x64": "1.0.0-preview.47",
47
+ "@thegitai/tui-darwin-arm64": "1.0.0-preview.48",
48
+ "@thegitai/tui-darwin-x64": "1.0.0-preview.48",
49
+ "@thegitai/tui-linux-arm64": "1.0.0-preview.48",
50
+ "@thegitai/tui-linux-x64": "1.0.0-preview.48",
51
+ "@thegitai/tui-win32-x64": "1.0.0-preview.48",
52
52
  "@vscode/ripgrep": "1.18.0"
53
53
  },
54
54
  "repository": {