claude-slim 2.12.0 → 2.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -248,12 +248,12 @@ Token counts come from [js-tiktoken](https://github.com/nicolo-ribaudo/js-tiktok
248
248
 
249
249
  ---
250
250
 
251
- ## v2.12.0 — What's new
251
+ ## v2.12.1 — What's new
252
252
 
253
- - **`claude-slim update`** runs the upgrade command for however this copy was installed, after showing it and asking. `--dry-run` to preview, `--yes` to skip the prompt. Plugin installs get the marketplace refresh first, then the qualified `claude-slim@claude-slim` id, and are reminded that a restart is needed. npx and source checkouts run nothing and say why npx already resolves the latest every invocation, and pulling your own repository is not claude-slim's to do.
254
- - **This corrects v2.9.0's reasoning.** That release stopped at detection, arguing updating belonged to the package manager. Half held: claude-slim must not write into a directory `claude plugin` owns. The other half did not — invoking the package manager is something this tool already does during cleanup (`claude plugin disable`), so refusing to here was inconsistent. It still writes nothing itself.
253
+ - **Fixed: the `/claude-slim` skill reported project memory as zero.** It invoked the CLI with `cd "${CLAUDE_PLUGIN_ROOT}"`, making `cwd` the plugin cache directory; the project slug resolved there, matched nothing, and every project-memory token silently left the startup total **108,570** on the machine where this surfaced. `SKILL.md` no longer `cd`s. This hit the tool's primary entry point, and quietly: a zero reads as a clean result.
254
+ - **`--project-dir <path>`** for callers that cannot run from the project directory, plus a warning when the CLI notices it is running from its own install without one.
255
255
 
256
- Tests: 374392 (+18), pinning the safety properties — every argv a fixed literal, no shell metacharacters, executable only ever `claude` or `npm`, and a refusal to run unattended with no TTY and no `--yes`.
256
+ Tests: 392401 (+9).
257
257
 
258
258
  For older release notes, see [CHANGELOG.md](CHANGELOG.md).
259
259
 
package/dist/cli.js CHANGED
@@ -10,6 +10,7 @@ import { cleanIssues, restoreItem } from './cleaner.js';
10
10
  import { readManifest } from './manifest.js';
11
11
  import { formatScanSummary, formatReportBox, calculateReport, } from './report.js';
12
12
  import { collectDoctorReport, formatDoctorReport } from './doctor.js';
13
+ import { looksLikeToolInstallDir } from './paths.js';
13
14
  import { checkForUpdate, formatUpdateNotice } from './update-check.js';
14
15
  import { confirmDecision, planUpdate, renderStep, runUpdate } from './update-run.js';
15
16
  import { scanCodex } from './codex/index.js';
@@ -40,10 +41,15 @@ program
40
41
  .description('Scan environment and report issues')
41
42
  .option('--json', 'Output raw JSON')
42
43
  .option('--lookback-days <n>', 'Days of session history for skill-usage analysis', '60')
44
+ .option('--project-dir <path>', 'Directory whose project memory counts toward the total (default: cwd)')
43
45
  .option('--no-codex', 'Skip the ~/.codex scan even if Codex is installed')
44
46
  .action(async (opts) => {
45
47
  await initTokenizer();
46
- const result = await scan({ lookbackDays: parseNonNegativeInt(opts.lookbackDays, 60) });
48
+ const projectDir = resolveProjectDir(opts.projectDir);
49
+ const result = await scan({
50
+ lookbackDays: parseNonNegativeInt(opts.lookbackDays, 60),
51
+ projectDir,
52
+ });
47
53
  // Codex is scanned when present. Reported only — it is never modified, and
48
54
  // unused-skill detection is suppressed there for lack of a usage signal.
49
55
  // commander maps `--no-codex` to `opts.codex === false`, not `opts.noCodex`.
@@ -185,6 +191,7 @@ program
185
191
  .option('--auto', 'Non-interactive: auto-select Tier 1 items only')
186
192
  .option('--sessions-per-day <n>', 'Sessions per day for savings estimate', '2')
187
193
  .option('--lookback-days <n>', 'Days of session history for skill-usage analysis', '60')
194
+ .option('--project-dir <path>', 'Directory whose project memory counts toward the total (default: cwd)')
188
195
  .option('--no-codex', 'Skip ~/.codex entirely')
189
196
  .action(async (opts) => {
190
197
  await runCleanPipeline({
@@ -193,6 +200,7 @@ program
193
200
  sessionsPerDay: parseNonNegativeInt(opts.sessionsPerDay, 2),
194
201
  lookbackDays: parseNonNegativeInt(opts.lookbackDays, 60),
195
202
  codex: opts.codex !== false,
203
+ projectDir: opts.projectDir,
196
204
  });
197
205
  });
198
206
  // --- restore ---
@@ -350,10 +358,28 @@ program.action(async () => {
350
358
  }
351
359
  await runCleanPipeline({ dryRun: false, auto: false, sessionsPerDay: 2, lookbackDays: 60, codex: true });
352
360
  });
361
+ /**
362
+ * Resolve which directory's project memory counts toward the startup estimate.
363
+ *
364
+ * Warns when the CLI is running from its own install directory and no explicit
365
+ * directory was given: the slug would resolve to the plugin cache, match no
366
+ * project, and silently zero out every project-memory token. Warning beats
367
+ * guessing — we cannot know which project the user meant.
368
+ */
369
+ function resolveProjectDir(explicit) {
370
+ if (explicit)
371
+ return explicit;
372
+ if (looksLikeToolInstallDir()) {
373
+ console.error(' \x1b[33m!\x1b[0m Running from claude-slim\'s own install directory, so project memory\n' +
374
+ ' cannot be attributed and is reported as 0. Pass --project-dir <path>\n' +
375
+ ' (or run from your project) for an accurate startup total.\n');
376
+ }
377
+ return undefined;
378
+ }
353
379
  // --- shared clean pipeline ---
354
380
  async function runCleanPipeline(opts) {
355
381
  await initTokenizer();
356
- const result = await scan({ lookbackDays: opts.lookbackDays });
382
+ const result = await scan({ lookbackDays: opts.lookbackDays, projectDir: resolveProjectDir(opts.projectDir) });
357
383
  // Codex issues join the same tiered list. They carry `agent: 'codex'`, which
358
384
  // is what keeps the cleaner's path guard pointed at ~/.codex/.
359
385
  const codexContents = new Map();
package/dist/paths.d.ts CHANGED
@@ -12,6 +12,17 @@ export declare function getDisabledDir(): string;
12
12
  * the startup estimate must not sum memory across every project on disk.
13
13
  */
14
14
  export declare function getCurrentProjectSlug(cwd?: string): string;
15
+ /**
16
+ * True when `cwd` sits inside claude-slim's own install rather than a project.
17
+ *
18
+ * The `/claude-slim` skill invokes the CLI with `cd "${CLAUDE_PLUGIN_ROOT}"`,
19
+ * which makes `process.cwd()` the plugin cache directory. The project slug then
20
+ * resolves to that path, no memory matches it, and the startup estimate silently
21
+ * drops every project-memory token — 108,570 of them on the machine where this
22
+ * was found. Detecting it lets the caller fail loudly or be told to pass
23
+ * `--project-dir` instead of quietly reporting zero.
24
+ */
25
+ export declare function looksLikeToolInstallDir(cwd?: string): boolean;
15
26
  export declare function getManifestPath(): string;
16
27
  export declare function getLegacyManifestPath(): string;
17
28
  /** The agents claude-slim is allowed to touch. Adding one widens what every
package/dist/paths.js CHANGED
@@ -26,6 +26,22 @@ export function getDisabledDir() {
26
26
  export function getCurrentProjectSlug(cwd = process.cwd()) {
27
27
  return resolve(cwd).replace(/\//g, '-');
28
28
  }
29
+ /**
30
+ * True when `cwd` sits inside claude-slim's own install rather than a project.
31
+ *
32
+ * The `/claude-slim` skill invokes the CLI with `cd "${CLAUDE_PLUGIN_ROOT}"`,
33
+ * which makes `process.cwd()` the plugin cache directory. The project slug then
34
+ * resolves to that path, no memory matches it, and the startup estimate silently
35
+ * drops every project-memory token — 108,570 of them on the machine where this
36
+ * was found. Detecting it lets the caller fail loudly or be told to pass
37
+ * `--project-dir` instead of quietly reporting zero.
38
+ */
39
+ export function looksLikeToolInstallDir(cwd = process.cwd()) {
40
+ const p = resolve(cwd).replace(/\\/g, '/');
41
+ return (p.includes('/.claude/plugins/') ||
42
+ p.includes('/_npx/') ||
43
+ /\/node_modules\/claude-slim(\/|$)/.test(p));
44
+ }
29
45
  export function getManifestPath() {
30
46
  return join(getDisabledDir(), 'manifest.json');
31
47
  }
@@ -1,5 +1,14 @@
1
1
  import type { ScanResult } from '../types.js';
2
2
  export interface ScanOptions {
3
3
  lookbackDays?: number;
4
+ /**
5
+ * Directory whose project memory counts toward the startup estimate.
6
+ *
7
+ * Defaults to `process.cwd()`, which is wrong whenever the CLI is launched
8
+ * from its own install directory — the `/claude-slim` skill does exactly that
9
+ * via `cd "${CLAUDE_PLUGIN_ROOT}"`, and every project-memory token silently
10
+ * dropped out of the total as a result.
11
+ */
12
+ projectDir?: string;
4
13
  }
5
14
  export declare function scan(opts?: ScanOptions): Promise<ScanResult>;
@@ -97,7 +97,7 @@ export async function scan(opts = {}) {
97
97
  // disk. Summing all of them (pre-2.8 behaviour) inflated the startup estimate
98
98
  // by a factor of however many projects the user had — 100k+ tokens on a busy
99
99
  // machine, for a number labelled "tokens at session start".
100
- const currentProjectSlug = getCurrentProjectSlug();
100
+ const currentProjectSlug = getCurrentProjectSlug(opts.projectDir);
101
101
  const currentProjectMemoryTokens = memoryFiles
102
102
  .filter((m) => m.project === currentProjectSlug)
103
103
  .reduce((sum, m) => sum + m.tokens, 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-slim",
3
- "version": "2.12.0",
3
+ "version": "2.12.1",
4
4
  "description": "Audit and shrink your Claude Code startup context. Measures what every skill, plugin, agent, command, and memory file costs in the system prompt, then reversibly disables the dead weight. Non-destructive scan, tiered proposals, one-command restore — no proxy, no compression.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,7 +23,7 @@ Analyze the user's Claude Code environment for token waste and perform non-destr
23
23
  An outdated claude-slim does not merely lack features — it reports **wrong numbers**. Versions before 2.8.0 summed memory across every project on disk and inflated the startup estimate roughly 8×. Presenting those figures as fact is worse than not running at all, so check first:
24
24
 
25
25
  ```bash
26
- cd "${CLAUDE_PLUGIN_ROOT}" && node dist/cli.js check-update --json
26
+ node "${CLAUDE_PLUGIN_ROOT}/dist/cli.js" check-update --json
27
27
  ```
28
28
 
29
29
  The check is cached for 24h and fails open — if it errors, times out, or returns `"latest": null`, **proceed silently**. Never block the user because a version lookup failed.
@@ -50,13 +50,13 @@ If `"outdated": false`, say nothing and continue to Phase 1.
50
50
  Run the CLI to collect environment data:
51
51
 
52
52
  ```bash
53
- cd "${CLAUDE_PLUGIN_ROOT}" && node dist/cli.js scan --json
53
+ node "${CLAUDE_PLUGIN_ROOT}/dist/cli.js" scan --json
54
54
  ```
55
55
 
56
56
  If `CLAUDE_PLUGIN_ROOT` is not set:
57
57
  ```bash
58
58
  PLUGIN_DIR=$(find ~/.claude/plugins -path "*/claude-slim/dist/cli.js" -type f 2>/dev/null | head -1 | xargs dirname | xargs dirname)
59
- cd "$PLUGIN_DIR" && node dist/cli.js scan --json
59
+ node "$PLUGIN_DIR/dist/cli.js" scan --json
60
60
  ```
61
61
 
62
62
  If `node` is not available, fall back to the legacy bash scanner:
@@ -134,18 +134,18 @@ If subcommand is `scan`, stop here. Ask a localized equivalent of "Proceed with
134
134
  Run the interactive clean command:
135
135
 
136
136
  ```bash
137
- cd "${CLAUDE_PLUGIN_ROOT}" && node dist/cli.js clean
137
+ node "${CLAUDE_PLUGIN_ROOT}/dist/cli.js" clean
138
138
  ```
139
139
 
140
140
  Or with dry-run:
141
141
  ```bash
142
- cd "${CLAUDE_PLUGIN_ROOT}" && node dist/cli.js clean --dry-run
142
+ node "${CLAUDE_PLUGIN_ROOT}/dist/cli.js" clean --dry-run
143
143
  ```
144
144
 
145
145
  After cleanup, re-run scan to get updated numbers, then show the savings report:
146
146
 
147
147
  ```bash
148
- cd "${CLAUDE_PLUGIN_ROOT}" && node dist/cli.js report
148
+ node "${CLAUDE_PLUGIN_ROOT}/dist/cli.js" report
149
149
  ```
150
150
 
151
151
  Present the report box AND the before/after breakdown table to the user.
@@ -157,7 +157,7 @@ Present the report box AND the before/after breakdown table to the user.
157
157
  When `/claude-slim restore` is invoked:
158
158
 
159
159
  ```bash
160
- cd "${CLAUDE_PLUGIN_ROOT}" && node dist/cli.js restore
160
+ node "${CLAUDE_PLUGIN_ROOT}/dist/cli.js" restore
161
161
  ```
162
162
 
163
163
  ## Doctor
@@ -165,7 +165,7 @@ cd "${CLAUDE_PLUGIN_ROOT}" && node dist/cli.js restore
165
165
  When `/claude-slim doctor` is invoked:
166
166
 
167
167
  ```bash
168
- cd "${CLAUDE_PLUGIN_ROOT}" && node dist/cli.js doctor
168
+ node "${CLAUDE_PLUGIN_ROOT}/dist/cli.js" doctor
169
169
  ```
170
170
 
171
171
  Explain warnings in the user's language. Pay special attention to session-log warnings because they explain why unused-skill detection may be suppressed.