githits 0.4.3 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.plugin/plugin.json +1 -1
- package/README.md +40 -14
- package/dist/cli.js +882 -274
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-q6d3ttgn.js → chunk-96tjsv6y.js} +1 -1
- package/dist/shared/chunk-k35egwwf.js +15 -0
- package/dist/shared/{chunk-15argn2z.js → chunk-tfqxat16.js} +182 -43
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/dist/shared/chunk-kmka6wpx.js +0 -11
package/dist/cli.js
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
PackageIntelligenceValidationError,
|
|
33
33
|
PackageIntelligenceVersionNotFoundError,
|
|
34
34
|
PromptServiceImpl,
|
|
35
|
+
clearAutoLoginAuthSessionMetadata,
|
|
35
36
|
createAuthCommandDependencies,
|
|
36
37
|
createAuthStatusDependencies,
|
|
37
38
|
createContainer,
|
|
@@ -42,6 +43,7 @@ import {
|
|
|
42
43
|
formatUpdateNotice,
|
|
43
44
|
getCodeNavigationUrl,
|
|
44
45
|
isTelemetryEnabled,
|
|
46
|
+
loadAutoLoginAuthSessionMetadata,
|
|
45
47
|
refreshExpiredToken,
|
|
46
48
|
setClientMode,
|
|
47
49
|
setMcpClientVersionProvider,
|
|
@@ -49,11 +51,11 @@ import {
|
|
|
49
51
|
shouldRunUpdateCheck,
|
|
50
52
|
startTelemetrySpan,
|
|
51
53
|
withTelemetrySpan
|
|
52
|
-
} from "./shared/chunk-
|
|
54
|
+
} from "./shared/chunk-tfqxat16.js";
|
|
53
55
|
import {
|
|
54
56
|
__require,
|
|
55
57
|
version
|
|
56
|
-
} from "./shared/chunk-
|
|
58
|
+
} from "./shared/chunk-96tjsv6y.js";
|
|
57
59
|
|
|
58
60
|
// src/cli.ts
|
|
59
61
|
import { Command } from "commander";
|
|
@@ -914,7 +916,7 @@ var GREP_REPO_PATTERN_NOTE = "Text grep over indexed source files. `literal` (de
|
|
|
914
916
|
function buildGrepRepoParams(input) {
|
|
915
917
|
const pattern = input.pattern ?? "";
|
|
916
918
|
if (pattern.length === 0 || pattern.trim().length === 0) {
|
|
917
|
-
throw new InvalidPackageSpecError("`pattern` is required — pass the text to search for.");
|
|
919
|
+
throw new InvalidPackageSpecError("`pattern` is required — pass the text to search for. If you are trying to list files or count files in scope, use `code_files` instead.");
|
|
918
920
|
}
|
|
919
921
|
if (Buffer.byteLength(pattern, "utf8") > PATTERN_MAX) {
|
|
920
922
|
throw new InvalidPackageSpecError(`\`pattern\` must be ≤ ${PATTERN_MAX} UTF-8 bytes.`);
|
|
@@ -1057,7 +1059,13 @@ function normalizeWaitTimeoutMs(value) {
|
|
|
1057
1059
|
}
|
|
1058
1060
|
return value;
|
|
1059
1061
|
}
|
|
1062
|
+
// src/shared/shell-quote.ts
|
|
1063
|
+
function shellQuote(value) {
|
|
1064
|
+
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1060
1067
|
// src/shared/grep-repo-response.ts
|
|
1068
|
+
var UTF8_ENCODER = new TextEncoder;
|
|
1061
1069
|
function buildGrepRepoSuccessPayload(result, options) {
|
|
1062
1070
|
const envelope = {
|
|
1063
1071
|
pattern: options.pattern,
|
|
@@ -1369,7 +1377,7 @@ function renderVerboseLine(line, gutterWidth, useColors) {
|
|
|
1369
1377
|
if (line.symbolHint) {
|
|
1370
1378
|
const hintIndent = " ".repeat(2 + gutterWidth + 2);
|
|
1371
1379
|
return `${matchRow}
|
|
1372
|
-
${hintIndent}${dim(
|
|
1380
|
+
${hintIndent}${dim(`in: ${line.symbolHint}`, useColors)}`;
|
|
1373
1381
|
}
|
|
1374
1382
|
return matchRow;
|
|
1375
1383
|
}
|
|
@@ -1388,8 +1396,9 @@ function formatSymbolHint(symbol) {
|
|
|
1388
1396
|
parts.push("public");
|
|
1389
1397
|
if (symbol.arity !== undefined)
|
|
1390
1398
|
parts.push(`arity=${symbol.arity}`);
|
|
1391
|
-
if (symbol.callerCount !== undefined)
|
|
1399
|
+
if (symbol.callerCount !== undefined) {
|
|
1392
1400
|
parts.push(`callers=${symbol.callerCount}`);
|
|
1401
|
+
}
|
|
1393
1402
|
if (symbol.startLine !== undefined && symbol.endLine !== undefined) {
|
|
1394
1403
|
parts.push(`L${symbol.startLine}-${symbol.endLine}`);
|
|
1395
1404
|
}
|
|
@@ -1426,9 +1435,6 @@ function shouldSuggestNarrowingScope(envelope) {
|
|
|
1426
1435
|
function formatCount(count, singular, plural = `${singular}s`) {
|
|
1427
1436
|
return `${count} ${count === 1 ? singular : plural}`;
|
|
1428
1437
|
}
|
|
1429
|
-
function shellQuote(value) {
|
|
1430
|
-
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
1431
|
-
}
|
|
1432
1438
|
function padLeft(text, width) {
|
|
1433
1439
|
return text.length >= width ? text : `${" ".repeat(width - text.length)}${text}`;
|
|
1434
1440
|
}
|
|
@@ -1449,7 +1455,21 @@ function mergeRanges(existing, incoming) {
|
|
|
1449
1455
|
return merged;
|
|
1450
1456
|
}
|
|
1451
1457
|
function clampCharacterOffset(text, offset) {
|
|
1452
|
-
|
|
1458
|
+
if (offset <= 0)
|
|
1459
|
+
return 0;
|
|
1460
|
+
let byteOffset = 0;
|
|
1461
|
+
for (let index = 0;index < text.length; ) {
|
|
1462
|
+
const codePoint = text.codePointAt(index);
|
|
1463
|
+
if (codePoint === undefined)
|
|
1464
|
+
break;
|
|
1465
|
+
const char = String.fromCodePoint(codePoint);
|
|
1466
|
+
const nextByteOffset = byteOffset + UTF8_ENCODER.encode(char).length;
|
|
1467
|
+
if (nextByteOffset > offset)
|
|
1468
|
+
return index;
|
|
1469
|
+
byteOffset = nextByteOffset;
|
|
1470
|
+
index += char.length;
|
|
1471
|
+
}
|
|
1472
|
+
return text.length;
|
|
1453
1473
|
}
|
|
1454
1474
|
// src/shared/grep-repo-text.ts
|
|
1455
1475
|
var SEP = " | ";
|
|
@@ -1509,33 +1529,8 @@ function buildHeader(envelope) {
|
|
|
1509
1529
|
flags.push("case-sensitive");
|
|
1510
1530
|
if (flags.length > 0)
|
|
1511
1531
|
parts.push(flags.join(","));
|
|
1512
|
-
const filterEcho = buildFilterEcho(envelope);
|
|
1513
|
-
if (filterEcho)
|
|
1514
|
-
parts.push(filterEcho);
|
|
1515
1532
|
return parts.join(SEP);
|
|
1516
1533
|
}
|
|
1517
|
-
function buildFilterEcho(envelope) {
|
|
1518
|
-
const filter = envelope.filter;
|
|
1519
|
-
if (!filter)
|
|
1520
|
-
return "";
|
|
1521
|
-
const parts = [];
|
|
1522
|
-
if (filter.path)
|
|
1523
|
-
parts.push(`path=${quote2(filter.path)}`);
|
|
1524
|
-
if (filter.pathPrefix)
|
|
1525
|
-
parts.push(`path_prefix=${quote2(filter.pathPrefix)}`);
|
|
1526
|
-
if (filter.globs?.length)
|
|
1527
|
-
parts.push(`globs=${filter.globs.join(",")}`);
|
|
1528
|
-
if (filter.extensions?.length) {
|
|
1529
|
-
parts.push(`exts=${filter.extensions.join(",")}`);
|
|
1530
|
-
}
|
|
1531
|
-
if (typeof filter.maxMatches === "number") {
|
|
1532
|
-
parts.push(`max_matches=${filter.maxMatches}`);
|
|
1533
|
-
}
|
|
1534
|
-
if (typeof filter.maxMatchesPerFile === "number") {
|
|
1535
|
-
parts.push(`max_matches_per_file=${filter.maxMatchesPerFile}`);
|
|
1536
|
-
}
|
|
1537
|
-
return parts.join(" ");
|
|
1538
|
-
}
|
|
1539
1534
|
function buildTrailer(envelope) {
|
|
1540
1535
|
const lines = [];
|
|
1541
1536
|
if (envelope.truncatedReason) {
|
|
@@ -1701,7 +1696,7 @@ function buildHeader2(envelope) {
|
|
|
1701
1696
|
];
|
|
1702
1697
|
if (identity)
|
|
1703
1698
|
parts.push(identity);
|
|
1704
|
-
const filter =
|
|
1699
|
+
const filter = buildFilterEcho(envelope);
|
|
1705
1700
|
if (filter)
|
|
1706
1701
|
parts.push(filter);
|
|
1707
1702
|
return parts.join(SEP2);
|
|
@@ -1716,7 +1711,7 @@ function buildIdentity(envelope) {
|
|
|
1716
1711
|
}
|
|
1717
1712
|
return "";
|
|
1718
1713
|
}
|
|
1719
|
-
function
|
|
1714
|
+
function buildFilterEcho(envelope) {
|
|
1720
1715
|
const parts = [];
|
|
1721
1716
|
if (envelope.filter?.path) {
|
|
1722
1717
|
parts.push(`path=${quote3(envelope.filter.path)}`);
|
|
@@ -1910,6 +1905,8 @@ function formatListPackageDocsTerminal(envelope, options) {
|
|
|
1910
1905
|
lines.push(...meta);
|
|
1911
1906
|
lines.push("");
|
|
1912
1907
|
}
|
|
1908
|
+
lines.push(dim("Read a page: githits docs read '<pageId>'", options.useColors));
|
|
1909
|
+
lines.push("");
|
|
1913
1910
|
if (envelope.nextCursor) {
|
|
1914
1911
|
lines.push(dim(`Next cursor: ${envelope.nextCursor}`, options.useColors));
|
|
1915
1912
|
}
|
|
@@ -1923,7 +1920,7 @@ function formatListPackageDocsTerminal(envelope, options) {
|
|
|
1923
1920
|
}
|
|
1924
1921
|
function buildSummaryHeader(envelope, useColors) {
|
|
1925
1922
|
const target = envelope.registry && envelope.name ? `${envelope.registry}:${envelope.name}${envelope.version ? `@${envelope.version}` : ""}` : "package docs";
|
|
1926
|
-
const summary = `${target}
|
|
1923
|
+
const summary = `${target} | ${envelope.pages.length} page${envelope.pages.length === 1 ? "" : "s"}`;
|
|
1927
1924
|
const suffix = envelope.total !== undefined ? ` of ${envelope.total}` : "";
|
|
1928
1925
|
return `${colorize(summary, "bold", useColors)}${dim(suffix, useColors)}`;
|
|
1929
1926
|
}
|
|
@@ -2415,7 +2412,7 @@ function formatPackageDependenciesTerminal(report, options = {}) {
|
|
|
2415
2412
|
const issues = formatConflictsAndCycles(payload, verbose, useColors);
|
|
2416
2413
|
if (issues)
|
|
2417
2414
|
blocks.push(issues);
|
|
2418
|
-
} else {
|
|
2415
|
+
} else if (!showGroups) {
|
|
2419
2416
|
blocks.push(formatDirectDepsList(payload, verbose, useColors));
|
|
2420
2417
|
}
|
|
2421
2418
|
if (showGroups) {
|
|
@@ -2429,7 +2426,7 @@ function formatPackageDependenciesTerminal(report, options = {}) {
|
|
|
2429
2426
|
function formatHeaderBlock(payload, useColors, showGroups, options) {
|
|
2430
2427
|
const name = colorize(payload.name, "bold", useColors);
|
|
2431
2428
|
const lines = [
|
|
2432
|
-
`${name} @ ${payload.version}
|
|
2429
|
+
`${name} @ ${payload.version} | ${payload.registry}`
|
|
2433
2430
|
];
|
|
2434
2431
|
if (payload.requestedVersion) {
|
|
2435
2432
|
lines.push(dim(`(requested ${payload.requestedVersion})`, useColors));
|
|
@@ -2469,13 +2466,13 @@ function formatSummaryRow(payload, useColors, showGroups, options) {
|
|
|
2469
2466
|
countParts.push(colorize(`${cycleCount} ${noun}`, "red", useColors));
|
|
2470
2467
|
}
|
|
2471
2468
|
}
|
|
2472
|
-
const countLine = countParts.join("
|
|
2469
|
+
const countLine = countParts.join(" | ");
|
|
2473
2470
|
if (showGroups)
|
|
2474
2471
|
return countLine;
|
|
2475
2472
|
const hidden = collectHiddenGroupNames(payload);
|
|
2476
2473
|
if (hidden.length === 0)
|
|
2477
2474
|
return countLine;
|
|
2478
|
-
const hiddenLine = dim(`Hidden groups: ${hidden.join(", ")}
|
|
2475
|
+
const hiddenLine = dim(`Hidden groups: ${hidden.join(", ")} - ${options.hiddenGroupsHint ?? "use --lifecycle all."}`, useColors);
|
|
2479
2476
|
return `${countLine}
|
|
2480
2477
|
${hiddenLine}`;
|
|
2481
2478
|
}
|
|
@@ -2490,18 +2487,21 @@ function formatDirectDepsList(payload, verbose, useColors) {
|
|
|
2490
2487
|
if (!runtime || runtime.count === 0)
|
|
2491
2488
|
return "";
|
|
2492
2489
|
const sorted = sortAlphabetically(runtime.items, (i) => i.name);
|
|
2490
|
+
const lines = ["Runtime dependencies:", ""];
|
|
2493
2491
|
if (!verbose) {
|
|
2494
|
-
|
|
2492
|
+
lines.push(...sorted.map((item) => ` ${formatDepLabel(item)}`));
|
|
2493
|
+
return lines.join(`
|
|
2495
2494
|
`);
|
|
2496
2495
|
}
|
|
2497
2496
|
const rootLabel = `${payload.name}@${payload.version}`;
|
|
2498
|
-
|
|
2497
|
+
lines.push(...sorted.map((item) => {
|
|
2499
2498
|
const head = ` ${formatDepLabel(item)}`;
|
|
2500
2499
|
const constraintLabel = item.constraint ?? "*";
|
|
2501
2500
|
const line = dim(` - ${constraintLabel} required by ${rootLabel}`, useColors);
|
|
2502
2501
|
return `${head}
|
|
2503
2502
|
${line}`;
|
|
2504
|
-
})
|
|
2503
|
+
}));
|
|
2504
|
+
return lines.join(`
|
|
2505
2505
|
`);
|
|
2506
2506
|
}
|
|
2507
2507
|
function formatDepLabel(item) {
|
|
@@ -2516,11 +2516,13 @@ function formatTransitiveDepsList(payload, verbose, useColors) {
|
|
|
2516
2516
|
if (packages.length === 0)
|
|
2517
2517
|
return "";
|
|
2518
2518
|
const sorted = [...packages].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
2519
|
+
const lines = ["Transitive packages:", ""];
|
|
2519
2520
|
if (!verbose) {
|
|
2520
|
-
|
|
2521
|
+
lines.push(...sorted.map((pkg) => ` ${formatPackageLabel(pkg)}`));
|
|
2522
|
+
return lines.join(`
|
|
2521
2523
|
`);
|
|
2522
2524
|
}
|
|
2523
|
-
|
|
2525
|
+
lines.push(...sorted.map((pkg) => {
|
|
2524
2526
|
const head = ` ${formatPackageLabel(pkg)}`;
|
|
2525
2527
|
const importers = pkg.importers ?? [];
|
|
2526
2528
|
if (importers.length === 0)
|
|
@@ -2528,7 +2530,8 @@ function formatTransitiveDepsList(payload, verbose, useColors) {
|
|
|
2528
2530
|
const bullets = formatImporterBullets(importers, useColors);
|
|
2529
2531
|
return `${head}
|
|
2530
2532
|
${bullets}`;
|
|
2531
|
-
})
|
|
2533
|
+
}));
|
|
2534
|
+
return lines.join(`
|
|
2532
2535
|
`);
|
|
2533
2536
|
}
|
|
2534
2537
|
function formatPackageLabel(pkg) {
|
|
@@ -2583,7 +2586,7 @@ function formatConflictsAndCycles(payload, verbose, useColors) {
|
|
|
2583
2586
|
lines.push("");
|
|
2584
2587
|
lines.push(colorize(`Circular dependencies (${cycles.length}):`, "red", useColors));
|
|
2585
2588
|
for (const c of cycles)
|
|
2586
|
-
lines.push(` ${c.cycle.join("
|
|
2589
|
+
lines.push(` ${c.cycle.join(" -> ")}`);
|
|
2587
2590
|
}
|
|
2588
2591
|
return lines.join(`
|
|
2589
2592
|
`);
|
|
@@ -2598,6 +2601,8 @@ function formatGroupsBlock(payload, verbose, useColors) {
|
|
|
2598
2601
|
}
|
|
2599
2602
|
const summary = summariseGroupsByLifecycle(groups.items);
|
|
2600
2603
|
const groupNoun = groups.items.length === 1 ? "group" : "groups";
|
|
2604
|
+
lines.push("Dependency groups:");
|
|
2605
|
+
lines.push("");
|
|
2601
2606
|
lines.push(colorize(`${groups.items.length} ${groupNoun} (${summary}):`, "bold", useColors));
|
|
2602
2607
|
lines.push("");
|
|
2603
2608
|
if (verbose && groups.environmentMarkers && groups.environmentMarkers.length > 0) {
|
|
@@ -2622,9 +2627,7 @@ function formatGroupsBlock(payload, verbose, useColors) {
|
|
|
2622
2627
|
} else {
|
|
2623
2628
|
const nameWidth = Math.max(...deps.map((d) => d.name.length));
|
|
2624
2629
|
for (const dep of deps) {
|
|
2625
|
-
|
|
2626
|
-
const constraint = dep.constraint ?? "";
|
|
2627
|
-
lines.push(` ${name} ${constraint}`.trimEnd());
|
|
2630
|
+
lines.push(` ${formatGroupDependencyRow(dep, group, payload, nameWidth)}`);
|
|
2628
2631
|
}
|
|
2629
2632
|
}
|
|
2630
2633
|
lines.push("");
|
|
@@ -2632,6 +2635,20 @@ function formatGroupsBlock(payload, verbose, useColors) {
|
|
|
2632
2635
|
return lines.join(`
|
|
2633
2636
|
`).trimEnd();
|
|
2634
2637
|
}
|
|
2638
|
+
function formatGroupDependencyRow(dep, group, payload, nameWidth) {
|
|
2639
|
+
const constraint = dep.constraint ?? "";
|
|
2640
|
+
if (group.lifecycle !== "runtime") {
|
|
2641
|
+
const name = dep.name.padEnd(nameWidth);
|
|
2642
|
+
return `${name} ${constraint}`.trimEnd();
|
|
2643
|
+
}
|
|
2644
|
+
const resolvedVersion = payload.runtime?.items.find((item) => item.name === dep.name)?.version;
|
|
2645
|
+
if (!resolvedVersion) {
|
|
2646
|
+
const name = dep.name.padEnd(nameWidth);
|
|
2647
|
+
return `${name} ${constraint}`.trimEnd();
|
|
2648
|
+
}
|
|
2649
|
+
const versionedName = `${dep.name}@${resolvedVersion}`.padEnd(nameWidth);
|
|
2650
|
+
return `${versionedName} ${constraint}`.trimEnd();
|
|
2651
|
+
}
|
|
2635
2652
|
function formatEnvironmentMarker(marker) {
|
|
2636
2653
|
if (marker.type && marker.value)
|
|
2637
2654
|
return `${marker.type}: ${marker.value}`;
|
|
@@ -3272,7 +3289,7 @@ function buildPackageVulnerabilitiesParams(input) {
|
|
|
3272
3289
|
throw new InvalidPackageSpecError(`Invalid version '${trimmedVersion}'. Use the canonical package version without a leading 'v' (for example '4.18.0', not 'v4.18.0').`);
|
|
3273
3290
|
}
|
|
3274
3291
|
const advisoryScope = resolveAdvisoryScope(input.advisoryScope);
|
|
3275
|
-
const filterWithScope =
|
|
3292
|
+
const filterWithScope = buildFilterEcho2(severityLabel2, input.includeWithdrawn, advisoryScope);
|
|
3276
3293
|
return {
|
|
3277
3294
|
params: {
|
|
3278
3295
|
registry,
|
|
@@ -3297,7 +3314,7 @@ function resolveMinSeverityLabel(raw) {
|
|
|
3297
3314
|
}
|
|
3298
3315
|
return lower;
|
|
3299
3316
|
}
|
|
3300
|
-
function
|
|
3317
|
+
function buildFilterEcho2(minSeverity, includeWithdrawn, advisoryScope) {
|
|
3301
3318
|
const filter = {};
|
|
3302
3319
|
if (minSeverity !== undefined)
|
|
3303
3320
|
filter.minSeverity = minSeverity;
|
|
@@ -4094,16 +4111,144 @@ function requirePositiveInteger(raw, label) {
|
|
|
4094
4111
|
}
|
|
4095
4112
|
return parsed;
|
|
4096
4113
|
}
|
|
4114
|
+
// src/shared/read-file-response.ts
|
|
4115
|
+
function buildReadFileSuccessPayload(result, options) {
|
|
4116
|
+
const envelope = {
|
|
4117
|
+
path: result.filePath ?? options.requestedFilePath
|
|
4118
|
+
};
|
|
4119
|
+
if (options.registry)
|
|
4120
|
+
envelope.registry = options.registry;
|
|
4121
|
+
if (options.name)
|
|
4122
|
+
envelope.name = options.name;
|
|
4123
|
+
if (options.repoUrl)
|
|
4124
|
+
envelope.repoUrl = options.repoUrl;
|
|
4125
|
+
if (options.gitRef)
|
|
4126
|
+
envelope.gitRef = options.gitRef;
|
|
4127
|
+
if (result.language != null)
|
|
4128
|
+
envelope.language = result.language;
|
|
4129
|
+
if (result.totalLines != null)
|
|
4130
|
+
envelope.totalLines = result.totalLines;
|
|
4131
|
+
if (result.startLine != null)
|
|
4132
|
+
envelope.startLine = result.startLine;
|
|
4133
|
+
if (result.endLine != null)
|
|
4134
|
+
envelope.endLine = result.endLine;
|
|
4135
|
+
if (result.isBinary) {
|
|
4136
|
+
envelope.isBinary = true;
|
|
4137
|
+
} else if (result.content != null) {
|
|
4138
|
+
envelope.content = result.content;
|
|
4139
|
+
}
|
|
4140
|
+
return envelope;
|
|
4141
|
+
}
|
|
4142
|
+
function formatReadFileTerminal(envelope, options) {
|
|
4143
|
+
const verbose = options.verbose ?? false;
|
|
4144
|
+
if (envelope.isBinary) {
|
|
4145
|
+
return formatBinary(envelope, options, verbose);
|
|
4146
|
+
}
|
|
4147
|
+
if (envelope.content == null) {
|
|
4148
|
+
return formatNoContent(envelope, options, verbose);
|
|
4149
|
+
}
|
|
4150
|
+
if (!verbose) {
|
|
4151
|
+
return envelope.content;
|
|
4152
|
+
}
|
|
4153
|
+
return formatVerboseBody(envelope, options);
|
|
4154
|
+
}
|
|
4155
|
+
function formatBinary(envelope, options, verbose) {
|
|
4156
|
+
const sentinel = dim("Binary file — cannot display as text.", options.useColors);
|
|
4157
|
+
if (verbose) {
|
|
4158
|
+
return `${buildHeader4(envelope, options)}
|
|
4159
|
+
|
|
4160
|
+
${sentinel}
|
|
4161
|
+
`;
|
|
4162
|
+
}
|
|
4163
|
+
return `${sentinel}
|
|
4164
|
+
`;
|
|
4165
|
+
}
|
|
4166
|
+
function formatNoContent(envelope, options, verbose) {
|
|
4167
|
+
const sentinel = dim("(no content returned)", options.useColors);
|
|
4168
|
+
if (verbose) {
|
|
4169
|
+
return `${buildHeader4(envelope, options)}
|
|
4170
|
+
|
|
4171
|
+
${sentinel}
|
|
4172
|
+
`;
|
|
4173
|
+
}
|
|
4174
|
+
return `${sentinel}
|
|
4175
|
+
`;
|
|
4176
|
+
}
|
|
4177
|
+
function formatVerboseBody(envelope, options) {
|
|
4178
|
+
const lines = [];
|
|
4179
|
+
lines.push(buildHeader4(envelope, options));
|
|
4180
|
+
lines.push("");
|
|
4181
|
+
const bodyLines = splitReadFileContentLines(envelope);
|
|
4182
|
+
const startLine = envelope.startLine ?? 1;
|
|
4183
|
+
const endLine = startLine + bodyLines.length - 1;
|
|
4184
|
+
const gutterWidth = String(endLine).length;
|
|
4185
|
+
for (let i = 0;i < bodyLines.length; i++) {
|
|
4186
|
+
const lineNumber = startLine + i;
|
|
4187
|
+
const gutter = dim(String(lineNumber).padStart(gutterWidth, " "), options.useColors);
|
|
4188
|
+
lines.push(`${gutter} ${bodyLines[i]}`);
|
|
4189
|
+
}
|
|
4190
|
+
if (envelope.hint) {
|
|
4191
|
+
lines.push("");
|
|
4192
|
+
lines.push(dim(envelope.hint, options.useColors));
|
|
4193
|
+
}
|
|
4194
|
+
lines.push("");
|
|
4195
|
+
return lines.join(`
|
|
4196
|
+
`);
|
|
4197
|
+
}
|
|
4198
|
+
function splitReadFileContentLines(envelope) {
|
|
4199
|
+
if (!envelope.content)
|
|
4200
|
+
return [];
|
|
4201
|
+
const bodyLines = envelope.content.split(`
|
|
4202
|
+
`);
|
|
4203
|
+
const expectedCount = expectedLineCount(envelope);
|
|
4204
|
+
if (expectedCount === undefined) {
|
|
4205
|
+
if (bodyLines[bodyLines.length - 1] === "")
|
|
4206
|
+
bodyLines.pop();
|
|
4207
|
+
return bodyLines;
|
|
4208
|
+
}
|
|
4209
|
+
while (bodyLines.length > 0 && bodyLines[bodyLines.length - 1] === "" && bodyLines.length > expectedCount) {
|
|
4210
|
+
bodyLines.pop();
|
|
4211
|
+
}
|
|
4212
|
+
return bodyLines;
|
|
4213
|
+
}
|
|
4214
|
+
function expectedLineCount(envelope) {
|
|
4215
|
+
if (envelope.startLine === undefined || envelope.endLine === undefined) {
|
|
4216
|
+
return;
|
|
4217
|
+
}
|
|
4218
|
+
if (envelope.endLine < envelope.startLine)
|
|
4219
|
+
return;
|
|
4220
|
+
return envelope.endLine - envelope.startLine + 1;
|
|
4221
|
+
}
|
|
4222
|
+
function buildHeader4(envelope, options) {
|
|
4223
|
+
const parts = [envelope.path];
|
|
4224
|
+
if (envelope.language)
|
|
4225
|
+
parts.push(envelope.language);
|
|
4226
|
+
const rangeLabel = buildRangeLabel(envelope);
|
|
4227
|
+
if (rangeLabel)
|
|
4228
|
+
parts.push(rangeLabel);
|
|
4229
|
+
return colorize(parts.join(" · "), "bold", options.useColors);
|
|
4230
|
+
}
|
|
4231
|
+
function buildRangeLabel(envelope) {
|
|
4232
|
+
const { startLine, endLine, totalLines } = envelope;
|
|
4233
|
+
if (startLine != null && endLine != null) {
|
|
4234
|
+
return totalLines != null ? `lines ${startLine}-${endLine} of ${totalLines}` : `lines ${startLine}-${endLine}`;
|
|
4235
|
+
}
|
|
4236
|
+
if (totalLines != null) {
|
|
4237
|
+
return `${totalLines} lines`;
|
|
4238
|
+
}
|
|
4239
|
+
return;
|
|
4240
|
+
}
|
|
4241
|
+
|
|
4097
4242
|
// src/shared/read-file-text.ts
|
|
4098
4243
|
var SEP4 = " | ";
|
|
4099
4244
|
function renderReadFileText(envelope) {
|
|
4100
4245
|
const lines = [];
|
|
4101
|
-
lines.push(
|
|
4246
|
+
lines.push(buildHeader5(envelope));
|
|
4102
4247
|
lines.push("");
|
|
4103
4248
|
if (envelope.isBinary) {
|
|
4104
4249
|
lines.push("Binary file - cannot display as text.");
|
|
4105
4250
|
} else if (envelope.content) {
|
|
4106
|
-
appendNumberedContent(lines, envelope.content, envelope.startLine ?? 1);
|
|
4251
|
+
appendNumberedContent(lines, envelope.content, envelope.startLine ?? 1, envelope.endLine);
|
|
4107
4252
|
} else {
|
|
4108
4253
|
lines.push("(no content returned)");
|
|
4109
4254
|
}
|
|
@@ -4114,7 +4259,7 @@ function renderReadFileText(envelope) {
|
|
|
4114
4259
|
return lines.join(`
|
|
4115
4260
|
`);
|
|
4116
4261
|
}
|
|
4117
|
-
function
|
|
4262
|
+
function buildHeader5(envelope) {
|
|
4118
4263
|
const parts = [`code_read${SEP4}${envelope.path}`];
|
|
4119
4264
|
if (envelope.language)
|
|
4120
4265
|
parts.push(envelope.language);
|
|
@@ -4131,14 +4276,10 @@ function buildRange(envelope) {
|
|
|
4131
4276
|
return `${envelope.totalLines} lines`;
|
|
4132
4277
|
return;
|
|
4133
4278
|
}
|
|
4134
|
-
function appendNumberedContent(lines, content, startLine) {
|
|
4135
|
-
const bodyLines = content
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
bodyLines.pop();
|
|
4139
|
-
}
|
|
4140
|
-
const endLine = startLine + bodyLines.length - 1;
|
|
4141
|
-
const width = String(endLine).length;
|
|
4279
|
+
function appendNumberedContent(lines, content, startLine, endLine) {
|
|
4280
|
+
const bodyLines = splitReadFileContentLines({ content, startLine, endLine });
|
|
4281
|
+
const renderedEndLine = startLine + bodyLines.length - 1;
|
|
4282
|
+
const width = String(renderedEndLine).length;
|
|
4142
4283
|
for (let i = 0;i < bodyLines.length; i += 1) {
|
|
4143
4284
|
lines.push(`${String(startLine + i).padStart(width, " ")} ${bodyLines[i]}`);
|
|
4144
4285
|
}
|
|
@@ -4234,7 +4375,7 @@ function formatReadPackageDocTerminal(envelope, options) {
|
|
|
4234
4375
|
return envelope.content ?? "";
|
|
4235
4376
|
}
|
|
4236
4377
|
const lines = [];
|
|
4237
|
-
lines.push(
|
|
4378
|
+
lines.push(buildHeader6(envelope, options.useColors));
|
|
4238
4379
|
lines.push(`pageId: ${envelope.pageId}`);
|
|
4239
4380
|
if (envelope.sourceUrl)
|
|
4240
4381
|
lines.push(`source: ${envelope.sourceUrl}`);
|
|
@@ -4254,7 +4395,7 @@ function formatReadPackageDocTerminal(envelope, options) {
|
|
|
4254
4395
|
`)}
|
|
4255
4396
|
`;
|
|
4256
4397
|
}
|
|
4257
|
-
function
|
|
4398
|
+
function buildHeader6(envelope, useColors) {
|
|
4258
4399
|
const badge = envelope.sourceKind === "repo" ? "[repo]" : "[crawled]";
|
|
4259
4400
|
const title = envelope.title ?? envelope.pageId;
|
|
4260
4401
|
const prefix = envelope.registry && envelope.name ? `${envelope.registry}:${envelope.name}${envelope.version ? `@${envelope.version}` : ""}` : "documentation";
|
|
@@ -4264,7 +4405,7 @@ function buildHeader5(envelope, useColors) {
|
|
|
4264
4405
|
var SEP5 = " | ";
|
|
4265
4406
|
function renderReadPackageDocText(envelope) {
|
|
4266
4407
|
const lines = [];
|
|
4267
|
-
lines.push(
|
|
4408
|
+
lines.push(buildHeader7(envelope));
|
|
4268
4409
|
if (envelope.sourceUrl)
|
|
4269
4410
|
lines.push(`source: ${envelope.sourceUrl}`);
|
|
4270
4411
|
if (envelope.filePath) {
|
|
@@ -4281,7 +4422,7 @@ function renderReadPackageDocText(envelope) {
|
|
|
4281
4422
|
return lines.join(`
|
|
4282
4423
|
`);
|
|
4283
4424
|
}
|
|
4284
|
-
function
|
|
4425
|
+
function buildHeader7(envelope) {
|
|
4285
4426
|
const parts = [`docs_read${SEP5}${envelope.pageId}`];
|
|
4286
4427
|
if (envelope.title)
|
|
4287
4428
|
parts.push(envelope.title);
|
|
@@ -4601,6 +4742,7 @@ var AUTO_LOGIN_ELIGIBLE_COMMANDS = new Set([
|
|
|
4601
4742
|
"pkg deps",
|
|
4602
4743
|
"pkg changelog"
|
|
4603
4744
|
]);
|
|
4745
|
+
var AUTH_METADATA_TRUST_WINDOW_MS = 10 * 60 * 1000;
|
|
4604
4746
|
function getCommandPath(command) {
|
|
4605
4747
|
const names = [];
|
|
4606
4748
|
let current = command;
|
|
@@ -4633,10 +4775,15 @@ async function maybeAutoLoginBeforeCommand(command, deps) {
|
|
|
4633
4775
|
})) {
|
|
4634
4776
|
return { status: "skipped" };
|
|
4635
4777
|
}
|
|
4778
|
+
const metadata = await deps.loadAuthSessionMetadata?.();
|
|
4779
|
+
if (metadata && isUnexpiredAuthSessionMetadata(metadata, new Date)) {
|
|
4780
|
+
return { status: "already-authenticated" };
|
|
4781
|
+
}
|
|
4636
4782
|
const container = await deps.createContainer();
|
|
4637
4783
|
if (container.hasValidToken) {
|
|
4638
4784
|
return { status: "already-authenticated" };
|
|
4639
4785
|
}
|
|
4786
|
+
await deps.clearAuthSessionMetadata?.();
|
|
4640
4787
|
const result = await deps.loginFlow({}, container);
|
|
4641
4788
|
switch (result.status) {
|
|
4642
4789
|
case "success":
|
|
@@ -4647,6 +4794,20 @@ async function maybeAutoLoginBeforeCommand(command, deps) {
|
|
|
4647
4794
|
return { status: "failed", message: result.message };
|
|
4648
4795
|
}
|
|
4649
4796
|
}
|
|
4797
|
+
function isUnexpiredAuthSessionMetadata(metadata, now) {
|
|
4798
|
+
const updatedAtMs = Date.parse(metadata.updatedAt);
|
|
4799
|
+
if (Number.isNaN(updatedAtMs))
|
|
4800
|
+
return false;
|
|
4801
|
+
if (now.getTime() - updatedAtMs > AUTH_METADATA_TRUST_WINDOW_MS) {
|
|
4802
|
+
return false;
|
|
4803
|
+
}
|
|
4804
|
+
if (metadata.expiresAt === null)
|
|
4805
|
+
return true;
|
|
4806
|
+
const expiresAtMs = Date.parse(metadata.expiresAt);
|
|
4807
|
+
if (Number.isNaN(expiresAtMs))
|
|
4808
|
+
return false;
|
|
4809
|
+
return now.getTime() < expiresAtMs;
|
|
4810
|
+
}
|
|
4650
4811
|
|
|
4651
4812
|
// src/shared/root-cli-pre-action.ts
|
|
4652
4813
|
function createRootCliPreAction(deps) {
|
|
@@ -5071,7 +5232,7 @@ function compactProgress(progress) {
|
|
|
5071
5232
|
payload.requestedTargets = progress.requestedTargets;
|
|
5072
5233
|
}
|
|
5073
5234
|
if (progress.filters)
|
|
5074
|
-
payload.filters =
|
|
5235
|
+
payload.filters = buildFilterEcho3(progress.filters);
|
|
5075
5236
|
if (typeof progress.limit === "number")
|
|
5076
5237
|
payload.limit = progress.limit;
|
|
5077
5238
|
if (typeof progress.offset === "number")
|
|
@@ -5118,7 +5279,7 @@ function compactProgressTarget(target) {
|
|
|
5118
5279
|
payload.requestedRefKind = target.requestedRefKind;
|
|
5119
5280
|
return Object.keys(payload).length > 0 ? payload : undefined;
|
|
5120
5281
|
}
|
|
5121
|
-
function
|
|
5282
|
+
function buildFilterEcho3(filters) {
|
|
5122
5283
|
const echo = {};
|
|
5123
5284
|
if (filters.kind)
|
|
5124
5285
|
echo.kind = filters.kind.toLowerCase();
|
|
@@ -5293,7 +5454,7 @@ var SUMMARY_WRAP_WIDTH = 76;
|
|
|
5293
5454
|
var SEP6 = " | ";
|
|
5294
5455
|
function renderUnifiedSearchSuccess(payload) {
|
|
5295
5456
|
const lines = [];
|
|
5296
|
-
lines.push(
|
|
5457
|
+
lines.push(buildHeader8(payload));
|
|
5297
5458
|
lines.push("");
|
|
5298
5459
|
if (payload.results.length === 0) {
|
|
5299
5460
|
lines.push(payload.completed ? "No hits." : "No hits yet - indexing.");
|
|
@@ -5324,7 +5485,7 @@ function renderUnifiedSearchError(payload) {
|
|
|
5324
5485
|
return lines.join(`
|
|
5325
5486
|
`);
|
|
5326
5487
|
}
|
|
5327
|
-
function
|
|
5488
|
+
function buildHeader8(payload) {
|
|
5328
5489
|
const count = payload.results.length;
|
|
5329
5490
|
const status = payload.completed ? `${count} hit${count === 1 ? "" : "s"}` : `${count} partial`;
|
|
5330
5491
|
const parts = [`search${SEP6}${status}`];
|
|
@@ -5342,7 +5503,7 @@ function appendUnifiedSearchHits(lines, hits) {
|
|
|
5342
5503
|
});
|
|
5343
5504
|
}
|
|
5344
5505
|
function appendHit(lines, index, hit) {
|
|
5345
|
-
const headerParts = [hit
|
|
5506
|
+
const headerParts = [formatHitPrimary(hit), shortType(hit.type)];
|
|
5346
5507
|
lines.push(`[${index}] ${headerParts.join(" ")}`);
|
|
5347
5508
|
const locator = buildLocatorLine(hit);
|
|
5348
5509
|
if (locator)
|
|
@@ -5356,6 +5517,26 @@ function appendHit(lines, index, hit) {
|
|
|
5356
5517
|
}
|
|
5357
5518
|
}
|
|
5358
5519
|
}
|
|
5520
|
+
function formatHitPrimary(hit) {
|
|
5521
|
+
const loc = hit.locator;
|
|
5522
|
+
if (hit.type === "documentation_page" && loc.pageId) {
|
|
5523
|
+
const target = formatDocsPageTarget(loc, hit.target);
|
|
5524
|
+
return target ? `${loc.pageId} ${target}` : loc.pageId;
|
|
5525
|
+
}
|
|
5526
|
+
if (hit.type === "repository_doc" && loc.filePath) {
|
|
5527
|
+
return `${hit.target} ${loc.filePath}${formatLineRange(loc.startLine, loc.endLine)}`;
|
|
5528
|
+
}
|
|
5529
|
+
return hit.target;
|
|
5530
|
+
}
|
|
5531
|
+
function formatDocsPageTarget(locator, fallbackTarget) {
|
|
5532
|
+
return locator.registry && locator.packageName ? `${locator.registry}:${locator.packageName}` : stripVersionFromTarget(fallbackTarget);
|
|
5533
|
+
}
|
|
5534
|
+
function stripVersionFromTarget(value) {
|
|
5535
|
+
if (!value)
|
|
5536
|
+
return "";
|
|
5537
|
+
const atIndex = value.lastIndexOf("@");
|
|
5538
|
+
return atIndex > 0 ? value.slice(0, atIndex) : value;
|
|
5539
|
+
}
|
|
5359
5540
|
function shortType(type) {
|
|
5360
5541
|
switch (type) {
|
|
5361
5542
|
case "repository_code":
|
|
@@ -5524,7 +5705,7 @@ function wrapText2(text, width) {
|
|
|
5524
5705
|
var SEP7 = " | ";
|
|
5525
5706
|
function renderUnifiedSearchStatusText(payload) {
|
|
5526
5707
|
const lines = [];
|
|
5527
|
-
lines.push(
|
|
5708
|
+
lines.push(buildHeader9(payload));
|
|
5528
5709
|
if (!payload.completed && payload.progress) {
|
|
5529
5710
|
lines.push(formatProgress(payload.progress));
|
|
5530
5711
|
if (payload.progress.targets?.length) {
|
|
@@ -5548,7 +5729,7 @@ function renderUnifiedSearchStatusText(payload) {
|
|
|
5548
5729
|
return lines.join(`
|
|
5549
5730
|
`);
|
|
5550
5731
|
}
|
|
5551
|
-
function
|
|
5732
|
+
function buildHeader9(payload) {
|
|
5552
5733
|
const state = payload.completed ? "complete" : "indexing";
|
|
5553
5734
|
const parts = [`search_status${SEP7}${state}`];
|
|
5554
5735
|
if (payload.searchRef)
|
|
@@ -6121,8 +6302,8 @@ function looksLikeMissingNavpackMessage(message) {
|
|
|
6121
6302
|
const lower = message.toLowerCase();
|
|
6122
6303
|
return lower.includes("has no navpack for this ref") || lower.includes("navpack was pruned") || lower.includes("indexedrepository row still claims current state");
|
|
6123
6304
|
}
|
|
6124
|
-
function handleCodeNavCommandError(error2, json, terminalRenderer, exitCode = 1) {
|
|
6125
|
-
const mapped = mapCodeNavigationError(error2);
|
|
6305
|
+
function handleCodeNavCommandError(error2, json, terminalRenderer, exitCode = 1, mapMappedError = (mapped) => mapped) {
|
|
6306
|
+
const mapped = mapMappedError(mapCodeNavigationError(error2));
|
|
6126
6307
|
if (json) {
|
|
6127
6308
|
console.error(JSON.stringify({
|
|
6128
6309
|
error: mapped.message,
|
|
@@ -6393,7 +6574,7 @@ grep run. --symbol-field hydrates enclosing symbol metadata (appears under each
|
|
|
6393
6574
|
match in --verbose output; full payload in --json).`;
|
|
6394
6575
|
function registerCodeGrepCommand(pkgCommand) {
|
|
6395
6576
|
return pkgCommand.command("grep").summary("Deterministic text grep over indexed dependency source").description(PKG_GREP_DESCRIPTION).argument("[spec-or-pattern]", "Spec mode: package spec (e.g. npm:express). Repo mode (with --repo-url): the pattern.").argument("[pattern-or-prefix]", "Spec mode: the pattern. Repo mode: optional path-prefix.").argument("[path-prefix]", "Spec mode only: optional path-prefix. Ignored with --repo-url.").option("--repo-url <url>", "Repository URL addressing (requires --git-ref)").option("--git-ref <ref>", "Tag, commit, branch, or HEAD. Required with --repo-url.").option("--path <path>", "Exact file path to grep").option("--glob <glob>", "Glob scope (repeatable)", collectRepeatable2, []).option("--ext <ext>", "Extension filter without leading dot (repeatable)", collectRepeatable2, []).option("--regex", "Interpret the pattern as RE2 regex").option("--case-sensitive", "Enable ASCII case-sensitive matching").option("-C, --context <n>", "Context lines before and after each match (0-10)").option("-B, --before-context <n>", "Context lines before each match (0-10)").option("-A, --after-context <n>", "Context lines after each match (0-10)").option("--exclude-docs", "Skip files classified as documentation").option("--exclude-tests", "Skip files classified as tests").option("--limit <n>", "Max matches to return on this page (1-1000, default 50)").option("--per-file-limit <n>", "Cap matches per file within this page (0-1000, 0 = unlimited)").option("--cursor <cursor>", "Opaque nextCursor from a previous grep result").option("--symbol-field <field>", `Repeatable; surfaces in --json and under each --verbose match. ${GREP_REPO_SYMBOL_FIELDS_NOTE}`, collectRepeatable2, []).option("--wait <ms>", `Indexing wait timeout (0-${MAX_WAIT_TIMEOUT_MS}, default ${DEFAULT_WAIT_TIMEOUT_MS})`).option("-v, --verbose", "Render grouped output with file headers").option("--json", "Emit the JSON envelope").action(async (arg1, arg2, arg3, options) => {
|
|
6396
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
6577
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-k35egwwf.js");
|
|
6397
6578
|
const deps = await createContainer2();
|
|
6398
6579
|
await pkgGrepAction(arg1, arg2, arg3, options, {
|
|
6399
6580
|
codeNavigationService: deps.codeNavigationService,
|
|
@@ -6404,6 +6585,36 @@ function registerCodeGrepCommand(pkgCommand) {
|
|
|
6404
6585
|
});
|
|
6405
6586
|
}
|
|
6406
6587
|
|
|
6588
|
+
// src/shared/read-file-error.ts
|
|
6589
|
+
function withReadFileRecovery(mapped, requestedPath) {
|
|
6590
|
+
if (mapped.code !== "FILE_NOT_FOUND" && mapped.code !== "NOT_FOUND") {
|
|
6591
|
+
return mapped;
|
|
6592
|
+
}
|
|
6593
|
+
return {
|
|
6594
|
+
...mapped,
|
|
6595
|
+
details: {
|
|
6596
|
+
...mapped.details,
|
|
6597
|
+
action: buildReadFileNotFoundAction(requestedPath)
|
|
6598
|
+
}
|
|
6599
|
+
};
|
|
6600
|
+
}
|
|
6601
|
+
function buildReadFileNotFoundAction(requestedPath) {
|
|
6602
|
+
const prefix = buildPathPrefixSuggestion(requestedPath);
|
|
6603
|
+
return "`code_read` reads files only, not directories. " + `Use \`code_files\` with \`path_prefix: ${JSON.stringify(prefix)}\` ` + "to list candidate files, then pass an emitted `path` back to `code_read`.";
|
|
6604
|
+
}
|
|
6605
|
+
function buildPathPrefixSuggestion(requestedPath) {
|
|
6606
|
+
const trimmed = requestedPath.trim();
|
|
6607
|
+
if (trimmed === "")
|
|
6608
|
+
return "";
|
|
6609
|
+
if (trimmed.endsWith("/"))
|
|
6610
|
+
return trimmed;
|
|
6611
|
+
const slash = trimmed.lastIndexOf("/");
|
|
6612
|
+
const basename = slash === -1 ? trimmed : trimmed.slice(slash + 1);
|
|
6613
|
+
if (!basename.includes("."))
|
|
6614
|
+
return `${trimmed}/`;
|
|
6615
|
+
return slash === -1 ? "" : trimmed.slice(0, slash + 1);
|
|
6616
|
+
}
|
|
6617
|
+
|
|
6407
6618
|
// src/shared/read-file-request.ts
|
|
6408
6619
|
var WAIT_MIN3 = 0;
|
|
6409
6620
|
var WAIT_MAX2 = 60000;
|
|
@@ -6412,6 +6623,9 @@ function buildReadFileParams(input) {
|
|
|
6412
6623
|
if (!filePath) {
|
|
6413
6624
|
throw new InvalidPackageSpecError("`file_path` is required — pass the path to the file within the package or repo.");
|
|
6414
6625
|
}
|
|
6626
|
+
if (filePath.endsWith("/")) {
|
|
6627
|
+
throw new InvalidPackageSpecError(`\`file_path\` must be an exact file path, not a directory prefix. Use \`code_files\` with \`path_prefix: ${JSON.stringify(filePath)}\` to list files, then pass an emitted \`path\` to \`code_read\`.`);
|
|
6628
|
+
}
|
|
6415
6629
|
const startLine = normaliseLine(input.startLine, "start_line");
|
|
6416
6630
|
const endLine = normaliseLine(input.endLine, "end_line");
|
|
6417
6631
|
if (startLine !== undefined && endLine !== undefined && startLine > endLine) {
|
|
@@ -6445,164 +6659,57 @@ function normaliseWaitTimeoutMs2(raw) {
|
|
|
6445
6659
|
return raw;
|
|
6446
6660
|
}
|
|
6447
6661
|
|
|
6448
|
-
// src/
|
|
6449
|
-
function
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6662
|
+
// src/commands/code/read.ts
|
|
6663
|
+
async function pkgReadAction(firstArg, secondArg, options, deps) {
|
|
6664
|
+
requireAuth(deps);
|
|
6665
|
+
let requestedFilePath = "";
|
|
6666
|
+
try {
|
|
6667
|
+
if (!deps.codeNavigationUrl || !deps.codeNavigationService) {
|
|
6668
|
+
throw new InvalidPackageSpecError("Code navigation is not configured for this environment.");
|
|
6669
|
+
}
|
|
6670
|
+
const hasRepoUrl = Boolean(options.repoUrl);
|
|
6671
|
+
const { spec, path } = resolvePositionals3(firstArg, secondArg, hasRepoUrl);
|
|
6672
|
+
if (!path || path.trim().length === 0) {
|
|
6673
|
+
throw new InvalidPackageSpecError("A <path> argument is required — pass the path to the file within the package or repo.");
|
|
6674
|
+
}
|
|
6675
|
+
const target = resolveCliCodeNavTarget(spec, options);
|
|
6676
|
+
const pathWithRange = parsePathWithOptionalRange(path.trim());
|
|
6677
|
+
requestedFilePath = pathWithRange.filePath;
|
|
6678
|
+
const range = resolveLineRange(options, pathWithRange);
|
|
6679
|
+
const wait = parseIntCliOption(options.wait, "--wait", 0, MAX_WAIT_TIMEOUT_MS);
|
|
6680
|
+
const build = buildReadFileParams({
|
|
6681
|
+
target,
|
|
6682
|
+
filePath: pathWithRange.filePath,
|
|
6683
|
+
startLine: range.startLine,
|
|
6684
|
+
endLine: range.endLine,
|
|
6685
|
+
waitTimeoutMs: wait
|
|
6686
|
+
});
|
|
6687
|
+
const result = await deps.codeNavigationService.readFile(build.params);
|
|
6688
|
+
const payload = buildReadFileSuccessPayload(result, {
|
|
6689
|
+
registry: target.registry ? toPkgseerRegistryLowercase(target.registry) : undefined,
|
|
6690
|
+
name: target.packageName,
|
|
6691
|
+
repoUrl: target.repoUrl,
|
|
6692
|
+
gitRef: target.gitRef,
|
|
6693
|
+
requestedFilePath: build.params.filePath
|
|
6694
|
+
});
|
|
6695
|
+
if (options.json) {
|
|
6696
|
+
console.log(JSON.stringify(payload));
|
|
6697
|
+
return;
|
|
6698
|
+
}
|
|
6699
|
+
process.stdout.write(formatReadFileTerminal(payload, {
|
|
6700
|
+
useColors: shouldUseColors(),
|
|
6701
|
+
verbose: options.verbose ?? false
|
|
6702
|
+
}));
|
|
6703
|
+
} catch (error2) {
|
|
6704
|
+
handleCodeNavCommandError(error2, options.json ?? false, formatFileErrorWithFilesHint, 1, (mapped) => withReadFileRecovery(mapped, requestedFilePath));
|
|
6473
6705
|
}
|
|
6474
|
-
return envelope;
|
|
6475
6706
|
}
|
|
6476
|
-
function
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
return formatNoContent(envelope, options, verbose);
|
|
6483
|
-
}
|
|
6484
|
-
if (!verbose) {
|
|
6485
|
-
return envelope.content;
|
|
6486
|
-
}
|
|
6487
|
-
return formatVerboseBody(envelope, options);
|
|
6488
|
-
}
|
|
6489
|
-
function formatBinary(envelope, options, verbose) {
|
|
6490
|
-
const sentinel = dim("Binary file — cannot display as text.", options.useColors);
|
|
6491
|
-
if (verbose) {
|
|
6492
|
-
return `${buildHeader9(envelope, options)}
|
|
6493
|
-
|
|
6494
|
-
${sentinel}
|
|
6495
|
-
`;
|
|
6496
|
-
}
|
|
6497
|
-
return `${sentinel}
|
|
6498
|
-
`;
|
|
6499
|
-
}
|
|
6500
|
-
function formatNoContent(envelope, options, verbose) {
|
|
6501
|
-
const sentinel = dim("(no content returned)", options.useColors);
|
|
6502
|
-
if (verbose) {
|
|
6503
|
-
return `${buildHeader9(envelope, options)}
|
|
6504
|
-
|
|
6505
|
-
${sentinel}
|
|
6506
|
-
`;
|
|
6507
|
-
}
|
|
6508
|
-
return `${sentinel}
|
|
6509
|
-
`;
|
|
6510
|
-
}
|
|
6511
|
-
function formatVerboseBody(envelope, options) {
|
|
6512
|
-
const lines = [];
|
|
6513
|
-
lines.push(buildHeader9(envelope, options));
|
|
6514
|
-
lines.push("");
|
|
6515
|
-
const content = envelope.content ?? "";
|
|
6516
|
-
const bodyLines = content.split(`
|
|
6517
|
-
`);
|
|
6518
|
-
if (bodyLines.length > 0 && bodyLines[bodyLines.length - 1] === "") {
|
|
6519
|
-
bodyLines.pop();
|
|
6520
|
-
}
|
|
6521
|
-
const startLine = envelope.startLine ?? 1;
|
|
6522
|
-
const endLine = startLine + bodyLines.length - 1;
|
|
6523
|
-
const gutterWidth = String(endLine).length;
|
|
6524
|
-
for (let i = 0;i < bodyLines.length; i++) {
|
|
6525
|
-
const lineNumber = startLine + i;
|
|
6526
|
-
const gutter = dim(String(lineNumber).padStart(gutterWidth, " "), options.useColors);
|
|
6527
|
-
lines.push(`${gutter} ${bodyLines[i]}`);
|
|
6528
|
-
}
|
|
6529
|
-
if (envelope.hint) {
|
|
6530
|
-
lines.push("");
|
|
6531
|
-
lines.push(dim(envelope.hint, options.useColors));
|
|
6532
|
-
}
|
|
6533
|
-
lines.push("");
|
|
6534
|
-
return lines.join(`
|
|
6535
|
-
`);
|
|
6536
|
-
}
|
|
6537
|
-
function buildHeader9(envelope, options) {
|
|
6538
|
-
const parts = [envelope.path];
|
|
6539
|
-
if (envelope.language)
|
|
6540
|
-
parts.push(envelope.language);
|
|
6541
|
-
const rangeLabel = buildRangeLabel(envelope);
|
|
6542
|
-
if (rangeLabel)
|
|
6543
|
-
parts.push(rangeLabel);
|
|
6544
|
-
return colorize(parts.join(" · "), "bold", options.useColors);
|
|
6545
|
-
}
|
|
6546
|
-
function buildRangeLabel(envelope) {
|
|
6547
|
-
const { startLine, endLine, totalLines } = envelope;
|
|
6548
|
-
if (startLine != null && endLine != null) {
|
|
6549
|
-
return totalLines != null ? `lines ${startLine}-${endLine} of ${totalLines}` : `lines ${startLine}-${endLine}`;
|
|
6550
|
-
}
|
|
6551
|
-
if (totalLines != null) {
|
|
6552
|
-
return `${totalLines} lines`;
|
|
6553
|
-
}
|
|
6554
|
-
return;
|
|
6555
|
-
}
|
|
6556
|
-
|
|
6557
|
-
// src/commands/code/read.ts
|
|
6558
|
-
async function pkgReadAction(firstArg, secondArg, options, deps) {
|
|
6559
|
-
requireAuth(deps);
|
|
6560
|
-
try {
|
|
6561
|
-
if (!deps.codeNavigationUrl || !deps.codeNavigationService) {
|
|
6562
|
-
throw new InvalidPackageSpecError("Code navigation is not configured for this environment.");
|
|
6563
|
-
}
|
|
6564
|
-
const hasRepoUrl = Boolean(options.repoUrl);
|
|
6565
|
-
const { spec, path } = resolvePositionals3(firstArg, secondArg, hasRepoUrl);
|
|
6566
|
-
if (!path || path.trim().length === 0) {
|
|
6567
|
-
throw new InvalidPackageSpecError("A <path> argument is required — pass the path to the file within the package or repo.");
|
|
6568
|
-
}
|
|
6569
|
-
const target = resolveCliCodeNavTarget(spec, options);
|
|
6570
|
-
const pathWithRange = parsePathWithOptionalRange(path.trim());
|
|
6571
|
-
const range = resolveLineRange(options, pathWithRange);
|
|
6572
|
-
const wait = parseIntCliOption(options.wait, "--wait", 0, MAX_WAIT_TIMEOUT_MS);
|
|
6573
|
-
const build = buildReadFileParams({
|
|
6574
|
-
target,
|
|
6575
|
-
filePath: pathWithRange.filePath,
|
|
6576
|
-
startLine: range.startLine,
|
|
6577
|
-
endLine: range.endLine,
|
|
6578
|
-
waitTimeoutMs: wait
|
|
6579
|
-
});
|
|
6580
|
-
const result = await deps.codeNavigationService.readFile(build.params);
|
|
6581
|
-
const payload = buildReadFileSuccessPayload(result, {
|
|
6582
|
-
registry: target.registry ? toPkgseerRegistryLowercase(target.registry) : undefined,
|
|
6583
|
-
name: target.packageName,
|
|
6584
|
-
repoUrl: target.repoUrl,
|
|
6585
|
-
gitRef: target.gitRef,
|
|
6586
|
-
requestedFilePath: build.params.filePath
|
|
6587
|
-
});
|
|
6588
|
-
if (options.json) {
|
|
6589
|
-
console.log(JSON.stringify(payload));
|
|
6590
|
-
return;
|
|
6591
|
-
}
|
|
6592
|
-
process.stdout.write(formatReadFileTerminal(payload, {
|
|
6593
|
-
useColors: shouldUseColors(),
|
|
6594
|
-
verbose: options.verbose ?? false
|
|
6595
|
-
}));
|
|
6596
|
-
} catch (error2) {
|
|
6597
|
-
handleCodeNavCommandError(error2, options.json ?? false, formatFileErrorWithFilesHint);
|
|
6598
|
-
}
|
|
6599
|
-
}
|
|
6600
|
-
function resolvePositionals3(firstArg, secondArg, hasRepoUrl) {
|
|
6601
|
-
if (hasRepoUrl) {
|
|
6602
|
-
if (secondArg !== undefined) {
|
|
6603
|
-
throw new InvalidPackageSpecError("In --repo-url mode, pass only the <path> positional — the package spec is replaced by --repo-url.");
|
|
6604
|
-
}
|
|
6605
|
-
return { spec: undefined, path: firstArg };
|
|
6707
|
+
function resolvePositionals3(firstArg, secondArg, hasRepoUrl) {
|
|
6708
|
+
if (hasRepoUrl) {
|
|
6709
|
+
if (secondArg !== undefined) {
|
|
6710
|
+
throw new InvalidPackageSpecError("In --repo-url mode, pass only the <path> positional — the package spec is replaced by --repo-url.");
|
|
6711
|
+
}
|
|
6712
|
+
return { spec: undefined, path: firstArg };
|
|
6606
6713
|
}
|
|
6607
6714
|
return { spec: firstArg, path: secondArg };
|
|
6608
6715
|
}
|
|
@@ -6927,7 +7034,7 @@ function registerExampleCommand(program) {
|
|
|
6927
7034
|
});
|
|
6928
7035
|
}
|
|
6929
7036
|
async function loadContainer() {
|
|
6930
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
7037
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-k35egwwf.js");
|
|
6931
7038
|
return createContainer2();
|
|
6932
7039
|
}
|
|
6933
7040
|
// src/commands/feedback.ts
|
|
@@ -7183,6 +7290,39 @@ function mergeServerConfig(existingContent, serversKey, serverName, serverConfig
|
|
|
7183
7290
|
`
|
|
7184
7291
|
};
|
|
7185
7292
|
}
|
|
7293
|
+
function removeServerConfig(existingContent, serversKey, serverName) {
|
|
7294
|
+
const parsedConfig = parseConfigObject(existingContent);
|
|
7295
|
+
if (parsedConfig.format === "invalid") {
|
|
7296
|
+
return {
|
|
7297
|
+
status: "parse_error",
|
|
7298
|
+
error: parsedConfig.error
|
|
7299
|
+
};
|
|
7300
|
+
}
|
|
7301
|
+
const config = parsedConfig.value;
|
|
7302
|
+
const servers = config[serversKey];
|
|
7303
|
+
if (servers === undefined) {
|
|
7304
|
+
return { status: "not_configured" };
|
|
7305
|
+
}
|
|
7306
|
+
if (typeof servers !== "object" || servers === null || Array.isArray(servers)) {
|
|
7307
|
+
return {
|
|
7308
|
+
status: "parse_error",
|
|
7309
|
+
error: `"${serversKey}" is not a JSON object`
|
|
7310
|
+
};
|
|
7311
|
+
}
|
|
7312
|
+
const serversObj = servers;
|
|
7313
|
+
const matchingKeys = getMatchingServerKeys(serversObj, serverName);
|
|
7314
|
+
if (matchingKeys.length === 0) {
|
|
7315
|
+
return { status: "not_configured" };
|
|
7316
|
+
}
|
|
7317
|
+
for (const key of matchingKeys) {
|
|
7318
|
+
delete serversObj[key];
|
|
7319
|
+
}
|
|
7320
|
+
return {
|
|
7321
|
+
status: "removed",
|
|
7322
|
+
content: `${JSON.stringify(config, null, 2)}
|
|
7323
|
+
`
|
|
7324
|
+
};
|
|
7325
|
+
}
|
|
7186
7326
|
function formatSetupPreview(config) {
|
|
7187
7327
|
if (config.method === "cli") {
|
|
7188
7328
|
return config.commands.map((cmd) => `Will run: ${cmd.command} ${cmd.args.join(" ")}`).join(`
|
|
@@ -7193,6 +7333,13 @@ function formatSetupPreview(config) {
|
|
|
7193
7333
|
|
|
7194
7334
|
${snippet}`;
|
|
7195
7335
|
}
|
|
7336
|
+
function formatUninstallPreview(config) {
|
|
7337
|
+
if (config.method === "cli") {
|
|
7338
|
+
return config.commands.map((cmd) => `Will run: ${cmd.command} ${cmd.args.join(" ")}`).join(`
|
|
7339
|
+
`);
|
|
7340
|
+
}
|
|
7341
|
+
return `Will remove ${config.serverName} from ${config.configPath}`;
|
|
7342
|
+
}
|
|
7196
7343
|
async function isAlreadyConfigured(config, fs) {
|
|
7197
7344
|
try {
|
|
7198
7345
|
const content = await fs.readFile(config.configPath);
|
|
@@ -7215,16 +7362,48 @@ async function isAlreadyConfigured(config, fs) {
|
|
|
7215
7362
|
return false;
|
|
7216
7363
|
}
|
|
7217
7364
|
}
|
|
7365
|
+
async function getConfigUninstallCheckStatus(config, fs) {
|
|
7366
|
+
try {
|
|
7367
|
+
const content = await fs.readFile(config.configPath);
|
|
7368
|
+
const parsedConfig = parseConfigObject(content);
|
|
7369
|
+
if (parsedConfig.format === "invalid") {
|
|
7370
|
+
return {
|
|
7371
|
+
status: "failed",
|
|
7372
|
+
message: `Cannot parse ${config.configPath}: ${parsedConfig.error}. File left unchanged.`
|
|
7373
|
+
};
|
|
7374
|
+
}
|
|
7375
|
+
const servers = parsedConfig.value[config.serversKey];
|
|
7376
|
+
if (servers === undefined) {
|
|
7377
|
+
return { status: "not_configured" };
|
|
7378
|
+
}
|
|
7379
|
+
if (typeof servers !== "object" || servers === null || Array.isArray(servers)) {
|
|
7380
|
+
return {
|
|
7381
|
+
status: "failed",
|
|
7382
|
+
message: `Cannot parse ${config.configPath}: "${config.serversKey}" is not a JSON object. File left unchanged.`
|
|
7383
|
+
};
|
|
7384
|
+
}
|
|
7385
|
+
const hasEntry = getMatchingServerKeys(servers, config.serverName).length > 0;
|
|
7386
|
+
return { status: hasEntry ? "configured" : "not_configured" };
|
|
7387
|
+
} catch (err) {
|
|
7388
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
7389
|
+
return { status: "not_configured" };
|
|
7390
|
+
}
|
|
7391
|
+
return {
|
|
7392
|
+
status: "failed",
|
|
7393
|
+
message: `Cannot read ${config.configPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
7394
|
+
};
|
|
7395
|
+
}
|
|
7396
|
+
}
|
|
7218
7397
|
async function getCliCheckStatus(check, execService) {
|
|
7219
7398
|
try {
|
|
7220
7399
|
const result = await execService.exec(check.command, check.args);
|
|
7221
|
-
if (check.requireExitCodeZero && result.exitCode !== 0) {
|
|
7222
|
-
return "probe_failed";
|
|
7223
|
-
}
|
|
7224
7400
|
const combined = `${result.stdout} ${result.stderr}`;
|
|
7225
7401
|
if (check.notConfiguredPattern?.test(combined)) {
|
|
7226
7402
|
return "not_configured";
|
|
7227
7403
|
}
|
|
7404
|
+
if (check.requireExitCodeZero && result.exitCode !== 0) {
|
|
7405
|
+
return "probe_failed";
|
|
7406
|
+
}
|
|
7228
7407
|
if (check.configuredPattern) {
|
|
7229
7408
|
return check.configuredPattern.test(combined) ? "configured" : "not_configured";
|
|
7230
7409
|
}
|
|
@@ -7242,9 +7421,18 @@ var ALREADY_EXISTS_PATTERNS = [
|
|
|
7242
7421
|
/already added/i,
|
|
7243
7422
|
/extension\s+"githits"\s+is\s+already\s+installed/i
|
|
7244
7423
|
];
|
|
7424
|
+
var ALREADY_ABSENT_PATTERNS = [
|
|
7425
|
+
/(?:plugin|extension|server|mcp server)\s+["']?githits["']?\s+(?:was\s+)?not\s+found/i,
|
|
7426
|
+
/["']?githits["']?\s+(?:plugin|extension|server)?\s*(?:does\s+not\s+exist|is\s+not\s+installed|not\s+installed)/i,
|
|
7427
|
+
/unknown\s+(?:plugin|extension|server)\s+["']?githits["']?/i,
|
|
7428
|
+
/marketplace\s+["']?githits-plugins["']?\s+(?:was\s+)?not\s+found/i
|
|
7429
|
+
];
|
|
7245
7430
|
function isAlreadyConfiguredOutput(output) {
|
|
7246
7431
|
return ALREADY_EXISTS_PATTERNS.some((pattern) => pattern.test(output));
|
|
7247
7432
|
}
|
|
7433
|
+
function isAlreadyAbsentOutput(output) {
|
|
7434
|
+
return ALREADY_ABSENT_PATTERNS.some((pattern) => pattern.test(output));
|
|
7435
|
+
}
|
|
7248
7436
|
async function executeCliCommand(cmd, execService) {
|
|
7249
7437
|
try {
|
|
7250
7438
|
const result = await execService.exec(cmd.command, cmd.args);
|
|
@@ -7276,6 +7464,37 @@ async function executeCliCommand(cmd, execService) {
|
|
|
7276
7464
|
};
|
|
7277
7465
|
}
|
|
7278
7466
|
}
|
|
7467
|
+
async function executeCliUninstallCommand(cmd, execService) {
|
|
7468
|
+
try {
|
|
7469
|
+
const result = await execService.exec(cmd.command, cmd.args);
|
|
7470
|
+
const combined = `${result.stdout} ${result.stderr}`;
|
|
7471
|
+
if (result.exitCode === 0) {
|
|
7472
|
+
return { status: "removed", message: "Removed successfully" };
|
|
7473
|
+
}
|
|
7474
|
+
if (isAlreadyAbsentOutput(combined)) {
|
|
7475
|
+
return {
|
|
7476
|
+
status: "not_configured",
|
|
7477
|
+
message: `GitHits not configured via ${cmd.command}`
|
|
7478
|
+
};
|
|
7479
|
+
}
|
|
7480
|
+
const detail = result.stderr.trim() || result.stdout.trim();
|
|
7481
|
+
return {
|
|
7482
|
+
status: "failed",
|
|
7483
|
+
message: `Command exited with code ${result.exitCode}${detail ? `: ${detail}` : ""}`
|
|
7484
|
+
};
|
|
7485
|
+
} catch (err) {
|
|
7486
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
7487
|
+
return {
|
|
7488
|
+
status: "failed",
|
|
7489
|
+
message: `"${cmd.command}" not found on PATH. Install it or remove GitHits manually.`
|
|
7490
|
+
};
|
|
7491
|
+
}
|
|
7492
|
+
return {
|
|
7493
|
+
status: "failed",
|
|
7494
|
+
message: `Failed to run command: ${err instanceof Error ? err.message : String(err)}`
|
|
7495
|
+
};
|
|
7496
|
+
}
|
|
7497
|
+
}
|
|
7279
7498
|
async function executeCliSetup(setup, execService) {
|
|
7280
7499
|
let anyAlreadyConfigured = false;
|
|
7281
7500
|
for (const cmd of setup.commands) {
|
|
@@ -7295,6 +7514,52 @@ async function executeCliSetup(setup, execService) {
|
|
|
7295
7514
|
}
|
|
7296
7515
|
return { status: "success", message: "Configured successfully" };
|
|
7297
7516
|
}
|
|
7517
|
+
async function executeCliUninstall(uninstall, execService) {
|
|
7518
|
+
if (uninstall.commands.length === 0) {
|
|
7519
|
+
return {
|
|
7520
|
+
status: "failed",
|
|
7521
|
+
message: "No uninstall commands configured."
|
|
7522
|
+
};
|
|
7523
|
+
}
|
|
7524
|
+
let anyRemoved = false;
|
|
7525
|
+
let anyNotConfigured = false;
|
|
7526
|
+
const warnings = [];
|
|
7527
|
+
for (let index = 0;index < uninstall.commands.length; index += 1) {
|
|
7528
|
+
const cmd = uninstall.commands[index];
|
|
7529
|
+
const result = await executeCliUninstallCommand(cmd, execService);
|
|
7530
|
+
if (result.status === "failed") {
|
|
7531
|
+
if (anyRemoved) {
|
|
7532
|
+
warnings.push(result.message);
|
|
7533
|
+
continue;
|
|
7534
|
+
}
|
|
7535
|
+
return result;
|
|
7536
|
+
}
|
|
7537
|
+
if (result.status === "removed") {
|
|
7538
|
+
anyRemoved = true;
|
|
7539
|
+
}
|
|
7540
|
+
if (result.status === "not_configured") {
|
|
7541
|
+
if (anyRemoved) {
|
|
7542
|
+
warnings.push(result.message);
|
|
7543
|
+
continue;
|
|
7544
|
+
}
|
|
7545
|
+
anyNotConfigured = true;
|
|
7546
|
+
}
|
|
7547
|
+
}
|
|
7548
|
+
if (anyRemoved) {
|
|
7549
|
+
return {
|
|
7550
|
+
status: "removed",
|
|
7551
|
+
message: "Removed successfully",
|
|
7552
|
+
warnings: warnings.length > 0 ? warnings : undefined
|
|
7553
|
+
};
|
|
7554
|
+
}
|
|
7555
|
+
if (anyNotConfigured) {
|
|
7556
|
+
return {
|
|
7557
|
+
status: "not_configured",
|
|
7558
|
+
message: `GitHits not configured via ${uninstall.commands[0]?.command}`
|
|
7559
|
+
};
|
|
7560
|
+
}
|
|
7561
|
+
return { status: "removed", message: "Removed successfully" };
|
|
7562
|
+
}
|
|
7298
7563
|
async function executeConfigFileSetup(setup, fs) {
|
|
7299
7564
|
try {
|
|
7300
7565
|
const parentDir = fs.getDirname(setup.configPath);
|
|
@@ -7338,6 +7603,51 @@ async function executeConfigFileSetup(setup, fs) {
|
|
|
7338
7603
|
};
|
|
7339
7604
|
}
|
|
7340
7605
|
}
|
|
7606
|
+
async function executeConfigFileUninstall(setup, fs) {
|
|
7607
|
+
try {
|
|
7608
|
+
let existingContent = "";
|
|
7609
|
+
try {
|
|
7610
|
+
existingContent = await fs.readFile(setup.configPath);
|
|
7611
|
+
} catch (err) {
|
|
7612
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
7613
|
+
return {
|
|
7614
|
+
status: "not_configured",
|
|
7615
|
+
message: `GitHits not configured in ${setup.configPath}`
|
|
7616
|
+
};
|
|
7617
|
+
}
|
|
7618
|
+
return {
|
|
7619
|
+
status: "failed",
|
|
7620
|
+
message: `Cannot read ${setup.configPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
7621
|
+
};
|
|
7622
|
+
}
|
|
7623
|
+
const result = removeServerConfig(existingContent, setup.serversKey, setup.serverName);
|
|
7624
|
+
if (result.status === "not_configured") {
|
|
7625
|
+
return {
|
|
7626
|
+
status: "not_configured",
|
|
7627
|
+
message: `GitHits not configured in ${setup.configPath}`
|
|
7628
|
+
};
|
|
7629
|
+
}
|
|
7630
|
+
if (result.status === "parse_error") {
|
|
7631
|
+
return {
|
|
7632
|
+
status: "failed",
|
|
7633
|
+
message: `Cannot parse ${setup.configPath}: ${result.error}. File left unchanged.`
|
|
7634
|
+
};
|
|
7635
|
+
}
|
|
7636
|
+
await fs.atomicWriteFile(setup.configPath, result.content);
|
|
7637
|
+
return { status: "removed", message: "Removed successfully" };
|
|
7638
|
+
} catch (err) {
|
|
7639
|
+
if (err instanceof Error && "code" in err && err.code === "EACCES") {
|
|
7640
|
+
return {
|
|
7641
|
+
status: "failed",
|
|
7642
|
+
message: `Permission denied writing to ${setup.configPath}. Check file permissions.`
|
|
7643
|
+
};
|
|
7644
|
+
}
|
|
7645
|
+
return {
|
|
7646
|
+
status: "failed",
|
|
7647
|
+
message: `Failed to uninstall: ${err instanceof Error ? err.message : String(err)}`
|
|
7648
|
+
};
|
|
7649
|
+
}
|
|
7650
|
+
}
|
|
7341
7651
|
|
|
7342
7652
|
// src/commands/init/agent-definitions.ts
|
|
7343
7653
|
var GITHITS_SERVER_NAME = "GitHits";
|
|
@@ -7347,6 +7657,10 @@ var GITHITS_MCP_INVOCATION = [
|
|
|
7347
7657
|
GITHITS_MCP_COMMAND,
|
|
7348
7658
|
...GITHITS_MCP_ARGS
|
|
7349
7659
|
];
|
|
7660
|
+
var CLAUDE_GITHITS_PLUGIN = "githits";
|
|
7661
|
+
var CLAUDE_GITHITS_MARKETPLACE = "githits-plugins";
|
|
7662
|
+
var CLAUDE_GITHITS_PLUGIN_REF = `${CLAUDE_GITHITS_PLUGIN}@${CLAUDE_GITHITS_MARKETPLACE}`;
|
|
7663
|
+
var CLAUDE_GITHITS_MARKETPLACE_SOURCE = "githits-com/githits-cli";
|
|
7350
7664
|
function getAppDataPath(fs, appName) {
|
|
7351
7665
|
const home = fs.getHomeDir();
|
|
7352
7666
|
switch (process.platform) {
|
|
@@ -7404,18 +7718,36 @@ var claudeCode = {
|
|
|
7404
7718
|
commands: [
|
|
7405
7719
|
{
|
|
7406
7720
|
command: "claude",
|
|
7407
|
-
args: [
|
|
7721
|
+
args: [
|
|
7722
|
+
"plugin",
|
|
7723
|
+
"marketplace",
|
|
7724
|
+
"add",
|
|
7725
|
+
CLAUDE_GITHITS_MARKETPLACE_SOURCE
|
|
7726
|
+
]
|
|
7408
7727
|
},
|
|
7409
7728
|
{
|
|
7410
7729
|
command: "claude",
|
|
7411
|
-
args: ["plugin", "install",
|
|
7730
|
+
args: ["plugin", "install", CLAUDE_GITHITS_PLUGIN_REF]
|
|
7412
7731
|
}
|
|
7413
7732
|
],
|
|
7414
7733
|
checkCommand: {
|
|
7415
7734
|
command: "claude",
|
|
7416
7735
|
args: ["plugin", "list"],
|
|
7417
|
-
configuredPattern: /githits/i
|
|
7736
|
+
configuredPattern: /(^|\s)githits@githits-plugins\b/i
|
|
7418
7737
|
}
|
|
7738
|
+
}),
|
|
7739
|
+
getUninstallConfig: () => ({
|
|
7740
|
+
method: "cli",
|
|
7741
|
+
commands: [
|
|
7742
|
+
{
|
|
7743
|
+
command: "claude",
|
|
7744
|
+
args: ["plugin", "uninstall", CLAUDE_GITHITS_PLUGIN]
|
|
7745
|
+
},
|
|
7746
|
+
{
|
|
7747
|
+
command: "claude",
|
|
7748
|
+
args: ["plugin", "marketplace", "remove", CLAUDE_GITHITS_MARKETPLACE]
|
|
7749
|
+
}
|
|
7750
|
+
]
|
|
7419
7751
|
})
|
|
7420
7752
|
};
|
|
7421
7753
|
var cursor = {
|
|
@@ -7501,8 +7833,17 @@ var codexCli = {
|
|
|
7501
7833
|
checkCommand: {
|
|
7502
7834
|
command: "codex",
|
|
7503
7835
|
args: ["mcp", "list"],
|
|
7504
|
-
configuredPattern:
|
|
7836
|
+
configuredPattern: /^\s*githits\b/im
|
|
7505
7837
|
}
|
|
7838
|
+
}),
|
|
7839
|
+
getUninstallConfig: () => ({
|
|
7840
|
+
method: "cli",
|
|
7841
|
+
commands: [
|
|
7842
|
+
{
|
|
7843
|
+
command: "codex",
|
|
7844
|
+
args: ["mcp", "remove", "githits"]
|
|
7845
|
+
}
|
|
7846
|
+
]
|
|
7506
7847
|
})
|
|
7507
7848
|
};
|
|
7508
7849
|
var vscode = {
|
|
@@ -7570,6 +7911,15 @@ var geminiCli = {
|
|
|
7570
7911
|
notConfiguredPattern: /not installed/i,
|
|
7571
7912
|
requireExitCodeZero: true
|
|
7572
7913
|
}
|
|
7914
|
+
}),
|
|
7915
|
+
getUninstallConfig: () => ({
|
|
7916
|
+
method: "cli",
|
|
7917
|
+
commands: [
|
|
7918
|
+
{
|
|
7919
|
+
command: "gemini",
|
|
7920
|
+
args: ["extensions", "uninstall", "githits"]
|
|
7921
|
+
}
|
|
7922
|
+
]
|
|
7573
7923
|
})
|
|
7574
7924
|
};
|
|
7575
7925
|
async function isGeminiExtensionInstalledFromFilesystem(fs) {
|
|
@@ -7721,6 +8071,90 @@ async function verifyAgentConfigured(agent, fileSystemService, execService) {
|
|
|
7721
8071
|
message: `${agent.name} verification failed: agent not detected after setup.`
|
|
7722
8072
|
};
|
|
7723
8073
|
}
|
|
8074
|
+
async function verifyAgentUnconfigured(agent, fileSystemService, execService) {
|
|
8075
|
+
const postCheck = await scanAgents([agent], fileSystemService, execService);
|
|
8076
|
+
if (postCheck.needsSetup.some((a) => a.id === agent.id)) {
|
|
8077
|
+
return { ok: true };
|
|
8078
|
+
}
|
|
8079
|
+
if (postCheck.notDetected.some((a) => a.id === agent.id)) {
|
|
8080
|
+
return {
|
|
8081
|
+
ok: false,
|
|
8082
|
+
message: `${agent.name} verification failed: agent was not detected after uninstall, so removal could not be confirmed.`
|
|
8083
|
+
};
|
|
8084
|
+
}
|
|
8085
|
+
return {
|
|
8086
|
+
ok: false,
|
|
8087
|
+
message: `${agent.name} verification failed: still configured after uninstall.`
|
|
8088
|
+
};
|
|
8089
|
+
}
|
|
8090
|
+
async function scanCliAgentForUninstall(agent, fileSystemService, execService) {
|
|
8091
|
+
const config = agent.getSetupConfig(fileSystemService);
|
|
8092
|
+
if (config.method !== "cli" || !config.checkCommand) {
|
|
8093
|
+
return {
|
|
8094
|
+
status: "failed",
|
|
8095
|
+
message: `${agent.name} does not have a verified uninstall check command.`
|
|
8096
|
+
};
|
|
8097
|
+
}
|
|
8098
|
+
const checkStatus = await getCliCheckStatus(config.checkCommand, execService);
|
|
8099
|
+
if (checkStatus === "configured") {
|
|
8100
|
+
return "configured";
|
|
8101
|
+
}
|
|
8102
|
+
if (checkStatus === "not_configured") {
|
|
8103
|
+
return "not_configured";
|
|
8104
|
+
}
|
|
8105
|
+
if (agent.id === "gemini-cli" && await isGeminiExtensionInstalledFromFilesystem(fileSystemService)) {
|
|
8106
|
+
return "configured";
|
|
8107
|
+
}
|
|
8108
|
+
return {
|
|
8109
|
+
status: "failed",
|
|
8110
|
+
message: `Cannot inspect ${agent.name}: ${config.checkCommand.command} ${config.checkCommand.args.join(" ")} failed.`
|
|
8111
|
+
};
|
|
8112
|
+
}
|
|
8113
|
+
async function scanAgentsForUninstall(fileSystemService, execService) {
|
|
8114
|
+
const setupScan = await scanAgents(agentDefinitions, fileSystemService, execService);
|
|
8115
|
+
const result = {
|
|
8116
|
+
configured: [],
|
|
8117
|
+
notConfigured: [],
|
|
8118
|
+
notDetected: setupScan.notDetected,
|
|
8119
|
+
failed: []
|
|
8120
|
+
};
|
|
8121
|
+
for (const agent of [
|
|
8122
|
+
...setupScan.alreadyConfigured,
|
|
8123
|
+
...setupScan.needsSetup
|
|
8124
|
+
]) {
|
|
8125
|
+
const config = agent.getSetupConfig(fileSystemService);
|
|
8126
|
+
if (config.method === "config-file") {
|
|
8127
|
+
const check = await getConfigUninstallCheckStatus(config, fileSystemService);
|
|
8128
|
+
if (check.status === "configured") {
|
|
8129
|
+
result.configured.push(agent);
|
|
8130
|
+
} else if (check.status === "failed") {
|
|
8131
|
+
result.failed.push({
|
|
8132
|
+
id: agent.id,
|
|
8133
|
+
name: agent.name,
|
|
8134
|
+
status: "failed",
|
|
8135
|
+
message: check.message
|
|
8136
|
+
});
|
|
8137
|
+
} else {
|
|
8138
|
+
result.notConfigured.push(agent);
|
|
8139
|
+
}
|
|
8140
|
+
} else {
|
|
8141
|
+
const check = await scanCliAgentForUninstall(agent, fileSystemService, execService);
|
|
8142
|
+
if (check === "configured") {
|
|
8143
|
+
result.configured.push(agent);
|
|
8144
|
+
} else if (check === "not_configured") {
|
|
8145
|
+
result.notConfigured.push(agent);
|
|
8146
|
+
} else {
|
|
8147
|
+
result.failed.push({
|
|
8148
|
+
id: agent.id,
|
|
8149
|
+
name: agent.name,
|
|
8150
|
+
status: "failed",
|
|
8151
|
+
message: check.message
|
|
8152
|
+
});
|
|
8153
|
+
}
|
|
8154
|
+
}
|
|
8155
|
+
}
|
|
8156
|
+
return result;
|
|
8157
|
+
}
|
|
7724
8158
|
async function initAction(options, deps) {
|
|
7725
8159
|
const useColors = shouldUseColors();
|
|
7726
8160
|
const { fileSystemService, promptService, execService, createLoginDeps } = deps;
|
|
@@ -7886,6 +8320,147 @@ async function initAction(options, deps) {
|
|
|
7886
8320
|
}
|
|
7887
8321
|
console.log();
|
|
7888
8322
|
}
|
|
8323
|
+
async function initUninstallAction(options, deps) {
|
|
8324
|
+
const useColors = shouldUseColors();
|
|
8325
|
+
const { fileSystemService, promptService, execService } = deps;
|
|
8326
|
+
console.log(`
|
|
8327
|
+
${colorize("GitHits", "bold", useColors)} — Remove MCP server from your coding agents
|
|
8328
|
+
`);
|
|
8329
|
+
console.log(` Scanning for configured agents...
|
|
8330
|
+
`);
|
|
8331
|
+
const scan = await scanAgentsForUninstall(fileSystemService, execService);
|
|
8332
|
+
for (const agent of scan.configured) {
|
|
8333
|
+
console.log(` ${colorize(`● ${agent.name} — configured`, "cyan", useColors)}`);
|
|
8334
|
+
}
|
|
8335
|
+
for (const agent of scan.notConfigured) {
|
|
8336
|
+
console.log(` ${warning(`${agent.name} — not configured`, useColors)}`);
|
|
8337
|
+
}
|
|
8338
|
+
for (const outcome of scan.failed) {
|
|
8339
|
+
console.log(` ${error(`${outcome.name} — cannot inspect config`, useColors)}`);
|
|
8340
|
+
}
|
|
8341
|
+
for (const agent of scan.notDetected) {
|
|
8342
|
+
console.log(` ${colorize(`${agent.name} — not detected`, "dim", useColors)}`);
|
|
8343
|
+
}
|
|
8344
|
+
console.log();
|
|
8345
|
+
if (scan.configured.length === 0 && scan.failed.length === 0) {
|
|
8346
|
+
console.log(` No GitHits MCP configurations found. Nothing to uninstall.
|
|
8347
|
+
`);
|
|
8348
|
+
return;
|
|
8349
|
+
}
|
|
8350
|
+
const outcomes = [...scan.failed];
|
|
8351
|
+
let alwaysMode = options.yes ?? false;
|
|
8352
|
+
for (const agent of scan.configured) {
|
|
8353
|
+
console.log(` Uninstalling from ${colorize(agent.name, "bold", useColors)}...
|
|
8354
|
+
`);
|
|
8355
|
+
const setupConfig = agent.getSetupConfig(fileSystemService);
|
|
8356
|
+
const uninstallConfig = setupConfig.method === "config-file" ? setupConfig : agent.getUninstallConfig?.(fileSystemService);
|
|
8357
|
+
if (!uninstallConfig) {
|
|
8358
|
+
outcomes.push({
|
|
8359
|
+
id: agent.id,
|
|
8360
|
+
name: agent.name,
|
|
8361
|
+
status: "failed",
|
|
8362
|
+
message: `${agent.name} does not have a verified uninstall command.`
|
|
8363
|
+
});
|
|
8364
|
+
console.log(` ${error(`${agent.name} does not have a verified uninstall command.`, useColors)}
|
|
8365
|
+
`);
|
|
8366
|
+
continue;
|
|
8367
|
+
}
|
|
8368
|
+
const preview = formatUninstallPreview(uninstallConfig);
|
|
8369
|
+
for (const line of preview.split(`
|
|
8370
|
+
`)) {
|
|
8371
|
+
console.log(` ${line}`);
|
|
8372
|
+
}
|
|
8373
|
+
console.log();
|
|
8374
|
+
if (!alwaysMode) {
|
|
8375
|
+
let choice;
|
|
8376
|
+
try {
|
|
8377
|
+
choice = await promptService.confirm3("Proceed?");
|
|
8378
|
+
} catch (err) {
|
|
8379
|
+
if (err instanceof ExitPromptError) {
|
|
8380
|
+
console.log(`
|
|
8381
|
+
Uninstall cancelled.
|
|
8382
|
+
`);
|
|
8383
|
+
return;
|
|
8384
|
+
}
|
|
8385
|
+
throw err;
|
|
8386
|
+
}
|
|
8387
|
+
if (choice === "no") {
|
|
8388
|
+
outcomes.push({ id: agent.id, name: agent.name, status: "skipped" });
|
|
8389
|
+
console.log();
|
|
8390
|
+
continue;
|
|
8391
|
+
}
|
|
8392
|
+
if (choice === "always") {
|
|
8393
|
+
alwaysMode = true;
|
|
8394
|
+
}
|
|
8395
|
+
}
|
|
8396
|
+
let result = uninstallConfig.method === "cli" ? await executeCliUninstall(uninstallConfig, execService) : await executeConfigFileUninstall(uninstallConfig, fileSystemService);
|
|
8397
|
+
if (result.status === "removed") {
|
|
8398
|
+
const verification = await verifyAgentUnconfigured(agent, fileSystemService, execService);
|
|
8399
|
+
if (!verification.ok) {
|
|
8400
|
+
result = {
|
|
8401
|
+
status: "failed",
|
|
8402
|
+
message: verification.message ?? `${agent.name} verification failed after uninstall.`,
|
|
8403
|
+
warnings: result.warnings
|
|
8404
|
+
};
|
|
8405
|
+
}
|
|
8406
|
+
}
|
|
8407
|
+
outcomes.push({
|
|
8408
|
+
id: agent.id,
|
|
8409
|
+
name: agent.name,
|
|
8410
|
+
status: result.status,
|
|
8411
|
+
message: result.status === "failed" ? result.message : undefined,
|
|
8412
|
+
warnings: result.warnings
|
|
8413
|
+
});
|
|
8414
|
+
if (result.status === "removed") {
|
|
8415
|
+
console.log(` ${success(`${agent.name} removed`, useColors)}
|
|
8416
|
+
`);
|
|
8417
|
+
for (const warn of result.warnings ?? []) {
|
|
8418
|
+
console.log(` ${warning(`Warning: ${warn}`, useColors)}`);
|
|
8419
|
+
}
|
|
8420
|
+
} else if (result.status === "not_configured") {
|
|
8421
|
+
console.log(` ${warning(`${agent.name} was not configured`, useColors)}
|
|
8422
|
+
`);
|
|
8423
|
+
} else {
|
|
8424
|
+
console.log(` ${error(result.message, useColors)}
|
|
8425
|
+
`);
|
|
8426
|
+
for (const warn of result.warnings ?? []) {
|
|
8427
|
+
console.log(` ${warning(`Warning: ${warn}`, useColors)}`);
|
|
8428
|
+
}
|
|
8429
|
+
}
|
|
8430
|
+
}
|
|
8431
|
+
const removed = outcomes.filter((o) => o.status === "removed").length;
|
|
8432
|
+
const notConfigured = outcomes.filter((o) => o.status === "not_configured").length + scan.notConfigured.length;
|
|
8433
|
+
const failed = outcomes.filter((o) => o.status === "failed").length;
|
|
8434
|
+
const skipped = outcomes.filter((o) => o.status === "skipped").length;
|
|
8435
|
+
if (failed > 0) {
|
|
8436
|
+
console.log(" Uninstall completed with errors.");
|
|
8437
|
+
} else if (removed > 0) {
|
|
8438
|
+
console.log(" Done! GitHits MCP configuration was removed.");
|
|
8439
|
+
} else if (skipped > 0) {
|
|
8440
|
+
console.log(" Uninstall skipped.");
|
|
8441
|
+
} else if (notConfigured > 0) {
|
|
8442
|
+
console.log(" No GitHits MCP configurations were active. Nothing to remove.");
|
|
8443
|
+
}
|
|
8444
|
+
if (removed > 0) {
|
|
8445
|
+
console.log(` ${removed} agent${removed !== 1 ? "s" : ""} removed.`);
|
|
8446
|
+
}
|
|
8447
|
+
if (notConfigured > 0) {
|
|
8448
|
+
console.log(` ${notConfigured} agent${notConfigured !== 1 ? "s" : ""} not configured.`);
|
|
8449
|
+
}
|
|
8450
|
+
if (skipped > 0) {
|
|
8451
|
+
console.log(` ${skipped} agent${skipped !== 1 ? "s" : ""} skipped.`);
|
|
8452
|
+
}
|
|
8453
|
+
if (failed > 0) {
|
|
8454
|
+
console.log(` ${failed} agent${failed !== 1 ? "s" : ""} failed to uninstall.`);
|
|
8455
|
+
for (const outcome of outcomes.filter((o) => o.status === "failed")) {
|
|
8456
|
+
console.log(` - ${outcome.name}: ${outcome.message ?? "Unknown error"}`);
|
|
8457
|
+
for (const warn of outcome.warnings ?? []) {
|
|
8458
|
+
console.log(` Warning: ${warn}`);
|
|
8459
|
+
}
|
|
8460
|
+
}
|
|
8461
|
+
}
|
|
8462
|
+
console.log();
|
|
8463
|
+
}
|
|
7889
8464
|
function printAuthRecoveryHint() {
|
|
7890
8465
|
console.log(" You can still configure MCP, but GitHits tools will require auth.");
|
|
7891
8466
|
console.log(" Recovery steps:");
|
|
@@ -7905,8 +8480,13 @@ and sets up unconfigured ones with your confirmation.
|
|
|
7905
8480
|
Supports CLI-based setup (Claude Code, Codex, Gemini CLI) and config
|
|
7906
8481
|
file editing (Cursor, Windsurf, VS Code, Cline, Claude Desktop,
|
|
7907
8482
|
Google Antigravity) with atomic writes.`;
|
|
8483
|
+
var INIT_UNINSTALL_DESCRIPTION = `Remove GitHits MCP server configuration from your coding agents.
|
|
8484
|
+
|
|
8485
|
+
Scans for available agents that currently have GitHits configured, then removes
|
|
8486
|
+
only the GitHits MCP/plugin configuration with your confirmation. Authentication
|
|
8487
|
+
tokens are not removed; use \`githits logout\` to remove stored credentials.`;
|
|
7908
8488
|
function registerInitCommand(program) {
|
|
7909
|
-
program.command("init").summary("Set up MCP server for your coding agents").description(INIT_DESCRIPTION).option("-y, --yes", "Skip prompts, configure all detected agents").option("--skip-login", "Skip authentication step").action(async (options) => {
|
|
8489
|
+
const initCommand = program.command("init").summary("Set up MCP server for your coding agents").description(INIT_DESCRIPTION).option("-y, --yes", "Skip prompts, configure all detected agents").option("--skip-login", "Skip authentication step").action(async (options) => {
|
|
7910
8490
|
const fileSystemService = new FileSystemServiceImpl;
|
|
7911
8491
|
const promptService = new PromptServiceImpl;
|
|
7912
8492
|
const execService = new ExecServiceImpl;
|
|
@@ -7917,6 +8497,16 @@ function registerInitCommand(program) {
|
|
|
7917
8497
|
createLoginDeps: () => createAuthCommandDependencies()
|
|
7918
8498
|
});
|
|
7919
8499
|
});
|
|
8500
|
+
initCommand.command("uninstall").summary("Remove MCP server from your coding agents").description(INIT_UNINSTALL_DESCRIPTION).option("-y, --yes", "Skip prompts, uninstall from all configured agents").action(async (options) => {
|
|
8501
|
+
const fileSystemService = new FileSystemServiceImpl;
|
|
8502
|
+
const promptService = new PromptServiceImpl;
|
|
8503
|
+
const execService = new ExecServiceImpl;
|
|
8504
|
+
await initUninstallAction(options, {
|
|
8505
|
+
fileSystemService,
|
|
8506
|
+
promptService,
|
|
8507
|
+
execService
|
|
8508
|
+
});
|
|
8509
|
+
});
|
|
7920
8510
|
}
|
|
7921
8511
|
// src/commands/languages.ts
|
|
7922
8512
|
async function languagesAction(query, options, deps) {
|
|
@@ -8178,7 +8768,7 @@ function invalidTargetResult(message) {
|
|
|
8178
8768
|
// src/tools/grep-repo.ts
|
|
8179
8769
|
var schema3 = {
|
|
8180
8770
|
target: codeTargetSchema,
|
|
8181
|
-
pattern: z4.string().describe(GREP_REPO_PATTERN_NOTE),
|
|
8771
|
+
pattern: z4.string().optional().describe(GREP_REPO_PATTERN_NOTE),
|
|
8182
8772
|
path: z4.string().optional().describe("Exact file path to grep. Shares the same path vocabulary as `code_read`."),
|
|
8183
8773
|
path_prefix: z4.string().optional().describe("Literal directory prefix to scope grep, matching `code_files` / `search` naming."),
|
|
8184
8774
|
globs: z4.array(z4.string()).optional().describe("Repeatable glob scopes with real glob semantics (e.g. `src/**/*.ts`)."),
|
|
@@ -8197,7 +8787,7 @@ var schema3 = {
|
|
|
8197
8787
|
wait_timeout_ms: z4.number().optional(),
|
|
8198
8788
|
format: z4.enum(["json", "text", "text-v1"]).optional().describe('Response format. Default `text-v1` — compact line-oriented output (matches grouped by file with grep -A/-B notation for context). Pass `format: "json"` for the structured envelope. `text` is an alias for `text-v1`. Errors stay JSON-formatted in either mode for now.')
|
|
8199
8789
|
};
|
|
8200
|
-
var DESCRIPTION3 = "Deterministic text or regex grep over indexed dependency and repository source files. " + 'Use this when you know the pattern (literal by default; pass `pattern_type: "regex"` for RE2). ' + "Use `search` for discovery instead. " + "Whole-target grep is the default — narrow with `path`, `path_prefix`, `globs`, or `extensions` to keep responses small. " + "Each match's `
|
|
8790
|
+
var DESCRIPTION3 = "Deterministic text or regex grep over indexed dependency and repository source files. " + 'Use this when you know the pattern (literal by default; pass `pattern_type: "regex"` for RE2). ' + "Use `search` for discovery instead. " + "Whole-target grep is the default — narrow with `path`, `path_prefix`, `globs`, or `extensions` to keep responses small. " + "Each match's `filePath` (or text file heading) chains into `code_read.path`; pick a window around `match.line` for `code_read.start_line` / `end_line`.";
|
|
8201
8791
|
function createGrepRepoTool(service) {
|
|
8202
8792
|
return {
|
|
8203
8793
|
name: "code_grep",
|
|
@@ -8292,7 +8882,7 @@ var schema4 = {
|
|
|
8292
8882
|
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`."),
|
|
8293
8883
|
format: z5.enum(["json", "text", "text-v1"]).optional().describe('Response format. Default `text-v1` — compact paths-only listing. Pass `format: "json"` for the structured envelope. `text` is an alias for `text-v1`. Errors stay JSON-formatted in either mode for now.')
|
|
8294
8884
|
};
|
|
8295
|
-
var DESCRIPTION4 = "List files in an indexed dependency. Use this to discover paths " + "before `code_read` (when `code_read` returns `FILE_NOT_FOUND` or " + "you don't yet know the path) and to scope `code_grep`. Address " + "via `target.registry` + `target.package_name` (package scope) or " + "`target.repo_url` + `target.git_ref` (repo scope), mutually " + "exclusive. Narrow with `path`, `path_prefix`, `globs`, " + "`extensions`, `file_types`, `languages`, or file-intent filters. " + "JSON envelope shape: `{total, hasMore, files: [{path, name, " + "language, fileType, byteSize}], resolution, indexedVersion}`. " + "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`.";
|
|
8885
|
+
var DESCRIPTION4 = "List files in an indexed dependency. First choice for file/path " + "enumeration tasks such as files under a directory; use " + "`path_prefix` for directory prefixes (e.g. `lib/`) and optional " + "`extensions` for language filtering. Use this to discover paths " + "before `code_read` (when `code_read` returns `FILE_NOT_FOUND` or " + "you don't yet know the path) and to scope `code_grep`. Address " + "via `target.registry` + `target.package_name` (package scope) or " + "`target.repo_url` + `target.git_ref` (repo scope), mutually " + "exclusive. Narrow with `path`, `path_prefix`, `globs`, " + "`extensions`, `file_types`, `languages`, or file-intent filters. " + "JSON envelope shape: `{total, hasMore, files: [{path, name, " + "language, fileType, byteSize}], resolution, indexedVersion}`. " + "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`.";
|
|
8296
8886
|
function createListFilesTool(service) {
|
|
8297
8887
|
return {
|
|
8298
8888
|
name: "code_files",
|
|
@@ -8371,7 +8961,7 @@ var schema5 = {
|
|
|
8371
8961
|
after: z6.string().optional().describe("Pagination cursor from a prior response."),
|
|
8372
8962
|
format: z6.enum(["json", "text", "text-v1"]).optional().describe('Response format. Default `text-v1` — compact page list with ready-to-call `docs_read` follow-ups. Pass `format: "json"` for the structured envelope.')
|
|
8373
8963
|
};
|
|
8374
|
-
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.";
|
|
8964
|
+
var DESCRIPTION5 = "List mixed package documentation pages from hosted docs and repository-backed docs. " + 'This browses available pages; for topic search, use `search` with `sources: ["docs"]` and pass the returned `pageId` to `docs_read`. ' + "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.";
|
|
8375
8965
|
function createListPackageDocsTool(service) {
|
|
8376
8966
|
return {
|
|
8377
8967
|
name: "docs_list",
|
|
@@ -8781,7 +9371,7 @@ var schema7 = {
|
|
|
8781
9371
|
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`."),
|
|
8782
9372
|
format: z8.enum(["json", "text", "text-v1"]).optional().describe('Response format. Default `text-v1` — compact dependency listing. Pass `format: "json"` for the structured envelope.')
|
|
8783
9373
|
};
|
|
8784
|
-
var DESCRIPTION7 = "Analyze a package's dependency graph. Lists direct runtime " + "dependencies with resolved versions; non-runtime groups are " + "omitted by default. Use `lifecycle` with a concrete value for " + "
|
|
9374
|
+
var DESCRIPTION7 = "Analyze a package's dependency graph. Lists direct runtime " + "dependencies with resolved versions; non-runtime groups are " + "omitted by default. Use `lifecycle` with a concrete value for " + "matching dependency groups, or `all` for every available group. " + "Runtime group rows include resolved versions when available. " + "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, Zig, vcpkg, RubyGems, " + "and Go.";
|
|
8785
9375
|
function createPackageDependenciesTool(service) {
|
|
8786
9376
|
return {
|
|
8787
9377
|
name: "pkg_deps",
|
|
@@ -8974,13 +9564,13 @@ import { z as z11 } from "zod";
|
|
|
8974
9564
|
var MCP_READ_MAX_SPAN = 150;
|
|
8975
9565
|
var schema10 = {
|
|
8976
9566
|
target: codeTargetSchema,
|
|
8977
|
-
path: z11.string().describe("
|
|
9567
|
+
path: z11.string().describe("Exact file path to read, not a directory. Package addressing: package-relative. Repo addressing: repo-relative. Use `code_files` with `path_prefix` to list directories, then pass an emitted `path` here."),
|
|
8978
9568
|
start_line: z11.number().optional().describe(`Starting line (1-indexed). Omit to start at line 1. The MCP surface caps any single read at ${MCP_READ_MAX_SPAN} lines — pick a focused window from your prior \`search\` / \`code_grep\` hit.`),
|
|
8979
9569
|
end_line: z11.number().optional().describe(`Ending line (inclusive). Must be ≥ \`start_line\` when both are set. Omitting it implies \`start_line + ${MCP_READ_MAX_SPAN - 1}\` because the MCP surface caps each read at ${MCP_READ_MAX_SPAN} lines.`),
|
|
8980
9570
|
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`."),
|
|
8981
9571
|
format: z11.enum(["json", "text", "text-v1"]).optional().describe('Response format. Default `text-v1` — line-numbered source content. Pass `format: "json"` for the structured envelope.')
|
|
8982
9572
|
};
|
|
8983
|
-
var DESCRIPTION10 = "Read
|
|
9573
|
+
var DESCRIPTION10 = "Read one exact file from an indexed dependency; it does not list " + "directories. Use `code_files` with `path_prefix` for file/path " + "enumeration. **MCP cap: " + `${MCP_READ_MAX_SPAN} lines per call** — broader requests (or no ` + `range) silently truncate to the first ${MCP_READ_MAX_SPAN} lines ` + "from your start, with a `hint` describing what was returned vs. " + "requested. Pick a focused window from a `search` / `code_grep` " + "match. Response: `{path, language, totalLines, startLine, endLine, " + "content, isBinary, hint?}`. Binary files set `isBinary: true` and " + "omit `content`. 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`. On `NOT_FOUND` / `FILE_NOT_FOUND` call " + "`code_files` to discover the actual path.";
|
|
8984
9574
|
function deriveBoundedRange(startLine, endLine) {
|
|
8985
9575
|
const start = startLine ?? 1;
|
|
8986
9576
|
if (endLine === undefined) {
|
|
@@ -9035,7 +9625,7 @@ function createReadFileTool(service) {
|
|
|
9035
9625
|
}
|
|
9036
9626
|
return textResult(JSON.stringify(payload));
|
|
9037
9627
|
} catch (error2) {
|
|
9038
|
-
const mapped = mapCodeNavigationError(error2);
|
|
9628
|
+
const mapped = withReadFileRecovery(mapCodeNavigationError(error2), args.path);
|
|
9039
9629
|
return errorResult(JSON.stringify({
|
|
9040
9630
|
error: mapped.message,
|
|
9041
9631
|
code: mapped.code,
|
|
@@ -9378,23 +9968,23 @@ Package spec: \`registry:name[@version]\`. Default outputs are compact \`text-v1
|
|
|
9378
9968
|
var MULTI_TURN_TIP = '**Delegate multi-call work to a sub-agent.** Code-navigation work (`search`, `code_grep`, `code_read`, `code_files`) often takes 3-10 calls. For cross-project comparisons, codebase mapping, pattern surveys, or "how does X actually work" investigations, spawn a sub-task/sub-agent and ask for a compact synthesis. Do it inline only when the raw snippet belongs in the main conversation.';
|
|
9379
9969
|
var SEARCH_BULLET = '- `search` — unified search across indexed dependency code, docs, and symbols. Omit `sources` for AUTO. Use `sources:["code"]` for implementation/examples/tests text, `sources:["symbol"]` for precise API/entity lookup, and `sources:["docs"]` for guides/reference/changelogs. Default output is compact `text-v1` with ready-to-call follow-up arguments; pass `format: "json"` for structured locators, highlights, and source status. Complete by default; opt into partial hits with `allow_partial_results: true`. Incomplete responses carry a `searchRef`.';
|
|
9380
9970
|
var SEARCH_STATUS_BULLET = "- `search_status` — follow up a prior `search` by `searchRef` to check progress, fetch partial hits, or fetch final results.";
|
|
9381
|
-
var CODE_GREP_BULLET = "- `code_grep` — deterministic text or regex grep over indexed source. Use it when you know the pattern; use `search` for discovery. Narrow with `path`, `path_prefix`, `globs`, or `extensions`. Each match's `
|
|
9382
|
-
var CODE_READ_BULLET = "- `code_read` — read
|
|
9383
|
-
var CODE_FILES_BULLET = '- `code_files` — list
|
|
9384
|
-
var DOCS_LIST_BULLET =
|
|
9385
|
-
var DOCS_READ_BULLET = "- `docs_read` — read a documentation page by pageId. Works for both hosted docs and repo-backed docs.";
|
|
9971
|
+
var CODE_GREP_BULLET = "- `code_grep` — deterministic text or regex grep over indexed source. Use it when you know the pattern; use `search` for discovery. Narrow with `path`, `path_prefix`, `globs`, or `extensions`. Each match's `filePath`/file heading plus line number chains into `code_read`.";
|
|
9972
|
+
var CODE_READ_BULLET = "- `code_read` — read one exact dependency file by `path`; do not use it to probe/list directories like `lib` or `lib/`. **MCP cap: 150 lines per call**. When you already have an exact path (e.g. from a stack trace), call this directly; otherwise locate it first with `search`, `code_grep`, or `code_files` and pick a focused `start_line` / `end_line` window. Binary files set `isBinary: true` and omit `content`. On `FILE_NOT_FOUND` / `NOT_FOUND`, follow `details.action` or call `code_files` for the actual path.";
|
|
9973
|
+
var CODE_FILES_BULLET = '- `code_files` — list or discover file paths in an indexed dependency. First choice for file-listing/path-enumeration tasks such as "files under lib/" (`path_prefix: "lib/"`, optional `extensions: ["js"]`); do not use `code_read` to probe directories and do not use `code_grep` with empty or generic patterns to list files. `path`, `path_prefix`, and `globs` are OR-ed selectors; extensions, language, file type, and file-intent filters intersect on top. Returned paths feed into `code_read` and help scope `code_grep`; pass `format: "json"` for language/type/size metadata.';
|
|
9974
|
+
var DOCS_LIST_BULLET = '- `docs_list` — browse hosted and repository-backed package docs when you need the available pages. It is not topic search; for "find docs about X", call `search` with `sources:["docs"]`, then pass the returned `pageId` to `docs_read`. Entries include stable pageIds, source URLs, and repo-file follow-up metadata when available.';
|
|
9975
|
+
var DOCS_READ_BULLET = "- `docs_read` — read a documentation page by pageId. Works for both hosted docs and repo-backed docs. Prefer focused `start_line` / `end_line` windows from `search` hits or prior `docs_read` `totalLines` metadata instead of rereading large pages.";
|
|
9386
9976
|
var PKG_INFO_BULLET = '- `pkg_info` — latest-version package triage by `registry` + `package_name` (e.g. `npm` + `express`): license, repository popularity, downloads, publish age, and vulnerability status. Set `verbose: true` for GitHub language/topics/last-pushed, recent advisories, and recent changes; pass `format: "json"` for structured fields.';
|
|
9387
9977
|
var PKG_VULNS_BULLET = '- `pkg_vulns` — compact known CVE / OSV advisory summary for npm, PyPI, Hex, Crates, NuGet, Maven, Packagist, RubyGems, or Go packages; vcpkg and Zig are not supported. Optionally pin `version` (e.g. `npm` + `lodash` + `4.17.20`). Filter with `min_severity`; include retracted advisories with `include_withdrawn`; set `advisory_scope: "non_affecting"` for historical advisories or `"all"` for affected + historical rows. Default text is capped; use `verbose: true` for all selected rows or `format: "json"` for the complete per-advisory envelope.';
|
|
9388
9978
|
var PKG_DEPS_BULLET = '- `pkg_deps` — compact direct runtime deps by default. Use `lifecycle: "runtime"` for explicit runtime-only, a concrete lifecycle for runtime plus matching non-runtime deps, or `lifecycle: "all"` for all groups. Use `include_transitive` for the full graph and `include_importers` for provenance. Pass `format: "json"` for the structured envelope.';
|
|
9389
9979
|
var PKG_CHANGELOG_BULLET = '- `pkg_changelog` — compact release notes for a package or GitHub repo, newest-first (e.g. `npm` + `express` + `limit: 2`). Default latest mode returns recent entries with 10-line markdown previews; `from_version` switches to range mode. Set `body_lines` to tune text previews, `verbose: true` for full text bodies, `include_bodies: false` for a compact timeline, or `format: "json"` for the complete envelope.';
|
|
9390
|
-
var STRATEGY_TIP = 'Strategy — reference-first.
|
|
9980
|
+
var STRATEGY_TIP = 'Strategy — reference-first. For file/path enumeration, call `code_files` directly; never test directory paths with `code_read`. For behavioral claims, locate symbols and lines with `search` or `code_grep` first, then read the needed window with `code_read` using explicit `start_line` / `end_line` (typical 80-150 lines around the match; the MCP `code_read` surface caps each call at 150 lines). Source, symbols, tests, and call sites beat docs prose; use `sources:["symbol"]` when you want symbol-shaped results, `code_grep` for deterministic text matching, and `get_example` for global canonical examples after package-scoped grounding.';
|
|
9391
9981
|
function buildMcpInstructions(_deps) {
|
|
9392
9982
|
const bullets = [
|
|
9393
9983
|
SEARCH_BULLET,
|
|
9394
9984
|
SEARCH_STATUS_BULLET,
|
|
9985
|
+
CODE_FILES_BULLET,
|
|
9395
9986
|
CODE_GREP_BULLET,
|
|
9396
9987
|
CODE_READ_BULLET,
|
|
9397
|
-
CODE_FILES_BULLET,
|
|
9398
9988
|
DOCS_LIST_BULLET,
|
|
9399
9989
|
DOCS_READ_BULLET,
|
|
9400
9990
|
PKG_INFO_BULLET,
|
|
@@ -9506,14 +10096,14 @@ Authenticated tool calls require a valid GitHits token.`).action(async () => {
|
|
|
9506
10096
|
showMcpSetupInstructions();
|
|
9507
10097
|
return;
|
|
9508
10098
|
}
|
|
9509
|
-
const deps = await createContainer();
|
|
10099
|
+
const deps = await createContainer({ resolveStoredToken: false });
|
|
9510
10100
|
await startMcpServer(deps);
|
|
9511
10101
|
});
|
|
9512
10102
|
mcpCommand.command("start").summary("Start MCP server (stdio mode)").description(`Start the MCP server using STDIO transport.
|
|
9513
10103
|
|
|
9514
10104
|
This command explicitly starts the server and is intended for use
|
|
9515
10105
|
in MCP configuration files. Use 'githits mcp' for interactive setup.`).action(async () => {
|
|
9516
|
-
const deps = await createContainer();
|
|
10106
|
+
const deps = await createContainer({ resolveStoredToken: false });
|
|
9517
10107
|
await startMcpServer(deps);
|
|
9518
10108
|
});
|
|
9519
10109
|
}
|
|
@@ -9744,7 +10334,7 @@ function formatDepsTerminalError(mapped) {
|
|
|
9744
10334
|
var PKG_DEPS_DESCRIPTION = `Analyze package dependencies. By default shows the flat list of
|
|
9745
10335
|
direct runtime dependencies. Use --lifecycle all for the structured view
|
|
9746
10336
|
(dev / peer / build / optional, plus registry-specific feature / TFM
|
|
9747
|
-
groups).
|
|
10337
|
+
groups). Runtime group rows include resolved versions when available.
|
|
9748
10338
|
--transitive opts into aggregate edge / unique-package counts,
|
|
9749
10339
|
conflict detection, and circular-dependency flags.
|
|
9750
10340
|
|
|
@@ -10067,7 +10657,7 @@ function requireSearchService(deps) {
|
|
|
10067
10657
|
return deps.codeNavigationService;
|
|
10068
10658
|
}
|
|
10069
10659
|
async function loadContainer2() {
|
|
10070
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
10660
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-k35egwwf.js");
|
|
10071
10661
|
return createContainer2();
|
|
10072
10662
|
}
|
|
10073
10663
|
function parseTargetSpecs(specs) {
|
|
@@ -10177,13 +10767,13 @@ function formatUnifiedSearchTerminal(payload) {
|
|
|
10177
10767
|
`).trimEnd();
|
|
10178
10768
|
}
|
|
10179
10769
|
const { display, duplicatesFolded } = dedupeSearchResultsForDisplay(payload.results);
|
|
10180
|
-
const baseCount = `${display.length} result
|
|
10770
|
+
const baseCount = `${display.length} result${display.length === 1 ? "" : "s"}`;
|
|
10181
10771
|
const countSuffix = [
|
|
10182
10772
|
payload.hasMore ? " (more available)" : "",
|
|
10183
10773
|
duplicatesFolded > 0 ? ` (+${duplicatesFolded} near-duplicate folded)` : ""
|
|
10184
10774
|
].join("");
|
|
10185
|
-
|
|
10186
|
-
lines.push(dim(
|
|
10775
|
+
const typeSummary = formatUnifiedSearchTypeSummary(display);
|
|
10776
|
+
lines.push(`${highlight(baseCount, useColors)}${dim(countSuffix, useColors)}${typeSummary ? dim(` | ${typeSummary}`, useColors) : ""}`);
|
|
10187
10777
|
lines.push("");
|
|
10188
10778
|
for (const entry of display) {
|
|
10189
10779
|
const location = formatUnifiedSearchLocation(entry.locator);
|
|
@@ -10333,7 +10923,7 @@ function formatUnifiedSearchTypeSummary(results) {
|
|
|
10333
10923
|
for (const result of results) {
|
|
10334
10924
|
counts.set(result.type, (counts.get(result.type) ?? 0) + 1);
|
|
10335
10925
|
}
|
|
10336
|
-
return Array.from(counts.entries()).map(([type, count]) => formatUnifiedSearchCountLabel(type, count)).join("
|
|
10926
|
+
return Array.from(counts.entries()).map(([type, count]) => formatUnifiedSearchCountLabel(type, count)).join(", ");
|
|
10337
10927
|
}
|
|
10338
10928
|
function formatUnifiedSearchResultLabel(type) {
|
|
10339
10929
|
switch (type) {
|
|
@@ -10386,11 +10976,33 @@ function formatUnifiedSearchLocation(locator) {
|
|
|
10386
10976
|
return `${locator.filePath}:${locator.startLine}${locator.endLine && locator.endLine !== locator.startLine ? `-${locator.endLine}` : ""}`;
|
|
10387
10977
|
}
|
|
10388
10978
|
function formatUnifiedSearchHeader(entry, useColors, location, rawQuery) {
|
|
10979
|
+
if (entry.type === "documentation_page") {
|
|
10980
|
+
return formatDocumentationPageHeader(entry, useColors);
|
|
10981
|
+
}
|
|
10389
10982
|
const primary = formatUnifiedSearchPrimary(entry.type, entry.target, location, rawQuery, useColors);
|
|
10390
10983
|
const badge = `[${formatUnifiedSearchResultLabel(entry.type)}]`;
|
|
10391
10984
|
const title = entry.title ? highlightRanges(entry.title, entry.highlights?.title, useColors) : undefined;
|
|
10392
10985
|
return `${primary} ${dim(badge, useColors)}${title ? ` - ${title}` : ""}`;
|
|
10393
10986
|
}
|
|
10987
|
+
function formatDocumentationPageHeader(entry, useColors) {
|
|
10988
|
+
const pageId = entry.locator.pageId ?? "unknown";
|
|
10989
|
+
const title = entry.title ? highlightRanges(entry.title, entry.highlights?.title, useColors) : "Untitled documentation page";
|
|
10990
|
+
const source = entry.locator.sourceUrl ? ` - ${formatDisplayUrl(entry.locator.sourceUrl)}` : "";
|
|
10991
|
+
const target = formatDocsPageTarget2(entry.locator, entry.target);
|
|
10992
|
+
return `${highlight(pageId, useColors)} ${dim("[docs page]", useColors)}${target ? ` ${dim(target, useColors)}` : ""} - ${title}${dim(source, useColors)}`;
|
|
10993
|
+
}
|
|
10994
|
+
function formatDisplayUrl(value) {
|
|
10995
|
+
return value.replace(/^https?:\/\//, "");
|
|
10996
|
+
}
|
|
10997
|
+
function formatDocsPageTarget2(locator, fallbackTarget) {
|
|
10998
|
+
return locator.registry && locator.packageName ? `${locator.registry}:${locator.packageName}` : stripVersionFromTarget2(fallbackTarget);
|
|
10999
|
+
}
|
|
11000
|
+
function stripVersionFromTarget2(value) {
|
|
11001
|
+
if (!value)
|
|
11002
|
+
return "";
|
|
11003
|
+
const atIndex = value.lastIndexOf("@");
|
|
11004
|
+
return atIndex > 0 ? value.slice(0, atIndex) : value;
|
|
11005
|
+
}
|
|
10394
11006
|
function formatUnifiedSearchPrimary(type, target, location, rawQuery, useColors) {
|
|
10395
11007
|
const formattedTarget = highlight(target, useColors);
|
|
10396
11008
|
if (type === "documentation_page" || !location) {
|
|
@@ -10498,14 +11110,8 @@ function formatUnifiedSearchMetadata(entry, useColors) {
|
|
|
10498
11110
|
return [];
|
|
10499
11111
|
}
|
|
10500
11112
|
const lines = [];
|
|
10501
|
-
if (entry.
|
|
10502
|
-
|
|
10503
|
-
lines.push(` ${dim("pageId:", useColors)} ${entry.locator.pageId}`);
|
|
10504
|
-
}
|
|
10505
|
-
}
|
|
10506
|
-
const sourceBadge = entry.locator.sourceKind?.toLowerCase() === "repository" ? "[repo]" : entry.locator.sourceKind?.toLowerCase() === "crawled" ? "[crawled]" : undefined;
|
|
10507
|
-
if (entry.locator.sourceUrl && entry.type === "documentation_page") {
|
|
10508
|
-
lines.push(` ${dim("source:", useColors)} ${sourceBadge ? `${sourceBadge} ` : ""}${entry.locator.sourceUrl}`);
|
|
11113
|
+
if (entry.type === "documentation_page") {
|
|
11114
|
+
return lines;
|
|
10509
11115
|
}
|
|
10510
11116
|
return lines;
|
|
10511
11117
|
}
|
|
@@ -10544,6 +11150,8 @@ if (isTelemetryEnabled()) {
|
|
|
10544
11150
|
}
|
|
10545
11151
|
var rootCliPreAction = createRootCliPreAction({
|
|
10546
11152
|
createContainer,
|
|
11153
|
+
loadAuthSessionMetadata: loadAutoLoginAuthSessionMetadata,
|
|
11154
|
+
clearAuthSessionMetadata: clearAutoLoginAuthSessionMetadata,
|
|
10547
11155
|
loginFlow: (options, deps) => loginFlow(options, deps, stderrLoginOutput)
|
|
10548
11156
|
});
|
|
10549
11157
|
program.name("githits").description("Code examples from global open source for your AI assistant").version(version).option("--no-color", "Disable colored output").hook("preAction", async (thisCommand, actionCommand) => {
|