nowaikit 4.12.1 → 4.15.1

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 (54) hide show
  1. package/README.md +12 -5
  2. package/dist/cli/auth.d.ts +13 -0
  3. package/dist/cli/auth.d.ts.map +1 -1
  4. package/dist/cli/auth.js +257 -54
  5. package/dist/cli/auth.js.map +1 -1
  6. package/dist/cli/detect-clients.d.ts.map +1 -1
  7. package/dist/cli/detect-clients.js +78 -2
  8. package/dist/cli/detect-clients.js.map +1 -1
  9. package/dist/cli/setup.d.ts.map +1 -1
  10. package/dist/cli/setup.js +243 -45
  11. package/dist/cli/setup.js.map +1 -1
  12. package/dist/servicenow/client.d.ts +49 -1
  13. package/dist/servicenow/client.d.ts.map +1 -1
  14. package/dist/servicenow/client.js +346 -40
  15. package/dist/servicenow/client.js.map +1 -1
  16. package/dist/servicenow/instances.d.ts.map +1 -1
  17. package/dist/servicenow/instances.js +56 -4
  18. package/dist/servicenow/instances.js.map +1 -1
  19. package/dist/servicenow/types.d.ts +17 -0
  20. package/dist/servicenow/types.d.ts.map +1 -1
  21. package/dist/tools/app-studio.d.ts.map +1 -1
  22. package/dist/tools/app-studio.js +80 -9
  23. package/dist/tools/app-studio.js.map +1 -1
  24. package/dist/tools/change.d.ts.map +1 -1
  25. package/dist/tools/change.js +3 -1
  26. package/dist/tools/change.js.map +1 -1
  27. package/dist/tools/core.d.ts.map +1 -1
  28. package/dist/tools/core.js +28 -2
  29. package/dist/tools/core.js.map +1 -1
  30. package/dist/tools/decision.d.ts.map +1 -1
  31. package/dist/tools/decision.js +19 -0
  32. package/dist/tools/decision.js.map +1 -1
  33. package/dist/tools/incident.d.ts.map +1 -1
  34. package/dist/tools/incident.js +5 -3
  35. package/dist/tools/incident.js.map +1 -1
  36. package/dist/tools/index.d.ts +159 -0
  37. package/dist/tools/index.d.ts.map +1 -1
  38. package/dist/tools/index.js +2 -2
  39. package/dist/tools/index.js.map +1 -1
  40. package/dist/tools/knowledge.d.ts.map +1 -1
  41. package/dist/tools/knowledge.js +12 -1
  42. package/dist/tools/knowledge.js.map +1 -1
  43. package/dist/tools/notification.d.ts +169 -0
  44. package/dist/tools/notification.d.ts.map +1 -1
  45. package/dist/tools/notification.js +88 -9
  46. package/dist/tools/notification.js.map +1 -1
  47. package/dist/tools/problem.d.ts.map +1 -1
  48. package/dist/tools/problem.js +3 -1
  49. package/dist/tools/problem.js.map +1 -1
  50. package/dist/tools/updateset.d.ts.map +1 -1
  51. package/dist/tools/updateset.js +62 -38
  52. package/dist/tools/updateset.js.map +1 -1
  53. package/dist/tools-manifest.json +98 -11
  54. package/package.json +1 -1
package/README.md CHANGED
@@ -19,19 +19,26 @@ New in 4.4 to 4.7: **impact analysis** to see what depends on a table, field, or
19
19
 
20
20
  ---
21
21
 
22
- ## 🚀 Install (2 minutes)
22
+ ## 🚀 Get started (2 minutes)
23
23
 
24
24
  > Requires **Node.js 20+**.
25
25
 
26
+ **1. Install and run the wizard.** It connects you to ServiceNow and writes your AI client's config for you.
27
+
26
28
  ```bash
27
- # 1 — install
28
29
  npm install -g nowaikit
30
+ nowaikit setup
31
+ ```
32
+
33
+ For OAuth the wizard signs in once, detects an existing OAuth app, or creates one for you (with an admin sign-in), or falls back to username/password. No manual OAuth app steps. On newer ServiceNow releases it creates a public client with PKCE (no secret).
29
34
 
30
- # 2 run the wizard: it detects your AI clients and writes their config for you
31
- npx nowaikit setup
35
+ **2. Sign in as yourself (per-user OAuth only).** Each user runs this once; the browser opens, you approve, and your queries then run in your own ServiceNow permission context.
36
+
37
+ ```bash
38
+ nowaikit auth login
32
39
  ```
33
40
 
34
- Restart your AI client (Claude Desktop, Cursor, …) and start asking. Done.
41
+ **3. Restart your AI client** (Claude Desktop, Cursor, …) and start asking. Done.
35
42
 
