context-doctor 0.13.3 → 0.13.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -34,6 +34,8 @@ Findings (4)
34
34
  npx context-doctor install
35
35
  ```
36
36
 
37
+ `install` configures every app it detects and does not stop at the first problem: a corrupt Claude Desktop config still gets you Claude Code and Cursor. It does not pretend either. Any target that failed is named with a ✗ line, the summary reads "Done with N problem(s)" instead of "Done.", and the **exit code is 1**, so dotfiles and onboarding scripts can react. A broken config file is never overwritten; fix it and re-run.
38
+
37
39
  That single command is also all it takes to **set up context-doctor on anyone else's machine**. Prefer a global install, or want the unreleased `main`? Both work (Node 20+):
38
40
 
39
41
  ```bash
package/dist/cli.js CHANGED
@@ -359,7 +359,10 @@ function main() {
359
359
  return;
360
360
  }
361
361
  if (args.command === "install") {
362
- runInstall();
362
+ // Partial success is still installed, but not silent: any failed target
363
+ // makes the exit code non-zero so automation can react.
364
+ if (runInstall().failures.length > 0)
365
+ process.exitCode = 1;
363
366
  return;
364
367
  }
365
368
  if (args.command === "uninstall") {
package/dist/install.d.ts CHANGED
@@ -20,5 +20,20 @@ export declare function npxLauncher(platformName: string): {
20
20
  command: string;
21
21
  args: string[];
22
22
  };
23
- export declare function runInstall(): void;
23
+ /** Outcome of an install run, so the CLI can set a truthful exit code. */
24
+ export interface InstallResult {
25
+ /** Detected targets that could not be configured, with the reason. */
26
+ failures: string[];
27
+ }
28
+ /**
29
+ * Install into every detected app.
30
+ *
31
+ * A failure in one app must not stop the others: someone with a corrupt
32
+ * Claude Desktop config still wants Claude Code and Cursor wired. But it
33
+ * must not be reported as success either — automation (dotfiles, CI,
34
+ * onboarding scripts) reads the exit code, and a "Done." with exit 0 over a
35
+ * failed target is a lie that surfaces later as "the tools never showed up".
36
+ * So: keep going, summarize, and return the failures for a non-zero exit.
37
+ */
38
+ export declare function runInstall(): InstallResult;
24
39
  export declare function runUninstall(): void;
package/dist/install.js CHANGED
@@ -214,6 +214,16 @@ function installSkill() {
214
214
  copyFileSync(skillSource, join(skillDest, "SKILL.md"));
215
215
  return join(skillDest, "SKILL.md");
216
216
  }
217
+ /**
218
+ * Install into every detected app.
219
+ *
220
+ * A failure in one app must not stop the others: someone with a corrupt
221
+ * Claude Desktop config still wants Claude Code and Cursor wired. But it
222
+ * must not be reported as success either — automation (dotfiles, CI,
223
+ * onboarding scripts) reads the exit code, and a "Done." with exit 0 over a
224
+ * failed target is a lie that surfaces later as "the tools never showed up".
225
+ * So: keep going, summarize, and return the failures for a non-zero exit.
226
+ */
217
227
  export function runInstall() {
218
228
  const entry = serverEntry();
219
229
  const found = targets().filter((t) => t.detect());
@@ -221,8 +231,9 @@ export function runInstall() {
221
231
  console.log("No supported AI apps detected (Claude Desktop, Claude Code, Cursor).");
222
232
  console.log("Manual setup — add to your app's MCP config:");
223
233
  console.log(JSON.stringify({ mcpServers: { "context-doctor": entry } }, null, 2));
224
- return;
234
+ return { failures: [] };
225
235
  }
236
+ const failures = [];
226
237
  for (const target of found) {
227
238
  try {
228
239
  const config = readJson(target.configPath);
@@ -234,22 +245,44 @@ export function runInstall() {
234
245
  }
235
246
  catch (e) {
236
247
  console.error(`✗ ${target.name}: ${e.message}`);
248
+ failures.push(target.name);
237
249
  }
238
250
  }
239
- const skillPath = installSkill();
240
- if (skillPath)
241
- console.log(`✓ Agent Skill installed for Claude Code (${skillPath})`);
242
- const hookPath = installHook();
243
- if (hookPath) {
244
- console.log(`✓ Claude Code every-prompt hook installed (${hookPath}) — heavy sessions get automatic hygiene guidance`);
245
- // npx resolves the package on every single prompt; a global install makes
246
- // the hook a plain exec instead, which is both faster and update-proof.
247
- if (hookUsesNpx()) {
248
- console.log(" note: the hook falls back to npx. For a faster, permanent hook: npm i -g context-doctor && context-doctor install");
251
+ try {
252
+ const skillPath = installSkill();
253
+ if (skillPath)
254
+ console.log(`✓ Agent Skill installed for Claude Code (${skillPath})`);
255
+ }
256
+ catch (e) {
257
+ console.error(`✗ Agent Skill: ${e.message}`);
258
+ failures.push("Agent Skill");
259
+ }
260
+ try {
261
+ const hookPath = installHook();
262
+ if (hookPath) {
263
+ console.log(`✓ Claude Code every-prompt hook installed (${hookPath}) — heavy sessions get automatic hygiene guidance`);
264
+ // npx resolves the package on every single prompt; a global install makes
265
+ // the hook a plain exec instead, which is both faster and update-proof.
266
+ if (hookUsesNpx()) {
267
+ console.log(" note: the hook falls back to npx. For a faster, permanent hook: npm i -g context-doctor && context-doctor install");
268
+ }
249
269
  }
250
270
  }
251
- console.log("\nDone. Restart the apps to pick up the new tools, then try:");
252
- console.log(' "What\'s eating my context?" — or paste a conversation and ask for a profile.');
271
+ catch (e) {
272
+ // An unreadable settings.json used to escape as a stack trace and abort
273
+ // the run; it is a failed target like any other.
274
+ console.error(`✗ Claude Code every-prompt hook: ${e.message}`);
275
+ failures.push("Claude Code hook");
276
+ }
277
+ if (failures.length > 0) {
278
+ console.log(`\nDone with ${failures.length} problem(s): ${failures.join(", ")}. See the ✗ lines above.`);
279
+ console.log("Everything else was installed. Exit code is 1 so scripts can tell; fix the file(s) and re-run install.");
280
+ }
281
+ else {
282
+ console.log("\nDone. Restart the apps to pick up the new tools, then try:");
283
+ console.log(' "What\'s eating my context?" — or paste a conversation and ask for a profile.');
284
+ }
285
+ return { failures };
253
286
  }
254
287
  export function runUninstall() {
255
288
  for (const target of targets().filter((t) => t.detect())) {
package/dist/mcp.js CHANGED
@@ -37,7 +37,7 @@ const STRATEGY_IDS = ["dedupe", "trim-tool-results", "trim-tool-calls", "strip-b
37
37
  * recommended pattern.
38
38
  */
39
39
  function createServer() {
40
- const server = new McpServer({ name: "context-doctor", version: "0.13.3" }, { instructions: SERVER_INSTRUCTIONS });
40
+ const server = new McpServer({ name: "context-doctor", version: "0.13.4" }, { instructions: SERVER_INSTRUCTIONS });
41
41
  server.tool("profile_context", "Profile an LLM conversation or prompt: token breakdown by category, largest messages, and actionable findings about wasted context (duplicates, oversized tool results, base64 blobs, cache-unfriendly ordering). Accepts OpenAI/Anthropic conversation JSON or raw text. Call this immediately whenever the user asks about token usage, context size, LLM cost, or latency — and proactively offer it once a conversation grows long or accumulates large pasted content.", {
42
42
  conversation: z.string().describe("Conversation JSON (OpenAI or Anthropic format, or bare message array) or raw prompt text"),
43
43
  model: z.string().optional().describe("Target model name for context-window math, e.g. claude-sonnet-5 or gpt-4o"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-doctor",
3
- "version": "0.13.3",
3
+ "version": "0.13.4",
4
4
  "description": "Profile and optimize LLM context windows. See what's eating your tokens and fix it — works with Claude, GPT, Gemini, and any MCP-capable AI app.",
5
5
  "keywords": [
6
6
  "llm",