githits 0.4.8 → 0.4.10
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.plugin/plugin.json +1 -1
- package/README.md +5 -0
- package/commands/example.md +5 -3
- package/dist/cli.js +935 -290
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-wyphcypv.js → chunk-fvpvx4x4.js} +1 -1
- package/dist/shared/{chunk-681avsyw.js → chunk-mw1910qd.js} +2 -2
- package/dist/shared/{chunk-6hq1gf0g.js → chunk-p9ak72j0.js} +237 -71
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/commands/example.md +5 -3
- package/skills/githits-code/SKILL.md +7 -4
- package/skills/githits-package/SKILL.md +1 -1
- package/skills/githits-package/references/package.md +2 -2
package/dist/index.js
CHANGED
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
createAuthStatusDependencies,
|
|
5
5
|
createContainer,
|
|
6
6
|
loadAutoLoginAuthSessionMetadata
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import"./chunk-
|
|
7
|
+
} from "./chunk-p9ak72j0.js";
|
|
8
|
+
import"./chunk-fvpvx4x4.js";
|
|
9
9
|
export {
|
|
10
10
|
loadAutoLoginAuthSessionMetadata,
|
|
11
11
|
createContainer,
|
|
@@ -1,35 +1,62 @@
|
|
|
1
1
|
import {
|
|
2
2
|
__require,
|
|
3
3
|
version
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-fvpvx4x4.js";
|
|
5
5
|
|
|
6
6
|
// src/services/app-config-paths.ts
|
|
7
7
|
var APP_DIR = "githits";
|
|
8
8
|
function getAppConfigDir(fs) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
return getAppConfigDirForEnv(fs, process.env, process.platform, fs.getHomeDir());
|
|
10
|
+
}
|
|
11
|
+
function getAppConfigDirForEnv(fs, env, platform, home = getHomeDirForEnv(fs, env, platform)) {
|
|
12
|
+
if (platform === "win32") {
|
|
13
|
+
return fs.joinPath(env.APPDATA ?? fs.joinPath(home, "AppData", "Roaming"), APP_DIR);
|
|
12
14
|
}
|
|
13
|
-
return fs.joinPath(
|
|
15
|
+
return fs.joinPath(env.XDG_CONFIG_HOME ?? fs.joinPath(home, ".config"), APP_DIR);
|
|
14
16
|
}
|
|
15
17
|
function getAuthConfigPath(fs) {
|
|
16
18
|
return fs.joinPath(getAppConfigDir(fs), "config.toml");
|
|
17
19
|
}
|
|
20
|
+
function getAuthConfigPathForEnv(fs, env, platform) {
|
|
21
|
+
return fs.joinPath(getAppConfigDirForEnv(fs, env, platform), "config.toml");
|
|
22
|
+
}
|
|
18
23
|
function getAuthFileStorageDir(fs) {
|
|
19
24
|
return fs.joinPath(getAppConfigDir(fs), "auth");
|
|
20
25
|
}
|
|
26
|
+
function getAuthFileStorageDirForEnv(fs, env, platform) {
|
|
27
|
+
return fs.joinPath(getAppConfigDirForEnv(fs, env, platform), "auth");
|
|
28
|
+
}
|
|
29
|
+
function getHomeDirForEnv(fs, env, platform) {
|
|
30
|
+
if (platform === "win32" && env.USERPROFILE)
|
|
31
|
+
return env.USERPROFILE;
|
|
32
|
+
if (platform !== "win32" && env.HOME)
|
|
33
|
+
return env.HOME;
|
|
34
|
+
return fs.getHomeDir();
|
|
35
|
+
}
|
|
21
36
|
function getLegacyAuthStorageDir(fs) {
|
|
22
37
|
return fs.joinPath(fs.getHomeDir(), ".githits");
|
|
23
38
|
}
|
|
39
|
+
function getLegacyAuthStorageDirForEnv(fs, env, platform) {
|
|
40
|
+
return fs.joinPath(getHomeDirForEnv(fs, env, platform), ".githits");
|
|
41
|
+
}
|
|
24
42
|
function getLegacyMacAppConfigDir(fs) {
|
|
25
43
|
return fs.joinPath(fs.getHomeDir(), "Library", "Application Support", APP_DIR);
|
|
26
44
|
}
|
|
45
|
+
function getLegacyMacAppConfigDirForEnv(fs, env) {
|
|
46
|
+
return fs.joinPath(getHomeDirForEnv(fs, env, "darwin"), "Library", "Application Support", APP_DIR);
|
|
47
|
+
}
|
|
27
48
|
function getLegacyMacAuthConfigPath(fs) {
|
|
28
49
|
return fs.joinPath(getLegacyMacAppConfigDir(fs), "config.toml");
|
|
29
50
|
}
|
|
51
|
+
function getLegacyMacAuthConfigPathForEnv(fs, env) {
|
|
52
|
+
return fs.joinPath(getLegacyMacAppConfigDirForEnv(fs, env), "config.toml");
|
|
53
|
+
}
|
|
30
54
|
function getLegacyMacAuthFileStorageDir(fs) {
|
|
31
55
|
return fs.joinPath(getLegacyMacAppConfigDir(fs), "auth");
|
|
32
56
|
}
|
|
57
|
+
function getLegacyMacAuthFileStorageDirForEnv(fs, env) {
|
|
58
|
+
return fs.joinPath(getLegacyMacAppConfigDirForEnv(fs, env), "auth");
|
|
59
|
+
}
|
|
33
60
|
// src/services/auth-config.ts
|
|
34
61
|
import { parse as parseToml } from "smol-toml";
|
|
35
62
|
import { z } from "zod";
|
|
@@ -114,11 +141,57 @@ function generateState() {
|
|
|
114
141
|
return randomBytes(32).toString("hex");
|
|
115
142
|
}
|
|
116
143
|
|
|
144
|
+
// src/shared/fetch-timeout.ts
|
|
145
|
+
var DEFAULT_FETCH_TIMEOUT_MS = 120000;
|
|
146
|
+
|
|
147
|
+
class FetchTimeoutError extends Error {
|
|
148
|
+
timeoutMs;
|
|
149
|
+
constructor(timeoutMs, options) {
|
|
150
|
+
super(`Request timed out after ${timeoutMs}ms.`, options);
|
|
151
|
+
this.name = "FetchTimeoutError";
|
|
152
|
+
this.timeoutMs = timeoutMs;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async function fetchWithTimeout(input, init = {}, options = {}) {
|
|
156
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;
|
|
157
|
+
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
158
|
+
const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
|
|
159
|
+
const fetchFn = options.fetchFn ?? globalThis.fetch;
|
|
160
|
+
let timeoutId;
|
|
161
|
+
const timeout = new Promise((_, reject) => {
|
|
162
|
+
timeoutId = setTimeout(() => {
|
|
163
|
+
reject(new FetchTimeoutError(timeoutMs));
|
|
164
|
+
}, timeoutMs);
|
|
165
|
+
});
|
|
166
|
+
try {
|
|
167
|
+
return await Promise.race([fetchFn(input, { ...init, signal }), timeout]);
|
|
168
|
+
} catch (cause) {
|
|
169
|
+
if (cause instanceof FetchTimeoutError)
|
|
170
|
+
throw cause;
|
|
171
|
+
if (timeoutSignal.aborted && !init.signal?.aborted) {
|
|
172
|
+
throw new FetchTimeoutError(timeoutMs, { cause });
|
|
173
|
+
}
|
|
174
|
+
throw cause;
|
|
175
|
+
} finally {
|
|
176
|
+
if (timeoutId)
|
|
177
|
+
clearTimeout(timeoutId);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function isFetchTimeoutError(error) {
|
|
181
|
+
return error instanceof FetchTimeoutError;
|
|
182
|
+
}
|
|
183
|
+
|
|
117
184
|
// src/services/auth-service.ts
|
|
118
185
|
class AuthServiceImpl {
|
|
186
|
+
fetchFn;
|
|
187
|
+
fetchTimeoutMs;
|
|
188
|
+
constructor(fetchFn, fetchTimeoutMs = DEFAULT_FETCH_TIMEOUT_MS) {
|
|
189
|
+
this.fetchFn = fetchFn;
|
|
190
|
+
this.fetchTimeoutMs = fetchTimeoutMs;
|
|
191
|
+
}
|
|
119
192
|
async discoverEndpoints(mcpBaseUrl) {
|
|
120
193
|
const url = `${mcpBaseUrl}/.well-known/oauth-authorization-server`;
|
|
121
|
-
const response = await
|
|
194
|
+
const response = await fetchWithTimeout(url, {}, this.fetchOptions());
|
|
122
195
|
if (!response.ok) {
|
|
123
196
|
throw new Error(`Failed to discover OAuth endpoints: ${response.status} ${response.statusText}`);
|
|
124
197
|
}
|
|
@@ -136,7 +209,7 @@ class AuthServiceImpl {
|
|
|
136
209
|
};
|
|
137
210
|
}
|
|
138
211
|
async registerClient(params) {
|
|
139
|
-
const response = await
|
|
212
|
+
const response = await fetchWithTimeout(params.registrationEndpoint, {
|
|
140
213
|
method: "POST",
|
|
141
214
|
headers: { "Content-Type": "application/json" },
|
|
142
215
|
body: JSON.stringify({
|
|
@@ -146,7 +219,7 @@ class AuthServiceImpl {
|
|
|
146
219
|
response_types: ["code"],
|
|
147
220
|
token_endpoint_auth_method: "client_secret_post"
|
|
148
221
|
})
|
|
149
|
-
});
|
|
222
|
+
}, this.fetchOptions());
|
|
150
223
|
if (!response.ok) {
|
|
151
224
|
const error = await response.text();
|
|
152
225
|
throw new Error(`Client registration failed: ${error}`);
|
|
@@ -251,11 +324,11 @@ class AuthServiceImpl {
|
|
|
251
324
|
code_verifier: params.codeVerifier,
|
|
252
325
|
redirect_uri: params.redirectUri
|
|
253
326
|
});
|
|
254
|
-
const response = await
|
|
327
|
+
const response = await fetchWithTimeout(params.tokenEndpoint, {
|
|
255
328
|
method: "POST",
|
|
256
329
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
257
330
|
body: body.toString()
|
|
258
|
-
});
|
|
331
|
+
}, this.fetchOptions());
|
|
259
332
|
if (!response.ok) {
|
|
260
333
|
const error = await response.text();
|
|
261
334
|
throw new Error(`Token exchange failed: ${error}`);
|
|
@@ -269,17 +342,23 @@ class AuthServiceImpl {
|
|
|
269
342
|
client_secret: params.clientSecret,
|
|
270
343
|
refresh_token: params.refreshToken
|
|
271
344
|
});
|
|
272
|
-
const response = await
|
|
345
|
+
const response = await fetchWithTimeout(params.tokenEndpoint, {
|
|
273
346
|
method: "POST",
|
|
274
347
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
275
348
|
body: body.toString()
|
|
276
|
-
});
|
|
349
|
+
}, this.fetchOptions());
|
|
277
350
|
if (!response.ok) {
|
|
278
351
|
const error = await response.text();
|
|
279
352
|
throw new Error(`Token refresh failed: ${error}`);
|
|
280
353
|
}
|
|
281
354
|
return parseRefreshTokenResponse(await response.json());
|
|
282
355
|
}
|
|
356
|
+
fetchOptions() {
|
|
357
|
+
return {
|
|
358
|
+
fetchFn: this.fetchFn,
|
|
359
|
+
timeoutMs: this.fetchTimeoutMs
|
|
360
|
+
};
|
|
361
|
+
}
|
|
283
362
|
}
|
|
284
363
|
function parseTokenResponse(data) {
|
|
285
364
|
const d = data;
|
|
@@ -1272,11 +1351,11 @@ function baseUrl(endpointUrl) {
|
|
|
1272
1351
|
return endpointUrl.replace(/\/+$/, "");
|
|
1273
1352
|
}
|
|
1274
1353
|
async function postPkgseerGraphql(request) {
|
|
1275
|
-
const fetchFn = request.fetchFn ?? globalThis.fetch;
|
|
1276
1354
|
const userAgent = request.userAgent ?? `githits-cli/${version}`;
|
|
1355
|
+
const timeoutMs = request.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;
|
|
1277
1356
|
let response;
|
|
1278
1357
|
try {
|
|
1279
|
-
response = await
|
|
1358
|
+
response = await fetchWithTimeout(`${baseUrl(request.endpointUrl)}/api/graphql`, {
|
|
1280
1359
|
method: "POST",
|
|
1281
1360
|
headers: {
|
|
1282
1361
|
...buildClientHeaders(),
|
|
@@ -1288,7 +1367,7 @@ async function postPkgseerGraphql(request) {
|
|
|
1288
1367
|
query: request.query,
|
|
1289
1368
|
variables: request.variables
|
|
1290
1369
|
})
|
|
1291
|
-
});
|
|
1370
|
+
}, { fetchFn: request.fetchFn, timeoutMs });
|
|
1292
1371
|
} catch (cause) {
|
|
1293
1372
|
debugLog("pkg-graphql", {
|
|
1294
1373
|
event: "transport-error",
|
|
@@ -1478,13 +1557,17 @@ function parseDetail(body) {
|
|
|
1478
1557
|
class GitHitsServiceImpl {
|
|
1479
1558
|
apiUrl;
|
|
1480
1559
|
token;
|
|
1481
|
-
|
|
1560
|
+
fetchFn;
|
|
1561
|
+
fetchTimeoutMs;
|
|
1562
|
+
constructor(apiUrl, token, fetchFn, fetchTimeoutMs = DEFAULT_FETCH_TIMEOUT_MS) {
|
|
1482
1563
|
this.apiUrl = apiUrl;
|
|
1483
1564
|
this.token = token;
|
|
1565
|
+
this.fetchFn = fetchFn;
|
|
1566
|
+
this.fetchTimeoutMs = fetchTimeoutMs;
|
|
1484
1567
|
}
|
|
1485
1568
|
async search(params) {
|
|
1486
1569
|
return withTelemetrySpan("githits.search.request", async () => {
|
|
1487
|
-
const response = await
|
|
1570
|
+
const response = await fetchWithTimeout(`${this.apiUrl}/search`, {
|
|
1488
1571
|
method: "POST",
|
|
1489
1572
|
headers: this.headers(),
|
|
1490
1573
|
body: JSON.stringify({
|
|
@@ -1493,7 +1576,7 @@ class GitHitsServiceImpl {
|
|
|
1493
1576
|
license_mode: params.licenseMode ?? "strict",
|
|
1494
1577
|
include_explanation: params.includeExplanation ?? false
|
|
1495
1578
|
})
|
|
1496
|
-
});
|
|
1579
|
+
}, this.fetchOptions());
|
|
1497
1580
|
if (!response.ok) {
|
|
1498
1581
|
throw await this.createError(response);
|
|
1499
1582
|
}
|
|
@@ -1502,9 +1585,9 @@ class GitHitsServiceImpl {
|
|
|
1502
1585
|
}
|
|
1503
1586
|
async getLanguages() {
|
|
1504
1587
|
return withTelemetrySpan("githits.languages.request", async () => {
|
|
1505
|
-
const response = await
|
|
1588
|
+
const response = await fetchWithTimeout(`${this.apiUrl}/languages`, {
|
|
1506
1589
|
headers: this.headers()
|
|
1507
|
-
});
|
|
1590
|
+
}, this.fetchOptions());
|
|
1508
1591
|
if (!response.ok) {
|
|
1509
1592
|
throw await this.createError(response);
|
|
1510
1593
|
}
|
|
@@ -1513,7 +1596,7 @@ class GitHitsServiceImpl {
|
|
|
1513
1596
|
}
|
|
1514
1597
|
async submitFeedback(params) {
|
|
1515
1598
|
return withTelemetrySpan("githits.feedback.request", async () => {
|
|
1516
|
-
const response = await
|
|
1599
|
+
const response = await fetchWithTimeout(`${this.apiUrl}/feedbacks`, {
|
|
1517
1600
|
method: "POST",
|
|
1518
1601
|
headers: this.headers(),
|
|
1519
1602
|
body: JSON.stringify({
|
|
@@ -1529,7 +1612,7 @@ class GitHitsServiceImpl {
|
|
|
1529
1612
|
tool_name: params.toolName
|
|
1530
1613
|
}
|
|
1531
1614
|
})
|
|
1532
|
-
});
|
|
1615
|
+
}, this.fetchOptions());
|
|
1533
1616
|
if (!response.ok) {
|
|
1534
1617
|
throw await this.createError(response);
|
|
1535
1618
|
}
|
|
@@ -1544,6 +1627,12 @@ class GitHitsServiceImpl {
|
|
|
1544
1627
|
"User-Agent": `githits-cli/${version}`
|
|
1545
1628
|
};
|
|
1546
1629
|
}
|
|
1630
|
+
fetchOptions() {
|
|
1631
|
+
return {
|
|
1632
|
+
fetchFn: this.fetchFn,
|
|
1633
|
+
timeoutMs: this.fetchTimeoutMs
|
|
1634
|
+
};
|
|
1635
|
+
}
|
|
1547
1636
|
async createError(response) {
|
|
1548
1637
|
const status = response.status;
|
|
1549
1638
|
const body = await response.text().catch(() => "");
|
|
@@ -2628,7 +2717,7 @@ class CodeNavigationServiceImpl {
|
|
|
2628
2717
|
});
|
|
2629
2718
|
} catch (cause) {
|
|
2630
2719
|
if (cause instanceof PkgseerTransportError) {
|
|
2631
|
-
throw
|
|
2720
|
+
throw this.createTransportError(cause);
|
|
2632
2721
|
}
|
|
2633
2722
|
throw cause;
|
|
2634
2723
|
}
|
|
@@ -2661,7 +2750,7 @@ class CodeNavigationServiceImpl {
|
|
|
2661
2750
|
});
|
|
2662
2751
|
} catch (cause) {
|
|
2663
2752
|
if (cause instanceof PkgseerTransportError) {
|
|
2664
|
-
throw
|
|
2753
|
+
throw this.createTransportError(cause);
|
|
2665
2754
|
}
|
|
2666
2755
|
throw cause;
|
|
2667
2756
|
}
|
|
@@ -2712,6 +2801,12 @@ class CodeNavigationServiceImpl {
|
|
|
2712
2801
|
}
|
|
2713
2802
|
return new CodeNavigationBackendError(detail ?? `Request failed with status ${status}`, status);
|
|
2714
2803
|
}
|
|
2804
|
+
createTransportError(error) {
|
|
2805
|
+
if (isFetchTimeoutError(error.cause)) {
|
|
2806
|
+
return new CodeNavigationBackendError("Code navigation request timed out.", undefined, "TIMEOUT", true);
|
|
2807
|
+
}
|
|
2808
|
+
return new CodeNavigationNetworkError("Could not reach the code navigation service. Check your connection or set GITHITS_CODE_NAV_URL.", { cause: error });
|
|
2809
|
+
}
|
|
2715
2810
|
createGraphQLError(errors) {
|
|
2716
2811
|
const message = errors.map((error) => error.message).join(", ");
|
|
2717
2812
|
const extensions = getPrimaryExtensions(errors);
|
|
@@ -2975,7 +3070,7 @@ class CodeNavigationServiceImpl {
|
|
|
2975
3070
|
});
|
|
2976
3071
|
} catch (cause) {
|
|
2977
3072
|
if (cause instanceof PkgseerTransportError) {
|
|
2978
|
-
throw
|
|
3073
|
+
throw this.createTransportError(cause);
|
|
2979
3074
|
}
|
|
2980
3075
|
throw cause;
|
|
2981
3076
|
}
|
|
@@ -3043,7 +3138,7 @@ class CodeNavigationServiceImpl {
|
|
|
3043
3138
|
});
|
|
3044
3139
|
} catch (cause) {
|
|
3045
3140
|
if (cause instanceof PkgseerTransportError) {
|
|
3046
|
-
throw
|
|
3141
|
+
throw this.createTransportError(cause);
|
|
3047
3142
|
}
|
|
3048
3143
|
throw cause;
|
|
3049
3144
|
}
|
|
@@ -3116,7 +3211,7 @@ class CodeNavigationServiceImpl {
|
|
|
3116
3211
|
});
|
|
3117
3212
|
} catch (cause) {
|
|
3118
3213
|
if (cause instanceof PkgseerTransportError) {
|
|
3119
|
-
throw
|
|
3214
|
+
throw this.createTransportError(cause);
|
|
3120
3215
|
}
|
|
3121
3216
|
throw cause;
|
|
3122
3217
|
}
|
|
@@ -5322,7 +5417,7 @@ class PackageIntelligenceServiceImpl {
|
|
|
5322
5417
|
});
|
|
5323
5418
|
} catch (cause) {
|
|
5324
5419
|
if (cause instanceof PkgseerTransportError) {
|
|
5325
|
-
throw
|
|
5420
|
+
throw this.createTransportError(cause);
|
|
5326
5421
|
}
|
|
5327
5422
|
throw cause;
|
|
5328
5423
|
}
|
|
@@ -5356,6 +5451,12 @@ class PackageIntelligenceServiceImpl {
|
|
|
5356
5451
|
}
|
|
5357
5452
|
return new PackageIntelligenceBackendError(detail ?? `Request failed with status ${status}`, status);
|
|
5358
5453
|
}
|
|
5454
|
+
createTransportError(error) {
|
|
5455
|
+
if (isFetchTimeoutError(error.cause)) {
|
|
5456
|
+
return new PackageIntelligenceBackendError("Package intelligence request timed out.", undefined, "TIMEOUT", true);
|
|
5457
|
+
}
|
|
5458
|
+
return new PackageIntelligenceNetworkError("Could not reach the package intelligence service. Check your connection or set GITHITS_CODE_NAV_URL.", { cause: error });
|
|
5459
|
+
}
|
|
5359
5460
|
createGraphQLError(errors) {
|
|
5360
5461
|
const message = errors.map((error) => error.message).join(", ");
|
|
5361
5462
|
const extensions = getPrimaryExtensions2(errors);
|
|
@@ -5527,7 +5628,7 @@ class PackageIntelligenceServiceImpl {
|
|
|
5527
5628
|
});
|
|
5528
5629
|
} catch (cause) {
|
|
5529
5630
|
if (cause instanceof PkgseerTransportError) {
|
|
5530
|
-
throw
|
|
5631
|
+
throw this.createTransportError(cause);
|
|
5531
5632
|
}
|
|
5532
5633
|
throw cause;
|
|
5533
5634
|
}
|
|
@@ -5631,7 +5732,7 @@ class PackageIntelligenceServiceImpl {
|
|
|
5631
5732
|
});
|
|
5632
5733
|
} catch (cause) {
|
|
5633
5734
|
if (cause instanceof PkgseerTransportError) {
|
|
5634
|
-
throw
|
|
5735
|
+
throw this.createTransportError(cause);
|
|
5635
5736
|
}
|
|
5636
5737
|
throw cause;
|
|
5637
5738
|
}
|
|
@@ -5670,7 +5771,7 @@ class PackageIntelligenceServiceImpl {
|
|
|
5670
5771
|
});
|
|
5671
5772
|
} catch (cause) {
|
|
5672
5773
|
if (cause instanceof PkgseerTransportError) {
|
|
5673
|
-
throw
|
|
5774
|
+
throw this.createTransportError(cause);
|
|
5674
5775
|
}
|
|
5675
5776
|
throw cause;
|
|
5676
5777
|
}
|
|
@@ -5907,7 +6008,7 @@ class PackageIntelligenceServiceImpl {
|
|
|
5907
6008
|
});
|
|
5908
6009
|
} catch (cause) {
|
|
5909
6010
|
if (cause instanceof PkgseerTransportError) {
|
|
5910
|
-
throw
|
|
6011
|
+
throw this.createTransportError(cause);
|
|
5911
6012
|
}
|
|
5912
6013
|
throw cause;
|
|
5913
6014
|
}
|
|
@@ -5982,7 +6083,7 @@ class PackageIntelligenceServiceImpl {
|
|
|
5982
6083
|
});
|
|
5983
6084
|
} catch (cause) {
|
|
5984
6085
|
if (cause instanceof PkgseerTransportError) {
|
|
5985
|
-
throw
|
|
6086
|
+
throw this.createTransportError(cause);
|
|
5986
6087
|
}
|
|
5987
6088
|
throw cause;
|
|
5988
6089
|
}
|
|
@@ -6051,7 +6152,7 @@ class PackageIntelligenceServiceImpl {
|
|
|
6051
6152
|
});
|
|
6052
6153
|
} catch (cause) {
|
|
6053
6154
|
if (cause instanceof PkgseerTransportError) {
|
|
6054
|
-
throw
|
|
6155
|
+
throw this.createTransportError(cause);
|
|
6055
6156
|
}
|
|
6056
6157
|
throw cause;
|
|
6057
6158
|
}
|
|
@@ -6217,7 +6318,8 @@ class TokenManager {
|
|
|
6217
6318
|
authStorage;
|
|
6218
6319
|
mcpUrl;
|
|
6219
6320
|
cachedToken = null;
|
|
6220
|
-
|
|
6321
|
+
softRefreshPromise = null;
|
|
6322
|
+
forceRefreshPromise = null;
|
|
6221
6323
|
constructor(deps) {
|
|
6222
6324
|
this.authService = deps.authService;
|
|
6223
6325
|
this.authStorage = deps.authStorage;
|
|
@@ -6225,6 +6327,9 @@ class TokenManager {
|
|
|
6225
6327
|
}
|
|
6226
6328
|
async getToken() {
|
|
6227
6329
|
return withTelemetrySpan("token-manager.get-token", async () => {
|
|
6330
|
+
if (this.forceRefreshPromise) {
|
|
6331
|
+
return (await this.forceRefreshPromise).accessToken;
|
|
6332
|
+
}
|
|
6228
6333
|
if (!this.cachedToken) {
|
|
6229
6334
|
this.cachedToken = await withTelemetrySpan("token-manager.load-tokens", () => this.authStorage.loadTokens(this.mcpUrl));
|
|
6230
6335
|
if (!this.cachedToken)
|
|
@@ -6235,7 +6340,9 @@ class TokenManager {
|
|
|
6235
6340
|
if (!shouldRefresh) {
|
|
6236
6341
|
return currentToken;
|
|
6237
6342
|
}
|
|
6238
|
-
const refreshedToken = await this.doRefresh(
|
|
6343
|
+
const refreshedToken = await this.doRefresh({
|
|
6344
|
+
allowFreshExternalToken: true
|
|
6345
|
+
});
|
|
6239
6346
|
if (refreshedToken) {
|
|
6240
6347
|
return refreshedToken;
|
|
6241
6348
|
}
|
|
@@ -6246,27 +6353,56 @@ class TokenManager {
|
|
|
6246
6353
|
});
|
|
6247
6354
|
}
|
|
6248
6355
|
async forceRefresh() {
|
|
6249
|
-
return withTelemetrySpan("token-manager.force-refresh", () => this.doRefresh());
|
|
6250
|
-
}
|
|
6251
|
-
async doRefresh() {
|
|
6252
|
-
|
|
6253
|
-
|
|
6356
|
+
return withTelemetrySpan("token-manager.force-refresh", () => this.doRefresh({ allowFreshExternalToken: false }));
|
|
6357
|
+
}
|
|
6358
|
+
async doRefresh(options) {
|
|
6359
|
+
const result = await this.doRefreshResult(options);
|
|
6360
|
+
return result.accessToken;
|
|
6361
|
+
}
|
|
6362
|
+
async doRefreshResult(options) {
|
|
6363
|
+
if (!options.allowFreshExternalToken) {
|
|
6364
|
+
if (this.forceRefreshPromise)
|
|
6365
|
+
return this.forceRefreshPromise;
|
|
6366
|
+
this.forceRefreshPromise = (async () => {
|
|
6367
|
+
const softResult = await this.softRefreshPromise?.catch(() => {
|
|
6368
|
+
return;
|
|
6369
|
+
});
|
|
6370
|
+
if (softResult?.accessToken && softResult.refreshedViaEndpoint) {
|
|
6371
|
+
return softResult;
|
|
6372
|
+
}
|
|
6373
|
+
return this.executeRefresh(options);
|
|
6374
|
+
})();
|
|
6375
|
+
try {
|
|
6376
|
+
return await this.forceRefreshPromise;
|
|
6377
|
+
} finally {
|
|
6378
|
+
this.forceRefreshPromise = null;
|
|
6379
|
+
}
|
|
6254
6380
|
}
|
|
6255
|
-
|
|
6381
|
+
if (this.forceRefreshPromise)
|
|
6382
|
+
return this.forceRefreshPromise;
|
|
6383
|
+
if (this.softRefreshPromise)
|
|
6384
|
+
return this.softRefreshPromise;
|
|
6385
|
+
this.softRefreshPromise = this.executeRefresh(options);
|
|
6256
6386
|
try {
|
|
6257
|
-
return await this.
|
|
6387
|
+
return await this.softRefreshPromise;
|
|
6258
6388
|
} finally {
|
|
6259
|
-
this.
|
|
6389
|
+
this.softRefreshPromise = null;
|
|
6260
6390
|
}
|
|
6261
6391
|
}
|
|
6262
|
-
async executeRefresh() {
|
|
6392
|
+
async executeRefresh(options) {
|
|
6263
6393
|
return withTelemetrySpan("token-manager.refresh", async () => {
|
|
6264
|
-
const
|
|
6265
|
-
if (!
|
|
6266
|
-
return;
|
|
6394
|
+
const candidate = await this.loadRefreshCandidate();
|
|
6395
|
+
if (!candidate)
|
|
6396
|
+
return refreshResult(undefined, false);
|
|
6397
|
+
if (candidate.externallyUpdated && options.allowFreshExternalToken) {
|
|
6398
|
+
const { shouldRefresh } = shouldRefreshToken(candidate.tokens, PROACTIVE_REFRESH_RATIO, new Date);
|
|
6399
|
+
if (!shouldRefresh)
|
|
6400
|
+
return refreshResult(candidate.tokens.accessToken, false);
|
|
6401
|
+
}
|
|
6402
|
+
const tokens = candidate.tokens;
|
|
6267
6403
|
const client = await withTelemetrySpan("token-manager.load-client", () => this.authStorage.loadClient(this.mcpUrl));
|
|
6268
6404
|
if (!client)
|
|
6269
|
-
return;
|
|
6405
|
+
return refreshResult(undefined, false);
|
|
6270
6406
|
let response;
|
|
6271
6407
|
try {
|
|
6272
6408
|
const metadata = await withTelemetrySpan("token-manager.discover-endpoints", () => this.authService.discoverEndpoints(this.mcpUrl));
|
|
@@ -6279,21 +6415,25 @@ class TokenManager {
|
|
|
6279
6415
|
} catch {
|
|
6280
6416
|
const reloadedToken = await this.loadExternallyUpdatedToken(tokens);
|
|
6281
6417
|
if (reloadedToken)
|
|
6282
|
-
return reloadedToken.accessToken;
|
|
6418
|
+
return refreshResult(reloadedToken.accessToken, false);
|
|
6283
6419
|
const isExpired = tokens.expiresAt ? new Date >= new Date(tokens.expiresAt) : false;
|
|
6420
|
+
if (candidate.externallyUpdated && !isExpired) {
|
|
6421
|
+
return refreshResult(tokens.accessToken, false);
|
|
6422
|
+
}
|
|
6284
6423
|
if (isExpired) {
|
|
6285
6424
|
const currentStoredTokens = await this.loadExternallyUpdatedToken(tokens);
|
|
6286
|
-
if (currentStoredTokens)
|
|
6287
|
-
return currentStoredTokens.accessToken;
|
|
6425
|
+
if (currentStoredTokens) {
|
|
6426
|
+
return refreshResult(currentStoredTokens.accessToken, false);
|
|
6427
|
+
}
|
|
6288
6428
|
const cleared = await withTelemetrySpan("token-manager.clear-tokens-if-unchanged", () => this.authStorage.clearTokensIfUnchanged(this.mcpUrl, tokens));
|
|
6289
6429
|
if (!cleared) {
|
|
6290
6430
|
const currentToken = await this.authStorage.loadTokens(this.mcpUrl);
|
|
6291
6431
|
this.cachedToken = currentToken;
|
|
6292
|
-
return currentToken?.accessToken;
|
|
6432
|
+
return refreshResult(currentToken?.accessToken, false);
|
|
6293
6433
|
}
|
|
6294
6434
|
this.cachedToken = null;
|
|
6295
6435
|
}
|
|
6296
|
-
return;
|
|
6436
|
+
return refreshResult(undefined, false);
|
|
6297
6437
|
}
|
|
6298
6438
|
const newTokenData = {
|
|
6299
6439
|
accessToken: response.accessToken,
|
|
@@ -6301,30 +6441,53 @@ class TokenManager {
|
|
|
6301
6441
|
expiresAt: new Date(Date.now() + response.expiresIn * 1000).toISOString(),
|
|
6302
6442
|
createdAt: new Date().toISOString()
|
|
6303
6443
|
};
|
|
6304
|
-
const externallyUpdatedToken = await this.loadExternallyUpdatedToken(tokens, {
|
|
6305
|
-
treatMissingAsExternalUpdate: true
|
|
6306
|
-
});
|
|
6307
|
-
if (externallyUpdatedToken === null)
|
|
6308
|
-
return;
|
|
6309
|
-
if (externallyUpdatedToken)
|
|
6310
|
-
return externallyUpdatedToken.accessToken;
|
|
6311
6444
|
const saved = await withTelemetrySpan("token-manager.save-tokens", () => this.authStorage.saveTokensIfUnchanged(this.mcpUrl, tokens, newTokenData));
|
|
6312
6445
|
if (!saved) {
|
|
6313
|
-
|
|
6314
|
-
this.cachedToken = currentToken;
|
|
6315
|
-
return currentToken?.accessToken;
|
|
6446
|
+
return this.resolveSuccessfulRefreshConflict(tokens, response, newTokenData);
|
|
6316
6447
|
}
|
|
6317
6448
|
this.cachedToken = newTokenData;
|
|
6318
|
-
return response.accessToken;
|
|
6449
|
+
return refreshResult(response.accessToken, true);
|
|
6319
6450
|
});
|
|
6320
6451
|
}
|
|
6321
|
-
async
|
|
6322
|
-
const
|
|
6452
|
+
async resolveSuccessfulRefreshConflict(refreshedFrom, response, newTokenData) {
|
|
6453
|
+
const currentToken = await withTelemetrySpan("token-manager.reload-tokens", () => this.authStorage.loadTokens(this.mcpUrl));
|
|
6454
|
+
if (!currentToken) {
|
|
6455
|
+
this.cachedToken = null;
|
|
6456
|
+
return refreshResult(undefined, false);
|
|
6457
|
+
}
|
|
6458
|
+
if (!response.refreshToken || currentToken.refreshToken !== refreshedFrom.refreshToken) {
|
|
6459
|
+
this.cachedToken = currentToken;
|
|
6460
|
+
return refreshResult(currentToken.accessToken, false);
|
|
6461
|
+
}
|
|
6462
|
+
const saved = await withTelemetrySpan("token-manager.save-rotated-tokens-after-conflict", () => this.authStorage.saveTokensIfUnchanged(this.mcpUrl, currentToken, newTokenData));
|
|
6463
|
+
if (saved) {
|
|
6464
|
+
this.cachedToken = newTokenData;
|
|
6465
|
+
return refreshResult(newTokenData.accessToken, true);
|
|
6466
|
+
}
|
|
6467
|
+
const latestToken = await withTelemetrySpan("token-manager.reload-tokens", () => this.authStorage.loadTokens(this.mcpUrl));
|
|
6468
|
+
this.cachedToken = latestToken;
|
|
6469
|
+
return refreshResult(latestToken?.accessToken, false);
|
|
6470
|
+
}
|
|
6471
|
+
async loadRefreshCandidate() {
|
|
6472
|
+
const storedTokens = await withTelemetrySpan("token-manager.load-tokens", () => this.authStorage.loadTokens(this.mcpUrl));
|
|
6473
|
+
if (!this.cachedToken) {
|
|
6474
|
+
this.cachedToken = storedTokens;
|
|
6475
|
+
return storedTokens ? { tokens: storedTokens, externallyUpdated: false } : null;
|
|
6476
|
+
}
|
|
6323
6477
|
if (!storedTokens) {
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6478
|
+
this.cachedToken = null;
|
|
6479
|
+
return null;
|
|
6480
|
+
}
|
|
6481
|
+
if (!areSameTokenData(storedTokens, this.cachedToken)) {
|
|
6482
|
+
this.cachedToken = storedTokens;
|
|
6483
|
+
return { tokens: storedTokens, externallyUpdated: true };
|
|
6327
6484
|
}
|
|
6485
|
+
return { tokens: this.cachedToken, externallyUpdated: false };
|
|
6486
|
+
}
|
|
6487
|
+
async loadExternallyUpdatedToken(failedTokens) {
|
|
6488
|
+
const storedTokens = await withTelemetrySpan("token-manager.reload-tokens", () => this.authStorage.loadTokens(this.mcpUrl));
|
|
6489
|
+
if (!storedTokens)
|
|
6490
|
+
return;
|
|
6328
6491
|
if (areSameTokenData(storedTokens, failedTokens))
|
|
6329
6492
|
return;
|
|
6330
6493
|
this.cachedToken = storedTokens;
|
|
@@ -6334,6 +6497,9 @@ class TokenManager {
|
|
|
6334
6497
|
function areSameTokenData(a, b) {
|
|
6335
6498
|
return a.accessToken === b.accessToken && a.refreshToken === b.refreshToken && a.expiresAt === b.expiresAt && a.createdAt === b.createdAt;
|
|
6336
6499
|
}
|
|
6500
|
+
function refreshResult(accessToken, refreshedViaEndpoint) {
|
|
6501
|
+
return { accessToken, refreshedViaEndpoint };
|
|
6502
|
+
}
|
|
6337
6503
|
// src/services/update-check-service.ts
|
|
6338
6504
|
import semver from "semver";
|
|
6339
6505
|
var NPM_DIST_TAGS_URL = "https://registry.npmjs.org/-/package/githits/dist-tags";
|
|
@@ -6785,4 +6951,4 @@ async function createContainer(options = {}) {
|
|
|
6785
6951
|
});
|
|
6786
6952
|
}
|
|
6787
6953
|
|
|
6788
|
-
export { AuthConfigError, CLIENT_UPDATE_REQUIRED_REASON, ClientUpdateRequiredError, debugLog, setMcpClientVersionProvider, setClientMode, isTelemetryEnabled, withTelemetrySpan, startTelemetrySpan, endTelemetrySpan, flushTelemetry, AuthenticationError, CodeNavigationAccessError, CodeNavigationGraphQLError, CodeNavigationIndexingError, CodeNavigationUnresolvableError, MalformedCodeNavigationResponseError, CodeNavigationTargetNotFoundError, CodeNavigationFileNotFoundError, CodeNavigationVersionNotFoundError, CodeNavigationValidationError, CodeNavigationFeatureFlagRequiredError, CodeNavigationNetworkError, CodeNavigationBackendError, getCodeNavigationUrl, ExecServiceImpl, FileSystemServiceImpl, AuthStorageLockTimeoutError, AuthStoragePolicyError, PackageIntelligenceAccessError, PackageIntelligenceFeatureFlagRequiredError, PackageIntelligenceNetworkError, PackageIntelligenceBackendError, PackageIntelligenceGraphQLError, PackageIntelligenceTargetNotFoundError, PackageIntelligenceValidationError, PackageIntelligenceVersionNotFoundError, MalformedPackageIntelligenceResponseError, PackageIntelligenceChangelogSourceNotFoundError, PromptServiceImpl, refreshExpiredToken, NpmRegistryUpdateCheckService, shouldRunUpdateCheck, shouldRunRequiredUpdateEnforcement, formatUpdateNotice, formatRequiredUpdateNotice, loadAutoLoginAuthSessionMetadata, clearAutoLoginAuthSessionMetadata, createAuthCommandDependencies, createAuthStatusDependencies, createContainer };
|
|
6954
|
+
export { getAppConfigDirForEnv, getAuthConfigPathForEnv, getAuthFileStorageDirForEnv, getLegacyAuthStorageDirForEnv, getLegacyMacAuthConfigPathForEnv, getLegacyMacAuthFileStorageDirForEnv, AuthConfigError, parseAuthStorageMode, normalizeBaseUrl, CLIENT_UPDATE_REQUIRED_REASON, ClientUpdateRequiredError, debugLog, setMcpClientVersionProvider, setClientMode, isTelemetryEnabled, withTelemetrySpan, startTelemetrySpan, endTelemetrySpan, flushTelemetry, AuthenticationError, CodeNavigationAccessError, CodeNavigationGraphQLError, CodeNavigationIndexingError, CodeNavigationUnresolvableError, MalformedCodeNavigationResponseError, CodeNavigationTargetNotFoundError, CodeNavigationFileNotFoundError, CodeNavigationVersionNotFoundError, CodeNavigationValidationError, CodeNavigationFeatureFlagRequiredError, CodeNavigationNetworkError, CodeNavigationBackendError, DEFAULT_MCP_URL, DEFAULT_API_URL, DEFAULT_CODE_NAV_URL, getCodeNavigationUrl, ExecServiceImpl, FileSystemServiceImpl, AuthStorageLockTimeoutError, AuthStoragePolicyError, PackageIntelligenceAccessError, PackageIntelligenceFeatureFlagRequiredError, PackageIntelligenceNetworkError, PackageIntelligenceBackendError, PackageIntelligenceGraphQLError, PackageIntelligenceTargetNotFoundError, PackageIntelligenceValidationError, PackageIntelligenceVersionNotFoundError, MalformedPackageIntelligenceResponseError, PackageIntelligenceChangelogSourceNotFoundError, PromptServiceImpl, refreshExpiredToken, NpmRegistryUpdateCheckService, shouldRunUpdateCheck, shouldRunRequiredUpdateEnforcement, formatUpdateNotice, formatRequiredUpdateNotice, loadAutoLoginAuthSessionMetadata, clearAutoLoginAuthSessionMetadata, createAuthCommandDependencies, createAuthStatusDependencies, createContainer };
|
package/gemini-extension.json
CHANGED