githits 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -49,11 +49,11 @@ import {
49
49
  shouldRunUpdateCheck,
50
50
  startTelemetrySpan,
51
51
  withTelemetrySpan
52
- } from "./shared/chunk-0s7mxdt3.js";
52
+ } from "./shared/chunk-zarrkzvq.js";
53
53
  import {
54
54
  __require,
55
55
  version
56
- } from "./shared/chunk-m1xx8hzw.js";
56
+ } from "./shared/chunk-w5kw8sef.js";
57
57
 
58
58
  // src/cli.ts
59
59
  import { Command } from "commander";
@@ -485,6 +485,12 @@ function knownSymbolCategoryList() {
485
485
  function toFileIntent(intent) {
486
486
  return intent ? fileIntentMap[intent] : undefined;
487
487
  }
488
+ function isKnownFileIntent(value) {
489
+ return value in fileIntentMap;
490
+ }
491
+ function knownFileIntentList() {
492
+ return Object.keys(fileIntentMap);
493
+ }
488
494
  // src/shared/code-navigation-error-map.ts
489
495
  function mapCodeNavigationError(error2) {
490
496
  const mapped = classify(error2);
@@ -664,23 +670,6 @@ function isInvalidArgumentError(error2) {
664
670
  return false;
665
671
  return error2.name.startsWith("Invalid") || error2.name.startsWith("Unsupported");
666
672
  }
667
- // src/shared/docs-follow-up.ts
668
- function lowerDocSourceKind(value) {
669
- switch (value) {
670
- case "CRAWLED":
671
- return "crawled";
672
- case "REPOSITORY":
673
- return "repo";
674
- default:
675
- return;
676
- }
677
- }
678
- // src/shared/extract-solution-id.ts
679
- var SOLUTION_URL_RE = /solutions\/([0-9a-fA-F-]{36})/;
680
- function extractSolutionId(markdown) {
681
- const match = SOLUTION_URL_RE.exec(markdown);
682
- return match?.[1];
683
- }
684
673
  // src/shared/package-spec.ts
685
674
  var KNOWN_REGISTRIES = [
686
675
  "npm",
@@ -755,6 +744,112 @@ function isKnownRegistry(value) {
755
744
  return KNOWN_REGISTRIES.includes(value);
756
745
  }
757
746
 
747
+ // src/shared/code-navigation-target.ts
748
+ function parseCodeNavigationTargetSpec(spec) {
749
+ const trimmed = spec.trim();
750
+ if (trimmed.length === 0) {
751
+ throw new InvalidArgumentError("Target spec cannot be empty.");
752
+ }
753
+ if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
754
+ return parseRepoTarget(trimmed);
755
+ }
756
+ const parsed = parsePackageSpec(trimmed);
757
+ return {
758
+ registry: toCodeNavigationRegistry(parsed.registry),
759
+ packageName: parsed.name,
760
+ version: parsed.version
761
+ };
762
+ }
763
+ function parseRepoTarget(spec) {
764
+ const hashIndex = spec.lastIndexOf("#");
765
+ if (hashIndex === -1) {
766
+ return { repoUrl: spec, gitRef: "HEAD" };
767
+ }
768
+ const repoUrl = spec.slice(0, hashIndex);
769
+ const gitRef = spec.slice(hashIndex + 1);
770
+ if (!repoUrl || !gitRef) {
771
+ throw new InvalidArgumentError("Repository target must be a full URL with optional #gitRef suffix.");
772
+ }
773
+ return { repoUrl, gitRef };
774
+ }
775
+ // src/shared/docs-follow-up.ts
776
+ function lowerDocSourceKind(value) {
777
+ switch (value) {
778
+ case "CRAWLED":
779
+ return "crawled";
780
+ case "REPOSITORY":
781
+ return "repo";
782
+ default:
783
+ return;
784
+ }
785
+ }
786
+ // src/shared/extract-solution-id.ts
787
+ var SOLUTION_URL_RE = /solutions\/([0-9a-fA-F-]{36})/;
788
+ function extractSolutionId(markdown) {
789
+ const match = SOLUTION_URL_RE.exec(markdown);
790
+ return match?.[1];
791
+ }
792
+ // src/shared/follow-up-command-text.ts
793
+ function buildSearchHitFollowUpCommand(hit) {
794
+ const loc = hit.locator;
795
+ if (loc.pageId) {
796
+ return buildDocsReadCommand(loc.pageId, loc.startLine, loc.endLine);
797
+ }
798
+ if (loc.filePath) {
799
+ return buildCodeReadCommand({
800
+ registry: loc.registry,
801
+ packageName: loc.packageName,
802
+ version: loc.version,
803
+ repoUrl: loc.repoUrl,
804
+ gitRef: loc.gitRef,
805
+ filePath: loc.filePath,
806
+ startLine: loc.startLine,
807
+ endLine: loc.endLine
808
+ });
809
+ }
810
+ if (hit.type === "repository_code" || hit.type === "repository_symbol") {
811
+ return "follow-up unavailable: missing filePath";
812
+ }
813
+ if (loc.sourceUrl)
814
+ return loc.sourceUrl;
815
+ return "";
816
+ }
817
+ function buildDocsReadCommand(pageId, startLine, endLine) {
818
+ const parts = [`docs_read page_id=${quote(pageId)}`];
819
+ appendRange(parts, startLine, endLine);
820
+ return parts.join(" ");
821
+ }
822
+ function buildCodeReadCommand(input) {
823
+ if (!input.filePath)
824
+ return "follow-up unavailable: missing filePath";
825
+ const target = buildTargetSpec(input);
826
+ if (!target)
827
+ return "follow-up unavailable: missing target";
828
+ const parts = [
829
+ `code_read target=${quote(target)}`,
830
+ `path=${quote(input.filePath)}`
831
+ ];
832
+ appendRange(parts, input.startLine, input.endLine);
833
+ return parts.join(" ");
834
+ }
835
+ function buildTargetSpec(input) {
836
+ if (input.repoUrl) {
837
+ return `${input.repoUrl}#${input.gitRef ?? "HEAD"}`;
838
+ }
839
+ if (input.registry && input.packageName) {
840
+ return `${input.registry}:${input.packageName}${input.version ? `@${input.version}` : ""}`;
841
+ }
842
+ return;
843
+ }
844
+ function appendRange(parts, startLine, endLine) {
845
+ if (typeof startLine === "number")
846
+ parts.push(`start_line=${startLine}`);
847
+ if (typeof endLine === "number")
848
+ parts.push(`end_line=${endLine}`);
849
+ }
850
+ function quote(value) {
851
+ return JSON.stringify(value);
852
+ }
758
853
  // src/shared/grep-repo-request.ts
759
854
  var PATTERN_MAX = 200;
760
855
  var CONTEXT_MIN = 0;
@@ -1372,7 +1467,7 @@ function buildHeader(envelope) {
1372
1467
  const parts = [
1373
1468
  `code_grep${SEP}${envelope.totalMatches} match${envelope.totalMatches === 1 ? "" : "es"} in ${envelope.uniqueFilesMatched} file${envelope.uniqueFilesMatched === 1 ? "" : "s"}`
1374
1469
  ];
1375
- parts.push(`pattern=${quote(envelope.pattern)}`);
1470
+ parts.push(`pattern=${quote2(envelope.pattern)}`);
1376
1471
  const flags = [];
1377
1472
  if (envelope.patternType === "regex")
1378
1473
  flags.push("regex");
@@ -1391,9 +1486,9 @@ function buildFilterEcho(envelope) {
1391
1486
  return "";
1392
1487
  const parts = [];
1393
1488
  if (filter.path)
1394
- parts.push(`path=${quote(filter.path)}`);
1489
+ parts.push(`path=${quote2(filter.path)}`);
1395
1490
  if (filter.pathPrefix)
1396
- parts.push(`path_prefix=${quote(filter.pathPrefix)}`);
1491
+ parts.push(`path_prefix=${quote2(filter.pathPrefix)}`);
1397
1492
  if (filter.globs?.length)
1398
1493
  parts.push(`globs=${filter.globs.join(",")}`);
1399
1494
  if (filter.extensions?.length) {
@@ -1526,14 +1621,18 @@ function renderLine(line, gutterWidth, useContext) {
1526
1621
  const sep = !useContext || line.isMatch ? ":" : "-";
1527
1622
  return ` ${gutter}${sep} ${line.content}`;
1528
1623
  }
1529
- function quote(value) {
1624
+ function quote2(value) {
1530
1625
  return value.includes('"') ? `'${value}'` : `"${value}"`;
1531
1626
  }
1532
1627
  // src/shared/language-filter.ts
1533
1628
  var DEFAULT_LIMIT = 5;
1534
1629
  function filterLanguages(languages, query, limit = DEFAULT_LIMIT) {
1535
1630
  const lowerQuery = query.toLowerCase();
1536
- return languages.filter((lang) => lang.name.toLowerCase().includes(lowerQuery) || lang.display_name.toLowerCase().includes(lowerQuery) || lang.aliases.some((a) => a.toLowerCase().includes(lowerQuery))).slice(0, limit).map(({ name, display_name }) => ({ name, display_name }));
1631
+ return languages.filter((lang) => lang.name.toLowerCase().includes(lowerQuery) || lang.display_name.toLowerCase().includes(lowerQuery) || lang.aliases.some((a) => a.toLowerCase().includes(lowerQuery))).slice(0, limit).map(({ name, display_name, aliases }) => ({
1632
+ name,
1633
+ display_name,
1634
+ aliases
1635
+ }));
1537
1636
  }
1538
1637
  // src/shared/list-files-text.ts
1539
1638
  var SEP2 = " | ";
@@ -1551,7 +1650,7 @@ function renderListFilesText(envelope) {
1551
1650
  }
1552
1651
  if (envelope.hasMore) {
1553
1652
  lines.push("");
1554
- lines.push("More files available. Pass limit=N to widen or refine path_prefix.");
1653
+ lines.push("More files available. Pass limit=N or refine the filter.");
1555
1654
  }
1556
1655
  if (envelope.hint) {
1557
1656
  lines.push("");
@@ -1585,15 +1684,48 @@ function buildIdentity(envelope) {
1585
1684
  }
1586
1685
  function buildFilterEcho2(envelope) {
1587
1686
  const parts = [];
1687
+ if (envelope.filter?.path) {
1688
+ parts.push(`path=${quote3(envelope.filter.path)}`);
1689
+ }
1588
1690
  if (envelope.filter?.pathPrefix) {
1589
- parts.push(`path_prefix=${quote2(envelope.filter.pathPrefix)}`);
1691
+ parts.push(`path_prefix=${quote3(envelope.filter.pathPrefix)}`);
1692
+ }
1693
+ if (envelope.filter?.globs?.length) {
1694
+ parts.push(`globs=${envelope.filter.globs.join(",")}`);
1695
+ }
1696
+ if (envelope.filter?.extensions?.length) {
1697
+ parts.push(`exts=${envelope.filter.extensions.join(",")}`);
1698
+ }
1699
+ if (envelope.filter?.fileTypes?.length) {
1700
+ parts.push(`file_types=${envelope.filter.fileTypes.join(",")}`);
1701
+ }
1702
+ if (envelope.filter?.languages?.length) {
1703
+ parts.push(`languages=${envelope.filter.languages.join(",")}`);
1704
+ }
1705
+ if (envelope.filter?.fileIntent) {
1706
+ parts.push(`file_intent=${envelope.filter.fileIntent}`);
1707
+ }
1708
+ if (envelope.filter?.fileIntents?.length) {
1709
+ parts.push(`file_intents=${envelope.filter.fileIntents.join(",")}`);
1710
+ }
1711
+ if (envelope.filter?.excludeFileIntents?.length) {
1712
+ parts.push(`exclude_file_intents=${envelope.filter.excludeFileIntents.join(",")}`);
1713
+ }
1714
+ if (envelope.filter?.excludeDocFiles !== undefined) {
1715
+ parts.push(`exclude_doc_files=${String(envelope.filter.excludeDocFiles)}`);
1716
+ }
1717
+ if (envelope.filter?.excludeTestFiles !== undefined) {
1718
+ parts.push(`exclude_test_files=${String(envelope.filter.excludeTestFiles)}`);
1719
+ }
1720
+ if (envelope.filter?.includeHidden !== undefined) {
1721
+ parts.push(`include_hidden=${String(envelope.filter.includeHidden)}`);
1590
1722
  }
1591
1723
  if (envelope.filter?.limit !== undefined) {
1592
1724
  parts.push(`limit=${envelope.filter.limit}`);
1593
1725
  }
1594
1726
  return parts.join(" ");
1595
1727
  }
1596
- function quote2(value) {
1728
+ function quote3(value) {
1597
1729
  return value.includes('"') ? `'${value}'` : `"${value}"`;
1598
1730
  }
1599
1731
  // src/shared/list-package-docs-request.ts
@@ -1693,8 +1825,6 @@ function buildListPackageDocsSuccessPayload(result, options) {
1693
1825
  entry.requestedRef = page.requestedRef;
1694
1826
  if (page.filePath)
1695
1827
  entry.filePath = page.filePath;
1696
- if (page.linkName)
1697
- entry.linkName = page.linkName;
1698
1828
  if (lastUpdatedAt)
1699
1829
  entry.lastUpdatedAt = lastUpdatedAt;
1700
1830
  return entry;
@@ -1782,6 +1912,51 @@ function formatPageMeta(page, useColors, verbose) {
1782
1912
  }
1783
1913
  return lines;
1784
1914
  }
1915
+ // src/shared/list-package-docs-text.ts
1916
+ var SEP3 = " | ";
1917
+ function renderListPackageDocsText(envelope) {
1918
+ const lines = [];
1919
+ lines.push(buildHeader3(envelope));
1920
+ lines.push("");
1921
+ if (envelope.pages.length === 0) {
1922
+ lines.push("No documentation pages found.");
1923
+ return lines.join(`
1924
+ `);
1925
+ }
1926
+ for (const page of envelope.pages) {
1927
+ lines.push([
1928
+ page.pageId,
1929
+ page.title ?? "",
1930
+ page.sourceKind ?? "",
1931
+ page.sourceUrl ?? ""
1932
+ ].join(SEP3));
1933
+ lines.push(` ${buildDocsReadCommand(page.pageId)}`);
1934
+ if (page.sourceKind === "repo" && page.repoUrl && page.filePath) {
1935
+ lines.push(` ${buildCodeReadCommand({
1936
+ repoUrl: page.repoUrl,
1937
+ gitRef: page.requestedRef ?? page.gitRef,
1938
+ filePath: page.filePath,
1939
+ startLine: 1,
1940
+ endLine: 150
1941
+ })}`);
1942
+ }
1943
+ }
1944
+ if (envelope.nextCursor) {
1945
+ lines.push("");
1946
+ lines.push(`More docs available. Pass after=${envelope.nextCursor}.`);
1947
+ }
1948
+ if (envelope.stale) {
1949
+ lines.push("");
1950
+ lines.push("Documentation may be stale.");
1951
+ }
1952
+ return lines.join(`
1953
+ `);
1954
+ }
1955
+ function buildHeader3(envelope) {
1956
+ const target = envelope.registry && envelope.name ? `${envelope.registry}:${envelope.name}${envelope.version ? `@${envelope.version}` : ""}` : "package docs";
1957
+ const suffix = envelope.total !== undefined ? `/${envelope.total}` : "";
1958
+ return `docs_list${SEP3}${target}${SEP3}${envelope.pages.length}${suffix} page${envelope.pages.length === 1 ? "" : "s"}`;
1959
+ }
1785
1960
  // src/shared/package-dependencies-request.ts
1786
1961
  class UnsupportedDependenciesRegistryError extends Error {
1787
1962
  constructor(message) {
@@ -1830,6 +2005,7 @@ function buildPackageDependenciesParams(input) {
1830
2005
  }
1831
2006
  const version2 = normaliseVersion(input.version);
1832
2007
  const canonicalLifecycles = resolveLifecycles(input.lifecycle);
2008
+ const wireLifecycles = canonicalLifecycles.filter((entry) => entry !== "runtime" && entry !== "all");
1833
2009
  const maxDepth = input.maxDepth;
1834
2010
  if (maxDepth !== undefined) {
1835
2011
  if (!Number.isInteger(maxDepth) || maxDepth < 1 || maxDepth > 10) {
@@ -1838,13 +2014,14 @@ function buildPackageDependenciesParams(input) {
1838
2014
  }
1839
2015
  return {
1840
2016
  canonicalLifecycles,
2017
+ wireLifecycles,
1841
2018
  params: {
1842
2019
  registry,
1843
2020
  packageName: trimmedName,
1844
2021
  version: version2,
1845
2022
  includeTransitive: input.includeTransitive,
1846
2023
  maxDepth,
1847
- lifecycle: canonicalLifecycles.length > 0 ? canonicalLifecycles : undefined
2024
+ lifecycle: wireLifecycles.length > 0 ? wireLifecycles : undefined
1848
2025
  }
1849
2026
  };
1850
2027
  }
@@ -1869,16 +2046,29 @@ function resolveLifecycles(raw) {
1869
2046
  if (trimmed.length === 0)
1870
2047
  continue;
1871
2048
  const lower = trimmed.toLowerCase();
1872
- if (!isLifecycle(lower)) {
1873
- throw new InvalidPackageSpecError(`Unknown lifecycle '${trimmed}'. Expected one of: ${LIFECYCLES.join(", ")}.`);
2049
+ if (!isLifecycleInput(lower)) {
2050
+ throw new InvalidPackageSpecError(`Unknown lifecycle '${trimmed}'. Expected one of: ${LIFECYCLES.join(", ")}, all.`);
1874
2051
  }
1875
2052
  seen.add(lower);
1876
2053
  }
1877
- return Array.from(seen).sort((a, b) => LIFECYCLE_ORDER[a] - LIFECYCLE_ORDER[b]);
2054
+ if (seen.has("all") && seen.size > 1) {
2055
+ throw new InvalidPackageSpecError("lifecycle=all cannot be combined with other lifecycle values.");
2056
+ }
2057
+ return Array.from(seen).sort(lifecycleInputSort);
1878
2058
  }
1879
2059
  function isLifecycle(value) {
1880
2060
  return LIFECYCLES.includes(value);
1881
2061
  }
2062
+ function isLifecycleInput(value) {
2063
+ return value === "all" || isLifecycle(value);
2064
+ }
2065
+ function lifecycleInputSort(a, b) {
2066
+ if (a === "all")
2067
+ return b === "all" ? 0 : 1;
2068
+ if (b === "all")
2069
+ return -1;
2070
+ return LIFECYCLE_ORDER[a] - LIFECYCLE_ORDER[b];
2071
+ }
1882
2072
  // src/shared/package-dependencies-response.ts
1883
2073
  function buildPackageDependenciesSuccessPayload(report, options = {}) {
1884
2074
  const pkg = report.package;
@@ -1900,10 +2090,16 @@ function buildPackageDependenciesSuccessPayload(report, options = {}) {
1900
2090
  payload.runtime = { count: items.length, items };
1901
2091
  }
1902
2092
  const groupsInfo = report.dependencyGroups;
1903
- if (groupsInfo !== undefined) {
1904
- const groupItems = sortGroups(groupsInfo.groups.map(buildGroup));
2093
+ if (groupsInfo !== undefined && shouldEmitGroups(options.canonicalLifecycles)) {
2094
+ const groupItems = sortGroups(groupsInfo.groups.map(buildGroup).filter((group) => {
2095
+ if (!options.canonicalLifecycles)
2096
+ return false;
2097
+ if (options.canonicalLifecycles.includes("all"))
2098
+ return true;
2099
+ return options.canonicalLifecycles.includes(group.lifecycle);
2100
+ }));
1905
2101
  const groupsBlock = { items: groupItems };
1906
- if (groupsInfo.primaryGroup) {
2102
+ if (groupsInfo.primaryGroup && groupItems.some((group) => group.name === groupsInfo.primaryGroup)) {
1907
2103
  groupsBlock.primaryGroup = groupsInfo.primaryGroup;
1908
2104
  }
1909
2105
  if (groupsInfo.environmentMarkers && groupsInfo.environmentMarkers.length > 0) {
@@ -1945,6 +2141,11 @@ function buildPackageDependenciesSuccessPayload(report, options = {}) {
1945
2141
  }
1946
2142
  return payload;
1947
2143
  }
2144
+ function shouldEmitGroups(lifecycles) {
2145
+ if (!lifecycles || lifecycles.length === 0)
2146
+ return false;
2147
+ return lifecycles.some((entry) => entry !== "runtime");
2148
+ }
1948
2149
  function projectEnvironmentMarker(marker) {
1949
2150
  const out = {};
1950
2151
  if (marker.type !== undefined)
@@ -2163,7 +2364,7 @@ function formatPackageDependenciesTerminal(report, options = {}) {
2163
2364
  const verbose = options.verbose ?? false;
2164
2365
  const payload = buildPackageDependenciesSuccessPayload(report, {
2165
2366
  requestedVersion: options.requestedVersion,
2166
- canonicalLifecycles: options.canonicalLifecycles,
2367
+ canonicalLifecycles: options.canonicalLifecycles ?? ["all"],
2167
2368
  includeTransitive: options.includeTransitive,
2168
2369
  maxDepth: options.maxDepth,
2169
2370
  includeImporters: verbose
@@ -2172,7 +2373,7 @@ function formatPackageDependenciesTerminal(report, options = {}) {
2172
2373
  const showGroups = options.showGroups ?? false;
2173
2374
  const includeTransitive = options.includeTransitive ?? false;
2174
2375
  const blocks = [];
2175
- blocks.push(formatHeaderBlock(payload, useColors, showGroups));
2376
+ blocks.push(formatHeaderBlock(payload, useColors, showGroups, options));
2176
2377
  if (includeTransitive) {
2177
2378
  blocks.push(formatTransitiveDepsList(payload, verbose, useColors));
2178
2379
  const issues = formatConflictsAndCycles(payload, verbose, useColors);
@@ -2189,7 +2390,7 @@ function formatPackageDependenciesTerminal(report, options = {}) {
2189
2390
  `)}
2190
2391
  `;
2191
2392
  }
2192
- function formatHeaderBlock(payload, useColors, showGroups) {
2393
+ function formatHeaderBlock(payload, useColors, showGroups, options) {
2193
2394
  const name = colorize(payload.name, "bold", useColors);
2194
2395
  const lines = [
2195
2396
  `${name} @ ${payload.version} · ${payload.registry}`
@@ -2197,11 +2398,11 @@ function formatHeaderBlock(payload, useColors, showGroups) {
2197
2398
  if (payload.requestedVersion) {
2198
2399
  lines.push(dim(`(requested ${payload.requestedVersion})`, useColors));
2199
2400
  }
2200
- lines.push(formatSummaryRow(payload, useColors, showGroups));
2401
+ lines.push(formatSummaryRow(payload, useColors, showGroups, options));
2201
2402
  return lines.join(`
2202
2403
  `);
2203
2404
  }
2204
- function formatSummaryRow(payload, useColors, showGroups) {
2405
+ function formatSummaryRow(payload, useColors, showGroups, options) {
2205
2406
  const countParts = [];
2206
2407
  const runtimeCount = payload.runtime?.count ?? 0;
2207
2408
  if (runtimeCount === 0) {
@@ -2238,7 +2439,7 @@ function formatSummaryRow(payload, useColors, showGroups) {
2238
2439
  const hidden = collectHiddenGroupNames(payload);
2239
2440
  if (hidden.length === 0)
2240
2441
  return countLine;
2241
- const hiddenLine = dim(`Hidden groups: ${hidden.join(", ")} — use --groups.`, useColors);
2442
+ const hiddenLine = dim(`Hidden groups: ${hidden.join(", ")} — ${options.hiddenGroupsHint ?? "use --lifecycle all."}`, useColors);
2242
2443
  return `${countLine}
2243
2444
  ${hiddenLine}`;
2244
2445
  }
@@ -3735,6 +3936,55 @@ function requirePositiveInteger(raw, label) {
3735
3936
  }
3736
3937
  return parsed;
3737
3938
  }
3939
+ // src/shared/read-file-text.ts
3940
+ var SEP4 = " | ";
3941
+ function renderReadFileText(envelope) {
3942
+ const lines = [];
3943
+ lines.push(buildHeader4(envelope));
3944
+ lines.push("");
3945
+ if (envelope.isBinary) {
3946
+ lines.push("Binary file - cannot display as text.");
3947
+ } else if (envelope.content) {
3948
+ appendNumberedContent(lines, envelope.content, envelope.startLine ?? 1);
3949
+ } else {
3950
+ lines.push("(no content returned)");
3951
+ }
3952
+ if (envelope.hint) {
3953
+ lines.push("");
3954
+ lines.push(`hint: ${envelope.hint}`);
3955
+ }
3956
+ return lines.join(`
3957
+ `);
3958
+ }
3959
+ function buildHeader4(envelope) {
3960
+ const parts = [`code_read${SEP4}${envelope.path}`];
3961
+ if (envelope.language)
3962
+ parts.push(envelope.language);
3963
+ const range = buildRange(envelope);
3964
+ if (range)
3965
+ parts.push(range);
3966
+ return parts.join(SEP4);
3967
+ }
3968
+ function buildRange(envelope) {
3969
+ if (envelope.startLine !== undefined && envelope.endLine !== undefined) {
3970
+ return envelope.totalLines !== undefined ? `lines ${envelope.startLine}-${envelope.endLine}/${envelope.totalLines}` : `lines ${envelope.startLine}-${envelope.endLine}`;
3971
+ }
3972
+ if (envelope.totalLines !== undefined)
3973
+ return `${envelope.totalLines} lines`;
3974
+ return;
3975
+ }
3976
+ function appendNumberedContent(lines, content, startLine) {
3977
+ const bodyLines = content.split(`
3978
+ `);
3979
+ if (bodyLines.length > 0 && bodyLines[bodyLines.length - 1] === "") {
3980
+ bodyLines.pop();
3981
+ }
3982
+ const endLine = startLine + bodyLines.length - 1;
3983
+ const width = String(endLine).length;
3984
+ for (let i = 0;i < bodyLines.length; i += 1) {
3985
+ lines.push(`${String(startLine + i).padStart(width, " ")} ${bodyLines[i]}`);
3986
+ }
3987
+ }
3738
3988
  // src/shared/read-package-doc-request.ts
3739
3989
  function buildReadPackageDocParams(input) {
3740
3990
  const pageId = input.pageId?.trim() ?? "";
@@ -3778,8 +4028,6 @@ function buildReadPackageDocSuccessPayload(result, requestedPageId, range) {
3778
4028
  if (result.page?.breadcrumbs && result.page.breadcrumbs.length > 0) {
3779
4029
  envelope.breadcrumbs = result.page.breadcrumbs;
3780
4030
  }
3781
- if (result.page?.linkName)
3782
- envelope.linkName = result.page.linkName;
3783
4031
  if (result.page?.lastUpdatedAt) {
3784
4032
  envelope.lastUpdatedAt = toIsoDate(result.page.lastUpdatedAt) ?? undefined;
3785
4033
  }
@@ -3828,7 +4076,7 @@ function formatReadPackageDocTerminal(envelope, options) {
3828
4076
  return envelope.content ?? "";
3829
4077
  }
3830
4078
  const lines = [];
3831
- lines.push(buildHeader3(envelope, options.useColors));
4079
+ lines.push(buildHeader5(envelope, options.useColors));
3832
4080
  lines.push(`pageId: ${envelope.pageId}`);
3833
4081
  if (envelope.sourceUrl)
3834
4082
  lines.push(`source: ${envelope.sourceUrl}`);
@@ -3848,12 +4096,50 @@ function formatReadPackageDocTerminal(envelope, options) {
3848
4096
  `)}
3849
4097
  `;
3850
4098
  }
3851
- function buildHeader3(envelope, useColors) {
4099
+ function buildHeader5(envelope, useColors) {
3852
4100
  const badge = envelope.sourceKind === "repo" ? "[repo]" : "[crawled]";
3853
4101
  const title = envelope.title ?? envelope.pageId;
3854
4102
  const prefix = envelope.registry && envelope.name ? `${envelope.registry}:${envelope.name}${envelope.version ? `@${envelope.version}` : ""}` : "documentation";
3855
4103
  return `${colorize(`${prefix} ${badge}`, "bold", useColors)}${title ? ` - ${title}` : ""}`;
3856
4104
  }
4105
+ // src/shared/read-package-doc-text.ts
4106
+ var SEP5 = " | ";
4107
+ function renderReadPackageDocText(envelope) {
4108
+ const lines = [];
4109
+ lines.push(buildHeader6(envelope));
4110
+ if (envelope.sourceUrl)
4111
+ lines.push(`source: ${envelope.sourceUrl}`);
4112
+ if (envelope.filePath) {
4113
+ const ref = envelope.requestedRef ?? envelope.gitRef;
4114
+ lines.push(`file: ${envelope.filePath}${ref ? ` @ ${ref}` : ""}`);
4115
+ }
4116
+ lines.push("");
4117
+ if (envelope.content)
4118
+ lines.push(envelope.content);
4119
+ if (envelope.hint) {
4120
+ lines.push("");
4121
+ lines.push(`hint: ${envelope.hint}`);
4122
+ }
4123
+ return lines.join(`
4124
+ `);
4125
+ }
4126
+ function buildHeader6(envelope) {
4127
+ const parts = [`docs_read${SEP5}${envelope.pageId}`];
4128
+ if (envelope.title)
4129
+ parts.push(envelope.title);
4130
+ const range = buildRange2(envelope);
4131
+ if (range)
4132
+ parts.push(range);
4133
+ return parts.join(SEP5);
4134
+ }
4135
+ function buildRange2(envelope) {
4136
+ if (envelope.startLine !== undefined && envelope.endLine !== undefined) {
4137
+ return envelope.totalLines !== undefined ? `lines ${envelope.startLine}-${envelope.endLine}/${envelope.totalLines}` : `lines ${envelope.startLine}-${envelope.endLine}`;
4138
+ }
4139
+ if (envelope.totalLines !== undefined)
4140
+ return `${envelope.totalLines} lines`;
4141
+ return;
4142
+ }
3857
4143
  // src/shared/unified-search-request.ts
3858
4144
  var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
3859
4145
  function buildUnifiedSearchParams(input) {
@@ -4128,8 +4414,6 @@ function buildHitPayload(hit) {
4128
4414
  payload.title = hit.title;
4129
4415
  if (hit.summary)
4130
4416
  payload.summary = hit.summary;
4131
- if (typeof hit.score === "number")
4132
- payload.score = hit.score;
4133
4417
  const highlights = buildHighlights(hit.highlights);
4134
4418
  if (highlights)
4135
4419
  payload.highlights = highlights;
@@ -4296,49 +4580,17 @@ function assertSearchFollowUpInvariant(hit) {
4296
4580
  throw new MalformedCodeNavigationResponseError("REPOSITORY_DOC search hit missing repo locator fields.");
4297
4581
  }
4298
4582
  }
4299
- // src/shared/unified-search-target.ts
4300
- function parseUnifiedSearchTargetSpec(spec) {
4301
- const trimmed = spec.trim();
4302
- if (trimmed.length === 0) {
4303
- throw new InvalidArgumentError("Target spec cannot be empty.");
4304
- }
4305
- if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
4306
- return parseRepoTarget(trimmed);
4307
- }
4308
- const parsed = parsePackageSpec(trimmed);
4309
- return {
4310
- registry: toCodeNavigationRegistry(parsed.registry),
4311
- packageName: parsed.name,
4312
- version: parsed.version
4313
- };
4314
- }
4315
- function parseRepoTarget(spec) {
4316
- const hashIndex = spec.lastIndexOf("#");
4317
- if (hashIndex === -1) {
4318
- return { repoUrl: spec, gitRef: "HEAD" };
4319
- }
4320
- const repoUrl = spec.slice(0, hashIndex);
4321
- const gitRef = spec.slice(hashIndex + 1);
4322
- if (!repoUrl || !gitRef) {
4323
- throw new InvalidArgumentError("Repository target must be a full URL with optional #gitRef suffix.");
4324
- }
4325
- return { repoUrl, gitRef };
4326
- }
4327
4583
  // src/shared/unified-search-text.ts
4328
4584
  var SUMMARY_WRAP_WIDTH = 76;
4329
- var SEP3 = " | ";
4585
+ var SEP6 = " | ";
4330
4586
  function renderUnifiedSearchSuccess(payload) {
4331
4587
  const lines = [];
4332
- lines.push(buildHeader4(payload));
4588
+ lines.push(buildHeader7(payload));
4333
4589
  lines.push("");
4334
4590
  if (payload.results.length === 0) {
4335
4591
  lines.push(payload.completed ? "No hits." : "No hits yet - indexing.");
4336
4592
  } else {
4337
- payload.results.forEach((hit, idx) => {
4338
- if (idx > 0)
4339
- lines.push("");
4340
- appendHit(lines, idx + 1, hit);
4341
- });
4593
+ appendUnifiedSearchHits(lines, payload.results);
4342
4594
  }
4343
4595
  const trailer = buildTrailer2(payload);
4344
4596
  if (trailer.length > 0) {
@@ -4351,7 +4603,7 @@ function renderUnifiedSearchSuccess(payload) {
4351
4603
  }
4352
4604
  function renderUnifiedSearchError(payload) {
4353
4605
  const lines = [];
4354
- const header = `search${SEP3}ERROR${SEP3}code=${payload.code}${payload.retryable ? `${SEP3}retryable` : ""}`;
4606
+ const header = `search${SEP6}ERROR${SEP6}code=${payload.code}${payload.retryable ? `${SEP6}retryable` : ""}`;
4355
4607
  lines.push(header);
4356
4608
  lines.push(payload.error);
4357
4609
  if (payload.details && Object.keys(payload.details).length > 0) {
@@ -4364,21 +4616,25 @@ function renderUnifiedSearchError(payload) {
4364
4616
  return lines.join(`
4365
4617
  `);
4366
4618
  }
4367
- function buildHeader4(payload) {
4619
+ function buildHeader7(payload) {
4368
4620
  const count = payload.results.length;
4369
4621
  const status = payload.completed ? `${count} hit${count === 1 ? "" : "s"}` : `${count} partial`;
4370
- const parts = [`search${SEP3}${status}`];
4371
- parts.push(`query=${quote3(payload.query.raw)}`);
4622
+ const parts = [`search${SEP6}${status}`];
4623
+ parts.push(`query=${quote4(payload.query.raw)}`);
4372
4624
  if (!payload.completed) {
4373
4625
  parts.push(`searchRef=${payload.searchRef}`);
4374
4626
  }
4375
- return parts.join(SEP3);
4627
+ return parts.join(SEP6);
4628
+ }
4629
+ function appendUnifiedSearchHits(lines, hits) {
4630
+ hits.forEach((hit, idx) => {
4631
+ if (idx > 0)
4632
+ lines.push("");
4633
+ appendHit(lines, idx + 1, hit);
4634
+ });
4376
4635
  }
4377
4636
  function appendHit(lines, index, hit) {
4378
4637
  const headerParts = [hit.target, shortType(hit.type)];
4379
- if (typeof hit.score === "number") {
4380
- headerParts.push(formatScore(hit.score));
4381
- }
4382
4638
  lines.push(`[${index}] ${headerParts.join(" ")}`);
4383
4639
  const locator = buildLocatorLine(hit);
4384
4640
  if (locator)
@@ -4408,6 +4664,15 @@ function shortType(type) {
4408
4664
  }
4409
4665
  function buildLocatorLine(hit) {
4410
4666
  const loc = hit.locator;
4667
+ const followUp = buildSearchHitFollowUpCommand(hit);
4668
+ if (followUp) {
4669
+ const tail = [];
4670
+ if (loc.qualifiedPath)
4671
+ tail.push(loc.qualifiedPath);
4672
+ if (loc.kind)
4673
+ tail.push(loc.kind);
4674
+ return tail.length > 0 ? `${followUp} ${tail.join(SEP6)}` : followUp;
4675
+ }
4411
4676
  if (loc.filePath) {
4412
4677
  let line = `${loc.filePath}${formatLineRange(loc.startLine, loc.endLine)}`;
4413
4678
  const tail = [];
@@ -4416,7 +4681,7 @@ function buildLocatorLine(hit) {
4416
4681
  if (loc.kind)
4417
4682
  tail.push(loc.kind);
4418
4683
  if (tail.length > 0)
4419
- line += ` ${tail.join(SEP3)}`;
4684
+ line += ` ${tail.join(SEP6)}`;
4420
4685
  return line;
4421
4686
  }
4422
4687
  if (loc.pageId)
@@ -4432,9 +4697,6 @@ function formatLineRange(start, end) {
4432
4697
  return `:${start}`;
4433
4698
  return `:${start}-${end}`;
4434
4699
  }
4435
- function formatScore(score) {
4436
- return score.toFixed(2);
4437
- }
4438
4700
  function buildTrailer2(payload) {
4439
4701
  const lines = [];
4440
4702
  if (payload.warnings && payload.warnings.length > 0) {
@@ -4478,9 +4740,9 @@ function formatSourceStatus(entry) {
4478
4740
  }
4479
4741
  if (entry.note)
4480
4742
  parts.push(entry.note);
4481
- return parts.join(SEP3);
4743
+ return parts.join(SEP6);
4482
4744
  }
4483
- function quote3(value) {
4745
+ function quote4(value) {
4484
4746
  return value.includes('"') ? `'${value}'` : `"${value}"`;
4485
4747
  }
4486
4748
  function formatDetailValue(value) {
@@ -4512,6 +4774,89 @@ function wrapText2(text, width) {
4512
4774
  }
4513
4775
  return lines;
4514
4776
  }
4777
+
4778
+ // src/shared/unified-search-status-text.ts
4779
+ var SEP7 = " | ";
4780
+ function renderUnifiedSearchStatusText(payload) {
4781
+ const lines = [];
4782
+ lines.push(buildHeader8(payload));
4783
+ if (!payload.completed && payload.progress) {
4784
+ lines.push(formatProgress(payload.progress));
4785
+ }
4786
+ const result = payload.result;
4787
+ if (result)
4788
+ appendResult(lines, result);
4789
+ if (!payload.completed) {
4790
+ lines.push(`next: call search_status search_ref=${quote5(payload.searchRef)}`);
4791
+ }
4792
+ return lines.join(`
4793
+ `);
4794
+ }
4795
+ function buildHeader8(payload) {
4796
+ const state = payload.completed ? "complete" : "indexing";
4797
+ const parts = [`search_status${SEP7}${state}`];
4798
+ if (payload.searchRef)
4799
+ parts.push(`searchRef=${payload.searchRef}`);
4800
+ return parts.join(SEP7);
4801
+ }
4802
+ function appendResult(lines, result) {
4803
+ lines.push("");
4804
+ if (result.warnings && result.warnings.length > 0) {
4805
+ lines.push("warnings:");
4806
+ for (const warning2 of result.warnings)
4807
+ lines.push(` - ${warning2}`);
4808
+ lines.push("");
4809
+ }
4810
+ if (result.results.length === 0) {
4811
+ lines.push("No hits.");
4812
+ } else {
4813
+ appendUnifiedSearchHits(lines, result.results);
4814
+ }
4815
+ if (result.hasMore) {
4816
+ const nextOffsetHint = typeof result.nextOffset === "number" ? ` Pass offset=${result.nextOffset} for the next page or limit=N to widen.` : " Pass limit=N to widen.";
4817
+ lines.push("");
4818
+ lines.push(`More hits available.${nextOffsetHint}`);
4819
+ }
4820
+ if (result.sourceStatus && result.sourceStatus.length > 0) {
4821
+ lines.push("");
4822
+ lines.push("source notes:");
4823
+ for (const entry of result.sourceStatus) {
4824
+ lines.push(` - ${formatSourceStatus2(entry)}`);
4825
+ }
4826
+ }
4827
+ }
4828
+ function formatSourceStatus2(entry) {
4829
+ const parts = [`${entry.source} (${entry.targetLabel})`];
4830
+ if (entry.indexingStatus)
4831
+ parts.push(`indexing=${entry.indexingStatus}`);
4832
+ if (entry.codeIndexState)
4833
+ parts.push(`codeIndex=${entry.codeIndexState}`);
4834
+ if (entry.ignoredFilters?.length) {
4835
+ parts.push(`ignored=${entry.ignoredFilters.join(",")}`);
4836
+ }
4837
+ if (entry.incompatibleFilters?.length) {
4838
+ parts.push(`incompatible=${entry.incompatibleFilters.join(",")}`);
4839
+ }
4840
+ if (entry.ignoredQueryFeatures?.length) {
4841
+ parts.push(`ignoredQuery=${entry.ignoredQueryFeatures.join(",")}`);
4842
+ }
4843
+ if (entry.incompatibleQueryFeatures?.length) {
4844
+ parts.push(`incompatibleQuery=${entry.incompatibleQueryFeatures.join(",")}`);
4845
+ }
4846
+ if (entry.note)
4847
+ parts.push(entry.note);
4848
+ return parts.join(SEP7);
4849
+ }
4850
+ function formatProgress(progress) {
4851
+ return `progress: ${progress.status}, ${progress.targetsReady}/${progress.targetsTotal} targets ready, ${progress.elapsedMs}ms elapsed`;
4852
+ }
4853
+ function quote5(value) {
4854
+ return JSON.stringify(value);
4855
+ }
4856
+ // src/shared/unified-search-target.ts
4857
+ function parseUnifiedSearchTargetSpec(spec) {
4858
+ return parseCodeNavigationTargetSpec(spec);
4859
+ }
4515
4860
  // src/shared/list-files-request.ts
4516
4861
  var LIMIT_MIN2 = 1;
4517
4862
  var LIMIT_MAX2 = 1000;
@@ -4522,20 +4867,140 @@ function buildListFilesParams(input) {
4522
4867
  const limitExplicit = input.limit !== undefined;
4523
4868
  const limit = normaliseLimit(input.limit);
4524
4869
  const waitTimeoutMs = normaliseWaitTimeoutMs(input.waitTimeoutMs);
4870
+ const path = normalizeOptionalNonEmpty2(input.path, "path");
4525
4871
  const pathPrefix = normalisePathPrefix(input.pathPrefix);
4872
+ const globs = normalizeStringList2(input.globs, "globs");
4873
+ const extensions = normalizeExtensions2(input.extensions);
4874
+ const fileTypes = normalizeStringList2(input.fileTypes, "file_types");
4875
+ const languages = normalizeStringList2(input.languages, "languages");
4876
+ const { fileIntent, fileIntentEcho } = normalizeOptionalFileIntent(input.fileIntent, "file_intent");
4877
+ const fileIntents = normalizeFileIntentList(input.fileIntents, "file_intents");
4878
+ const excludeFileIntents = normalizeFileIntentList(input.excludeFileIntents, "exclude_file_intents");
4879
+ if (fileIntent && fileIntents.length > 0) {
4880
+ throw new InvalidPackageSpecError("`file_intent` cannot be combined with `file_intents`.");
4881
+ }
4882
+ const pathSelectors = buildPathSelectors2({ path, globs });
4883
+ const pathExplicit = path !== undefined;
4526
4884
  const pathPrefixExplicit = pathPrefix !== undefined;
4885
+ const globsExplicit = globs.length > 0;
4527
4886
  return {
4528
4887
  params: {
4529
4888
  target: input.target,
4889
+ pathSelectors,
4530
4890
  pathPrefix,
4891
+ extensions: extensions.length > 0 ? extensions : undefined,
4892
+ fileTypes: fileTypes.length > 0 ? fileTypes : undefined,
4893
+ languages: languages.length > 0 ? languages : undefined,
4894
+ fileIntent,
4895
+ fileIntents: fileIntents.length > 0 ? fileIntents : undefined,
4896
+ excludeFileIntents: excludeFileIntents.length > 0 ? excludeFileIntents : undefined,
4897
+ excludeDocFiles: input.excludeDocFiles,
4898
+ excludeTestFiles: input.excludeTestFiles,
4899
+ includeHidden: input.includeHidden,
4531
4900
  limit,
4532
4901
  waitTimeoutMs
4533
4902
  },
4534
4903
  effectiveLimit: limit,
4535
4904
  limitExplicit,
4536
- pathPrefixExplicit
4905
+ explicit: {
4906
+ path: pathExplicit,
4907
+ pathPrefix: pathPrefixExplicit,
4908
+ globs: globsExplicit,
4909
+ extensions: extensions.length > 0,
4910
+ fileTypes: fileTypes.length > 0,
4911
+ languages: languages.length > 0,
4912
+ fileIntent: fileIntent !== undefined,
4913
+ fileIntents: fileIntents.length > 0,
4914
+ excludeFileIntents: excludeFileIntents.length > 0,
4915
+ excludeDocFiles: input.excludeDocFiles !== undefined,
4916
+ excludeTestFiles: input.excludeTestFiles !== undefined,
4917
+ includeHidden: input.includeHidden !== undefined,
4918
+ limit: limitExplicit
4919
+ },
4920
+ filterEcho: {
4921
+ path,
4922
+ pathPrefix,
4923
+ globs: globsExplicit ? globs : undefined,
4924
+ extensions: extensions.length > 0 ? extensions : undefined,
4925
+ fileTypes: fileTypes.length > 0 ? fileTypes : undefined,
4926
+ languages: languages.length > 0 ? languages : undefined,
4927
+ fileIntent: fileIntentEcho,
4928
+ fileIntents: fileIntents.length > 0 ? fileIntents.map((intent) => intent.toLowerCase()) : undefined,
4929
+ excludeFileIntents: excludeFileIntents.length > 0 ? excludeFileIntents.map((intent) => intent.toLowerCase()) : undefined,
4930
+ excludeDocFiles: input.excludeDocFiles,
4931
+ excludeTestFiles: input.excludeTestFiles,
4932
+ includeHidden: input.includeHidden,
4933
+ limit: limitExplicit ? limit : undefined
4934
+ }
4935
+ };
4936
+ }
4937
+ function buildPathSelectors2(input) {
4938
+ const selectors = [];
4939
+ if (input.path)
4940
+ selectors.push({ kind: "EXACT", value: input.path });
4941
+ for (const glob of input.globs) {
4942
+ selectors.push({ kind: "GLOB", value: glob });
4943
+ }
4944
+ return selectors.length > 0 ? selectors : undefined;
4945
+ }
4946
+ function normalizeOptionalNonEmpty2(raw, field) {
4947
+ if (raw === undefined)
4948
+ return;
4949
+ const trimmed = raw.trim();
4950
+ if (trimmed.length === 0) {
4951
+ throw new InvalidPackageSpecError(`\`${field}\` cannot be empty when provided.`);
4952
+ }
4953
+ return trimmed;
4954
+ }
4955
+ function normalizeStringList2(raw, field) {
4956
+ if (!raw)
4957
+ return [];
4958
+ const values = [];
4959
+ for (const entry of raw) {
4960
+ const trimmed = entry.trim();
4961
+ if (trimmed.length === 0) {
4962
+ throw new InvalidPackageSpecError(`\`${field}\` entries cannot be empty.`);
4963
+ }
4964
+ values.push(trimmed);
4965
+ }
4966
+ return values;
4967
+ }
4968
+ function normalizeExtensions2(raw) {
4969
+ const values = normalizeStringList2(raw, "extensions");
4970
+ for (const value of values) {
4971
+ if (value.startsWith(".")) {
4972
+ throw new InvalidPackageSpecError("`extensions` values must not include a leading dot.");
4973
+ }
4974
+ }
4975
+ return values;
4976
+ }
4977
+ function normalizeOptionalFileIntent(raw, field) {
4978
+ if (raw === undefined)
4979
+ return {};
4980
+ const trimmed = raw.trim().toLowerCase();
4981
+ if (trimmed.length === 0) {
4982
+ throw new InvalidPackageSpecError(`\`${field}\` cannot be empty when provided.`);
4983
+ }
4984
+ if (!isKnownFileIntent(trimmed)) {
4985
+ throw new InvalidPackageSpecError(`\`${field}\` must be one of: ${knownFileIntentList().join(", ")}. Got ${raw}.`);
4986
+ }
4987
+ return {
4988
+ fileIntent: toFileIntent(trimmed),
4989
+ fileIntentEcho: trimmed
4537
4990
  };
4538
4991
  }
4992
+ function normalizeFileIntentList(raw, field) {
4993
+ const values = normalizeStringList2(raw, field);
4994
+ const intents = [];
4995
+ for (const value of values) {
4996
+ const lower = value.toLowerCase();
4997
+ if (!isKnownFileIntent(lower)) {
4998
+ throw new InvalidPackageSpecError(`\`${field}\` values must be one of: ${knownFileIntentList().join(", ")}. Got ${value}.`);
4999
+ }
5000
+ intents.push(toFileIntent(lower));
5001
+ }
5002
+ return intents;
5003
+ }
4539
5004
  function normaliseLimit(raw) {
4540
5005
  if (raw === undefined)
4541
5006
  return LIMIT_DEFAULT2;
@@ -4614,10 +5079,43 @@ function projectResolution2(resolution) {
4614
5079
  }
4615
5080
  function buildFilterBlock2(options) {
4616
5081
  const filter = {};
4617
- if (options.pathPrefixExplicit && options.pathPrefix) {
5082
+ if (options.explicit.path && options.path) {
5083
+ filter.path = options.path;
5084
+ }
5085
+ if (options.explicit.pathPrefix && options.pathPrefix) {
4618
5086
  filter.pathPrefix = options.pathPrefix;
4619
5087
  }
4620
- if (options.limitExplicit && options.limit !== undefined) {
5088
+ if (options.explicit.globs && options.globs && options.globs.length > 0) {
5089
+ filter.globs = options.globs;
5090
+ }
5091
+ if (options.explicit.extensions && options.extensions && options.extensions.length > 0) {
5092
+ filter.extensions = options.extensions;
5093
+ }
5094
+ if (options.explicit.fileTypes && options.fileTypes && options.fileTypes.length > 0) {
5095
+ filter.fileTypes = options.fileTypes;
5096
+ }
5097
+ if (options.explicit.languages && options.languages && options.languages.length > 0) {
5098
+ filter.languages = options.languages;
5099
+ }
5100
+ if (options.explicit.fileIntent && options.fileIntent) {
5101
+ filter.fileIntent = options.fileIntent;
5102
+ }
5103
+ if (options.explicit.fileIntents && options.fileIntents && options.fileIntents.length > 0) {
5104
+ filter.fileIntents = options.fileIntents;
5105
+ }
5106
+ if (options.explicit.excludeFileIntents && options.excludeFileIntents && options.excludeFileIntents.length > 0) {
5107
+ filter.excludeFileIntents = options.excludeFileIntents;
5108
+ }
5109
+ if (options.explicit.excludeDocFiles) {
5110
+ filter.excludeDocFiles = options.excludeDocFiles;
5111
+ }
5112
+ if (options.explicit.excludeTestFiles) {
5113
+ filter.excludeTestFiles = options.excludeTestFiles;
5114
+ }
5115
+ if (options.explicit.includeHidden) {
5116
+ filter.includeHidden = options.includeHidden;
5117
+ }
5118
+ if (options.explicit.limit && options.limit !== undefined) {
4621
5119
  filter.limit = options.limit;
4622
5120
  }
4623
5121
  return Object.keys(filter).length > 0 ? filter : undefined;
@@ -4869,9 +5367,19 @@ async function pkgFilesAction(firstArg, secondArg, options, deps) {
4869
5367
  const target = resolveCliCodeNavTarget(spec, options);
4870
5368
  const limit = parseIntCliOption(options.limit, "--limit", 1, 1000);
4871
5369
  const wait = parseIntCliOption(options.wait, "--wait", 0, MAX_WAIT_TIMEOUT_MS);
4872
- const build = buildListFilesParams({
5370
+ const build = buildCliListFilesParams({
4873
5371
  target,
5372
+ path: options.path,
4874
5373
  pathPrefix,
5374
+ globs: options.glob,
5375
+ extensions: options.ext,
5376
+ fileTypes: options.fileType,
5377
+ languages: options.language,
5378
+ fileIntents: options.fileIntent,
5379
+ excludeFileIntents: options.excludeIntent,
5380
+ excludeDocFiles: options.excludeDocs,
5381
+ excludeTestFiles: options.excludeTests,
5382
+ includeHidden: options.hidden,
4875
5383
  limit,
4876
5384
  waitTimeoutMs: wait
4877
5385
  });
@@ -4881,10 +5389,20 @@ async function pkgFilesAction(firstArg, secondArg, options, deps) {
4881
5389
  name: target.packageName,
4882
5390
  repoUrl: target.repoUrl,
4883
5391
  gitRef: target.gitRef,
4884
- limitExplicit: build.limitExplicit,
4885
- pathPrefixExplicit: build.pathPrefixExplicit,
4886
- pathPrefix: build.params.pathPrefix,
4887
- limit: build.params.limit
5392
+ path: build.filterEcho.path,
5393
+ pathPrefix: build.filterEcho.pathPrefix,
5394
+ globs: build.filterEcho.globs,
5395
+ extensions: build.filterEcho.extensions,
5396
+ fileTypes: build.filterEcho.fileTypes,
5397
+ languages: build.filterEcho.languages,
5398
+ fileIntent: build.filterEcho.fileIntent,
5399
+ fileIntents: build.filterEcho.fileIntents,
5400
+ excludeFileIntents: build.filterEcho.excludeFileIntents,
5401
+ excludeDocFiles: build.filterEcho.excludeDocFiles,
5402
+ excludeTestFiles: build.filterEcho.excludeTestFiles,
5403
+ includeHidden: build.filterEcho.includeHidden,
5404
+ limit: build.filterEcho.limit,
5405
+ explicit: build.explicit
4888
5406
  });
4889
5407
  if (options.json) {
4890
5408
  console.log(JSON.stringify(payload));
@@ -4901,6 +5419,21 @@ async function pkgFilesAction(firstArg, secondArg, options, deps) {
4901
5419
  handleCodeNavCommandError(error2, options.json ?? false, formatIndexingError);
4902
5420
  }
4903
5421
  }
5422
+ function collectRepeatable(value, previous) {
5423
+ return [...previous ?? [], value];
5424
+ }
5425
+ function buildCliListFilesParams(input) {
5426
+ try {
5427
+ return buildListFilesParams(input);
5428
+ } catch (error2) {
5429
+ if (!(error2 instanceof InvalidPackageSpecError))
5430
+ throw error2;
5431
+ const rewritten = error2.message.replace(/^`path`/, "`--path`").replace(/`globs`/g, "`--glob`").replace(/`extensions`/g, "`--ext`").replace(/`file_types`/g, "`--file-type`").replace(/`languages`/g, "`--language`").replace(/`file_intent`/g, "`--file-intent`").replace(/`file_intents`/g, "`--file-intent`").replace(/`exclude_file_intents`/g, "`--exclude-intent`").replace(/`path_prefix`/g, "`[path-prefix]`");
5432
+ if (rewritten === error2.message)
5433
+ throw error2;
5434
+ throw new InvalidPackageSpecError(rewritten);
5435
+ }
5436
+ }
4904
5437
  var REGISTRY_SPEC_HINT = /^(npm|pypi|hex|crates|nuget|maven|zig|vcpkg|packagist):/i;
4905
5438
  function resolvePositionals(firstArg, secondArg, hasRepoUrl) {
4906
5439
  if (hasRepoUrl) {
@@ -4920,8 +5453,11 @@ fetch more. Returned paths feed directly into \`githits code read\`
4920
5453
  and \`githits code grep\`.
4921
5454
 
4922
5455
  [path-prefix] is a literal directory prefix (e.g. \`src/\` or
4923
- \`lib/parser\`), NOT a glob \`*.ts\` and similar patterns won't
4924
- match. File-type / extension filtering is not supported server-side.
5456
+ \`lib/parser\`). Use --path for exact-file selectors, repeatable
5457
+ --glob for glob selectors, and --ext / --file-type / --language /
5458
+ --file-intent to intersect further. Selectors ([path-prefix], --path,
5459
+ --glob) are OR-ed — a file matches if any selector matches. The other
5460
+ filters intersect on top.
4925
5461
 
4926
5462
  Addressing: <spec> (registry:name[@version]) OR --repo-url <url>
4927
5463
  --git-ref <ref>. Supported registries: npm, pypi, hex, crates,
@@ -4934,7 +5470,7 @@ On an INDEXING response, the dependency is being indexed on-demand
4934
5470
  — retry with a longer --wait (up to 60000 ms) or pick one of the
4935
5471
  already-indexed versions surfaced in the error detail.`;
4936
5472
  function registerCodeFilesCommand(pkgCommand) {
4937
- return pkgCommand.command("files").summary("List files in an indexed dependency").description(PKG_FILES_DESCRIPTION).argument("[spec-or-prefix]", "Spec mode: package spec (e.g. npm:express). Repo mode (with --repo-url): the path-prefix.").argument("[path-prefix]", "Spec mode only: literal directory prefix (not a glob). Ignored with --repo-url.").option("--repo-url <url>", "Repository URL addressing (requires --git-ref)").option("--git-ref <ref>", "Tag, commit, branch, or HEAD. Required with --repo-url.").option("--limit <n>", "Max entries (1-1000, default 200)").option("--wait <ms>", `Indexing wait timeout (0-${MAX_WAIT_TIMEOUT_MS}, default ${DEFAULT_WAIT_TIMEOUT_MS})`).option("-v, --verbose", "Annotate each path with language / file-type / byte size").option("--json", "Emit the JSON envelope").action(async (arg1, arg2, options) => {
5473
+ return pkgCommand.command("files").summary("List files in an indexed dependency").description(PKG_FILES_DESCRIPTION).argument("[spec-or-prefix]", "Spec mode: package spec (e.g. npm:express). Repo mode (with --repo-url): the path-prefix.").argument("[path-prefix]", "Spec mode only: literal directory prefix (not a glob). Ignored with --repo-url.").option("--repo-url <url>", "Repository URL addressing (requires --git-ref)").option("--git-ref <ref>", "Tag, commit, branch, or HEAD. Required with --repo-url.").option("--path <path>", "Exact file selector").option("--glob <glob>", "Glob selector (repeatable)", collectRepeatable).option("--ext <ext>", "Extension filter without leading dot (repeatable)", collectRepeatable).option("--file-type <type>", "File type filter such as source or doc (repeatable)", collectRepeatable).option("--language <language>", "Language filter matching aigrep language names (repeatable)", collectRepeatable).option("--file-intent <intent>", "Inclusive file-intent filter. Repeat to include multiple intents: production, test, benchmark, example, generated, fixture, build, vendor", collectRepeatable).option("--exclude-intent <intent>", "Exclude these file intents after inclusive filtering (repeatable)", collectRepeatable).option("--exclude-docs", "Skip files classified as documentation").option("--exclude-tests", "Skip files classified as tests").option("--hidden", "Include dotfiles and dot-prefixed paths").option("--limit <n>", "Max entries (1-1000, default 200)").option("--wait <ms>", `Indexing wait timeout (0-${MAX_WAIT_TIMEOUT_MS}, default ${DEFAULT_WAIT_TIMEOUT_MS})`).option("-v, --verbose", "Annotate each path with language / file-type / byte size").option("--json", "Emit the JSON envelope").action(async (arg1, arg2, options) => {
4938
5474
  const deps = await createContainer();
4939
5475
  await pkgFilesAction(arg1, arg2, options, {
4940
5476
  codeNavigationService: deps.codeNavigationService,
@@ -5041,7 +5577,7 @@ function resolvePositionals2(first, second, third, hasRepoUrl) {
5041
5577
  }
5042
5578
  return { spec: first, pattern: second, pathPrefix: third };
5043
5579
  }
5044
- function collectRepeatable(value, previous = []) {
5580
+ function collectRepeatable2(value, previous = []) {
5045
5581
  return [...previous, value];
5046
5582
  }
5047
5583
  function buildCliGrepParams(input) {
@@ -5076,8 +5612,8 @@ for context, --verbose for grouped output, and --cursor to continue a paginated
5076
5612
  grep run. --symbol-field hydrates enclosing symbol metadata (appears under each
5077
5613
  match in --verbose output; full payload in --json).`;
5078
5614
  function registerCodeGrepCommand(pkgCommand) {
5079
- return pkgCommand.command("grep").summary("Deterministic text grep over indexed dependency source").description(PKG_GREP_DESCRIPTION).argument("[spec-or-pattern]", "Spec mode: package spec (e.g. npm:express). Repo mode (with --repo-url): the pattern.").argument("[pattern-or-prefix]", "Spec mode: the pattern. Repo mode: optional path-prefix.").argument("[path-prefix]", "Spec mode only: optional path-prefix. Ignored with --repo-url.").option("--repo-url <url>", "Repository URL addressing (requires --git-ref)").option("--git-ref <ref>", "Tag, commit, branch, or HEAD. Required with --repo-url.").option("--path <path>", "Exact file path to grep").option("--glob <glob>", "Glob scope (repeatable)", collectRepeatable, []).option("--ext <ext>", "Extension filter without leading dot (repeatable)", collectRepeatable, []).option("--regex", "Interpret the pattern as RE2 regex").option("--case-sensitive", "Enable ASCII case-sensitive matching").option("-C, --context <n>", "Context lines before and after each match (0-10)").option("-B, --before-context <n>", "Context lines before each match (0-10)").option("-A, --after-context <n>", "Context lines after each match (0-10)").option("--exclude-docs", "Skip files classified as documentation").option("--exclude-tests", "Skip files classified as tests").option("--limit <n>", "Max matches to return on this page (1-1000, default 50)").option("--per-file-limit <n>", "Cap matches per file within this page (0-1000, 0 = unlimited)").option("--cursor <cursor>", "Opaque nextCursor from a previous grep result").option("--symbol-field <field>", `Repeatable; surfaces in --json and under each --verbose match. ${GREP_REPO_SYMBOL_FIELDS_NOTE}`, collectRepeatable, []).option("--wait <ms>", `Indexing wait timeout (0-${MAX_WAIT_TIMEOUT_MS}, default ${DEFAULT_WAIT_TIMEOUT_MS})`).option("-v, --verbose", "Render grouped output with file headers").option("--json", "Emit the JSON envelope").action(async (arg1, arg2, arg3, options) => {
5080
- const { createContainer: createContainer2 } = await import("./shared/chunk-zg5dnven.js");
5615
+ return pkgCommand.command("grep").summary("Deterministic text grep over indexed dependency source").description(PKG_GREP_DESCRIPTION).argument("[spec-or-pattern]", "Spec mode: package spec (e.g. npm:express). Repo mode (with --repo-url): the pattern.").argument("[pattern-or-prefix]", "Spec mode: the pattern. Repo mode: optional path-prefix.").argument("[path-prefix]", "Spec mode only: optional path-prefix. Ignored with --repo-url.").option("--repo-url <url>", "Repository URL addressing (requires --git-ref)").option("--git-ref <ref>", "Tag, commit, branch, or HEAD. Required with --repo-url.").option("--path <path>", "Exact file path to grep").option("--glob <glob>", "Glob scope (repeatable)", collectRepeatable2, []).option("--ext <ext>", "Extension filter without leading dot (repeatable)", collectRepeatable2, []).option("--regex", "Interpret the pattern as RE2 regex").option("--case-sensitive", "Enable ASCII case-sensitive matching").option("-C, --context <n>", "Context lines before and after each match (0-10)").option("-B, --before-context <n>", "Context lines before each match (0-10)").option("-A, --after-context <n>", "Context lines after each match (0-10)").option("--exclude-docs", "Skip files classified as documentation").option("--exclude-tests", "Skip files classified as tests").option("--limit <n>", "Max matches to return on this page (1-1000, default 50)").option("--per-file-limit <n>", "Cap matches per file within this page (0-1000, 0 = unlimited)").option("--cursor <cursor>", "Opaque nextCursor from a previous grep result").option("--symbol-field <field>", `Repeatable; surfaces in --json and under each --verbose match. ${GREP_REPO_SYMBOL_FIELDS_NOTE}`, collectRepeatable2, []).option("--wait <ms>", `Indexing wait timeout (0-${MAX_WAIT_TIMEOUT_MS}, default ${DEFAULT_WAIT_TIMEOUT_MS})`).option("-v, --verbose", "Render grouped output with file headers").option("--json", "Emit the JSON envelope").action(async (arg1, arg2, arg3, options) => {
5616
+ const { createContainer: createContainer2 } = await import("./shared/chunk-rwcs5gyy.js");
5081
5617
  const deps = await createContainer2();
5082
5618
  await pkgGrepAction(arg1, arg2, arg3, options, {
5083
5619
  codeNavigationService: deps.codeNavigationService,
@@ -5173,7 +5709,7 @@ function formatReadFileTerminal(envelope, options) {
5173
5709
  function formatBinary(envelope, options, verbose) {
5174
5710
  const sentinel = dim("Binary file — cannot display as text.", options.useColors);
5175
5711
  if (verbose) {
5176
- return `${buildHeader5(envelope, options)}
5712
+ return `${buildHeader9(envelope, options)}
5177
5713
 
5178
5714
  ${sentinel}
5179
5715
  `;
@@ -5184,7 +5720,7 @@ ${sentinel}
5184
5720
  function formatNoContent(envelope, options, verbose) {
5185
5721
  const sentinel = dim("(no content returned)", options.useColors);
5186
5722
  if (verbose) {
5187
- return `${buildHeader5(envelope, options)}
5723
+ return `${buildHeader9(envelope, options)}
5188
5724
 
5189
5725
  ${sentinel}
5190
5726
  `;
@@ -5194,7 +5730,7 @@ ${sentinel}
5194
5730
  }
5195
5731
  function formatVerboseBody(envelope, options) {
5196
5732
  const lines = [];
5197
- lines.push(buildHeader5(envelope, options));
5733
+ lines.push(buildHeader9(envelope, options));
5198
5734
  lines.push("");
5199
5735
  const content = envelope.content ?? "";
5200
5736
  const bodyLines = content.split(`
@@ -5218,7 +5754,7 @@ function formatVerboseBody(envelope, options) {
5218
5754
  return lines.join(`
5219
5755
  `);
5220
5756
  }
5221
- function buildHeader5(envelope, options) {
5757
+ function buildHeader9(envelope, options) {
5222
5758
  const parts = [envelope.path];
5223
5759
  if (envelope.language)
5224
5760
  parts.push(envelope.language);
@@ -5596,7 +6132,7 @@ function registerExampleCommand(program) {
5596
6132
  });
5597
6133
  }
5598
6134
  async function loadContainer() {
5599
- const { createContainer: createContainer2 } = await import("./shared/chunk-zg5dnven.js");
6135
+ const { createContainer: createContainer2 } = await import("./shared/chunk-rwcs5gyy.js");
5600
6136
  return createContainer2();
5601
6137
  }
5602
6138
  // src/commands/feedback.ts
@@ -6778,7 +7314,11 @@ async function languagesAction(query, options, deps) {
6778
7314
  requireAuth(deps);
6779
7315
  try {
6780
7316
  const allLanguages = await deps.githitsService.getLanguages();
6781
- const displayList = query ? filterLanguages(allLanguages, query) : allLanguages.map(({ name, display_name }) => ({ name, display_name }));
7317
+ const displayList = query ? filterLanguages(allLanguages, query) : allLanguages.map(({ name, display_name, aliases }) => ({
7318
+ name,
7319
+ display_name,
7320
+ aliases
7321
+ }));
6782
7322
  if (options.json) {
6783
7323
  console.log(JSON.stringify(displayList));
6784
7324
  } else if (query && displayList.length === 0) {
@@ -6918,11 +7458,12 @@ import { z as z2 } from "zod";
6918
7458
  var schema2 = {
6919
7459
  query: z2.string().min(1).describe("Natural-language example-search query for canonical code examples."),
6920
7460
  language: z2.string().min(1).optional().describe("Optional programming language. If omitted, GitHits tries to infer it automatically. Use search_language first only when you need to force a specific language and the exact name is uncertain."),
6921
- license_mode: z2.enum(["strict", "yolo", "custom"]).optional().describe("License filtering mode: strict (default), yolo, or custom.")
7461
+ license_mode: z2.enum(["strict", "yolo", "custom"]).optional().describe("License filtering mode: strict (default), yolo, or custom."),
7462
+ format: z2.enum(["json", "text", "text-v1"]).optional().describe("Response format. Default `text-v1` returns markdown directly with a trailing `solution_id` line when available. Pass `json` for `{result, solution_id?}`.")
6922
7463
  };
6923
7464
  var DESCRIPTION2 = `Get verified, canonical code examples from global open source.
6924
7465
 
6925
- Returns JSON \`{result, solution_id?}\`. \`result\` is markdown render or quote it directly. Pass \`solution_id\` to \`feedback\` after using or rejecting the example. For searching indexed dependency and repository code/docs, use the unified \`search\` tool instead.`;
7466
+ Default output is markdown, with a trailing \`solution_id: ...\` line when available. Pass \`format: "json"\` for \`{result, solution_id?}\`. Pass \`solution_id\` to \`feedback\` after using or rejecting the example. For searching indexed dependency and repository code/docs, use the unified \`search\` tool instead.`;
6926
7467
  function createGetExampleTool(service) {
6927
7468
  return {
6928
7469
  name: "get_example",
@@ -6938,17 +7479,25 @@ function createGetExampleTool(service) {
6938
7479
  });
6939
7480
  const solutionId = extractSolutionId(markdown);
6940
7481
  const payload = solutionId ? { result: markdown, solution_id: solutionId } : { result: markdown };
7482
+ if (isTextFormat(args.format)) {
7483
+ return textResult(solutionId ? `${markdown.trimEnd()}
7484
+
7485
+ solution_id: ${solutionId}` : markdown);
7486
+ }
6941
7487
  return textResult(JSON.stringify(payload));
6942
7488
  });
6943
7489
  }
6944
7490
  };
6945
7491
  }
7492
+ function isTextFormat(format) {
7493
+ return format === undefined || format === "text" || format === "text-v1";
7494
+ }
6946
7495
  // src/tools/grep-repo.ts
6947
7496
  import { z as z4 } from "zod";
6948
7497
 
6949
7498
  // src/tools/code-navigation-shared.ts
6950
7499
  import { z as z3 } from "zod";
6951
- var codeTargetSchema = z3.object({
7500
+ var structuredCodeTargetSchema = z3.object({
6952
7501
  registry: z3.enum([
6953
7502
  "npm",
6954
7503
  "pypi",
@@ -6965,7 +7514,18 @@ var codeTargetSchema = z3.object({
6965
7514
  repo_url: z3.string().optional().describe("Repository URL (GitHub). Required for repo scope. Example: https://github.com/expressjs/express"),
6966
7515
  git_ref: z3.string().optional().describe("Git ref - tag, branch, or commit. Required with repo_url. Use HEAD for latest.")
6967
7516
  }).describe("Target: provide registry + package_name (package scope) or repo_url + git_ref (repo scope).");
7517
+ var codeTargetSchema = z3.union([
7518
+ structuredCodeTargetSchema,
7519
+ z3.string().min(1).describe("Compact target string. Package: `npm:react@18.2.0`. Repository: `https://github.com/facebook/react#HEAD` (git ref suffix optional, defaults to HEAD).")
7520
+ ]);
6968
7521
  function resolveCodeTarget(target) {
7522
+ if (typeof target === "string") {
7523
+ try {
7524
+ return parseCodeNavigationTargetSpec(target);
7525
+ } catch (error2) {
7526
+ return mappedInvalidTargetResult(error2);
7527
+ }
7528
+ }
6969
7529
  const hasPackageTarget = Boolean(target.registry || target.package_name);
6970
7530
  const hasRepoTarget = Boolean(target.repo_url || target.git_ref);
6971
7531
  if (hasPackageTarget && hasRepoTarget) {
@@ -6998,6 +7558,15 @@ function resolveCodeTarget(target) {
6998
7558
  gitRef: target.git_ref
6999
7559
  };
7000
7560
  }
7561
+ function mappedInvalidTargetResult(error2) {
7562
+ const mapped = mapCodeNavigationError(error2);
7563
+ return errorResult(JSON.stringify({
7564
+ error: mapped.message,
7565
+ code: mapped.code,
7566
+ retryable: mapped.retryable ?? false,
7567
+ ...mapped.details ? { details: mapped.details } : {}
7568
+ }));
7569
+ }
7001
7570
  function invalidTargetResult(message) {
7002
7571
  return errorResult(JSON.stringify({
7003
7572
  error: message,
@@ -7084,7 +7653,7 @@ function createGrepRepoTool(service) {
7084
7653
  excludeTestFiles: build.params.excludeTestFiles,
7085
7654
  explicit: build.explicit
7086
7655
  });
7087
- if (isTextFormat(args.format)) {
7656
+ if (isTextFormat2(args.format)) {
7088
7657
  return textResult(renderGrepRepoText(payload));
7089
7658
  }
7090
7659
  return textResult(JSON.stringify(payload));
@@ -7100,19 +7669,30 @@ function createGrepRepoTool(service) {
7100
7669
  }
7101
7670
  };
7102
7671
  }
7103
- function isTextFormat(format) {
7672
+ function isTextFormat2(format) {
7104
7673
  return format === undefined || format === "text" || format === "text-v1";
7105
7674
  }
7106
7675
  // src/tools/list-files.ts
7107
7676
  import { z as z5 } from "zod";
7108
7677
  var schema4 = {
7109
7678
  target: codeTargetSchema,
7110
- path_prefix: z5.string().optional().describe("Literal directory prefix to filter by (e.g. `src/` or `lib/parser`). NOT a glob — `*.ts` and similar patterns won't match. Omit to list from the repository root."),
7679
+ path: z5.string().optional().describe("Exact target-relative file path to include. When combined with `path_prefix` or `globs`, files matching any selector are returned."),
7680
+ path_prefix: z5.string().optional().describe("Literal directory prefix to filter by (e.g. `src/` or `lib/parser`). NOT a glob. OR-ed with `path` and `globs` when combined."),
7681
+ globs: z5.array(z5.string()).optional().describe("Repeatable glob selectors with real glob semantics (e.g. `src/**/*.ts`). OR-ed with `path` and `path_prefix`."),
7682
+ extensions: z5.array(z5.string()).optional().describe("File extensions to include, without a leading dot."),
7683
+ file_types: z5.array(z5.string()).optional().describe("File type filters to include, matching aigrep file_type values such as `source` or `doc`."),
7684
+ languages: z5.array(z5.string()).optional().describe("Language filters to include, matching aigrep language names."),
7685
+ file_intent: z5.string().optional().describe(`Single inclusive file-intent filter. Cannot be combined with \`file_intents\`. Valid values: ${knownFileIntentList().join(", ")}.`),
7686
+ file_intents: z5.array(z5.string()).optional().describe(`Inclusive file-intent filters. Cannot be combined with \`file_intent\`. Valid values: ${knownFileIntentList().join(", ")}.`),
7687
+ exclude_file_intents: z5.array(z5.string()).optional().describe(`Exclude these file intents after inclusive intent filtering. Valid values: ${knownFileIntentList().join(", ")}.`),
7688
+ exclude_doc_files: z5.boolean().optional(),
7689
+ exclude_test_files: z5.boolean().optional(),
7690
+ include_hidden: z5.boolean().optional(),
7111
7691
  limit: z5.number().optional().describe("Max entries to return (1–1000, default 200). Out-of-range values return an `INVALID_ARGUMENT` envelope."),
7112
7692
  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`."),
7113
7693
  format: z5.enum(["json", "text", "text-v1"]).optional().describe('Response format. Default `text-v1` — compact paths-only listing tuned for agent context efficiency. Pass `format: "json"` for the structured envelope. `text` is an alias for `text-v1`. Errors stay JSON-formatted in either mode for now.')
7114
7694
  };
7115
- var DESCRIPTION4 = "List files in an indexed dependency. Default response is a compact " + 'paths-only listing (`format: "text-v1"`); pass `format: "json"` ' + "for the structured envelope `{total, hasMore, files: [{path, name, " + "language, fileType, byteSize}], resolution, indexedVersion}`. " + "Address via `target.registry` + `target.package_name` (package " + "scope) or `target.repo_url` + `target.git_ref` (repo scope), " + "mutually exclusive. `path_prefix` is a literal directory prefix — " + "it does NOT accept globs (`*.ts`) or extension filters. The " + "returned paths feed directly into `code_read` and help scope " + "`code_grep`. Returns an `INDEXING` error envelope when the " + "dependency is being indexed on-demand — retry with a longer " + "`wait_timeout_ms` or use a version from `details.availableVersions`.";
7695
+ var DESCRIPTION4 = "List files in an indexed dependency. Default response is a compact " + 'paths-only listing (`format: "text-v1"`); pass `format: "json"` ' + "for the structured envelope `{total, hasMore, files: [{path, name, " + "language, fileType, byteSize}], resolution, indexedVersion}`. " + "Address via `target.registry` + `target.package_name` (package " + "scope) or `target.repo_url` + `target.git_ref` (repo scope), " + "mutually exclusive. Narrow with `path`, `path_prefix`, `globs`, " + "`extensions`, `file_types`, `languages`, or file-intent filters. " + "The returned paths feed directly into `code_read` and help scope " + "`code_grep`. Returns an `INDEXING` error envelope when the " + "dependency is being indexed on-demand — retry with a longer " + "`wait_timeout_ms` or use a version from `details.availableVersions`.";
7116
7696
  function createListFilesTool(service) {
7117
7697
  return {
7118
7698
  name: "code_files",
@@ -7126,7 +7706,18 @@ function createListFilesTool(service) {
7126
7706
  try {
7127
7707
  const build = buildListFilesParams({
7128
7708
  target,
7709
+ path: args.path,
7129
7710
  pathPrefix: args.path_prefix,
7711
+ globs: args.globs,
7712
+ extensions: args.extensions,
7713
+ fileTypes: args.file_types,
7714
+ languages: args.languages,
7715
+ fileIntent: args.file_intent,
7716
+ fileIntents: args.file_intents,
7717
+ excludeFileIntents: args.exclude_file_intents,
7718
+ excludeDocFiles: args.exclude_doc_files,
7719
+ excludeTestFiles: args.exclude_test_files,
7720
+ includeHidden: args.include_hidden,
7130
7721
  limit: args.limit,
7131
7722
  waitTimeoutMs: args.wait_timeout_ms
7132
7723
  });
@@ -7136,12 +7727,22 @@ function createListFilesTool(service) {
7136
7727
  name: target.packageName,
7137
7728
  repoUrl: target.repoUrl,
7138
7729
  gitRef: target.gitRef,
7139
- limitExplicit: build.limitExplicit,
7140
- pathPrefixExplicit: build.pathPrefixExplicit,
7141
- pathPrefix: build.params.pathPrefix,
7142
- limit: build.params.limit
7730
+ path: build.filterEcho.path,
7731
+ pathPrefix: build.filterEcho.pathPrefix,
7732
+ globs: build.filterEcho.globs,
7733
+ extensions: build.filterEcho.extensions,
7734
+ fileTypes: build.filterEcho.fileTypes,
7735
+ languages: build.filterEcho.languages,
7736
+ fileIntent: build.filterEcho.fileIntent,
7737
+ fileIntents: build.filterEcho.fileIntents,
7738
+ excludeFileIntents: build.filterEcho.excludeFileIntents,
7739
+ excludeDocFiles: build.filterEcho.excludeDocFiles,
7740
+ excludeTestFiles: build.filterEcho.excludeTestFiles,
7741
+ includeHidden: build.filterEcho.includeHidden,
7742
+ limit: build.filterEcho.limit,
7743
+ explicit: build.explicit
7143
7744
  });
7144
- if (isTextFormat2(args.format)) {
7745
+ if (isTextFormat3(args.format)) {
7145
7746
  return textResult(renderListFilesText(payload));
7146
7747
  }
7147
7748
  return textResult(JSON.stringify(payload));
@@ -7157,7 +7758,7 @@ function createListFilesTool(service) {
7157
7758
  }
7158
7759
  };
7159
7760
  }
7160
- function isTextFormat2(format) {
7761
+ function isTextFormat3(format) {
7161
7762
  return format === undefined || format === "text" || format === "text-v1";
7162
7763
  }
7163
7764
  // src/tools/list-package-docs.ts
@@ -7167,7 +7768,8 @@ var schema5 = {
7167
7768
  package_name: z6.string().describe("Package name (scoped names ok: @types/node)."),
7168
7769
  version: z6.string().optional().describe("Optional package version."),
7169
7770
  limit: z6.number().optional().describe("Max pages to return (1-500, default 100)."),
7170
- after: z6.string().optional().describe("Pagination cursor from a prior response.")
7771
+ after: z6.string().optional().describe("Pagination cursor from a prior response."),
7772
+ 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.')
7171
7773
  };
7172
7774
  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.";
7173
7775
  function createListPackageDocsTool(service) {
@@ -7192,6 +7794,9 @@ function createListPackageDocsTool(service) {
7192
7794
  limit: build.params.limit,
7193
7795
  after: build.params.after
7194
7796
  });
7797
+ if (isTextFormat4(args.format)) {
7798
+ return textResult(renderListPackageDocsText(payload));
7799
+ }
7195
7800
  return textResult(JSON.stringify(payload));
7196
7801
  } catch (error2) {
7197
7802
  const mapped = mapPackageIntelligenceError(error2);
@@ -7205,6 +7810,9 @@ function createListPackageDocsTool(service) {
7205
7810
  }
7206
7811
  };
7207
7812
  }
7813
+ function isTextFormat4(format) {
7814
+ return format === undefined || format === "text" || format === "text-v1";
7815
+ }
7208
7816
  // src/tools/package-changelog.ts
7209
7817
  import { z as z7 } from "zod";
7210
7818
 
@@ -7405,7 +8013,7 @@ function appendBodyLines(lines, body, options) {
7405
8013
  }
7406
8014
  const hidden = bodyLines.length - visible.length;
7407
8015
  if (hidden > 0) {
7408
- lines.push(` ${dim(`… (+${hidden} more line${hidden === 1 ? "" : "s"} — use --verbose for the full body)`, options.useColors)}`);
8016
+ lines.push(` ${dim(`… (+${hidden} more line${hidden === 1 ? "" : "s"} — ${options.fullBodyHint ?? "use --verbose for the full body"})`, options.useColors)}`);
7409
8017
  }
7410
8018
  }
7411
8019
  function buildSummaryLine(envelope, options) {
@@ -7477,9 +8085,10 @@ var schema6 = {
7477
8085
  to_version: z7.string().optional().describe("End of range / latest-mode cap. Works in either mode. Defaults to latest on the wire. Tag-style `v`-prefixed inputs are rejected."),
7478
8086
  limit: z7.number().optional().describe("Latest-mode cap on entry count (1–50, default 10). Rejected with `INVALID_ARGUMENT` when `from_version` is also set or when out of range."),
7479
8087
  git_ref: z7.string().optional().describe("Git branch or tag for CHANGELOG.md source (no effect on GitHub Releases or HexDocs). Defaults to the repository's default branch."),
7480
- include_bodies: z7.boolean().optional().describe("When false, each entry in `entries.items[]` omits its `body` field. Default true. Set false when you only need the version / date / URL timeline — drops 10 KB+ per entry on large release notes.")
8088
+ include_bodies: z7.boolean().optional().describe("When false, each entry in `entries.items[]` omits its `body` field. Default true. Set false when you only need the version / date / URL timeline — drops 10 KB+ per entry on large release notes."),
8089
+ format: z7.enum(["json", "text", "text-v1"]).optional().describe("Response format. Default `text-v1` is compact for agents. Pass `json` for the structured envelope.")
7481
8090
  };
7482
- var DESCRIPTION6 = "Release notes for a package or GitHub repo, newest-first. Default " + "latest mode returns the ten most recent entries (`limit` 1–50). " + "With `from_version`, returns every entry in the " + "`[from_version, to_version]` range (range mode, no count cap). " + "Address via `registry` + `package_name` or `repo_url` (mutually " + 'exclusive). Response includes optional `source` (`"releases"` / ' + '`"changelog_file"` / `"hexdocs"`) when a concrete changelog source ' + 'exists, `mode` (`"latest"` or `"range"`), ' + "`entries: { count, items }` with full markdown bodies. Set " + "`include_bodies: false` for a version / date / URL timeline only. " + "Package-version entries without changelog text succeed with `source` " + "omitted; no-source plus no entries returns `NOT_FOUND`. Supports npm, " + "PyPI, Hex, Crates, vcpkg, Zig, NuGet, Maven, Packagist.";
8091
+ var DESCRIPTION6 = "Release notes for a package or GitHub repo, newest-first. Default " + "latest mode returns the ten most recent entries (`limit` 1–50). " + "With `from_version`, returns every entry in the " + "`[from_version, to_version]` range (range mode, no count cap). " + "Address via `registry` + `package_name` or `repo_url` (mutually " + 'exclusive). Response includes optional `source` (`"releases"` / ' + '`"changelog_file"` / `"hexdocs"`) when a concrete changelog source ' + 'exists, `mode` (`"latest"` or `"range"`), ' + 'and entries with markdown body previews. Pass `format: "json"` ' + "for the structured envelope with full markdown bodies. Set " + "`include_bodies: false` for a version / date / URL timeline only. " + "Package-version entries without changelog text succeed with `source` " + "omitted; no-source plus no entries returns `NOT_FOUND`. Supports npm, " + "PyPI, Hex, Crates, vcpkg, Zig, NuGet, Maven, Packagist.";
7483
8092
  function createPackageChangelogTool(service) {
7484
8093
  return {
7485
8094
  name: "pkg_changelog",
@@ -7510,6 +8119,13 @@ function createPackageChangelogTool(service) {
7510
8119
  limit: params.limit,
7511
8120
  gitRef: params.gitRef
7512
8121
  });
8122
+ if (isTextFormat5(args.format)) {
8123
+ return textResult(formatPackageChangelogTerminal(payload, {
8124
+ useColors: false,
8125
+ verbose: false,
8126
+ fullBodyHint: 'pass format="json" for full bodies'
8127
+ }).trimEnd());
8128
+ }
7513
8129
  return textResult(JSON.stringify(payload));
7514
8130
  } catch (error2) {
7515
8131
  const mapped = mapPackageIntelligenceError(error2);
@@ -7531,18 +8147,22 @@ function createPackageChangelogTool(service) {
7531
8147
  }
7532
8148
  };
7533
8149
  }
8150
+ function isTextFormat5(format) {
8151
+ return format === undefined || format === "text" || format === "text-v1";
8152
+ }
7534
8153
  // src/tools/package-dependencies.ts
7535
8154
  import { z as z8 } from "zod";
7536
8155
  var schema7 = {
7537
8156
  registry: z8.string().describe("Package registry. Dependency data is available on npm, pypi, hex, crates, vcpkg, and zig."),
7538
8157
  package_name: z8.string().describe("Package name (scoped names ok: @types/node)."),
7539
8158
  version: z8.string().optional().describe("Specific version to inspect. Defaults to latest when omitted. Tag-style inputs with a leading `v` (for example `v4.18.0`) are rejected — pass the canonical version (`4.18.0`)."),
7540
- lifecycle: z8.union([z8.string(), z8.array(z8.string())]).optional().describe('Filter the `groups` block server-side by lifecycle phase. Accepts a single value, a comma-separated string (e.g. `"runtime,development"`), or an array of strings. Canonical values: `runtime`, `development`, `build`, `peer`, `optional`. Uppercase is tolerated. When the filter matches nothing the response still includes `groups: { items: [] }` so you can tell an empty-match apart from a registry that has no groups concept.'),
8159
+ lifecycle: z8.union([z8.string(), z8.array(z8.string())]).optional().describe("Lifecycle breadth. Omit for runtime-only. Use `runtime` for explicit runtime-only, a concrete non-runtime lifecycle (`development`, `build`, `peer`, `optional`) for runtime plus matching groups, or `all` for runtime plus all available groups. Accepts a single value, a comma-separated string, or an array; `all` cannot be combined with other values. Uppercase is tolerated."),
7541
8160
  include_transitive: z8.boolean().optional().describe("When true the response gains a `transitive` block with aggregate counts (`edges`, `uniquePackages`), the preprocessed `packages[]` list (each `{name, version}` — the complete install footprint), plus typed `conflicts[]` (`{name, requiredVersions}`) and `circularDependencies[]` (`{cycle: string[]}`) when the backend reported any. Off by default."),
7542
8161
  include_importers: z8.boolean().optional().describe("Requires `include_transitive: true`. When true, each entry in `transitive.packages[]` also carries an `importers` array — every upstream package that pulls it in, with that importer's own resolved version and the constraint it declared. Off by default because adding provenance roughly quadruples the envelope size on heavy graphs. Turn on when you need to trace why a specific transitive dep is present."),
7543
- 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`.")
8162
+ 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`."),
8163
+ format: z8.enum(["json", "text", "text-v1"]).optional().describe("Response format. Default `text-v1` is compact for agents. Pass `json` for the structured envelope.")
7544
8164
  };
7545
- var DESCRIPTION7 = "Analyze a package's dependency graph. The response always includes " + "a `runtime` block listing the direct runtime dependencies as " + "`{name, version, constraint}` records (the backend resolves each " + "constraint to a concrete version for you). It also always includes " + "a structured `groups` block whenever the backend returns group " + "metadata one group per lifecycle (`runtime`, `development`, " + "`build`, `peer`, `optional`) plus feature-conditional groups for " + "registries that have them (PyPI extras, Crates features). Use " + "`lifecycle` to filter `groups` server-side. Set " + "`include_transitive: true` to add a `transitive` block with the " + "full install footprint, conflict detection, and circular-" + "dependency flags; layer `include_importers: true` on top when you " + "also need per-package provenance. Supports npm, PyPI, Hex, Crates, " + "vcpkg, and Zig.";
8165
+ var DESCRIPTION7 = "Analyze a package's dependency graph. Default output is compact " + "text listing direct runtime dependencies with resolved versions; " + 'pass `format: "json"` for the structured envelope. Non-runtime ' + "groups are omitted by default for token efficiency. Use `lifecycle` " + "with a concrete value for runtime plus matching groups, or `all` " + "for runtime plus all available groups. Set " + "`include_transitive: true` to add a `transitive` block with the " + "full install footprint, conflict detection, and circular-" + "dependency flags; layer `include_importers: true` on top when you " + "also need per-package provenance. Supports npm, PyPI, Hex, Crates, " + "vcpkg, and Zig.";
7546
8166
  function createPackageDependenciesTool(service) {
7547
8167
  return {
7548
8168
  name: "pkg_deps",
@@ -7574,6 +8194,18 @@ function createPackageDependenciesTool(service) {
7574
8194
  maxDepth: args.max_depth,
7575
8195
  includeImporters: args.include_importers ?? false
7576
8196
  });
8197
+ if (isTextFormat6(args.format)) {
8198
+ const textLifecycles = canonicalLifecycles.length > 0 ? canonicalLifecycles : ["all"];
8199
+ return textResult(formatPackageDependenciesTerminal(report, {
8200
+ useColors: false,
8201
+ requestedVersion: args.version,
8202
+ canonicalLifecycles: textLifecycles,
8203
+ includeTransitive: args.include_transitive,
8204
+ maxDepth: args.max_depth,
8205
+ showGroups: canonicalLifecycles.length > 0 && !canonicalLifecycles.every((item) => item === "runtime"),
8206
+ hiddenGroupsHint: 'pass lifecycle="all".'
8207
+ }).trimEnd());
8208
+ }
7577
8209
  return textResult(JSON.stringify(payload));
7578
8210
  } catch (error2) {
7579
8211
  const mapped = mapPackageIntelligenceError(error2);
@@ -7595,13 +8227,17 @@ function createPackageDependenciesTool(service) {
7595
8227
  }
7596
8228
  };
7597
8229
  }
8230
+ function isTextFormat6(format) {
8231
+ return format === undefined || format === "text" || format === "text-v1";
8232
+ }
7598
8233
  // src/tools/package-summary.ts
7599
8234
  import { z as z9 } from "zod";
7600
8235
  var schema8 = {
7601
8236
  registry: z9.string().describe("Package registry. One of: npm, pypi, hex, crates, nuget, maven, zig, vcpkg, packagist."),
7602
- package_name: z9.string().describe("Package name (scoped names ok: @types/node).")
8237
+ package_name: z9.string().describe("Package name (scoped names ok: @types/node)."),
8238
+ format: z9.enum(["json", "text", "text-v1"]).optional().describe("Response format. Default `text-v1` is compact for agents. Pass `json` for the structured envelope.")
7603
8239
  };
7604
- var DESCRIPTION8 = "Get a package overview — latest version, license, description, " + "repository, downloads, GitHub stars, install command, recent " + "changes, and a count of known vulnerabilities. Use before " + "recommending a package or to orient on what a dependency is. " + "Works across npm, PyPI, Hex, Crates, NuGet, Maven, Packagist, " + "vcpkg, and Zig. Always returns data for the latest published " + "version.";
8240
+ var DESCRIPTION8 = "Get a package overview — latest version, license, description, " + "repository, downloads, GitHub stars, install command, recent " + "changes, and a count of known vulnerabilities. Use before " + "recommending a package or to orient on what a dependency is. " + 'Default output is compact text; pass `format: "json"` for the ' + "structured envelope. " + "Works across npm, PyPI, Hex, Crates, NuGet, Maven, Packagist, " + "vcpkg, and Zig. Always returns data for the latest published " + "version.";
7605
8241
  function createPackageSummaryTool(service) {
7606
8242
  return {
7607
8243
  name: "pkg_info",
@@ -7616,6 +8252,11 @@ function createPackageSummaryTool(service) {
7616
8252
  });
7617
8253
  const summary = await service.packageSummary(params);
7618
8254
  const payload = buildPackageSummarySuccessPayload(summary);
8255
+ if (isTextFormat7(args.format)) {
8256
+ return textResult(formatPackageSummaryTerminal(summary, {
8257
+ useColors: false
8258
+ }).trimEnd());
8259
+ }
7619
8260
  return textResult(JSON.stringify(payload));
7620
8261
  } catch (error2) {
7621
8262
  const mapped = mapPackageIntelligenceError(error2);
@@ -7637,6 +8278,9 @@ function createPackageSummaryTool(service) {
7637
8278
  }
7638
8279
  };
7639
8280
  }
8281
+ function isTextFormat7(format) {
8282
+ return format === undefined || format === "text" || format === "text-v1";
8283
+ }
7640
8284
  // src/tools/package-vulnerabilities.ts
7641
8285
  import { z as z10 } from "zod";
7642
8286
  var schema9 = {
@@ -7644,9 +8288,10 @@ var schema9 = {
7644
8288
  package_name: z10.string().describe("Package name (scoped names ok: @types/node)."),
7645
8289
  version: z10.string().optional().describe("Specific version to check. Defaults to latest when omitted."),
7646
8290
  min_severity: z10.string().optional().describe("Only return advisories at or above this severity (`low`, `medium`, `high`, `critical`; uppercase tolerated). Omit to see all, including null-severity advisories."),
7647
- include_withdrawn: z10.boolean().optional().describe("Include retracted advisories (default: false).")
8291
+ include_withdrawn: z10.boolean().optional().describe("Include retracted advisories (default: false)."),
8292
+ format: z10.enum(["json", "text", "text-v1"]).optional().describe("Response format. Default `text-v1` is compact for agents. Pass `json` for the structured envelope.")
7648
8293
  };
7649
- var DESCRIPTION9 = "Check known vulnerabilities for a package on npm, PyPI, Hex, or " + "Crates (other registries are not yet supported for vulnerability " + "data). Returns a count summary, each advisory with OSV ID, " + "severity, affected ranges, and fix versions. Malicious-package advisories surface in a separate " + "bucket. Pass `version` to inspect a specific release; otherwise " + "the latest is checked. Use `min_severity` to filter to a threshold " + "(`low`, `medium`, `high`, `critical`) and `include_withdrawn` to " + "also see retracted advisories.";
8294
+ var DESCRIPTION9 = "Check known vulnerabilities for a package on npm, PyPI, Hex, or " + "Crates (other registries are not yet supported for vulnerability " + "data). Returns a count summary, each advisory with OSV ID, " + "severity, affected ranges, and fix versions. Malicious-package advisories surface in a separate " + "bucket. Pass `version` to inspect a specific release; otherwise " + "the latest is checked. Use `min_severity` to filter to a threshold " + "(`low`, `medium`, `high`, `critical`) and `include_withdrawn` to " + "also see retracted advisories. Default output is compact text; " + 'pass `format: "json"` for the structured envelope.';
7650
8295
  function createPackageVulnerabilitiesTool(service) {
7651
8296
  return {
7652
8297
  name: "pkg_vulns",
@@ -7666,6 +8311,12 @@ function createPackageVulnerabilitiesTool(service) {
7666
8311
  const payload = buildPackageVulnerabilitiesSuccessPayload(report, {
7667
8312
  requestedVersion: args.version
7668
8313
  });
8314
+ if (isTextFormat8(args.format)) {
8315
+ return textResult(formatPackageVulnerabilitiesTerminal(report, {
8316
+ useColors: false,
8317
+ requestedVersion: args.version
8318
+ }).trimEnd());
8319
+ }
7669
8320
  return textResult(JSON.stringify(payload));
7670
8321
  } catch (error2) {
7671
8322
  const mapped = mapPackageIntelligenceError(error2);
@@ -7687,6 +8338,9 @@ function createPackageVulnerabilitiesTool(service) {
7687
8338
  }
7688
8339
  };
7689
8340
  }
8341
+ function isTextFormat8(format) {
8342
+ return format === undefined || format === "text" || format === "text-v1";
8343
+ }
7690
8344
  // src/tools/read-file.ts
7691
8345
  import { z as z11 } from "zod";
7692
8346
  var MCP_READ_MAX_SPAN = 150;
@@ -7695,7 +8349,8 @@ var schema10 = {
7695
8349
  path: z11.string().describe("Path to the file. Package addressing: package-relative. Repo addressing: repo-relative. This is the same `path` key that `code_files` emits for each entry, so chaining needs no renaming."),
7696
8350
  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.`),
7697
8351
  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.`),
7698
- 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`.")
8352
+ 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`."),
8353
+ 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.')
7699
8354
  };
7700
8355
  var DESCRIPTION10 = "Read a file from an indexed dependency. **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.";
7701
8356
  function deriveBoundedRange(startLine, endLine) {
@@ -7747,6 +8402,9 @@ function createReadFileTool(service) {
7747
8402
  if (shouldEmitCappedHint(bounded, payload)) {
7748
8403
  payload.hint = buildCappedHint(payload, args.start_line, args.end_line);
7749
8404
  }
8405
+ if (isTextFormat9(args.format)) {
8406
+ return textResult(renderReadFileText(payload));
8407
+ }
7750
8408
  return textResult(JSON.stringify(payload));
7751
8409
  } catch (error2) {
7752
8410
  const mapped = mapCodeNavigationError(error2);
@@ -7760,6 +8418,9 @@ function createReadFileTool(service) {
7760
8418
  }
7761
8419
  };
7762
8420
  }
8421
+ function isTextFormat9(format) {
8422
+ return format === undefined || format === "text" || format === "text-v1";
8423
+ }
7763
8424
  function shouldEmitCappedHint(bounded, payload) {
7764
8425
  if (!bounded.capped)
7765
8426
  return false;
@@ -7789,10 +8450,12 @@ function describeRequest(originalStart, originalEnd) {
7789
8450
  }
7790
8451
  // src/tools/read-package-doc.ts
7791
8452
  import { z as z12 } from "zod";
8453
+ var MCP_DOC_READ_MAX_SPAN = 150;
7792
8454
  var schema11 = {
7793
8455
  page_id: z12.string().describe("Documentation page ID from `docs_list` or `search` results. Pass through unchanged; repo-backed IDs are snapshot-pinned."),
7794
8456
  start_line: z12.number().optional().describe("Starting line (1-indexed). Omit for the full page. Use with `end_line` to bound how much content the tool returns when a page is large."),
7795
- end_line: z12.number().optional().describe("Ending line (inclusive). Omit for end of page. Must be ≥ `start_line` when both are set.")
8457
+ end_line: z12.number().optional().describe("Ending line (inclusive). Omit for end of page. Must be ≥ `start_line` when both are set."),
8458
+ format: z12.enum(["json", "text", "text-v1"]).optional().describe('Response format. Default `text-v1` — raw markdown content capped to 150 lines by default. Pass `format: "json"` for the structured envelope; explicit ranges still slice JSON content.')
7796
8459
  };
7797
8460
  var DESCRIPTION11 = "Read a documentation page by page ID. Works for both hosted/crawled docs and repository-backed docs. " + "Pass `start_line` / `end_line` to fetch only a slice when a page is too long — response carries `totalLines` so you can target the next slice. " + "Repo-backed results additionally include exact file follow-up metadata for `code_read`.";
7798
8461
  function createReadPackageDocTool(service) {
@@ -7805,8 +8468,14 @@ function createReadPackageDocTool(service) {
7805
8468
  try {
7806
8469
  const build = buildReadPackageDocParams({ pageId: args.page_id });
7807
8470
  const result = await service.readPackageDoc(build.params);
7808
- const range = args.start_line !== undefined || args.end_line !== undefined ? { startLine: args.start_line, endLine: args.end_line } : undefined;
7809
- const payload = buildReadPackageDocSuccessPayload(result, build.params.pageId, range);
8471
+ const textMode = isTextFormat10(args.format);
8472
+ const range = buildRange3(args, textMode);
8473
+ const payload = buildReadPackageDocSuccessPayload(result, build.params.pageId, range?.range);
8474
+ if (range?.hint && payload.endLine !== undefined) {
8475
+ payload.hint = range.hint(payload);
8476
+ }
8477
+ if (textMode)
8478
+ return textResult(renderReadPackageDocText(payload));
7810
8479
  return textResult(JSON.stringify(payload));
7811
8480
  } catch (error2) {
7812
8481
  const mapped = mapPackageIntelligenceError(error2);
@@ -7820,6 +8489,22 @@ function createReadPackageDocTool(service) {
7820
8489
  }
7821
8490
  };
7822
8491
  }
8492
+ function isTextFormat10(format) {
8493
+ return format === undefined || format === "text" || format === "text-v1";
8494
+ }
8495
+ function buildRange3(args, textMode) {
8496
+ if (textMode) {
8497
+ const startLine = args.start_line ?? 1;
8498
+ const requestedEnd = args.end_line ?? startLine + MCP_DOC_READ_MAX_SPAN - 1;
8499
+ const endLine = Math.min(requestedEnd, startLine + MCP_DOC_READ_MAX_SPAN - 1);
8500
+ const wasClamped = requestedEnd > endLine;
8501
+ return {
8502
+ range: { startLine, endLine },
8503
+ hint: wasClamped ? (payload) => `Returned lines ${payload.startLine}-${payload.endLine}${payload.totalLines !== undefined ? `/${payload.totalLines}` : ""} (MCP text cap: ${MCP_DOC_READ_MAX_SPAN} lines per call; you requested lines ${startLine}-${requestedEnd}).` : undefined
8504
+ };
8505
+ }
8506
+ return args.start_line !== undefined || args.end_line !== undefined ? { range: { startLine: args.start_line, endLine: args.end_line } } : undefined;
8507
+ }
7823
8508
  // src/tools/search.ts
7824
8509
  import { z as z13 } from "zod";
7825
8510
  var schema12 = {
@@ -7914,13 +8599,13 @@ function createSearchTool(service) {
7914
8599
  });
7915
8600
  const outcome = await service.search(built.params);
7916
8601
  const payload = buildUnifiedSearchSuccessPayload(built.params, built.rawQuery, built.compiledQuery, outcome);
7917
- if (isTextFormat3(args.format)) {
8602
+ if (isTextFormat11(args.format)) {
7918
8603
  return textResult(renderUnifiedSearchSuccess(payload));
7919
8604
  }
7920
8605
  return textResult(JSON.stringify(payload));
7921
8606
  } catch (error2) {
7922
8607
  const payload = buildUnifiedSearchErrorPayload(error2);
7923
- if (isTextFormat3(args.format)) {
8608
+ if (isTextFormat11(args.format)) {
7924
8609
  return errorResult(renderUnifiedSearchError(payload));
7925
8610
  }
7926
8611
  return errorResult(JSON.stringify(payload));
@@ -7931,15 +8616,16 @@ function createSearchTool(service) {
7931
8616
  function isResolvedCodeTarget(target) {
7932
8617
  return !("content" in target);
7933
8618
  }
7934
- function isTextFormat3(format) {
8619
+ function isTextFormat11(format) {
7935
8620
  return format === undefined || format === "text" || format === "text-v1";
7936
8621
  }
7937
8622
  // src/tools/search-language.ts
7938
8623
  import { z as z14 } from "zod";
7939
8624
  var schema13 = {
7940
- query: z14.string().min(1).describe('Language name or partial name to search for (e.g., "python", "type", "java")')
8625
+ query: z14.string().min(1).describe('Language name or partial name to search for (e.g., "python", "type", "java")'),
8626
+ format: z14.enum(["json", "text", "text-v1"]).optional().describe("Response format. Default `text-v1` returns one language per line. Pass `json` for the structured array.")
7941
8627
  };
7942
- var DESCRIPTION13 = `Find the correct language name for \`get_example\` when it is uncertain. Returns up to 5 matching languages by name, display name, or alias.`;
8628
+ var DESCRIPTION13 = `Find the correct language name for \`get_example\` when it is uncertain. Returns up to 5 matching languages by name, display name, or alias. Default output is one language per line; pass \`format: "json"\` for the structured array.`;
7943
8629
  function createSearchLanguageTool(service) {
7944
8630
  return {
7945
8631
  name: "search_language",
@@ -7949,15 +8635,32 @@ function createSearchLanguageTool(service) {
7949
8635
  return withErrorHandling("search languages", async () => {
7950
8636
  const allLanguages = await service.getLanguages();
7951
8637
  const result = filterLanguages(allLanguages, args.query);
8638
+ if (isTextFormat12(args.format)) {
8639
+ return textResult(renderLanguageMatches(result));
8640
+ }
7952
8641
  return textResult(JSON.stringify(result));
7953
8642
  });
7954
8643
  }
7955
8644
  };
7956
8645
  }
8646
+ function isTextFormat12(format) {
8647
+ return format === undefined || format === "text" || format === "text-v1";
8648
+ }
8649
+ function renderLanguageMatches(matches) {
8650
+ if (matches.length === 0)
8651
+ return "No matching languages.";
8652
+ return matches.map((match) => {
8653
+ const label = match.display_name ? `${match.name} (${match.display_name})` : match.name;
8654
+ const aliases = match.aliases?.length ? ` aliases: ${match.aliases.join(", ")}` : "";
8655
+ return `${label}${aliases}`;
8656
+ }).join(`
8657
+ `);
8658
+ }
7957
8659
  // src/tools/search-status.ts
7958
8660
  import { z as z15 } from "zod";
7959
8661
  var schema14 = {
7960
- search_ref: z15.string().min(1).describe("Search reference returned by search.")
8662
+ search_ref: z15.string().min(1).describe("Search reference returned by search."),
8663
+ format: z15.enum(["json", "text", "text-v1"]).optional().describe('Response format. Default `text-v1` — compact line-oriented output matching `search`. Pass `format: "json"` for the structured envelope.')
7961
8664
  };
7962
8665
  var DESCRIPTION14 = "Check progress, fetch partial hits when the original request used allow_partial_results: true, or fetch final results for a prior unified search. " + "Pass the search_ref returned by `search` when the original request did not complete within the wait window.";
7963
8666
  function createSearchStatusTool(service) {
@@ -7970,6 +8673,9 @@ function createSearchStatusTool(service) {
7970
8673
  try {
7971
8674
  const outcome = await service.searchStatus(args.search_ref);
7972
8675
  const payload = buildUnifiedSearchStatusPayload(outcome);
8676
+ if (isTextFormat13(args.format)) {
8677
+ return textResult(renderUnifiedSearchStatusText(payload));
8678
+ }
7973
8679
  return textResult(JSON.stringify(payload));
7974
8680
  } catch (error2) {
7975
8681
  return errorResult(JSON.stringify(buildUnifiedSearchErrorPayload(error2)));
@@ -7977,25 +8683,28 @@ function createSearchStatusTool(service) {
7977
8683
  }
7978
8684
  };
7979
8685
  }
8686
+ function isTextFormat13(format) {
8687
+ return format === undefined || format === "text" || format === "text-v1";
8688
+ }
7980
8689
  // src/commands/mcp-instructions.ts
7981
- var CORE_BLOCK = `GitHits provides verified, canonical code examples from global open source. Use it when you're stuck, repeated attempts failed, you need up-to-date API usage, the question is comparative across OSS projects (e.g. "how does X vs Y handle Z"), the answer requires reading how a real codebase implements a feature, or the user mentions GitHits.
8690
+ var CORE_BLOCK = `GitHits provides verified, canonical code examples from global open source. Use it for global solution synthesis and canonical examples when you're stuck, repeated attempts failed, you need up-to-date API usage, the question is comparative across OSS projects (e.g. "how does X vs Y handle Z"), the answer requires reading how a real codebase implements a feature, or the user mentions GitHits.
7982
8691
 
7983
- Example workflow: call \`get_example\` with one focused question; pass \`language\` only when you know the exact language name, otherwise call \`search_language\` first. Send \`feedback\` on the returned solution_id. Reuse prior results before searching again.`;
8692
+ Example workflow: call \`get_example\` with one focused question; pass \`language\` only when you know the exact language name, otherwise call \`search_language\` first. Default output is markdown with a trailing \`solution_id\`; send \`feedback\` on that solution_id. Reuse prior results before searching again. For dependency-specific grounding, use package-scoped \`search\` before global \`get_example\`.`;
7984
8693
  var PACKAGE_TOOLS_PREAMBLE = `Indexed package/source tools inspect third-party dependency source, docs, and registry metadata. Use them when a stack trace points into a dependency, you need to verify how a library works, or you're evaluating whether to add or upgrade a package.
7985
8694
 
7986
- Package spec: \`registry:name[@version]\`.`;
7987
- var PKG_INFO_BULLET = "- `pkg_info` — instant package overview: latest version, license, downloads, quickstart, and active advisory count.";
8695
+ Package spec: \`registry:name[@version]\`. Default outputs are compact \`text-v1\` for agent context efficiency; pass \`format: "json"\` only when you need structured fields for programmatic parsing.`;
8696
+ var PKG_INFO_BULLET = '- `pkg_info` — compact package overview: latest version, license, downloads, quickstart, and active advisory count. Pass `format: "json"` for the structured envelope.';
7988
8697
  var DOCS_LIST_BULLET = "- `docs_list` — browse hosted and repository-backed package docs. Entries include stable pageIds, source URLs, and repo-file follow-up metadata when available.";
7989
8698
  var DOCS_READ_BULLET = "- `docs_read` — read a documentation page by pageId. Works for both hosted docs and repo-backed docs.";
7990
- var PKG_VULNS_BULLET = "- `pkg_vulns` — known CVE / OSV advisories for npm, PyPI, Hex, or Crates packages, optionally pinned to `@version`. Filter with `min_severity`; include retracted advisories with `include_withdrawn`.";
7991
- var PKG_DEPS_BULLET = "- `pkg_deps` — direct runtime deps plus lifecycle/feature groups when available. Use `lifecycle` to filter groups, `include_transitive` for the full graph, and `include_importers` for provenance. Supports npm, PyPI, Hex, Crates, vcpkg, and Zig.";
7992
- var PKG_CHANGELOG_BULLET = "- `pkg_changelog` — release notes for a package or GitHub repo, newest-first. Default latest mode returns recent entries with markdown bodies; `from_version` switches to range mode. Set `include_bodies: false` for a compact timeline.";
7993
- var SEARCH_BULLET = '- `search` — unified search across indexed dependency code, docs, and symbols. Omit `sources` for AUTO. Default output is compact `text-v1`; pass `format: "json"` for locators, highlights, and source status. Complete by default; opt into partial hits with `allow_partial_results: true`. Incomplete responses carry a `searchRef`.';
8699
+ var PKG_VULNS_BULLET = '- `pkg_vulns` — compact known CVE / OSV advisory summary for npm, PyPI, Hex, or Crates packages, optionally pinned to `version`. Filter with `min_severity`; include retracted advisories with `include_withdrawn`. Pass `format: "json"` for per-advisory structured fields.';
8700
+ 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.';
8701
+ var PKG_CHANGELOG_BULLET = '- `pkg_changelog` — compact release notes for a package or GitHub repo, newest-first. Default latest mode returns recent entries with markdown body previews; `from_version` switches to range mode. Set `include_bodies: false` for a compact timeline or pass `format: "json"` for full bodies.';
8702
+ 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`.';
7994
8703
  var SEARCH_STATUS_BULLET = "- `search_status` — follow up a prior `search` by `searchRef` to check progress, fetch partial hits, or fetch final results.";
7995
- var CODE_FILES_BULLET = '- `code_files` — list files in an indexed dependency. Use `path_prefix` to scope to a directory. Returned paths feed into `code_read` and help scope `code_grep`; pass `format: "json"` for language/type/size metadata.';
8704
+ var CODE_FILES_BULLET = '- `code_files` — list files in an indexed dependency. `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.';
7996
8705
  var CODE_READ_BULLET = "- `code_read` — read a dependency file by `path`. **MCP cap: 150 lines per call**; choose focused `start_line` / `end_line` windows from `search` or `code_grep`. Binary files set `isBinary: true` and omit `content`. On `FILE_NOT_FOUND` / `NOT_FOUND`, call `code_files` for the actual path.";
7997
8706
  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 `path:line` chains into `code_read`.";
7998
- var SEARCH_VS_SYMBOLS_TIP = 'Prefer `get_example` for canonical example retrieval; prefer unified `search` for indexed dependency and repository discovery; use `sources:["symbol"]` when you want symbol-shaped results. Use `code_grep` for deterministic text matching and `code_read` for focused-window inspection of a known file.';
8707
+ var SEARCH_VS_SYMBOLS_TIP = 'Use code-first grounding for behavioral claims: source, symbols, tests, examples, and call sites beat docs prose. Prefer unified `search` for indexed dependency and repository discovery; use `sources:["symbol"]` when you want symbol-shaped results. Prefer `get_example` for global canonical example retrieval after package-scoped grounding. Use `code_grep` for deterministic text matching and `code_read` for focused-window inspection of a known file.';
7999
8708
  var REFERENCE_FIRST_TIP = "Strategy — reference-first, content-second. Locate symbols and lines with `search` / `code_grep` first, then read only the needed window with `code_read` using explicit `start_line` / `end_line` values, typically 80-150 lines around the match. The MCP `code_read` surface caps each call at 150 lines.";
8000
8709
  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.';
8001
8710
  function buildMcpInstructions(_deps) {
@@ -8286,12 +8995,12 @@ async function pkgDepsAction(spec, options, deps) {
8286
8995
  console.log(JSON.stringify(payload));
8287
8996
  return;
8288
8997
  }
8289
- const showGroups = (options.groups ?? false) || canonicalLifecycles.length > 0;
8998
+ const showGroups = canonicalLifecycles.some((entry) => entry !== "runtime");
8290
8999
  const output = formatPackageDependenciesTerminal(report, {
8291
9000
  verbose: options.verbose,
8292
9001
  useColors: shouldUseColors(),
8293
9002
  requestedVersion: parsed.version,
8294
- canonicalLifecycles,
9003
+ canonicalLifecycles: canonicalLifecycles.length > 0 ? canonicalLifecycles : undefined,
8295
9004
  includeTransitive: options.transitive,
8296
9005
  maxDepth: userDepth,
8297
9006
  showGroups
@@ -8353,9 +9062,9 @@ function formatDepsTerminalError(mapped) {
8353
9062
  `);
8354
9063
  }
8355
9064
  var PKG_DEPS_DESCRIPTION = `Analyze package dependencies. By default shows the flat list of
8356
- direct runtime dependencies. Use --groups for the structured view
9065
+ direct runtime dependencies. Use --lifecycle all for the structured view
8357
9066
  (dev / peer / build / optional, plus registry-specific feature / TFM
8358
- groups). --lifecycle filters groups server-side and implies --groups.
9067
+ groups). Concrete --lifecycle values include runtime plus matching groups.
8359
9068
  --transitive opts into aggregate edge / unique-package counts,
8360
9069
  conflict detection, and circular-dependency flags.
8361
9070
 
@@ -8363,7 +9072,7 @@ Package spec: <registry>:<name>[@<version>]. Supported registries:
8363
9072
  npm, pypi, hex, crates, vcpkg, zig. Omit @<version> for the latest
8364
9073
  release.`;
8365
9074
  function registerPkgDepsCommand(pkgCommand) {
8366
- return pkgCommand.command("deps").summary("Analyze dependencies for a package").description(PKG_DEPS_DESCRIPTION).argument("<spec>", "Package spec, e.g. npm:express or npm:express@4.18.0").option("-g, --groups", "Render the structured groups view instead of the flat runtime list").option("-l, --lifecycle <phases>", "Filter groups server-side (runtime, development, build, peer, optional; comma-separated for multi-select). Implies --groups.").option("-t, --transitive", "Include aggregate transitive counts, conflicts, and circular dependencies").option("--depth <n>", "Cap transitive traversal depth (1-10). Omit for the full graph.").option("-v, --verbose", "Show conditionType / selectionMode / environmentConstraints metadata in the groups view").option("--json", "Emit the lean JSON envelope").action(async (spec, options) => {
9075
+ return pkgCommand.command("deps").summary("Analyze dependencies for a package").description(PKG_DEPS_DESCRIPTION).argument("<spec>", "Package spec, e.g. npm:express or npm:express@4.18.0").option("-l, --lifecycle <phases>", "Dependency lifecycle breadth (runtime, development, build, peer, optional, all; comma-separated for multi-select except all).").option("-t, --transitive", "Include aggregate transitive counts, conflicts, and circular dependencies").option("--depth <n>", "Cap transitive traversal depth (1-10). Omit for the full graph.").option("-v, --verbose", "Show conditionType / selectionMode / environmentConstraints metadata in the groups view").option("--json", "Emit the lean JSON envelope").action(async (spec, options) => {
8367
9076
  const deps = await createContainer();
8368
9077
  await pkgDepsAction(spec, options, {
8369
9078
  packageIntelligenceService: deps.packageIntelligenceService,
@@ -8632,7 +9341,7 @@ Pass the searchRef returned by githits search when the initial request could
8632
9341
  not complete within the wait window. This can return progress, partial hits when
8633
9342
  the original request used --allow-partial, or final results.`;
8634
9343
  function registerSearchCommand(program) {
8635
- program.command("search").summary("Search indexed dependency and repository code, docs, and symbols").description(SEARCH_DESCRIPTION).argument("<query>", "Search query").requiredOption("--in <target>", "Search target: registry:name[@version] or https://github.com/org/repo[#ref]", collectRepeatable2, []).addOption(new Option3("--source <source>", "Source to search (repeatable; default: auto)").choices(["docs", "code", "symbol"]).argParser((value, previous = []) => collectRepeatable2(value.toLowerCase(), previous)).default(undefined)).addOption(new Option3("--kind <kind>", "Precise symbol kind filter").choices([
9344
+ program.command("search").summary("Search indexed dependency and repository code, docs, and symbols").description(SEARCH_DESCRIPTION).argument("<query>", "Search query").requiredOption("--in <target>", "Search target: registry:name[@version] or https://github.com/org/repo[#ref]", collectRepeatable3, []).addOption(new Option3("--source <source>", "Source to search (repeatable; default: auto)").choices(["docs", "code", "symbol"]).argParser((value, previous = []) => collectRepeatable3(value.toLowerCase(), previous)).default(undefined)).addOption(new Option3("--kind <kind>", "Precise symbol kind filter").choices([
8636
9345
  ...knownSymbolKindList()
8637
9346
  ])).addOption(new Option3("--category <category>", "Broad symbol category filter").choices([...knownSymbolCategoryList()])).option("--path-prefix <prefix>", "Repository path prefix filter").addOption(new Option3("--intent <intent>", "File intent filter (omit to search across all intents)").choices([
8638
9347
  "production",
@@ -8666,7 +9375,7 @@ function requireSearchService(deps) {
8666
9375
  return deps.codeNavigationService;
8667
9376
  }
8668
9377
  async function loadContainer2() {
8669
- const { createContainer: createContainer2 } = await import("./shared/chunk-zg5dnven.js");
9378
+ const { createContainer: createContainer2 } = await import("./shared/chunk-rwcs5gyy.js");
8670
9379
  return createContainer2();
8671
9380
  }
8672
9381
  function parseTargetSpecs(specs) {
@@ -8723,7 +9432,7 @@ function parseWaitMs(value) {
8723
9432
  }
8724
9433
  return seconds * 1000;
8725
9434
  }
8726
- function collectRepeatable2(value, previous) {
9435
+ function collectRepeatable3(value, previous) {
8727
9436
  return [...previous, value];
8728
9437
  }
8729
9438
  function handleSearchError(error2, json, context = "search") {