githits 0.4.0 → 0.4.2
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/dist/cli.js +467 -436
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-fqzth5mv.js → chunk-jdygt0ra.js} +1 -1
- package/dist/shared/{chunk-1h7sanjw.js → chunk-q2mre780.js} +2 -2
- package/dist/shared/{chunk-1cyka46a.js → chunk-v8sths32.js} +1 -1
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
package/.plugin/plugin.json
CHANGED
package/dist/cli.js
CHANGED
|
@@ -49,11 +49,11 @@ import {
|
|
|
49
49
|
shouldRunUpdateCheck,
|
|
50
50
|
startTelemetrySpan,
|
|
51
51
|
withTelemetrySpan
|
|
52
|
-
} from "./shared/chunk-
|
|
52
|
+
} from "./shared/chunk-v8sths32.js";
|
|
53
53
|
import {
|
|
54
54
|
__require,
|
|
55
55
|
version
|
|
56
|
-
} from "./shared/chunk-
|
|
56
|
+
} from "./shared/chunk-jdygt0ra.js";
|
|
57
57
|
|
|
58
58
|
// src/cli.ts
|
|
59
59
|
import { Command } from "commander";
|
|
@@ -411,6 +411,19 @@ function dim(text, useColors) {
|
|
|
411
411
|
}
|
|
412
412
|
|
|
413
413
|
// src/shared/pkgseer-registry.ts
|
|
414
|
+
var PKGSEER_REGISTRY_ARGS = [
|
|
415
|
+
"npm",
|
|
416
|
+
"pypi",
|
|
417
|
+
"hex",
|
|
418
|
+
"crates",
|
|
419
|
+
"nuget",
|
|
420
|
+
"maven",
|
|
421
|
+
"zig",
|
|
422
|
+
"vcpkg",
|
|
423
|
+
"packagist",
|
|
424
|
+
"rubygems",
|
|
425
|
+
"go"
|
|
426
|
+
];
|
|
414
427
|
var registryMap = {
|
|
415
428
|
npm: "NPM",
|
|
416
429
|
pypi: "PYPI",
|
|
@@ -420,8 +433,11 @@ var registryMap = {
|
|
|
420
433
|
maven: "MAVEN",
|
|
421
434
|
zig: "ZIG",
|
|
422
435
|
vcpkg: "VCPKG",
|
|
423
|
-
packagist: "PACKAGIST"
|
|
436
|
+
packagist: "PACKAGIST",
|
|
437
|
+
rubygems: "RUBYGEMS",
|
|
438
|
+
go: "GO"
|
|
424
439
|
};
|
|
440
|
+
var PKGSEER_REGISTRY_LIST = PKGSEER_REGISTRY_ARGS.join(", ");
|
|
425
441
|
function toPkgseerRegistry(registry) {
|
|
426
442
|
return registryMap[registry];
|
|
427
443
|
}
|
|
@@ -688,22 +704,12 @@ function isInvalidArgumentError(error2) {
|
|
|
688
704
|
return error2.name.startsWith("Invalid") || error2.name.startsWith("Unsupported");
|
|
689
705
|
}
|
|
690
706
|
// src/shared/package-spec.ts
|
|
691
|
-
var KNOWN_REGISTRIES =
|
|
692
|
-
"npm",
|
|
693
|
-
"pypi",
|
|
694
|
-
"hex",
|
|
695
|
-
"crates",
|
|
696
|
-
"nuget",
|
|
697
|
-
"maven",
|
|
698
|
-
"zig",
|
|
699
|
-
"vcpkg",
|
|
700
|
-
"packagist"
|
|
701
|
-
];
|
|
707
|
+
var KNOWN_REGISTRIES = PKGSEER_REGISTRY_ARGS;
|
|
702
708
|
|
|
703
709
|
class UnsupportedRegistryError extends Error {
|
|
704
710
|
attempted;
|
|
705
711
|
constructor(attempted) {
|
|
706
|
-
super(`Unsupported registry "${attempted}". Supported: ${
|
|
712
|
+
super(`Unsupported registry "${attempted}". Supported: ${PKGSEER_REGISTRY_LIST}.`);
|
|
707
713
|
this.attempted = attempted;
|
|
708
714
|
this.name = "UnsupportedRegistryError";
|
|
709
715
|
}
|
|
@@ -1764,7 +1770,7 @@ function buildListPackageDocsParams(input) {
|
|
|
1764
1770
|
}
|
|
1765
1771
|
const registry = input.registry?.trim().toLowerCase() ?? "";
|
|
1766
1772
|
if (!isKnownPkgseerRegistryArg(registry)) {
|
|
1767
|
-
throw new UnsupportedRegistryError(`Unsupported registry '${input.registry}'. Supported:
|
|
1773
|
+
throw new UnsupportedRegistryError(`Unsupported registry '${input.registry}'. Supported: ${PKGSEER_REGISTRY_LIST}.`);
|
|
1768
1774
|
}
|
|
1769
1775
|
const params = {
|
|
1770
1776
|
registry: toPkgseerRegistry(registry),
|
|
@@ -2012,9 +2018,11 @@ var SUPPORTED_DEPS_REGISTRIES = new Set([
|
|
|
2012
2018
|
"HEX",
|
|
2013
2019
|
"CRATES",
|
|
2014
2020
|
"VCPKG",
|
|
2015
|
-
"ZIG"
|
|
2021
|
+
"ZIG",
|
|
2022
|
+
"RUBYGEMS",
|
|
2023
|
+
"GO"
|
|
2016
2024
|
]);
|
|
2017
|
-
var SUPPORTED_DEPS_REGISTRIES_HUMAN = "npm, pypi, hex, crates, vcpkg, and
|
|
2025
|
+
var SUPPORTED_DEPS_REGISTRIES_HUMAN = "npm, pypi, hex, crates, vcpkg, zig, rubygems, and go";
|
|
2018
2026
|
function supportsDependenciesRegistry(registry) {
|
|
2019
2027
|
return SUPPORTED_DEPS_REGISTRIES.has(registry);
|
|
2020
2028
|
}
|
|
@@ -2025,7 +2033,7 @@ function buildPackageDependenciesParams(input) {
|
|
|
2025
2033
|
}
|
|
2026
2034
|
const normalisedRegistryArg = input.registry?.trim().toLowerCase() ?? "";
|
|
2027
2035
|
if (!isKnownPkgseerRegistryArg(normalisedRegistryArg)) {
|
|
2028
|
-
throw new UnsupportedRegistryError(`Unsupported registry '${input.registry}'. Supported:
|
|
2036
|
+
throw new UnsupportedRegistryError(`Unsupported registry '${input.registry}'. Supported: ${PKGSEER_REGISTRY_LIST}.`);
|
|
2029
2037
|
}
|
|
2030
2038
|
const registry = toPkgseerRegistry(normalisedRegistryArg);
|
|
2031
2039
|
if (!supportsDependenciesRegistry(registry)) {
|
|
@@ -2831,7 +2839,7 @@ function buildPackageSummaryParams(input) {
|
|
|
2831
2839
|
}
|
|
2832
2840
|
const normalisedRegistry = input.registry?.trim().toLowerCase() ?? "";
|
|
2833
2841
|
if (!isKnownPkgseerRegistryArg(normalisedRegistry)) {
|
|
2834
|
-
throw new UnsupportedRegistryError(`Unsupported registry '${input.registry}'. Supported:
|
|
2842
|
+
throw new UnsupportedRegistryError(`Unsupported registry '${input.registry}'. Supported: ${PKGSEER_REGISTRY_LIST}.`);
|
|
2835
2843
|
}
|
|
2836
2844
|
return {
|
|
2837
2845
|
params: {
|
|
@@ -3233,7 +3241,7 @@ function buildPackageVulnerabilitiesParams(input) {
|
|
|
3233
3241
|
}
|
|
3234
3242
|
const normalisedRegistryArg = input.registry?.trim().toLowerCase() ?? "";
|
|
3235
3243
|
if (!isKnownPkgseerRegistryArg(normalisedRegistryArg)) {
|
|
3236
|
-
throw new UnsupportedRegistryError(`Unsupported registry '${input.registry}'. Supported:
|
|
3244
|
+
throw new UnsupportedRegistryError(`Unsupported registry '${input.registry}'. Supported: ${PKGSEER_REGISTRY_LIST}.`);
|
|
3237
3245
|
}
|
|
3238
3246
|
const registry = toPkgseerRegistry(normalisedRegistryArg);
|
|
3239
3247
|
if (!supportsVulnerabilitiesRegistry(registry)) {
|
|
@@ -4168,150 +4176,437 @@ function buildRange2(envelope) {
|
|
|
4168
4176
|
return `${envelope.totalLines} lines`;
|
|
4169
4177
|
return;
|
|
4170
4178
|
}
|
|
4171
|
-
// src/
|
|
4172
|
-
var
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
"feedback",
|
|
4176
|
-
"search",
|
|
4177
|
-
"search-status",
|
|
4178
|
-
"code files",
|
|
4179
|
-
"code read",
|
|
4180
|
-
"code grep",
|
|
4181
|
-
"docs list",
|
|
4182
|
-
"docs read",
|
|
4183
|
-
"pkg info",
|
|
4184
|
-
"pkg vulns",
|
|
4185
|
-
"pkg deps",
|
|
4186
|
-
"pkg changelog"
|
|
4187
|
-
]);
|
|
4188
|
-
function getCommandPath(command) {
|
|
4189
|
-
const names = [];
|
|
4190
|
-
let current = command;
|
|
4191
|
-
while (current) {
|
|
4192
|
-
const name = current.name();
|
|
4193
|
-
if (name && name !== "githits") {
|
|
4194
|
-
names.unshift(name);
|
|
4195
|
-
}
|
|
4196
|
-
current = current.parent ?? null;
|
|
4179
|
+
// src/commands/login.ts
|
|
4180
|
+
var stdoutLoginOutput = {
|
|
4181
|
+
write: (message) => {
|
|
4182
|
+
console.log(message);
|
|
4197
4183
|
}
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
stdoutIsTTY: Boolean(process.stdout.isTTY)
|
|
4203
|
-
}) {
|
|
4204
|
-
const commandPath = getCommandPath(command).join(" ");
|
|
4205
|
-
if (!AUTO_LOGIN_ELIGIBLE_COMMANDS.has(commandPath)) {
|
|
4206
|
-
return false;
|
|
4184
|
+
};
|
|
4185
|
+
var stderrLoginOutput = {
|
|
4186
|
+
write: (message) => {
|
|
4187
|
+
console.error(message);
|
|
4207
4188
|
}
|
|
4208
|
-
|
|
4209
|
-
|
|
4189
|
+
};
|
|
4190
|
+
var TIMEOUT_MS = 5 * 60 * 1000;
|
|
4191
|
+
var AUTH_TIMEOUT_MESSAGE = "Authentication timed out after 5 minutes. The browser link has expired, so it will not work anymore. Run the same command again to try signing in again.";
|
|
4192
|
+
function randomPort() {
|
|
4193
|
+
return Math.floor(Math.random() * 2000) + 8000;
|
|
4194
|
+
}
|
|
4195
|
+
async function preflightAuthPersistence(authStorage, mcpUrl) {
|
|
4196
|
+
const probeUrl = `${mcpUrl.replace(/\/+$/, "")}/__githits_storage_probe__`;
|
|
4197
|
+
const probeClient = {
|
|
4198
|
+
clientId: "__githits_storage_probe__",
|
|
4199
|
+
clientSecret: "__githits_storage_probe__",
|
|
4200
|
+
redirectUri: "http://127.0.0.1:1/callback",
|
|
4201
|
+
registeredAt: new Date(0).toISOString()
|
|
4202
|
+
};
|
|
4203
|
+
const probeTokens = {
|
|
4204
|
+
accessToken: "__githits_storage_probe__",
|
|
4205
|
+
refreshToken: "__githits_storage_probe__",
|
|
4206
|
+
expiresAt: new Date(0).toISOString(),
|
|
4207
|
+
createdAt: new Date(0).toISOString()
|
|
4208
|
+
};
|
|
4209
|
+
try {
|
|
4210
|
+
await authStorage.saveAuthSession(probeUrl, probeClient, probeTokens);
|
|
4211
|
+
await authStorage.clearAuthSession(probeUrl);
|
|
4212
|
+
return null;
|
|
4213
|
+
} catch (error2) {
|
|
4214
|
+
await authStorage.clearAuthSession(probeUrl).catch(() => {});
|
|
4215
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
4216
|
+
return {
|
|
4217
|
+
status: "failed",
|
|
4218
|
+
message: `Cannot persist OAuth credentials: ${message}`
|
|
4219
|
+
};
|
|
4210
4220
|
}
|
|
4211
|
-
return true;
|
|
4212
4221
|
}
|
|
4213
|
-
async function
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4222
|
+
async function loginFlow(options, deps, output = stdoutLoginOutput) {
|
|
4223
|
+
const { authService, authStorage, browserService, mcpUrl } = deps;
|
|
4224
|
+
const existing = await authStorage.loadTokens(mcpUrl);
|
|
4225
|
+
if (options.port !== undefined && (Number.isNaN(options.port) || options.port < 1 || options.port > 65535)) {
|
|
4226
|
+
return {
|
|
4227
|
+
status: "failed",
|
|
4228
|
+
message: "Invalid port number. Must be between 1 and 65535."
|
|
4229
|
+
};
|
|
4219
4230
|
}
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4231
|
+
if (existing && !options.force) {
|
|
4232
|
+
const isExpired = existing.expiresAt && new Date(existing.expiresAt) < new Date;
|
|
4233
|
+
if (!isExpired) {
|
|
4234
|
+
return { status: "already_authenticated", message: "Already logged in." };
|
|
4235
|
+
}
|
|
4236
|
+
output.write(`Token expired. Starting new login...
|
|
4237
|
+
`);
|
|
4238
|
+
} else if (existing && options.force) {
|
|
4239
|
+
output.write(`Re-authenticating (--force flag)...
|
|
4240
|
+
`);
|
|
4223
4241
|
}
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
case "success":
|
|
4227
|
-
return { status: "authenticated", message: result.message };
|
|
4228
|
-
case "already_authenticated":
|
|
4229
|
-
return { status: "already-authenticated", message: result.message };
|
|
4230
|
-
case "failed":
|
|
4231
|
-
return { status: "failed", message: result.message };
|
|
4242
|
+
if (!existing) {
|
|
4243
|
+
await authStorage.clearClient(mcpUrl);
|
|
4232
4244
|
}
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4245
|
+
const persistenceError = await preflightAuthPersistence(authStorage, mcpUrl);
|
|
4246
|
+
if (persistenceError)
|
|
4247
|
+
return persistenceError;
|
|
4248
|
+
output.write("Discovering OAuth endpoints...");
|
|
4249
|
+
const metadata = await authService.discoverEndpoints(mcpUrl);
|
|
4250
|
+
let client = await authStorage.loadClient(mcpUrl);
|
|
4251
|
+
const hadStoredClient = client !== null;
|
|
4252
|
+
let shouldClearClientOnFailedAttempt = false;
|
|
4253
|
+
let port;
|
|
4254
|
+
let redirectUri;
|
|
4255
|
+
if (client) {
|
|
4256
|
+
if (options.port) {
|
|
4257
|
+
redirectUri = `http://127.0.0.1:${options.port}/callback`;
|
|
4258
|
+
if (redirectUri !== client.redirectUri) {
|
|
4259
|
+
output.write("Registering CLI client with new port...");
|
|
4260
|
+
const registration = await authService.registerClient({
|
|
4261
|
+
registrationEndpoint: metadata.registrationEndpoint,
|
|
4262
|
+
redirectUri
|
|
4263
|
+
});
|
|
4264
|
+
client = {
|
|
4265
|
+
clientId: registration.clientId,
|
|
4266
|
+
clientSecret: registration.clientSecret,
|
|
4267
|
+
redirectUri,
|
|
4268
|
+
registeredAt: new Date().toISOString()
|
|
4269
|
+
};
|
|
4270
|
+
shouldClearClientOnFailedAttempt = !hadStoredClient;
|
|
4251
4271
|
}
|
|
4272
|
+
port = options.port;
|
|
4273
|
+
} else {
|
|
4274
|
+
redirectUri = client.redirectUri;
|
|
4275
|
+
const storedUrl = new URL(redirectUri);
|
|
4276
|
+
port = Number(storedUrl.port) || randomPort();
|
|
4252
4277
|
}
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
}
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
case "feedback":
|
|
4269
|
-
return "Authentication complete. Submitting feedback...";
|
|
4270
|
-
case "search":
|
|
4271
|
-
case "search-status":
|
|
4272
|
-
case "code files":
|
|
4273
|
-
case "code read":
|
|
4274
|
-
case "code grep":
|
|
4275
|
-
case "docs list":
|
|
4276
|
-
case "docs read":
|
|
4277
|
-
case "pkg info":
|
|
4278
|
-
case "pkg vulns":
|
|
4279
|
-
case "pkg deps":
|
|
4280
|
-
case "pkg changelog":
|
|
4281
|
-
return "Authentication complete. Running command...";
|
|
4282
|
-
default:
|
|
4283
|
-
return;
|
|
4278
|
+
} else {
|
|
4279
|
+
port = options.port ?? randomPort();
|
|
4280
|
+
redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
4281
|
+
output.write("Registering CLI client...");
|
|
4282
|
+
const registration = await authService.registerClient({
|
|
4283
|
+
registrationEndpoint: metadata.registrationEndpoint,
|
|
4284
|
+
redirectUri
|
|
4285
|
+
});
|
|
4286
|
+
client = {
|
|
4287
|
+
clientId: registration.clientId,
|
|
4288
|
+
clientSecret: registration.clientSecret,
|
|
4289
|
+
redirectUri,
|
|
4290
|
+
registeredAt: new Date().toISOString()
|
|
4291
|
+
};
|
|
4292
|
+
shouldClearClientOnFailedAttempt = !hadStoredClient;
|
|
4284
4293
|
}
|
|
4285
|
-
}
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
const offset = input.offset ?? 0;
|
|
4293
|
-
const waitTimeoutMs = input.waitTimeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;
|
|
4294
|
-
const qualifierClauses = buildQualifierClauses({
|
|
4295
|
-
name: input.name,
|
|
4296
|
-
language: input.language
|
|
4297
|
-
});
|
|
4298
|
-
const compiledQuery = compileQuery(rawQuery, qualifierClauses);
|
|
4299
|
-
const filters = buildFilters({
|
|
4300
|
-
kind: input.kind,
|
|
4301
|
-
category: input.category,
|
|
4302
|
-
pathPrefix: input.pathPrefix,
|
|
4303
|
-
fileIntent: input.fileIntent,
|
|
4304
|
-
publicOnly: input.publicOnly
|
|
4294
|
+
const { verifier, challenge, state } = authService.generatePkceParams();
|
|
4295
|
+
const authUrl = authService.buildAuthUrl({
|
|
4296
|
+
authorizationEndpoint: metadata.authorizationEndpoint,
|
|
4297
|
+
clientId: client.clientId,
|
|
4298
|
+
redirectUri,
|
|
4299
|
+
state,
|
|
4300
|
+
codeChallenge: challenge
|
|
4305
4301
|
});
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4302
|
+
let callbackServer;
|
|
4303
|
+
try {
|
|
4304
|
+
callbackServer = await authService.startCallbackServer(port, state);
|
|
4305
|
+
} catch (error2) {
|
|
4306
|
+
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
4307
|
+
return { status: "failed", message: msg };
|
|
4308
|
+
}
|
|
4309
|
+
if (options.browser === false) {
|
|
4310
|
+
output.write(`Open this URL in your browser:
|
|
4311
|
+
`);
|
|
4312
|
+
output.write(` ${authUrl}
|
|
4313
|
+
`);
|
|
4314
|
+
} else {
|
|
4315
|
+
output.write("Opening browser...");
|
|
4316
|
+
try {
|
|
4317
|
+
await browserService.open(authUrl);
|
|
4318
|
+
} catch (error2) {
|
|
4319
|
+
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
4320
|
+
output.write(`Could not open browser automatically: ${msg}
|
|
4321
|
+
`);
|
|
4322
|
+
output.write(`Open this URL in your browser:
|
|
4323
|
+
`);
|
|
4324
|
+
output.write(` ${authUrl}
|
|
4325
|
+
`);
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4328
|
+
output.write(`Waiting for authentication...
|
|
4329
|
+
`);
|
|
4330
|
+
let timeoutId;
|
|
4331
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
4332
|
+
timeoutId = setTimeout(() => reject(new Error(AUTH_TIMEOUT_MESSAGE)), TIMEOUT_MS);
|
|
4333
|
+
});
|
|
4334
|
+
let callback;
|
|
4335
|
+
try {
|
|
4336
|
+
callback = await Promise.race([callbackServer.result, timeoutPromise]);
|
|
4337
|
+
if (timeoutId)
|
|
4338
|
+
clearTimeout(timeoutId);
|
|
4339
|
+
await callbackServer.close().catch(() => {});
|
|
4340
|
+
} catch (error2) {
|
|
4341
|
+
if (timeoutId)
|
|
4342
|
+
clearTimeout(timeoutId);
|
|
4343
|
+
await callbackServer.close().catch(() => {});
|
|
4344
|
+
if (shouldClearClientOnFailedAttempt) {
|
|
4345
|
+
await authStorage.clearClient(mcpUrl).catch(() => {});
|
|
4346
|
+
}
|
|
4347
|
+
const msg = error2 instanceof Error ? error2.message : "Authentication failed";
|
|
4348
|
+
return { status: "failed", message: ensureTerminalPeriod(msg) };
|
|
4349
|
+
}
|
|
4350
|
+
if (callback.type !== "success") {
|
|
4351
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
4352
|
+
if (shouldClearClientOnFailedAttempt) {
|
|
4353
|
+
await authStorage.clearClient(mcpUrl).catch(() => {});
|
|
4354
|
+
}
|
|
4355
|
+
return {
|
|
4356
|
+
status: "failed",
|
|
4357
|
+
message: callback.message ?? "Authentication callback failed."
|
|
4358
|
+
};
|
|
4359
|
+
}
|
|
4360
|
+
let tokenResponse;
|
|
4361
|
+
try {
|
|
4362
|
+
tokenResponse = await authService.exchangeCodeForTokens({
|
|
4363
|
+
tokenEndpoint: metadata.tokenEndpoint,
|
|
4364
|
+
clientId: client.clientId,
|
|
4365
|
+
clientSecret: client.clientSecret,
|
|
4366
|
+
code: callback.code,
|
|
4367
|
+
codeVerifier: verifier,
|
|
4368
|
+
redirectUri
|
|
4369
|
+
});
|
|
4370
|
+
} catch (error2) {
|
|
4371
|
+
try {
|
|
4372
|
+
await authStorage.clearClient(mcpUrl);
|
|
4373
|
+
} catch {}
|
|
4374
|
+
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
4375
|
+
return {
|
|
4376
|
+
status: "failed",
|
|
4377
|
+
message: `Failed to complete authentication: ${msg}`
|
|
4378
|
+
};
|
|
4379
|
+
}
|
|
4380
|
+
const expiresAt = new Date(Date.now() + tokenResponse.expiresIn * 1000).toISOString();
|
|
4381
|
+
await authStorage.saveAuthSession(mcpUrl, client, {
|
|
4382
|
+
accessToken: tokenResponse.accessToken,
|
|
4383
|
+
refreshToken: tokenResponse.refreshToken,
|
|
4384
|
+
expiresAt,
|
|
4385
|
+
createdAt: new Date().toISOString()
|
|
4386
|
+
});
|
|
4387
|
+
const hours = Math.round(tokenResponse.expiresIn / 3600);
|
|
4388
|
+
return {
|
|
4389
|
+
status: "success",
|
|
4390
|
+
message: `Logged in successfully. Token expires in ${hours} hour${hours !== 1 ? "s" : ""}.`
|
|
4391
|
+
};
|
|
4392
|
+
}
|
|
4393
|
+
async function loginAction(options, deps) {
|
|
4394
|
+
const result = await loginFlow(options, deps, stdoutLoginOutput);
|
|
4395
|
+
if (result.status === "already_authenticated") {
|
|
4396
|
+
console.log(`Already logged in.
|
|
4397
|
+
`);
|
|
4398
|
+
console.log(` Environment: ${deps.mcpUrl}
|
|
4399
|
+
`);
|
|
4400
|
+
console.log("To re-authenticate, use `githits login --force`.");
|
|
4401
|
+
return;
|
|
4402
|
+
}
|
|
4403
|
+
if (result.status === "failed") {
|
|
4404
|
+
console.error(`${result.message}
|
|
4405
|
+
`);
|
|
4406
|
+
printLoginRecoveryHint(result.message);
|
|
4407
|
+
process.exit(1);
|
|
4408
|
+
}
|
|
4409
|
+
console.log(`Logged in successfully.
|
|
4410
|
+
`);
|
|
4411
|
+
console.log(` Environment: ${deps.mcpUrl}`);
|
|
4412
|
+
console.log(result.message.replace("Logged in successfully. ", " "));
|
|
4413
|
+
console.log(`
|
|
4414
|
+
You're ready to use githits with your AI assistant.`);
|
|
4415
|
+
}
|
|
4416
|
+
function printLoginRecoveryHint(message) {
|
|
4417
|
+
console.log("Recovery steps:");
|
|
4418
|
+
if (message.includes("Authentication timed out")) {
|
|
4419
|
+
console.log(" Run the same command again to open a fresh sign-in link.");
|
|
4420
|
+
console.log(" githits login --no-browser # if the browser did not open or you are on SSH");
|
|
4421
|
+
console.log(" githits logout && githits login # if sign-in keeps failing after a retry");
|
|
4422
|
+
return;
|
|
4423
|
+
}
|
|
4424
|
+
console.log(" githits auth status");
|
|
4425
|
+
console.log(" githits login --force");
|
|
4426
|
+
if (message.includes("Cannot persist OAuth credentials")) {
|
|
4427
|
+
console.log("If your system keychain is locked or unavailable, unlock it and retry.");
|
|
4428
|
+
console.log("For CI/automation, set GITHITS_API_TOKEN.");
|
|
4429
|
+
console.log("As a last resort, set GITHITS_AUTH_STORAGE=file to use plaintext file storage.");
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
function printAutoLoginRecoveryHint(message) {
|
|
4433
|
+
if (message.includes("Authentication timed out")) {
|
|
4434
|
+
console.error("Run the same command again to open a fresh sign-in link.");
|
|
4435
|
+
console.error("If the browser did not open, run `githits login --no-browser` and follow the printed link.");
|
|
4436
|
+
console.error("If sign-in keeps failing after a retry, run `githits logout` and then run your command again.");
|
|
4437
|
+
return;
|
|
4438
|
+
}
|
|
4439
|
+
console.error("Run the same command again to try signing in again.");
|
|
4440
|
+
console.error("Run `githits auth status` to check whether you are signed in.");
|
|
4441
|
+
if (message.includes("Cannot persist OAuth credentials")) {
|
|
4442
|
+
console.error("If your system keychain is locked or unavailable, unlock it and try again.");
|
|
4443
|
+
console.error("For CI/automation, set GITHITS_API_TOKEN.");
|
|
4444
|
+
}
|
|
4445
|
+
}
|
|
4446
|
+
function ensureTerminalPeriod(message) {
|
|
4447
|
+
return /[.!?]$/.test(message) ? message : `${message}.`;
|
|
4448
|
+
}
|
|
4449
|
+
var LOGIN_DESCRIPTION = `Authenticate with your GitHits account via browser.
|
|
4450
|
+
|
|
4451
|
+
Opens your browser to complete authentication securely using OAuth.
|
|
4452
|
+
OAuth credentials are stored in the system keychain by default. If your
|
|
4453
|
+
machine has no usable keychain, use GITHITS_API_TOKEN or explicitly configure
|
|
4454
|
+
auth.storage = "file". File storage is plaintext on disk.
|
|
4455
|
+
|
|
4456
|
+
Use --no-browser in environments without a display (CI, SSH sessions)
|
|
4457
|
+
to get a URL you can open on another device.`;
|
|
4458
|
+
function registerLoginCommand(program) {
|
|
4459
|
+
program.command("login").summary("Authenticate with your GitHits account").description(LOGIN_DESCRIPTION).option("--no-browser", "Print URL instead of opening browser").option("--port <port>", "Port for local callback server", parseInt).option("--force", "Re-authenticate even if already logged in").action(async (options) => {
|
|
4460
|
+
const deps = await createAuthCommandDependencies();
|
|
4461
|
+
await loginAction(options, deps);
|
|
4462
|
+
});
|
|
4463
|
+
}
|
|
4464
|
+
|
|
4465
|
+
// src/shared/auto-login.ts
|
|
4466
|
+
var AUTO_LOGIN_ELIGIBLE_COMMANDS = new Set([
|
|
4467
|
+
"example",
|
|
4468
|
+
"languages",
|
|
4469
|
+
"feedback",
|
|
4470
|
+
"search",
|
|
4471
|
+
"search-status",
|
|
4472
|
+
"code files",
|
|
4473
|
+
"code read",
|
|
4474
|
+
"code grep",
|
|
4475
|
+
"docs list",
|
|
4476
|
+
"docs read",
|
|
4477
|
+
"pkg info",
|
|
4478
|
+
"pkg vulns",
|
|
4479
|
+
"pkg deps",
|
|
4480
|
+
"pkg changelog"
|
|
4481
|
+
]);
|
|
4482
|
+
function getCommandPath(command) {
|
|
4483
|
+
const names = [];
|
|
4484
|
+
let current = command;
|
|
4485
|
+
while (current) {
|
|
4486
|
+
const name = current.name();
|
|
4487
|
+
if (name && name !== "githits") {
|
|
4488
|
+
names.unshift(name);
|
|
4489
|
+
}
|
|
4490
|
+
current = current.parent ?? null;
|
|
4491
|
+
}
|
|
4492
|
+
return names;
|
|
4493
|
+
}
|
|
4494
|
+
function isAutoLoginEligibleCommand(command, runtime = {
|
|
4495
|
+
stdinIsTTY: Boolean(process.stdin.isTTY),
|
|
4496
|
+
stdoutIsTTY: Boolean(process.stdout.isTTY)
|
|
4497
|
+
}) {
|
|
4498
|
+
const commandPath = getCommandPath(command).join(" ");
|
|
4499
|
+
if (!AUTO_LOGIN_ELIGIBLE_COMMANDS.has(commandPath)) {
|
|
4500
|
+
return false;
|
|
4501
|
+
}
|
|
4502
|
+
if (!runtime.stdinIsTTY || !runtime.stdoutIsTTY) {
|
|
4503
|
+
return false;
|
|
4504
|
+
}
|
|
4505
|
+
return true;
|
|
4506
|
+
}
|
|
4507
|
+
async function maybeAutoLoginBeforeCommand(command, deps) {
|
|
4508
|
+
if (!isAutoLoginEligibleCommand(command, {
|
|
4509
|
+
stdinIsTTY: deps.stdinIsTTY ?? Boolean(process.stdin.isTTY),
|
|
4510
|
+
stdoutIsTTY: deps.stdoutIsTTY ?? Boolean(process.stdout.isTTY)
|
|
4511
|
+
})) {
|
|
4512
|
+
return { status: "skipped" };
|
|
4513
|
+
}
|
|
4514
|
+
const container = await deps.createContainer();
|
|
4515
|
+
if (container.hasValidToken) {
|
|
4516
|
+
return { status: "already-authenticated" };
|
|
4517
|
+
}
|
|
4518
|
+
const result = await deps.loginFlow({}, container);
|
|
4519
|
+
switch (result.status) {
|
|
4520
|
+
case "success":
|
|
4521
|
+
return { status: "authenticated", message: result.message };
|
|
4522
|
+
case "already_authenticated":
|
|
4523
|
+
return { status: "already-authenticated", message: result.message };
|
|
4524
|
+
case "failed":
|
|
4525
|
+
return { status: "failed", message: result.message };
|
|
4526
|
+
}
|
|
4527
|
+
}
|
|
4528
|
+
|
|
4529
|
+
// src/shared/root-cli-pre-action.ts
|
|
4530
|
+
function createRootCliPreAction(deps) {
|
|
4531
|
+
return async (thisCommand, actionCommand) => {
|
|
4532
|
+
if (thisCommand.opts().color === false) {
|
|
4533
|
+
process.env.NO_COLOR = "1";
|
|
4534
|
+
}
|
|
4535
|
+
const command = actionCommand ?? thisCommand;
|
|
4536
|
+
const authResult = await maybeAutoLoginBeforeCommand(command, {
|
|
4537
|
+
...deps,
|
|
4538
|
+
stdinIsTTY: deps.stdinIsTTY,
|
|
4539
|
+
stdoutIsTTY: deps.stdoutIsTTY
|
|
4540
|
+
});
|
|
4541
|
+
if (authResult.status === "authenticated") {
|
|
4542
|
+
const continuationMessage = getPostLoginContinuationMessage(command);
|
|
4543
|
+
if (continuationMessage) {
|
|
4544
|
+
console.error(continuationMessage);
|
|
4545
|
+
}
|
|
4546
|
+
}
|
|
4547
|
+
if (authResult.status !== "failed") {
|
|
4548
|
+
return;
|
|
4549
|
+
}
|
|
4550
|
+
const failureMessage = authResult.message ?? "Authentication failed.";
|
|
4551
|
+
console.error(`${failureMessage}
|
|
4552
|
+
`);
|
|
4553
|
+
printAutoLoginRecoveryHint(failureMessage);
|
|
4554
|
+
(deps.exit ?? process.exit)(1);
|
|
4555
|
+
};
|
|
4556
|
+
}
|
|
4557
|
+
function getPostLoginContinuationMessage(command) {
|
|
4558
|
+
switch (getCommandPath(command).join(" ")) {
|
|
4559
|
+
case "example":
|
|
4560
|
+
return "Authentication complete. Running example search...";
|
|
4561
|
+
case "languages":
|
|
4562
|
+
return "Authentication complete. Loading supported languages...";
|
|
4563
|
+
case "feedback":
|
|
4564
|
+
return "Authentication complete. Submitting feedback...";
|
|
4565
|
+
case "search":
|
|
4566
|
+
case "search-status":
|
|
4567
|
+
case "code files":
|
|
4568
|
+
case "code read":
|
|
4569
|
+
case "code grep":
|
|
4570
|
+
case "docs list":
|
|
4571
|
+
case "docs read":
|
|
4572
|
+
case "pkg info":
|
|
4573
|
+
case "pkg vulns":
|
|
4574
|
+
case "pkg deps":
|
|
4575
|
+
case "pkg changelog":
|
|
4576
|
+
return "Authentication complete. Running command...";
|
|
4577
|
+
default:
|
|
4578
|
+
return;
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
4581
|
+
// src/shared/unified-search-request.ts
|
|
4582
|
+
var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
|
|
4583
|
+
function buildUnifiedSearchParams(input) {
|
|
4584
|
+
const targets = resolveTargets(input.target, input.targets);
|
|
4585
|
+
const rawQuery = normaliseRequiredQuery(input.query);
|
|
4586
|
+
const limit = input.limit ?? DEFAULT_UNIFIED_SEARCH_LIMIT;
|
|
4587
|
+
const offset = input.offset ?? 0;
|
|
4588
|
+
const waitTimeoutMs = input.waitTimeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;
|
|
4589
|
+
const qualifierClauses = buildQualifierClauses({
|
|
4590
|
+
name: input.name,
|
|
4591
|
+
language: input.language
|
|
4592
|
+
});
|
|
4593
|
+
const compiledQuery = compileQuery(rawQuery, qualifierClauses);
|
|
4594
|
+
const filters = buildFilters({
|
|
4595
|
+
kind: input.kind,
|
|
4596
|
+
category: input.category,
|
|
4597
|
+
pathPrefix: input.pathPrefix,
|
|
4598
|
+
fileIntent: input.fileIntent,
|
|
4599
|
+
publicOnly: input.publicOnly
|
|
4600
|
+
});
|
|
4601
|
+
return {
|
|
4602
|
+
params: {
|
|
4603
|
+
targets,
|
|
4604
|
+
query: compiledQuery,
|
|
4605
|
+
sources: input.sources,
|
|
4606
|
+
filters,
|
|
4607
|
+
allowPartialResults: input.allowPartialResults,
|
|
4608
|
+
limit,
|
|
4609
|
+
offset,
|
|
4315
4610
|
waitTimeoutMs
|
|
4316
4611
|
},
|
|
4317
4612
|
rawQuery,
|
|
@@ -5798,7 +6093,7 @@ function buildCliListFilesParams(input) {
|
|
|
5798
6093
|
throw new InvalidPackageSpecError(rewritten);
|
|
5799
6094
|
}
|
|
5800
6095
|
}
|
|
5801
|
-
var REGISTRY_SPEC_HINT =
|
|
6096
|
+
var REGISTRY_SPEC_HINT = new RegExp(`^(${PKGSEER_REGISTRY_ARGS.join("|")}):`, "i");
|
|
5802
6097
|
function resolvePositionals(firstArg, secondArg, hasRepoUrl) {
|
|
5803
6098
|
if (hasRepoUrl) {
|
|
5804
6099
|
if (secondArg !== undefined) {
|
|
@@ -5824,8 +6119,7 @@ and \`githits code grep\`.
|
|
|
5824
6119
|
filters intersect on top.
|
|
5825
6120
|
|
|
5826
6121
|
Addressing: <spec> (registry:name[@version]) OR --repo-url <url>
|
|
5827
|
-
--git-ref <ref>. Supported registries:
|
|
5828
|
-
vcpkg, zig, nuget, maven, packagist.
|
|
6122
|
+
--git-ref <ref>. Supported registries: ${PKGSEER_REGISTRY_LIST}.
|
|
5829
6123
|
|
|
5830
6124
|
By default each result is a bare path for easy piping; pass
|
|
5831
6125
|
--verbose to include language / file-type / size annotations.
|
|
@@ -5977,7 +6271,7 @@ grep run. --symbol-field hydrates enclosing symbol metadata (appears under each
|
|
|
5977
6271
|
match in --verbose output; full payload in --json).`;
|
|
5978
6272
|
function registerCodeGrepCommand(pkgCommand) {
|
|
5979
6273
|
return pkgCommand.command("grep").summary("Deterministic text grep over indexed dependency source").description(PKG_GREP_DESCRIPTION).argument("[spec-or-pattern]", "Spec mode: package spec (e.g. npm:express). Repo mode (with --repo-url): the pattern.").argument("[pattern-or-prefix]", "Spec mode: the pattern. Repo mode: optional path-prefix.").argument("[path-prefix]", "Spec mode only: optional path-prefix. Ignored with --repo-url.").option("--repo-url <url>", "Repository URL addressing (requires --git-ref)").option("--git-ref <ref>", "Tag, commit, branch, or HEAD. Required with --repo-url.").option("--path <path>", "Exact file path to grep").option("--glob <glob>", "Glob scope (repeatable)", collectRepeatable2, []).option("--ext <ext>", "Extension filter without leading dot (repeatable)", collectRepeatable2, []).option("--regex", "Interpret the pattern as RE2 regex").option("--case-sensitive", "Enable ASCII case-sensitive matching").option("-C, --context <n>", "Context lines before and after each match (0-10)").option("-B, --before-context <n>", "Context lines before each match (0-10)").option("-A, --after-context <n>", "Context lines after each match (0-10)").option("--exclude-docs", "Skip files classified as documentation").option("--exclude-tests", "Skip files classified as tests").option("--limit <n>", "Max matches to return on this page (1-1000, default 50)").option("--per-file-limit <n>", "Cap matches per file within this page (0-1000, 0 = unlimited)").option("--cursor <cursor>", "Opaque nextCursor from a previous grep result").option("--symbol-field <field>", `Repeatable; surfaces in --json and under each --verbose match. ${GREP_REPO_SYMBOL_FIELDS_NOTE}`, collectRepeatable2, []).option("--wait <ms>", `Indexing wait timeout (0-${MAX_WAIT_TIMEOUT_MS}, default ${DEFAULT_WAIT_TIMEOUT_MS})`).option("-v, --verbose", "Render grouped output with file headers").option("--json", "Emit the JSON envelope").action(async (arg1, arg2, arg3, options) => {
|
|
5980
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
6274
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-q2mre780.js");
|
|
5981
6275
|
const deps = await createContainer2();
|
|
5982
6276
|
await pkgGrepAction(arg1, arg2, arg3, options, {
|
|
5983
6277
|
codeNavigationService: deps.codeNavigationService,
|
|
@@ -6511,7 +6805,7 @@ function registerExampleCommand(program) {
|
|
|
6511
6805
|
});
|
|
6512
6806
|
}
|
|
6513
6807
|
async function loadContainer() {
|
|
6514
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
6808
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-q2mre780.js");
|
|
6515
6809
|
return createContainer2();
|
|
6516
6810
|
}
|
|
6517
6811
|
// src/commands/feedback.ts
|
|
@@ -7280,257 +7574,6 @@ async function scanAgents(definitions, fs, execService) {
|
|
|
7280
7574
|
class ExitPromptError extends Error {
|
|
7281
7575
|
name = "ExitPromptError";
|
|
7282
7576
|
}
|
|
7283
|
-
// src/commands/login.ts
|
|
7284
|
-
var stdoutLoginOutput = {
|
|
7285
|
-
write: (message) => {
|
|
7286
|
-
console.log(message);
|
|
7287
|
-
}
|
|
7288
|
-
};
|
|
7289
|
-
var stderrLoginOutput = {
|
|
7290
|
-
write: (message) => {
|
|
7291
|
-
console.error(message);
|
|
7292
|
-
}
|
|
7293
|
-
};
|
|
7294
|
-
var TIMEOUT_MS = 5 * 60 * 1000;
|
|
7295
|
-
function randomPort() {
|
|
7296
|
-
return Math.floor(Math.random() * 2000) + 8000;
|
|
7297
|
-
}
|
|
7298
|
-
async function preflightAuthPersistence(authStorage, mcpUrl) {
|
|
7299
|
-
const probeUrl = `${mcpUrl.replace(/\/+$/, "")}/__githits_storage_probe__`;
|
|
7300
|
-
const probeClient = {
|
|
7301
|
-
clientId: "__githits_storage_probe__",
|
|
7302
|
-
clientSecret: "__githits_storage_probe__",
|
|
7303
|
-
redirectUri: "http://127.0.0.1:1/callback",
|
|
7304
|
-
registeredAt: new Date(0).toISOString()
|
|
7305
|
-
};
|
|
7306
|
-
const probeTokens = {
|
|
7307
|
-
accessToken: "__githits_storage_probe__",
|
|
7308
|
-
refreshToken: "__githits_storage_probe__",
|
|
7309
|
-
expiresAt: new Date(0).toISOString(),
|
|
7310
|
-
createdAt: new Date(0).toISOString()
|
|
7311
|
-
};
|
|
7312
|
-
try {
|
|
7313
|
-
await authStorage.saveAuthSession(probeUrl, probeClient, probeTokens);
|
|
7314
|
-
await authStorage.clearAuthSession(probeUrl);
|
|
7315
|
-
return null;
|
|
7316
|
-
} catch (error2) {
|
|
7317
|
-
await authStorage.clearAuthSession(probeUrl).catch(() => {});
|
|
7318
|
-
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
7319
|
-
return {
|
|
7320
|
-
status: "failed",
|
|
7321
|
-
message: `Cannot persist OAuth credentials: ${message}`
|
|
7322
|
-
};
|
|
7323
|
-
}
|
|
7324
|
-
}
|
|
7325
|
-
async function loginFlow(options, deps, output = stdoutLoginOutput) {
|
|
7326
|
-
const { authService, authStorage, browserService, mcpUrl } = deps;
|
|
7327
|
-
if (options.port !== undefined && (Number.isNaN(options.port) || options.port < 1 || options.port > 65535)) {
|
|
7328
|
-
return {
|
|
7329
|
-
status: "failed",
|
|
7330
|
-
message: "Invalid port number. Must be between 1 and 65535."
|
|
7331
|
-
};
|
|
7332
|
-
}
|
|
7333
|
-
const existing = await authStorage.loadTokens(mcpUrl);
|
|
7334
|
-
if (existing && !options.force) {
|
|
7335
|
-
const isExpired = existing.expiresAt && new Date(existing.expiresAt) < new Date;
|
|
7336
|
-
if (!isExpired) {
|
|
7337
|
-
return { status: "already_authenticated", message: "Already logged in." };
|
|
7338
|
-
}
|
|
7339
|
-
output.write(`Token expired. Starting new login...
|
|
7340
|
-
`);
|
|
7341
|
-
} else if (existing && options.force) {
|
|
7342
|
-
output.write(`Re-authenticating (--force flag)...
|
|
7343
|
-
`);
|
|
7344
|
-
}
|
|
7345
|
-
if (!existing) {
|
|
7346
|
-
await authStorage.clearClient(mcpUrl);
|
|
7347
|
-
}
|
|
7348
|
-
const persistenceError = await preflightAuthPersistence(authStorage, mcpUrl);
|
|
7349
|
-
if (persistenceError)
|
|
7350
|
-
return persistenceError;
|
|
7351
|
-
output.write("Discovering OAuth endpoints...");
|
|
7352
|
-
const metadata = await authService.discoverEndpoints(mcpUrl);
|
|
7353
|
-
let client = await authStorage.loadClient(mcpUrl);
|
|
7354
|
-
let port;
|
|
7355
|
-
let redirectUri;
|
|
7356
|
-
if (client) {
|
|
7357
|
-
if (options.port) {
|
|
7358
|
-
redirectUri = `http://127.0.0.1:${options.port}/callback`;
|
|
7359
|
-
if (redirectUri !== client.redirectUri) {
|
|
7360
|
-
output.write("Registering CLI client with new port...");
|
|
7361
|
-
const registration = await authService.registerClient({
|
|
7362
|
-
registrationEndpoint: metadata.registrationEndpoint,
|
|
7363
|
-
redirectUri
|
|
7364
|
-
});
|
|
7365
|
-
client = {
|
|
7366
|
-
clientId: registration.clientId,
|
|
7367
|
-
clientSecret: registration.clientSecret,
|
|
7368
|
-
redirectUri,
|
|
7369
|
-
registeredAt: new Date().toISOString()
|
|
7370
|
-
};
|
|
7371
|
-
}
|
|
7372
|
-
port = options.port;
|
|
7373
|
-
} else {
|
|
7374
|
-
redirectUri = client.redirectUri;
|
|
7375
|
-
const storedUrl = new URL(redirectUri);
|
|
7376
|
-
port = Number(storedUrl.port) || randomPort();
|
|
7377
|
-
}
|
|
7378
|
-
} else {
|
|
7379
|
-
port = options.port ?? randomPort();
|
|
7380
|
-
redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
7381
|
-
output.write("Registering CLI client...");
|
|
7382
|
-
const registration = await authService.registerClient({
|
|
7383
|
-
registrationEndpoint: metadata.registrationEndpoint,
|
|
7384
|
-
redirectUri
|
|
7385
|
-
});
|
|
7386
|
-
client = {
|
|
7387
|
-
clientId: registration.clientId,
|
|
7388
|
-
clientSecret: registration.clientSecret,
|
|
7389
|
-
redirectUri,
|
|
7390
|
-
registeredAt: new Date().toISOString()
|
|
7391
|
-
};
|
|
7392
|
-
}
|
|
7393
|
-
const { verifier, challenge, state } = authService.generatePkceParams();
|
|
7394
|
-
const authUrl = authService.buildAuthUrl({
|
|
7395
|
-
authorizationEndpoint: metadata.authorizationEndpoint,
|
|
7396
|
-
clientId: client.clientId,
|
|
7397
|
-
redirectUri,
|
|
7398
|
-
state,
|
|
7399
|
-
codeChallenge: challenge
|
|
7400
|
-
});
|
|
7401
|
-
let callbackServer;
|
|
7402
|
-
try {
|
|
7403
|
-
callbackServer = await authService.startCallbackServer(port, state);
|
|
7404
|
-
} catch (error2) {
|
|
7405
|
-
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
7406
|
-
return { status: "failed", message: msg };
|
|
7407
|
-
}
|
|
7408
|
-
if (options.browser === false) {
|
|
7409
|
-
output.write(`Open this URL in your browser:
|
|
7410
|
-
`);
|
|
7411
|
-
output.write(` ${authUrl}
|
|
7412
|
-
`);
|
|
7413
|
-
} else {
|
|
7414
|
-
output.write("Opening browser...");
|
|
7415
|
-
try {
|
|
7416
|
-
await browserService.open(authUrl);
|
|
7417
|
-
} catch (error2) {
|
|
7418
|
-
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
7419
|
-
output.write(`Could not open browser automatically: ${msg}
|
|
7420
|
-
`);
|
|
7421
|
-
output.write(`Open this URL in your browser:
|
|
7422
|
-
`);
|
|
7423
|
-
output.write(` ${authUrl}
|
|
7424
|
-
`);
|
|
7425
|
-
}
|
|
7426
|
-
}
|
|
7427
|
-
output.write(`Waiting for authentication...
|
|
7428
|
-
`);
|
|
7429
|
-
let timeoutId;
|
|
7430
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
7431
|
-
timeoutId = setTimeout(() => reject(new Error("Authentication timed out")), TIMEOUT_MS);
|
|
7432
|
-
});
|
|
7433
|
-
let callback;
|
|
7434
|
-
try {
|
|
7435
|
-
callback = await Promise.race([callbackServer.result, timeoutPromise]);
|
|
7436
|
-
if (timeoutId)
|
|
7437
|
-
clearTimeout(timeoutId);
|
|
7438
|
-
} catch (error2) {
|
|
7439
|
-
if (timeoutId)
|
|
7440
|
-
clearTimeout(timeoutId);
|
|
7441
|
-
await callbackServer.close().catch(() => {});
|
|
7442
|
-
const msg = error2 instanceof Error ? error2.message : "Authentication failed";
|
|
7443
|
-
return { status: "failed", message: `${msg}.` };
|
|
7444
|
-
}
|
|
7445
|
-
if (callback.type !== "success") {
|
|
7446
|
-
await new Promise((r) => setTimeout(r, 2000));
|
|
7447
|
-
return {
|
|
7448
|
-
status: "failed",
|
|
7449
|
-
message: callback.message ?? "Authentication callback failed."
|
|
7450
|
-
};
|
|
7451
|
-
}
|
|
7452
|
-
let tokenResponse;
|
|
7453
|
-
try {
|
|
7454
|
-
tokenResponse = await authService.exchangeCodeForTokens({
|
|
7455
|
-
tokenEndpoint: metadata.tokenEndpoint,
|
|
7456
|
-
clientId: client.clientId,
|
|
7457
|
-
clientSecret: client.clientSecret,
|
|
7458
|
-
code: callback.code,
|
|
7459
|
-
codeVerifier: verifier,
|
|
7460
|
-
redirectUri
|
|
7461
|
-
});
|
|
7462
|
-
} catch (error2) {
|
|
7463
|
-
try {
|
|
7464
|
-
await authStorage.clearClient(mcpUrl);
|
|
7465
|
-
} catch {}
|
|
7466
|
-
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
7467
|
-
return {
|
|
7468
|
-
status: "failed",
|
|
7469
|
-
message: `Failed to complete authentication: ${msg}`
|
|
7470
|
-
};
|
|
7471
|
-
}
|
|
7472
|
-
const expiresAt = new Date(Date.now() + tokenResponse.expiresIn * 1000).toISOString();
|
|
7473
|
-
await authStorage.saveAuthSession(mcpUrl, client, {
|
|
7474
|
-
accessToken: tokenResponse.accessToken,
|
|
7475
|
-
refreshToken: tokenResponse.refreshToken,
|
|
7476
|
-
expiresAt,
|
|
7477
|
-
createdAt: new Date().toISOString()
|
|
7478
|
-
});
|
|
7479
|
-
const hours = Math.round(tokenResponse.expiresIn / 3600);
|
|
7480
|
-
return {
|
|
7481
|
-
status: "success",
|
|
7482
|
-
message: `Logged in successfully. Token expires in ${hours} hour${hours !== 1 ? "s" : ""}.`
|
|
7483
|
-
};
|
|
7484
|
-
}
|
|
7485
|
-
async function loginAction(options, deps) {
|
|
7486
|
-
const result = await loginFlow(options, deps, stdoutLoginOutput);
|
|
7487
|
-
if (result.status === "already_authenticated") {
|
|
7488
|
-
console.log(`Already logged in.
|
|
7489
|
-
`);
|
|
7490
|
-
console.log(` Environment: ${deps.mcpUrl}
|
|
7491
|
-
`);
|
|
7492
|
-
console.log("To re-authenticate, use `githits login --force`.");
|
|
7493
|
-
return;
|
|
7494
|
-
}
|
|
7495
|
-
if (result.status === "failed") {
|
|
7496
|
-
console.error(`${result.message}
|
|
7497
|
-
`);
|
|
7498
|
-
printLoginRecoveryHint(result.message);
|
|
7499
|
-
process.exit(1);
|
|
7500
|
-
}
|
|
7501
|
-
console.log(`Logged in successfully.
|
|
7502
|
-
`);
|
|
7503
|
-
console.log(` Environment: ${deps.mcpUrl}`);
|
|
7504
|
-
console.log(result.message.replace("Logged in successfully. ", " "));
|
|
7505
|
-
console.log(`
|
|
7506
|
-
You're ready to use githits with your AI assistant.`);
|
|
7507
|
-
}
|
|
7508
|
-
function printLoginRecoveryHint(message) {
|
|
7509
|
-
console.log("Recovery steps:");
|
|
7510
|
-
console.log(" githits auth status");
|
|
7511
|
-
console.log(" githits login --force");
|
|
7512
|
-
if (message.includes("Cannot persist OAuth credentials")) {
|
|
7513
|
-
console.log("If your system keychain is locked or unavailable, unlock it and retry.");
|
|
7514
|
-
console.log("For CI/automation, set GITHITS_API_TOKEN.");
|
|
7515
|
-
console.log("As a last resort, set GITHITS_AUTH_STORAGE=file to use plaintext file storage.");
|
|
7516
|
-
}
|
|
7517
|
-
}
|
|
7518
|
-
var LOGIN_DESCRIPTION = `Authenticate with your GitHits account via browser.
|
|
7519
|
-
|
|
7520
|
-
Opens your browser to complete authentication securely using OAuth.
|
|
7521
|
-
OAuth credentials are stored in the system keychain by default. If your
|
|
7522
|
-
machine has no usable keychain, use GITHITS_API_TOKEN or explicitly configure
|
|
7523
|
-
auth.storage = "file". File storage is plaintext on disk.
|
|
7524
|
-
|
|
7525
|
-
Use --no-browser in environments without a display (CI, SSH sessions)
|
|
7526
|
-
to get a URL you can open on another device.`;
|
|
7527
|
-
function registerLoginCommand(program) {
|
|
7528
|
-
program.command("login").summary("Authenticate with your GitHits account").description(LOGIN_DESCRIPTION).option("--no-browser", "Print URL instead of opening browser").option("--port <port>", "Port for local callback server", parseInt).option("--force", "Re-authenticate even if already logged in").action(async (options) => {
|
|
7529
|
-
const deps = await createAuthCommandDependencies();
|
|
7530
|
-
await loginAction(options, deps);
|
|
7531
|
-
});
|
|
7532
|
-
}
|
|
7533
|
-
|
|
7534
7577
|
// src/commands/init/init.ts
|
|
7535
7578
|
async function verifyAgentConfigured(agent, fileSystemService, execService) {
|
|
7536
7579
|
const postCheck = await scanAgents([agent], fileSystemService, execService);
|
|
@@ -7934,17 +7977,7 @@ import { z as z4 } from "zod";
|
|
|
7934
7977
|
// src/tools/code-navigation-shared.ts
|
|
7935
7978
|
import { z as z3 } from "zod";
|
|
7936
7979
|
var structuredCodeTargetSchema = z3.object({
|
|
7937
|
-
registry: z3.enum(
|
|
7938
|
-
"npm",
|
|
7939
|
-
"pypi",
|
|
7940
|
-
"hex",
|
|
7941
|
-
"crates",
|
|
7942
|
-
"nuget",
|
|
7943
|
-
"maven",
|
|
7944
|
-
"zig",
|
|
7945
|
-
"vcpkg",
|
|
7946
|
-
"packagist"
|
|
7947
|
-
]).optional().describe("Package registry (npm, pypi, hex, etc.). Required for package scope."),
|
|
7980
|
+
registry: z3.enum(PKGSEER_REGISTRY_ARGS).optional().describe(`Package registry (${PKGSEER_REGISTRY_LIST}). Required for package scope.`),
|
|
7948
7981
|
package_name: z3.string().max(255).optional().describe("Package name. Required for package scope."),
|
|
7949
7982
|
version: z3.string().max(100).optional().describe("Package version, e.g. '4.18.2' (defaults to latest). For package scope only."),
|
|
7950
7983
|
repo_url: z3.string().optional().describe("Repository URL (GitHub). Required for repo scope. Example: https://github.com/expressjs/express"),
|
|
@@ -8197,7 +8230,7 @@ function isTextFormat3(format) {
|
|
|
8197
8230
|
// src/tools/list-package-docs.ts
|
|
8198
8231
|
import { z as z6 } from "zod";
|
|
8199
8232
|
var schema5 = {
|
|
8200
|
-
registry: z6.string().describe(
|
|
8233
|
+
registry: z6.string().describe(`Package registry. One of: ${PKGSEER_REGISTRY_LIST}.`),
|
|
8201
8234
|
package_name: z6.string().describe("Package name (scoped names ok: @types/node)."),
|
|
8202
8235
|
version: z6.string().optional().describe("Optional package version."),
|
|
8203
8236
|
limit: z6.number().optional().describe("Max pages to return (1-500, default 100)."),
|
|
@@ -8304,7 +8337,7 @@ function resolveAddressing(input) {
|
|
|
8304
8337
|
}
|
|
8305
8338
|
const normalisedRegistryArg = input.registry?.trim().toLowerCase() ?? "";
|
|
8306
8339
|
if (!isKnownPkgseerRegistryArg(normalisedRegistryArg)) {
|
|
8307
|
-
throw new UnsupportedRegistryError(`Unsupported registry '${input.registry}'. Supported:
|
|
8340
|
+
throw new UnsupportedRegistryError(`Unsupported registry '${input.registry}'. Supported: ${PKGSEER_REGISTRY_LIST}.`);
|
|
8308
8341
|
}
|
|
8309
8342
|
const registry = toPkgseerRegistry(normalisedRegistryArg);
|
|
8310
8343
|
return { registry, packageName };
|
|
@@ -8511,7 +8544,7 @@ function stripAnsi(text) {
|
|
|
8511
8544
|
|
|
8512
8545
|
// src/tools/package-changelog.ts
|
|
8513
8546
|
var schema6 = {
|
|
8514
|
-
registry: z7.string().optional().describe(
|
|
8547
|
+
registry: z7.string().optional().describe(`Package registry (with \`package_name\`). Mutually exclusive with \`repo_url\`. Supported: ${PKGSEER_REGISTRY_LIST}.`),
|
|
8515
8548
|
package_name: z7.string().optional().describe("Package name (with `registry`). Scoped names ok (`@types/node`). Mutually exclusive with `repo_url`."),
|
|
8516
8549
|
repo_url: z7.string().optional().describe("GitHub repository URL (https://…). Mutually exclusive with `registry` + `package_name`. Use when agents have a repo URL without a registry mapping."),
|
|
8517
8550
|
from_version: z7.string().optional().describe("Start of version range. When set, the response returns every entry between `from_version` and `to_version` (or latest) with no count cap — range mode. Mutually exclusive with `limit`. Tag-style `v`-prefixed inputs are rejected."),
|
|
@@ -8521,7 +8554,7 @@ var schema6 = {
|
|
|
8521
8554
|
include_bodies: z7.boolean().optional().describe("When false, each entry in `entries.items[]` omits its `body` field. Default true. Set false when you only need the version / date / URL timeline — drops 10 KB+ per entry on large release notes."),
|
|
8522
8555
|
format: z7.enum(["json", "text", "text-v1"]).optional().describe("Response format. Default `text-v1` is compact for agents. Pass `json` for the structured envelope.")
|
|
8523
8556
|
};
|
|
8524
|
-
var DESCRIPTION6 = "Release notes for a package or GitHub repo, newest-first. Default " + "latest mode returns the ten most recent entries (`limit` 1–50). " + "With `from_version`, returns every entry in the " + "`[from_version, to_version]` range (range mode, no count cap). " + "Address via `registry` + `package_name` or `repo_url` (mutually " + 'exclusive). Response includes optional `source` (`"releases"` / ' + '`"changelog_file"` / `"hexdocs"`) when a concrete changelog source ' + 'exists, `mode` (`"latest"` or `"range"`), ' + 'and entries with markdown body previews. Pass `format: "json"` ' + "for the structured envelope with full markdown bodies. Set " + "`include_bodies: false` for a version / date / URL timeline only. " + "Package-version entries without changelog text succeed with `source` " + "omitted; no-source plus no entries returns `NOT_FOUND`. Supports npm, " + "PyPI, Hex, Crates, vcpkg, Zig, NuGet, Maven, Packagist.";
|
|
8557
|
+
var DESCRIPTION6 = "Release notes for a package or GitHub repo, newest-first. Default " + "latest mode returns the ten most recent entries (`limit` 1–50). " + "With `from_version`, returns every entry in the " + "`[from_version, to_version]` range (range mode, no count cap). " + "Address via `registry` + `package_name` or `repo_url` (mutually " + 'exclusive). Response includes optional `source` (`"releases"` / ' + '`"changelog_file"` / `"hexdocs"`) when a concrete changelog source ' + 'exists, `mode` (`"latest"` or `"range"`), ' + 'and entries with markdown body previews. Pass `format: "json"` ' + "for the structured envelope with full markdown bodies. Set " + "`include_bodies: false` for a version / date / URL timeline only. " + "Package-version entries without changelog text succeed with `source` " + "omitted; no-source plus no entries returns `NOT_FOUND`. Supports npm, " + "PyPI, Hex, Crates, vcpkg, Zig, NuGet, Maven, Packagist, RubyGems, Go.";
|
|
8525
8558
|
function createPackageChangelogTool(service) {
|
|
8526
8559
|
return {
|
|
8527
8560
|
name: "pkg_changelog",
|
|
@@ -8586,7 +8619,7 @@ function isTextFormat5(format) {
|
|
|
8586
8619
|
// src/tools/package-dependencies.ts
|
|
8587
8620
|
import { z as z8 } from "zod";
|
|
8588
8621
|
var schema7 = {
|
|
8589
|
-
registry: z8.string().describe(
|
|
8622
|
+
registry: z8.string().describe(`Package registry. Dependency data is available on ${SUPPORTED_DEPS_REGISTRIES_HUMAN}.`),
|
|
8590
8623
|
package_name: z8.string().describe("Package name (scoped names ok: @types/node)."),
|
|
8591
8624
|
version: z8.string().optional().describe("Specific version to inspect. Defaults to latest when omitted. Tag-style inputs with a leading `v` (for example `v4.18.0`) are rejected — pass the canonical version (`4.18.0`)."),
|
|
8592
8625
|
lifecycle: z8.union([z8.string(), z8.array(z8.string())]).optional().describe("Lifecycle breadth. Omit for runtime-only. Use `runtime` for explicit runtime-only, a concrete non-runtime lifecycle (`development`, `build`, `peer`, `optional`) for runtime plus matching groups, or `all` for runtime plus all available groups. Accepts a single value, a comma-separated string, or an array; `all` cannot be combined with other values. Uppercase is tolerated."),
|
|
@@ -8595,7 +8628,7 @@ var schema7 = {
|
|
|
8595
8628
|
max_depth: z8.number().int().min(1).max(10).optional().describe("Cap the transitive traversal at this depth (1–10). Omit to get the backend's full graph. Requires `include_transitive: true` — passing `max_depth` without the transitive flag is rejected with `INVALID_ARGUMENT`."),
|
|
8596
8629
|
format: z8.enum(["json", "text", "text-v1"]).optional().describe("Response format. Default `text-v1` is compact for agents. Pass `json` for the structured envelope.")
|
|
8597
8630
|
};
|
|
8598
|
-
var DESCRIPTION7 = "Analyze a package's dependency graph. Default output is compact " + "text listing direct runtime dependencies with resolved versions; " + 'pass `format: "json"` for the structured envelope. Non-runtime ' + "groups are omitted by default for token efficiency. Use `lifecycle` " + "with a concrete value for runtime plus matching groups, or `all` " + "for runtime plus all available groups. Set " + "`include_transitive: true` to add a `transitive` block with the " + "full install footprint, conflict detection, and circular-" + "dependency flags; layer `include_importers: true` on top when you " + "also need per-package provenance. Supports npm, PyPI, Hex, Crates, " + "vcpkg, and Zig.";
|
|
8631
|
+
var DESCRIPTION7 = "Analyze a package's dependency graph. Default output is compact " + "text listing direct runtime dependencies with resolved versions; " + 'pass `format: "json"` for the structured envelope. Non-runtime ' + "groups are omitted by default for token efficiency. Use `lifecycle` " + "with a concrete value for runtime plus matching groups, or `all` " + "for runtime plus all available groups. Set " + "`include_transitive: true` to add a `transitive` block with the " + "full install footprint, conflict detection, and circular-" + "dependency flags; layer `include_importers: true` on top when you " + "also need per-package provenance. Supports npm, PyPI, Hex, Crates, " + "RubyGems, Go, vcpkg, and Zig.";
|
|
8599
8632
|
function createPackageDependenciesTool(service) {
|
|
8600
8633
|
return {
|
|
8601
8634
|
name: "pkg_deps",
|
|
@@ -8666,11 +8699,11 @@ function isTextFormat6(format) {
|
|
|
8666
8699
|
// src/tools/package-summary.ts
|
|
8667
8700
|
import { z as z9 } from "zod";
|
|
8668
8701
|
var schema8 = {
|
|
8669
|
-
registry: z9.string().describe(
|
|
8702
|
+
registry: z9.string().describe(`Package registry. One of: ${PKGSEER_REGISTRY_LIST}.`),
|
|
8670
8703
|
package_name: z9.string().describe("Package name (scoped names ok: @types/node)."),
|
|
8671
8704
|
format: z9.enum(["json", "text", "text-v1"]).optional().describe("Response format. Default `text-v1` is compact for agents. Pass `json` for the structured envelope.")
|
|
8672
8705
|
};
|
|
8673
|
-
var DESCRIPTION8 = "Get a package overview — latest version, license, description, " + "repository, downloads, GitHub stars, install command, recent " + "changes, and a count of known vulnerabilities. Use before " + "recommending a package or to orient on what a dependency is. " + 'Default output is compact text; pass `format: "json"` for the ' + "structured envelope. " + "Works across npm, PyPI, Hex, Crates, NuGet, Maven, Packagist, " + "vcpkg, and Zig. Always returns data for the latest published " + "version.";
|
|
8706
|
+
var DESCRIPTION8 = "Get a package overview — latest version, license, description, " + "repository, downloads, GitHub stars, install command, recent " + "changes, and a count of known vulnerabilities. Use before " + "recommending a package or to orient on what a dependency is. " + 'Default output is compact text; pass `format: "json"` for the ' + "structured envelope. " + "Works across npm, PyPI, Hex, Crates, NuGet, Maven, Packagist, " + "RubyGems, Go, vcpkg, and Zig. Always returns data for the latest published " + "version.";
|
|
8674
8707
|
function createPackageSummaryTool(service) {
|
|
8675
8708
|
return {
|
|
8676
8709
|
name: "pkg_info",
|
|
@@ -9426,8 +9459,7 @@ Addressing: <spec> (registry:name) OR --repo-url <url>. Source
|
|
|
9426
9459
|
(GitHub Releases, CHANGELOG.md, or HexDocs) is shown on the summary
|
|
9427
9460
|
line.
|
|
9428
9461
|
|
|
9429
|
-
Package spec: <registry>:<name>. Supported registries:
|
|
9430
|
-
hex, crates, vcpkg, zig, nuget, maven, packagist. \`<spec>@<version>\`
|
|
9462
|
+
Package spec: <registry>:<name>. Supported registries: ${PKGSEER_REGISTRY_LIST}. \`<spec>@<version>\`
|
|
9431
9463
|
is NOT accepted here — use --to <version> for "entries up to this
|
|
9432
9464
|
version".`;
|
|
9433
9465
|
function registerPkgChangelogCommand(pkgCommand) {
|
|
@@ -9550,7 +9582,7 @@ groups). Concrete --lifecycle values include runtime plus matching groups.
|
|
|
9550
9582
|
conflict detection, and circular-dependency flags.
|
|
9551
9583
|
|
|
9552
9584
|
Package spec: <registry>:<name>[@<version>]. Supported registries:
|
|
9553
|
-
npm, pypi, hex, crates, vcpkg, zig. Omit @<version> for the latest
|
|
9585
|
+
npm, pypi, hex, crates, vcpkg, zig, rubygems, go. Omit @<version> for the latest
|
|
9554
9586
|
release.`;
|
|
9555
9587
|
function registerPkgDepsCommand(pkgCommand) {
|
|
9556
9588
|
return pkgCommand.command("deps").summary("Analyze dependencies for a package").description(PKG_DEPS_DESCRIPTION).argument("<spec>", "Package spec, e.g. npm:express or npm:express@4.18.0").option("-l, --lifecycle <phases>", "Dependency lifecycle breadth (runtime, development, build, peer, optional, all; comma-separated for multi-select except all).").option("-t, --transitive", "Include aggregate transitive counts, conflicts, and circular dependencies").option("--depth <n>", "Cap transitive traversal depth (1-10). Omit for the full graph.").option("-v, --verbose", "Show conditionType / selectionMode / environmentConstraints metadata in the groups view").option("--json", "Emit the lean JSON envelope").action(async (spec, options) => {
|
|
@@ -9613,8 +9645,7 @@ repository, downloads, GitHub stars, install command, and known
|
|
|
9613
9645
|
vulnerabilities. Use before picking a dependency or to orient on what
|
|
9614
9646
|
a package is.
|
|
9615
9647
|
|
|
9616
|
-
Package spec: <registry>:<name>. Supported registries:
|
|
9617
|
-
crates, nuget, maven, zig, vcpkg, packagist.
|
|
9648
|
+
Package spec: <registry>:<name>. Supported registries: ${PKGSEER_REGISTRY_LIST}.
|
|
9618
9649
|
|
|
9619
9650
|
Always returns data for the latest published version.`;
|
|
9620
9651
|
function registerPkgInfoCommand(pkgCommand) {
|
|
@@ -9732,7 +9763,7 @@ async function registerPkgCommandGroup(program, options = {}) {
|
|
|
9732
9763
|
if (!registration.shouldRegister) {
|
|
9733
9764
|
return;
|
|
9734
9765
|
}
|
|
9735
|
-
const pkgCommand = program.command("pkg").summary("Package metadata: info, vulnerabilities, dependencies, changelog").description("Inspect package metadata from npm, PyPI, Hex, Crates, NuGet, Maven, Packagist, vcpkg, and Zig: overviews, advisories, dependency graphs, and changelogs. For source-level operations inside a dependency, use `githits code`.");
|
|
9766
|
+
const pkgCommand = program.command("pkg").summary("Package metadata: info, vulnerabilities, dependencies, changelog").description("Inspect package metadata from npm, PyPI, Hex, Crates, NuGet, Maven, Packagist, RubyGems, Go, vcpkg, and Zig: overviews, advisories, dependency graphs, and changelogs. For source-level operations inside a dependency, use `githits code`.");
|
|
9736
9767
|
registerPkgInfoCommand(pkgCommand);
|
|
9737
9768
|
registerPkgVulnsCommand(pkgCommand);
|
|
9738
9769
|
registerPkgDepsCommand(pkgCommand);
|
|
@@ -9856,7 +9887,7 @@ function requireSearchService(deps) {
|
|
|
9856
9887
|
return deps.codeNavigationService;
|
|
9857
9888
|
}
|
|
9858
9889
|
async function loadContainer2() {
|
|
9859
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
9890
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-q2mre780.js");
|
|
9860
9891
|
return createContainer2();
|
|
9861
9892
|
}
|
|
9862
9893
|
function parseTargetSpecs(specs) {
|
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@ import {
|
|
|
2
2
|
createAuthCommandDependencies,
|
|
3
3
|
createAuthStatusDependencies,
|
|
4
4
|
createContainer
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import"./chunk-
|
|
5
|
+
} from "./chunk-v8sths32.js";
|
|
6
|
+
import"./chunk-jdygt0ra.js";
|
|
7
7
|
export {
|
|
8
8
|
createContainer,
|
|
9
9
|
createAuthStatusDependencies,
|
package/gemini-extension.json
CHANGED
package/package.json
CHANGED