ctx7 0.4.0 → 0.4.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/index.js CHANGED
@@ -453,11 +453,9 @@ async function getLibraryContext(libraryId, query, options, accessToken) {
453
453
  if (options?.type) {
454
454
  params.set("type", options.type);
455
455
  }
456
- if (options?.researchMode) {
457
- params.set("researchMode", "true");
458
- }
456
+ const headers = getAuthHeaders(accessToken);
459
457
  const response = await fetch(`${baseUrl}/api/v2/context?${params}`, {
460
- headers: getAuthHeaders(accessToken)
458
+ headers
461
459
  });
462
460
  if (!response.ok) {
463
461
  const errorData = await response.json().catch(() => ({}));
@@ -2605,6 +2603,15 @@ var AUTH_MODE_LABELS = {
2605
2603
  "api-key": "API Key"
2606
2604
  };
2607
2605
  var MCP_BASE_URL = "https://mcp.context7.com";
2606
+ function claudeConfigDir() {
2607
+ return process.env.CLAUDE_CONFIG_DIR || join8(homedir5(), ".claude");
2608
+ }
2609
+ function claudeGlobalMcpPath() {
2610
+ if (process.env.CLAUDE_CONFIG_DIR) {
2611
+ return join8(claudeConfigDir(), ".claude.json");
2612
+ }
2613
+ return join8(homedir5(), ".claude.json");
2614
+ }
2608
2615
  function mcpUrl(auth) {
2609
2616
  return auth.mode === "oauth" ? `${MCP_BASE_URL}/mcp/oauth` : `${MCP_BASE_URL}/mcp`;
2610
2617
  }
@@ -2620,22 +2627,26 @@ var agents = {
2620
2627
  displayName: "Claude Code",
2621
2628
  mcp: {
2622
2629
  projectPaths: [".mcp.json"],
2623
- globalPaths: [join8(homedir5(), ".claude.json")],
2630
+ get globalPaths() {
2631
+ return [claudeGlobalMcpPath()];
2632
+ },
2624
2633
  configKey: "mcpServers",
2625
2634
  buildEntry: (auth) => withHeaders({ type: "http", url: mcpUrl(auth) }, auth)
2626
2635
  },
2627
2636
  rule: {
2628
2637
  kind: "file",
2629
- dir: (scope) => scope === "global" ? join8(homedir5(), ".claude", "rules") : join8(".claude", "rules"),
2638
+ dir: (scope) => scope === "global" ? join8(claudeConfigDir(), "rules") : join8(".claude", "rules"),
2630
2639
  filename: "context7.md"
2631
2640
  },
2632
2641
  skill: {
2633
2642
  name: "context7-mcp",
2634
- dir: (scope) => scope === "global" ? join8(homedir5(), ".claude", "skills") : join8(".claude", "skills")
2643
+ dir: (scope) => scope === "global" ? join8(claudeConfigDir(), "skills") : join8(".claude", "skills")
2635
2644
  },
2636
2645
  detect: {
2637
2646
  projectPaths: [".mcp.json", ".claude"],
2638
- globalPaths: [join8(homedir5(), ".claude")]
2647
+ get globalPaths() {
2648
+ return [claudeConfigDir()];
2649
+ }
2639
2650
  }
2640
2651
  },
2641
2652
  cursor: {
@@ -2783,8 +2794,7 @@ Do not use for: refactoring, writing scripts from scratch, debugging business lo
2783
2794
  1. \`resolve-library-id\` with the library name and the user's question. Use the official library name with proper punctuation (e.g., "Next.js" not "nextjs", "Customer.io" not "customerio", "Three.js" not "threejs")
2784
2795
  2. Pick the best match by: exact name match, description relevance, code snippet count, source reputation (High/Medium preferred), and benchmark score (higher is better). Use version-specific IDs when the user mentions a version
2785
2796
  3. \`query-docs\` with the selected library ID and the user's full question (not single words)
2786
- 4. If you weren't satisfied with the answer, call \`query-docs\` again for the same library with \`researchMode: true\`. This retries with sandboxed agents that git-pull the actual source repos plus a live web search, then synthesizes a fresh answer. More costly than the default
2787
- 5. Answer using the fetched docs
2797
+ 4. Answer using the fetched docs
2788
2798
  `;
2789
2799
  var FALLBACK_CLI = `Use the \`ctx7\` CLI to fetch current documentation whenever the user asks about a library, framework, SDK, API, CLI tool, or cloud service -- even well-known ones like React, Next.js, Prisma, Express, Tailwind, Django, or Spring Boot. This includes API syntax, configuration, version migration, library-specific debugging, setup instructions, and CLI tool usage. Use even when you think you know the answer -- your training data may not reflect recent changes. Prefer this over web search for library docs.
2790
2800
 
@@ -2795,8 +2805,7 @@ Do not use for: refactoring, writing scripts from scratch, debugging business lo
2795
2805
  1. Resolve library: \`npx ctx7@latest library <name> "<user's question>"\`
2796
2806
  2. Pick the best match by: exact name match, description relevance, code snippet count, source reputation (High/Medium preferred), and benchmark score (higher is better). If results don't look right, try the full name with punctuation (e.g., "next.js" not "nextjs")
2797
2807
  3. Fetch docs: \`npx ctx7@latest docs <libraryId> "<user's question>"\`
2798
- 4. If you weren't satisfied with the answer, re-run the same command with \`--research\`. This retries with sandboxed agents that git-pull the actual source repos plus a live web search, then synthesizes a fresh answer. More costly than the default
2799
- 5. Answer using the fetched documentation
2808
+ 4. Answer using the fetched documentation
2800
2809
 
2801
2810
  You MUST call \`library\` first to get a valid ID (format: \`/org/project\`) unless the user provides one directly. Use the user's full question as the query -- specific and detailed queries return better results than vague single words. Do not run more than 3 commands per question. Do not include sensitive information (API keys, passwords, credentials) in queries.
2802
2811
 
@@ -3492,7 +3501,15 @@ async function hasMcpConfig(agentName, scope) {
3492
3501
  if (mcpPath.endsWith(".toml")) {
3493
3502
  return readTomlServerExists(mcpPath, "context7");
3494
3503
  }
3495
- const existing = await readJsonConfig(mcpPath);
3504
+ let existing;
3505
+ try {
3506
+ existing = await readJsonConfig(mcpPath);
3507
+ } catch (err) {
3508
+ log.warn(
3509
+ `Skipped ${mcpPath}: could not parse (${err instanceof Error ? err.message : String(err)})`
3510
+ );
3511
+ return false;
3512
+ }
3496
3513
  const section = existing[agent.mcp.configKey];
3497
3514
  return !!section && typeof section === "object" && !Array.isArray(section) && "context7" in section;
3498
3515
  }
@@ -3806,19 +3823,12 @@ async function queryCommand(libraryId, query, options) {
3806
3823
  process.exitCode = 1;
3807
3824
  return;
3808
3825
  }
3809
- const spinner = isTTY ? ora6(
3810
- options.research ? `Researching "${libraryId}"...` : `Fetching docs for "${libraryId}"...`
3811
- ).start() : null;
3812
3826
  const accessToken = getAccessToken();
3827
+ const spinner = isTTY ? ora6(`Fetching docs for "${libraryId}"...`).start() : null;
3813
3828
  const outputType = options.json ? "json" : "txt";
3814
3829
  let result;
3815
3830
  try {
3816
- result = await getLibraryContext(
3817
- libraryId,
3818
- query,
3819
- { type: outputType, researchMode: options.research },
3820
- accessToken
3821
- );
3831
+ result = await getLibraryContext(libraryId, query, { type: outputType }, accessToken);
3822
3832
  } catch (err) {
3823
3833
  spinner?.fail(`Error: ${err instanceof Error ? err.message : String(err)}`);
3824
3834
  if (!spinner) log.error(err instanceof Error ? err.message : String(err));
@@ -3882,14 +3892,9 @@ function registerDocsCommands(program2) {
3882
3892
  program2.command("library").argument("<name>", "Library name to search for").argument("[query]", "Question or task for relevance ranking").option("--json", "Output as JSON").description("Resolve a library name to a Context7 library ID").action(async (name, query, options) => {
3883
3893
  await resolveCommand(name, query, options);
3884
3894
  });
3885
- program2.command("docs").argument("<libraryId>", "Context7 library ID (e.g., /facebook/react)").argument("<query>", "Question or task to get docs for").option("--json", "Output as JSON").option(
3886
- "--research",
3887
- "Retry the query with deep research: spins up sandboxed agents that read the actual source repos (git pull + inspect) and runs a live web search, then synthesizes a fresh answer. Use on retry if you weren't satisfied with the first answer. More costly than the default."
3888
- ).description("Query documentation for a library").action(
3889
- async (libraryId, query, options) => {
3890
- await queryCommand(libraryId, query, options);
3891
- }
3892
- );
3895
+ program2.command("docs").argument("<libraryId>", "Context7 library ID (e.g., /facebook/react)").argument("<query>", "Question or task to get docs for").option("--json", "Output as JSON").description("Query documentation for a library").action(async (libraryId, query, options) => {
3896
+ await queryCommand(libraryId, query, options);
3897
+ });
3893
3898
  }
3894
3899
 
3895
3900
  // src/commands/upgrade.ts