36
43
  **Keeping it up to date:** NowAIKit checks on startup and, when a newer version is out, asks a single **"Update now?"**. Say yes and it updates itself. You can also run `nowaikit update` any time, or `npm install -g nowaikit@latest`.
37
44
 
@@ -10,5 +10,18 @@ export declare function authLogin(): Promise<void>;
10
10
  export declare function authLogout(instanceUrl?: string): void;
11
11
  export declare function authWhoami(): void;
12
12
  export declare function getStoredToken(instanceUrl: string): UserToken | undefined;
13
+ /**
14
+ * Return a currently-valid stored token for an instance, refreshing it first if it is expired (or
15
+ * within 60s of expiry) and a refresh token + OAuth client are available. Persists the rotated
16
+ * token. Returns undefined if there is no stored token. Never throws (falls back to the stale token
17
+ * so the caller can still try, and the client will refresh reactively on a 401).
18
+ */
19
+ export declare function getValidUserToken(instanceUrl: string): Promise<UserToken | undefined>;
20
+ /** Persist a refreshed per-user token (used as the client's onTokenRefreshed callback). */
21
+ export declare function persistRefreshedToken(instanceUrl: string, t: {
22
+ accessToken: string;
23
+ refreshToken: string;
24
+ expiresAt: number;
25
+ }): void;
13
26
  export {};
14
27
  //# sourceMappingURL=auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/cli/auth.ts"],"names":[],"mappings":"AAeA,UAAU,SAAS;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AA8BD,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CA2H/C;AAED,wBAAgB,UAAU,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAgBrD;AAED,wBAAgB,UAAU,IAAI,IAAI,CAYjC;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAGzE"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/cli/auth.ts"],"names":[],"mappings":"AAiEA,UAAU,SAAS;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAqCD,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CA6I/C;AA4CD,wBAAgB,UAAU,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAgBrD;AAED,wBAAgB,UAAU,IAAI,IAAI,CAYjC;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAGzE;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CA4B3F;AAED,2FAA2F;AAC3F,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAapI"}
package/dist/cli/auth.js CHANGED
@@ -5,17 +5,91 @@
5
5
  * logout — removes stored token
6
6
  * whoami — show which ServiceNow user is currently authenticated
7
7
  */
8
- import { input, password, select } from '@inquirer/prompts';
8
+ import { confirm, input, password, select } from '@inquirer/prompts';
9
9
  import chalk from 'chalk';
10
10
  import ora from 'ora';
11
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
11
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
12
12
  import { homedir } from 'os';
13
13
  import { join } from 'path';
14
+ import { createHash, randomBytes } from 'crypto';
15
+ import { createServer } from 'node:http';
16
+ import { spawn } from 'node:child_process';
14
17
  import { listInstances } from './config-store.js';
18
+ const b64url = (b) => b.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
19
+ /** Open a URL in the user's default browser (best-effort, cross-platform). */
20
+ function openBrowser(url) {
21
+ try {
22
+ if (process.platform === 'darwin') {
23
+ spawn('open', [url], { stdio: 'ignore', detached: true }).unref();
24
+ }
25
+ else if (process.platform === 'win32') {
26
+ // NOT `cmd /c start` — cmd treats the `&` in an OAuth URL as a command separator and breaks it.
27
+ // rundll32 gets the full URL as a single argument, so query strings survive intact.
28
+ spawn('rundll32', ['url.dll,FileProtocolHandler', url], { stdio: 'ignore', detached: true }).unref();
29
+ }
30
+ else {
31
+ spawn('xdg-open', [url], { stdio: 'ignore', detached: true }).unref();
32
+ }
33
+ }
34
+ catch { /* best effort; the URL is also printed for manual open */ }
35
+ }
36
+ /**
37
+ * Loopback OAuth capture (RFC 8252): run a tiny local server on the redirect port, open the browser,
38
+ * and capture the ?code= automatically so the user never pastes anything. Rejects if the port can't
39
+ * bind or the flow times out, so the caller can fall back to the manual paste prompt.
40
+ */
41
+ function captureCodeViaLoopback(authUrl, port, expectedState) {
42
+ return new Promise((resolve, reject) => {
43
+ const server = createServer((req, res) => {
44
+ try {
45
+ const u = new URL(req.url || '/', `http://127.0.0.1:${port}`);
46
+ if (u.pathname !== '/callback') {
47
+ res.writeHead(404);
48
+ res.end('Not found');
49
+ return;
50
+ }
51
+ const code = u.searchParams.get('code');
52
+ const err = u.searchParams.get('error');
53
+ const returnedState = u.searchParams.get('state');
54
+ // CSRF guard: the state returned must match the one we sent.
55
+ const stateOk = !expectedState || returnedState === expectedState;
56
+ const ok = !!code && stateOk;
57
+ res.writeHead(200, { 'Content-Type': 'text/html' });
58
+ res.end(`<html><body style="font-family:sans-serif;padding:48px;color:#2b2630"><h2 style="color:#2f7256">NowAIKit</h2><p>${ok ? 'Signed in. You can close this tab and return to your terminal.' : 'Sign-in failed: ' + (err || (!stateOk ? 'state mismatch' : 'no authorization code returned'))}.</p></body></html>`);
59
+ server.close();
60
+ if (!stateOk) {
61
+ reject(new Error('state mismatch (possible CSRF)'));
62
+ return;
63
+ }
64
+ if (code)
65
+ resolve(code);
66
+ else
67
+ reject(new Error(err || 'no code in callback'));
68
+ }
69
+ catch (e) {
70
+ try {
71
+ res.writeHead(500);
72
+ res.end();
73
+ }
74
+ catch { /* noop */ }
75
+ server.close();
76
+ reject(e);
77
+ }
78
+ });
79
+ server.on('error', (e) => reject(e));
80
+ server.listen(port, '127.0.0.1', () => openBrowser(authUrl));
81
+ setTimeout(() => { try {
82
+ server.close();
83
+ }
84
+ catch { /* noop */ } reject(new Error('timed out waiting for browser sign-in')); }, 180_000);
85
+ });
86
+ }
15
87
  function tokenPath() {
16
88
  const dir = join(homedir(), '.config', 'nowaikit');
89
+ // mode is honored on POSIX (owner-only) and harmlessly ignored on Windows,
90
+ // where the file is already scoped to the user profile.
17
91
  if (!existsSync(dir))
18
- mkdirSync(dir, { recursive: true });
92
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
19
93
  return join(dir, 'tokens.json');
20
94
  }
