githits 0.3.3 → 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 +524 -65
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-2d202fpq.js → chunk-1cyka46a.js} +227 -17
- package/dist/shared/{chunk-b6avnx6d.js → chunk-1h7sanjw.js} +2 -2
- package/dist/shared/{chunk-tze0rsay.js → chunk-fqzth5mv.js} +1 -1
- package/gemini-extension.json +1 -1
- package/package.json +1 -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("");
|
|
@@ -4142,7 +4170,6 @@ function buildRange2(envelope) {
|
|
|
4142
4170
|
}
|
|
4143
4171
|
// src/shared/auto-login.ts
|
|
4144
4172
|
var AUTO_LOGIN_ELIGIBLE_COMMANDS = new Set([
|
|
4145
|
-
"init",
|
|
4146
4173
|
"example",
|
|
4147
4174
|
"languages",
|
|
4148
4175
|
"feedback",
|
|
@@ -4175,9 +4202,6 @@ function isAutoLoginEligibleCommand(command, runtime = {
|
|
|
4175
4202
|
stdoutIsTTY: Boolean(process.stdout.isTTY)
|
|
4176
4203
|
}) {
|
|
4177
4204
|
const commandPath = getCommandPath(command).join(" ");
|
|
4178
|
-
if (commandPath === "init" && command.opts().skipLogin === true) {
|
|
4179
|
-
return false;
|
|
4180
|
-
}
|
|
4181
4205
|
if (!AUTO_LOGIN_ELIGIBLE_COMMANDS.has(commandPath)) {
|
|
4182
4206
|
return false;
|
|
4183
4207
|
}
|
|
@@ -4237,8 +4261,6 @@ function createRootCliPreAction(deps) {
|
|
|
4237
4261
|
}
|
|
4238
4262
|
function getPostLoginContinuationMessage(command) {
|
|
4239
4263
|
switch (getCommandPath(command).join(" ")) {
|
|
4240
|
-
case "init":
|
|
4241
|
-
return "Authentication complete. Continuing setup...";
|
|
4242
4264
|
case "example":
|
|
4243
4265
|
return "Authentication complete. Running example search...";
|
|
4244
4266
|
case "languages":
|
|
@@ -4313,11 +4335,6 @@ function resolveTargets(target, targets) {
|
|
|
4313
4335
|
seen.add(key);
|
|
4314
4336
|
deduped.push(entry);
|
|
4315
4337
|
}
|
|
4316
|
-
const hasPackageTarget = deduped.some((entry) => entry.packageName);
|
|
4317
|
-
const hasRepoTarget = deduped.some((entry) => entry.repoUrl);
|
|
4318
|
-
if (hasPackageTarget && hasRepoTarget) {
|
|
4319
|
-
throw new InvalidArgumentError("Do not mix package-scoped and repo-scoped targets in one search.");
|
|
4320
|
-
}
|
|
4321
4338
|
return deduped;
|
|
4322
4339
|
}
|
|
4323
4340
|
function normaliseRequiredQuery(query) {
|
|
@@ -4376,6 +4393,7 @@ var DEFAULT_LIMIT2 = DEFAULT_UNIFIED_SEARCH_LIMIT;
|
|
|
4376
4393
|
var DEFAULT_OFFSET = 0;
|
|
4377
4394
|
function buildUnifiedSearchSuccessPayload(params, rawQuery, compiledQuery, outcome) {
|
|
4378
4395
|
const warnings = outcome.state === "completed" ? outcome.result.queryWarnings : outcome.result?.queryWarnings ?? outcome.progress?.queryWarnings ?? [];
|
|
4396
|
+
const progress = compactProgress(outcome.progress);
|
|
4379
4397
|
const query = buildQueryEcho(params, rawQuery, compiledQuery, warnings);
|
|
4380
4398
|
if (outcome.state === "incomplete") {
|
|
4381
4399
|
const result = outcome.result;
|
|
@@ -4389,13 +4407,12 @@ function buildUnifiedSearchSuccessPayload(params, rawQuery, compiledQuery, outco
|
|
|
4389
4407
|
if (result?.page.hasMore === true) {
|
|
4390
4408
|
payload.nextOffset = result.page.offset + result.page.returned;
|
|
4391
4409
|
}
|
|
4392
|
-
const progress = compactProgress(outcome.progress);
|
|
4393
4410
|
if (progress)
|
|
4394
4411
|
payload.progress = progress;
|
|
4395
4412
|
const sourceStatus2 = compactSourceStatus(result?.sourceStatus);
|
|
4396
4413
|
if (sourceStatus2)
|
|
4397
4414
|
payload.sourceStatus = sourceStatus2;
|
|
4398
|
-
const combinedWarnings2 = combineWarnings(warnings, sourceStatus2);
|
|
4415
|
+
const combinedWarnings2 = combineWarnings(warnings, sourceStatus2, payload.results, progress);
|
|
4399
4416
|
if (combinedWarnings2.length > 0)
|
|
4400
4417
|
payload.warnings = combinedWarnings2;
|
|
4401
4418
|
return payload;
|
|
@@ -4414,15 +4431,17 @@ function buildUnifiedSearchSuccessPayload(params, rawQuery, compiledQuery, outco
|
|
|
4414
4431
|
const sourceStatus = compactSourceStatus(outcome.result.sourceStatus);
|
|
4415
4432
|
if (sourceStatus)
|
|
4416
4433
|
completed.sourceStatus = sourceStatus;
|
|
4417
|
-
const combinedWarnings = combineWarnings(warnings, sourceStatus);
|
|
4434
|
+
const combinedWarnings = combineWarnings(warnings, sourceStatus, completed.results, progress);
|
|
4418
4435
|
if (combinedWarnings.length > 0)
|
|
4419
4436
|
completed.warnings = combinedWarnings;
|
|
4420
4437
|
return completed;
|
|
4421
4438
|
}
|
|
4422
|
-
function combineWarnings(parserWarnings, sourceStatus) {
|
|
4439
|
+
function combineWarnings(parserWarnings, sourceStatus, hits = [], progress) {
|
|
4423
4440
|
const out = [];
|
|
4424
4441
|
if (parserWarnings.length > 0)
|
|
4425
4442
|
out.push(...parserWarnings);
|
|
4443
|
+
out.push(...buildHitFreshnessWarnings(hits));
|
|
4444
|
+
out.push(...buildProgressFreshnessWarnings(progress));
|
|
4426
4445
|
out.push(...buildSourceStatusWarnings(sourceStatus));
|
|
4427
4446
|
return out;
|
|
4428
4447
|
}
|
|
@@ -4449,6 +4468,9 @@ function buildUnifiedSearchStatusPayload(outcome) {
|
|
|
4449
4468
|
const progress = compactProgress(outcome.progress);
|
|
4450
4469
|
if (progress)
|
|
4451
4470
|
payload2.progress = progress;
|
|
4471
|
+
const progressWarnings = buildProgressFreshnessWarnings(progress);
|
|
4472
|
+
if (progressWarnings.length > 0)
|
|
4473
|
+
payload2.warnings = progressWarnings;
|
|
4452
4474
|
if (outcome.result) {
|
|
4453
4475
|
payload2.result = buildUnifiedSearchStatusResultPayload(outcome.result);
|
|
4454
4476
|
}
|
|
@@ -4464,6 +4486,7 @@ function buildUnifiedSearchStatusPayload(outcome) {
|
|
|
4464
4486
|
}
|
|
4465
4487
|
function buildUnifiedSearchStatusResultPayload(result) {
|
|
4466
4488
|
const payload = {
|
|
4489
|
+
query: buildStatusQueryEcho(result),
|
|
4467
4490
|
hasMore: result.page.hasMore,
|
|
4468
4491
|
results: result.results.map(buildHitPayload)
|
|
4469
4492
|
};
|
|
@@ -4482,6 +4505,18 @@ function buildUnifiedSearchStatusResultPayload(result) {
|
|
|
4482
4505
|
}
|
|
4483
4506
|
return payload;
|
|
4484
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
|
+
}
|
|
4485
4520
|
function buildQueryEcho(params, rawQuery, compiledQuery, warnings) {
|
|
4486
4521
|
const echo = {
|
|
4487
4522
|
raw: rawQuery
|
|
@@ -4531,6 +4566,12 @@ function buildHitPayload(hit) {
|
|
|
4531
4566
|
target: hit.targetLabel,
|
|
4532
4567
|
locator: buildLocatorPayload(hit)
|
|
4533
4568
|
};
|
|
4569
|
+
appendFreshness(payload, {
|
|
4570
|
+
requestedTargetLabel: hit.requestedTargetLabel,
|
|
4571
|
+
freshTargetLabel: hit.freshTargetLabel,
|
|
4572
|
+
servedTargetLabel: hit.servedTargetLabel,
|
|
4573
|
+
freshness: hit.freshness
|
|
4574
|
+
});
|
|
4534
4575
|
if (hit.title)
|
|
4535
4576
|
payload.title = hit.title;
|
|
4536
4577
|
if (hit.summary)
|
|
@@ -4538,6 +4579,9 @@ function buildHitPayload(hit) {
|
|
|
4538
4579
|
const highlights = buildHighlights(hit.highlights);
|
|
4539
4580
|
if (highlights)
|
|
4540
4581
|
payload.highlights = highlights;
|
|
4582
|
+
const followUp = buildSearchHitFollowUpCommand(payload);
|
|
4583
|
+
if (followUp)
|
|
4584
|
+
payload.followUp = followUp;
|
|
4541
4585
|
return payload;
|
|
4542
4586
|
}
|
|
4543
4587
|
function buildLocatorPayload(hit) {
|
|
@@ -4599,10 +4643,79 @@ function compactProgress(progress) {
|
|
|
4599
4643
|
targetsTotal: progress.targetsTotal,
|
|
4600
4644
|
elapsedMs: progress.elapsedMs
|
|
4601
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
|
+
}
|
|
4602
4666
|
if (progress.expiresAt)
|
|
4603
4667
|
payload.expiresAt = progress.expiresAt;
|
|
4668
|
+
payload.next = `search_status search_ref=${JSON.stringify(progress.searchRef)}`;
|
|
4604
4669
|
return payload;
|
|
4605
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
|
+
}
|
|
4606
4719
|
function buildSourceStatusWarnings(sourceStatus) {
|
|
4607
4720
|
if (!sourceStatus || sourceStatus.length === 0)
|
|
4608
4721
|
return [];
|
|
@@ -4614,8 +4727,51 @@ function buildSourceStatusWarnings(sourceStatus) {
|
|
|
4614
4727
|
}
|
|
4615
4728
|
return warnings;
|
|
4616
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
|
+
}
|
|
4617
4765
|
function warningForEntry(entry) {
|
|
4618
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;
|
|
4619
4775
|
if (entry.incompatibleQueryFeatures?.length) {
|
|
4620
4776
|
reasons.push(`incompatible query features [${entry.incompatibleQueryFeatures.join(", ")}]`);
|
|
4621
4777
|
}
|
|
@@ -4632,7 +4788,9 @@ function warningForEntry(entry) {
|
|
|
4632
4788
|
reasons.push(`indexing status ${entry.indexingStatus}`);
|
|
4633
4789
|
}
|
|
4634
4790
|
if (entry.codeIndexState) {
|
|
4635
|
-
|
|
4791
|
+
if (entry.codeIndexState !== "STALE") {
|
|
4792
|
+
reasons.push(`code index state ${entry.codeIndexState}`);
|
|
4793
|
+
}
|
|
4636
4794
|
}
|
|
4637
4795
|
const prefix = `Source '${entry.source}' for ${entry.targetLabel}`;
|
|
4638
4796
|
if (reasons.length > 0) {
|
|
@@ -4660,11 +4818,23 @@ function compactSourceStatusEntry(entry) {
|
|
|
4660
4818
|
targetLabel: entry.targetLabel
|
|
4661
4819
|
};
|
|
4662
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
|
+
}
|
|
4663
4833
|
if (entry.indexingStatus && entry.indexingStatus !== "INDEXED") {
|
|
4664
4834
|
payload.indexingStatus = entry.indexingStatus;
|
|
4665
4835
|
interesting = true;
|
|
4666
4836
|
}
|
|
4667
|
-
if (entry.codeIndexState && entry.codeIndexState !== "CURRENT" && entry.codeIndexState !== "STALE") {
|
|
4837
|
+
if (entry.codeIndexState && entry.codeIndexState !== "CURRENT" && (entry.codeIndexState !== "STALE" || staleDiverges)) {
|
|
4668
4838
|
payload.codeIndexState = entry.codeIndexState;
|
|
4669
4839
|
interesting = true;
|
|
4670
4840
|
}
|
|
@@ -4839,8 +5009,45 @@ function buildTrailer2(payload) {
|
|
|
4839
5009
|
lines.push(` - ${formatSourceStatus(entry)}`);
|
|
4840
5010
|
}
|
|
4841
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
|
+
}
|
|
4842
5019
|
return lines;
|
|
4843
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
|
+
}
|
|
4844
5051
|
function formatSourceStatus(entry) {
|
|
4845
5052
|
const parts = [`${entry.source} (${entry.targetLabel})`];
|
|
4846
5053
|
if (entry.indexingStatus)
|
|
@@ -4903,6 +5110,17 @@ function renderUnifiedSearchStatusText(payload) {
|
|
|
4903
5110
|
lines.push(buildHeader8(payload));
|
|
4904
5111
|
if (!payload.completed && payload.progress) {
|
|
4905
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}`);
|
|
4906
5124
|
}
|
|
4907
5125
|
const result = payload.result;
|
|
4908
5126
|
if (result)
|
|
@@ -4969,14 +5187,39 @@ function formatSourceStatus2(entry) {
|
|
|
4969
5187
|
return parts.join(SEP7);
|
|
4970
5188
|
}
|
|
4971
5189
|
function formatProgress(progress) {
|
|
4972
|
-
|
|
5190
|
+
const next = progress.next ? `; next: ${progress.next}` : "";
|
|
5191
|
+
return `progress: ${progress.status}, ${progress.targetsReady}/${progress.targetsTotal} targets ready, ${progress.elapsedMs}ms elapsed${next}`;
|
|
4973
5192
|
}
|
|
4974
5193
|
function quote5(value) {
|
|
4975
5194
|
return JSON.stringify(value);
|
|
4976
5195
|
}
|
|
4977
5196
|
// src/shared/unified-search-target.ts
|
|
4978
5197
|
function parseUnifiedSearchTargetSpec(spec) {
|
|
4979
|
-
|
|
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 };
|
|
4980
5223
|
}
|
|
4981
5224
|
// src/shared/list-files-request.ts
|
|
4982
5225
|
var LIMIT_MIN2 = 1;
|
|
@@ -5734,7 +5977,7 @@ grep run. --symbol-field hydrates enclosing symbol metadata (appears under each
|
|
|
5734
5977
|
match in --verbose output; full payload in --json).`;
|
|
5735
5978
|
function registerCodeGrepCommand(pkgCommand) {
|
|
5736
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) => {
|
|
5737
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
5980
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-1h7sanjw.js");
|
|
5738
5981
|
const deps = await createContainer2();
|
|
5739
5982
|
await pkgGrepAction(arg1, arg2, arg3, options, {
|
|
5740
5983
|
codeNavigationService: deps.codeNavigationService,
|
|
@@ -6210,6 +6453,10 @@ async function registerDocsCommandGroup(program, options = {}) {
|
|
|
6210
6453
|
// src/commands/example.ts
|
|
6211
6454
|
import { Option } from "commander";
|
|
6212
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
|
+
}
|
|
6213
6460
|
requireAuth(deps);
|
|
6214
6461
|
try {
|
|
6215
6462
|
const result = await deps.githitsService.search({
|
|
@@ -6226,10 +6473,21 @@ async function exampleAction(query, options, deps) {
|
|
|
6226
6473
|
console.log(result);
|
|
6227
6474
|
}
|
|
6228
6475
|
} catch (error2) {
|
|
6229
|
-
|
|
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);
|
|
6230
6481
|
process.exit(1);
|
|
6231
6482
|
}
|
|
6232
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
|
+
}
|
|
6233
6491
|
var EXAMPLE_DESCRIPTION = `Get verified, canonical code examples from global open source.
|
|
6234
6492
|
|
|
6235
6493
|
For dependency, package, or repository source search, use \`githits search\` instead.
|
|
@@ -6253,7 +6511,7 @@ function registerExampleCommand(program) {
|
|
|
6253
6511
|
});
|
|
6254
6512
|
}
|
|
6255
6513
|
async function loadContainer() {
|
|
6256
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
6514
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-1h7sanjw.js");
|
|
6257
6515
|
return createContainer2();
|
|
6258
6516
|
}
|
|
6259
6517
|
// src/commands/feedback.ts
|
|
@@ -7140,7 +7398,13 @@ async function loginFlow(options, deps, output = stdoutLoginOutput) {
|
|
|
7140
7398
|
state,
|
|
7141
7399
|
codeChallenge: challenge
|
|
7142
7400
|
});
|
|
7143
|
-
|
|
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
|
+
}
|
|
7144
7408
|
if (options.browser === false) {
|
|
7145
7409
|
output.write(`Open this URL in your browser:
|
|
7146
7410
|
`);
|
|
@@ -7148,7 +7412,17 @@ async function loginFlow(options, deps, output = stdoutLoginOutput) {
|
|
|
7148
7412
|
`);
|
|
7149
7413
|
} else {
|
|
7150
7414
|
output.write("Opening browser...");
|
|
7151
|
-
|
|
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
|
+
}
|
|
7152
7426
|
}
|
|
7153
7427
|
output.write(`Waiting for authentication...
|
|
7154
7428
|
`);
|
|
@@ -7158,12 +7432,13 @@ async function loginFlow(options, deps, output = stdoutLoginOutput) {
|
|
|
7158
7432
|
});
|
|
7159
7433
|
let callback;
|
|
7160
7434
|
try {
|
|
7161
|
-
callback = await Promise.race([
|
|
7435
|
+
callback = await Promise.race([callbackServer.result, timeoutPromise]);
|
|
7162
7436
|
if (timeoutId)
|
|
7163
7437
|
clearTimeout(timeoutId);
|
|
7164
7438
|
} catch (error2) {
|
|
7165
7439
|
if (timeoutId)
|
|
7166
7440
|
clearTimeout(timeoutId);
|
|
7441
|
+
await callbackServer.close().catch(() => {});
|
|
7167
7442
|
const msg = error2 instanceof Error ? error2.message : "Authentication failed";
|
|
7168
7443
|
return { status: "failed", message: `${msg}.` };
|
|
7169
7444
|
}
|
|
@@ -7220,7 +7495,7 @@ async function loginAction(options, deps) {
|
|
|
7220
7495
|
if (result.status === "failed") {
|
|
7221
7496
|
console.error(`${result.message}
|
|
7222
7497
|
`);
|
|
7223
|
-
|
|
7498
|
+
printLoginRecoveryHint(result.message);
|
|
7224
7499
|
process.exit(1);
|
|
7225
7500
|
}
|
|
7226
7501
|
console.log(`Logged in successfully.
|
|
@@ -7230,6 +7505,16 @@ async function loginAction(options, deps) {
|
|
|
7230
7505
|
console.log(`
|
|
7231
7506
|
You're ready to use githits with your AI assistant.`);
|
|
7232
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
|
+
}
|
|
7233
7518
|
var LOGIN_DESCRIPTION = `Authenticate with your GitHits account via browser.
|
|
7234
7519
|
|
|
7235
7520
|
Opens your browser to complete authentication securely using OAuth.
|
|
@@ -7266,6 +7551,7 @@ async function verifyAgentConfigured(agent, fileSystemService, execService) {
|
|
|
7266
7551
|
async function initAction(options, deps) {
|
|
7267
7552
|
const useColors = shouldUseColors();
|
|
7268
7553
|
const { fileSystemService, promptService, execService, createLoginDeps } = deps;
|
|
7554
|
+
let continuedWithoutAuth = false;
|
|
7269
7555
|
console.log(`
|
|
7270
7556
|
${colorize("GitHits", "bold", useColors)} — Set up MCP server for your coding agents
|
|
7271
7557
|
`);
|
|
@@ -7289,6 +7575,7 @@ async function initAction(options, deps) {
|
|
|
7289
7575
|
} else {
|
|
7290
7576
|
console.log(` ${warning(`Login failed: ${loginResult.message}`, useColors)}
|
|
7291
7577
|
`);
|
|
7578
|
+
printAuthRecoveryHint();
|
|
7292
7579
|
if (!options.yes) {
|
|
7293
7580
|
try {
|
|
7294
7581
|
const choice = await promptService.confirm3("Continue without authentication?");
|
|
@@ -7306,6 +7593,7 @@ async function initAction(options, deps) {
|
|
|
7306
7593
|
throw err;
|
|
7307
7594
|
}
|
|
7308
7595
|
}
|
|
7596
|
+
continuedWithoutAuth = true;
|
|
7309
7597
|
console.log(` Continuing without authentication...
|
|
7310
7598
|
`);
|
|
7311
7599
|
}
|
|
@@ -7329,6 +7617,11 @@ async function initAction(options, deps) {
|
|
|
7329
7617
|
return;
|
|
7330
7618
|
}
|
|
7331
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
|
+
}
|
|
7332
7625
|
console.log(` All detected agents are already configured. Nothing to do.
|
|
7333
7626
|
`);
|
|
7334
7627
|
return;
|
|
@@ -7401,6 +7694,9 @@ async function initAction(options, deps) {
|
|
|
7401
7694
|
const skipped = outcomes.filter((o) => o.status === "skipped").length;
|
|
7402
7695
|
if (failed > 0) {
|
|
7403
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.");
|
|
7404
7700
|
} else if (configured > 0 || alreadyDone > 0) {
|
|
7405
7701
|
console.log(" Done! GitHits is ready.");
|
|
7406
7702
|
} else if (skipped > 0) {
|
|
@@ -7417,6 +7713,15 @@ async function initAction(options, deps) {
|
|
|
7417
7713
|
}
|
|
7418
7714
|
console.log();
|
|
7419
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
|
+
}
|
|
7420
7725
|
var INIT_DESCRIPTION = `Set up GitHits MCP server for your coding agents.
|
|
7421
7726
|
|
|
7422
7727
|
Authenticates with your GitHits account, then scans for available agents
|
|
@@ -7647,7 +7952,7 @@ var structuredCodeTargetSchema = z3.object({
|
|
|
7647
7952
|
}).describe("Target: provide registry + package_name (package scope) or repo_url + git_ref (repo scope).");
|
|
7648
7953
|
var codeTargetSchema = z3.union([
|
|
7649
7954
|
structuredCodeTargetSchema,
|
|
7650
|
-
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).")
|
|
7651
7956
|
]);
|
|
7652
7957
|
function resolveCodeTarget(target) {
|
|
7653
7958
|
if (typeof target === "string") {
|
|
@@ -7679,10 +7984,7 @@ function resolveCodeTarget(target) {
|
|
|
7679
7984
|
if (!target.repo_url) {
|
|
7680
7985
|
return invalidTargetResult("Incomplete repository target: repo_url is required.");
|
|
7681
7986
|
}
|
|
7682
|
-
return
|
|
7683
|
-
repoUrl: target.repo_url,
|
|
7684
|
-
gitRef: target.git_ref ?? "HEAD"
|
|
7685
|
-
};
|
|
7987
|
+
return invalidTargetResult("Incomplete repository target: git_ref is required for exact code navigation.");
|
|
7686
7988
|
}
|
|
7687
7989
|
return {
|
|
7688
7990
|
repoUrl: target.repo_url,
|
|
@@ -8638,10 +8940,14 @@ function buildRange3(args, textMode) {
|
|
|
8638
8940
|
}
|
|
8639
8941
|
// src/tools/search.ts
|
|
8640
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
|
+
]);
|
|
8641
8947
|
var schema12 = {
|
|
8642
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."),
|
|
8643
|
-
target:
|
|
8644
|
-
targets: z13.array(
|
|
8949
|
+
target: searchTargetSchema.optional(),
|
|
8950
|
+
targets: z13.array(searchTargetSchema).max(20).optional(),
|
|
8645
8951
|
sources: z13.array(z13.enum(["docs", "code", "symbol"])).optional().describe("Optional source selection. Omit for backend AUTO."),
|
|
8646
8952
|
category: z13.enum(["callable", "type", "module", "data", "documentation"]).optional(),
|
|
8647
8953
|
kind: z13.enum([
|
|
@@ -8703,17 +9009,17 @@ function createSearchTool(service) {
|
|
|
8703
9009
|
annotations: { readOnlyHint: true },
|
|
8704
9010
|
handler: async (args) => {
|
|
8705
9011
|
try {
|
|
8706
|
-
const resolvedTarget = args.target ?
|
|
9012
|
+
const resolvedTarget = args.target ? resolveSearchTarget(args.target) : undefined;
|
|
8707
9013
|
if (resolvedTarget && "content" in resolvedTarget)
|
|
8708
9014
|
return resolvedTarget;
|
|
8709
|
-
const resolvedTargets = args.targets?.map((entry) =>
|
|
9015
|
+
const resolvedTargets = args.targets?.map((entry) => resolveSearchTarget(entry));
|
|
8710
9016
|
const resolvedTargetsError = resolvedTargets?.find((entry) => ("content" in entry));
|
|
8711
9017
|
if (resolvedTargetsError) {
|
|
8712
9018
|
return resolvedTargetsError;
|
|
8713
9019
|
}
|
|
8714
9020
|
const built = buildUnifiedSearchParams({
|
|
8715
9021
|
target: resolvedTarget && !("content" in resolvedTarget) ? resolvedTarget : undefined,
|
|
8716
|
-
targets: resolvedTargets?.filter(
|
|
9022
|
+
targets: resolvedTargets?.filter(isResolvedSearchTarget),
|
|
8717
9023
|
query: args.query,
|
|
8718
9024
|
sources: args.sources?.map((entry) => entry.toUpperCase()),
|
|
8719
9025
|
kind: toSymbolKind(args.kind),
|
|
@@ -8744,9 +9050,53 @@ function createSearchTool(service) {
|
|
|
8744
9050
|
}
|
|
8745
9051
|
};
|
|
8746
9052
|
}
|
|
8747
|
-
function
|
|
9053
|
+
function isResolvedSearchTarget(target) {
|
|
8748
9054
|
return !("content" in target);
|
|
8749
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
|
+
}
|
|
8750
9100
|
function isTextFormat11(format) {
|
|
8751
9101
|
return format === undefined || format === "text" || format === "text-v1";
|
|
8752
9102
|
}
|
|
@@ -9506,7 +9856,7 @@ function requireSearchService(deps) {
|
|
|
9506
9856
|
return deps.codeNavigationService;
|
|
9507
9857
|
}
|
|
9508
9858
|
async function loadContainer2() {
|
|
9509
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
9859
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-1h7sanjw.js");
|
|
9510
9860
|
return createContainer2();
|
|
9511
9861
|
}
|
|
9512
9862
|
function parseTargetSpecs(specs) {
|
|
@@ -9585,8 +9935,9 @@ function formatSearchErrorTerminal(payload, context) {
|
|
|
9585
9935
|
function formatUnifiedSearchTerminal(payload) {
|
|
9586
9936
|
const lines = [];
|
|
9587
9937
|
const useColors = shouldUseColors();
|
|
9588
|
-
|
|
9589
|
-
|
|
9938
|
+
const warnings = payload.warnings ?? payload.query.warnings;
|
|
9939
|
+
if (warnings && warnings.length > 0) {
|
|
9940
|
+
for (const warning2 of warnings) {
|
|
9590
9941
|
lines.push(`Warning: ${warning2}`);
|
|
9591
9942
|
}
|
|
9592
9943
|
lines.push("");
|
|
@@ -9625,7 +9976,7 @@ function formatUnifiedSearchTerminal(payload) {
|
|
|
9625
9976
|
lines.push("");
|
|
9626
9977
|
for (const entry of display) {
|
|
9627
9978
|
const location = formatUnifiedSearchLocation(entry.locator);
|
|
9628
|
-
const header = formatUnifiedSearchHeader(entry, useColors, location);
|
|
9979
|
+
const header = formatUnifiedSearchHeader(entry, useColors, location, payload.query.raw);
|
|
9629
9980
|
lines.push(header);
|
|
9630
9981
|
const metadata = formatUnifiedSearchMetadata(entry, useColors);
|
|
9631
9982
|
if (metadata.length > 0) {
|
|
@@ -9692,7 +10043,11 @@ function formatSearchStatusCompletedTerminal(payload) {
|
|
|
9692
10043
|
results: payload.result.results,
|
|
9693
10044
|
searchRef: payload.searchRef,
|
|
9694
10045
|
progress: undefined,
|
|
9695
|
-
query: {
|
|
10046
|
+
query: {
|
|
10047
|
+
raw: payload.result.query?.raw,
|
|
10048
|
+
warnings: payload.result.warnings
|
|
10049
|
+
},
|
|
10050
|
+
warnings: payload.result.warnings,
|
|
9696
10051
|
sourceStatus: payload.result.sourceStatus
|
|
9697
10052
|
});
|
|
9698
10053
|
}
|
|
@@ -9704,7 +10059,11 @@ function formatSearchStatusPartialTerminal(payload) {
|
|
|
9704
10059
|
results: payload.result.results,
|
|
9705
10060
|
searchRef: payload.searchRef,
|
|
9706
10061
|
progress: payload.progress,
|
|
9707
|
-
query: {
|
|
10062
|
+
query: {
|
|
10063
|
+
raw: payload.result.query?.raw,
|
|
10064
|
+
warnings: payload.result.warnings
|
|
10065
|
+
},
|
|
10066
|
+
warnings: payload.result.warnings,
|
|
9708
10067
|
sourceStatus: payload.result.sourceStatus
|
|
9709
10068
|
});
|
|
9710
10069
|
}
|
|
@@ -9815,11 +10174,113 @@ function formatUnifiedSearchLocation(locator) {
|
|
|
9815
10174
|
}
|
|
9816
10175
|
return `${locator.filePath}:${locator.startLine}${locator.endLine && locator.endLine !== locator.startLine ? `-${locator.endLine}` : ""}`;
|
|
9817
10176
|
}
|
|
9818
|
-
function formatUnifiedSearchHeader(entry, useColors, location) {
|
|
9819
|
-
const primary = entry.type
|
|
10177
|
+
function formatUnifiedSearchHeader(entry, useColors, location, rawQuery) {
|
|
10178
|
+
const primary = formatUnifiedSearchPrimary(entry.type, entry.target, location, rawQuery, useColors);
|
|
9820
10179
|
const badge = `[${formatUnifiedSearchResultLabel(entry.type)}]`;
|
|
9821
10180
|
const title = entry.title ? highlightRanges(entry.title, entry.highlights?.title, useColors) : undefined;
|
|
9822
|
-
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;
|
|
9823
10284
|
}
|
|
9824
10285
|
function formatUnifiedSearchMetadata(entry, useColors) {
|
|
9825
10286
|
if (entry.type !== "documentation_page" && entry.type !== "repository_doc") {
|
|
@@ -9827,16 +10288,14 @@ function formatUnifiedSearchMetadata(entry, useColors) {
|
|
|
9827
10288
|
}
|
|
9828
10289
|
const lines = [];
|
|
9829
10290
|
if (entry.locator.pageId) {
|
|
9830
|
-
|
|
10291
|
+
if (entry.type === "documentation_page") {
|
|
10292
|
+
lines.push(` ${dim("pageId:", useColors)} ${entry.locator.pageId}`);
|
|
10293
|
+
}
|
|
9831
10294
|
}
|
|
9832
10295
|
const sourceBadge = entry.locator.sourceKind?.toLowerCase() === "repository" ? "[repo]" : entry.locator.sourceKind?.toLowerCase() === "crawled" ? "[crawled]" : undefined;
|
|
9833
|
-
if (entry.locator.sourceUrl) {
|
|
10296
|
+
if (entry.locator.sourceUrl && entry.type === "documentation_page") {
|
|
9834
10297
|
lines.push(` ${dim("source:", useColors)} ${sourceBadge ? `${sourceBadge} ` : ""}${entry.locator.sourceUrl}`);
|
|
9835
10298
|
}
|
|
9836
|
-
if (entry.type === "repository_doc" && entry.locator.filePath) {
|
|
9837
|
-
const ref = entry.locator.requestedRef ?? entry.locator.gitRef;
|
|
9838
|
-
lines.push(` ${dim("file:", useColors)} ${entry.locator.filePath}${ref ? ` @ ${ref}` : ""}`);
|
|
9839
|
-
}
|
|
9840
10299
|
return lines;
|
|
9841
10300
|
}
|
|
9842
10301
|
// src/cli.ts
|