githits 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.plugin/plugin.json +1 -1
- package/dist/cli.js +1125 -905
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-cdx2gnrs.js → chunk-67qnnqby.js} +2 -2
- package/dist/shared/{chunk-fa4571ch.js → chunk-szjytcvw.js} +1 -1
- package/dist/shared/{chunk-1t81jdax.js → chunk-ykr7x8jp.js} +370 -237
- 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
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
flushTelemetry,
|
|
33
33
|
getCodeNavigationCapability,
|
|
34
34
|
getCodeNavigationUrl,
|
|
35
|
+
getEnvApiToken,
|
|
35
36
|
isCodeNavigationCliOverrideEnabled,
|
|
36
37
|
isTelemetryEnabled,
|
|
37
38
|
refreshExpiredToken,
|
|
@@ -40,11 +41,11 @@ import {
|
|
|
40
41
|
setMcpClientVersionProvider,
|
|
41
42
|
startTelemetrySpan,
|
|
42
43
|
withTelemetrySpan
|
|
43
|
-
} from "./shared/chunk-
|
|
44
|
+
} from "./shared/chunk-ykr7x8jp.js";
|
|
44
45
|
import {
|
|
45
46
|
__require,
|
|
46
47
|
version
|
|
47
|
-
} from "./shared/chunk-
|
|
48
|
+
} from "./shared/chunk-szjytcvw.js";
|
|
48
49
|
|
|
49
50
|
// src/cli.ts
|
|
50
51
|
import { Command } from "commander";
|
|
@@ -80,7 +81,6 @@ async function authStatusAction(deps) {
|
|
|
80
81
|
console.log(`Authenticated via environment variable.
|
|
81
82
|
`);
|
|
82
83
|
console.log(` Source: GITHITS_API_TOKEN`);
|
|
83
|
-
console.log(` Token: ${envApiToken.slice(0, 8)}...`);
|
|
84
84
|
displayCodeNavigationStatus(getCodeNavigationCapability(envApiToken), codeNavigationCliOverrideEnabled);
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
@@ -138,10 +138,27 @@ function registerAuthStatusCommand(program) {
|
|
|
138
138
|
await authStatusAction(deps);
|
|
139
139
|
});
|
|
140
140
|
}
|
|
141
|
+
// src/commands/gated-command-group.ts
|
|
142
|
+
async function resolveGatedCommandGroupRegistrationState(options = {}) {
|
|
143
|
+
const codeNavigationUrl = options.codeNavigationUrl ?? getCodeNavigationUrl();
|
|
144
|
+
if (!codeNavigationUrl) {
|
|
145
|
+
return { codeNavigationUrl: undefined, shouldRegister: false };
|
|
146
|
+
}
|
|
147
|
+
const overrideEnabled = options.overrideEnabled ?? isCodeNavigationCliOverrideEnabled();
|
|
148
|
+
const registrationState = options.capability !== undefined || options.expiredStoredAuth !== undefined ? {
|
|
149
|
+
capability: options.capability ?? "unknown",
|
|
150
|
+
expiredStoredAuth: options.expiredStoredAuth ?? false
|
|
151
|
+
} : await resolveStartupCodeNavigationRegistrationState();
|
|
152
|
+
const envTokenPresent = options.envTokenPresent ?? Boolean(getEnvApiToken());
|
|
153
|
+
return {
|
|
154
|
+
codeNavigationUrl,
|
|
155
|
+
shouldRegister: overrideEnabled || registrationState.capability === "enabled" || envTokenPresent || registrationState.expiredStoredAuth
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
141
159
|
// src/shared/code-navigation-defaults.ts
|
|
142
160
|
var DEFAULT_WAIT_TIMEOUT_MS = 20000;
|
|
143
161
|
var MAX_WAIT_TIMEOUT_MS = 60000;
|
|
144
|
-
var SEARCH_SYMBOLS_DEFAULT_FILE_INTENT = "PRODUCTION";
|
|
145
162
|
var FILE_INTENT_ALL = Symbol("FILE_INTENT_ALL");
|
|
146
163
|
|
|
147
164
|
// src/shared/colors.ts
|
|
@@ -299,17 +316,10 @@ var fileIntentMap = {
|
|
|
299
316
|
build: "BUILD",
|
|
300
317
|
vendor: "VENDOR"
|
|
301
318
|
};
|
|
302
|
-
var matchModeMap = {
|
|
303
|
-
or: "OR",
|
|
304
|
-
and: "AND"
|
|
305
|
-
};
|
|
306
319
|
function toCodeNavigationRegistry(registry) {
|
|
307
320
|
return toPkgseerRegistry(registry);
|
|
308
321
|
}
|
|
309
|
-
function
|
|
310
|
-
return mode ? matchModeMap[mode] : undefined;
|
|
311
|
-
}
|
|
312
|
-
function toSearchSymbolsKind(kind) {
|
|
322
|
+
function toSymbolKind(kind) {
|
|
313
323
|
return kind ? symbolKindMap[kind] : undefined;
|
|
314
324
|
}
|
|
315
325
|
function toSymbolCategory(category) {
|
|
@@ -321,7 +331,7 @@ function knownSymbolKindList() {
|
|
|
321
331
|
function knownSymbolCategoryList() {
|
|
322
332
|
return Object.keys(symbolCategoryMap);
|
|
323
333
|
}
|
|
324
|
-
function
|
|
334
|
+
function toFileIntent(intent) {
|
|
325
335
|
return intent ? fileIntentMap[intent] : undefined;
|
|
326
336
|
}
|
|
327
337
|
// src/shared/code-navigation-error-map.ts
|
|
@@ -478,6 +488,23 @@ function isInvalidArgumentError(error2) {
|
|
|
478
488
|
return false;
|
|
479
489
|
return error2.name.startsWith("Invalid") || error2.name.startsWith("Unsupported");
|
|
480
490
|
}
|
|
491
|
+
// src/shared/docs-follow-up.ts
|
|
492
|
+
function lowerDocSourceKind(value) {
|
|
493
|
+
switch (value) {
|
|
494
|
+
case "CRAWLED":
|
|
495
|
+
return "crawled";
|
|
496
|
+
case "REPOSITORY":
|
|
497
|
+
return "repo";
|
|
498
|
+
default:
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
// src/shared/extract-solution-id.ts
|
|
503
|
+
var SOLUTION_URL_RE = /solutions\/([0-9a-fA-F-]{36})/;
|
|
504
|
+
function extractSolutionId(markdown) {
|
|
505
|
+
const match = SOLUTION_URL_RE.exec(markdown);
|
|
506
|
+
return match?.[1];
|
|
507
|
+
}
|
|
481
508
|
// src/shared/package-spec.ts
|
|
482
509
|
var KNOWN_REGISTRIES = [
|
|
483
510
|
"npm",
|
|
@@ -729,19 +756,27 @@ function normalizeWaitTimeoutMs(value) {
|
|
|
729
756
|
function buildGrepRepoSuccessPayload(result, options) {
|
|
730
757
|
const envelope = {
|
|
731
758
|
pattern: options.pattern,
|
|
732
|
-
patternType: options.patternType,
|
|
733
|
-
caseSensitive: options.caseSensitive,
|
|
734
759
|
matches: result.matches.map(projectMatch),
|
|
735
760
|
hasMore: result.hasMore,
|
|
736
|
-
truncatedReason: result.truncatedReason.toLowerCase(),
|
|
737
|
-
routeTaken: result.routeTaken?.toLowerCase(),
|
|
738
761
|
filesScanned: result.filesScanned,
|
|
739
762
|
filesInScope: result.filesInScope,
|
|
740
|
-
binaryFilesSkipped: result.binaryFilesSkipped,
|
|
741
|
-
filesTooLargeSkipped: result.filesTooLargeSkipped,
|
|
742
763
|
totalMatches: result.totalMatches,
|
|
743
764
|
uniqueFilesMatched: result.uniqueFilesMatched
|
|
744
765
|
};
|
|
766
|
+
if (options.patternType !== "literal") {
|
|
767
|
+
envelope.patternType = options.patternType;
|
|
768
|
+
}
|
|
769
|
+
if (options.caseSensitive)
|
|
770
|
+
envelope.caseSensitive = true;
|
|
771
|
+
if (result.binaryFilesSkipped > 0) {
|
|
772
|
+
envelope.binaryFilesSkipped = result.binaryFilesSkipped;
|
|
773
|
+
}
|
|
774
|
+
if (result.filesTooLargeSkipped > 0) {
|
|
775
|
+
envelope.filesTooLargeSkipped = result.filesTooLargeSkipped;
|
|
776
|
+
}
|
|
777
|
+
if (result.truncatedReason && result.truncatedReason !== "NONE") {
|
|
778
|
+
envelope.truncatedReason = result.truncatedReason.toLowerCase();
|
|
779
|
+
}
|
|
745
780
|
if (options.registry)
|
|
746
781
|
envelope.registry = options.registry;
|
|
747
782
|
if (options.name)
|
|
@@ -763,19 +798,26 @@ function buildGrepRepoSuccessPayload(result, options) {
|
|
|
763
798
|
return envelope;
|
|
764
799
|
}
|
|
765
800
|
function projectMatch(match) {
|
|
766
|
-
|
|
801
|
+
const projected = {
|
|
767
802
|
filePath: match.filePath,
|
|
768
803
|
line: match.line,
|
|
769
804
|
matchStartByte: match.matchStartByte,
|
|
770
805
|
matchEndByte: match.matchEndByte,
|
|
771
|
-
lineContent: match.lineContent
|
|
772
|
-
contextBefore: match.contextBefore,
|
|
773
|
-
contextAfter: match.contextAfter,
|
|
774
|
-
fileContentHash: match.fileContentHash,
|
|
775
|
-
fileIntent: match.fileIntent,
|
|
776
|
-
symbolRowId: match.symbolRowId,
|
|
777
|
-
symbol: match.symbol
|
|
806
|
+
lineContent: match.lineContent
|
|
778
807
|
};
|
|
808
|
+
if (match.contextBefore && match.contextBefore.length > 0) {
|
|
809
|
+
projected.contextBefore = match.contextBefore;
|
|
810
|
+
}
|
|
811
|
+
if (match.contextAfter && match.contextAfter.length > 0) {
|
|
812
|
+
projected.contextAfter = match.contextAfter;
|
|
813
|
+
}
|
|
814
|
+
if (match.fileContentHash)
|
|
815
|
+
projected.fileContentHash = match.fileContentHash;
|
|
816
|
+
if (match.fileIntent)
|
|
817
|
+
projected.fileIntent = match.fileIntent;
|
|
818
|
+
if (match.symbol)
|
|
819
|
+
projected.symbol = match.symbol;
|
|
820
|
+
return projected;
|
|
779
821
|
}
|
|
780
822
|
function projectResolution(resolution) {
|
|
781
823
|
if (!resolution)
|
|
@@ -1110,39 +1152,191 @@ function filterLanguages(languages, query, limit = DEFAULT_LIMIT) {
|
|
|
1110
1152
|
const lowerQuery = query.toLowerCase();
|
|
1111
1153
|
return languages.filter((lang) => lang.name.toLowerCase().includes(lowerQuery) || lang.display_name.toLowerCase().includes(lowerQuery) || lang.aliases.some((a) => a.toLowerCase().includes(lowerQuery))).slice(0, limit).map(({ name, display_name }) => ({ name, display_name }));
|
|
1112
1154
|
}
|
|
1113
|
-
// src/shared/
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
super(message);
|
|
1119
|
-
this.name = "InvalidKeywordsError";
|
|
1155
|
+
// src/shared/list-package-docs-request.ts
|
|
1156
|
+
function buildListPackageDocsParams(input) {
|
|
1157
|
+
const packageName = input.packageName?.trim() ?? "";
|
|
1158
|
+
if (!packageName) {
|
|
1159
|
+
throw new InvalidPackageSpecError("Package name is required.");
|
|
1120
1160
|
}
|
|
1161
|
+
const registry = input.registry?.trim().toLowerCase() ?? "";
|
|
1162
|
+
if (!isKnownPkgseerRegistryArg(registry)) {
|
|
1163
|
+
throw new UnsupportedRegistryError(`Unsupported registry '${input.registry}'. Supported: npm, pypi, hex, crates, nuget, maven, zig, vcpkg, packagist.`);
|
|
1164
|
+
}
|
|
1165
|
+
const params = {
|
|
1166
|
+
registry: toPkgseerRegistry(registry),
|
|
1167
|
+
packageName
|
|
1168
|
+
};
|
|
1169
|
+
const version2 = input.version?.trim();
|
|
1170
|
+
if (version2)
|
|
1171
|
+
params.version = version2;
|
|
1172
|
+
const after = input.after?.trim();
|
|
1173
|
+
if (after)
|
|
1174
|
+
params.after = after;
|
|
1175
|
+
if (input.limit !== undefined) {
|
|
1176
|
+
if (!Number.isInteger(input.limit) || input.limit < 1 || input.limit > 500) {
|
|
1177
|
+
throw new InvalidPackageSpecError("Limit must be an integer between 1 and 500.");
|
|
1178
|
+
}
|
|
1179
|
+
params.limit = input.limit;
|
|
1180
|
+
}
|
|
1181
|
+
return {
|
|
1182
|
+
params,
|
|
1183
|
+
limitExplicit: input.limit !== undefined,
|
|
1184
|
+
afterExplicit: Boolean(after)
|
|
1185
|
+
};
|
|
1121
1186
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1187
|
+
// src/shared/format-date.ts
|
|
1188
|
+
function toIsoDate(iso) {
|
|
1189
|
+
if (!iso)
|
|
1190
|
+
return null;
|
|
1191
|
+
const parsed = new Date(iso);
|
|
1192
|
+
if (Number.isNaN(parsed.getTime()))
|
|
1193
|
+
return null;
|
|
1194
|
+
return parsed.toISOString().slice(0, 10);
|
|
1195
|
+
}
|
|
1196
|
+
var MINUTE = 60;
|
|
1197
|
+
var HOUR = 60 * MINUTE;
|
|
1198
|
+
var DAY = 24 * HOUR;
|
|
1199
|
+
var MONTH = 30 * DAY;
|
|
1200
|
+
var YEAR = 365 * DAY;
|
|
1201
|
+
function toRelativeDate(iso, now = new Date) {
|
|
1202
|
+
if (!iso)
|
|
1203
|
+
return null;
|
|
1204
|
+
const parsed = new Date(iso);
|
|
1205
|
+
if (Number.isNaN(parsed.getTime()))
|
|
1206
|
+
return null;
|
|
1207
|
+
const deltaSeconds = Math.floor((now.getTime() - parsed.getTime()) / 1000);
|
|
1208
|
+
if (deltaSeconds < 0) {
|
|
1209
|
+
return toIsoDate(iso);
|
|
1210
|
+
}
|
|
1211
|
+
if (deltaSeconds < MINUTE)
|
|
1212
|
+
return "just now";
|
|
1213
|
+
if (deltaSeconds < HOUR)
|
|
1214
|
+
return formatUnit(deltaSeconds, MINUTE, "minute");
|
|
1215
|
+
if (deltaSeconds < DAY)
|
|
1216
|
+
return formatUnit(deltaSeconds, HOUR, "hour");
|
|
1217
|
+
if (deltaSeconds < MONTH)
|
|
1218
|
+
return formatUnit(deltaSeconds, DAY, "day");
|
|
1219
|
+
if (deltaSeconds < YEAR)
|
|
1220
|
+
return formatUnit(deltaSeconds, MONTH, "month");
|
|
1221
|
+
return formatUnit(deltaSeconds, YEAR, "year");
|
|
1222
|
+
}
|
|
1223
|
+
function formatUnit(deltaSeconds, unit, label) {
|
|
1224
|
+
const n = Math.floor(deltaSeconds / unit);
|
|
1225
|
+
return `${n} ${label}${n === 1 ? "" : "s"} ago`;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// src/shared/list-package-docs-response.ts
|
|
1229
|
+
function buildListPackageDocsSuccessPayload(result, options) {
|
|
1230
|
+
const envelope = {
|
|
1231
|
+
hasMore: result.pageInfo?.hasNextPage ?? false,
|
|
1232
|
+
pages: result.pages.map((page) => {
|
|
1233
|
+
assertDocListEntry(page);
|
|
1234
|
+
const pageId = page.id;
|
|
1235
|
+
const lastUpdatedAt = toIsoDate(page.lastUpdatedAt);
|
|
1236
|
+
const entry = { pageId };
|
|
1237
|
+
if (page.title)
|
|
1238
|
+
entry.title = page.title;
|
|
1239
|
+
const sourceKind = lowerDocSourceKind(page.sourceKind);
|
|
1240
|
+
if (sourceKind)
|
|
1241
|
+
entry.sourceKind = sourceKind;
|
|
1242
|
+
if (page.sourceUrl)
|
|
1243
|
+
entry.sourceUrl = page.sourceUrl;
|
|
1244
|
+
if (page.repoUrl)
|
|
1245
|
+
entry.repoUrl = page.repoUrl;
|
|
1246
|
+
if (page.gitRef)
|
|
1247
|
+
entry.gitRef = page.gitRef;
|
|
1248
|
+
if (page.requestedRef)
|
|
1249
|
+
entry.requestedRef = page.requestedRef;
|
|
1250
|
+
if (page.filePath)
|
|
1251
|
+
entry.filePath = page.filePath;
|
|
1252
|
+
if (page.linkName)
|
|
1253
|
+
entry.linkName = page.linkName;
|
|
1254
|
+
if (lastUpdatedAt)
|
|
1255
|
+
entry.lastUpdatedAt = lastUpdatedAt;
|
|
1256
|
+
return entry;
|
|
1257
|
+
})
|
|
1133
1258
|
};
|
|
1134
|
-
if (
|
|
1135
|
-
|
|
1136
|
-
|
|
1259
|
+
if (result.registry)
|
|
1260
|
+
envelope.registry = result.registry.toLowerCase();
|
|
1261
|
+
if (result.packageName)
|
|
1262
|
+
envelope.name = result.packageName;
|
|
1263
|
+
if (result.version)
|
|
1264
|
+
envelope.version = result.version;
|
|
1265
|
+
if (typeof result.stale === "boolean")
|
|
1266
|
+
envelope.stale = result.stale;
|
|
1267
|
+
if (result.pageInfo?.totalCount !== undefined)
|
|
1268
|
+
envelope.total = result.pageInfo.totalCount;
|
|
1269
|
+
if (result.pageInfo?.endCursor)
|
|
1270
|
+
envelope.nextCursor = result.pageInfo.endCursor;
|
|
1271
|
+
const filter = {};
|
|
1272
|
+
if (options.limitExplicit && options.limit !== undefined)
|
|
1273
|
+
filter.limit = options.limit;
|
|
1274
|
+
if (options.afterExplicit && options.after)
|
|
1275
|
+
filter.after = options.after;
|
|
1276
|
+
if (Object.keys(filter).length > 0)
|
|
1277
|
+
envelope.filter = filter;
|
|
1278
|
+
return envelope;
|
|
1279
|
+
}
|
|
1280
|
+
function assertDocListEntry(page) {
|
|
1281
|
+
if (!page.id) {
|
|
1282
|
+
throw new MalformedPackageIntelligenceResponseError("Documentation page list entry missing required id.");
|
|
1137
1283
|
}
|
|
1138
|
-
if (
|
|
1139
|
-
|
|
1140
|
-
add(piece);
|
|
1284
|
+
if (page.sourceKind === "REPOSITORY" && (!page.repoUrl || !page.gitRef || !page.filePath)) {
|
|
1285
|
+
throw new MalformedPackageIntelligenceResponseError("Repository-backed documentation list entry missing repo locator fields.");
|
|
1141
1286
|
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1287
|
+
}
|
|
1288
|
+
function formatListPackageDocsTerminal(envelope, options) {
|
|
1289
|
+
const lines = [];
|
|
1290
|
+
lines.push(buildSummaryHeader(envelope, options.useColors));
|
|
1291
|
+
lines.push("");
|
|
1292
|
+
if (envelope.pages.length === 0) {
|
|
1293
|
+
lines.push(dim("No documentation pages found.", options.useColors));
|
|
1294
|
+
lines.push("");
|
|
1295
|
+
return lines.join(`
|
|
1296
|
+
`);
|
|
1144
1297
|
}
|
|
1145
|
-
|
|
1298
|
+
for (const page of envelope.pages) {
|
|
1299
|
+
lines.push(formatPageHeader(page, options.useColors));
|
|
1300
|
+
const meta = formatPageMeta(page, options.useColors, options.verbose ?? false);
|
|
1301
|
+
if (meta.length > 0)
|
|
1302
|
+
lines.push(...meta);
|
|
1303
|
+
lines.push("");
|
|
1304
|
+
}
|
|
1305
|
+
if (envelope.nextCursor) {
|
|
1306
|
+
lines.push(dim(`Next cursor: ${envelope.nextCursor}`, options.useColors));
|
|
1307
|
+
}
|
|
1308
|
+
if (envelope.stale) {
|
|
1309
|
+
lines.push(dim("Documentation may be stale.", options.useColors));
|
|
1310
|
+
}
|
|
1311
|
+
if (envelope.nextCursor || envelope.stale)
|
|
1312
|
+
lines.push("");
|
|
1313
|
+
return lines.join(`
|
|
1314
|
+
`);
|
|
1315
|
+
}
|
|
1316
|
+
function buildSummaryHeader(envelope, useColors) {
|
|
1317
|
+
const target = envelope.registry && envelope.name ? `${envelope.registry}:${envelope.name}${envelope.version ? `@${envelope.version}` : ""}` : "package docs";
|
|
1318
|
+
const summary = `${target} · ${envelope.pages.length} page${envelope.pages.length === 1 ? "" : "s"}`;
|
|
1319
|
+
const suffix = envelope.total !== undefined ? ` of ${envelope.total}` : "";
|
|
1320
|
+
return `${colorize(summary, "bold", useColors)}${dim(suffix, useColors)}`;
|
|
1321
|
+
}
|
|
1322
|
+
function formatPageHeader(page, useColors) {
|
|
1323
|
+
const badge = page.sourceKind === "repo" ? "[repo]" : "[crawled]";
|
|
1324
|
+
const title = page.title ?? page.pageId;
|
|
1325
|
+
return `${colorize(page.pageId, "bold", useColors)} ${dim(badge, useColors)} - ${title}`;
|
|
1326
|
+
}
|
|
1327
|
+
function formatPageMeta(page, useColors, verbose) {
|
|
1328
|
+
const lines = [];
|
|
1329
|
+
if (page.sourceUrl) {
|
|
1330
|
+
lines.push(` ${dim("source:", useColors)} ${page.sourceUrl}`);
|
|
1331
|
+
}
|
|
1332
|
+
if (page.filePath) {
|
|
1333
|
+
const ref = page.requestedRef ?? page.gitRef;
|
|
1334
|
+
lines.push(` ${dim("file:", useColors)} ${page.filePath}${ref ? ` @ ${ref}` : ""}`);
|
|
1335
|
+
}
|
|
1336
|
+
if (verbose && page.lastUpdatedAt) {
|
|
1337
|
+
lines.push(` ${dim("updated:", useColors)} ${page.lastUpdatedAt}`);
|
|
1338
|
+
}
|
|
1339
|
+
return lines;
|
|
1146
1340
|
}
|
|
1147
1341
|
// src/shared/package-dependencies-request.ts
|
|
1148
1342
|
class UnsupportedDependenciesRegistryError extends Error {
|
|
@@ -1969,47 +2163,6 @@ function buildPackageSummaryParams(input) {
|
|
|
1969
2163
|
}
|
|
1970
2164
|
};
|
|
1971
2165
|
}
|
|
1972
|
-
// src/shared/format-date.ts
|
|
1973
|
-
function toIsoDate(iso) {
|
|
1974
|
-
if (!iso)
|
|
1975
|
-
return null;
|
|
1976
|
-
const parsed = new Date(iso);
|
|
1977
|
-
if (Number.isNaN(parsed.getTime()))
|
|
1978
|
-
return null;
|
|
1979
|
-
return parsed.toISOString().slice(0, 10);
|
|
1980
|
-
}
|
|
1981
|
-
var MINUTE = 60;
|
|
1982
|
-
var HOUR = 60 * MINUTE;
|
|
1983
|
-
var DAY = 24 * HOUR;
|
|
1984
|
-
var MONTH = 30 * DAY;
|
|
1985
|
-
var YEAR = 365 * DAY;
|
|
1986
|
-
function toRelativeDate(iso, now = new Date) {
|
|
1987
|
-
if (!iso)
|
|
1988
|
-
return null;
|
|
1989
|
-
const parsed = new Date(iso);
|
|
1990
|
-
if (Number.isNaN(parsed.getTime()))
|
|
1991
|
-
return null;
|
|
1992
|
-
const deltaSeconds = Math.floor((now.getTime() - parsed.getTime()) / 1000);
|
|
1993
|
-
if (deltaSeconds < 0) {
|
|
1994
|
-
return toIsoDate(iso);
|
|
1995
|
-
}
|
|
1996
|
-
if (deltaSeconds < MINUTE)
|
|
1997
|
-
return "just now";
|
|
1998
|
-
if (deltaSeconds < HOUR)
|
|
1999
|
-
return formatUnit(deltaSeconds, MINUTE, "minute");
|
|
2000
|
-
if (deltaSeconds < DAY)
|
|
2001
|
-
return formatUnit(deltaSeconds, HOUR, "hour");
|
|
2002
|
-
if (deltaSeconds < MONTH)
|
|
2003
|
-
return formatUnit(deltaSeconds, DAY, "day");
|
|
2004
|
-
if (deltaSeconds < YEAR)
|
|
2005
|
-
return formatUnit(deltaSeconds, MONTH, "month");
|
|
2006
|
-
return formatUnit(deltaSeconds, YEAR, "year");
|
|
2007
|
-
}
|
|
2008
|
-
function formatUnit(deltaSeconds, unit, label) {
|
|
2009
|
-
const n = Math.floor(deltaSeconds / unit);
|
|
2010
|
-
return `${n} ${label}${n === 1 ? "" : "s"} ago`;
|
|
2011
|
-
}
|
|
2012
|
-
|
|
2013
2166
|
// src/shared/format-number.ts
|
|
2014
2167
|
function formatCompactNumber(n) {
|
|
2015
2168
|
if (!Number.isFinite(n)) {
|
|
@@ -2836,6 +2989,157 @@ function formatUpgradeFooter(paths) {
|
|
|
2836
2989
|
return `Upgrade to ${paths[0]}.`;
|
|
2837
2990
|
return `Upgrade options: ${paths.join(", ")}.`;
|
|
2838
2991
|
}
|
|
2992
|
+
// src/shared/parse-lines-option.ts
|
|
2993
|
+
function parseLinesOption(raw) {
|
|
2994
|
+
const trimmed = raw.trim();
|
|
2995
|
+
const dashIndex = trimmed.indexOf("-");
|
|
2996
|
+
if (dashIndex < 0) {
|
|
2997
|
+
throw new InvalidPackageSpecError(`--lines expects a range like \`10-40\`, \`10-\`, or \`-40\`. Single-line form isn't accepted — use --start ${trimmed}.`);
|
|
2998
|
+
}
|
|
2999
|
+
const startRaw = trimmed.slice(0, dashIndex).trim();
|
|
3000
|
+
const endRaw = trimmed.slice(dashIndex + 1).trim();
|
|
3001
|
+
if (startRaw.length === 0 && endRaw.length === 0) {
|
|
3002
|
+
throw new InvalidPackageSpecError("--lines requires at least one bound. Use `10-40`, `10-` for open end, or `-40` for open start.");
|
|
3003
|
+
}
|
|
3004
|
+
const startLine = startRaw.length > 0 ? requirePositiveInteger(startRaw, "--lines start") : undefined;
|
|
3005
|
+
const endLine = endRaw.length > 0 ? requirePositiveInteger(endRaw, "--lines end") : undefined;
|
|
3006
|
+
if (startLine !== undefined && endLine !== undefined && startLine > endLine) {
|
|
3007
|
+
throw new InvalidPackageSpecError(`--lines range is reversed: ${startLine} > ${endLine}.`);
|
|
3008
|
+
}
|
|
3009
|
+
if (startLine === undefined && endLine !== undefined) {
|
|
3010
|
+
return { startLine: 1, endLine };
|
|
3011
|
+
}
|
|
3012
|
+
return { startLine, endLine };
|
|
3013
|
+
}
|
|
3014
|
+
function requirePositiveInteger(raw, label) {
|
|
3015
|
+
if (!/^\d+$/.test(raw)) {
|
|
3016
|
+
throw new InvalidPackageSpecError(`${label} must be a positive integer. Got '${raw}'.`);
|
|
3017
|
+
}
|
|
3018
|
+
const parsed = Number.parseInt(raw, 10);
|
|
3019
|
+
if (parsed < 1) {
|
|
3020
|
+
throw new InvalidPackageSpecError(`${label} must be ≥ 1 (lines are 1-indexed). Got ${parsed}.`);
|
|
3021
|
+
}
|
|
3022
|
+
return parsed;
|
|
3023
|
+
}
|
|
3024
|
+
// src/shared/read-package-doc-request.ts
|
|
3025
|
+
function buildReadPackageDocParams(input) {
|
|
3026
|
+
const pageId = input.pageId?.trim() ?? "";
|
|
3027
|
+
if (!pageId) {
|
|
3028
|
+
throw new InvalidPackageSpecError("Page ID is required.");
|
|
3029
|
+
}
|
|
3030
|
+
return {
|
|
3031
|
+
params: { pageId }
|
|
3032
|
+
};
|
|
3033
|
+
}
|
|
3034
|
+
// src/shared/read-package-doc-response.ts
|
|
3035
|
+
function buildReadPackageDocSuccessPayload(result, requestedPageId, range) {
|
|
3036
|
+
const pageId = result.page?.id;
|
|
3037
|
+
if (!pageId) {
|
|
3038
|
+
throw new MalformedPackageIntelligenceResponseError(`Documentation page '${requestedPageId}' missing required id in response.`);
|
|
3039
|
+
}
|
|
3040
|
+
if ((result.page?.sourceKind ?? result.sourceKind) === "REPOSITORY" && (!result.page?.repoUrl || !result.page?.gitRef || !result.page?.filePath)) {
|
|
3041
|
+
throw new MalformedPackageIntelligenceResponseError(`Repository-backed documentation page '${pageId}' missing repo locator fields.`);
|
|
3042
|
+
}
|
|
3043
|
+
const envelope = { pageId };
|
|
3044
|
+
if (result.registry)
|
|
3045
|
+
envelope.registry = result.registry.toLowerCase();
|
|
3046
|
+
if (result.packageName)
|
|
3047
|
+
envelope.name = result.packageName;
|
|
3048
|
+
if (result.version)
|
|
3049
|
+
envelope.version = result.version;
|
|
3050
|
+
if (result.page?.title)
|
|
3051
|
+
envelope.title = result.page.title;
|
|
3052
|
+
if (result.page?.contentFormat)
|
|
3053
|
+
envelope.format = result.page.contentFormat;
|
|
3054
|
+
if (result.page?.content !== undefined) {
|
|
3055
|
+
const sliced = sliceContent(result.page.content, range);
|
|
3056
|
+
envelope.content = sliced.content;
|
|
3057
|
+
if (sliced.totalLines !== undefined)
|
|
3058
|
+
envelope.totalLines = sliced.totalLines;
|
|
3059
|
+
if (sliced.startLine !== undefined)
|
|
3060
|
+
envelope.startLine = sliced.startLine;
|
|
3061
|
+
if (sliced.endLine !== undefined)
|
|
3062
|
+
envelope.endLine = sliced.endLine;
|
|
3063
|
+
}
|
|
3064
|
+
if (result.page?.breadcrumbs && result.page.breadcrumbs.length > 0) {
|
|
3065
|
+
envelope.breadcrumbs = result.page.breadcrumbs;
|
|
3066
|
+
}
|
|
3067
|
+
if (result.page?.linkName)
|
|
3068
|
+
envelope.linkName = result.page.linkName;
|
|
3069
|
+
if (result.page?.lastUpdatedAt) {
|
|
3070
|
+
envelope.lastUpdatedAt = toIsoDate(result.page.lastUpdatedAt) ?? undefined;
|
|
3071
|
+
}
|
|
3072
|
+
const sourceKind = lowerDocSourceKind(result.page?.sourceKind ?? result.sourceKind);
|
|
3073
|
+
if (sourceKind)
|
|
3074
|
+
envelope.sourceKind = sourceKind;
|
|
3075
|
+
if (result.page?.source?.url)
|
|
3076
|
+
envelope.sourceUrl = result.page.source.url;
|
|
3077
|
+
if (result.page?.source?.label)
|
|
3078
|
+
envelope.sourceLabel = result.page.source.label;
|
|
3079
|
+
if (result.page?.repoUrl)
|
|
3080
|
+
envelope.repoUrl = result.page.repoUrl;
|
|
3081
|
+
if (result.page?.gitRef)
|
|
3082
|
+
envelope.gitRef = result.page.gitRef;
|
|
3083
|
+
if (result.page?.requestedRef)
|
|
3084
|
+
envelope.requestedRef = result.page.requestedRef;
|
|
3085
|
+
if (result.page?.filePath)
|
|
3086
|
+
envelope.filePath = result.page.filePath;
|
|
3087
|
+
if (result.page?.baseUrl)
|
|
3088
|
+
envelope.baseUrl = result.page.baseUrl;
|
|
3089
|
+
return envelope;
|
|
3090
|
+
}
|
|
3091
|
+
function sliceContent(content, range) {
|
|
3092
|
+
if (content.length === 0) {
|
|
3093
|
+
return { content };
|
|
3094
|
+
}
|
|
3095
|
+
const trimmed = content.endsWith(`
|
|
3096
|
+
`) ? content.slice(0, -1) : content;
|
|
3097
|
+
const lines = trimmed.split(`
|
|
3098
|
+
`);
|
|
3099
|
+
const totalLines = lines.length;
|
|
3100
|
+
if (!range || range.startLine === undefined && range.endLine === undefined) {
|
|
3101
|
+
return { content, totalLines };
|
|
3102
|
+
}
|
|
3103
|
+
const startLine = Math.max(1, range.startLine ?? 1);
|
|
3104
|
+
const endLine = Math.min(totalLines, range.endLine ?? totalLines);
|
|
3105
|
+
if (startLine > totalLines) {
|
|
3106
|
+
return { content: "", totalLines, startLine, endLine: startLine - 1 };
|
|
3107
|
+
}
|
|
3108
|
+
const sliced = lines.slice(startLine - 1, endLine).join(`
|
|
3109
|
+
`);
|
|
3110
|
+
return { content: sliced, totalLines, startLine, endLine };
|
|
3111
|
+
}
|
|
3112
|
+
function formatReadPackageDocTerminal(envelope, options) {
|
|
3113
|
+
if (!(options.verbose ?? false)) {
|
|
3114
|
+
return envelope.content ?? "";
|
|
3115
|
+
}
|
|
3116
|
+
const lines = [];
|
|
3117
|
+
lines.push(buildHeader(envelope, options.useColors));
|
|
3118
|
+
lines.push(`pageId: ${envelope.pageId}`);
|
|
3119
|
+
if (envelope.sourceUrl)
|
|
3120
|
+
lines.push(`source: ${envelope.sourceUrl}`);
|
|
3121
|
+
if (envelope.filePath) {
|
|
3122
|
+
const ref = envelope.requestedRef ?? envelope.gitRef;
|
|
3123
|
+
lines.push(`file: ${envelope.filePath}${ref ? ` @ ${ref}` : ""}`);
|
|
3124
|
+
}
|
|
3125
|
+
if (envelope.lastUpdatedAt)
|
|
3126
|
+
lines.push(`updated: ${envelope.lastUpdatedAt}`);
|
|
3127
|
+
if (envelope.breadcrumbs && envelope.breadcrumbs.length > 0) {
|
|
3128
|
+
lines.push(`breadcrumbs: ${envelope.breadcrumbs.join(" > ")}`);
|
|
3129
|
+
}
|
|
3130
|
+
lines.push("");
|
|
3131
|
+
if (envelope.content)
|
|
3132
|
+
lines.push(envelope.content);
|
|
3133
|
+
return `${lines.join(`
|
|
3134
|
+
`)}
|
|
3135
|
+
`;
|
|
3136
|
+
}
|
|
3137
|
+
function buildHeader(envelope, useColors) {
|
|
3138
|
+
const badge = envelope.sourceKind === "repo" ? "[repo]" : "[crawled]";
|
|
3139
|
+
const title = envelope.title ?? envelope.pageId;
|
|
3140
|
+
const prefix = envelope.registry && envelope.name ? `${envelope.registry}:${envelope.name}${envelope.version ? `@${envelope.version}` : ""}` : "documentation";
|
|
3141
|
+
return `${colorize(`${prefix} ${badge}`, "bold", useColors)}${title ? ` - ${title}` : ""}`;
|
|
3142
|
+
}
|
|
2839
3143
|
// src/shared/require-auth.ts
|
|
2840
3144
|
class AuthRequiredError extends Error {
|
|
2841
3145
|
constructor(message) {
|
|
@@ -2862,106 +3166,13 @@ function requireAuth(deps, context) {
|
|
|
2862
3166
|
Need help? support@githits.com`);
|
|
2863
3167
|
throw new AuthRequiredError(`Authentication required${suffix}`);
|
|
2864
3168
|
}
|
|
2865
|
-
// src/shared/search-symbols-request.ts
|
|
2866
|
-
function buildSearchSymbolsParams(input) {
|
|
2867
|
-
const defaulted = [];
|
|
2868
|
-
const resolvedFileIntent = resolveFileIntent(input.fileIntent, defaulted);
|
|
2869
|
-
const resolvedWaitTimeoutMs = resolveWaitTimeoutMs(input.waitTimeoutMs, defaulted);
|
|
2870
|
-
return {
|
|
2871
|
-
params: {
|
|
2872
|
-
target: input.target,
|
|
2873
|
-
query: input.query,
|
|
2874
|
-
keywords: input.keywords,
|
|
2875
|
-
matchMode: input.matchMode,
|
|
2876
|
-
kind: input.kind,
|
|
2877
|
-
category: input.category,
|
|
2878
|
-
filePath: input.filePath,
|
|
2879
|
-
limit: input.limit,
|
|
2880
|
-
fileIntent: resolvedFileIntent,
|
|
2881
|
-
waitTimeoutMs: resolvedWaitTimeoutMs
|
|
2882
|
-
},
|
|
2883
|
-
defaulted
|
|
2884
|
-
};
|
|
2885
|
-
}
|
|
2886
|
-
function resolveFileIntent(input, defaulted) {
|
|
2887
|
-
if (input === FILE_INTENT_ALL) {
|
|
2888
|
-
return;
|
|
2889
|
-
}
|
|
2890
|
-
if (input === undefined) {
|
|
2891
|
-
defaulted.push("fileIntent");
|
|
2892
|
-
return SEARCH_SYMBOLS_DEFAULT_FILE_INTENT;
|
|
2893
|
-
}
|
|
2894
|
-
return input;
|
|
2895
|
-
}
|
|
2896
|
-
function resolveWaitTimeoutMs(input, defaulted) {
|
|
2897
|
-
if (input === undefined) {
|
|
2898
|
-
defaulted.push("waitTimeoutMs");
|
|
2899
|
-
return DEFAULT_WAIT_TIMEOUT_MS;
|
|
2900
|
-
}
|
|
2901
|
-
return input;
|
|
2902
|
-
}
|
|
2903
|
-
// src/shared/search-symbols-response.ts
|
|
2904
|
-
function buildSearchSymbolsSuccessPayload(params, defaulted, result) {
|
|
2905
|
-
const payload = {
|
|
2906
|
-
query: {
|
|
2907
|
-
target: params.target,
|
|
2908
|
-
query: params.query,
|
|
2909
|
-
keywords: params.keywords,
|
|
2910
|
-
matchMode: params.matchMode?.toLowerCase(),
|
|
2911
|
-
kind: params.kind?.toLowerCase(),
|
|
2912
|
-
category: params.category?.toLowerCase(),
|
|
2913
|
-
filePath: params.filePath,
|
|
2914
|
-
fileIntent: echoFileIntent(params.fileIntent),
|
|
2915
|
-
limit: params.limit,
|
|
2916
|
-
waitTimeoutMs: params.waitTimeoutMs ?? 0,
|
|
2917
|
-
defaulted
|
|
2918
|
-
},
|
|
2919
|
-
results: result.results,
|
|
2920
|
-
returnedCount: result.results.length,
|
|
2921
|
-
totalMatches: result.totalMatches,
|
|
2922
|
-
hasMore: result.hasMore
|
|
2923
|
-
};
|
|
2924
|
-
if (result.version)
|
|
2925
|
-
payload.version = result.version;
|
|
2926
|
-
if (result.resolution)
|
|
2927
|
-
payload.resolution = result.resolution;
|
|
2928
|
-
if (result.warning)
|
|
2929
|
-
payload.warning = result.warning;
|
|
2930
|
-
if (result.hint && !isLegacyZeroChunksHint(result.hint)) {
|
|
2931
|
-
payload.hint = result.hint;
|
|
2932
|
-
}
|
|
2933
|
-
return payload;
|
|
2934
|
-
}
|
|
2935
|
-
function isLegacyZeroChunksHint(hint) {
|
|
2936
|
-
return hint.toLowerCase().includes("0 searchable chunks");
|
|
2937
|
-
}
|
|
2938
|
-
function buildSearchSymbolsErrorPayload(error2) {
|
|
2939
|
-
const mapped = mapCodeNavigationError(error2);
|
|
2940
|
-
const payload = {
|
|
2941
|
-
error: mapped.message,
|
|
2942
|
-
code: mapped.code
|
|
2943
|
-
};
|
|
2944
|
-
if (typeof mapped.retryable === "boolean") {
|
|
2945
|
-
payload.retryable = mapped.retryable;
|
|
2946
|
-
}
|
|
2947
|
-
if (mapped.details && Object.keys(mapped.details).length > 0) {
|
|
2948
|
-
payload.details = mapped.details;
|
|
2949
|
-
}
|
|
2950
|
-
return payload;
|
|
2951
|
-
}
|
|
2952
|
-
function echoFileIntent(resolved) {
|
|
2953
|
-
if (resolved === undefined)
|
|
2954
|
-
return "all";
|
|
2955
|
-
return resolved.toLowerCase();
|
|
2956
|
-
}
|
|
2957
3169
|
// src/shared/unified-search-request.ts
|
|
2958
3170
|
function buildUnifiedSearchParams(input) {
|
|
2959
3171
|
const targets = resolveTargets(input.target, input.targets);
|
|
2960
3172
|
const rawQuery = normaliseRequiredQuery(input.query);
|
|
2961
|
-
const
|
|
2962
|
-
const
|
|
2963
|
-
const
|
|
2964
|
-
const waitTimeoutMs = resolveNumber(input.waitTimeoutMs, DEFAULT_WAIT_TIMEOUT_MS, "waitTimeoutMs", defaulted);
|
|
3173
|
+
const limit = input.limit ?? 20;
|
|
3174
|
+
const offset = input.offset ?? 0;
|
|
3175
|
+
const waitTimeoutMs = input.waitTimeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;
|
|
2965
3176
|
const qualifierClauses = buildQualifierClauses({
|
|
2966
3177
|
name: input.name,
|
|
2967
3178
|
language: input.language
|
|
@@ -2971,7 +3182,7 @@ function buildUnifiedSearchParams(input) {
|
|
|
2971
3182
|
kind: input.kind,
|
|
2972
3183
|
category: input.category,
|
|
2973
3184
|
pathPrefix: input.pathPrefix,
|
|
2974
|
-
fileIntent:
|
|
3185
|
+
fileIntent: input.fileIntent,
|
|
2975
3186
|
publicOnly: input.publicOnly
|
|
2976
3187
|
});
|
|
2977
3188
|
return {
|
|
@@ -2986,8 +3197,7 @@ function buildUnifiedSearchParams(input) {
|
|
|
2986
3197
|
waitTimeoutMs
|
|
2987
3198
|
},
|
|
2988
3199
|
rawQuery,
|
|
2989
|
-
compiledQuery
|
|
2990
|
-
defaulted
|
|
3200
|
+
compiledQuery
|
|
2991
3201
|
};
|
|
2992
3202
|
}
|
|
2993
3203
|
function resolveTargets(target, targets) {
|
|
@@ -3021,23 +3231,6 @@ function normaliseRequiredQuery(query) {
|
|
|
3021
3231
|
}
|
|
3022
3232
|
return trimmed;
|
|
3023
3233
|
}
|
|
3024
|
-
function resolveNumber(value, fallback, field, defaulted) {
|
|
3025
|
-
if (value === undefined) {
|
|
3026
|
-
defaulted.push(field);
|
|
3027
|
-
return fallback;
|
|
3028
|
-
}
|
|
3029
|
-
return value;
|
|
3030
|
-
}
|
|
3031
|
-
function resolveFileIntent2(value, sources, defaulted) {
|
|
3032
|
-
if (value === undefined) {
|
|
3033
|
-
if (sources && sources.length > 0 && sources.every((entry) => entry === "DOCS")) {
|
|
3034
|
-
return;
|
|
3035
|
-
}
|
|
3036
|
-
defaulted.push("fileIntent");
|
|
3037
|
-
return SEARCH_SYMBOLS_DEFAULT_FILE_INTENT;
|
|
3038
|
-
}
|
|
3039
|
-
return value;
|
|
3040
|
-
}
|
|
3041
3234
|
function buildQualifierClauses(input) {
|
|
3042
3235
|
const clauses = [];
|
|
3043
3236
|
if (input.name) {
|
|
@@ -3083,39 +3276,46 @@ function buildFilters(input) {
|
|
|
3083
3276
|
return Object.keys(filters).length > 0 ? filters : undefined;
|
|
3084
3277
|
}
|
|
3085
3278
|
// src/shared/unified-search-response.ts
|
|
3086
|
-
|
|
3279
|
+
var DEFAULT_LIMIT2 = 20;
|
|
3280
|
+
var DEFAULT_OFFSET = 0;
|
|
3281
|
+
function buildUnifiedSearchSuccessPayload(params, rawQuery, compiledQuery, outcome) {
|
|
3087
3282
|
const warnings = outcome.state === "completed" ? outcome.result.queryWarnings : outcome.result?.queryWarnings ?? outcome.progress?.queryWarnings ?? [];
|
|
3088
|
-
const query = buildQueryEcho(params, rawQuery, compiledQuery,
|
|
3283
|
+
const query = buildQueryEcho(params, rawQuery, compiledQuery, warnings);
|
|
3089
3284
|
if (outcome.state === "incomplete") {
|
|
3090
3285
|
const result = outcome.result;
|
|
3091
3286
|
const payload = {
|
|
3092
3287
|
query,
|
|
3093
3288
|
completed: false,
|
|
3094
|
-
returnedCount: result?.results.length ?? 0,
|
|
3095
3289
|
hasMore: result?.page.hasMore ?? false,
|
|
3096
3290
|
results: result?.results.map(buildHitPayload) ?? [],
|
|
3097
|
-
searchRef: outcome.searchRef
|
|
3098
|
-
progress: outcome.progress
|
|
3291
|
+
searchRef: outcome.searchRef
|
|
3099
3292
|
};
|
|
3100
3293
|
if (result?.page.hasMore === true) {
|
|
3101
3294
|
payload.nextOffset = result.page.offset + result.page.returned;
|
|
3102
3295
|
}
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3296
|
+
const progress = compactProgress(outcome.progress);
|
|
3297
|
+
if (progress)
|
|
3298
|
+
payload.progress = progress;
|
|
3299
|
+
const sourceStatus2 = compactSourceStatus(result?.sourceStatus);
|
|
3300
|
+
if (sourceStatus2)
|
|
3301
|
+
payload.sourceStatus = sourceStatus2;
|
|
3106
3302
|
return payload;
|
|
3107
3303
|
}
|
|
3108
|
-
|
|
3304
|
+
const completed = {
|
|
3109
3305
|
query,
|
|
3110
3306
|
completed: true,
|
|
3111
|
-
returnedCount: outcome.result.results.length,
|
|
3112
3307
|
hasMore: outcome.result.page.hasMore,
|
|
3113
|
-
|
|
3114
|
-
results: outcome.result.results.map(buildHitPayload),
|
|
3115
|
-
searchRef: outcome.searchRef,
|
|
3116
|
-
progress: outcome.progress,
|
|
3117
|
-
sourceStatus: outcome.result.sourceStatus
|
|
3308
|
+
results: outcome.result.results.map(buildHitPayload)
|
|
3118
3309
|
};
|
|
3310
|
+
if (outcome.result.page.hasMore) {
|
|
3311
|
+
completed.nextOffset = outcome.result.page.offset + outcome.result.page.returned;
|
|
3312
|
+
}
|
|
3313
|
+
if (outcome.searchRef)
|
|
3314
|
+
completed.searchRef = outcome.searchRef;
|
|
3315
|
+
const sourceStatus = compactSourceStatus(outcome.result.sourceStatus);
|
|
3316
|
+
if (sourceStatus)
|
|
3317
|
+
completed.sourceStatus = sourceStatus;
|
|
3318
|
+
return completed;
|
|
3119
3319
|
}
|
|
3120
3320
|
function buildUnifiedSearchErrorPayload(error2) {
|
|
3121
3321
|
const mapped = mapCodeNavigationError(error2);
|
|
@@ -3133,82 +3333,225 @@ function buildUnifiedSearchErrorPayload(error2) {
|
|
|
3133
3333
|
}
|
|
3134
3334
|
function buildUnifiedSearchStatusPayload(outcome) {
|
|
3135
3335
|
if (outcome.state === "incomplete") {
|
|
3136
|
-
const
|
|
3336
|
+
const payload2 = {
|
|
3137
3337
|
completed: false,
|
|
3138
|
-
searchRef: outcome.searchRef
|
|
3139
|
-
progress: outcome.progress
|
|
3338
|
+
searchRef: outcome.searchRef
|
|
3140
3339
|
};
|
|
3340
|
+
const progress = compactProgress(outcome.progress);
|
|
3341
|
+
if (progress)
|
|
3342
|
+
payload2.progress = progress;
|
|
3141
3343
|
if (outcome.result) {
|
|
3142
|
-
|
|
3344
|
+
payload2.result = buildUnifiedSearchStatusResultPayload(outcome.result);
|
|
3143
3345
|
}
|
|
3144
|
-
return
|
|
3346
|
+
return payload2;
|
|
3145
3347
|
}
|
|
3146
|
-
|
|
3348
|
+
const payload = {
|
|
3147
3349
|
completed: true,
|
|
3148
|
-
searchRef: outcome.searchRef,
|
|
3149
|
-
progress: outcome.progress,
|
|
3150
3350
|
result: buildUnifiedSearchStatusResultPayload(outcome.result)
|
|
3151
3351
|
};
|
|
3352
|
+
if (outcome.searchRef)
|
|
3353
|
+
payload.searchRef = outcome.searchRef;
|
|
3354
|
+
return payload;
|
|
3152
3355
|
}
|
|
3153
3356
|
function buildUnifiedSearchStatusResultPayload(result) {
|
|
3154
|
-
|
|
3155
|
-
query: result.query,
|
|
3156
|
-
queryWarnings: result.queryWarnings,
|
|
3157
|
-
sources: result.sources.map((entry) => entry.toLowerCase()),
|
|
3158
|
-
returnedCount: result.results.length,
|
|
3357
|
+
const payload = {
|
|
3159
3358
|
hasMore: result.page.hasMore,
|
|
3160
|
-
|
|
3161
|
-
results: result.results.map(buildHitPayload),
|
|
3162
|
-
sourceStatus: result.sourceStatus
|
|
3359
|
+
results: result.results.map(buildHitPayload)
|
|
3163
3360
|
};
|
|
3361
|
+
if (result.page.hasMore) {
|
|
3362
|
+
payload.nextOffset = result.page.offset + result.page.returned;
|
|
3363
|
+
}
|
|
3364
|
+
if (result.queryWarnings.length > 0) {
|
|
3365
|
+
payload.warnings = result.queryWarnings;
|
|
3366
|
+
}
|
|
3367
|
+
if (result.sources.length > 0) {
|
|
3368
|
+
payload.sources = result.sources.map((entry) => entry.toLowerCase());
|
|
3369
|
+
}
|
|
3370
|
+
const sourceStatus = compactSourceStatus(result.sourceStatus);
|
|
3371
|
+
if (sourceStatus)
|
|
3372
|
+
payload.sourceStatus = sourceStatus;
|
|
3373
|
+
return payload;
|
|
3164
3374
|
}
|
|
3165
|
-
function buildQueryEcho(params, rawQuery, compiledQuery,
|
|
3166
|
-
|
|
3167
|
-
raw: rawQuery
|
|
3168
|
-
compiled: compiledQuery,
|
|
3169
|
-
warnings,
|
|
3170
|
-
targets: params.targets,
|
|
3171
|
-
sources: params.sources?.map((entry) => entry.toLowerCase()),
|
|
3172
|
-
filters: params.filters ? {
|
|
3173
|
-
kind: params.filters.kind?.toLowerCase(),
|
|
3174
|
-
category: params.filters.category?.toLowerCase(),
|
|
3175
|
-
pathPrefix: params.filters.pathPrefix,
|
|
3176
|
-
fileIntent: params.filters.fileIntent?.toLowerCase(),
|
|
3177
|
-
publicOnly: params.filters.publicOnly
|
|
3178
|
-
} : undefined,
|
|
3179
|
-
allowPartialResults: params.allowPartialResults ?? false,
|
|
3180
|
-
limit: params.limit ?? 0,
|
|
3181
|
-
offset: params.offset ?? 0,
|
|
3182
|
-
waitTimeoutMs: params.waitTimeoutMs ?? 0,
|
|
3183
|
-
defaulted
|
|
3375
|
+
function buildQueryEcho(params, rawQuery, compiledQuery, warnings) {
|
|
3376
|
+
const echo = {
|
|
3377
|
+
raw: rawQuery
|
|
3184
3378
|
};
|
|
3379
|
+
if (compiledQuery !== rawQuery) {
|
|
3380
|
+
echo.compiled = compiledQuery;
|
|
3381
|
+
}
|
|
3382
|
+
if (warnings.length > 0) {
|
|
3383
|
+
echo.warnings = warnings;
|
|
3384
|
+
}
|
|
3385
|
+
if (params.sources && params.sources.length > 0) {
|
|
3386
|
+
echo.sources = params.sources.map((entry) => entry.toLowerCase());
|
|
3387
|
+
}
|
|
3388
|
+
if (params.filters) {
|
|
3389
|
+
const filters = {};
|
|
3390
|
+
if (params.filters.kind)
|
|
3391
|
+
filters.kind = params.filters.kind.toLowerCase();
|
|
3392
|
+
if (params.filters.category)
|
|
3393
|
+
filters.category = params.filters.category.toLowerCase();
|
|
3394
|
+
if (params.filters.pathPrefix)
|
|
3395
|
+
filters.pathPrefix = params.filters.pathPrefix;
|
|
3396
|
+
if (params.filters.fileIntent)
|
|
3397
|
+
filters.fileIntent = params.filters.fileIntent.toLowerCase();
|
|
3398
|
+
if (typeof params.filters.publicOnly === "boolean")
|
|
3399
|
+
filters.publicOnly = params.filters.publicOnly;
|
|
3400
|
+
if (Object.keys(filters).length > 0)
|
|
3401
|
+
echo.filters = filters;
|
|
3402
|
+
}
|
|
3403
|
+
if (params.allowPartialResults === true) {
|
|
3404
|
+
echo.allowPartialResults = true;
|
|
3405
|
+
}
|
|
3406
|
+
if (params.limit !== undefined && params.limit !== DEFAULT_LIMIT2) {
|
|
3407
|
+
echo.limit = params.limit;
|
|
3408
|
+
}
|
|
3409
|
+
if (params.offset !== undefined && params.offset !== DEFAULT_OFFSET) {
|
|
3410
|
+
echo.offset = params.offset;
|
|
3411
|
+
}
|
|
3412
|
+
if (params.waitTimeoutMs !== undefined && params.waitTimeoutMs !== DEFAULT_WAIT_TIMEOUT_MS) {
|
|
3413
|
+
echo.waitTimeoutMs = params.waitTimeoutMs;
|
|
3414
|
+
}
|
|
3415
|
+
return echo;
|
|
3185
3416
|
}
|
|
3186
3417
|
function buildHitPayload(hit) {
|
|
3187
|
-
|
|
3418
|
+
assertSearchFollowUpInvariant(hit);
|
|
3419
|
+
const payload = {
|
|
3188
3420
|
type: hit.resultType.toLowerCase(),
|
|
3189
3421
|
target: hit.targetLabel,
|
|
3190
|
-
|
|
3191
|
-
summary: hit.summary,
|
|
3192
|
-
score: hit.score,
|
|
3193
|
-
highlights: hit.highlights,
|
|
3194
|
-
locator: {
|
|
3195
|
-
registry: hit.locator.registry,
|
|
3196
|
-
packageName: hit.locator.packageName,
|
|
3197
|
-
version: hit.locator.version,
|
|
3198
|
-
pageId: hit.locator.pageId,
|
|
3199
|
-
repoUrl: hit.locator.repoUrl,
|
|
3200
|
-
gitRef: hit.locator.gitRef,
|
|
3201
|
-
filePath: hit.locator.filePath,
|
|
3202
|
-
startLine: hit.locator.startLine,
|
|
3203
|
-
endLine: hit.locator.endLine,
|
|
3204
|
-
fileContentHash: hit.locator.fileContentHash,
|
|
3205
|
-
symbolRef: hit.locator.symbolRef,
|
|
3206
|
-
qualifiedPath: hit.locator.qualifiedPath,
|
|
3207
|
-
kind: hit.locator.kind,
|
|
3208
|
-
category: hit.locator.category,
|
|
3209
|
-
language: hit.locator.language
|
|
3210
|
-
}
|
|
3422
|
+
locator: buildLocatorPayload(hit)
|
|
3211
3423
|
};
|
|
3424
|
+
if (hit.title)
|
|
3425
|
+
payload.title = hit.title;
|
|
3426
|
+
if (hit.summary)
|
|
3427
|
+
payload.summary = hit.summary;
|
|
3428
|
+
if (typeof hit.score === "number")
|
|
3429
|
+
payload.score = hit.score;
|
|
3430
|
+
const highlights = buildHighlights(hit.highlights);
|
|
3431
|
+
if (highlights)
|
|
3432
|
+
payload.highlights = highlights;
|
|
3433
|
+
return payload;
|
|
3434
|
+
}
|
|
3435
|
+
function buildLocatorPayload(hit) {
|
|
3436
|
+
const locator = {};
|
|
3437
|
+
const src = hit.locator;
|
|
3438
|
+
if (src.registry)
|
|
3439
|
+
locator.registry = src.registry;
|
|
3440
|
+
if (src.packageName)
|
|
3441
|
+
locator.packageName = src.packageName;
|
|
3442
|
+
if (src.version)
|
|
3443
|
+
locator.version = src.version;
|
|
3444
|
+
if (src.pageId)
|
|
3445
|
+
locator.pageId = src.pageId;
|
|
3446
|
+
if (src.sourceKind)
|
|
3447
|
+
locator.sourceKind = src.sourceKind;
|
|
3448
|
+
if (src.sourceUrl)
|
|
3449
|
+
locator.sourceUrl = src.sourceUrl;
|
|
3450
|
+
if (src.repoUrl)
|
|
3451
|
+
locator.repoUrl = src.repoUrl;
|
|
3452
|
+
if (src.gitRef)
|
|
3453
|
+
locator.gitRef = src.gitRef;
|
|
3454
|
+
if (src.requestedRef)
|
|
3455
|
+
locator.requestedRef = src.requestedRef;
|
|
3456
|
+
if (src.filePath)
|
|
3457
|
+
locator.filePath = src.filePath;
|
|
3458
|
+
if (typeof src.startLine === "number")
|
|
3459
|
+
locator.startLine = src.startLine;
|
|
3460
|
+
if (typeof src.endLine === "number")
|
|
3461
|
+
locator.endLine = src.endLine;
|
|
3462
|
+
if (src.qualifiedPath && src.qualifiedPath !== hit.title) {
|
|
3463
|
+
locator.qualifiedPath = src.qualifiedPath;
|
|
3464
|
+
}
|
|
3465
|
+
if (src.kind)
|
|
3466
|
+
locator.kind = src.kind;
|
|
3467
|
+
if (src.category)
|
|
3468
|
+
locator.category = src.category;
|
|
3469
|
+
if (src.language)
|
|
3470
|
+
locator.language = src.language;
|
|
3471
|
+
return locator;
|
|
3472
|
+
}
|
|
3473
|
+
function buildHighlights(highlights) {
|
|
3474
|
+
if (!highlights)
|
|
3475
|
+
return;
|
|
3476
|
+
const compact = {};
|
|
3477
|
+
if (highlights.title && highlights.title.length > 0) {
|
|
3478
|
+
compact.title = highlights.title;
|
|
3479
|
+
}
|
|
3480
|
+
if (highlights.summary && highlights.summary.length > 0) {
|
|
3481
|
+
compact.summary = highlights.summary;
|
|
3482
|
+
}
|
|
3483
|
+
return Object.keys(compact).length > 0 ? compact : undefined;
|
|
3484
|
+
}
|
|
3485
|
+
function compactProgress(progress) {
|
|
3486
|
+
if (!progress)
|
|
3487
|
+
return;
|
|
3488
|
+
const payload = {
|
|
3489
|
+
status: progress.status,
|
|
3490
|
+
targetsReady: progress.targetsReady,
|
|
3491
|
+
targetsTotal: progress.targetsTotal,
|
|
3492
|
+
elapsedMs: progress.elapsedMs
|
|
3493
|
+
};
|
|
3494
|
+
if (progress.expiresAt)
|
|
3495
|
+
payload.expiresAt = progress.expiresAt;
|
|
3496
|
+
return payload;
|
|
3497
|
+
}
|
|
3498
|
+
function compactSourceStatus(sourceStatus) {
|
|
3499
|
+
if (!sourceStatus || sourceStatus.length === 0)
|
|
3500
|
+
return;
|
|
3501
|
+
const compact = [];
|
|
3502
|
+
for (const entry of sourceStatus) {
|
|
3503
|
+
const slim = compactSourceStatusEntry(entry);
|
|
3504
|
+
if (slim)
|
|
3505
|
+
compact.push(slim);
|
|
3506
|
+
}
|
|
3507
|
+
return compact.length > 0 ? compact : undefined;
|
|
3508
|
+
}
|
|
3509
|
+
function compactSourceStatusEntry(entry) {
|
|
3510
|
+
const payload = {
|
|
3511
|
+
source: entry.source.toLowerCase(),
|
|
3512
|
+
targetLabel: entry.targetLabel
|
|
3513
|
+
};
|
|
3514
|
+
let interesting = false;
|
|
3515
|
+
if (entry.indexingStatus && entry.indexingStatus !== "INDEXED") {
|
|
3516
|
+
payload.indexingStatus = entry.indexingStatus;
|
|
3517
|
+
interesting = true;
|
|
3518
|
+
}
|
|
3519
|
+
if (entry.codeIndexState && entry.codeIndexState !== "CURRENT" && entry.codeIndexState !== "STALE") {
|
|
3520
|
+
payload.codeIndexState = entry.codeIndexState;
|
|
3521
|
+
interesting = true;
|
|
3522
|
+
}
|
|
3523
|
+
if (typeof entry.resultCount === "number" && entry.resultCount > 0) {
|
|
3524
|
+
payload.resultCount = entry.resultCount;
|
|
3525
|
+
}
|
|
3526
|
+
if (entry.ignoredFilters.length > 0) {
|
|
3527
|
+
payload.ignoredFilters = entry.ignoredFilters;
|
|
3528
|
+
interesting = true;
|
|
3529
|
+
}
|
|
3530
|
+
if (entry.incompatibleFilters.length > 0) {
|
|
3531
|
+
payload.incompatibleFilters = entry.incompatibleFilters;
|
|
3532
|
+
interesting = true;
|
|
3533
|
+
}
|
|
3534
|
+
if (entry.ignoredQueryFeatures.length > 0) {
|
|
3535
|
+
payload.ignoredQueryFeatures = entry.ignoredQueryFeatures;
|
|
3536
|
+
interesting = true;
|
|
3537
|
+
}
|
|
3538
|
+
if (entry.incompatibleQueryFeatures.length > 0) {
|
|
3539
|
+
payload.incompatibleQueryFeatures = entry.incompatibleQueryFeatures;
|
|
3540
|
+
interesting = true;
|
|
3541
|
+
}
|
|
3542
|
+
if (entry.note) {
|
|
3543
|
+
payload.note = entry.note;
|
|
3544
|
+
interesting = true;
|
|
3545
|
+
}
|
|
3546
|
+
return interesting ? payload : undefined;
|
|
3547
|
+
}
|
|
3548
|
+
function assertSearchFollowUpInvariant(hit) {
|
|
3549
|
+
if ((hit.resultType === "DOCUMENTATION_PAGE" || hit.resultType === "REPOSITORY_DOC") && !hit.locator.pageId) {
|
|
3550
|
+
throw new MalformedCodeNavigationResponseError(`${hit.resultType} search hit missing required pageId.`);
|
|
3551
|
+
}
|
|
3552
|
+
if (hit.resultType === "REPOSITORY_DOC" && (!hit.locator.repoUrl || !hit.locator.gitRef || !hit.locator.filePath)) {
|
|
3553
|
+
throw new MalformedCodeNavigationResponseError("REPOSITORY_DOC search hit missing repo locator fields.");
|
|
3554
|
+
}
|
|
3212
3555
|
}
|
|
3213
3556
|
// src/shared/unified-search-target.ts
|
|
3214
3557
|
function parseUnifiedSearchTargetSpec(spec) {
|
|
@@ -3378,7 +3721,7 @@ function formatPlain2(envelope, options) {
|
|
|
3378
3721
|
}
|
|
3379
3722
|
function formatVerbose2(envelope, options) {
|
|
3380
3723
|
const lines = [];
|
|
3381
|
-
lines.push(
|
|
3724
|
+
lines.push(buildSummaryHeader2(envelope, options));
|
|
3382
3725
|
if (envelope.resolution || envelope.indexedVersion) {
|
|
3383
3726
|
lines.push(buildResolutionLine(envelope, options));
|
|
3384
3727
|
}
|
|
@@ -3406,7 +3749,7 @@ function formatEmpty(envelope, options, verbose) {
|
|
|
3406
3749
|
` };
|
|
3407
3750
|
}
|
|
3408
3751
|
const lines = [];
|
|
3409
|
-
lines.push(
|
|
3752
|
+
lines.push(buildSummaryHeader2(envelope, options));
|
|
3410
3753
|
if (envelope.resolution || envelope.indexedVersion) {
|
|
3411
3754
|
lines.push(buildResolutionLine(envelope, options));
|
|
3412
3755
|
}
|
|
@@ -3416,7 +3759,7 @@ function formatEmpty(envelope, options, verbose) {
|
|
|
3416
3759
|
return { stdout: lines.join(`
|
|
3417
3760
|
`) };
|
|
3418
3761
|
}
|
|
3419
|
-
function
|
|
3762
|
+
function buildSummaryHeader2(envelope, options) {
|
|
3420
3763
|
const identity = buildIdentityLabel(envelope);
|
|
3421
3764
|
const countValue = envelope.hasMore ? `${envelope.files.length}+` : String(envelope.total);
|
|
3422
3765
|
const counts = `${countValue} ${plural("file", "files", envelope.files.length)}`;
|
|
@@ -3654,7 +3997,7 @@ On an INDEXING response, the dependency is being indexed on-demand
|
|
|
3654
3997
|
— retry with a longer --wait (up to 60000 ms) or pick one of the
|
|
3655
3998
|
already-indexed versions surfaced in the error detail.`;
|
|
3656
3999
|
function registerCodeFilesCommand(pkgCommand) {
|
|
3657
|
-
return pkgCommand.command("files").summary("List files in an indexed dependency").description(PKG_FILES_DESCRIPTION).argument("[
|
|
4000
|
+
return pkgCommand.command("files").summary("List files in an indexed dependency").description(PKG_FILES_DESCRIPTION).argument("[spec-or-prefix]", "Spec mode: package spec (e.g. npm:express). Repo mode (with --repo-url): the path-prefix.").argument("[path-prefix]", "Spec mode only: literal directory prefix (not a glob). 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("--limit <n>", "Max entries (1-1000, default 200)").option("--wait <ms>", `Indexing wait timeout (0-${MAX_WAIT_TIMEOUT_MS}, default ${DEFAULT_WAIT_TIMEOUT_MS})`).option("-v, --verbose", "Annotate each path with language / file-type / byte size").option("--json", "Emit the JSON envelope").action(async (arg1, arg2, options) => {
|
|
3658
4001
|
const deps = await createContainer();
|
|
3659
4002
|
await pkgFilesAction(arg1, arg2, options, {
|
|
3660
4003
|
codeNavigationService: deps.codeNavigationService,
|
|
@@ -3796,8 +4139,8 @@ for context, --verbose for grouped output, and --cursor to continue a paginated
|
|
|
3796
4139
|
grep run. --symbol-field hydrates enclosing symbol metadata (appears under each
|
|
3797
4140
|
match in --verbose output; full payload in --json).`;
|
|
3798
4141
|
function registerCodeGrepCommand(pkgCommand) {
|
|
3799
|
-
return pkgCommand.command("grep").summary("Deterministic text grep over indexed dependency source").description(PKG_GREP_DESCRIPTION).argument("[
|
|
3800
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
4142
|
+
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)", collectRepeatable, []).option("--ext <ext>", "Extension filter without leading dot (repeatable)", collectRepeatable, []).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}`, collectRepeatable, []).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) => {
|
|
4143
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-67qnnqby.js");
|
|
3801
4144
|
const deps = await createContainer2();
|
|
3802
4145
|
await pkgGrepAction(arg1, arg2, arg3, options, {
|
|
3803
4146
|
codeNavigationService: deps.codeNavigationService,
|
|
@@ -3895,7 +4238,7 @@ function formatReadFileTerminal(envelope, options) {
|
|
|
3895
4238
|
function formatBinary(envelope, options, verbose) {
|
|
3896
4239
|
const sentinel = dim("Binary file — cannot display as text.", options.useColors);
|
|
3897
4240
|
if (verbose) {
|
|
3898
|
-
return `${
|
|
4241
|
+
return `${buildHeader2(envelope, options)}
|
|
3899
4242
|
|
|
3900
4243
|
${sentinel}
|
|
3901
4244
|
`;
|
|
@@ -3906,7 +4249,7 @@ ${sentinel}
|
|
|
3906
4249
|
function formatNoContent(envelope, options, verbose) {
|
|
3907
4250
|
const sentinel = dim("(no content returned)", options.useColors);
|
|
3908
4251
|
if (verbose) {
|
|
3909
|
-
return `${
|
|
4252
|
+
return `${buildHeader2(envelope, options)}
|
|
3910
4253
|
|
|
3911
4254
|
${sentinel}
|
|
3912
4255
|
`;
|
|
@@ -3916,7 +4259,7 @@ ${sentinel}
|
|
|
3916
4259
|
}
|
|
3917
4260
|
function formatVerboseBody(envelope, options) {
|
|
3918
4261
|
const lines = [];
|
|
3919
|
-
lines.push(
|
|
4262
|
+
lines.push(buildHeader2(envelope, options));
|
|
3920
4263
|
lines.push("");
|
|
3921
4264
|
const content = envelope.content ?? "";
|
|
3922
4265
|
const bodyLines = content.split(`
|
|
@@ -3936,7 +4279,7 @@ function formatVerboseBody(envelope, options) {
|
|
|
3936
4279
|
return lines.join(`
|
|
3937
4280
|
`);
|
|
3938
4281
|
}
|
|
3939
|
-
function
|
|
4282
|
+
function buildHeader2(envelope, options) {
|
|
3940
4283
|
const parts = [envelope.path];
|
|
3941
4284
|
if (envelope.language)
|
|
3942
4285
|
parts.push(envelope.language);
|
|
@@ -4026,14 +4369,14 @@ function resolveLineRange(options, pathWithRange) {
|
|
|
4026
4369
|
};
|
|
4027
4370
|
}
|
|
4028
4371
|
if (hasLines) {
|
|
4029
|
-
return
|
|
4372
|
+
return parseLinesOption2(options.lines);
|
|
4030
4373
|
}
|
|
4031
4374
|
return {
|
|
4032
4375
|
startLine: parseIntCliOption(options.start, "--start", 1, Number.MAX_SAFE_INTEGER),
|
|
4033
4376
|
endLine: parseIntCliOption(options.end, "--end", 1, Number.MAX_SAFE_INTEGER)
|
|
4034
4377
|
};
|
|
4035
4378
|
}
|
|
4036
|
-
function
|
|
4379
|
+
function parseLinesOption2(raw) {
|
|
4037
4380
|
const trimmed = raw.trim();
|
|
4038
4381
|
const dashIndex = trimmed.indexOf("-");
|
|
4039
4382
|
if (dashIndex < 0) {
|
|
@@ -4044,8 +4387,8 @@ function parseLinesOption(raw) {
|
|
|
4044
4387
|
if (startRaw.length === 0 && endRaw.length === 0) {
|
|
4045
4388
|
throw new InvalidPackageSpecError("--lines requires at least one bound. Use `10-40`, `10-` for open end, or `-40` for open start.");
|
|
4046
4389
|
}
|
|
4047
|
-
const startLine = startRaw.length > 0 ?
|
|
4048
|
-
const endLine = endRaw.length > 0 ?
|
|
4390
|
+
const startLine = startRaw.length > 0 ? requirePositiveInteger2(startRaw, "--lines start") : undefined;
|
|
4391
|
+
const endLine = endRaw.length > 0 ? requirePositiveInteger2(endRaw, "--lines end") : undefined;
|
|
4049
4392
|
if (startLine !== undefined && endLine !== undefined && startLine > endLine) {
|
|
4050
4393
|
throw new InvalidPackageSpecError(`--lines range is reversed: ${startLine} > ${endLine}.`);
|
|
4051
4394
|
}
|
|
@@ -4068,14 +4411,14 @@ function parsePathWithOptionalRange(path) {
|
|
|
4068
4411
|
if (!startRaw) {
|
|
4069
4412
|
throw new InvalidPackageSpecError(`Invalid path with range: '${path}'. Use <path>:<start>-<end>.`);
|
|
4070
4413
|
}
|
|
4071
|
-
const startLine =
|
|
4072
|
-
const endLine = endRaw !== undefined && endRaw.length > 0 ?
|
|
4414
|
+
const startLine = requirePositiveInteger2(startRaw, "path range start");
|
|
4415
|
+
const endLine = endRaw !== undefined && endRaw.length > 0 ? requirePositiveInteger2(endRaw, "path range end") : startLine;
|
|
4073
4416
|
if (startLine > endLine) {
|
|
4074
4417
|
throw new InvalidPackageSpecError(`Path range is reversed: ${startLine} > ${endLine}.`);
|
|
4075
4418
|
}
|
|
4076
4419
|
return { filePath, startLine, endLine };
|
|
4077
4420
|
}
|
|
4078
|
-
function
|
|
4421
|
+
function requirePositiveInteger2(raw, label) {
|
|
4079
4422
|
if (!/^\d+$/.test(raw)) {
|
|
4080
4423
|
throw new InvalidPackageSpecError(`${label} must be a positive integer. Got '${raw}'.`);
|
|
4081
4424
|
}
|
|
@@ -4114,308 +4457,210 @@ function registerCodeReadCommand(pkgCommand) {
|
|
|
4114
4457
|
});
|
|
4115
4458
|
}
|
|
4116
4459
|
|
|
4117
|
-
// src/commands/code/
|
|
4118
|
-
async function
|
|
4460
|
+
// src/commands/code/index.ts
|
|
4461
|
+
async function registerCodeCommandGroup(program, options = {}) {
|
|
4462
|
+
const registration = await resolveGatedCommandGroupRegistrationState(options);
|
|
4463
|
+
if (!registration.shouldRegister) {
|
|
4464
|
+
return;
|
|
4465
|
+
}
|
|
4466
|
+
const codeCommand = program.command("code").summary("Source-level operations on indexed dependencies").description("List files, read files, and grep substrings inside indexed dependency source. Every command accepts either `<spec>` (registry:name[@version]) or `--repo-url <url> --git-ref <ref>`. For symbol or unified discovery search use `githits search`; for package-level metadata use `githits pkg`.");
|
|
4467
|
+
registerCodeFilesCommand(codeCommand);
|
|
4468
|
+
registerCodeReadCommand(codeCommand);
|
|
4469
|
+
registerCodeGrepCommand(codeCommand);
|
|
4470
|
+
}
|
|
4471
|
+
// src/commands/docs/list.ts
|
|
4472
|
+
async function docsListAction(spec, options, deps) {
|
|
4119
4473
|
requireAuth(deps);
|
|
4120
4474
|
try {
|
|
4121
|
-
if (!deps.codeNavigationUrl || !deps.
|
|
4122
|
-
throw new
|
|
4123
|
-
}
|
|
4124
|
-
const
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
category: parseCategory(options.category),
|
|
4140
|
-
filePath: options.file,
|
|
4141
|
-
limit: parseOptionalInt(options.limit, "--limit", 1, 50),
|
|
4142
|
-
fileIntent: parseIntent(options.intent),
|
|
4143
|
-
waitTimeoutMs: parseWaitSeconds(options.wait)
|
|
4475
|
+
if (!deps.codeNavigationUrl || !deps.packageIntelligenceService) {
|
|
4476
|
+
throw new InvalidPackageSpecError("Package intelligence is not configured for this environment.");
|
|
4477
|
+
}
|
|
4478
|
+
const parsed = parsePackageSpec(spec);
|
|
4479
|
+
const limit = parseLimitOption(options.limit);
|
|
4480
|
+
const build = buildListPackageDocsParams({
|
|
4481
|
+
registry: parsed.registry,
|
|
4482
|
+
packageName: parsed.name,
|
|
4483
|
+
version: parsed.version,
|
|
4484
|
+
limit,
|
|
4485
|
+
after: options.after
|
|
4486
|
+
});
|
|
4487
|
+
const result = await deps.packageIntelligenceService.listPackageDocs(build.params);
|
|
4488
|
+
const payload = buildListPackageDocsSuccessPayload(result, {
|
|
4489
|
+
limitExplicit: build.limitExplicit,
|
|
4490
|
+
afterExplicit: build.afterExplicit,
|
|
4491
|
+
limit: build.params.limit,
|
|
4492
|
+
after: build.params.after
|
|
4144
4493
|
});
|
|
4145
|
-
const result = await deps.codeNavigationService.searchSymbols(params);
|
|
4146
|
-
const payload = buildSearchSymbolsSuccessPayload(params, defaulted, result);
|
|
4147
4494
|
if (options.json) {
|
|
4148
4495
|
console.log(JSON.stringify(payload));
|
|
4149
4496
|
return;
|
|
4150
4497
|
}
|
|
4151
|
-
|
|
4498
|
+
process.stdout.write(formatListPackageDocsTerminal(payload, {
|
|
4499
|
+
verbose: options.verbose ?? false,
|
|
4500
|
+
useColors: shouldUseColors()
|
|
4501
|
+
}));
|
|
4152
4502
|
} catch (error2) {
|
|
4153
|
-
|
|
4503
|
+
handleDocsListError(error2, options.json ?? false);
|
|
4154
4504
|
}
|
|
4155
4505
|
}
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
Prefer top-level \`githits search --source symbol\` for new symbol-shaped workflows. \`githits code search\` remains available for the older dedicated symbol-search UX and JSON parity contract.
|
|
4159
|
-
|
|
4160
|
-
Package spec: <registry>:<name>[@<version>]. Omit the registry to default to
|
|
4161
|
-
npm. Supported registries: npm, pypi, hex, crates, nuget, maven, zig, vcpkg,
|
|
4162
|
-
packagist.
|
|
4163
|
-
|
|
4164
|
-
Filter by --category (broad: callable, type, module, data, documentation)
|
|
4165
|
-
or --kind (precise: function, method, class, trait, …). Prefer --category
|
|
4166
|
-
for most use cases; reach for --kind when you need a specific construct.
|
|
4167
|
-
|
|
4168
|
-
Default file intent is production source. Pass --intent all to include tests,
|
|
4169
|
-
examples, benchmarks, generated files, and other non-production code.
|
|
4170
|
-
|
|
4171
|
-
Examples:
|
|
4172
|
-
githits code search npm:express middleware
|
|
4173
|
-
githits code search npm:express middleware --intent all
|
|
4174
|
-
githits code search pypi:requests timeout --category callable --limit 10
|
|
4175
|
-
githits code search crates:serde Serialize --kind trait --limit 5
|
|
4176
|
-
githits code search npm:@types/node Buffer --file src/ --json
|
|
4177
|
-
githits code search npm:express --keywords "router,handler" --match-mode and`;
|
|
4178
|
-
function registerCodeSearchSymbolsCommand(program) {
|
|
4179
|
-
program.command("search <package> [query]").alias("search-symbols").summary("Legacy symbol search over indexed package source").description(SEARCH_SYMBOLS_DESCRIPTION).option("--category <category>", "Filter by broad symbol category: callable, type, module, data, documentation. Preferred over --kind for most use cases.").option("--kind <kind>", "Filter by precise symbol kind (function, method, constructor, getter, setter, class, interface, trait, struct, enum, record, module, namespace, property, event, etc.). Prefer --category for broad filtering.").option("--limit <n>", "Max results (1-50; default: 25)").option("--keywords <words>", "Comma-separated keywords (alternative to the query argument)").option("--keyword <word>", "Single keyword (repeatable; combines with --keywords)", collectRepeatable2, []).option("--match-mode <mode>", "How to combine keywords: or (any match) or and (all match)").option("--file <prefix>", "Filter to files matching path prefix").option("--intent <intent>", "File intent filter (production, test, benchmark, example, generated, fixture, build, vendor, all). Default: production.").option("--wait <seconds>", "Max seconds to wait for indexing (0-60; default: 20). Accepts `10` or `10s`. Indexing usually completes within 30 seconds; pass `--wait 60` to block on a first-time request.").option("--json", "Output as JSON").action(async (packageArg, query, options) => {
|
|
4180
|
-
try {
|
|
4181
|
-
const deps = await createContainer();
|
|
4182
|
-
await searchSymbolsAction(packageArg, query, options, deps);
|
|
4183
|
-
} catch (error2) {
|
|
4184
|
-
if (error2 instanceof AuthRequiredError) {
|
|
4185
|
-
process.exit(1);
|
|
4186
|
-
}
|
|
4187
|
-
throw error2;
|
|
4188
|
-
}
|
|
4189
|
-
});
|
|
4190
|
-
}
|
|
4191
|
-
function collectRepeatable2(value, previous) {
|
|
4192
|
-
return [...previous, value];
|
|
4193
|
-
}
|
|
4194
|
-
function formatSearchSymbolsTerminal(payload, registry, packageName, version2, query) {
|
|
4195
|
-
const lines = [];
|
|
4196
|
-
if (payload.warning) {
|
|
4197
|
-
lines.push(`Warning: ${payload.warning}`);
|
|
4198
|
-
lines.push("");
|
|
4199
|
-
}
|
|
4200
|
-
lines.push(formatHeader2(payload));
|
|
4201
|
-
lines.push("");
|
|
4202
|
-
if (payload.results.length === 0) {
|
|
4203
|
-
lines.push(formatZeroResultMessage(query, registry, packageName, version2, payload.query, payload.hint));
|
|
4204
|
-
return lines.join(`
|
|
4205
|
-
`).trimEnd();
|
|
4206
|
-
}
|
|
4207
|
-
for (const entry of payload.results) {
|
|
4208
|
-
lines.push(...formatEntry(entry));
|
|
4209
|
-
lines.push("");
|
|
4210
|
-
}
|
|
4211
|
-
if (payload.hint) {
|
|
4212
|
-
lines.push(`Note: ${payload.hint}`);
|
|
4213
|
-
}
|
|
4214
|
-
return lines.join(`
|
|
4215
|
-
`).trimEnd();
|
|
4216
|
-
}
|
|
4217
|
-
function formatHeader2(payload) {
|
|
4218
|
-
let summary = `${payload.returnedCount} match(es)`;
|
|
4219
|
-
if (payload.hasMore)
|
|
4220
|
-
summary += " (more available)";
|
|
4221
|
-
if (payload.version) {
|
|
4222
|
-
summary += ` · indexed ${displayVersion(payload.version)}`;
|
|
4223
|
-
const requested = payload.resolution?.requestedVersion ?? payload.resolution?.requestedRef;
|
|
4224
|
-
if (requested && !isTrivialRefDifference(requested, payload.version) && !isTrivialRefDifference(requested, payload.resolution?.resolvedRef)) {
|
|
4225
|
-
summary += ` (requested ${requested})`;
|
|
4226
|
-
}
|
|
4227
|
-
}
|
|
4228
|
-
return summary;
|
|
4229
|
-
}
|
|
4230
|
-
function displayVersion(version2) {
|
|
4231
|
-
if (/^[0-9a-f]{40}$/i.test(version2))
|
|
4232
|
-
return version2.slice(0, 7);
|
|
4233
|
-
return version2;
|
|
4234
|
-
}
|
|
4235
|
-
function isTrivialRefDifference(requested, resolved) {
|
|
4236
|
-
if (!resolved)
|
|
4237
|
-
return false;
|
|
4238
|
-
if (requested === resolved)
|
|
4239
|
-
return true;
|
|
4240
|
-
const stripV = (v) => v.startsWith("v") ? v.slice(1) : v;
|
|
4241
|
-
return stripV(requested) === stripV(resolved);
|
|
4242
|
-
}
|
|
4243
|
-
function formatEntry(entry) {
|
|
4244
|
-
const out = [];
|
|
4245
|
-
const locationParts = [];
|
|
4246
|
-
if (entry.filePath) {
|
|
4247
|
-
if (entry.startLine) {
|
|
4248
|
-
locationParts.push(entry.endLine && entry.endLine !== entry.startLine ? `${entry.filePath}:${entry.startLine}-${entry.endLine}` : `${entry.filePath}:${entry.startLine}`);
|
|
4249
|
-
} else {
|
|
4250
|
-
locationParts.push(entry.filePath);
|
|
4251
|
-
}
|
|
4252
|
-
}
|
|
4253
|
-
const kindLabel = resolveKindLabel(entry);
|
|
4254
|
-
if (kindLabel)
|
|
4255
|
-
locationParts.push(`[${kindLabel}]`);
|
|
4256
|
-
out.push(locationParts.length > 0 ? locationParts.join(" ") : "unnamed match");
|
|
4257
|
-
if (entry.name)
|
|
4258
|
-
out.push(` ${entry.name}`);
|
|
4259
|
-
const snippet = buildSnippet(entry.code);
|
|
4260
|
-
for (const snippetLine of snippet)
|
|
4261
|
-
out.push(snippetLine);
|
|
4262
|
-
return out;
|
|
4263
|
-
}
|
|
4264
|
-
function resolveKindLabel(entry) {
|
|
4265
|
-
if (!entry.kind)
|
|
4266
|
-
return;
|
|
4267
|
-
const normalised = entry.kind.toLowerCase();
|
|
4268
|
-
if (normalised === "fallback")
|
|
4506
|
+
function parseLimitOption(value) {
|
|
4507
|
+
if (value === undefined)
|
|
4269
4508
|
return;
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
if (!code)
|
|
4274
|
-
return [];
|
|
4275
|
-
const raw = code.split(`
|
|
4276
|
-
`);
|
|
4277
|
-
while (raw.length > 0 && raw[0]?.trim() === "")
|
|
4278
|
-
raw.shift();
|
|
4279
|
-
while (raw.length > 0 && raw[raw.length - 1]?.trim() === "")
|
|
4280
|
-
raw.pop();
|
|
4281
|
-
if (raw.length === 0)
|
|
4282
|
-
return [];
|
|
4283
|
-
const indent = commonLeadingIndent(raw);
|
|
4284
|
-
const dedented = raw.map((line) => indent > 0 ? line.slice(indent) : line);
|
|
4285
|
-
const truncated = dedented.length > maxLines;
|
|
4286
|
-
const selected = dedented.slice(0, maxLines);
|
|
4287
|
-
const visible = truncated ? [...selected, "…"] : selected;
|
|
4288
|
-
return visible.map((line) => ` ${line}`);
|
|
4289
|
-
}
|
|
4290
|
-
function commonLeadingIndent(lines) {
|
|
4291
|
-
let min = Number.POSITIVE_INFINITY;
|
|
4292
|
-
for (const line of lines) {
|
|
4293
|
-
if (line.trim() === "")
|
|
4294
|
-
continue;
|
|
4295
|
-
const match = line.match(/^(\s*)/);
|
|
4296
|
-
const len = match?.[1]?.length ?? 0;
|
|
4297
|
-
if (len < min)
|
|
4298
|
-
min = len;
|
|
4299
|
-
}
|
|
4300
|
-
return Number.isFinite(min) ? min : 0;
|
|
4301
|
-
}
|
|
4302
|
-
function formatZeroResultMessage(query, registry, packageName, version2, echo, serverHint) {
|
|
4303
|
-
const target = version2 ? `${registry}:${packageName}@${version2}` : `${registry}:${packageName}`;
|
|
4304
|
-
const queryText = query ? `"${query}"` : "the given keywords";
|
|
4305
|
-
const header = `No matches for ${queryText} in ${target}.`;
|
|
4306
|
-
if (serverHint) {
|
|
4307
|
-
return [header, serverHint].join(`
|
|
4308
|
-
`);
|
|
4509
|
+
const parsed = Number(value);
|
|
4510
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 500) {
|
|
4511
|
+
throw new InvalidPackageSpecError("--limit must be an integer between 1 and 500.");
|
|
4309
4512
|
}
|
|
4310
|
-
|
|
4311
|
-
if (echo.kind)
|
|
4312
|
-
suggestions.push("drop --kind");
|
|
4313
|
-
if (echo.category)
|
|
4314
|
-
suggestions.push("drop --category");
|
|
4315
|
-
if (echo.filePath)
|
|
4316
|
-
suggestions.push("broaden or remove --file");
|
|
4317
|
-
if (echo.fileIntent !== "all")
|
|
4318
|
-
suggestions.push("try --intent all");
|
|
4319
|
-
if (echo.matchMode === "and")
|
|
4320
|
-
suggestions.push("try --match-mode or");
|
|
4321
|
-
suggestions.push("try broader keywords");
|
|
4322
|
-
return [header, `Try: ${suggestions.join(", ")}.`].join(`
|
|
4323
|
-
`);
|
|
4513
|
+
return parsed;
|
|
4324
4514
|
}
|
|
4325
|
-
function
|
|
4515
|
+
function handleDocsListError(error2, json) {
|
|
4516
|
+
const mapped = mapPackageIntelligenceError(error2);
|
|
4326
4517
|
if (json) {
|
|
4327
|
-
console.error(JSON.stringify(
|
|
4328
|
-
|
|
4518
|
+
console.error(JSON.stringify({
|
|
4519
|
+
error: mapped.message,
|
|
4520
|
+
code: mapped.code,
|
|
4521
|
+
retryable: mapped.retryable ?? false,
|
|
4522
|
+
...mapped.details ? { details: mapped.details } : {}
|
|
4523
|
+
}));
|
|
4524
|
+
} else {
|
|
4525
|
+
console.error(mapped.message);
|
|
4329
4526
|
}
|
|
4330
|
-
const mapped = mapCodeNavigationError(error2);
|
|
4331
|
-
console.error(`Failed to search symbols: ${mapped.message}`);
|
|
4332
4527
|
process.exit(1);
|
|
4333
4528
|
}
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4529
|
+
var DOCS_LIST_DESCRIPTION = `List package documentation pages from mixed sources.
|
|
4530
|
+
|
|
4531
|
+
Docs are mixed by default: hosted/crawled docs and repository-backed docs
|
|
4532
|
+
appear together. Every entry shows its page ID, source badge, and source
|
|
4533
|
+
location. Repo-backed docs also carry exact file follow-up metadata in JSON.
|
|
4534
|
+
|
|
4535
|
+
Package spec: <registry>:<name>[@version].`;
|
|
4536
|
+
function registerDocsListCommand(docsCommand) {
|
|
4537
|
+
return docsCommand.command("list").summary("List documentation pages for a package").description(DOCS_LIST_DESCRIPTION).argument("<spec>", "Package spec, e.g. npm:express@5.2.1").option("--limit <n>", "Max pages (1-500, default 100)").option("--after <cursor>", "Pagination cursor from a prior response").option("-v, --verbose", "Show updated timestamps when available").option("--json", "Emit the JSON envelope").action(async (spec, options) => {
|
|
4538
|
+
const deps = await createContainer();
|
|
4539
|
+
await docsListAction(spec, options, {
|
|
4540
|
+
packageIntelligenceService: deps.packageIntelligenceService,
|
|
4541
|
+
codeNavigationUrl: deps.codeNavigationUrl,
|
|
4542
|
+
hasValidToken: deps.hasValidToken,
|
|
4543
|
+
mcpUrl: deps.mcpUrl
|
|
4544
|
+
});
|
|
4545
|
+
});
|
|
4342
4546
|
}
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4547
|
+
|
|
4548
|
+
// src/commands/docs/read.ts
|
|
4549
|
+
async function docsReadAction(pageId, options, deps) {
|
|
4550
|
+
requireAuth(deps);
|
|
4551
|
+
try {
|
|
4552
|
+
if (!deps.codeNavigationUrl || !deps.packageIntelligenceService) {
|
|
4553
|
+
throw new InvalidPackageSpecError("Package intelligence is not configured for this environment.");
|
|
4554
|
+
}
|
|
4555
|
+
const range = options.lines ? parseLinesOption(options.lines) : undefined;
|
|
4556
|
+
const build = buildReadPackageDocParams({ pageId });
|
|
4557
|
+
const result = await deps.packageIntelligenceService.readPackageDoc(build.params);
|
|
4558
|
+
const payload = buildReadPackageDocSuccessPayload(result, build.params.pageId, range);
|
|
4559
|
+
if (options.json) {
|
|
4560
|
+
console.log(JSON.stringify(payload));
|
|
4561
|
+
return;
|
|
4562
|
+
}
|
|
4563
|
+
process.stdout.write(formatReadPackageDocTerminal(payload, {
|
|
4564
|
+
verbose: options.verbose ?? false,
|
|
4565
|
+
useColors: shouldUseColors()
|
|
4566
|
+
}));
|
|
4567
|
+
} catch (error2) {
|
|
4568
|
+
handleDocsReadError(error2, options.json ?? false);
|
|
4349
4569
|
}
|
|
4350
|
-
return parsed;
|
|
4351
4570
|
}
|
|
4352
|
-
function
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4571
|
+
function handleDocsReadError(error2, json) {
|
|
4572
|
+
const mapped = mapPackageIntelligenceError(error2);
|
|
4573
|
+
if (json) {
|
|
4574
|
+
console.error(JSON.stringify({
|
|
4575
|
+
error: mapped.message,
|
|
4576
|
+
code: mapped.code,
|
|
4577
|
+
retryable: mapped.retryable ?? false,
|
|
4578
|
+
...mapped.details ? { details: mapped.details } : {}
|
|
4579
|
+
}));
|
|
4580
|
+
} else {
|
|
4581
|
+
console.error(mapped.message);
|
|
4358
4582
|
}
|
|
4359
|
-
|
|
4583
|
+
process.exit(1);
|
|
4360
4584
|
}
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4585
|
+
var DOCS_READ_DESCRIPTION = `Read a documentation page by page ID.
|
|
4586
|
+
|
|
4587
|
+
Use page IDs from githits docs list, githits search --json, or MCP doc/search
|
|
4588
|
+
results. Default output is content-only for easy piping; pass --verbose for a
|
|
4589
|
+
metadata header. Use --lines for a bounded line range (e.g. \`--lines 10-40\`,
|
|
4590
|
+
\`--lines 10-\` for open-ended, or \`--lines -40\` for the first 40 lines) —
|
|
4591
|
+
useful when a page is too long to read whole.`;
|
|
4592
|
+
function registerDocsReadCommand(docsCommand) {
|
|
4593
|
+
return docsCommand.command("read").summary("Read a documentation page by page ID").description(DOCS_READ_DESCRIPTION).argument("<page-id>", "Documentation page ID from docs/search results").option("--lines <range>", "Bounded line range, e.g. 10-40, 10-, or -40 (1-indexed inclusive)").option("-v, --verbose", "Show metadata header before content").option("--json", "Emit the JSON envelope").action(async (pageId, options) => {
|
|
4594
|
+
const deps = await createContainer();
|
|
4595
|
+
await docsReadAction(pageId, options, {
|
|
4596
|
+
packageIntelligenceService: deps.packageIntelligenceService,
|
|
4597
|
+
codeNavigationUrl: deps.codeNavigationUrl,
|
|
4598
|
+
hasValidToken: deps.hasValidToken,
|
|
4599
|
+
mcpUrl: deps.mcpUrl
|
|
4600
|
+
});
|
|
4601
|
+
});
|
|
4369
4602
|
}
|
|
4370
|
-
|
|
4371
|
-
|
|
4603
|
+
|
|
4604
|
+
// src/commands/docs/index.ts
|
|
4605
|
+
async function registerDocsCommandGroup(program, options = {}) {
|
|
4606
|
+
const registration = await resolveGatedCommandGroupRegistrationState(options);
|
|
4607
|
+
if (!registration.shouldRegister) {
|
|
4372
4608
|
return;
|
|
4373
|
-
const lower = value.toLowerCase();
|
|
4374
|
-
if (lower === "all")
|
|
4375
|
-
return FILE_INTENT_ALL;
|
|
4376
|
-
const parsed = toSearchSymbolsFileIntent(lower);
|
|
4377
|
-
if (!parsed) {
|
|
4378
|
-
throw new InvalidArgumentError("--intent must be one of production, test, benchmark, example, generated, fixture, build, vendor, or all");
|
|
4379
4609
|
}
|
|
4380
|
-
|
|
4610
|
+
const docsCommand = program.command("docs").summary("Browse and read mixed package documentation").description("Browse and read package documentation across hosted docs and repository-backed docs. Docs are mixed by default; entries are source-badged and repo-backed pages also expose exact file follow-up metadata.");
|
|
4611
|
+
registerDocsListCommand(docsCommand);
|
|
4612
|
+
registerDocsReadCommand(docsCommand);
|
|
4381
4613
|
}
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4614
|
+
// src/commands/example.ts
|
|
4615
|
+
import { Option } from "commander";
|
|
4616
|
+
async function exampleAction(query, options, deps) {
|
|
4617
|
+
requireAuth(deps);
|
|
4618
|
+
try {
|
|
4619
|
+
const result = await deps.githitsService.search({
|
|
4620
|
+
query,
|
|
4621
|
+
language: options.lang,
|
|
4622
|
+
licenseMode: options.license,
|
|
4623
|
+
includeExplanation: options.explain
|
|
4624
|
+
});
|
|
4625
|
+
if (options.json) {
|
|
4626
|
+
const solutionId = extractSolutionId(result);
|
|
4627
|
+
const payload = solutionId ? { result, solution_id: solutionId } : { result };
|
|
4628
|
+
console.log(JSON.stringify(payload));
|
|
4629
|
+
} else {
|
|
4630
|
+
console.log(result);
|
|
4631
|
+
}
|
|
4632
|
+
} catch (error2) {
|
|
4633
|
+
console.error(`Failed to get example: ${error2 instanceof Error ? error2.message : error2}`);
|
|
4634
|
+
process.exit(1);
|
|
4393
4635
|
}
|
|
4394
|
-
return parsed * 1000;
|
|
4395
4636
|
}
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4637
|
+
var EXAMPLE_DESCRIPTION = `Get verified, canonical code examples from global open source.
|
|
4638
|
+
|
|
4639
|
+
For dependency, package, or repository source search, use \`githits search\` instead.
|
|
4640
|
+
|
|
4641
|
+
Examples:
|
|
4642
|
+
githits example "how to use express middleware" --lang javascript
|
|
4643
|
+
githits example "async file reading" -l python --license yolo
|
|
4644
|
+
githits example "react hooks patterns" -l typescript --explain
|
|
4645
|
+
githits example "react hooks patterns" -l typescript --json`;
|
|
4646
|
+
function registerExampleCommand(program) {
|
|
4647
|
+
program.command("example").summary("Get code examples from global open source").description(EXAMPLE_DESCRIPTION).argument("<query>", "Natural language example-search query").requiredOption("-l, --lang <language>", "Programming language").addOption(new Option("--license <mode>", "License filter mode").choices(["strict", "yolo", "custom"]).default(undefined)).option("--explain", "Include AI-generated explanation").option("--json", "Output as JSON for piping").action(async (query, options) => {
|
|
4648
|
+
try {
|
|
4649
|
+
const deps = await loadContainer();
|
|
4650
|
+
await exampleAction(query, options, deps);
|
|
4651
|
+
} catch (error2) {
|
|
4652
|
+
if (error2 instanceof AuthRequiredError)
|
|
4653
|
+
process.exit(1);
|
|
4654
|
+
throw error2;
|
|
4655
|
+
}
|
|
4656
|
+
});
|
|
4657
|
+
}
|
|
4658
|
+
async function loadContainer() {
|
|
4659
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-67qnnqby.js");
|
|
4660
|
+
return createContainer2();
|
|
4416
4661
|
}
|
|
4417
4662
|
// src/commands/feedback.ts
|
|
4418
|
-
import { Option } from "commander";
|
|
4663
|
+
import { Option as Option2 } from "commander";
|
|
4419
4664
|
async function feedbackAction(solutionId, options, deps) {
|
|
4420
4665
|
requireAuth(deps);
|
|
4421
4666
|
if (!options.accept && !options.reject) {
|
|
@@ -4449,7 +4694,7 @@ Examples:
|
|
|
4449
4694
|
githits feedback abc123 --reject -m "Example was outdated"
|
|
4450
4695
|
githits feedback abc123 --accept --message "Solved my problem" --json`;
|
|
4451
4696
|
function registerFeedbackCommand(program) {
|
|
4452
|
-
program.command("feedback").summary("Submit feedback on a search result").description(FEEDBACK_DESCRIPTION).argument("<solution_id>", "Solution ID from search result").addOption(new
|
|
4697
|
+
program.command("feedback").summary("Submit feedback on a search result").description(FEEDBACK_DESCRIPTION).argument("<solution_id>", "Solution ID from search result").addOption(new Option2("--accept", "Mark as helpful").conflicts("reject")).addOption(new Option2("--reject", "Mark as unhelpful").conflicts("accept")).option("-m, --message <text>", "Feedback explanation").option("--json", "Output as JSON for piping").action(async (solutionId, options) => {
|
|
4453
4698
|
try {
|
|
4454
4699
|
const deps = await createContainer();
|
|
4455
4700
|
await feedbackAction(solutionId, options, deps);
|
|
@@ -5586,9 +5831,23 @@ async function withErrorHandling(operation, fn) {
|
|
|
5586
5831
|
try {
|
|
5587
5832
|
return await fn();
|
|
5588
5833
|
} catch (error2) {
|
|
5589
|
-
|
|
5590
|
-
|
|
5834
|
+
return errorResult(JSON.stringify(classify3(operation, error2)));
|
|
5835
|
+
}
|
|
5836
|
+
}
|
|
5837
|
+
function classify3(operation, error2) {
|
|
5838
|
+
if (error2 instanceof AuthenticationError) {
|
|
5839
|
+
return {
|
|
5840
|
+
error: error2.message,
|
|
5841
|
+
code: "UNAUTHENTICATED",
|
|
5842
|
+
retryable: false
|
|
5843
|
+
};
|
|
5591
5844
|
}
|
|
5845
|
+
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
5846
|
+
return {
|
|
5847
|
+
error: `Failed to ${operation}: ${message}`,
|
|
5848
|
+
code: "UNKNOWN",
|
|
5849
|
+
retryable: false
|
|
5850
|
+
};
|
|
5592
5851
|
}
|
|
5593
5852
|
|
|
5594
5853
|
// src/tools/feedback.ts
|
|
@@ -5597,24 +5856,9 @@ var schema = {
|
|
|
5597
5856
|
accepted: z.boolean().describe("True if the example was helpful/good, False if unhelpful/bad"),
|
|
5598
5857
|
feedback_text: z.string().optional().describe('Optional text explaining why (e.g., "This solved problem X" or "Example was outdated")')
|
|
5599
5858
|
};
|
|
5600
|
-
var DESCRIPTION = `Submit feedback on a GitHits
|
|
5601
|
-
|
|
5602
|
-
Use this tool after receiving a search result to indicate whether the example was helpful.
|
|
5603
|
-
This feedback helps improve GitHits' search quality.
|
|
5859
|
+
var DESCRIPTION = `Submit feedback on a GitHits example result.
|
|
5604
5860
|
|
|
5605
|
-
|
|
5606
|
-
- After using the search tool, provide feedback on whether the result was useful
|
|
5607
|
-
- Use \`accepted=true\` if the example solved your problem or was helpful, and you used it
|
|
5608
|
-
- Use \`accepted=false\` if the example was not relevant or unhelpful, and you did not use it
|
|
5609
|
-
- Optionally provide textual feedback explaining why
|
|
5610
|
-
|
|
5611
|
-
Args:
|
|
5612
|
-
solution_id: The solution ID from a previous search result (shown in the result)
|
|
5613
|
-
accepted: True if the example was helpful/good, False if unhelpful/bad
|
|
5614
|
-
feedback_text: Optional text explaining why (e.g., "This solved problem X" or "Example was outdated")
|
|
5615
|
-
|
|
5616
|
-
Returns:
|
|
5617
|
-
Confirmation message or error`;
|
|
5861
|
+
Call after \`get_example\` to record whether the returned example was used. \`accepted=true\` when it solved the problem or was useful; \`accepted=false\` when it was irrelevant or wrong. Use \`feedback_text\` to add a short reason. Feeds back into ranking quality.`;
|
|
5618
5862
|
function createFeedbackTool(service) {
|
|
5619
5863
|
return {
|
|
5620
5864
|
name: "feedback",
|
|
@@ -5641,8 +5885,7 @@ var schema2 = {
|
|
|
5641
5885
|
};
|
|
5642
5886
|
var DESCRIPTION2 = `Get verified, canonical code examples from global open source.
|
|
5643
5887
|
|
|
5644
|
-
|
|
5645
|
-
use the unified \`search\` tool instead.`;
|
|
5888
|
+
Returns JSON \`{result, solution_id?}\`. \`result\` is markdown — render or quote it directly. Pass \`solution_id\` to \`feedback\` after using or rejecting the example. For searching indexed dependency and repository code/docs, use the unified \`search\` tool instead.`;
|
|
5646
5889
|
function createGetExampleTool(service) {
|
|
5647
5890
|
return {
|
|
5648
5891
|
name: "get_example",
|
|
@@ -5650,13 +5893,15 @@ function createGetExampleTool(service) {
|
|
|
5650
5893
|
schema: schema2,
|
|
5651
5894
|
handler: async (args) => {
|
|
5652
5895
|
return withErrorHandling("get example", async () => {
|
|
5653
|
-
const
|
|
5896
|
+
const markdown = await service.search({
|
|
5654
5897
|
query: args.query,
|
|
5655
5898
|
language: args.language,
|
|
5656
5899
|
licenseMode: args.license_mode,
|
|
5657
5900
|
includeExplanation: false
|
|
5658
5901
|
});
|
|
5659
|
-
|
|
5902
|
+
const solutionId = extractSolutionId(markdown);
|
|
5903
|
+
const payload = solutionId ? { result: markdown, solution_id: solutionId } : { result: markdown };
|
|
5904
|
+
return textResult(JSON.stringify(payload));
|
|
5660
5905
|
});
|
|
5661
5906
|
}
|
|
5662
5907
|
};
|
|
@@ -5732,8 +5977,8 @@ var pathSelectorSchema = z4.object({
|
|
|
5732
5977
|
var schema3 = {
|
|
5733
5978
|
target: codeTargetSchema,
|
|
5734
5979
|
pattern: z4.string().describe(GREP_REPO_PATTERN_NOTE),
|
|
5735
|
-
path: z4.string().optional().describe("Exact file path to grep. Shares the same path vocabulary as `
|
|
5736
|
-
path_prefix: z4.string().optional().describe("Literal directory prefix to scope grep, matching `
|
|
5980
|
+
path: z4.string().optional().describe("Exact file path to grep. Shares the same path vocabulary as `code_read`."),
|
|
5981
|
+
path_prefix: z4.string().optional().describe("Literal directory prefix to scope grep, matching `code_files` / `search` naming."),
|
|
5737
5982
|
globs: z4.array(z4.string()).optional().describe("Repeatable glob scopes with real glob semantics (e.g. `src/**/*.ts`)."),
|
|
5738
5983
|
extensions: z4.array(z4.string()).optional().describe("Extensions to include, without a leading dot."),
|
|
5739
5984
|
pattern_type: z4.enum(["literal", "regex"]).optional(),
|
|
@@ -5749,10 +5994,10 @@ var schema3 = {
|
|
|
5749
5994
|
symbol_fields: z4.array(z4.enum(GREP_REPO_SYMBOL_FIELDS)).optional().describe(GREP_REPO_SYMBOL_FIELDS_NOTE),
|
|
5750
5995
|
wait_timeout_ms: z4.number().optional()
|
|
5751
5996
|
};
|
|
5752
|
-
var DESCRIPTION3 = "Deterministic text grep over indexed dependency and repository source files. " + "Use this when you know the text pattern you want; use `search` for discovery. " + "Whole-target grep is the default. Narrow with `path`, `path_prefix`, `globs`, or `extensions`. " + "Matches chain directly into `
|
|
5997
|
+
var DESCRIPTION3 = "Deterministic text grep over indexed dependency and repository source files. " + "Use this when you know the text pattern you want; use `search` for discovery. " + "Whole-target grep is the default. Narrow with `path`, `path_prefix`, `globs`, or `extensions`. " + "Matches chain directly into `code_read` via `matches[].filePath`.";
|
|
5753
5998
|
function createGrepRepoTool(service) {
|
|
5754
5999
|
return {
|
|
5755
|
-
name: "
|
|
6000
|
+
name: "code_grep",
|
|
5756
6001
|
description: DESCRIPTION3,
|
|
5757
6002
|
schema: schema3,
|
|
5758
6003
|
annotations: { readOnlyHint: true },
|
|
@@ -5826,10 +6071,10 @@ var schema4 = {
|
|
|
5826
6071
|
limit: z5.number().optional().describe("Max entries to return (1–1000, default 200). Out-of-range values return an `INVALID_ARGUMENT` envelope."),
|
|
5827
6072
|
wait_timeout_ms: z5.number().optional().describe("Max milliseconds to wait for indexing (0–60000, default 20000). On an `INDEXING` error envelope, retry with a longer timeout or pass a version from `details.availableVersions`.")
|
|
5828
6073
|
};
|
|
5829
|
-
var DESCRIPTION4 = "List files in an indexed dependency. Response: " + "`{total, hasMore, files: [{path, name, language, fileType, byteSize}], " + "resolution, indexedVersion}`. Address via `target.registry` + " + "`target.package_name` (package scope) or `target.repo_url` + " + "`target.git_ref` (repo scope), mutually exclusive. `path_prefix` " + "is a literal directory prefix — it does NOT accept globs " + "(`*.ts`) or extension filters. The returned `path` values feed " + "directly into `
|
|
6074
|
+
var DESCRIPTION4 = "List files in an indexed dependency. Response: " + "`{total, hasMore, files: [{path, name, language, fileType, byteSize}], " + "resolution, indexedVersion}`. Address via `target.registry` + " + "`target.package_name` (package scope) or `target.repo_url` + " + "`target.git_ref` (repo scope), mutually exclusive. `path_prefix` " + "is a literal directory prefix — it does NOT accept globs " + "(`*.ts`) or extension filters. The returned `path` values feed " + "directly into `code_read` and help scope `code_grep`. Returns an `INDEXING` " + "error envelope when the dependency is being indexed on-demand — " + "retry with a longer `wait_timeout_ms` or use a version from " + "`details.availableVersions`.";
|
|
5830
6075
|
function createListFilesTool(service) {
|
|
5831
6076
|
return {
|
|
5832
|
-
name: "
|
|
6077
|
+
name: "code_files",
|
|
5833
6078
|
description: DESCRIPTION4,
|
|
5834
6079
|
schema: schema4,
|
|
5835
6080
|
annotations: { readOnlyHint: true },
|
|
@@ -5868,8 +6113,53 @@ function createListFilesTool(service) {
|
|
|
5868
6113
|
}
|
|
5869
6114
|
};
|
|
5870
6115
|
}
|
|
5871
|
-
// src/tools/package-
|
|
6116
|
+
// src/tools/list-package-docs.ts
|
|
5872
6117
|
import { z as z6 } from "zod";
|
|
6118
|
+
var schema5 = {
|
|
6119
|
+
registry: z6.string().describe("Package registry. One of: npm, pypi, hex, crates, nuget, maven, zig, vcpkg, packagist."),
|
|
6120
|
+
package_name: z6.string().describe("Package name (scoped names ok: @types/node)."),
|
|
6121
|
+
version: z6.string().optional().describe("Optional package version."),
|
|
6122
|
+
limit: z6.number().optional().describe("Max pages to return (1-500, default 100)."),
|
|
6123
|
+
after: z6.string().optional().describe("Pagination cursor from a prior response.")
|
|
6124
|
+
};
|
|
6125
|
+
var DESCRIPTION5 = "List mixed package documentation pages from hosted docs and repository-backed docs. " + "Every entry includes a stable `pageId`, `sourceKind` (`crawled` or `repo`), and source URL; repo-backed entries also expose `repoUrl` / `gitRef` / `filePath` for exact file reads. " + "Pass a returned `pageId` to `docs_read`. Use this to browse before reading a full page.";
|
|
6126
|
+
function createListPackageDocsTool(service) {
|
|
6127
|
+
return {
|
|
6128
|
+
name: "docs_list",
|
|
6129
|
+
description: DESCRIPTION5,
|
|
6130
|
+
schema: schema5,
|
|
6131
|
+
annotations: { readOnlyHint: true },
|
|
6132
|
+
handler: async (args) => {
|
|
6133
|
+
try {
|
|
6134
|
+
const build = buildListPackageDocsParams({
|
|
6135
|
+
registry: args.registry,
|
|
6136
|
+
packageName: args.package_name,
|
|
6137
|
+
version: args.version,
|
|
6138
|
+
limit: args.limit,
|
|
6139
|
+
after: args.after
|
|
6140
|
+
});
|
|
6141
|
+
const result = await service.listPackageDocs(build.params);
|
|
6142
|
+
const payload = buildListPackageDocsSuccessPayload(result, {
|
|
6143
|
+
limitExplicit: build.limitExplicit,
|
|
6144
|
+
afterExplicit: build.afterExplicit,
|
|
6145
|
+
limit: build.params.limit,
|
|
6146
|
+
after: build.params.after
|
|
6147
|
+
});
|
|
6148
|
+
return textResult(JSON.stringify(payload));
|
|
6149
|
+
} catch (error2) {
|
|
6150
|
+
const mapped = mapPackageIntelligenceError(error2);
|
|
6151
|
+
return errorResult(JSON.stringify({
|
|
6152
|
+
error: mapped.message,
|
|
6153
|
+
code: mapped.code,
|
|
6154
|
+
retryable: mapped.retryable ?? false,
|
|
6155
|
+
...mapped.details ? { details: mapped.details } : {}
|
|
6156
|
+
}));
|
|
6157
|
+
}
|
|
6158
|
+
}
|
|
6159
|
+
};
|
|
6160
|
+
}
|
|
6161
|
+
// src/tools/package-changelog.ts
|
|
6162
|
+
import { z as z7 } from "zod";
|
|
5873
6163
|
|
|
5874
6164
|
// src/shared/package-changelog-request.ts
|
|
5875
6165
|
function buildPackageChangelogParams(input) {
|
|
@@ -6134,22 +6424,22 @@ function stripAnsi(text) {
|
|
|
6134
6424
|
}
|
|
6135
6425
|
|
|
6136
6426
|
// src/tools/package-changelog.ts
|
|
6137
|
-
var
|
|
6138
|
-
registry:
|
|
6139
|
-
package_name:
|
|
6140
|
-
repo_url:
|
|
6141
|
-
from_version:
|
|
6142
|
-
to_version:
|
|
6143
|
-
limit:
|
|
6144
|
-
git_ref:
|
|
6145
|
-
include_bodies:
|
|
6427
|
+
var schema6 = {
|
|
6428
|
+
registry: z7.string().optional().describe("Package registry (with `package_name`). Mutually exclusive with `repo_url`. Supported: npm, pypi, hex, crates, vcpkg, zig, nuget, maven, packagist."),
|
|
6429
|
+
package_name: z7.string().optional().describe("Package name (with `registry`). Scoped names ok (`@types/node`). Mutually exclusive with `repo_url`."),
|
|
6430
|
+
repo_url: z7.string().optional().describe("GitHub repository URL (https://…). Mutually exclusive with `registry` + `package_name`. Use when agents have a repo URL without a registry mapping."),
|
|
6431
|
+
from_version: z7.string().optional().describe("Start of version range. When set, the response returns every entry between `from_version` and `to_version` (or latest) with no count cap — range mode. Mutually exclusive with `limit`. Tag-style `v`-prefixed inputs are rejected."),
|
|
6432
|
+
to_version: z7.string().optional().describe("End of range / latest-mode cap. Works in either mode. Defaults to latest on the wire. Tag-style `v`-prefixed inputs are rejected."),
|
|
6433
|
+
limit: z7.number().optional().describe("Latest-mode cap on entry count (1–50, default 10). Rejected with `INVALID_ARGUMENT` when `from_version` is also set or when out of range."),
|
|
6434
|
+
git_ref: z7.string().optional().describe("Git branch or tag for CHANGELOG.md source (no effect on GitHub Releases or HexDocs). Defaults to the repository's default branch."),
|
|
6435
|
+
include_bodies: z7.boolean().optional().describe("When false, each entry in `entries.items[]` omits its `body` field. Default true. Set false when you only need the version / date / URL timeline — drops 10 KB+ per entry on large release notes.")
|
|
6146
6436
|
};
|
|
6147
|
-
var
|
|
6437
|
+
var DESCRIPTION6 = "Release notes for a package or GitHub repo, newest-first. Default " + "latest mode returns the ten most recent entries (`limit` 1–50). " + "With `from_version`, returns every entry in the " + "`[from_version, to_version]` range (range mode, no count cap). " + "Address via `registry` + `package_name` or `repo_url` (mutually " + 'exclusive). Response: `source` (`"releases"` / `"changelog_file"` ' + '/ `"hexdocs"`), `mode` (`"latest"` or `"range"`), ' + "`entries: { count, items }` with full markdown bodies. Set " + "`include_bodies: false` for a version / date / URL timeline only. " + "Supports npm, PyPI, Hex, Crates, vcpkg, Zig, NuGet, Maven, " + "Packagist; returns `NOT_FOUND` when a package has no changelog " + "source.";
|
|
6148
6438
|
function createPackageChangelogTool(service) {
|
|
6149
6439
|
return {
|
|
6150
|
-
name: "
|
|
6151
|
-
description:
|
|
6152
|
-
schema:
|
|
6440
|
+
name: "pkg_changelog",
|
|
6441
|
+
description: DESCRIPTION6,
|
|
6442
|
+
schema: schema6,
|
|
6153
6443
|
annotations: { readOnlyHint: true },
|
|
6154
6444
|
handler: async (args) => {
|
|
6155
6445
|
try {
|
|
@@ -6197,22 +6487,22 @@ function createPackageChangelogTool(service) {
|
|
|
6197
6487
|
};
|
|
6198
6488
|
}
|
|
6199
6489
|
// src/tools/package-dependencies.ts
|
|
6200
|
-
import { z as
|
|
6201
|
-
var
|
|
6202
|
-
registry:
|
|
6203
|
-
package_name:
|
|
6204
|
-
version:
|
|
6205
|
-
lifecycle:
|
|
6206
|
-
include_transitive:
|
|
6207
|
-
include_importers:
|
|
6208
|
-
max_depth:
|
|
6490
|
+
import { z as z8 } from "zod";
|
|
6491
|
+
var schema7 = {
|
|
6492
|
+
registry: z8.string().describe("Package registry. Dependency data is available on npm, pypi, hex, crates, vcpkg, and zig."),
|
|
6493
|
+
package_name: z8.string().describe("Package name (scoped names ok: @types/node)."),
|
|
6494
|
+
version: z8.string().optional().describe("Specific version to inspect. Defaults to latest when omitted. Tag-style inputs with a leading `v` (for example `v4.18.0`) are rejected — pass the canonical version (`4.18.0`)."),
|
|
6495
|
+
lifecycle: z8.union([z8.string(), z8.array(z8.string())]).optional().describe('Filter the `groups` block server-side by lifecycle phase. Accepts a single value, a comma-separated string (e.g. `"runtime,development"`), or an array of strings. Canonical values: `runtime`, `development`, `build`, `peer`, `optional`. Uppercase is tolerated. When the filter matches nothing the response still includes `groups: { items: [] }` so you can tell an empty-match apart from a registry that has no groups concept.'),
|
|
6496
|
+
include_transitive: z8.boolean().optional().describe("When true the response gains a `transitive` block with aggregate counts (`edges`, `uniquePackages`), the preprocessed `packages[]` list (each `{name, version}` — the complete install footprint), plus typed `conflicts[]` (`{name, requiredVersions}`) and `circularDependencies[]` (`{cycle: string[]}`) when the backend reported any. Off by default."),
|
|
6497
|
+
include_importers: z8.boolean().optional().describe("Requires `include_transitive: true`. When true, each entry in `transitive.packages[]` also carries an `importers` array — every upstream package that pulls it in, with that importer's own resolved version and the constraint it declared. Off by default because adding provenance roughly quadruples the envelope size on heavy graphs. Turn on when you need to trace why a specific transitive dep is present."),
|
|
6498
|
+
max_depth: z8.number().int().min(1).max(10).optional().describe("Cap the transitive traversal at this depth (1–10). Omit to get the backend's full graph. Requires `include_transitive: true` — passing `max_depth` without the transitive flag is rejected with `INVALID_ARGUMENT`.")
|
|
6209
6499
|
};
|
|
6210
|
-
var
|
|
6500
|
+
var DESCRIPTION7 = "Analyze a package's dependency graph. The response always includes " + "a `runtime` block listing the direct runtime dependencies as " + "`{name, version, constraint}` records (the backend resolves each " + "constraint to a concrete version for you). It also always includes " + "a structured `groups` block whenever the backend returns group " + "metadata — one group per lifecycle (`runtime`, `development`, " + "`build`, `peer`, `optional`) plus feature-conditional groups for " + "registries that have them (PyPI extras, Crates features). Use " + "`lifecycle` to filter `groups` server-side. Set " + "`include_transitive: true` to add a `transitive` block with the " + "full install footprint, conflict detection, and circular-" + "dependency flags; layer `include_importers: true` on top when you " + "also need per-package provenance. Supports npm, PyPI, Hex, Crates, " + "vcpkg, and Zig.";
|
|
6211
6501
|
function createPackageDependenciesTool(service) {
|
|
6212
6502
|
return {
|
|
6213
|
-
name: "
|
|
6214
|
-
description:
|
|
6215
|
-
schema:
|
|
6503
|
+
name: "pkg_deps",
|
|
6504
|
+
description: DESCRIPTION7,
|
|
6505
|
+
schema: schema7,
|
|
6216
6506
|
annotations: { readOnlyHint: true },
|
|
6217
6507
|
handler: async (args) => {
|
|
6218
6508
|
try {
|
|
@@ -6261,17 +6551,17 @@ function createPackageDependenciesTool(service) {
|
|
|
6261
6551
|
};
|
|
6262
6552
|
}
|
|
6263
6553
|
// src/tools/package-summary.ts
|
|
6264
|
-
import { z as
|
|
6265
|
-
var
|
|
6266
|
-
registry:
|
|
6267
|
-
package_name:
|
|
6554
|
+
import { z as z9 } from "zod";
|
|
6555
|
+
var schema8 = {
|
|
6556
|
+
registry: z9.string().describe("Package registry. One of: npm, pypi, hex, crates, nuget, maven, zig, vcpkg, packagist."),
|
|
6557
|
+
package_name: z9.string().describe("Package name (scoped names ok: @types/node).")
|
|
6268
6558
|
};
|
|
6269
|
-
var
|
|
6559
|
+
var DESCRIPTION8 = "Get a package overview — latest version, license, description, " + "repository, downloads, GitHub stars, install command, recent " + "changes, and a count of known vulnerabilities. Use before " + "recommending a package or to orient on what a dependency is. " + "Works across npm, PyPI, Hex, Crates, NuGet, Maven, Packagist, " + "vcpkg, and Zig. Always returns data for the latest published " + "version.";
|
|
6270
6560
|
function createPackageSummaryTool(service) {
|
|
6271
6561
|
return {
|
|
6272
|
-
name: "
|
|
6273
|
-
description:
|
|
6274
|
-
schema:
|
|
6562
|
+
name: "pkg_info",
|
|
6563
|
+
description: DESCRIPTION8,
|
|
6564
|
+
schema: schema8,
|
|
6275
6565
|
annotations: { readOnlyHint: true },
|
|
6276
6566
|
handler: async (args) => {
|
|
6277
6567
|
try {
|
|
@@ -6303,20 +6593,20 @@ function createPackageSummaryTool(service) {
|
|
|
6303
6593
|
};
|
|
6304
6594
|
}
|
|
6305
6595
|
// src/tools/package-vulnerabilities.ts
|
|
6306
|
-
import { z as
|
|
6307
|
-
var
|
|
6308
|
-
registry:
|
|
6309
|
-
package_name:
|
|
6310
|
-
version:
|
|
6311
|
-
min_severity:
|
|
6312
|
-
include_withdrawn:
|
|
6596
|
+
import { z as z10 } from "zod";
|
|
6597
|
+
var schema9 = {
|
|
6598
|
+
registry: z10.string().describe("Package registry. Vulnerability data available on npm, pypi, hex, and crates only."),
|
|
6599
|
+
package_name: z10.string().describe("Package name (scoped names ok: @types/node)."),
|
|
6600
|
+
version: z10.string().optional().describe("Specific version to check. Defaults to latest when omitted."),
|
|
6601
|
+
min_severity: z10.string().optional().describe("Only return advisories at or above this severity (`low`, `medium`, `high`, `critical`; uppercase tolerated). Omit to see all, including null-severity advisories."),
|
|
6602
|
+
include_withdrawn: z10.boolean().optional().describe("Include retracted advisories (default: false).")
|
|
6313
6603
|
};
|
|
6314
|
-
var
|
|
6604
|
+
var DESCRIPTION9 = "Check known vulnerabilities for a package on npm, PyPI, Hex, or " + "Crates (other registries are not yet supported for vulnerability " + "data). Returns a count summary, each advisory with OSV ID, " + "severity, affected ranges and fix versions, plus suggested " + "upgrade paths. Malicious-package advisories surface in a separate " + "bucket. Pass `version` to inspect a specific release; otherwise " + "the latest is checked. Use `min_severity` to filter to a threshold " + "(`low`, `medium`, `high`, `critical`) and `include_withdrawn` to " + "also see retracted advisories.";
|
|
6315
6605
|
function createPackageVulnerabilitiesTool(service) {
|
|
6316
6606
|
return {
|
|
6317
|
-
name: "
|
|
6318
|
-
description:
|
|
6319
|
-
schema:
|
|
6607
|
+
name: "pkg_vulns",
|
|
6608
|
+
description: DESCRIPTION9,
|
|
6609
|
+
schema: schema9,
|
|
6320
6610
|
annotations: { readOnlyHint: true },
|
|
6321
6611
|
handler: async (args) => {
|
|
6322
6612
|
try {
|
|
@@ -6353,20 +6643,20 @@ function createPackageVulnerabilitiesTool(service) {
|
|
|
6353
6643
|
};
|
|
6354
6644
|
}
|
|
6355
6645
|
// src/tools/read-file.ts
|
|
6356
|
-
import { z as
|
|
6357
|
-
var
|
|
6646
|
+
import { z as z11 } from "zod";
|
|
6647
|
+
var schema10 = {
|
|
6358
6648
|
target: codeTargetSchema,
|
|
6359
|
-
path:
|
|
6360
|
-
start_line:
|
|
6361
|
-
end_line:
|
|
6362
|
-
wait_timeout_ms:
|
|
6649
|
+
path: z11.string().describe("Path to the file. Package addressing: package-relative. Repo addressing: repo-relative. This is the same `path` key that `code_files` emits for each entry, so chaining needs no renaming."),
|
|
6650
|
+
start_line: z11.number().optional().describe("Starting line (1-indexed). Omit for the full file from line 1."),
|
|
6651
|
+
end_line: z11.number().optional().describe("Ending line (inclusive). Omit for end of file. Must be ≥ `start_line` when both are set."),
|
|
6652
|
+
wait_timeout_ms: z11.number().optional().describe("Max milliseconds to wait for indexing (0–60000, default 20000). On an `INDEXING` error envelope, retry with a longer timeout or pass a version from `details.availableVersions`.")
|
|
6363
6653
|
};
|
|
6364
|
-
var
|
|
6654
|
+
var DESCRIPTION10 = "Read a file from an indexed dependency. Default returns the full " + "file; use `start_line` / `end_line` for a bounded range. Response: " + "`{path, language, totalLines, startLine, endLine, content, " + "isBinary}`. Binary files set `isBinary: true` and omit `content` — " + "agents branch on the flag rather than checking null. Pass the same " + "`path` emitted by `code_files`. Address via " + "`target.registry` + `target.package_name` (package scope) or " + "`target.repo_url` + `target.git_ref` (repo scope), mutually " + "exclusive. On `INDEXING` retry with a longer `wait_timeout_ms`. " + "When the path doesn't resolve the response is a `NOT_FOUND` (or " + "`FILE_NOT_FOUND`) error — call `code_files` to discover the " + "actual paths.";
|
|
6365
6655
|
function createReadFileTool(service) {
|
|
6366
6656
|
return {
|
|
6367
|
-
name: "
|
|
6368
|
-
description:
|
|
6369
|
-
schema:
|
|
6657
|
+
name: "code_read",
|
|
6658
|
+
description: DESCRIPTION10,
|
|
6659
|
+
schema: schema10,
|
|
6370
6660
|
annotations: { readOnlyHint: true },
|
|
6371
6661
|
handler: async (args) => {
|
|
6372
6662
|
const target = resolveCodeTarget(args.target);
|
|
@@ -6401,15 +6691,48 @@ function createReadFileTool(service) {
|
|
|
6401
6691
|
}
|
|
6402
6692
|
};
|
|
6403
6693
|
}
|
|
6694
|
+
// src/tools/read-package-doc.ts
|
|
6695
|
+
import { z as z12 } from "zod";
|
|
6696
|
+
var schema11 = {
|
|
6697
|
+
page_id: z12.string().describe("Documentation page ID from `docs_list` or `search` results. Pass through unchanged; repo-backed IDs are snapshot-pinned."),
|
|
6698
|
+
start_line: z12.number().optional().describe("Starting line (1-indexed). Omit for the full page. Use with `end_line` to bound how much content the tool returns when a page is large."),
|
|
6699
|
+
end_line: z12.number().optional().describe("Ending line (inclusive). Omit for end of page. Must be ≥ `start_line` when both are set.")
|
|
6700
|
+
};
|
|
6701
|
+
var DESCRIPTION11 = "Read a documentation page by page ID. Works for both hosted/crawled docs and repository-backed docs. " + "Pass `start_line` / `end_line` to fetch only a slice when a page is too long — response carries `totalLines` so you can target the next slice. " + "Repo-backed results additionally include exact file follow-up metadata for `code_read`.";
|
|
6702
|
+
function createReadPackageDocTool(service) {
|
|
6703
|
+
return {
|
|
6704
|
+
name: "docs_read",
|
|
6705
|
+
description: DESCRIPTION11,
|
|
6706
|
+
schema: schema11,
|
|
6707
|
+
annotations: { readOnlyHint: true },
|
|
6708
|
+
handler: async (args) => {
|
|
6709
|
+
try {
|
|
6710
|
+
const build = buildReadPackageDocParams({ pageId: args.page_id });
|
|
6711
|
+
const result = await service.readPackageDoc(build.params);
|
|
6712
|
+
const range = args.start_line !== undefined || args.end_line !== undefined ? { startLine: args.start_line, endLine: args.end_line } : undefined;
|
|
6713
|
+
const payload = buildReadPackageDocSuccessPayload(result, build.params.pageId, range);
|
|
6714
|
+
return textResult(JSON.stringify(payload));
|
|
6715
|
+
} catch (error2) {
|
|
6716
|
+
const mapped = mapPackageIntelligenceError(error2);
|
|
6717
|
+
return errorResult(JSON.stringify({
|
|
6718
|
+
error: mapped.message,
|
|
6719
|
+
code: mapped.code,
|
|
6720
|
+
retryable: mapped.retryable ?? false,
|
|
6721
|
+
...mapped.details ? { details: mapped.details } : {}
|
|
6722
|
+
}));
|
|
6723
|
+
}
|
|
6724
|
+
}
|
|
6725
|
+
};
|
|
6726
|
+
}
|
|
6404
6727
|
// src/tools/search.ts
|
|
6405
|
-
import { z as
|
|
6406
|
-
var
|
|
6407
|
-
query:
|
|
6728
|
+
import { z as z13 } from "zod";
|
|
6729
|
+
var schema12 = {
|
|
6730
|
+
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."),
|
|
6408
6731
|
target: codeTargetSchema.optional(),
|
|
6409
|
-
targets:
|
|
6410
|
-
sources:
|
|
6411
|
-
category:
|
|
6412
|
-
kind:
|
|
6732
|
+
targets: z13.array(codeTargetSchema).max(20).optional(),
|
|
6733
|
+
sources: z13.array(z13.enum(["docs", "code", "symbol"])).optional().describe("Optional source selection. Omit for backend AUTO."),
|
|
6734
|
+
category: z13.enum(["callable", "type", "module", "data", "documentation"]).optional(),
|
|
6735
|
+
kind: z13.enum([
|
|
6413
6736
|
"function",
|
|
6414
6737
|
"method",
|
|
6415
6738
|
"constructor",
|
|
@@ -6439,8 +6762,8 @@ var schema10 = {
|
|
|
6439
6762
|
"constant",
|
|
6440
6763
|
"doc_section"
|
|
6441
6764
|
]).optional(),
|
|
6442
|
-
path_prefix:
|
|
6443
|
-
file_intent:
|
|
6765
|
+
path_prefix: z13.string().optional(),
|
|
6766
|
+
file_intent: z13.enum([
|
|
6444
6767
|
"production",
|
|
6445
6768
|
"test",
|
|
6446
6769
|
"benchmark",
|
|
@@ -6449,21 +6772,21 @@ var schema10 = {
|
|
|
6449
6772
|
"fixture",
|
|
6450
6773
|
"build",
|
|
6451
6774
|
"vendor"
|
|
6452
|
-
]).optional().describe("Optional file-intent filter.
|
|
6453
|
-
public_only:
|
|
6454
|
-
name:
|
|
6455
|
-
language:
|
|
6456
|
-
allow_partial_results:
|
|
6457
|
-
limit:
|
|
6458
|
-
offset:
|
|
6459
|
-
wait_timeout_ms:
|
|
6775
|
+
]).optional().describe("Optional file-intent filter. Omit it to search across all intents; some sources may ignore this filter and report that in sourceStatus."),
|
|
6776
|
+
public_only: z13.boolean().optional(),
|
|
6777
|
+
name: z13.string().optional(),
|
|
6778
|
+
language: z13.string().optional(),
|
|
6779
|
+
allow_partial_results: z13.boolean().optional().describe("Default false waits for all sources; if the wait window expires, returns only searchRef/progress. When true, includes hits from sources that finished so far and still returns searchRef for continuation. Partial payloads support normal pagination via nextOffset."),
|
|
6780
|
+
limit: z13.coerce.number().int().min(1).max(100).optional(),
|
|
6781
|
+
offset: z13.coerce.number().int().min(0).optional(),
|
|
6782
|
+
wait_timeout_ms: z13.coerce.number().int().min(0).max(60000).optional()
|
|
6460
6783
|
};
|
|
6461
|
-
var
|
|
6784
|
+
var DESCRIPTION12 = "Search indexed dependency and repository code, docs, and explicit symbols. " + "Provide either `target` for one target or `targets` for many; omit `sources` to use backend AUTO. " + "The query field uses GitHits discovery syntax (AND/OR/parens/qualifiers; see the parameter description). " + "Structured parameters combine with that query using AND semantics. " + "Results are complete by default — if indexing is still running, the response carries a `searchRef` and no hits; pass it to `search_status` to follow up. " + "Set `allow_partial_results: true` to opt into hits from sources that finished while others continue indexing. " + "Each hit's `type` tells you the follow-up tool: `documentation_page` and `repository_doc` → `docs_read` with `locator.pageId`; `repository_code` and `repository_symbol` → `code_read` with `locator.filePath` (and `locator.startLine`/`endLine` when present).";
|
|
6462
6785
|
function createSearchTool(service) {
|
|
6463
6786
|
return {
|
|
6464
6787
|
name: "search",
|
|
6465
|
-
description:
|
|
6466
|
-
schema:
|
|
6788
|
+
description: DESCRIPTION12,
|
|
6789
|
+
schema: schema12,
|
|
6467
6790
|
annotations: { readOnlyHint: true },
|
|
6468
6791
|
handler: async (args) => {
|
|
6469
6792
|
try {
|
|
@@ -6480,10 +6803,10 @@ function createSearchTool(service) {
|
|
|
6480
6803
|
targets: resolvedTargets?.filter(isResolvedCodeTarget),
|
|
6481
6804
|
query: args.query,
|
|
6482
6805
|
sources: args.sources?.map((entry) => entry.toUpperCase()),
|
|
6483
|
-
kind:
|
|
6806
|
+
kind: toSymbolKind(args.kind),
|
|
6484
6807
|
category: toSymbolCategory(args.category),
|
|
6485
6808
|
pathPrefix: args.path_prefix,
|
|
6486
|
-
fileIntent:
|
|
6809
|
+
fileIntent: toFileIntent(args.file_intent),
|
|
6487
6810
|
publicOnly: args.public_only,
|
|
6488
6811
|
name: args.name,
|
|
6489
6812
|
language: args.language,
|
|
@@ -6493,7 +6816,7 @@ function createSearchTool(service) {
|
|
|
6493
6816
|
waitTimeoutMs: args.wait_timeout_ms
|
|
6494
6817
|
});
|
|
6495
6818
|
const outcome = await service.search(built.params);
|
|
6496
|
-
const payload = buildUnifiedSearchSuccessPayload(built.params, built.rawQuery, built.compiledQuery,
|
|
6819
|
+
const payload = buildUnifiedSearchSuccessPayload(built.params, built.rawQuery, built.compiledQuery, outcome);
|
|
6497
6820
|
return textResult(JSON.stringify(payload));
|
|
6498
6821
|
} catch (error2) {
|
|
6499
6822
|
return errorResult(JSON.stringify(buildUnifiedSearchErrorPayload(error2)));
|
|
@@ -6505,45 +6828,36 @@ function isResolvedCodeTarget(target) {
|
|
|
6505
6828
|
return !("content" in target);
|
|
6506
6829
|
}
|
|
6507
6830
|
// src/tools/search-language.ts
|
|
6508
|
-
import { z as
|
|
6509
|
-
var
|
|
6510
|
-
query:
|
|
6831
|
+
import { z as z14 } from "zod";
|
|
6832
|
+
var schema13 = {
|
|
6833
|
+
query: z14.string().min(1).describe('Language name or partial name to search for (e.g., "python", "type", "java")')
|
|
6511
6834
|
};
|
|
6512
|
-
var
|
|
6513
|
-
|
|
6514
|
-
Use this tool to find the correct language name before calling the search tool.
|
|
6515
|
-
Returns up to 5 matching languages.
|
|
6516
|
-
|
|
6517
|
-
Args:
|
|
6518
|
-
query: Language name or partial name to search for (e.g., "python", "type", "java")
|
|
6519
|
-
|
|
6520
|
-
Returns:
|
|
6521
|
-
List of matching languages with name and display_name`;
|
|
6835
|
+
var DESCRIPTION13 = `Find the correct language name for \`get_example\` when it is uncertain. Returns up to 5 matching languages by name, display name, or alias.`;
|
|
6522
6836
|
function createSearchLanguageTool(service) {
|
|
6523
6837
|
return {
|
|
6524
6838
|
name: "search_language",
|
|
6525
|
-
description:
|
|
6526
|
-
schema:
|
|
6839
|
+
description: DESCRIPTION13,
|
|
6840
|
+
schema: schema13,
|
|
6527
6841
|
handler: async (args) => {
|
|
6528
6842
|
return withErrorHandling("search languages", async () => {
|
|
6529
6843
|
const allLanguages = await service.getLanguages();
|
|
6530
6844
|
const result = filterLanguages(allLanguages, args.query);
|
|
6531
|
-
return textResult(JSON.stringify(result
|
|
6845
|
+
return textResult(JSON.stringify(result));
|
|
6532
6846
|
});
|
|
6533
6847
|
}
|
|
6534
6848
|
};
|
|
6535
6849
|
}
|
|
6536
6850
|
// src/tools/search-status.ts
|
|
6537
|
-
import { z as
|
|
6538
|
-
var
|
|
6539
|
-
search_ref:
|
|
6851
|
+
import { z as z15 } from "zod";
|
|
6852
|
+
var schema14 = {
|
|
6853
|
+
search_ref: z15.string().min(1).describe("Search reference returned by search.")
|
|
6540
6854
|
};
|
|
6541
|
-
var
|
|
6855
|
+
var DESCRIPTION14 = "Check progress, fetch partial hits when the original request used allow_partial_results: true, or fetch final results for a prior unified search. " + "Pass the search_ref returned by `search` when the original request did not complete within the wait window.";
|
|
6542
6856
|
function createSearchStatusTool(service) {
|
|
6543
6857
|
return {
|
|
6544
6858
|
name: "search_status",
|
|
6545
|
-
description:
|
|
6546
|
-
schema:
|
|
6859
|
+
description: DESCRIPTION14,
|
|
6860
|
+
schema: schema14,
|
|
6547
6861
|
annotations: { readOnlyHint: true },
|
|
6548
6862
|
handler: async (args) => {
|
|
6549
6863
|
try {
|
|
@@ -6556,60 +6870,6 @@ function createSearchStatusTool(service) {
|
|
|
6556
6870
|
}
|
|
6557
6871
|
};
|
|
6558
6872
|
}
|
|
6559
|
-
// src/tools/search-symbols.ts
|
|
6560
|
-
import { z as z14 } from "zod";
|
|
6561
|
-
var schema13 = {
|
|
6562
|
-
target: codeTargetSchema,
|
|
6563
|
-
query: z14.string().max(500).optional().describe("Search keywords - exact source tokens, not natural language. Required if keywords not provided."),
|
|
6564
|
-
keywords: z14.array(z14.string()).max(20).optional().describe("Search keywords (max 20). Combined using match_mode. Can be used alone or together with query."),
|
|
6565
|
-
match_mode: z14.enum(["or", "and"]).optional().describe("How to combine keywords: or (any match) or and (all match)"),
|
|
6566
|
-
category: z14.enum(["callable", "type", "module", "data", "documentation"]).optional().describe("Broad symbol category filter — the preferred surface for filtering. callable (function/method/constructor/getter/setter/operator), type (class/interface/trait/struct/enum/record/protocol/extension/etc.), module (module/namespace/package/object), data (field/property/event/constant), documentation (doc_section)."),
|
|
6567
|
-
kind: z14.enum([
|
|
6568
|
-
"function",
|
|
6569
|
-
"method",
|
|
6570
|
-
"constructor",
|
|
6571
|
-
"getter",
|
|
6572
|
-
"setter",
|
|
6573
|
-
"operator",
|
|
6574
|
-
"class",
|
|
6575
|
-
"interface",
|
|
6576
|
-
"trait",
|
|
6577
|
-
"struct",
|
|
6578
|
-
"enum",
|
|
6579
|
-
"record",
|
|
6580
|
-
"protocol",
|
|
6581
|
-
"extension",
|
|
6582
|
-
"delegate",
|
|
6583
|
-
"mixin",
|
|
6584
|
-
"actor",
|
|
6585
|
-
"annotation",
|
|
6586
|
-
"type",
|
|
6587
|
-
"module",
|
|
6588
|
-
"namespace",
|
|
6589
|
-
"package",
|
|
6590
|
-
"object",
|
|
6591
|
-
"field",
|
|
6592
|
-
"property",
|
|
6593
|
-
"event",
|
|
6594
|
-
"constant",
|
|
6595
|
-
"doc_section"
|
|
6596
|
-
]).optional().describe("Precise symbol kind filter. Prefer `category` for broad filtering; use `kind` only when you need a specific construct (e.g. trait vs interface)."),
|
|
6597
|
-
file_path: z14.string().optional().describe("Filter results to files whose path starts with this value (e.g., 'src/' for a directory)"),
|
|
6598
|
-
limit: z14.coerce.number().int().min(1).max(50).optional().describe("Max results to return (max 50)"),
|
|
6599
|
-
file_intent: z14.enum([
|
|
6600
|
-
"production",
|
|
6601
|
-
"test",
|
|
6602
|
-
"benchmark",
|
|
6603
|
-
"example",
|
|
6604
|
-
"generated",
|
|
6605
|
-
"fixture",
|
|
6606
|
-
"build",
|
|
6607
|
-
"vendor",
|
|
6608
|
-
"all"
|
|
6609
|
-
]).optional().describe("File intent filter. Defaults to 'production' so top results are production source. Pass 'all' to include tests, benchmarks, examples, and other non-production files."),
|
|
6610
|
-
wait_timeout_ms: z14.coerce.number().int().min(0).max(60000).optional().describe("Max milliseconds to wait for indexing before returning. Defaults to 20000 (20 seconds) to cover typical indexing (p50 ~11s). On an INDEXING response, retry with wait_timeout_ms up to 60000 to block until ready.")
|
|
6611
|
-
};
|
|
6612
|
-
var DESCRIPTION13 = "Search a dependency's source code by exact-token matches. Use for symbol lookup, not natural-language questions. " + 'Prefer unified `search` with `sources:["symbol"]` for new symbol-shaped workflows; use `search_symbols` when you specifically need this dedicated legacy contract. ' + "Package scope: pass target.registry + target.package_name. Repo scope: pass target.repo_url + target.git_ref. " + "`file_intent` defaults to 'production' so top results are production source; pass 'all' to include tests, examples, benchmarks. " + "`query` and `keywords` can combine; `match_mode` controls AND vs OR across keywords. " + "Filter by `category` (broad: callable/type/module/data/documentation — preferred) or `kind` (precise construct like trait/record/namespace). " + "Prefer `file_path` to scope to a directory (e.g., 'src/'). " + "Responses include each match's source code, line range, and unified `kind`/`category` classification. " + "If the response is an INDEXING error, the package is being indexed on-demand — retry the same call with `wait_timeout_ms: 60000` to block until ready.";
|
|
6613
6873
|
// src/commands/mcp-instructions.ts
|
|
6614
6874
|
var CORE_BLOCK = `GitHits surfaces verified, canonical code examples from global open source. Use it when you're stuck, the user is frustrated by repeated failed attempts, you need up-to-date API usage, or the user mentions GitHits.
|
|
6615
6875
|
|
|
@@ -6617,18 +6877,20 @@ Workflow: call \`search_language\` first if the language name is uncertain → c
|
|
|
6617
6877
|
var PACKAGE_TOOLS_PREAMBLE = `Package tools work with third-party dependency source plus registry metadata. Use them when a stack trace points into a dependency, you need to verify how a library actually works, or you're evaluating whether to add or upgrade a package.
|
|
6618
6878
|
|
|
6619
6879
|
Package spec: \`registry:name[@version]\`.`;
|
|
6620
|
-
var
|
|
6621
|
-
var
|
|
6622
|
-
var
|
|
6623
|
-
var
|
|
6624
|
-
var
|
|
6880
|
+
var PKG_INFO_BULLET = "- `pkg_info` — instant package overview: latest version, license, downloads, quickstart, and active advisory count.";
|
|
6881
|
+
var DOCS_LIST_BULLET = "- `docs_list` — browse mixed package documentation pages from hosted docs and repository-backed docs. Each entry includes a stable pageId, source kind, source URL, and for repo docs exact file follow-up metadata.";
|
|
6882
|
+
var DOCS_READ_BULLET = "- `docs_read` — read a documentation page by pageId. Works for both hosted docs and repo-backed docs.";
|
|
6883
|
+
var PKG_VULNS_BULLET = "- `pkg_vulns` — known CVE / OSV advisories for npm, PyPI, Hex, or Crates packages (optionally pinned to `@version`). Malicious-package advisories surface in a disjoint `malware` bucket; filter with `min_severity` or include retracted advisories with `include_withdrawn`.";
|
|
6884
|
+
var PKG_DEPS_BULLET = "- `pkg_deps` — direct runtime deps plus, when the backend has them, dev / peer / optional / feature groups. Pass `lifecycle` to filter groups server-side, `include_transitive` for the full graph, and `include_importers` when you also need per-package provenance. Supports npm, PyPI, Hex, Crates, vcpkg, and Zig.";
|
|
6885
|
+
var PKG_CHANGELOG_BULLET = "- `pkg_changelog` — release notes for a package or GitHub repo, newest-first. Default latest mode returns the 10 most recent entries with full markdown bodies; `from_version` switches to range mode between two versions. Addressable via `registry` + `package_name` or `repo_url`. Set `include_bodies: false` for a version / date / URL timeline when bodies aren't needed.";
|
|
6886
|
+
var SEARCH_BULLET = "- `search` — unified search across indexed dependency code, docs, and explicit symbols. Structured fields are the primary UX; omit `sources` for AUTO. Returns only trustworthy complete results by default; opt into partial hits with `allow_partial_results: true`. If indexing is still in progress, the response carries a `searchRef`.";
|
|
6625
6887
|
var SEARCH_STATUS_BULLET = "- `search_status` — follow up a prior unified search by `searchRef`. Use it after `search` returns incomplete state to check progress, fetch partial hits when the original request used `allow_partial_results: true`, or fetch final results.";
|
|
6626
|
-
var
|
|
6627
|
-
var
|
|
6628
|
-
var
|
|
6629
|
-
var SEARCH_VS_SYMBOLS_TIP = 'Prefer `get_example` for canonical example retrieval; prefer unified `search` for indexed dependency and repository discovery; use `sources:["symbol"]` when you want symbol-shaped results. Use `
|
|
6888
|
+
var CODE_FILES_BULLET = "- `code_files` — discover what files a dependency ships. Use `path_prefix` to scope to a subdirectory; the response includes each file's language, type, and byte size. Returned `path` values feed directly into `code_read` and help scope `code_grep`.";
|
|
6889
|
+
var CODE_READ_BULLET = "- `code_read` — fetch a file's contents from a dependency. Pass the same `path` emitted by `code_files`. Default returns the full file; pass `start_line` / `end_line` for a bounded range. Binary files set `isBinary: true` and omit `content` — branch on the flag. A `FILE_NOT_FOUND` (or `NOT_FOUND`) response is the signal to call `code_files` for the actual path.";
|
|
6890
|
+
var CODE_GREP_BULLET = "- `code_grep` — deterministic text grep over indexed source files. Use it when you know the exact text or regex to match; use `search` for discovery. Whole-target grep is the default; narrow with `path`, `path_prefix`, `globs`, or `extensions`. Returned `matches[].filePath` feeds directly into `code_read`.";
|
|
6891
|
+
var SEARCH_VS_SYMBOLS_TIP = 'Prefer `get_example` for canonical example retrieval; prefer unified `search` for indexed dependency and repository discovery; use `sources:["symbol"]` when you want symbol-shaped results. Use `code_grep` for deterministic text matching and `code_read` for full-file inspection.';
|
|
6630
6892
|
function isPackageToolsCapabilityOpen(deps) {
|
|
6631
|
-
return deps.codeNavigationCapability === "enabled";
|
|
6893
|
+
return deps.codeNavigationCliOverrideEnabled || deps.codeNavigationCapability === "enabled" || deps.codeNavigationCapability === "unknown" && deps.envApiToken !== undefined;
|
|
6632
6894
|
}
|
|
6633
6895
|
function buildMcpInstructions(deps) {
|
|
6634
6896
|
const sections = [CORE_BLOCK];
|
|
@@ -6639,17 +6901,19 @@ function buildMcpInstructions(deps) {
|
|
|
6639
6901
|
}
|
|
6640
6902
|
const bullets = [];
|
|
6641
6903
|
if (deps.packageIntelligenceService) {
|
|
6642
|
-
bullets.push(
|
|
6643
|
-
bullets.push(
|
|
6644
|
-
bullets.push(
|
|
6645
|
-
bullets.push(
|
|
6904
|
+
bullets.push(DOCS_LIST_BULLET);
|
|
6905
|
+
bullets.push(DOCS_READ_BULLET);
|
|
6906
|
+
bullets.push(PKG_INFO_BULLET);
|
|
6907
|
+
bullets.push(PKG_VULNS_BULLET);
|
|
6908
|
+
bullets.push(PKG_DEPS_BULLET);
|
|
6909
|
+
bullets.push(PKG_CHANGELOG_BULLET);
|
|
6646
6910
|
}
|
|
6647
6911
|
if (deps.codeNavigationService) {
|
|
6648
6912
|
bullets.push(SEARCH_BULLET);
|
|
6649
6913
|
bullets.push(SEARCH_STATUS_BULLET);
|
|
6650
|
-
bullets.push(
|
|
6651
|
-
bullets.push(
|
|
6652
|
-
bullets.push(
|
|
6914
|
+
bullets.push(CODE_FILES_BULLET);
|
|
6915
|
+
bullets.push(CODE_READ_BULLET);
|
|
6916
|
+
bullets.push(CODE_GREP_BULLET);
|
|
6653
6917
|
}
|
|
6654
6918
|
if (bullets.length === 0) {
|
|
6655
6919
|
return sections.join(`
|
|
@@ -6685,6 +6949,8 @@ function getMcpToolDefinitions(deps) {
|
|
|
6685
6949
|
tools.push(createGrepRepoTool(deps.codeNavigationService));
|
|
6686
6950
|
}
|
|
6687
6951
|
if (gateOpen && deps.packageIntelligenceService) {
|
|
6952
|
+
tools.push(createListPackageDocsTool(deps.packageIntelligenceService));
|
|
6953
|
+
tools.push(createReadPackageDocTool(deps.packageIntelligenceService));
|
|
6688
6954
|
tools.push(createPackageSummaryTool(deps.packageIntelligenceService));
|
|
6689
6955
|
tools.push(createPackageVulnerabilitiesTool(deps.packageIntelligenceService));
|
|
6690
6956
|
tools.push(createPackageDependenciesTool(deps.packageIntelligenceService));
|
|
@@ -7169,16 +7435,8 @@ function registerPkgVulnsCommand(pkgCommand) {
|
|
|
7169
7435
|
|
|
7170
7436
|
// src/commands/pkg/index.ts
|
|
7171
7437
|
async function registerPkgCommandGroup(program, options = {}) {
|
|
7172
|
-
const
|
|
7173
|
-
if (!
|
|
7174
|
-
return;
|
|
7175
|
-
}
|
|
7176
|
-
const overrideEnabled = options.overrideEnabled ?? isCodeNavigationCliOverrideEnabled();
|
|
7177
|
-
const registrationState = options.capability !== undefined || options.expiredStoredAuth !== undefined ? {
|
|
7178
|
-
capability: options.capability ?? "unknown",
|
|
7179
|
-
expiredStoredAuth: options.expiredStoredAuth ?? false
|
|
7180
|
-
} : await resolveStartupCodeNavigationRegistrationState();
|
|
7181
|
-
if (!overrideEnabled && registrationState.capability !== "enabled" && !registrationState.expiredStoredAuth) {
|
|
7438
|
+
const registration = await resolveGatedCommandGroupRegistrationState(options);
|
|
7439
|
+
if (!registration.shouldRegister) {
|
|
7182
7440
|
return;
|
|
7183
7441
|
}
|
|
7184
7442
|
const pkgCommand = program.command("pkg").summary("Package metadata: info, vulnerabilities, dependencies, changelog").description("Inspect package metadata from npm, PyPI, Hex, Crates, NuGet, Maven, Packagist, vcpkg, and Zig: overviews, advisories, dependency graphs, and changelogs. For source-level operations inside a dependency, use `githits code`.");
|
|
@@ -7187,56 +7445,6 @@ async function registerPkgCommandGroup(program, options = {}) {
|
|
|
7187
7445
|
registerPkgDepsCommand(pkgCommand);
|
|
7188
7446
|
registerPkgChangelogCommand(pkgCommand);
|
|
7189
7447
|
}
|
|
7190
|
-
// src/commands/example.ts
|
|
7191
|
-
import { Option as Option2 } from "commander";
|
|
7192
|
-
async function exampleAction(query, options, deps) {
|
|
7193
|
-
requireAuth(deps);
|
|
7194
|
-
try {
|
|
7195
|
-
const result = await deps.githitsService.search({
|
|
7196
|
-
query,
|
|
7197
|
-
language: options.lang,
|
|
7198
|
-
licenseMode: options.license,
|
|
7199
|
-
includeExplanation: options.explain
|
|
7200
|
-
});
|
|
7201
|
-
if (options.json) {
|
|
7202
|
-
console.log(JSON.stringify({ result }));
|
|
7203
|
-
} else {
|
|
7204
|
-
console.log(result);
|
|
7205
|
-
}
|
|
7206
|
-
} catch (error2) {
|
|
7207
|
-
console.error(`Failed to get example: ${error2 instanceof Error ? error2.message : error2}`);
|
|
7208
|
-
process.exit(1);
|
|
7209
|
-
}
|
|
7210
|
-
}
|
|
7211
|
-
var EXAMPLE_DESCRIPTION = `Get verified, canonical code examples from global open source.
|
|
7212
|
-
|
|
7213
|
-
This is the GitHits example-search surface. For dependency/package/repo source search,
|
|
7214
|
-
use
|
|
7215
|
-
githits search
|
|
7216
|
-
|
|
7217
|
-
instead.
|
|
7218
|
-
|
|
7219
|
-
Examples:
|
|
7220
|
-
githits example "how to use express middleware" --lang javascript
|
|
7221
|
-
githits example "async file reading" -l python --license yolo
|
|
7222
|
-
githits example "react hooks patterns" -l typescript --explain
|
|
7223
|
-
githits example "react hooks patterns" -l typescript --json`;
|
|
7224
|
-
function registerExampleCommand(program) {
|
|
7225
|
-
program.command("example").summary("Get code examples from global open source").description(EXAMPLE_DESCRIPTION).argument("<query>", "Natural language example-search query").requiredOption("-l, --lang <language>", "Programming language").addOption(new Option2("--license <mode>", "License filter mode").choices(["strict", "yolo", "custom"]).default(undefined)).option("--explain", "Include AI-generated explanation").option("--json", "Output as JSON for piping").action(async (query, options) => {
|
|
7226
|
-
try {
|
|
7227
|
-
const deps = await loadContainer();
|
|
7228
|
-
await exampleAction(query, options, deps);
|
|
7229
|
-
} catch (error2) {
|
|
7230
|
-
if (error2 instanceof AuthRequiredError)
|
|
7231
|
-
process.exit(1);
|
|
7232
|
-
throw error2;
|
|
7233
|
-
}
|
|
7234
|
-
});
|
|
7235
|
-
}
|
|
7236
|
-
async function loadContainer() {
|
|
7237
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-cdx2gnrs.js");
|
|
7238
|
-
return createContainer2();
|
|
7239
|
-
}
|
|
7240
7448
|
// src/commands/search.ts
|
|
7241
7449
|
import { Option as Option3 } from "commander";
|
|
7242
7450
|
async function searchAction(query, options, deps) {
|
|
@@ -7247,20 +7455,20 @@ async function searchAction(query, options, deps) {
|
|
|
7247
7455
|
targets: parseTargetSpecs(options.in),
|
|
7248
7456
|
query,
|
|
7249
7457
|
sources: parseSources(options.source),
|
|
7250
|
-
kind:
|
|
7458
|
+
kind: toSymbolKind(options.kind),
|
|
7251
7459
|
category: toSymbolCategory(options.category),
|
|
7252
7460
|
pathPrefix: options.pathPrefix,
|
|
7253
|
-
fileIntent:
|
|
7461
|
+
fileIntent: toFileIntent(options.intent),
|
|
7254
7462
|
publicOnly: options.public,
|
|
7255
7463
|
name: options.name,
|
|
7256
7464
|
language: options.lang,
|
|
7257
7465
|
allowPartialResults: options.allowPartial,
|
|
7258
|
-
limit:
|
|
7259
|
-
offset:
|
|
7466
|
+
limit: parseOptionalInt(options.limit, "--limit", 1, 100),
|
|
7467
|
+
offset: parseOptionalInt(options.offset, "--offset", 0),
|
|
7260
7468
|
waitTimeoutMs: parseWaitMs(options.wait)
|
|
7261
7469
|
});
|
|
7262
7470
|
const outcome = await service.search(built.params);
|
|
7263
|
-
const payload = buildUnifiedSearchSuccessPayload(built.params, built.rawQuery, built.compiledQuery,
|
|
7471
|
+
const payload = buildUnifiedSearchSuccessPayload(built.params, built.rawQuery, built.compiledQuery, outcome);
|
|
7264
7472
|
if (options.json) {
|
|
7265
7473
|
console.log(JSON.stringify(payload));
|
|
7266
7474
|
return;
|
|
@@ -7298,32 +7506,16 @@ async function searchStatusAction(searchRef, options, deps) {
|
|
|
7298
7506
|
}
|
|
7299
7507
|
var SEARCH_DESCRIPTION = `Search code, docs, and symbols across indexed dependencies and repositories.
|
|
7300
7508
|
|
|
7301
|
-
|
|
7302
|
-
form (https://github.com/org/repo[#ref]). Structured flags are AND-combined
|
|
7303
|
-
the
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
Query syntax:
|
|
7309
|
-
implicit AND foo bar
|
|
7310
|
-
OR foo OR bar (must be uppercase)
|
|
7311
|
-
grouping (foo OR bar) baz
|
|
7312
|
-
exclude foo -bar
|
|
7313
|
-
phrase "exact phrase"
|
|
7314
|
-
qualifiers kind: category: path: lang: name: intent:
|
|
7315
|
-
routing registry: package: version: repo:
|
|
7509
|
+
Repeatable --in targets accept package form (npm:express[@version]) or repo
|
|
7510
|
+
form (https://github.com/org/repo[#ref]). Structured flags are AND-combined
|
|
7511
|
+
with the query. Complete by default — if indexing is still running, returns
|
|
7512
|
+
a searchRef instead of partial hits unless --allow-partial is passed. Use
|
|
7513
|
+
\`githits example\` for canonical cross-project examples; \`--source symbol\`
|
|
7514
|
+
here returns symbol-shaped hits.
|
|
7316
7515
|
|
|
7317
|
-
|
|
7318
|
-
|
|
7319
|
-
|
|
7320
|
-
githits search --source symbol ... symbol-shaped unified search
|
|
7321
|
-
|
|
7322
|
-
Plain output labels:
|
|
7323
|
-
docs page hosted documentation page
|
|
7324
|
-
repo doc documentation-like block from a repository file
|
|
7325
|
-
repo code code block from a repository file
|
|
7326
|
-
repo symbol explicit symbol hit from the repository index
|
|
7516
|
+
The query supports implicit AND, uppercase OR, parens, unary -, "phrases",
|
|
7517
|
+
and qualifiers (kind:, category:, path:, lang:, name:, intent:, registry:,
|
|
7518
|
+
package:, version:, repo:).
|
|
7327
7519
|
|
|
7328
7520
|
Examples:
|
|
7329
7521
|
githits search "router middleware" --in npm:express
|
|
@@ -7337,9 +7529,9 @@ Pass the searchRef returned by githits search when the initial request could
|
|
|
7337
7529
|
not complete within the wait window. This can return progress, partial hits when
|
|
7338
7530
|
the original request used --allow-partial, or final results.`;
|
|
7339
7531
|
function registerSearchCommand(program) {
|
|
7340
|
-
program.command("search").summary("Search indexed dependency and repository code, docs, and symbols").description(SEARCH_DESCRIPTION).argument("<query>", "Search query").requiredOption("--in <target>", "Search target: registry:name[@version] or https://github.com/org/repo[#ref]",
|
|
7532
|
+
program.command("search").summary("Search indexed dependency and repository code, docs, and symbols").description(SEARCH_DESCRIPTION).argument("<query>", "Search query").requiredOption("--in <target>", "Search target: registry:name[@version] or https://github.com/org/repo[#ref]", collectRepeatable2, []).addOption(new Option3("--source <source>", "Source to search (repeatable; default: auto)").choices(["docs", "code", "symbol"]).argParser((value, previous = []) => collectRepeatable2(value.toLowerCase(), previous)).default(undefined)).addOption(new Option3("--kind <kind>", "Precise symbol kind filter").choices([
|
|
7341
7533
|
...knownSymbolKindList()
|
|
7342
|
-
])).addOption(new Option3("--category <category>", "Broad symbol category filter").choices([...knownSymbolCategoryList()])).option("--path-prefix <prefix>", "Repository path prefix filter").addOption(new Option3("--intent <intent>", "File intent filter (
|
|
7534
|
+
])).addOption(new Option3("--category <category>", "Broad symbol category filter").choices([...knownSymbolCategoryList()])).option("--path-prefix <prefix>", "Repository path prefix filter").addOption(new Option3("--intent <intent>", "File intent filter (omit to search across all intents)").choices([
|
|
7343
7535
|
"production",
|
|
7344
7536
|
"test",
|
|
7345
7537
|
"benchmark",
|
|
@@ -7379,11 +7571,11 @@ function requireSearchService(deps) {
|
|
|
7379
7571
|
return deps.codeNavigationService;
|
|
7380
7572
|
}
|
|
7381
7573
|
async function loadContainer2() {
|
|
7382
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
7574
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-67qnnqby.js");
|
|
7383
7575
|
return createContainer2();
|
|
7384
7576
|
}
|
|
7385
7577
|
async function loadStartupCodeNavigationRegistrationState() {
|
|
7386
|
-
const { resolveStartupCodeNavigationRegistrationState: resolveStartupCodeNavigationRegistrationState2 } = await import("./shared/chunk-
|
|
7578
|
+
const { resolveStartupCodeNavigationRegistrationState: resolveStartupCodeNavigationRegistrationState2 } = await import("./shared/chunk-67qnnqby.js");
|
|
7387
7579
|
return resolveStartupCodeNavigationRegistrationState2();
|
|
7388
7580
|
}
|
|
7389
7581
|
function parseTargetSpecs(specs) {
|
|
@@ -7421,7 +7613,7 @@ function parseSources(values) {
|
|
|
7421
7613
|
}
|
|
7422
7614
|
});
|
|
7423
7615
|
}
|
|
7424
|
-
function
|
|
7616
|
+
function parseOptionalInt(value, flag, min, max = Number.MAX_SAFE_INTEGER) {
|
|
7425
7617
|
if (value === undefined)
|
|
7426
7618
|
return;
|
|
7427
7619
|
const parsed = Number.parseInt(value, 10);
|
|
@@ -7440,7 +7632,7 @@ function parseWaitMs(value) {
|
|
|
7440
7632
|
}
|
|
7441
7633
|
return seconds * 1000;
|
|
7442
7634
|
}
|
|
7443
|
-
function
|
|
7635
|
+
function collectRepeatable2(value, previous) {
|
|
7444
7636
|
return [...previous, value];
|
|
7445
7637
|
}
|
|
7446
7638
|
function handleSearchError(error2, json, context = "search") {
|
|
@@ -7481,7 +7673,7 @@ function formatUnifiedSearchTerminal(payload) {
|
|
|
7481
7673
|
lines.push("");
|
|
7482
7674
|
lines.push("Partial results:");
|
|
7483
7675
|
}
|
|
7484
|
-
const sourceStatusNotes = formatSourceStatusNotes(payload.sourceStatus
|
|
7676
|
+
const sourceStatusNotes = formatSourceStatusNotes(payload.sourceStatus);
|
|
7485
7677
|
if (payload.results.length === 0) {
|
|
7486
7678
|
lines.push("No results.");
|
|
7487
7679
|
if (sourceStatusNotes.length > 0) {
|
|
@@ -7504,6 +7696,10 @@ function formatUnifiedSearchTerminal(payload) {
|
|
|
7504
7696
|
const location = formatUnifiedSearchLocation(entry.locator);
|
|
7505
7697
|
const header = formatUnifiedSearchHeader(entry, useColors, location);
|
|
7506
7698
|
lines.push(header);
|
|
7699
|
+
const metadata = formatUnifiedSearchMetadata(entry, useColors);
|
|
7700
|
+
if (metadata.length > 0) {
|
|
7701
|
+
lines.push(...metadata);
|
|
7702
|
+
}
|
|
7507
7703
|
if (entry.summary) {
|
|
7508
7704
|
lines.push(...formatUnifiedSearchSummary(entry.summary, entry.highlights?.summary, useColors));
|
|
7509
7705
|
}
|
|
@@ -7560,45 +7756,40 @@ function formatSearchStatusHeadline(status) {
|
|
|
7560
7756
|
function formatSearchStatusCompletedTerminal(payload) {
|
|
7561
7757
|
return formatUnifiedSearchTerminal({
|
|
7562
7758
|
completed: true,
|
|
7563
|
-
returnedCount: payload.result.returnedCount,
|
|
7564
7759
|
hasMore: payload.result.hasMore,
|
|
7565
7760
|
nextOffset: payload.result.nextOffset,
|
|
7566
7761
|
results: payload.result.results,
|
|
7567
7762
|
searchRef: payload.searchRef,
|
|
7568
7763
|
progress: undefined,
|
|
7569
|
-
query: { warnings: payload.result.
|
|
7764
|
+
query: { warnings: payload.result.warnings },
|
|
7570
7765
|
sourceStatus: payload.result.sourceStatus
|
|
7571
7766
|
});
|
|
7572
7767
|
}
|
|
7573
7768
|
function formatSearchStatusPartialTerminal(payload) {
|
|
7574
7769
|
return formatUnifiedSearchTerminal({
|
|
7575
7770
|
completed: false,
|
|
7576
|
-
returnedCount: payload.result.returnedCount,
|
|
7577
7771
|
hasMore: payload.result.hasMore,
|
|
7578
7772
|
nextOffset: payload.result.nextOffset,
|
|
7579
7773
|
results: payload.result.results,
|
|
7580
7774
|
searchRef: payload.searchRef,
|
|
7581
7775
|
progress: payload.progress,
|
|
7582
|
-
query: { warnings: payload.result.
|
|
7776
|
+
query: { warnings: payload.result.warnings },
|
|
7583
7777
|
sourceStatus: payload.result.sourceStatus
|
|
7584
7778
|
});
|
|
7585
7779
|
}
|
|
7586
|
-
function formatSourceStatusNotes(sourceStatus
|
|
7780
|
+
function formatSourceStatusNotes(sourceStatus) {
|
|
7587
7781
|
const useColors = shouldUseColors();
|
|
7588
7782
|
if (!sourceStatus) {
|
|
7589
7783
|
return [];
|
|
7590
7784
|
}
|
|
7591
|
-
const defaultedSet = new Set(defaulted ?? []);
|
|
7592
7785
|
const lines = [];
|
|
7593
7786
|
for (const entry of sourceStatus) {
|
|
7594
7787
|
const label = `${entry.source.toLowerCase()} on ${entry.targetLabel}`;
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
lines.push(dim(`Note: ${label} ignored filters: ${ignoredFilters.join(", ")}`, useColors));
|
|
7788
|
+
if (entry.ignoredFilters && entry.ignoredFilters.length > 0) {
|
|
7789
|
+
lines.push(dim(`Note: ${label} ignored filters: ${entry.ignoredFilters.join(", ")}`, useColors));
|
|
7598
7790
|
}
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
lines.push(dim(`Note: ${label} incompatible filters: ${incompatibleFilters.join(", ")}`, useColors));
|
|
7791
|
+
if (entry.incompatibleFilters && entry.incompatibleFilters.length > 0) {
|
|
7792
|
+
lines.push(dim(`Note: ${label} incompatible filters: ${entry.incompatibleFilters.join(", ")}`, useColors));
|
|
7602
7793
|
}
|
|
7603
7794
|
if (entry.ignoredQueryFeatures && entry.ignoredQueryFeatures.length > 0) {
|
|
7604
7795
|
lines.push(dim(`Note: ${label} ignored query features: ${entry.ignoredQueryFeatures.join(", ")}`, useColors));
|
|
@@ -7606,6 +7797,9 @@ function formatSourceStatusNotes(sourceStatus, defaulted) {
|
|
|
7606
7797
|
if (entry.incompatibleQueryFeatures && entry.incompatibleQueryFeatures.length > 0) {
|
|
7607
7798
|
lines.push(dim(`Note: ${label} incompatible query features: ${entry.incompatibleQueryFeatures.join(", ")}`, useColors));
|
|
7608
7799
|
}
|
|
7800
|
+
if (entry.indexingStatus === "INDEXING") {
|
|
7801
|
+
lines.push(dim(`Note: ${label} still indexing — re-run with the searchRef for full results.`, useColors));
|
|
7802
|
+
}
|
|
7609
7803
|
if (entry.note) {
|
|
7610
7804
|
lines.push(dim(`Note: ${label}: ${entry.note}`, useColors));
|
|
7611
7805
|
}
|
|
@@ -7623,11 +7817,12 @@ function dedupeSearchResultsForDisplay(results) {
|
|
|
7623
7817
|
entry.title ?? "",
|
|
7624
7818
|
(entry.summary ?? "").slice(0, 120)
|
|
7625
7819
|
].join("\x01");
|
|
7626
|
-
|
|
7820
|
+
const dedupeKey = `${key}\x01${entry.locator.pageId ?? entry.locator.filePath ?? ""}`;
|
|
7821
|
+
if (seen.has(dedupeKey)) {
|
|
7627
7822
|
duplicatesFolded += 1;
|
|
7628
7823
|
continue;
|
|
7629
7824
|
}
|
|
7630
|
-
seen.add(
|
|
7825
|
+
seen.add(dedupeKey);
|
|
7631
7826
|
display.push(entry);
|
|
7632
7827
|
}
|
|
7633
7828
|
return { display, duplicatesFolded };
|
|
@@ -7682,7 +7877,7 @@ function formatUnifiedSearchSummary(summary, ranges, useColors) {
|
|
|
7682
7877
|
}
|
|
7683
7878
|
function formatUnifiedSearchLocation(locator) {
|
|
7684
7879
|
if (!locator.filePath) {
|
|
7685
|
-
return;
|
|
7880
|
+
return locator.sourceUrl;
|
|
7686
7881
|
}
|
|
7687
7882
|
if (!locator.startLine) {
|
|
7688
7883
|
return locator.filePath;
|
|
@@ -7690,11 +7885,29 @@ function formatUnifiedSearchLocation(locator) {
|
|
|
7690
7885
|
return `${locator.filePath}:${locator.startLine}${locator.endLine && locator.endLine !== locator.startLine ? `-${locator.endLine}` : ""}`;
|
|
7691
7886
|
}
|
|
7692
7887
|
function formatUnifiedSearchHeader(entry, useColors, location) {
|
|
7693
|
-
const primary = location ? `${entry.target} ${location}` : entry.target;
|
|
7888
|
+
const primary = entry.type === "documentation_page" ? entry.target : location ? `${entry.target} ${location}` : entry.target;
|
|
7694
7889
|
const badge = `[${formatUnifiedSearchResultLabel(entry.type)}]`;
|
|
7695
7890
|
const title = entry.title ? highlightRanges(entry.title, entry.highlights?.title, useColors) : undefined;
|
|
7696
7891
|
return `${highlight(primary, useColors)} ${dim(badge, useColors)}${title ? ` - ${title}` : ""}`;
|
|
7697
7892
|
}
|
|
7893
|
+
function formatUnifiedSearchMetadata(entry, useColors) {
|
|
7894
|
+
if (entry.type !== "documentation_page" && entry.type !== "repository_doc") {
|
|
7895
|
+
return [];
|
|
7896
|
+
}
|
|
7897
|
+
const lines = [];
|
|
7898
|
+
if (entry.locator.pageId) {
|
|
7899
|
+
lines.push(` ${dim("pageId:", useColors)} ${entry.locator.pageId}`);
|
|
7900
|
+
}
|
|
7901
|
+
const sourceBadge = entry.locator.sourceKind?.toLowerCase() === "repository" ? "[repo]" : entry.locator.sourceKind?.toLowerCase() === "crawled" ? "[crawled]" : undefined;
|
|
7902
|
+
if (entry.locator.sourceUrl) {
|
|
7903
|
+
lines.push(` ${dim("source:", useColors)} ${sourceBadge ? `${sourceBadge} ` : ""}${entry.locator.sourceUrl}`);
|
|
7904
|
+
}
|
|
7905
|
+
if (entry.type === "repository_doc" && entry.locator.filePath) {
|
|
7906
|
+
const ref = entry.locator.requestedRef ?? entry.locator.gitRef;
|
|
7907
|
+
lines.push(` ${dim("file:", useColors)} ${entry.locator.filePath}${ref ? ` @ ${ref}` : ""}`);
|
|
7908
|
+
}
|
|
7909
|
+
return lines;
|
|
7910
|
+
}
|
|
7698
7911
|
// src/cli.ts
|
|
7699
7912
|
var program = new Command;
|
|
7700
7913
|
var commandSpans = new WeakMap;
|
|
@@ -7713,10 +7926,10 @@ program.name("githits").description("Code examples from global open source for y
|
|
|
7713
7926
|
endTelemetrySpan(commandSpans.get(actionCommand));
|
|
7714
7927
|
}).addHelpText("after", `
|
|
7715
7928
|
Getting started:
|
|
7716
|
-
githits init
|
|
7717
|
-
githits login
|
|
7718
|
-
githits mcp
|
|
7719
|
-
githits example "query"
|
|
7929
|
+
githits init Set up MCP for your coding agents
|
|
7930
|
+
githits login Authenticate with your GitHits account
|
|
7931
|
+
githits mcp Show MCP setup instructions
|
|
7932
|
+
githits example "query" -l python Get code examples
|
|
7720
7933
|
|
|
7721
7934
|
Learn more at https://githits.com
|
|
7722
7935
|
Docs: https://app.githits.com/docs/
|
|
@@ -7729,28 +7942,35 @@ registerExampleCommand(program);
|
|
|
7729
7942
|
registerLanguagesCommand(program);
|
|
7730
7943
|
registerFeedbackCommand(program);
|
|
7731
7944
|
var argv = process.argv.slice(2);
|
|
7732
|
-
var
|
|
7733
|
-
var
|
|
7734
|
-
var
|
|
7735
|
-
|
|
7945
|
+
var registrationArgv = stripRootRegistrationOptions(argv);
|
|
7946
|
+
var helpInvocation = isHelpInvocation(registrationArgv);
|
|
7947
|
+
var shouldLoadGatedHelpRegistration = needsGatedHelpRegistration(registrationArgv);
|
|
7948
|
+
var helpRegistrationOptions = shouldLoadGatedHelpRegistration ? await loadHelpRegistrationOptions(registrationArgv) : undefined;
|
|
7949
|
+
if (shouldEagerLoadSearchCommands(registrationArgv)) {
|
|
7736
7950
|
await withTelemetrySpan("cli.register.search", () => registerUnifiedSearchCommands(program, helpRegistrationOptions));
|
|
7737
7951
|
}
|
|
7738
|
-
if (shouldEagerLoadGatedCommandGroup(
|
|
7952
|
+
if (shouldEagerLoadGatedCommandGroup(registrationArgv, "code")) {
|
|
7739
7953
|
await withTelemetrySpan("cli.register.code-group", () => registerCodeCommandGroup(program, helpRegistrationOptions));
|
|
7740
7954
|
}
|
|
7741
|
-
if (shouldEagerLoadGatedCommandGroup(
|
|
7955
|
+
if (shouldEagerLoadGatedCommandGroup(registrationArgv, "pkg")) {
|
|
7742
7956
|
await withTelemetrySpan("cli.register.pkg-group", () => registerPkgCommandGroup(program, helpRegistrationOptions));
|
|
7743
7957
|
}
|
|
7958
|
+
if (shouldEagerLoadGatedCommandGroup(registrationArgv, "docs")) {
|
|
7959
|
+
await withTelemetrySpan("cli.register.docs-group", () => registerDocsCommandGroup(program, helpRegistrationOptions));
|
|
7960
|
+
}
|
|
7744
7961
|
var authCommand = program.command("auth").summary("Manage authentication").description("Manage authentication with GitHits.");
|
|
7745
7962
|
registerAuthStatusCommand(authCommand);
|
|
7746
7963
|
await withTelemetrySpan("cli.parse", () => program.parseAsync());
|
|
7964
|
+
function stripRootRegistrationOptions(args) {
|
|
7965
|
+
return args.filter((arg) => arg !== "--no-color");
|
|
7966
|
+
}
|
|
7747
7967
|
function shouldEagerLoadGatedCommandGroup(args, groupName) {
|
|
7748
7968
|
const [firstArg] = args;
|
|
7749
|
-
return firstArg === groupName || firstArg === "help" && args[1] === groupName;
|
|
7969
|
+
return args.length === 0 || firstArg === groupName || firstArg === "help" && (!args[1] || args[1] === groupName) || firstArg === "--help" || firstArg === "-h";
|
|
7750
7970
|
}
|
|
7751
7971
|
function shouldEagerLoadSearchCommands(args) {
|
|
7752
7972
|
const [firstArg] = args;
|
|
7753
|
-
return firstArg === "search" || firstArg === "search-status" || firstArg === "help" && isSearchHelpTarget(args[1]);
|
|
7973
|
+
return args.length === 0 || firstArg === "search" || firstArg === "search-status" || firstArg === "--help" || firstArg === "-h" || firstArg === "help" && (!args[1] || isSearchHelpTarget(args[1]));
|
|
7754
7974
|
}
|
|
7755
7975
|
function isHelpInvocation(args) {
|
|
7756
7976
|
return args.length === 0 || args[0] === "help" || args.includes("--help") || args.includes("-h");
|
|
@@ -7761,24 +7981,24 @@ function needsGatedHelpRegistration(args) {
|
|
|
7761
7981
|
}
|
|
7762
7982
|
const [firstArg, secondArg] = args;
|
|
7763
7983
|
if (firstArg === "help") {
|
|
7764
|
-
return isSearchHelpTarget(secondArg) || secondArg === "code" || secondArg === "pkg";
|
|
7984
|
+
return isSearchHelpTarget(secondArg) || secondArg === "code" || secondArg === "pkg" || secondArg === "docs";
|
|
7765
7985
|
}
|
|
7766
|
-
return isSearchHelpTarget(firstArg) || firstArg === "code" || firstArg === "pkg";
|
|
7986
|
+
return isSearchHelpTarget(firstArg) || firstArg === "code" || firstArg === "pkg" || firstArg === "docs";
|
|
7767
7987
|
}
|
|
7768
7988
|
function isSearchHelpTarget(value) {
|
|
7769
7989
|
return value === "search" || value === "search-status";
|
|
7770
7990
|
}
|
|
7771
|
-
async function loadHelpRegistrationOptions() {
|
|
7772
|
-
const { resolveStartupCodeNavigationRegistrationState: resolveStartupCodeNavigationRegistrationState2 } = await import("./shared/chunk-
|
|
7991
|
+
async function loadHelpRegistrationOptions(args) {
|
|
7992
|
+
const { resolveStartupCodeNavigationRegistrationState: resolveStartupCodeNavigationRegistrationState2 } = await import("./shared/chunk-67qnnqby.js");
|
|
7773
7993
|
const registrationState = await resolveStartupCodeNavigationRegistrationState2();
|
|
7774
7994
|
return {
|
|
7775
7995
|
capability: registrationState.capability,
|
|
7776
|
-
expiredStoredAuth: shouldUseExpiredStoredAuthFallbackForHelp(
|
|
7996
|
+
expiredStoredAuth: shouldUseExpiredStoredAuthFallbackForHelp(args) ? registrationState.expiredStoredAuth : false
|
|
7777
7997
|
};
|
|
7778
7998
|
}
|
|
7779
7999
|
function shouldUseExpiredStoredAuthFallbackForHelp(args) {
|
|
7780
8000
|
const [firstArg, secondArg] = args;
|
|
7781
|
-
return firstArg === "search" || firstArg === "search-status" || firstArg === "code" || firstArg === "pkg" || firstArg === "help" && (isSearchHelpTarget(secondArg) || secondArg === "code" || secondArg === "pkg");
|
|
8001
|
+
return firstArg === "search" || firstArg === "search-status" || firstArg === "code" || firstArg === "pkg" || firstArg === "docs" || firstArg === "help" && (isSearchHelpTarget(secondArg) || secondArg === "code" || secondArg === "pkg" || secondArg === "docs");
|
|
7782
8002
|
}
|
|
7783
8003
|
function getTelemetryCommandName(command) {
|
|
7784
8004
|
const names = [];
|