21
95
  function loadTokens() {
@@ -30,7 +104,15 @@ function loadTokens() {
30
104
  }
31
105
  }
32
106
  function saveTokens(store) {
33
- writeFileSync(tokenPath(), JSON.stringify(store, null, 2), 'utf8');
107
+ const p = tokenPath();
108
+ // tokens.json holds OAuth access + refresh tokens: keep it owner-only.
109
+ // `mode` only applies when the file is created, so also chmod an existing file.
110
+ // Both are POSIX-effective and safely ignored/no-op on Windows (user-profile scoped).
111
+ writeFileSync(p, JSON.stringify(store, null, 2), { encoding: 'utf8', mode: 0o600 });
112
+ try {
113
+ chmodSync(p, 0o600);
114
+ }
115
+ catch { /* Windows / restricted FS: ignore */ }
34
116
  }
35
117
  function tokenKey(instanceUrl) {
36
118
  return instanceUrl.replace(/https?:\/\//, '').replace(/[^a-z0-9]/gi, '_');
@@ -41,58 +123,112 @@ export async function authLogin() {
41
123
  console.log(chalk.yellow('No instances configured. Run `nowaikit setup` first.'));
42
124
  return;
43
125
  }
44
- const instanceUrl = instances.length === 1
45
- ? instances[0].instanceUrl
126
+ // Pick by the unique instance NAME, not the URL — several instances can share one instanceUrl
127
+ // (e.g. a basic and an OAuth config for the same box), and keying on the URL would resolve to the
128
+ // wrong one (the first match), silently using the wrong auth method.
129
+ const instanceName = instances.length === 1
130
+ ? instances[0].name
46
131
  : await select({
47
132
  message: 'Choose instance to authenticate against:',
48
- choices: instances.map(i => ({ name: `${i.name} (${i.instanceUrl})`, value: i.instanceUrl })),
133
+ choices: instances.map(i => ({ name: `${i.name} (${i.instanceUrl})`, value: i.name })),
49
134
  });
50
- const instance = instances.find(i => i.instanceUrl === instanceUrl);
135
+ const instance = instances.find(i => i.name === instanceName);
51
136
  if (!instance)
52
137
  return;
138
+ const instanceUrl = instance.instanceUrl;
53
139
  console.log('');
54
140
  console.log(chalk.bold('Per-user OAuth login'));
55
141
  console.log(chalk.dim('Your queries will run in your own ServiceNow permission context.'));
56
142
  console.log('');
57
143
  if (instance.authMethod === 'oauth' && instance.clientId) {
58
- // OAuth Authorization Code flow — open browser
144
+ // OAuth Authorization Code flow — open browser.
145
+ // PKCE is added ONLY for public clients (no client secret configured), so existing
146
+ // confidential-client setups keep the exact same request they use today.
147
+ const usePkce = !instance.clientSecret;
148
+ const codeVerifier = usePkce ? b64url(randomBytes(32)) : '';
149
+ const codeChallenge = usePkce ? b64url(createHash('sha256').update(codeVerifier).digest()) : '';
150
+ // ServiceNow requires a state parameter on the authorize request; we also verify it on the
151
+ // callback as a CSRF guard.
152
+ const state = b64url(randomBytes(16));
59
153
  const authUrl = `${instanceUrl}/oauth_auth.do` +
60
154
  `?response_type=code&client_id=${instance.clientId}` +
61
- `&redirect_uri=http://localhost:8765/callback`;
62
- console.log(chalk.cyan('Open this URL in your browser to authenticate:'));
63
- console.log(chalk.underline(authUrl));
64
- console.log('');
65
- const code = await input({
66
- message: 'Paste the authorization code from the redirect URL:',
67
- });
155
+ `&redirect_uri=http://localhost:8765/callback` +
156
+ `&state=${state}` +
157
+ (usePkce ? `&code_challenge=${codeChallenge}&code_challenge_method=S256` : '');
158
+ // Preferred: loopback capture (RFC 8252) — open the browser and grab the code automatically,
159
+ // no copy/paste. Falls back to manual paste if the local port can't bind or the flow times out.
160
+ let code;
161
+ try {
162
+ console.log(chalk.cyan('Opening your browser to sign in…'));
163
+ console.log(chalk.dim('If it does not open, use this URL:'));
164
+ console.log(chalk.underline(authUrl));
165
+ console.log('');
166
+ code = await captureCodeViaLoopback(authUrl, 8765, state);
167
+ }
168
+ catch {
169
+ console.log('');
170
+ console.log(chalk.yellow('Could not capture the sign-in automatically.'));
171
+ console.log(chalk.dim('If the browser showed a ServiceNow error, this instance may not have the NowAIKit OAuth app installed.'));
172
+ console.log(chalk.cyan('Open this URL in your browser to authenticate, then paste the code from the redirect:'));
173
+ console.log(chalk.underline(authUrl));
174
+ console.log('');
175
+ code = await input({
176
+ message: 'Paste the authorization code (or leave blank to sign in with username/password):',
177
+ });
178
+ }
179
+ // No OAuth app / user gave up on the browser flow → fall back to the no-app path.
180
+ if (!code || !code.trim()) {
181
+ const useBasic = await confirm({
182
+ message: 'No code entered. Sign in with your ServiceNow username and password instead?',
183
+ default: true,
184
+ });
185
+ if (useBasic)
186
+ return await basicAuthLogin(instanceUrl);
187
+ console.log(chalk.yellow('Sign-in cancelled.'));
188
+ return;
189
+ }
68
190
  const spinner = ora('Exchanging authorization code for token…').start();
69
191
  try {
192
+ const tokenBody = new URLSearchParams({
193
+ grant_type: 'authorization_code',
194
+ client_id: instance.clientId,
195
+ code,
196
+ redirect_uri: 'http://localhost:8765/callback',
197
+ });
198
+ if (instance.clientSecret)
199
+ tokenBody.set('client_secret', instance.clientSecret);
200
+ if (usePkce)
201
+ tokenBody.set('code_verifier', codeVerifier);
70
202
  const resp = await fetch(`${instanceUrl}/oauth_token.do`, {
71
203
  method: 'POST',
72
204
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
73
- body: new URLSearchParams({
74
- grant_type: 'authorization_code',
75
- client_id: instance.clientId,
76
- client_secret: instance.clientSecret || '',
77
- code,
78
- redirect_uri: 'http://localhost:8765/callback',
79
- }).toString(),
205
+ body: tokenBody.toString(),
80
206
  });
81
207
  if (!resp.ok) {
82
208
  spinner.fail(chalk.red(`Token exchange failed: ${resp.status} ${resp.statusText}`));
209
+ // 400/401 here usually means the OAuth app is missing or misconfigured on this instance.
210
+ if (resp.status === 400 || resp.status === 401) {
211
+ const useBasic = await confirm({
212
+ message: 'The OAuth app may not be set up on this instance. Sign in with username and password instead?',
213
+ default: true,
214
+ });
215
+ if (useBasic)
216
+ return await basicAuthLogin(instanceUrl);
217
+ }
83
218
  return;
84
219
  }
85
220
  const data = await resp.json();
86
- // Get the ServiceNow user tied to this token
87
- const meResp = await fetch(`${instanceUrl}/api/now/table/sys_user?sysparm_query=sys_idINSTANCEOF&sysparm_limit=1`, {
221
+ // Identify the ServiceNow user this token belongs to via the current-user endpoint
222
+ // (the old sys_idINSTANCEOF query matched nothing → always "unknown").
223
+ const meResp = await fetch(`${instanceUrl}/api/now/ui/user/current_user`, {
88
224
  headers: {
89
225
  Authorization: `Bearer ${data.access_token}`,
90
226
  Accept: 'application/json',
91
227
  },
92
228
  });
93
229
  const meData = await meResp.json();
94
- const snUserSysId = meData.result?.[0]?.sys_id?.value || '';
95
- const snUser = meData.result?.[0]?.user_name?.value || 'unknown';
230
+ const snUser = meData.result?.user_name || meData.result?.name || 'unknown';
231
+ const snUserSysId = meData.result?.user_sys_id || meData.result?.sys_id || '';
96
232
  const store = loadTokens();
97
233
  store.tokens[tokenKey(instanceUrl)] = {
98
234
  instanceUrl,
@@ -110,34 +246,44 @@ export async function authLogin() {
110
246
  }
111
247
  }
112
248
  else {
113
- // Basic auth per-user: prompt credentials, store them
114
- const username = await input({ message: 'Your ServiceNow username:' });
115
- const pass = await password({ message: 'Your ServiceNow password:', mask: '•' });
116
- const spinner = ora('Verifying credentials…').start();
117
- try {
118
- const creds = Buffer.from(`${username}:${pass}`).toString('base64');
119
- const resp = await fetch(`${instanceUrl}/api/now/table/sys_user?sysparm_query=user_name=${encodeURIComponent(username)}&sysparm_limit=1`, { headers: { Authorization: `Basic ${creds}`, Accept: 'application/json' } });
120
- if (!resp.ok) {
121
- spinner.fail(chalk.red(`Auth failed: ${resp.status} ${resp.statusText}`));
122
- return;
123
- }
124
- const data = await resp.json();
125
- const snUserSysId = data.result?.[0]?.sys_id?.value || '';
126
- const store = loadTokens();
127
- store.tokens[tokenKey(instanceUrl)] = {
128
- instanceUrl,
129
- accessToken: creds,
130
- refreshToken: '',
131
- expiresAt: Date.now() + 365 * 24 * 60 * 60 * 1000, // basic auth doesn't expire
132
- snUser: username,
133
- snUserSysId,
134
- };
135
- saveTokens(store);
136
- spinner.succeed(chalk.green(`Saved credentials for ${username} on ${instanceUrl}`));
137
- }
138
- catch (err) {
139
- spinner.fail(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
249
+ await basicAuthLogin(instanceUrl);
250
+ }
251
+ }
252
+ /**
253
+ * Per-user basic-auth login — the fallback that needs NO OAuth app on the instance. The user enters
254
+ * their own ServiceNow username and password, so queries still run in their own permission context.
255
+ * Works only where the instance permits basic REST auth and the user has a local password; on
256
+ * SSO-only / MFA-enforced instances this is not available and the OAuth app (or Entra) is required.
257
+ */
258
+ async function basicAuthLogin(instanceUrl) {
259
+ const username = await input({ message: 'Your ServiceNow username:' });
260
+ const pass = await password({ message: 'Your ServiceNow password:', mask: '•' });
261
+ const spinner = ora('Verifying credentials…').start();
262
+ try {
263
+ const creds = Buffer.from(`${username}:${pass}`).toString('base64');
264
+ const resp = await fetch(`${instanceUrl}/api/now/table/sys_user?sysparm_query=user_name=${encodeURIComponent(username)}&sysparm_limit=1`, { headers: { Authorization: `Basic ${creds}`, Accept: 'application/json' } });
265
+ if (!resp.ok) {
266
+ spinner.fail(chalk.red(`Auth failed: ${resp.status} ${resp.statusText}`));
267
+ if (resp.status === 401)
268
+ console.log(chalk.dim('If this instance is SSO-only or blocks basic REST auth, use the OAuth app path instead.'));
269
+ return;
140
270
  }
271
+ const data = await resp.json();
272
+ const snUserSysId = data.result?.[0]?.sys_id?.value || '';
273
+ const store = loadTokens();
274
+ store.tokens[tokenKey(instanceUrl)] = {
275
+ instanceUrl,
276
+ accessToken: creds,
277
+ refreshToken: '',
278
+ expiresAt: Date.now() + 365 * 24 * 60 * 60 * 1000, // basic auth doesn't expire
279
+ snUser: username,
280
+ snUserSysId,
281
+ };
282
+ saveTokens(store);
283
+ spinner.succeed(chalk.green(`Saved credentials for ${username} on ${instanceUrl}`));
284
+ }
285
+ catch (err) {
286
+ spinner.fail(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
141
287
  }
142
288
  }
143
289
  export function authLogout(instanceUrl) {
@@ -176,4 +322,61 @@ export function getStoredToken(instanceUrl) {
176
322
  const store = loadTokens();
177
323
  return store.tokens[tokenKey(instanceUrl)];
178
324
  }
325
+ /**
326
+ * Return a currently-valid stored token for an instance, refreshing it first if it is expired (or
327
+ * within 60s of expiry) and a refresh token + OAuth client are available. Persists the rotated
328
+ * token. Returns undefined if there is no stored token. Never throws (falls back to the stale token
329
+ * so the caller can still try, and the client will refresh reactively on a 401).
330
+ */
331
+ export async function getValidUserToken(instanceUrl) {
332
+ const store = loadTokens();
333
+ const key = tokenKey(instanceUrl);
334
+ const t = store.tokens[key];
335
+ if (!t)
336
+ return undefined;
337
+ // Basic-auth stored creds (no refresh token) or a token that is still fresh: use as-is.
338
+ if (!t.refreshToken || Date.now() < t.expiresAt - 60_000)
339
+ return t;
340
+ const inst = listInstances().find(i => i.instanceUrl === instanceUrl);
341
+ if (!inst?.clientId)
342
+ return t; // cannot refresh without the OAuth client id
343
+ try {
344
+ const body = new URLSearchParams({ grant_type: 'refresh_token', client_id: inst.clientId, refresh_token: t.refreshToken });
345
+ if (inst.clientSecret)
346
+ body.set('client_secret', inst.clientSecret);
347
+ const resp = await fetch(`${instanceUrl}/oauth_token.do`, {
348
+ method: 'POST',
349
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
350
+ body: body.toString(),
351
+ });
352
+ if (!resp.ok)
353
+ return t;
354
+ const data = await resp.json();
355
+ t.accessToken = data.access_token;
356
+ if (data.refresh_token)
357
+ t.refreshToken = data.refresh_token;
358
+ t.expiresAt = Date.now() + (data.expires_in ? data.expires_in * 1000 * 0.9 : 25 * 60 * 1000);
359
+ store.tokens[key] = t;
360
+ saveTokens(store);
361
+ return t;
362
+ }
363
+ catch {
364
+ return t;
365
+ }
366
+ }
367
+ /** Persist a refreshed per-user token (used as the client's onTokenRefreshed callback). */
368
+ export function persistRefreshedToken(instanceUrl, t) {
369
+ const store = loadTokens();
370
+ const key = tokenKey(instanceUrl);
371
+ const existing = store.tokens[key];
372
+ store.tokens[key] = {
373
+ instanceUrl,
374
+ accessToken: t.accessToken,
375
+ refreshToken: t.refreshToken,
376
+ expiresAt: t.expiresAt,
377
+ snUser: existing?.snUser || 'unknown',
378
+ snUserSysId: existing?.snUserSysId || '',
379
+ };
380
+ saveTokens(store);
381
+ }
179
382
  //# sourceMappingURL=auth.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/cli/auth.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAelD,SAAS,SAAS;IAChB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACnD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,OAAO,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,UAAU;IACjB,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;IACtB,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC1C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAe,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACxB,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,KAAiB;IACnC,aAAa,CAAC,SAAS,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,QAAQ,CAAC,WAAmB;IACnC,OAAO,WAAW,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;IAClC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,sDAAsD,CAAC,CAAC,CAAC;QAClF,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,KAAK,CAAC;QACxC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,CAAC,WAAW;QAC3B,CAAC,CAAC,MAAM,MAAM,CAAS;YACnB,OAAO,EAAE,0CAA0C;YACnD,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,WAAW,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;SAC9F,CAAC,CAAC;IAEP,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,WAAW,CAAC,CAAC;IACpE,IAAI,CAAC,QAAQ;QAAE,OAAO;IAEtB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC,CAAC;IAC3F,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,IAAI,QAAQ,CAAC,UAAU,KAAK,OAAO,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACzD,+CAA+C;QAC/C,MAAM,OAAO,GACX,GAAG,WAAW,gBAAgB;YAC9B,iCAAiC,QAAQ,CAAC,QAAQ,EAAE;YACpD,8CAA8C,CAAC;QAEjD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC,CAAC;QAC1E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC;YACvB,OAAO,EAAE,qDAAqD;SAC/D,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,GAAG,CAAC,0CAA0C,CAAC,CAAC,KAAK,EAAE,CAAC;QACxE,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,WAAW,iBAAiB,EAAE;gBACxD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;gBAChE,IAAI,EAAE,IAAI,eAAe,CAAC;oBACxB,UAAU,EAAE,oBAAoB;oBAChC,SAAS,EAAE,QAAQ,CAAC,QAAQ;oBAC5B,aAAa,EAAE,QAAQ,CAAC,YAAY,IAAI,EAAE;oBAC1C,IAAI;oBACJ,YAAY,EAAE,gCAAgC;iBAC/C,CAAC,CAAC,QAAQ,EAAE;aACd,CAAC,CAAC;YAEH,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,0BAA0B,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;gBACpF,OAAO;YACT,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAI3B,CAAC;YAEF,6CAA6C;YAC7C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,WAAW,wEAAwE,EAAE;gBACjH,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,IAAI,CAAC,YAAY,EAAE;oBAC5C,MAAM,EAAE,kBAAkB;iBAC3B;aACF,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,EAAuF,CAAC;YACxH,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;YAC5D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,IAAI,SAAS,CAAC;YAEjE,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;YAC3B,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,GAAG;gBACpC,WAAW;gBACX,WAAW,EAAE,IAAI,CAAC,YAAY;gBAC9B,YAAY,EAAE,IAAI,CAAC,aAAa;gBAChC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,GAAG;gBACpD,MAAM;gBACN,WAAW;aACZ,CAAC;YACF,UAAU,CAAC,KAAK,CAAC,CAAC;YAElB,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,MAAM,OAAO,WAAW,EAAE,CAAC,CAAC,CAAC;QAC/E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;SAAM,CAAC;QACN,sDAAsD;QACtD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAC,CAAC;QACvE,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,EAAE,OAAO,EAAE,2BAA2B,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QAEjF,MAAM,OAAO,GAAG,GAAG,CAAC,wBAAwB,CAAC,CAAC,KAAK,EAAE,CAAC;QACtD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACpE,MAAM,IAAI,GAAG,MAAM,KAAK,CACtB,GAAG,WAAW,mDAAmD,kBAAkB,CAAC,QAAQ,CAAC,kBAAkB,EAC/G,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,SAAS,KAAK,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAC7E,CAAC;YACF,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;gBAC1E,OAAO;YACT,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAuF,CAAC;YACpH,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;YAE1D,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;YAC3B,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,GAAG;gBACpC,WAAW;gBACX,WAAW,EAAE,KAAK;gBAClB,YAAY,EAAE,EAAE;gBAChB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,4BAA4B;gBAC/E,MAAM,EAAE,QAAQ;gBAChB,WAAW;aACZ,CAAC;YACF,UAAU,CAAC,KAAK,CAAC,CAAC;YAElB,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,yBAAyB,QAAQ,OAAO,WAAW,EAAE,CAAC,CAAC,CAAC;QACtF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,WAAoB;IAC7C,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;IAC3B,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;QAClC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,UAAU,CAAC,KAAK,CAAC,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,mBAAmB,WAAW,EAAE,CAAC,CAAC,CAAC;QAC7D,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,WAAW,EAAE,CAAC,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC;QAClB,UAAU,CAAC,KAAK,CAAC,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC,CAAC;QACvE,OAAO;IACT,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC;QACzC,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC1E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,WAAW,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC;IACxE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,WAAmB;IAChD,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;IAC3B,OAAO,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AAC7C,CAAC"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/cli/auth.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"detect-clients.d.ts","sourceRoot":"","sources":["../../src/cli/detect-clients.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,WAAW,GAAG,iBAAiB,GAAG,cAAc,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE5F,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA4ED,wBAAgB,aAAa,IAAI,cAAc,EAAE,CAgJhD"}
1
+ {"version":3,"file":"detect-clients.d.ts","sourceRoot":"","sources":["../../src/cli/detect-clients.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,WAAW,GAAG,iBAAiB,GAAG,cAAc,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE5F,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAuGD,wBAAgB,aAAa,IAAI,cAAc,EAAE,CAiMhD"}
@@ -27,6 +27,34 @@ function appExists(macPath, winExe, linuxBin) {
27
27
  }
28
28
  return which(linuxBin);
29
29
  }
30
+ /**
31
+ * VS Code's GLOBAL (user-profile) MCP config, which applies across every workspace — unlike the
32
+ * project-level .vscode/mcp.json. Path is platform-specific:
33
+ * macOS ~/Library/Application Support/Code/User/mcp.json
34
+ * Windows %APPDATA%\Code\User\mcp.json
35
+ * Linux ~/.config/Code/User/mcp.json
36
+ */
37
+ function vscodeUserConfigPath() {
38
+ const p = process.platform;
39
+ if (p === 'darwin')
40
+ return join(homedir(), 'Library', 'Application Support', 'Code', 'User', 'mcp.json');
41
+ if (p === 'win32')
42
+ return join(process.env['APPDATA'] || join(homedir(), 'AppData', 'Roaming'), 'Code', 'User', 'mcp.json');
43
+ return join(homedir(), '.config', 'Code', 'User', 'mcp.json');
44
+ }
45
+ /** VS Code User directory (holds extension globalStorage), platform-specific. */
46
+ function vscodeUserDir() {
47
+ const p = process.platform;
48
+ if (p === 'darwin')
49
+ return join(homedir(), 'Library', 'Application Support', 'Code', 'User');
50
+ if (p === 'win32')
51
+ return join(process.env['APPDATA'] || join(homedir(), 'AppData', 'Roaming'), 'Code', 'User');
52
+ return join(homedir(), '.config', 'Code', 'User');
53
+ }
54
+ /** Cline stores MCP config in its VS Code extension globalStorage (uses the standard mcpServers key). */
55
+ function clineConfigPath() {
56
+ return join(vscodeUserDir(), 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json');
57
+ }
30
58
  /**
31
59
  * Robust Claude Desktop detection. The config file only appears once you've added an MCP server,
32
60
  * so a fresh install shows nothing there. Check the config FOLDER (created on first launch), and on
@@ -124,11 +152,13 @@ export function detectClients() {
124
152
  id: 'vscode',
125
153
  name: 'VS Code (GitHub Copilot)',
126
154
  detected: false,
127
- configPath: join(process.cwd(), '.vscode', 'mcp.json'),
155
+ // Global user config → works in every workspace (was project-only .vscode/mcp.json, which
156
+ // depended on where setup was run). Cross-platform via vscodeUserConfigPath().
157
+ configPath: vscodeUserConfigPath(),
128
158
  configKey: 'servers',
129
159
  writeMethod: 'json-servers',
130
160
  requiresRestart: false,
131
- note: 'VS Code reads .vscode/mcp.json from the workspace root. Open the workspace folder in VS Code.',
161
+ note: 'Written to your global VS Code MCP config (all workspaces). A project-level .vscode/mcp.json also works. Needs VS Code 1.102+ with MCP enabled.',
132
162
  },
133
163
  {
134
164
  id: 'windsurf',
@@ -152,6 +182,38 @@ export function detectClients() {
152
182
  requiresRestart: false,
153
183
  note: 'Continue.dev will pick up the change automatically.',
154
184
  },
185
+ {
186
+ id: 'antigravity',
187
+ name: 'Antigravity (Google)',
188
+ detected: false,
189
+ // Antigravity reads ~/.gemini/antigravity/mcp_config.json on every platform (standard format).
190
+ configPath: join(home, '.gemini', 'antigravity', 'mcp_config.json'),
191
+ configKey: 'mcpServers',
192
+ writeMethod: 'json-mcpServers',
193
+ requiresRestart: true,
194
+ note: 'Restart Antigravity (or Manage MCP Servers → reload) to activate.',
195
+ },
196
+ {
197
+ id: 'cline',
198
+ name: 'Cline (VS Code)',
199
+ detected: false,
200
+ configPath: clineConfigPath(),
201
+ configKey: 'mcpServers',
202
+ writeMethod: 'json-mcpServers',
203
+ requiresRestart: false,
204
+ note: 'Cline picks up the change automatically. (VS Code Insiders/VSCodium use a different folder.)',
205
+ },
206
+ {
207
+ id: 'gemini-cli',
208
+ name: 'Gemini CLI',
209
+ detected: false,
210
+ // Global settings ~/.gemini/settings.json (mcpServers). Project .gemini/settings.json also works.
211
+ configPath: join(home, '.gemini', 'settings.json'),
212
+ configKey: 'mcpServers',
213
+ writeMethod: 'json-mcpServers',
214
+ requiresRestart: true,
215
+ note: 'Restart the Gemini CLI session to load the server.',
216
+ },
155
217
  {
156
218
  id: 'claude-code',
157
219
  name: 'Claude Code (CLI)',
@@ -210,6 +272,20 @@ export function detectClients() {
210
272
  if (c.id === 'continue') {
211
273
  return { ...c, detected: existsSync(c.configPath) };
212
274
  }
275
+ if (c.id === 'antigravity') {
276
+ return {
277
+ ...c,
278
+ detected: existsSync(c.configPath) || existsSync(dirname(c.configPath)) ||
279
+ appExists('/Applications/Antigravity.app', join('Programs', 'Antigravity', 'Antigravity.exe'), 'antigravity'),
280
+ };
281
+ }
282
+ if (c.id === 'cline') {
283
+ // Detect via the extension's globalStorage folder (created once Cline runs).
284
+ return { ...c, detected: existsSync(c.configPath) || existsSync(dirname(c.configPath)) };
285
+ }
286
+ if (c.id === 'gemini-cli') {
287
+ return { ...c, detected: existsSync(c.configPath) || existsSync(dirname(c.configPath)) || which('gemini') };
288
+ }
213
289
  if (c.id === 'claude-code') {
214
290
  return { ...c, detected: which('claude') };
215
291
  }