githits 0.3.2 → 0.4.0
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 +666 -74
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-zarrkzvq.js → chunk-1cyka46a.js} +430 -65
- package/dist/shared/{chunk-rwcs5gyy.js → chunk-1h7sanjw.js} +2 -2
- package/dist/shared/{chunk-w5kw8sef.js → chunk-fqzth5mv.js} +1 -1
- package/gemini-extension.json +1 -1
- package/package.json +3 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
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-1cyka46a.js";
|
|
53
53
|
import {
|
|
54
54
|
__require,
|
|
55
55
|
version
|
|
56
|
-
} from "./shared/chunk-
|
|
56
|
+
} from "./shared/chunk-fqzth5mv.js";
|
|
57
57
|
|
|
58
58
|
// src/cli.ts
|
|
59
59
|
import { Command } from "commander";
|
|
@@ -254,9 +254,9 @@ async function authStatusAction(deps) {
|
|
|
254
254
|
`);
|
|
255
255
|
console.log(` Environment: ${mcpUrl}
|
|
256
256
|
`);
|
|
257
|
-
console.log(
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
console.log(` Storage: ${authStorage.getStorageLocation()}
|
|
258
|
+
`);
|
|
259
|
+
printAuthTroubleshooting();
|
|
260
260
|
return;
|
|
261
261
|
}
|
|
262
262
|
if (auth.expiresAt && new Date(auth.expiresAt) < new Date) {
|
|
@@ -276,8 +276,9 @@ async function authStatusAction(deps) {
|
|
|
276
276
|
console.log(` Environment: ${mcpUrl}`);
|
|
277
277
|
console.log(` Expired: ${new Date(auth.expiresAt).toLocaleDateString()}
|
|
278
278
|
`);
|
|
279
|
-
console.log(
|
|
280
|
-
|
|
279
|
+
console.log(` Storage: ${authStorage.getStorageLocation()}
|
|
280
|
+
`);
|
|
281
|
+
printAuthTroubleshooting("expired");
|
|
281
282
|
return;
|
|
282
283
|
}
|
|
283
284
|
console.log(`Authenticated.
|
|
@@ -287,6 +288,17 @@ async function authStatusAction(deps) {
|
|
|
287
288
|
console.log(`
|
|
288
289
|
Storage: ${authStorage.getStorageLocation()}`);
|
|
289
290
|
}
|
|
291
|
+
function printAuthTroubleshooting(reason = "missing") {
|
|
292
|
+
const loginCommand = reason === "expired" ? "githits login --force" : "githits login";
|
|
293
|
+
console.log("Recovery steps:");
|
|
294
|
+
console.log(` ${loginCommand}`);
|
|
295
|
+
if (reason === "missing") {
|
|
296
|
+
console.log(" githits login --force # if a previous login is stale");
|
|
297
|
+
}
|
|
298
|
+
console.log("For CI/automation, set GITHITS_API_TOKEN.");
|
|
299
|
+
console.log("If your system keychain is locked or unavailable, unlock it and retry.");
|
|
300
|
+
console.log("As a last resort, set GITHITS_AUTH_STORAGE=file to use plaintext file storage.");
|
|
301
|
+
}
|
|
290
302
|
var STATUS_DESCRIPTION = `Show current authentication status.
|
|
291
303
|
|
|
292
304
|
Displays details about the stored token including environment
|
|
@@ -353,6 +365,11 @@ function highlight(text, useColors) {
|
|
|
353
365
|
return text;
|
|
354
366
|
return `${colors.bold}${colors.cyan}${text}${colors.reset}`;
|
|
355
367
|
}
|
|
368
|
+
function highlightMatch(text, useColors) {
|
|
369
|
+
if (!useColors)
|
|
370
|
+
return text;
|
|
371
|
+
return `${colors.bold}${colors.yellow}${text}${colors.reset}`;
|
|
372
|
+
}
|
|
356
373
|
function highlightRanges(text, ranges, useColors) {
|
|
357
374
|
if (!useColors || !text || !ranges || ranges.length === 0)
|
|
358
375
|
return text;
|
|
@@ -380,7 +397,7 @@ function highlightRanges(text, ranges, useColors) {
|
|
|
380
397
|
for (const [start, end] of merged) {
|
|
381
398
|
if (cursor < start)
|
|
382
399
|
result += text.slice(cursor, start);
|
|
383
|
-
result +=
|
|
400
|
+
result += highlightMatch(text.slice(start, end), useColors);
|
|
384
401
|
cursor = end;
|
|
385
402
|
}
|
|
386
403
|
if (cursor < text.length)
|
|
@@ -763,7 +780,7 @@ function parseCodeNavigationTargetSpec(spec) {
|
|
|
763
780
|
function parseRepoTarget(spec) {
|
|
764
781
|
const hashIndex = spec.lastIndexOf("#");
|
|
765
782
|
if (hashIndex === -1) {
|
|
766
|
-
|
|
783
|
+
throw new InvalidArgumentError("Repository target must include #gitRef for exact code navigation.");
|
|
767
784
|
}
|
|
768
785
|
const repoUrl = spec.slice(0, hashIndex);
|
|
769
786
|
const gitRef = spec.slice(hashIndex + 1);
|
|
@@ -804,7 +821,8 @@ function buildSearchHitFollowUpCommand(hit) {
|
|
|
804
821
|
gitRef: loc.gitRef,
|
|
805
822
|
filePath: loc.filePath,
|
|
806
823
|
startLine: loc.startLine,
|
|
807
|
-
endLine: loc.endLine
|
|
824
|
+
endLine: loc.endLine,
|
|
825
|
+
preferPackageTarget: isPackageTarget(hit)
|
|
808
826
|
});
|
|
809
827
|
}
|
|
810
828
|
if (hit.type === "repository_code" || hit.type === "repository_symbol") {
|
|
@@ -833,14 +851,24 @@ function buildCodeReadCommand(input) {
|
|
|
833
851
|
return parts.join(" ");
|
|
834
852
|
}
|
|
835
853
|
function buildTargetSpec(input) {
|
|
854
|
+
if (input.preferPackageTarget && input.registry && input.packageName) {
|
|
855
|
+
return `${input.registry}:${input.packageName}${input.version ? `@${input.version}` : ""}`;
|
|
856
|
+
}
|
|
836
857
|
if (input.repoUrl) {
|
|
837
|
-
|
|
858
|
+
if (!input.gitRef)
|
|
859
|
+
return;
|
|
860
|
+
return `${input.repoUrl}#${input.gitRef}`;
|
|
838
861
|
}
|
|
839
862
|
if (input.registry && input.packageName) {
|
|
840
863
|
return `${input.registry}:${input.packageName}${input.version ? `@${input.version}` : ""}`;
|
|
841
864
|
}
|
|
842
865
|
return;
|
|
843
866
|
}
|
|
867
|
+
function isPackageTarget(hit) {
|
|
868
|
+
const registry = hit.locator.registry;
|
|
869
|
+
const packageName = hit.locator.packageName;
|
|
870
|
+
return Boolean(registry && packageName && hit.target.startsWith(`${registry}:${packageName}`));
|
|
871
|
+
}
|
|
844
872
|
function appendRange(parts, startLine, endLine) {
|
|
845
873
|
if (typeof startLine === "number")
|
|
846
874
|
parts.push(`start_line=${startLine}`);
|
|
@@ -1934,7 +1962,7 @@ function renderListPackageDocsText(envelope) {
|
|
|
1934
1962
|
if (page.sourceKind === "repo" && page.repoUrl && page.filePath) {
|
|
1935
1963
|
lines.push(` ${buildCodeReadCommand({
|
|
1936
1964
|
repoUrl: page.repoUrl,
|
|
1937
|
-
gitRef: page.
|
|
1965
|
+
gitRef: page.gitRef,
|
|
1938
1966
|
filePath: page.filePath,
|
|
1939
1967
|
startLine: 1,
|
|
1940
1968
|
endLine: 150
|
|
@@ -4110,7 +4138,7 @@ function renderReadPackageDocText(envelope) {
|
|
|
4110
4138
|
if (envelope.sourceUrl)
|
|
4111
4139
|
lines.push(`source: ${envelope.sourceUrl}`);
|
|
4112
4140
|
if (envelope.filePath) {
|
|
4113
|
-
const ref = envelope.
|
|
4141
|
+
const ref = envelope.gitRef;
|
|
4114
4142
|
lines.push(`file: ${envelope.filePath}${ref ? ` @ ${ref}` : ""}`);
|
|
4115
4143
|
}
|
|
4116
4144
|
lines.push("");
|
|
@@ -4140,6 +4168,121 @@ function buildRange2(envelope) {
|
|
|
4140
4168
|
return `${envelope.totalLines} lines`;
|
|
4141
4169
|
return;
|
|
4142
4170
|
}
|
|
4171
|
+
// src/shared/auto-login.ts
|
|
4172
|
+
var AUTO_LOGIN_ELIGIBLE_COMMANDS = new Set([
|
|
4173
|
+
"example",
|
|
4174
|
+
"languages",
|
|
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;
|
|
4197
|
+
}
|
|
4198
|
+
return names;
|
|
4199
|
+
}
|
|
4200
|
+
function isAutoLoginEligibleCommand(command, runtime = {
|
|
4201
|
+
stdinIsTTY: Boolean(process.stdin.isTTY),
|
|
4202
|
+
stdoutIsTTY: Boolean(process.stdout.isTTY)
|
|
4203
|
+
}) {
|
|
4204
|
+
const commandPath = getCommandPath(command).join(" ");
|
|
4205
|
+
if (!AUTO_LOGIN_ELIGIBLE_COMMANDS.has(commandPath)) {
|
|
4206
|
+
return false;
|
|
4207
|
+
}
|
|
4208
|
+
if (!runtime.stdinIsTTY || !runtime.stdoutIsTTY) {
|
|
4209
|
+
return false;
|
|
4210
|
+
}
|
|
4211
|
+
return true;
|
|
4212
|
+
}
|
|
4213
|
+
async function maybeAutoLoginBeforeCommand(command, deps) {
|
|
4214
|
+
if (!isAutoLoginEligibleCommand(command, {
|
|
4215
|
+
stdinIsTTY: deps.stdinIsTTY ?? Boolean(process.stdin.isTTY),
|
|
4216
|
+
stdoutIsTTY: deps.stdoutIsTTY ?? Boolean(process.stdout.isTTY)
|
|
4217
|
+
})) {
|
|
4218
|
+
return { status: "skipped" };
|
|
4219
|
+
}
|
|
4220
|
+
const container = await deps.createContainer();
|
|
4221
|
+
if (container.hasValidToken) {
|
|
4222
|
+
return { status: "already-authenticated" };
|
|
4223
|
+
}
|
|
4224
|
+
const result = await deps.loginFlow({}, container);
|
|
4225
|
+
switch (result.status) {
|
|
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 };
|
|
4232
|
+
}
|
|
4233
|
+
}
|
|
4234
|
+
|
|
4235
|
+
// src/shared/root-cli-pre-action.ts
|
|
4236
|
+
function createRootCliPreAction(deps) {
|
|
4237
|
+
return async (thisCommand, actionCommand) => {
|
|
4238
|
+
if (thisCommand.opts().color === false) {
|
|
4239
|
+
process.env.NO_COLOR = "1";
|
|
4240
|
+
}
|
|
4241
|
+
const command = actionCommand ?? thisCommand;
|
|
4242
|
+
const authResult = await maybeAutoLoginBeforeCommand(command, {
|
|
4243
|
+
...deps,
|
|
4244
|
+
stdinIsTTY: deps.stdinIsTTY,
|
|
4245
|
+
stdoutIsTTY: deps.stdoutIsTTY
|
|
4246
|
+
});
|
|
4247
|
+
if (authResult.status === "authenticated") {
|
|
4248
|
+
const continuationMessage = getPostLoginContinuationMessage(command);
|
|
4249
|
+
if (continuationMessage) {
|
|
4250
|
+
console.error(continuationMessage);
|
|
4251
|
+
}
|
|
4252
|
+
}
|
|
4253
|
+
if (authResult.status !== "failed") {
|
|
4254
|
+
return;
|
|
4255
|
+
}
|
|
4256
|
+
console.error(`${authResult.message}
|
|
4257
|
+
`);
|
|
4258
|
+
console.error("Run `githits login` to try again.");
|
|
4259
|
+
(deps.exit ?? process.exit)(1);
|
|
4260
|
+
};
|
|
4261
|
+
}
|
|
4262
|
+
function getPostLoginContinuationMessage(command) {
|
|
4263
|
+
switch (getCommandPath(command).join(" ")) {
|
|
4264
|
+
case "example":
|
|
4265
|
+
return "Authentication complete. Running example search...";
|
|
4266
|
+
case "languages":
|
|
4267
|
+
return "Authentication complete. Loading supported languages...";
|
|
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;
|
|
4284
|
+
}
|
|
4285
|
+
}
|
|
4143
4286
|
// src/shared/unified-search-request.ts
|
|
4144
4287
|
var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
|
|
4145
4288
|
function buildUnifiedSearchParams(input) {
|
|
@@ -4192,11 +4335,6 @@ function resolveTargets(target, targets) {
|
|
|
4192
4335
|
seen.add(key);
|
|
4193
4336
|
deduped.push(entry);
|
|
4194
4337
|
}
|
|
4195
|
-
const hasPackageTarget = deduped.some((entry) => entry.packageName);
|
|
4196
|
-
const hasRepoTarget = deduped.some((entry) => entry.repoUrl);
|
|
4197
|
-
if (hasPackageTarget && hasRepoTarget) {
|
|
4198
|
-
throw new InvalidArgumentError("Do not mix package-scoped and repo-scoped targets in one search.");
|
|
4199
|
-
}
|
|
4200
4338
|
return deduped;
|
|
4201
4339
|
}
|
|
4202
4340
|
function normaliseRequiredQuery(query) {
|
|
@@ -4255,6 +4393,7 @@ var DEFAULT_LIMIT2 = DEFAULT_UNIFIED_SEARCH_LIMIT;
|
|
|
4255
4393
|
var DEFAULT_OFFSET = 0;
|
|
4256
4394
|
function buildUnifiedSearchSuccessPayload(params, rawQuery, compiledQuery, outcome) {
|
|
4257
4395
|
const warnings = outcome.state === "completed" ? outcome.result.queryWarnings : outcome.result?.queryWarnings ?? outcome.progress?.queryWarnings ?? [];
|
|
4396
|
+
const progress = compactProgress(outcome.progress);
|
|
4258
4397
|
const query = buildQueryEcho(params, rawQuery, compiledQuery, warnings);
|
|
4259
4398
|
if (outcome.state === "incomplete") {
|
|
4260
4399
|
const result = outcome.result;
|
|
@@ -4268,13 +4407,12 @@ function buildUnifiedSearchSuccessPayload(params, rawQuery, compiledQuery, outco
|
|
|
4268
4407
|
if (result?.page.hasMore === true) {
|
|
4269
4408
|
payload.nextOffset = result.page.offset + result.page.returned;
|
|
4270
4409
|
}
|
|
4271
|
-
const progress = compactProgress(outcome.progress);
|
|
4272
4410
|
if (progress)
|
|
4273
4411
|
payload.progress = progress;
|
|
4274
4412
|
const sourceStatus2 = compactSourceStatus(result?.sourceStatus);
|
|
4275
4413
|
if (sourceStatus2)
|
|
4276
4414
|
payload.sourceStatus = sourceStatus2;
|
|
4277
|
-
const combinedWarnings2 = combineWarnings(warnings, sourceStatus2);
|
|
4415
|
+
const combinedWarnings2 = combineWarnings(warnings, sourceStatus2, payload.results, progress);
|
|
4278
4416
|
if (combinedWarnings2.length > 0)
|
|
4279
4417
|
payload.warnings = combinedWarnings2;
|
|
4280
4418
|
return payload;
|
|
@@ -4293,15 +4431,17 @@ function buildUnifiedSearchSuccessPayload(params, rawQuery, compiledQuery, outco
|
|
|
4293
4431
|
const sourceStatus = compactSourceStatus(outcome.result.sourceStatus);
|
|
4294
4432
|
if (sourceStatus)
|
|
4295
4433
|
completed.sourceStatus = sourceStatus;
|
|
4296
|
-
const combinedWarnings = combineWarnings(warnings, sourceStatus);
|
|
4434
|
+
const combinedWarnings = combineWarnings(warnings, sourceStatus, completed.results, progress);
|
|
4297
4435
|
if (combinedWarnings.length > 0)
|
|
4298
4436
|
completed.warnings = combinedWarnings;
|
|
4299
4437
|
return completed;
|
|
4300
4438
|
}
|
|
4301
|
-
function combineWarnings(parserWarnings, sourceStatus) {
|
|
4439
|
+
function combineWarnings(parserWarnings, sourceStatus, hits = [], progress) {
|
|
4302
4440
|
const out = [];
|
|
4303
4441
|
if (parserWarnings.length > 0)
|
|
4304
4442
|
out.push(...parserWarnings);
|
|
4443
|
+
out.push(...buildHitFreshnessWarnings(hits));
|
|
4444
|
+
out.push(...buildProgressFreshnessWarnings(progress));
|
|
4305
4445
|
out.push(...buildSourceStatusWarnings(sourceStatus));
|
|
4306
4446
|
return out;
|
|
4307
4447
|
}
|
|
@@ -4328,6 +4468,9 @@ function buildUnifiedSearchStatusPayload(outcome) {
|
|
|
4328
4468
|
const progress = compactProgress(outcome.progress);
|
|
4329
4469
|
if (progress)
|
|
4330
4470
|
payload2.progress = progress;
|
|
4471
|
+
const progressWarnings = buildProgressFreshnessWarnings(progress);
|
|
4472
|
+
if (progressWarnings.length > 0)
|
|
4473
|
+
payload2.warnings = progressWarnings;
|
|
4331
4474
|
if (outcome.result) {
|
|
4332
4475
|
payload2.result = buildUnifiedSearchStatusResultPayload(outcome.result);
|
|
4333
4476
|
}
|
|
@@ -4343,6 +4486,7 @@ function buildUnifiedSearchStatusPayload(outcome) {
|
|
|
4343
4486
|
}
|
|
4344
4487
|
function buildUnifiedSearchStatusResultPayload(result) {
|
|
4345
4488
|
const payload = {
|
|
4489
|
+
query: buildStatusQueryEcho(result),
|
|
4346
4490
|
hasMore: result.page.hasMore,
|
|
4347
4491
|
results: result.results.map(buildHitPayload)
|
|
4348
4492
|
};
|
|
@@ -4361,6 +4505,18 @@ function buildUnifiedSearchStatusResultPayload(result) {
|
|
|
4361
4505
|
}
|
|
4362
4506
|
return payload;
|
|
4363
4507
|
}
|
|
4508
|
+
function buildStatusQueryEcho(result) {
|
|
4509
|
+
const query = {
|
|
4510
|
+
raw: result.query
|
|
4511
|
+
};
|
|
4512
|
+
if (result.queryWarnings.length > 0) {
|
|
4513
|
+
query.warnings = result.queryWarnings;
|
|
4514
|
+
}
|
|
4515
|
+
if (result.sources.length > 0) {
|
|
4516
|
+
query.sources = result.sources.map((entry) => entry.toLowerCase());
|
|
4517
|
+
}
|
|
4518
|
+
return query;
|
|
4519
|
+
}
|
|
4364
4520
|
function buildQueryEcho(params, rawQuery, compiledQuery, warnings) {
|
|
4365
4521
|
const echo = {
|
|
4366
4522
|
raw: rawQuery
|
|
@@ -4410,6 +4566,12 @@ function buildHitPayload(hit) {
|
|
|
4410
4566
|
target: hit.targetLabel,
|
|
4411
4567
|
locator: buildLocatorPayload(hit)
|
|
4412
4568
|
};
|
|
4569
|
+
appendFreshness(payload, {
|
|
4570
|
+
requestedTargetLabel: hit.requestedTargetLabel,
|
|
4571
|
+
freshTargetLabel: hit.freshTargetLabel,
|
|
4572
|
+
servedTargetLabel: hit.servedTargetLabel,
|
|
4573
|
+
freshness: hit.freshness
|
|
4574
|
+
});
|
|
4413
4575
|
if (hit.title)
|
|
4414
4576
|
payload.title = hit.title;
|
|
4415
4577
|
if (hit.summary)
|
|
@@ -4417,6 +4579,9 @@ function buildHitPayload(hit) {
|
|
|
4417
4579
|
const highlights = buildHighlights(hit.highlights);
|
|
4418
4580
|
if (highlights)
|
|
4419
4581
|
payload.highlights = highlights;
|
|
4582
|
+
const followUp = buildSearchHitFollowUpCommand(payload);
|
|
4583
|
+
if (followUp)
|
|
4584
|
+
payload.followUp = followUp;
|
|
4420
4585
|
return payload;
|
|
4421
4586
|
}
|
|
4422
4587
|
function buildLocatorPayload(hit) {
|
|
@@ -4478,10 +4643,79 @@ function compactProgress(progress) {
|
|
|
4478
4643
|
targetsTotal: progress.targetsTotal,
|
|
4479
4644
|
elapsedMs: progress.elapsedMs
|
|
4480
4645
|
};
|
|
4646
|
+
if (progress.query)
|
|
4647
|
+
payload.query = progress.query;
|
|
4648
|
+
if (progress.requestedSources?.length) {
|
|
4649
|
+
payload.requestedSources = progress.requestedSources.map((entry) => entry.toLowerCase());
|
|
4650
|
+
}
|
|
4651
|
+
if (progress.targetMode)
|
|
4652
|
+
payload.targetMode = progress.targetMode;
|
|
4653
|
+
if (progress.requestedTargets?.length) {
|
|
4654
|
+
payload.requestedTargets = progress.requestedTargets;
|
|
4655
|
+
}
|
|
4656
|
+
if (progress.filters)
|
|
4657
|
+
payload.filters = buildFilterEcho3(progress.filters);
|
|
4658
|
+
if (typeof progress.limit === "number")
|
|
4659
|
+
payload.limit = progress.limit;
|
|
4660
|
+
if (typeof progress.offset === "number")
|
|
4661
|
+
payload.offset = progress.offset;
|
|
4662
|
+
const targets = progress.targets?.map(compactProgressTarget).filter(Boolean);
|
|
4663
|
+
if (targets?.length) {
|
|
4664
|
+
payload.targets = targets;
|
|
4665
|
+
}
|
|
4481
4666
|
if (progress.expiresAt)
|
|
4482
4667
|
payload.expiresAt = progress.expiresAt;
|
|
4668
|
+
payload.next = `search_status search_ref=${JSON.stringify(progress.searchRef)}`;
|
|
4483
4669
|
return payload;
|
|
4484
4670
|
}
|
|
4671
|
+
function appendFreshness(payload, source) {
|
|
4672
|
+
if (!isTrustRelevantFreshness(source.freshness) || !labelsDiverge({
|
|
4673
|
+
requestedTarget: source.requestedTargetLabel,
|
|
4674
|
+
freshTarget: source.freshTargetLabel,
|
|
4675
|
+
servedTarget: source.servedTargetLabel
|
|
4676
|
+
})) {
|
|
4677
|
+
return;
|
|
4678
|
+
}
|
|
4679
|
+
if (source.requestedTargetLabel)
|
|
4680
|
+
payload.requestedTarget = source.requestedTargetLabel;
|
|
4681
|
+
if (source.freshTargetLabel)
|
|
4682
|
+
payload.freshTarget = source.freshTargetLabel;
|
|
4683
|
+
if (source.servedTargetLabel)
|
|
4684
|
+
payload.servedTarget = source.servedTargetLabel;
|
|
4685
|
+
if (source.freshness)
|
|
4686
|
+
payload.freshness = source.freshness;
|
|
4687
|
+
}
|
|
4688
|
+
function compactProgressTarget(target) {
|
|
4689
|
+
const payload = {};
|
|
4690
|
+
if (target.requested)
|
|
4691
|
+
payload.requested = target.requested;
|
|
4692
|
+
if (target.resolvedRequested)
|
|
4693
|
+
payload.resolvedRequested = target.resolvedRequested;
|
|
4694
|
+
if (target.served)
|
|
4695
|
+
payload.served = target.served;
|
|
4696
|
+
if (target.freshness)
|
|
4697
|
+
payload.freshness = target.freshness;
|
|
4698
|
+
if (target.indexingRef)
|
|
4699
|
+
payload.indexingRef = target.indexingRef;
|
|
4700
|
+
if (target.requestedRefKind)
|
|
4701
|
+
payload.requestedRefKind = target.requestedRefKind;
|
|
4702
|
+
return Object.keys(payload).length > 0 ? payload : undefined;
|
|
4703
|
+
}
|
|
4704
|
+
function buildFilterEcho3(filters) {
|
|
4705
|
+
const echo = {};
|
|
4706
|
+
if (filters.kind)
|
|
4707
|
+
echo.kind = filters.kind.toLowerCase();
|
|
4708
|
+
if (filters.category)
|
|
4709
|
+
echo.category = filters.category.toLowerCase();
|
|
4710
|
+
if (filters.pathPrefix)
|
|
4711
|
+
echo.pathPrefix = filters.pathPrefix;
|
|
4712
|
+
if (filters.fileIntent)
|
|
4713
|
+
echo.fileIntent = filters.fileIntent.toLowerCase();
|
|
4714
|
+
if (typeof filters.publicOnly === "boolean") {
|
|
4715
|
+
echo.publicOnly = filters.publicOnly;
|
|
4716
|
+
}
|
|
4717
|
+
return Object.keys(echo).length > 0 ? echo : undefined;
|
|
4718
|
+
}
|
|
4485
4719
|
function buildSourceStatusWarnings(sourceStatus) {
|
|
4486
4720
|
if (!sourceStatus || sourceStatus.length === 0)
|
|
4487
4721
|
return [];
|
|
@@ -4493,8 +4727,51 @@ function buildSourceStatusWarnings(sourceStatus) {
|
|
|
4493
4727
|
}
|
|
4494
4728
|
return warnings;
|
|
4495
4729
|
}
|
|
4730
|
+
function buildHitFreshnessWarnings(hits) {
|
|
4731
|
+
return hits.map((hit) => freshnessWarning({
|
|
4732
|
+
freshness: hit.freshness,
|
|
4733
|
+
requestedTarget: hit.requestedTarget,
|
|
4734
|
+
freshTarget: hit.freshTarget,
|
|
4735
|
+
servedTarget: hit.servedTarget
|
|
4736
|
+
})).filter((entry) => Boolean(entry));
|
|
4737
|
+
}
|
|
4738
|
+
function buildProgressFreshnessWarnings(progress) {
|
|
4739
|
+
return (progress?.targets ?? []).map((target) => freshnessWarning({
|
|
4740
|
+
freshness: target.freshness,
|
|
4741
|
+
requestedTarget: target.requested,
|
|
4742
|
+
freshTarget: target.resolvedRequested,
|
|
4743
|
+
servedTarget: target.served
|
|
4744
|
+
})).filter((entry) => Boolean(entry));
|
|
4745
|
+
}
|
|
4746
|
+
function freshnessWarning(input) {
|
|
4747
|
+
if (!isTrustRelevantFreshness(input.freshness))
|
|
4748
|
+
return;
|
|
4749
|
+
if (!labelsDiverge(input))
|
|
4750
|
+
return;
|
|
4751
|
+
const requested = input.requestedTarget ?? "requested target";
|
|
4752
|
+
const served = input.servedTarget ?? "served target";
|
|
4753
|
+
const fresh = input.freshTarget;
|
|
4754
|
+
return fresh ? `requested ${requested}; served stale ${served} while ${fresh} indexes.` : `requested ${requested}; served stale ${served}.`;
|
|
4755
|
+
}
|
|
4756
|
+
function isTrustRelevantFreshness(value) {
|
|
4757
|
+
return value === "STALE" || value === "INDEXING";
|
|
4758
|
+
}
|
|
4759
|
+
function labelsDiverge(input) {
|
|
4760
|
+
const served = input.servedTarget;
|
|
4761
|
+
if (!served)
|
|
4762
|
+
return false;
|
|
4763
|
+
return Boolean(input.freshTarget && input.freshTarget !== served || input.requestedTarget && input.requestedTarget !== served);
|
|
4764
|
+
}
|
|
4496
4765
|
function warningForEntry(entry) {
|
|
4497
4766
|
const reasons = [];
|
|
4767
|
+
const freshness = freshnessWarning({
|
|
4768
|
+
freshness: entry.codeIndexState,
|
|
4769
|
+
requestedTarget: entry.requestedTarget,
|
|
4770
|
+
freshTarget: entry.freshTarget,
|
|
4771
|
+
servedTarget: entry.servedTarget
|
|
4772
|
+
});
|
|
4773
|
+
if (freshness)
|
|
4774
|
+
return freshness;
|
|
4498
4775
|
if (entry.incompatibleQueryFeatures?.length) {
|
|
4499
4776
|
reasons.push(`incompatible query features [${entry.incompatibleQueryFeatures.join(", ")}]`);
|
|
4500
4777
|
}
|
|
@@ -4511,7 +4788,9 @@ function warningForEntry(entry) {
|
|
|
4511
4788
|
reasons.push(`indexing status ${entry.indexingStatus}`);
|
|
4512
4789
|
}
|
|
4513
4790
|
if (entry.codeIndexState) {
|
|
4514
|
-
|
|
4791
|
+
if (entry.codeIndexState !== "STALE") {
|
|
4792
|
+
reasons.push(`code index state ${entry.codeIndexState}`);
|
|
4793
|
+
}
|
|
4515
4794
|
}
|
|
4516
4795
|
const prefix = `Source '${entry.source}' for ${entry.targetLabel}`;
|
|
4517
4796
|
if (reasons.length > 0) {
|
|
@@ -4539,11 +4818,23 @@ function compactSourceStatusEntry(entry) {
|
|
|
4539
4818
|
targetLabel: entry.targetLabel
|
|
4540
4819
|
};
|
|
4541
4820
|
let interesting = false;
|
|
4821
|
+
const staleDiverges = entry.codeIndexState === "STALE" && labelsDiverge({
|
|
4822
|
+
requestedTarget: entry.requestedTargetLabel,
|
|
4823
|
+
freshTarget: entry.freshTargetLabel,
|
|
4824
|
+
servedTarget: entry.servedTargetLabel
|
|
4825
|
+
});
|
|
4826
|
+
if (staleDiverges) {
|
|
4827
|
+
payload.requestedTarget = entry.requestedTargetLabel;
|
|
4828
|
+
payload.freshTarget = entry.freshTargetLabel;
|
|
4829
|
+
payload.servedTarget = entry.servedTargetLabel;
|
|
4830
|
+
payload.codeIndexState = entry.codeIndexState;
|
|
4831
|
+
interesting = true;
|
|
4832
|
+
}
|
|
4542
4833
|
if (entry.indexingStatus && entry.indexingStatus !== "INDEXED") {
|
|
4543
4834
|
payload.indexingStatus = entry.indexingStatus;
|
|
4544
4835
|
interesting = true;
|
|
4545
4836
|
}
|
|
4546
|
-
if (entry.codeIndexState && entry.codeIndexState !== "CURRENT" && entry.codeIndexState !== "STALE") {
|
|
4837
|
+
if (entry.codeIndexState && entry.codeIndexState !== "CURRENT" && (entry.codeIndexState !== "STALE" || staleDiverges)) {
|
|
4547
4838
|
payload.codeIndexState = entry.codeIndexState;
|
|
4548
4839
|
interesting = true;
|
|
4549
4840
|
}
|
|
@@ -4718,8 +5009,45 @@ function buildTrailer2(payload) {
|
|
|
4718
5009
|
lines.push(` - ${formatSourceStatus(entry)}`);
|
|
4719
5010
|
}
|
|
4720
5011
|
}
|
|
5012
|
+
const progress = "progress" in payload ? payload.progress : undefined;
|
|
5013
|
+
if (progress?.targets?.length) {
|
|
5014
|
+
lines.push("progress targets:");
|
|
5015
|
+
for (const target of progress.targets) {
|
|
5016
|
+
lines.push(` - ${formatProgressTarget(target)}`);
|
|
5017
|
+
}
|
|
5018
|
+
}
|
|
4721
5019
|
return lines;
|
|
4722
5020
|
}
|
|
5021
|
+
function formatProgressTarget(target) {
|
|
5022
|
+
const parts = [];
|
|
5023
|
+
if (target.requested)
|
|
5024
|
+
parts.push(`requested=${target.requested}`);
|
|
5025
|
+
if (target.resolvedRequested)
|
|
5026
|
+
parts.push(`fresh=${target.resolvedRequested}`);
|
|
5027
|
+
if (target.served)
|
|
5028
|
+
parts.push(`served=${target.served}`);
|
|
5029
|
+
if (target.freshness)
|
|
5030
|
+
parts.push(`state=${describeFreshness(target.freshness)}`);
|
|
5031
|
+
if (target.requestedRefKind)
|
|
5032
|
+
parts.push(`intent=${target.requestedRefKind}`);
|
|
5033
|
+
if (target.indexingRef)
|
|
5034
|
+
parts.push(`indexingRef=${target.indexingRef}`);
|
|
5035
|
+
return parts.length > 0 ? parts.join(SEP6) : "target progress unavailable";
|
|
5036
|
+
}
|
|
5037
|
+
function describeFreshness(value) {
|
|
5038
|
+
switch (value) {
|
|
5039
|
+
case "PENDING":
|
|
5040
|
+
case "INDEXING":
|
|
5041
|
+
return "indexing fresh target";
|
|
5042
|
+
case "STALE":
|
|
5043
|
+
return "served stale evidence";
|
|
5044
|
+
case "CURRENT":
|
|
5045
|
+
case "INDEXED":
|
|
5046
|
+
return "current";
|
|
5047
|
+
default:
|
|
5048
|
+
return value.toLowerCase();
|
|
5049
|
+
}
|
|
5050
|
+
}
|
|
4723
5051
|
function formatSourceStatus(entry) {
|
|
4724
5052
|
const parts = [`${entry.source} (${entry.targetLabel})`];
|
|
4725
5053
|
if (entry.indexingStatus)
|
|
@@ -4782,6 +5110,17 @@ function renderUnifiedSearchStatusText(payload) {
|
|
|
4782
5110
|
lines.push(buildHeader8(payload));
|
|
4783
5111
|
if (!payload.completed && payload.progress) {
|
|
4784
5112
|
lines.push(formatProgress(payload.progress));
|
|
5113
|
+
if (payload.progress.targets?.length) {
|
|
5114
|
+
lines.push("progress targets:");
|
|
5115
|
+
for (const target of payload.progress.targets) {
|
|
5116
|
+
lines.push(` - ${formatProgressTarget(target)}`);
|
|
5117
|
+
}
|
|
5118
|
+
}
|
|
5119
|
+
}
|
|
5120
|
+
if (!payload.completed && payload.warnings && payload.warnings.length > 0) {
|
|
5121
|
+
lines.push("warnings:");
|
|
5122
|
+
for (const warning2 of payload.warnings)
|
|
5123
|
+
lines.push(` - ${warning2}`);
|
|
4785
5124
|
}
|
|
4786
5125
|
const result = payload.result;
|
|
4787
5126
|
if (result)
|
|
@@ -4848,14 +5187,39 @@ function formatSourceStatus2(entry) {
|
|
|
4848
5187
|
return parts.join(SEP7);
|
|
4849
5188
|
}
|
|
4850
5189
|
function formatProgress(progress) {
|
|
4851
|
-
|
|
5190
|
+
const next = progress.next ? `; next: ${progress.next}` : "";
|
|
5191
|
+
return `progress: ${progress.status}, ${progress.targetsReady}/${progress.targetsTotal} targets ready, ${progress.elapsedMs}ms elapsed${next}`;
|
|
4852
5192
|
}
|
|
4853
5193
|
function quote5(value) {
|
|
4854
5194
|
return JSON.stringify(value);
|
|
4855
5195
|
}
|
|
4856
5196
|
// src/shared/unified-search-target.ts
|
|
4857
5197
|
function parseUnifiedSearchTargetSpec(spec) {
|
|
4858
|
-
|
|
5198
|
+
const trimmed = spec.trim();
|
|
5199
|
+
if (trimmed.length === 0) {
|
|
5200
|
+
throw new InvalidArgumentError("Target spec cannot be empty.");
|
|
5201
|
+
}
|
|
5202
|
+
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
|
|
5203
|
+
return parseDiscoveryRepoTarget(trimmed);
|
|
5204
|
+
}
|
|
5205
|
+
const parsed = parsePackageSpec(trimmed);
|
|
5206
|
+
return {
|
|
5207
|
+
registry: toCodeNavigationRegistry(parsed.registry),
|
|
5208
|
+
packageName: parsed.name,
|
|
5209
|
+
version: parsed.version
|
|
5210
|
+
};
|
|
5211
|
+
}
|
|
5212
|
+
function parseDiscoveryRepoTarget(spec) {
|
|
5213
|
+
const hashIndex = spec.lastIndexOf("#");
|
|
5214
|
+
if (hashIndex === -1) {
|
|
5215
|
+
return { repoUrl: spec };
|
|
5216
|
+
}
|
|
5217
|
+
const repoUrl = spec.slice(0, hashIndex);
|
|
5218
|
+
const gitRef = spec.slice(hashIndex + 1);
|
|
5219
|
+
if (!repoUrl || !gitRef) {
|
|
5220
|
+
throw new InvalidArgumentError("Repository target must be a full URL with optional #gitRef suffix.");
|
|
5221
|
+
}
|
|
5222
|
+
return { repoUrl, gitRef };
|
|
4859
5223
|
}
|
|
4860
5224
|
// src/shared/list-files-request.ts
|
|
4861
5225
|
var LIMIT_MIN2 = 1;
|
|
@@ -5613,7 +5977,7 @@ grep run. --symbol-field hydrates enclosing symbol metadata (appears under each
|
|
|
5613
5977
|
match in --verbose output; full payload in --json).`;
|
|
5614
5978
|
function registerCodeGrepCommand(pkgCommand) {
|
|
5615
5979
|
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) => {
|
|
5616
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
5980
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-1h7sanjw.js");
|
|
5617
5981
|
const deps = await createContainer2();
|
|
5618
5982
|
await pkgGrepAction(arg1, arg2, arg3, options, {
|
|
5619
5983
|
codeNavigationService: deps.codeNavigationService,
|
|
@@ -6089,6 +6453,10 @@ async function registerDocsCommandGroup(program, options = {}) {
|
|
|
6089
6453
|
// src/commands/example.ts
|
|
6090
6454
|
import { Option } from "commander";
|
|
6091
6455
|
async function exampleAction(query, options, deps) {
|
|
6456
|
+
if (!deps.hasValidToken && options.json) {
|
|
6457
|
+
printExampleError("Authentication required. Run `githits login`, then retry this command.", "AUTH_REQUIRED", true);
|
|
6458
|
+
process.exit(1);
|
|
6459
|
+
}
|
|
6092
6460
|
requireAuth(deps);
|
|
6093
6461
|
try {
|
|
6094
6462
|
const result = await deps.githitsService.search({
|
|
@@ -6105,10 +6473,21 @@ async function exampleAction(query, options, deps) {
|
|
|
6105
6473
|
console.log(result);
|
|
6106
6474
|
}
|
|
6107
6475
|
} catch (error2) {
|
|
6108
|
-
|
|
6476
|
+
if (error2 instanceof AuthenticationError) {
|
|
6477
|
+
printExampleError("Authentication required. Run `githits login`, then retry this command.", "AUTH_REQUIRED", options.json ?? false);
|
|
6478
|
+
process.exit(1);
|
|
6479
|
+
}
|
|
6480
|
+
printExampleError(`Failed to get example: ${error2 instanceof Error ? error2.message : error2}`, "UNKNOWN", options.json ?? false);
|
|
6109
6481
|
process.exit(1);
|
|
6110
6482
|
}
|
|
6111
6483
|
}
|
|
6484
|
+
function printExampleError(error2, code, json) {
|
|
6485
|
+
if (json) {
|
|
6486
|
+
console.error(JSON.stringify({ error: error2, code, retryable: false }));
|
|
6487
|
+
return;
|
|
6488
|
+
}
|
|
6489
|
+
console.error(error2);
|
|
6490
|
+
}
|
|
6112
6491
|
var EXAMPLE_DESCRIPTION = `Get verified, canonical code examples from global open source.
|
|
6113
6492
|
|
|
6114
6493
|
For dependency, package, or repository source search, use \`githits search\` instead.
|
|
@@ -6132,7 +6511,7 @@ function registerExampleCommand(program) {
|
|
|
6132
6511
|
});
|
|
6133
6512
|
}
|
|
6134
6513
|
async function loadContainer() {
|
|
6135
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
6514
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-1h7sanjw.js");
|
|
6136
6515
|
return createContainer2();
|
|
6137
6516
|
}
|
|
6138
6517
|
// src/commands/feedback.ts
|
|
@@ -6902,6 +7281,16 @@ class ExitPromptError extends Error {
|
|
|
6902
7281
|
name = "ExitPromptError";
|
|
6903
7282
|
}
|
|
6904
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
|
+
};
|
|
6905
7294
|
var TIMEOUT_MS = 5 * 60 * 1000;
|
|
6906
7295
|
function randomPort() {
|
|
6907
7296
|
return Math.floor(Math.random() * 2000) + 8000;
|
|
@@ -6933,7 +7322,7 @@ async function preflightAuthPersistence(authStorage, mcpUrl) {
|
|
|
6933
7322
|
};
|
|
6934
7323
|
}
|
|
6935
7324
|
}
|
|
6936
|
-
async function loginFlow(options, deps) {
|
|
7325
|
+
async function loginFlow(options, deps, output = stdoutLoginOutput) {
|
|
6937
7326
|
const { authService, authStorage, browserService, mcpUrl } = deps;
|
|
6938
7327
|
if (options.port !== undefined && (Number.isNaN(options.port) || options.port < 1 || options.port > 65535)) {
|
|
6939
7328
|
return {
|
|
@@ -6947,10 +7336,10 @@ async function loginFlow(options, deps) {
|
|
|
6947
7336
|
if (!isExpired) {
|
|
6948
7337
|
return { status: "already_authenticated", message: "Already logged in." };
|
|
6949
7338
|
}
|
|
6950
|
-
|
|
7339
|
+
output.write(`Token expired. Starting new login...
|
|
6951
7340
|
`);
|
|
6952
7341
|
} else if (existing && options.force) {
|
|
6953
|
-
|
|
7342
|
+
output.write(`Re-authenticating (--force flag)...
|
|
6954
7343
|
`);
|
|
6955
7344
|
}
|
|
6956
7345
|
if (!existing) {
|
|
@@ -6959,7 +7348,7 @@ async function loginFlow(options, deps) {
|
|
|
6959
7348
|
const persistenceError = await preflightAuthPersistence(authStorage, mcpUrl);
|
|
6960
7349
|
if (persistenceError)
|
|
6961
7350
|
return persistenceError;
|
|
6962
|
-
|
|
7351
|
+
output.write("Discovering OAuth endpoints...");
|
|
6963
7352
|
const metadata = await authService.discoverEndpoints(mcpUrl);
|
|
6964
7353
|
let client = await authStorage.loadClient(mcpUrl);
|
|
6965
7354
|
let port;
|
|
@@ -6968,7 +7357,7 @@ async function loginFlow(options, deps) {
|
|
|
6968
7357
|
if (options.port) {
|
|
6969
7358
|
redirectUri = `http://127.0.0.1:${options.port}/callback`;
|
|
6970
7359
|
if (redirectUri !== client.redirectUri) {
|
|
6971
|
-
|
|
7360
|
+
output.write("Registering CLI client with new port...");
|
|
6972
7361
|
const registration = await authService.registerClient({
|
|
6973
7362
|
registrationEndpoint: metadata.registrationEndpoint,
|
|
6974
7363
|
redirectUri
|
|
@@ -6989,7 +7378,7 @@ async function loginFlow(options, deps) {
|
|
|
6989
7378
|
} else {
|
|
6990
7379
|
port = options.port ?? randomPort();
|
|
6991
7380
|
redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
6992
|
-
|
|
7381
|
+
output.write("Registering CLI client...");
|
|
6993
7382
|
const registration = await authService.registerClient({
|
|
6994
7383
|
registrationEndpoint: metadata.registrationEndpoint,
|
|
6995
7384
|
redirectUri
|
|
@@ -7009,17 +7398,33 @@ async function loginFlow(options, deps) {
|
|
|
7009
7398
|
state,
|
|
7010
7399
|
codeChallenge: challenge
|
|
7011
7400
|
});
|
|
7012
|
-
|
|
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
|
+
}
|
|
7013
7408
|
if (options.browser === false) {
|
|
7014
|
-
|
|
7409
|
+
output.write(`Open this URL in your browser:
|
|
7015
7410
|
`);
|
|
7016
|
-
|
|
7411
|
+
output.write(` ${authUrl}
|
|
7017
7412
|
`);
|
|
7018
7413
|
} else {
|
|
7019
|
-
|
|
7020
|
-
|
|
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
|
+
}
|
|
7021
7426
|
}
|
|
7022
|
-
|
|
7427
|
+
output.write(`Waiting for authentication...
|
|
7023
7428
|
`);
|
|
7024
7429
|
let timeoutId;
|
|
7025
7430
|
const timeoutPromise = new Promise((_, reject) => {
|
|
@@ -7027,12 +7432,13 @@ async function loginFlow(options, deps) {
|
|
|
7027
7432
|
});
|
|
7028
7433
|
let callback;
|
|
7029
7434
|
try {
|
|
7030
|
-
callback = await Promise.race([
|
|
7435
|
+
callback = await Promise.race([callbackServer.result, timeoutPromise]);
|
|
7031
7436
|
if (timeoutId)
|
|
7032
7437
|
clearTimeout(timeoutId);
|
|
7033
7438
|
} catch (error2) {
|
|
7034
7439
|
if (timeoutId)
|
|
7035
7440
|
clearTimeout(timeoutId);
|
|
7441
|
+
await callbackServer.close().catch(() => {});
|
|
7036
7442
|
const msg = error2 instanceof Error ? error2.message : "Authentication failed";
|
|
7037
7443
|
return { status: "failed", message: `${msg}.` };
|
|
7038
7444
|
}
|
|
@@ -7077,7 +7483,7 @@ async function loginFlow(options, deps) {
|
|
|
7077
7483
|
};
|
|
7078
7484
|
}
|
|
7079
7485
|
async function loginAction(options, deps) {
|
|
7080
|
-
const result = await loginFlow(options, deps);
|
|
7486
|
+
const result = await loginFlow(options, deps, stdoutLoginOutput);
|
|
7081
7487
|
if (result.status === "already_authenticated") {
|
|
7082
7488
|
console.log(`Already logged in.
|
|
7083
7489
|
`);
|
|
@@ -7089,7 +7495,7 @@ async function loginAction(options, deps) {
|
|
|
7089
7495
|
if (result.status === "failed") {
|
|
7090
7496
|
console.error(`${result.message}
|
|
7091
7497
|
`);
|
|
7092
|
-
|
|
7498
|
+
printLoginRecoveryHint(result.message);
|
|
7093
7499
|
process.exit(1);
|
|
7094
7500
|
}
|
|
7095
7501
|
console.log(`Logged in successfully.
|
|
@@ -7099,6 +7505,16 @@ async function loginAction(options, deps) {
|
|
|
7099
7505
|
console.log(`
|
|
7100
7506
|
You're ready to use githits with your AI assistant.`);
|
|
7101
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
|
+
}
|
|
7102
7518
|
var LOGIN_DESCRIPTION = `Authenticate with your GitHits account via browser.
|
|
7103
7519
|
|
|
7104
7520
|
Opens your browser to complete authentication securely using OAuth.
|
|
@@ -7135,6 +7551,7 @@ async function verifyAgentConfigured(agent, fileSystemService, execService) {
|
|
|
7135
7551
|
async function initAction(options, deps) {
|
|
7136
7552
|
const useColors = shouldUseColors();
|
|
7137
7553
|
const { fileSystemService, promptService, execService, createLoginDeps } = deps;
|
|
7554
|
+
let continuedWithoutAuth = false;
|
|
7138
7555
|
console.log(`
|
|
7139
7556
|
${colorize("GitHits", "bold", useColors)} — Set up MCP server for your coding agents
|
|
7140
7557
|
`);
|
|
@@ -7158,6 +7575,7 @@ async function initAction(options, deps) {
|
|
|
7158
7575
|
} else {
|
|
7159
7576
|
console.log(` ${warning(`Login failed: ${loginResult.message}`, useColors)}
|
|
7160
7577
|
`);
|
|
7578
|
+
printAuthRecoveryHint();
|
|
7161
7579
|
if (!options.yes) {
|
|
7162
7580
|
try {
|
|
7163
7581
|
const choice = await promptService.confirm3("Continue without authentication?");
|
|
@@ -7175,6 +7593,7 @@ async function initAction(options, deps) {
|
|
|
7175
7593
|
throw err;
|
|
7176
7594
|
}
|
|
7177
7595
|
}
|
|
7596
|
+
continuedWithoutAuth = true;
|
|
7178
7597
|
console.log(` Continuing without authentication...
|
|
7179
7598
|
`);
|
|
7180
7599
|
}
|
|
@@ -7198,6 +7617,11 @@ async function initAction(options, deps) {
|
|
|
7198
7617
|
return;
|
|
7199
7618
|
}
|
|
7200
7619
|
if (scan.needsSetup.length === 0) {
|
|
7620
|
+
if (continuedWithoutAuth) {
|
|
7621
|
+
console.log(" MCP is already configured, but authentication is still required.");
|
|
7622
|
+
console.log(" Run `githits login` before using GitHits tools.\n");
|
|
7623
|
+
return;
|
|
7624
|
+
}
|
|
7201
7625
|
console.log(` All detected agents are already configured. Nothing to do.
|
|
7202
7626
|
`);
|
|
7203
7627
|
return;
|
|
@@ -7270,6 +7694,9 @@ async function initAction(options, deps) {
|
|
|
7270
7694
|
const skipped = outcomes.filter((o) => o.status === "skipped").length;
|
|
7271
7695
|
if (failed > 0) {
|
|
7272
7696
|
console.log(" Setup completed with errors.");
|
|
7697
|
+
} else if (continuedWithoutAuth && (configured > 0 || alreadyDone > 0)) {
|
|
7698
|
+
console.log(" MCP is configured, but authentication is still required.");
|
|
7699
|
+
console.log(" Run `githits login` before using GitHits tools.");
|
|
7273
7700
|
} else if (configured > 0 || alreadyDone > 0) {
|
|
7274
7701
|
console.log(" Done! GitHits is ready.");
|
|
7275
7702
|
} else if (skipped > 0) {
|
|
@@ -7286,6 +7713,15 @@ async function initAction(options, deps) {
|
|
|
7286
7713
|
}
|
|
7287
7714
|
console.log();
|
|
7288
7715
|
}
|
|
7716
|
+
function printAuthRecoveryHint() {
|
|
7717
|
+
console.log(" You can still configure MCP, but GitHits tools will require auth.");
|
|
7718
|
+
console.log(" Recovery steps:");
|
|
7719
|
+
console.log(" githits auth status");
|
|
7720
|
+
console.log(" githits login --force");
|
|
7721
|
+
console.log(" For CI or locked-down machines, set GITHITS_API_TOKEN.");
|
|
7722
|
+
console.log(` If your system keychain is unavailable, set GITHITS_AUTH_STORAGE=file after accepting plaintext storage.
|
|
7723
|
+
`);
|
|
7724
|
+
}
|
|
7289
7725
|
var INIT_DESCRIPTION = `Set up GitHits MCP server for your coding agents.
|
|
7290
7726
|
|
|
7291
7727
|
Authenticates with your GitHits account, then scans for available agents
|
|
@@ -7516,7 +7952,7 @@ var structuredCodeTargetSchema = z3.object({
|
|
|
7516
7952
|
}).describe("Target: provide registry + package_name (package scope) or repo_url + git_ref (repo scope).");
|
|
7517
7953
|
var codeTargetSchema = z3.union([
|
|
7518
7954
|
structuredCodeTargetSchema,
|
|
7519
|
-
z3.string().min(1).describe("Compact target string. Package: `npm:react@18.2.0`. Repository: `https://github.com/facebook/react#HEAD` (git ref suffix
|
|
7955
|
+
z3.string().min(1).describe("Compact target string. Package: `npm:react@18.2.0`. Repository: `https://github.com/facebook/react#HEAD` (git ref suffix required for exact code navigation).")
|
|
7520
7956
|
]);
|
|
7521
7957
|
function resolveCodeTarget(target) {
|
|
7522
7958
|
if (typeof target === "string") {
|
|
@@ -7548,10 +7984,7 @@ function resolveCodeTarget(target) {
|
|
|
7548
7984
|
if (!target.repo_url) {
|
|
7549
7985
|
return invalidTargetResult("Incomplete repository target: repo_url is required.");
|
|
7550
7986
|
}
|
|
7551
|
-
return
|
|
7552
|
-
repoUrl: target.repo_url,
|
|
7553
|
-
gitRef: target.git_ref ?? "HEAD"
|
|
7554
|
-
};
|
|
7987
|
+
return invalidTargetResult("Incomplete repository target: git_ref is required for exact code navigation.");
|
|
7555
7988
|
}
|
|
7556
7989
|
return {
|
|
7557
7990
|
repoUrl: target.repo_url,
|
|
@@ -8507,10 +8940,14 @@ function buildRange3(args, textMode) {
|
|
|
8507
8940
|
}
|
|
8508
8941
|
// src/tools/search.ts
|
|
8509
8942
|
import { z as z13 } from "zod";
|
|
8943
|
+
var searchTargetSchema = z13.union([
|
|
8944
|
+
structuredCodeTargetSchema,
|
|
8945
|
+
z13.string().min(1).describe("Compact discovery target string. Package: `npm:react@18.2.0`. Repository: `https://github.com/facebook/react` for backend default branch or `https://github.com/facebook/react#HEAD` for an explicit ref.")
|
|
8946
|
+
]);
|
|
8510
8947
|
var schema12 = {
|
|
8511
8948
|
query: z13.string().min(1).describe("Discovery query string. Supports implicit AND, uppercase OR, parentheses, unary -, quoted phrases, semantic qualifiers (kind:, category:, path:, lang:, name:, intent:), and routing qualifiers (registry:, package:, version:, repo:). Parsed once and compiled per source; it is not forwarded as a raw backend query."),
|
|
8512
|
-
target:
|
|
8513
|
-
targets: z13.array(
|
|
8949
|
+
target: searchTargetSchema.optional(),
|
|
8950
|
+
targets: z13.array(searchTargetSchema).max(20).optional(),
|
|
8514
8951
|
sources: z13.array(z13.enum(["docs", "code", "symbol"])).optional().describe("Optional source selection. Omit for backend AUTO."),
|
|
8515
8952
|
category: z13.enum(["callable", "type", "module", "data", "documentation"]).optional(),
|
|
8516
8953
|
kind: z13.enum([
|
|
@@ -8572,17 +9009,17 @@ function createSearchTool(service) {
|
|
|
8572
9009
|
annotations: { readOnlyHint: true },
|
|
8573
9010
|
handler: async (args) => {
|
|
8574
9011
|
try {
|
|
8575
|
-
const resolvedTarget = args.target ?
|
|
9012
|
+
const resolvedTarget = args.target ? resolveSearchTarget(args.target) : undefined;
|
|
8576
9013
|
if (resolvedTarget && "content" in resolvedTarget)
|
|
8577
9014
|
return resolvedTarget;
|
|
8578
|
-
const resolvedTargets = args.targets?.map((entry) =>
|
|
9015
|
+
const resolvedTargets = args.targets?.map((entry) => resolveSearchTarget(entry));
|
|
8579
9016
|
const resolvedTargetsError = resolvedTargets?.find((entry) => ("content" in entry));
|
|
8580
9017
|
if (resolvedTargetsError) {
|
|
8581
9018
|
return resolvedTargetsError;
|
|
8582
9019
|
}
|
|
8583
9020
|
const built = buildUnifiedSearchParams({
|
|
8584
9021
|
target: resolvedTarget && !("content" in resolvedTarget) ? resolvedTarget : undefined,
|
|
8585
|
-
targets: resolvedTargets?.filter(
|
|
9022
|
+
targets: resolvedTargets?.filter(isResolvedSearchTarget),
|
|
8586
9023
|
query: args.query,
|
|
8587
9024
|
sources: args.sources?.map((entry) => entry.toUpperCase()),
|
|
8588
9025
|
kind: toSymbolKind(args.kind),
|
|
@@ -8613,9 +9050,53 @@ function createSearchTool(service) {
|
|
|
8613
9050
|
}
|
|
8614
9051
|
};
|
|
8615
9052
|
}
|
|
8616
|
-
function
|
|
9053
|
+
function isResolvedSearchTarget(target) {
|
|
8617
9054
|
return !("content" in target);
|
|
8618
9055
|
}
|
|
9056
|
+
function resolveSearchTarget(target) {
|
|
9057
|
+
if (typeof target === "string") {
|
|
9058
|
+
try {
|
|
9059
|
+
return parseUnifiedSearchTargetSpec(target);
|
|
9060
|
+
} catch (error2) {
|
|
9061
|
+
const mapped = mapCodeNavigationError(error2);
|
|
9062
|
+
return errorResult(JSON.stringify({
|
|
9063
|
+
error: mapped.message,
|
|
9064
|
+
code: mapped.code,
|
|
9065
|
+
retryable: mapped.retryable ?? false,
|
|
9066
|
+
...mapped.details ? { details: mapped.details } : {}
|
|
9067
|
+
}));
|
|
9068
|
+
}
|
|
9069
|
+
}
|
|
9070
|
+
const hasPackageTarget = Boolean(target.registry || target.package_name);
|
|
9071
|
+
const hasRepoTarget = Boolean(target.repo_url || target.git_ref);
|
|
9072
|
+
if (hasPackageTarget && hasRepoTarget) {
|
|
9073
|
+
return invalidSearchTargetResult("Invalid target: provide either registry + package_name or repo_url + git_ref, not both.");
|
|
9074
|
+
}
|
|
9075
|
+
if (!hasPackageTarget && !hasRepoTarget) {
|
|
9076
|
+
return invalidSearchTargetResult("Missing target: provide registry + package_name or repo_url.");
|
|
9077
|
+
}
|
|
9078
|
+
if (hasPackageTarget) {
|
|
9079
|
+
if (!target.registry || !target.package_name) {
|
|
9080
|
+
return invalidSearchTargetResult("Incomplete package target: both registry and package_name are required.");
|
|
9081
|
+
}
|
|
9082
|
+
return {
|
|
9083
|
+
registry: toCodeNavigationRegistry(target.registry),
|
|
9084
|
+
packageName: target.package_name,
|
|
9085
|
+
version: target.version
|
|
9086
|
+
};
|
|
9087
|
+
}
|
|
9088
|
+
if (!target.repo_url) {
|
|
9089
|
+
return invalidSearchTargetResult("Incomplete repository target: repo_url is required.");
|
|
9090
|
+
}
|
|
9091
|
+
return { repoUrl: target.repo_url, gitRef: target.git_ref };
|
|
9092
|
+
}
|
|
9093
|
+
function invalidSearchTargetResult(message) {
|
|
9094
|
+
return errorResult(JSON.stringify({
|
|
9095
|
+
error: message,
|
|
9096
|
+
code: "INVALID_ARGUMENT",
|
|
9097
|
+
retryable: false
|
|
9098
|
+
}));
|
|
9099
|
+
}
|
|
8619
9100
|
function isTextFormat11(format) {
|
|
8620
9101
|
return format === undefined || format === "text" || format === "text-v1";
|
|
8621
9102
|
}
|
|
@@ -9375,7 +9856,7 @@ function requireSearchService(deps) {
|
|
|
9375
9856
|
return deps.codeNavigationService;
|
|
9376
9857
|
}
|
|
9377
9858
|
async function loadContainer2() {
|
|
9378
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
9859
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-1h7sanjw.js");
|
|
9379
9860
|
return createContainer2();
|
|
9380
9861
|
}
|
|
9381
9862
|
function parseTargetSpecs(specs) {
|
|
@@ -9454,8 +9935,9 @@ function formatSearchErrorTerminal(payload, context) {
|
|
|
9454
9935
|
function formatUnifiedSearchTerminal(payload) {
|
|
9455
9936
|
const lines = [];
|
|
9456
9937
|
const useColors = shouldUseColors();
|
|
9457
|
-
|
|
9458
|
-
|
|
9938
|
+
const warnings = payload.warnings ?? payload.query.warnings;
|
|
9939
|
+
if (warnings && warnings.length > 0) {
|
|
9940
|
+
for (const warning2 of warnings) {
|
|
9459
9941
|
lines.push(`Warning: ${warning2}`);
|
|
9460
9942
|
}
|
|
9461
9943
|
lines.push("");
|
|
@@ -9494,7 +9976,7 @@ function formatUnifiedSearchTerminal(payload) {
|
|
|
9494
9976
|
lines.push("");
|
|
9495
9977
|
for (const entry of display) {
|
|
9496
9978
|
const location = formatUnifiedSearchLocation(entry.locator);
|
|
9497
|
-
const header = formatUnifiedSearchHeader(entry, useColors, location);
|
|
9979
|
+
const header = formatUnifiedSearchHeader(entry, useColors, location, payload.query.raw);
|
|
9498
9980
|
lines.push(header);
|
|
9499
9981
|
const metadata = formatUnifiedSearchMetadata(entry, useColors);
|
|
9500
9982
|
if (metadata.length > 0) {
|
|
@@ -9561,7 +10043,11 @@ function formatSearchStatusCompletedTerminal(payload) {
|
|
|
9561
10043
|
results: payload.result.results,
|
|
9562
10044
|
searchRef: payload.searchRef,
|
|
9563
10045
|
progress: undefined,
|
|
9564
|
-
query: {
|
|
10046
|
+
query: {
|
|
10047
|
+
raw: payload.result.query?.raw,
|
|
10048
|
+
warnings: payload.result.warnings
|
|
10049
|
+
},
|
|
10050
|
+
warnings: payload.result.warnings,
|
|
9565
10051
|
sourceStatus: payload.result.sourceStatus
|
|
9566
10052
|
});
|
|
9567
10053
|
}
|
|
@@ -9573,7 +10059,11 @@ function formatSearchStatusPartialTerminal(payload) {
|
|
|
9573
10059
|
results: payload.result.results,
|
|
9574
10060
|
searchRef: payload.searchRef,
|
|
9575
10061
|
progress: payload.progress,
|
|
9576
|
-
query: {
|
|
10062
|
+
query: {
|
|
10063
|
+
raw: payload.result.query?.raw,
|
|
10064
|
+
warnings: payload.result.warnings
|
|
10065
|
+
},
|
|
10066
|
+
warnings: payload.result.warnings,
|
|
9577
10067
|
sourceStatus: payload.result.sourceStatus
|
|
9578
10068
|
});
|
|
9579
10069
|
}
|
|
@@ -9684,11 +10174,113 @@ function formatUnifiedSearchLocation(locator) {
|
|
|
9684
10174
|
}
|
|
9685
10175
|
return `${locator.filePath}:${locator.startLine}${locator.endLine && locator.endLine !== locator.startLine ? `-${locator.endLine}` : ""}`;
|
|
9686
10176
|
}
|
|
9687
|
-
function formatUnifiedSearchHeader(entry, useColors, location) {
|
|
9688
|
-
const primary = entry.type
|
|
10177
|
+
function formatUnifiedSearchHeader(entry, useColors, location, rawQuery) {
|
|
10178
|
+
const primary = formatUnifiedSearchPrimary(entry.type, entry.target, location, rawQuery, useColors);
|
|
9689
10179
|
const badge = `[${formatUnifiedSearchResultLabel(entry.type)}]`;
|
|
9690
10180
|
const title = entry.title ? highlightRanges(entry.title, entry.highlights?.title, useColors) : undefined;
|
|
9691
|
-
return `${
|
|
10181
|
+
return `${primary} ${dim(badge, useColors)}${title ? ` - ${title}` : ""}`;
|
|
10182
|
+
}
|
|
10183
|
+
function formatUnifiedSearchPrimary(type, target, location, rawQuery, useColors) {
|
|
10184
|
+
const formattedTarget = highlight(target, useColors);
|
|
10185
|
+
if (type === "documentation_page" || !location) {
|
|
10186
|
+
return formattedTarget;
|
|
10187
|
+
}
|
|
10188
|
+
return `${formattedTarget} ${formatLocationWithQueryHighlights(location, rawQuery, useColors)}`;
|
|
10189
|
+
}
|
|
10190
|
+
function formatLocationWithQueryHighlights(location, rawQuery, useColors) {
|
|
10191
|
+
const ranges = buildQueryTermRanges(location, rawQuery);
|
|
10192
|
+
if (ranges.length === 0)
|
|
10193
|
+
return highlight(location, useColors);
|
|
10194
|
+
if (!useColors)
|
|
10195
|
+
return location;
|
|
10196
|
+
let result = "";
|
|
10197
|
+
let cursor2 = 0;
|
|
10198
|
+
for (const [start, end] of ranges) {
|
|
10199
|
+
if (cursor2 < start)
|
|
10200
|
+
result += highlight(location.slice(cursor2, start), true);
|
|
10201
|
+
result += highlightMatch(location.slice(start, end), true);
|
|
10202
|
+
cursor2 = end;
|
|
10203
|
+
}
|
|
10204
|
+
if (cursor2 < location.length)
|
|
10205
|
+
result += highlight(location.slice(cursor2), true);
|
|
10206
|
+
return result;
|
|
10207
|
+
}
|
|
10208
|
+
function buildQueryTermRanges(text, rawQuery) {
|
|
10209
|
+
const terms = extractQueryHighlightTerms(rawQuery);
|
|
10210
|
+
if (terms.length === 0)
|
|
10211
|
+
return [];
|
|
10212
|
+
const lowerText = text.toLowerCase();
|
|
10213
|
+
const ranges = [];
|
|
10214
|
+
const orderedTerms = [...terms].sort((left, right) => right.length - left.length);
|
|
10215
|
+
for (const term of orderedTerms) {
|
|
10216
|
+
const lowerTerm = term.toLowerCase();
|
|
10217
|
+
let cursor2 = 0;
|
|
10218
|
+
while (cursor2 < lowerText.length) {
|
|
10219
|
+
const start = lowerText.indexOf(lowerTerm, cursor2);
|
|
10220
|
+
if (start === -1)
|
|
10221
|
+
break;
|
|
10222
|
+
const end = start + lowerTerm.length;
|
|
10223
|
+
if (!ranges.some((range) => rangesOverlap(range, [start, end]))) {
|
|
10224
|
+
ranges.push([start, end]);
|
|
10225
|
+
}
|
|
10226
|
+
cursor2 = end;
|
|
10227
|
+
}
|
|
10228
|
+
}
|
|
10229
|
+
return mergeRanges2(ranges);
|
|
10230
|
+
}
|
|
10231
|
+
function extractQueryHighlightTerms(rawQuery) {
|
|
10232
|
+
if (!rawQuery)
|
|
10233
|
+
return [];
|
|
10234
|
+
const booleanOperators = new Set(["AND", "OR", "NOT"]);
|
|
10235
|
+
const terms = new Set;
|
|
10236
|
+
const quotedRanges = [];
|
|
10237
|
+
for (const match of rawQuery.matchAll(/"([^"]+)"/g)) {
|
|
10238
|
+
const phrase = match[1];
|
|
10239
|
+
if (phrase) {
|
|
10240
|
+
addQueryHighlightTerm(phrase, terms, booleanOperators, {
|
|
10241
|
+
stripQualifier: false
|
|
10242
|
+
});
|
|
10243
|
+
}
|
|
10244
|
+
if (typeof match.index === "number") {
|
|
10245
|
+
quotedRanges.push([match.index, match.index + match[0].length]);
|
|
10246
|
+
}
|
|
10247
|
+
}
|
|
10248
|
+
for (const match of rawQuery.matchAll(/[A-Za-z0-9_./@:-]+/g)) {
|
|
10249
|
+
const index = match.index ?? 0;
|
|
10250
|
+
if (quotedRanges.some(([start, end]) => index >= start && index < end)) {
|
|
10251
|
+
continue;
|
|
10252
|
+
}
|
|
10253
|
+
addQueryHighlightTerm(match[0], terms, booleanOperators);
|
|
10254
|
+
}
|
|
10255
|
+
return Array.from(terms);
|
|
10256
|
+
}
|
|
10257
|
+
function addQueryHighlightTerm(candidate, terms, booleanOperators, options = { stripQualifier: true }) {
|
|
10258
|
+
const normalised = options.stripQualifier && /^[A-Za-z]+:.+/.test(candidate) ? candidate.split(":").slice(1).join(":") : candidate;
|
|
10259
|
+
const term = normalised.replace(/^[-+]+/, "").replace(/[-+]+$/, "");
|
|
10260
|
+
if (term.length < 2)
|
|
10261
|
+
return;
|
|
10262
|
+
if (booleanOperators.has(term.toUpperCase()))
|
|
10263
|
+
return;
|
|
10264
|
+
terms.add(term);
|
|
10265
|
+
}
|
|
10266
|
+
function rangesOverlap(left, right) {
|
|
10267
|
+
return left[0] < right[1] && right[0] < left[1];
|
|
10268
|
+
}
|
|
10269
|
+
function mergeRanges2(ranges) {
|
|
10270
|
+
const sorted = ranges.filter(([start, end]) => end > start).sort((left, right) => left[0] - right[0] || left[1] - right[1]);
|
|
10271
|
+
const merged = [];
|
|
10272
|
+
for (const current of sorted) {
|
|
10273
|
+
const previous = merged[merged.length - 1];
|
|
10274
|
+
if (!previous || current[0] > previous[1]) {
|
|
10275
|
+
merged.push(current);
|
|
10276
|
+
continue;
|
|
10277
|
+
}
|
|
10278
|
+
merged[merged.length - 1] = [
|
|
10279
|
+
previous[0],
|
|
10280
|
+
Math.max(previous[1], current[1])
|
|
10281
|
+
];
|
|
10282
|
+
}
|
|
10283
|
+
return merged;
|
|
9692
10284
|
}
|
|
9693
10285
|
function formatUnifiedSearchMetadata(entry, useColors) {
|
|
9694
10286
|
if (entry.type !== "documentation_page" && entry.type !== "repository_doc") {
|
|
@@ -9696,16 +10288,14 @@ function formatUnifiedSearchMetadata(entry, useColors) {
|
|
|
9696
10288
|
}
|
|
9697
10289
|
const lines = [];
|
|
9698
10290
|
if (entry.locator.pageId) {
|
|
9699
|
-
|
|
10291
|
+
if (entry.type === "documentation_page") {
|
|
10292
|
+
lines.push(` ${dim("pageId:", useColors)} ${entry.locator.pageId}`);
|
|
10293
|
+
}
|
|
9700
10294
|
}
|
|
9701
10295
|
const sourceBadge = entry.locator.sourceKind?.toLowerCase() === "repository" ? "[repo]" : entry.locator.sourceKind?.toLowerCase() === "crawled" ? "[crawled]" : undefined;
|
|
9702
|
-
if (entry.locator.sourceUrl) {
|
|
10296
|
+
if (entry.locator.sourceUrl && entry.type === "documentation_page") {
|
|
9703
10297
|
lines.push(` ${dim("source:", useColors)} ${sourceBadge ? `${sourceBadge} ` : ""}${entry.locator.sourceUrl}`);
|
|
9704
10298
|
}
|
|
9705
|
-
if (entry.type === "repository_doc" && entry.locator.filePath) {
|
|
9706
|
-
const ref = entry.locator.requestedRef ?? entry.locator.gitRef;
|
|
9707
|
-
lines.push(` ${dim("file:", useColors)} ${entry.locator.filePath}${ref ? ` @ ${ref}` : ""}`);
|
|
9708
|
-
}
|
|
9709
10299
|
return lines;
|
|
9710
10300
|
}
|
|
9711
10301
|
// src/cli.ts
|
|
@@ -9741,12 +10331,14 @@ if (isTelemetryEnabled()) {
|
|
|
9741
10331
|
flushTelemetry(exitCode);
|
|
9742
10332
|
});
|
|
9743
10333
|
}
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
10334
|
+
var rootCliPreAction = createRootCliPreAction({
|
|
10335
|
+
createContainer,
|
|
10336
|
+
loginFlow: (options, deps) => loginFlow(options, deps, stderrLoginOutput)
|
|
10337
|
+
});
|
|
10338
|
+
program.name("githits").description("Code examples from global open source for your AI assistant").version(version).option("--no-color", "Disable colored output").hook("preAction", async (thisCommand, actionCommand) => {
|
|
9748
10339
|
const command = actionCommand ?? thisCommand;
|
|
9749
10340
|
commandSpans.set(command, startTelemetrySpan(getTelemetryCommandName(command)));
|
|
10341
|
+
await rootCliPreAction(thisCommand, actionCommand);
|
|
9750
10342
|
}).hook("postAction", (_thisCommand, actionCommand) => {
|
|
9751
10343
|
endTelemetrySpan(commandSpans.get(actionCommand));
|
|
9752
10344
|
}).addHelpText("after", `
|