claude-setup 1.1.6 → 1.1.8

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
@@ -1,161 +1,142 @@
1
1
  # claude-setup
2
2
 
3
- Setup layer for Claude Code. Reads your project, writes command files, Claude Code does the rest.
3
+ Your project already has the answers `claude-setup` reads them and configures Claude Code so you don't have to.
4
4
 
5
- **The CLI has zero intelligence.** All reasoning is delegated to Claude Code via the command files.
5
+ One command. No manual config. Works on **Windows, macOS, Linux, and WSL**.
6
6
 
7
- ## Install
7
+ ## Get started
8
8
 
9
9
  ```bash
10
- npx claude-setup init
10
+ npx claude-setup
11
11
  ```
12
12
 
13
- Then open Claude Code and run `/stack-init`.
13
+ Pick `1` (init). Then open Claude Code and run:
14
14
 
15
- ## Commands
16
-
17
- | Command | What it does |
18
- |---------|-------------|
19
- | `init` | Full project setup — detects empty projects, generates atomic setup steps |
20
- | `add` | Add capabilities — MCP servers, skills, hooks, plugins in one go |
21
- | `sync` | Update setup after project changes — diff-based, not full re-scan |
22
- | `status` | Dashboard — project info, setup files, snapshots, token usage |
23
- | `doctor` | Validate everything — OS format, hooks, env vars, stale skills |
24
- | `remove` | Remove capabilities cleanly with dangling reference detection |
25
- | `restore` | Jump to any snapshot — restore files to a previous state |
26
- | `compare` | Diff two snapshots — find exactly where something changed |
27
- | `export` | Save your setup as a reusable template |
28
-
29
- ### Flags
30
-
31
- ```bash
32
- npx claude-setup init --dry-run # Preview without writing
33
- npx claude-setup init --template my.json # Apply a saved template
34
- npx claude-setup sync --dry-run # Show changes without writing
35
- npx claude-setup sync --budget 3000 # Override token budget
36
- npx claude-setup doctor --verbose # Include passing checks
37
- npx claude-setup doctor --fix # Auto-fix issues
38
- npx claude-setup doctor --test-hooks # Run every hook in sandbox
15
+ ```
16
+ /stack-init
39
17
  ```
40
18
 
41
- ## How it works
19
+ That's it. Claude Code now knows your stack, your services, your conventions.
42
20
 
43
- 1. **CLI collects** reads project files with strict token cost controls
44
- 2. **CLI writes** — generates markdown instructions into `.claude/commands/`
45
- 3. **Claude Code executes** — you run `/stack-init`, `/stack-sync`, etc.
21
+ ## What happens during init
46
22
 
47
- ## What it creates
23
+ `claude-setup` scans your project files — `package.json`, `docker-compose.yml`, `.env.example`, source code — and generates everything Claude Code needs:
48
24
 
49
- | File | Purpose |
50
- |------|---------|
51
- | `CLAUDE.md` | Project-specific context for Claude Code |
52
- | `.mcp.json` | MCP server connections (only if evidenced by project files) |
53
- | `.claude/settings.json` | Hooks in correct Claude Code format |
54
- | `.claude/skills/` | Reusable patterns with frontmatter |
55
- | `.claude/commands/` | Project-specific slash commands |
56
- | `.github/workflows/` | CI workflows (only with confirmation) |
25
+ | Generated | What it does |
26
+ |-----------|-------------|
27
+ | **CLAUDE.md** | Project context stack, structure, commands, conventions |
28
+ | **.mcp.json** | MCP server connections auto-detected from your dependencies |
29
+ | **settings.json** | Hooks auto-format, token tracking, build triggers |
30
+ | **skills/** | Reusable patterns for your workflow |
31
+ | **commands/** | Slash commands that work inside Claude Code |
57
32
 
58
- ## Snapshots
33
+ Every line comes from evidence in your project files. No guessing.
59
34
 
60
- Every `init` and `sync` creates a snapshot node — a checkpoint on a timeline. Snapshots store the content of changed files only.
35
+ ### MCP servers are auto-configured
61
36
 
62
- ```
63
- init ──→ sync#1 ──→ sync#2 ──→ sync#3 (current)
64
- │ │
65
- │ └─ bug introduced here
66
- └─ jump back here
67
- ```
37
+ `claude-setup` detects your databases and services automatically:
68
38
 
69
- - `npx claude-setup restore` pick any snapshot and restore files to that state
70
- - `npx claude-setup compare` diff any two snapshots to find what changed
71
- - Jumping does **not** delete other snapshots all are preserved
39
+ - Finds PostgreSQL, MongoDB, Redis, MySQL from your deps, docker-compose, or env files
40
+ - Checks if the service is installed locally (`psql`, `mongosh`, `redis-cli`)
41
+ - Uses the right connection URLno broken `${VARNAME}` that fails silently
42
+ - Formats commands for your OS (`cmd /c npx` on Windows, `npx` everywhere else)
72
43
 
73
- ## Templates
44
+ ## After init
74
45
 
75
- Save your setup and reuse it across projects.
46
+ These slash commands work inside Claude Code:
76
47
 
77
- ```bash
78
- # Export current setup
79
- npx claude-setup export
80
- # creates my-template.claude-template.json
48
+ | Command | What it does |
49
+ |---------|-------------|
50
+ | `/stack-sync` | Detect file changes, update your setup |
51
+ | `/stack-add` | Add a capability — searches 400+ marketplace plugins first |
52
+ | `/stack-status` | Show project state, snapshots, token usage |
53
+ | `/stack-doctor` | Validate environment, auto-fix issues |
54
+ | `/stack-restore` | Time-travel to any snapshot |
55
+ | `/stack-remove` | Remove a capability cleanly |
81
56
 
82
- # Apply to a new project
83
- npx claude-setup init --template my-template.claude-template.json
57
+ ### `/stack-add` searches the marketplace for you
84
58
 
85
- # Apply from a URL
86
- npx claude-setup init --template https://example.com/template.json
87
- ```
59
+ Say what you want — it searches 400+ community plugins and 13 official Anthropic plugins, downloads and installs matching skills automatically. No manual steps.
88
60
 
89
- Templates capture CLAUDE.md, MCP servers, hooks, skills, and commands. On import:
90
- - Existing content is kept, new content is merged
91
- - MCP commands are auto-adapted for the target OS
92
- - Skills and commands with the same name are skipped
61
+ ```
62
+ /stack-add
63
+ > "E2E testing and Stripe integration"
64
+ ```
93
65
 
94
- ## Token Cost Tracking
66
+ ### `/stack-sync` shows what changed
95
67
 
96
- Every command shows estimated token usage and cost across all Claude models.
68
+ Every sync creates a snapshot and shows a color-coded diff:
97
69
 
98
70
  ```
99
- Token cost
100
- ~2,450 input tokens (Opus $0.0368 | Sonnet $0.0074 | Haiku $0.0006)
71
+ Changes since 2026-03-28T14:32:01.904Z:
72
+ +2 added ~3 modified -1 deleted
73
+
74
+ Added files:
75
+ + src/api/payments.ts (48 lines)
76
+ + src/api/webhooks.ts (32 lines)
77
+
78
+ Modified files:
79
+ ~ package.json (+3 lines, -1 lines)
80
+ ~ src/index.ts (+8 lines, -2 lines)
101
81
  ```
102
82
 
103
- Status shows cumulative stats, per-command averages, and cost trends. Use `--budget` on sync to override the token limit for a single run.
83
+ Claude Code sees the actual line-level changes and updates your setup surgically.
104
84
 
105
- ## Doctor
85
+ ## Snapshots
106
86
 
107
- Validates your entire setup and reports issues by severity.
87
+ Every init and sync saves a full snapshot. You can jump to any point in time:
108
88
 
109
- ```bash
110
- npx claude-setup doctor # Check everything
111
- npx claude-setup doctor --fix # Auto-fix what's possible
112
- npx claude-setup doctor --test-hooks # Run each hook, report pass/fail
89
+ ```
90
+ /stack-restore
113
91
  ```
114
92
 
115
- What `--fix` can repair:
116
- - Remove accidental model overrides from settings.json
117
- - Convert MCP commands to the correct OS format
118
- - Add missing `-y` flags to npx calls
119
- - Re-snapshot files modified outside the CLI
120
-
121
- What `--test-hooks` checks per hook:
122
- - Command exists on the system
123
- - Command executes without error
124
- - Exit code and stderr
125
- - Execution time and timeout detection
126
- - Matcher regex validity
93
+ ```
94
+ init ──> sync#1 ──> sync#2 ──> sync#3 (you are here)
95
+ |
96
+ └── jump back here anytime
97
+ ```
127
98
 
128
- ## Marketplace
99
+ Snapshots are never deleted. Go back, go forward, freely.
129
100
 
130
- The `add` command integrates with [claude-code-plugins-plus-skills](https://github.com/jeremylongshore/claude-code-plugins-plus-skills) — 340+ plugins and 1,367+ skills across 20 categories.
101
+ ## All CLI commands
131
102
 
132
103
  ```bash
133
- npx claude-setup add
134
- # "Stripe and frontend skills"
135
- # → generates stack-add.md with marketplace search + install instructions
104
+ npx claude-setup # Interactive menu
105
+ npx claude-setup init # Full project setup
106
+ npx claude-setup sync # Checkpoint + update
107
+ npx claude-setup add "postgres and testing" # Add capabilities
108
+ npx claude-setup status # Dashboard
109
+ npx claude-setup doctor # Validate everything
110
+ npx claude-setup doctor --fix # Auto-fix issues
111
+ npx claude-setup restore # Time-travel
112
+ npx claude-setup compare # Diff two snapshots
113
+ npx claude-setup remove "redis" # Remove cleanly
114
+ npx claude-setup export # Save as template
115
+ npx claude-setup init --template file # Apply a template
136
116
  ```
137
117
 
138
118
  ## Configuration
139
119
 
140
- Auto-generated on first run. Edit `.claude-setup.json` to customize:
120
+ Auto-generated on first run. Edit `.claude-setup.json` if needed:
141
121
 
142
122
  ```json
143
123
  {
144
124
  "maxSourceFiles": 15,
145
125
  "maxDepth": 6,
146
- "maxFileSizeKB": 80,
147
- "tokenBudget": {
148
- "init": 12000,
149
- "sync": 6000,
150
- "add": 3000,
151
- "remove": 2000
152
- },
153
- "digestMode": true,
154
- "extraBlockedDirs": [],
155
- "sourceDirs": []
126
+ "tokenBudget": { "init": 12000, "sync": 6000, "add": 3000 },
127
+ "digestMode": true
156
128
  }
157
129
  ```
158
130
 
131
+ ## Supported platforms
132
+
133
+ | Platform | Status | MCP format |
134
+ |----------|--------|-----------|
135
+ | Windows | Full support | `cmd /c npx -y <pkg>` |
136
+ | macOS | Full support + Homebrew detection | `npx -y <pkg>` |
137
+ | Linux | Full support | `npx -y <pkg>` |
138
+ | WSL | Full support + Windows host access | `npx -y <pkg>` |
139
+
159
140
  ## License
160
141
 
161
142
  MIT
package/dist/builder.d.ts CHANGED
@@ -11,6 +11,12 @@ export interface FileDiff {
11
11
  changed: Array<{
12
12
  path: string;
13
13
  current: string;
14
+ previous?: string;
15
+ lineDiff?: {
16
+ added: string[];
17
+ removed: string[];
18
+ summary: string;
19
+ };
14
20
  }>;
15
21
  deleted: string[];
16
22
  }
package/dist/builder.js CHANGED
@@ -2,7 +2,7 @@ import { readFileSync } from "fs";
2
2
  import { join, dirname } from "path";
3
3
  import { fileURLToPath } from "url";
4
4
  import { loadConfig } from "./config.js";
5
- import { detectOS, VERIFIED_MCP_PACKAGES } from "./os.js";
5
+ import { detectOS, isUnixLike, VERIFIED_MCP_PACKAGES, buildServiceDiscoveryInstructions } from "./os.js";
6
6
  import { buildMarketplaceInstructions } from "./marketplace.js";
7
7
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
8
  const TEMPLATES_DIR = join(__dirname, "..", "templates");
@@ -91,6 +91,7 @@ function buildVars(collected, state) {
91
91
  };
92
92
  }
93
93
  function buildFlags(_collected, state) {
94
+ const os = detectOS();
94
95
  return {
95
96
  HAS_SOURCE: _collected.source.length > 0,
96
97
  HAS_SKIPPED: _collected.skipped.length > 0,
@@ -98,7 +99,10 @@ function buildFlags(_collected, state) {
98
99
  HAS_MCP_JSON: state.mcpJson.exists,
99
100
  HAS_SETTINGS: state.settings.exists,
100
101
  HAS_GITHUB_DIR: state.hasGithubDir,
101
- IS_WINDOWS: detectOS() === "Windows",
102
+ IS_WINDOWS: os === "Windows", // WSL uses Unix-style commands, not cmd
103
+ IS_WSL: os === "WSL",
104
+ IS_MACOS: os === "macOS",
105
+ IS_UNIX_LIKE: isUnixLike(os),
102
106
  };
103
107
  }
104
108
  // --- Token budget enforcement ---
@@ -153,15 +157,43 @@ export function buildAddCommand(input, collected, state) {
153
157
  }, "add");
154
158
  }
155
159
  export function buildSyncCommand(diff, collected, state) {
156
- // Compact diff format — paths + one-line summary, not full content
160
+ // Rich diff format — paths + line-level changes for modified files
157
161
  const addedStr = diff.added.length > 0
158
162
  ? diff.added.map(f => `- **${f.path}** (new) — ${f.content.split("\n").length} lines`).join("\n")
159
163
  : "(none)";
160
- const modifiedStr = diff.changed.length > 0
161
- ? diff.changed.map(f => `- **${f.path}** (modified)`).join("\n")
162
- : "(none)";
164
+ // Modified files now include line-level diffs
165
+ let modifiedStr;
166
+ if (diff.changed.length > 0) {
167
+ const parts = [];
168
+ for (const f of diff.changed) {
169
+ const lines = [`- **${f.path}** (modified)`];
170
+ if (f.lineDiff) {
171
+ lines[0] += ` — ${f.lineDiff.summary}`;
172
+ if (f.lineDiff.removed.length > 0 || f.lineDiff.added.length > 0) {
173
+ lines.push(" ```diff");
174
+ for (const l of f.lineDiff.removed.slice(0, 8)) {
175
+ lines.push(` - ${l.trimEnd().slice(0, 120)}`);
176
+ }
177
+ for (const l of f.lineDiff.added.slice(0, 8)) {
178
+ lines.push(` + ${l.trimEnd().slice(0, 120)}`);
179
+ }
180
+ const totalShown = Math.min(f.lineDiff.removed.length, 8) + Math.min(f.lineDiff.added.length, 8);
181
+ const total = f.lineDiff.removed.length + f.lineDiff.added.length;
182
+ if (total > totalShown) {
183
+ lines.push(` # ... +${total - totalShown} more changes`);
184
+ }
185
+ lines.push(" ```");
186
+ }
187
+ }
188
+ parts.push(lines.join("\n"));
189
+ }
190
+ modifiedStr = parts.join("\n");
191
+ }
192
+ else {
193
+ modifiedStr = "(none)";
194
+ }
163
195
  const deletedStr = diff.deleted.length > 0
164
- ? diff.deleted.map(f => `- ${f}`).join("\n")
196
+ ? diff.deleted.map(f => `- ~~${f}~~ (deleted)`).join("\n")
165
197
  : "(none)";
166
198
  const lastRun = state.manifest?.runs.at(-1);
167
199
  return applyTemplate("sync.md", collected, state, {
@@ -180,8 +212,12 @@ export function buildBootstrapSync() {
180
212
  return `<!-- stack-sync: self-refreshing sync command. Last generated: ${new Date().toISOString().split("T")[0]} -->
181
213
 
182
214
  > **Step 1 — always do this first:** Run \`npx claude-setup sync\` to refresh this file with the latest diff.
183
- > - If it outputs "No changes since…" → respond "Stack already in sync." and STOP.
184
- > - Otherwise re-read \`.claude/commands/stack-sync.md\` (Step 2), then process the diff below (Step 3).
215
+ > - If the output says **"No changes"** and shows "Setup is current" → respond "No changes detected since last sync. Everything is up to date." and STOP.
216
+ > - If the output shows **changes** (any "+N added", "~N modified", or "-N deleted" with N > 0) → it means the file has been regenerated. Continue to Step 2.
217
+ > **Step 2:** Re-read \`.claude/commands/stack-sync.md\` — it now contains the actual diff with line-level changes.
218
+ > **Step 3:** Process every change listed. Update CLAUDE.md, .mcp.json, settings.json as needed. Surgical edits only.
219
+
220
+ **IMPORTANT:** The sync command creates a snapshot AND regenerates this file. The "Run /stack-sync" message in the output is for YOU — it means this file is now ready to be re-read. Do NOT tell the user to run /stack-sync again.
185
221
 
186
222
  ## Changes since last setup
187
223
 
@@ -196,8 +232,7 @@ export function buildBootstrapSync() {
196
232
 
197
233
  ## Your job
198
234
 
199
- For EACH changed file: does this change have any implication for the Claude Code setup?
200
- Update ONLY what the change demands. Do NOT rewrite files — surgical edits only.
235
+ For EACH changed file, update the Claude Code setup. New source files (routes, services, etc.) MUST be reflected in CLAUDE.md. Config changes may require .mcp.json or settings.json updates. Surgical edits only.
201
236
  `;
202
237
  }
203
238
  export function buildRemoveCommand(input, state) {
@@ -247,73 +282,94 @@ export function buildAtomicSteps(collected, state) {
247
282
  // --- Step 2: .mcp.json ---
248
283
  {
249
284
  filename: "stack-2-mcp.md",
250
- content: header + preamble +
251
- `## Target: .mcp.json\n\n` +
252
- (state.mcpJson.exists
253
- ? `### Current content — MERGE ONLY, never remove existing entries:\n${vars.MCP_JSON_CONTENT}\n\n`
254
- : `Does not exist.\n\n`) +
255
- `### When to create/update\n` +
256
- `Add an MCP server if you find ANY of these signals in /stack-0-context:\n` +
257
- `- Import statement referencing an external service (e.g., pg, mysql2, mongoose, redis, stripe)\n` +
258
- `- docker-compose service (database, cache, queue, message broker)\n` +
259
- `- Env var name in .env.example matching a known service pattern (DATABASE_URL, REDIS_URL, STRIPE_KEY, etc.)\n` +
260
- `- Explicit dependency on an MCP-compatible package\n` +
261
- `- User mentioned external services during init questions\n\n` +
262
- `If ANY evidence is found, create .mcp.json with the corresponding servers.\n` +
263
- `No evidence = no server. Do not invent services.\n\n` +
264
- `### Verified MCP package names ONLY use these\n` +
265
- `\`\`\`\n` +
266
- Object.entries(VERIFIED_MCP_PACKAGES).map(([k, v]) => `${k.padEnd(12)} ${v}`).join("\n") +
267
- `\n\`\`\`\n` +
268
- `If the service is not in this list, print:\n` +
269
- `\`⚠️ UNKNOWN PACKAGE — [service] MCP server not added: package name unverified. Find it at https://github.com/modelcontextprotocol/servers\`\n` +
270
- `Do not add a placeholder. Do not guess.\n\n` +
271
- `### OS-correct format (detected: ${os})\n` +
272
- `**Preferred: use CLI to add (writes to .mcp.json automatically):**\n` +
273
- (os === "Windows"
274
- ? `\`\`\`\nclaude mcp add --scope project --transport stdio <name> -- cmd /c npx -y <package>\n\`\`\`\n`
275
- : `\`\`\`\nclaude mcp add --scope project --transport stdio <name> -- npx -y <package>\n\`\`\`\n`) +
276
- `**Or write .mcp.json directly:**\n` +
277
- (os === "Windows"
278
- ? `Use: \`{ "command": "cmd", "args": ["/c", "npx", "-y", "<package>"] }\`\n`
279
- : `Use: \`{ "command": "npx", "args": ["-y", "<package>"] }\`\n`) +
280
- `Always include \`-y\` in npx args to prevent install hangs.\n` +
281
- `\n### Connection strings NEVER hardcode\n` +
282
- `Wrong: \`"args": [..., "postgresql://localhost:5432/db"]\`\n` +
283
- `Right: \`"env": { "DATABASE_URL": "\${DATABASE_URL}" }\`\n` +
284
- `All credentials and connection strings must go in \`env\` using \`\${VARNAME}\` syntax.\n` +
285
- `After adding any server with env vars, flag them:\n` +
286
- `\`⚠️ Add DATABASE_URL to .env.example and populate before starting Claude Code\`\n\n` +
287
- `\n### Rules\n` +
288
- `- All env var refs use \`\${VARNAME}\` syntax — never literal values\n` +
289
- `- Produce valid JSON only\n` +
290
- `- If creating: document every new env var in .env.example\n\n` +
291
- `### Channels (Telegram, Discord) — special MCP servers\n` +
292
- `Channels are MCP servers that push events INTO a session. They require:\n` +
293
- `- Claude Code v2.1.80+\n` +
294
- `- claude.ai login (not API key / Console)\n` +
295
- `- Bun runtime installed\n` +
296
- `- \`--channels\` flag at EVERY session launch\n\n` +
297
- `Verified channel plugins:\n` +
298
- `\`\`\`\n` +
299
- `Telegram plugin:telegram@claude-plugins-official\n` +
300
- `Discord → plugin:discord@claude-plugins-official\n` +
301
- `\`\`\`\n\n` +
302
- `If adding a channel-type server, bot tokens must NEVER be hardcoded:\n` +
303
- (os === "Windows"
304
- ? `\`{ "command": "cmd", "args": ["/c", "bun", "run", "\${CLAUDE_PLUGIN_ROOT}/servers/telegram"], "env": { "TELEGRAM_BOT_TOKEN": "\${TELEGRAM_BOT_TOKEN}" } }\`\n`
305
- : `\`{ "command": "bun", "args": ["run", "\${CLAUDE_PLUGIN_ROOT}/servers/telegram"], "env": { "TELEGRAM_BOT_TOKEN": "\${TELEGRAM_BOT_TOKEN}" } }\`\n`) +
306
- `After adding, flag: \`⚠️ CHANNEL ACTIVATION REQUIRED — launch with: claude --channels plugin:telegram@claude-plugins-official\`\n\n` +
307
- `### Self-correction fallback\n` +
308
- `If MCP configuration fails or produces warnings:\n` +
309
- `1. Read the official MCP documentation: https://modelcontextprotocol.io/introduction\n` +
310
- `2. Verify the package name against the MCP servers registry: https://github.com/modelcontextprotocol/servers\n` +
311
- `3. Check the server's README for required env vars and correct args format\n` +
312
- `4. Re-run \`npx claude-setup doctor\` to validate the fix\n` +
313
- `Do NOT leave broken MCP configuration in place — either fix it or remove the entry.\n\n` +
314
- `### Output\n` +
315
- `Created/Updated: .mcp.json [what server and evidence source]\n` +
316
- `Skipped: .mcp.json — checked [files], found [nothing], no action\n`,
285
+ content: (() => {
286
+ const serviceDiscovery = buildServiceDiscoveryInstructions(process.cwd());
287
+ return header + preamble +
288
+ `## Target: .mcp.json\n\n` +
289
+ (state.mcpJson.exists
290
+ ? `### Current content — MERGE ONLY, never remove existing entries:\n${vars.MCP_JSON_CONTENT}\n\n`
291
+ : `Does not exist.\n\n`) +
292
+ `### When to create/update\n` +
293
+ `Add an MCP server if you find ANY of these signals in /stack-0-context:\n` +
294
+ `- Import statement referencing an external service (e.g., pg, mysql2, mongoose, redis, stripe)\n` +
295
+ `- docker-compose service (database, cache, queue, message broker)\n` +
296
+ `- Env var name in .env.example matching a known service pattern (DATABASE_URL, REDIS_URL, STRIPE_KEY, etc.)\n` +
297
+ `- Explicit dependency on an MCP-compatible package\n` +
298
+ `- User mentioned external services during init questions\n\n` +
299
+ `If ANY evidence is found, create .mcp.json with the corresponding servers.\n` +
300
+ `No evidence = no server. Do not invent services.\n\n` +
301
+ (serviceDiscovery ? serviceDiscovery + `\n` : ``) +
302
+ `### Verified MCP package names — ONLY use these\n` +
303
+ `\`\`\`\n` +
304
+ Object.entries(VERIFIED_MCP_PACKAGES).map(([k, v]) => `${k.padEnd(12)} ${v}`).join("\n") +
305
+ `\n\`\`\`\n` +
306
+ `If the service is not in this list, print:\n` +
307
+ `\`⚠️ UNKNOWN PACKAGE — [service] MCP server not added: package name unverified. Find it at https://github.com/modelcontextprotocol/servers\`\n` +
308
+ `Do not add a placeholder. Do not guess.\n\n` +
309
+ `### OS-correct format (detected: ${os}${os === "WSL" ? " uses Unix-style commands, services reachable on localhost" : ""})\n` +
310
+ `**Preferred: use CLI to add (writes to .mcp.json automatically):**\n` +
311
+ (os === "Windows"
312
+ ? `\`\`\`\nclaude mcp add --scope project --transport stdio <name> -- cmd /c npx -y <package>\n\`\`\`\n`
313
+ : `\`\`\`\nclaude mcp add --scope project --transport stdio <name> -- npx -y <package>\n\`\`\`\n`) +
314
+ `**Or write .mcp.json directly:**\n` +
315
+ (os === "Windows"
316
+ ? `Use: \`{ "command": "cmd", "args": ["/c", "npx", "-y", "<package>"] }\`\n`
317
+ : `Use: \`{ "command": "npx", "args": ["-y", "<package>"] }\`\n`) +
318
+ `Always include \`-y\` in npx args to prevent install hangs.\n` +
319
+ (os === "WSL" ? `Note: WSL uses Unix-style npx do NOT use \`cmd /c\` wrapper.\n` : ``) +
320
+ (os === "macOS" ? `Note: On macOS, Homebrew services run on localhost by default. Check with \`brew services list\`.\n` : ``) +
321
+ `\n` +
322
+ `### Connection strings — smart auto-configuration\n` +
323
+ `For each MCP server that needs a connection string:\n` +
324
+ `1. **Check environment first:** If \`\${VARNAME}\` is set in the user's environment, use \`"env": { "VAR": "\${VAR}" }\`\n` +
325
+ `2. **Detect local service:** Run the OS-appropriate check command to see if the service is installed locally\n` +
326
+ (os === "Windows"
327
+ ? ` - PostgreSQL: \`where psql 2>nul\`\n - MongoDB: \`where mongosh 2>nul\`\n - Redis: \`where redis-cli 2>nul\`\n - MySQL: \`where mysql 2>nul\`\n`
328
+ : os === "macOS"
329
+ ? ` - PostgreSQL: \`command -v psql || brew list postgresql 2>/dev/null\`\n - MongoDB: \`command -v mongosh || brew list mongodb-community 2>/dev/null\`\n - Redis: \`command -v redis-cli || brew list redis 2>/dev/null\`\n - MySQL: \`command -v mysql || brew list mysql 2>/dev/null\`\n`
330
+ : ` - PostgreSQL: \`command -v psql\`\n - MongoDB: \`command -v mongosh\`\n - Redis: \`command -v redis-cli\`\n - MySQL: \`command -v mysql\`\n`) +
331
+ `3. **If local service found and env var NOT set:** Use the well-known default URL directly in the env block:\n` +
332
+ ` - PostgreSQL: \`postgresql://localhost:5432/postgres\`\n` +
333
+ ` - MongoDB: \`mongodb://localhost:27017\`\n` +
334
+ ` - Redis: \`redis://localhost:6379\`\n` +
335
+ ` - MySQL: \`mysql://root@localhost:3306\`\n` +
336
+ ` AND document the var in .env.example with the default value\n` +
337
+ `4. **If neither env var nor local service found:** Use \`\${VARNAME}\` syntax and flag:\n` +
338
+ ` \`⚠️ Set VARNAME in your environment or .env file before starting Claude Code\`\n\n` +
339
+ `**NEVER hardcode credentials.** Default localhost URLs are acceptable for dev environments.\n` +
340
+ `After adding any server with env vars, always document them in .env.example.\n\n` +
341
+ `### Rules\n` +
342
+ `- Produce valid JSON only\n` +
343
+ `- If creating: document every new env var in .env.example\n` +
344
+ `- OS format must match detected OS: ${os}\n\n` +
345
+ `### Channels (Telegram, Discord) special MCP servers\n` +
346
+ `Channels are MCP servers that push events INTO a session. They require:\n` +
347
+ `- Claude Code v2.1.80+\n` +
348
+ `- claude.ai login (not API key / Console)\n` +
349
+ `- Bun runtime installed\n` +
350
+ `- \`--channels\` flag at EVERY session launch\n\n` +
351
+ `Verified channel plugins:\n` +
352
+ `\`\`\`\n` +
353
+ `Telegram → plugin:telegram@claude-plugins-official\n` +
354
+ `Discord → plugin:discord@claude-plugins-official\n` +
355
+ `\`\`\`\n\n` +
356
+ `If adding a channel-type server, bot tokens must NEVER be hardcoded:\n` +
357
+ (os === "Windows"
358
+ ? `\`{ "command": "cmd", "args": ["/c", "bun", "run", "\${CLAUDE_PLUGIN_ROOT}/servers/telegram"], "env": { "TELEGRAM_BOT_TOKEN": "\${TELEGRAM_BOT_TOKEN}" } }\`\n`
359
+ : `\`{ "command": "bun", "args": ["run", "\${CLAUDE_PLUGIN_ROOT}/servers/telegram"], "env": { "TELEGRAM_BOT_TOKEN": "\${TELEGRAM_BOT_TOKEN}" } }\`\n`) +
360
+ (os === "WSL" ? `(WSL note: Bun must be installed inside WSL, not the Windows-side installation.)\n` : ``) +
361
+ `After adding, flag: \`⚠️ CHANNEL ACTIVATION REQUIRED — launch with: claude --channels plugin:telegram@claude-plugins-official\`\n\n` +
362
+ `### Self-correction fallback\n` +
363
+ `If MCP configuration fails or produces warnings:\n` +
364
+ `1. Read the official MCP documentation: https://modelcontextprotocol.io/introduction\n` +
365
+ `2. Verify the package name against the MCP servers registry: https://github.com/modelcontextprotocol/servers\n` +
366
+ `3. Check the server's README for required env vars and correct args format\n` +
367
+ `4. Re-run \`npx claude-setup doctor\` to validate the fix\n` +
368
+ `Do NOT leave broken MCP configuration in place — either fix it or remove the entry.\n\n` +
369
+ `### Output\n` +
370
+ `Created/Updated: ✅ .mcp.json — [what server and evidence source]\n` +
371
+ `Skipped: ⏭ .mcp.json — checked [files], found [nothing], no action\n`;
372
+ })(),
317
373
  },
318
374
  // --- Step 3: .claude/settings.json ---
319
375
  {
@@ -1 +1,3 @@
1
- export declare function runAdd(): Promise<void>;
1
+ export declare function runAdd(opts?: {
2
+ input?: string;
3
+ }): Promise<void>;
@@ -4,8 +4,8 @@ import { collectProjectFiles } from "../collect.js";
4
4
  import { readState } from "../state.js";
5
5
  import { updateManifest } from "../manifest.js";
6
6
  import { buildAddCommand } from "../builder.js";
7
- import { estimateTokens, estimateCost, formatCost } from "../tokens.js";
8
- import { c, section } from "../output.js";
7
+ import { estimateTokens, estimateCost } from "../tokens.js";
8
+ import { c } from "../output.js";
9
9
  function ensureDir(dir) {
10
10
  if (!existsSync(dir))
11
11
  mkdirSync(dir, { recursive: true });
@@ -19,16 +19,13 @@ async function promptFreeText(question) {
19
19
  });
20
20
  });
21
21
  }
22
- // Conservative — only redirect when unambiguously single-file
23
- // False negatives (multi-step for single-file request) are fine
24
- // False positives (redirecting a genuinely multi-file request) are bad
25
22
  function isSingleFileOperation(input) {
26
23
  return (/to \.mcp\.json\s*$/i.test(input) ||
27
24
  /to settings\.json\s*$/i.test(input) ||
28
25
  /to claude\.md\s*$/i.test(input));
29
26
  }
30
- export async function runAdd() {
31
- const userInput = await promptFreeText("What do you want to add to your Claude Code setup?");
27
+ export async function runAdd(opts = {}) {
28
+ const userInput = opts.input ?? await promptFreeText("What do you want to add to your Claude Code setup?");
32
29
  if (!userInput) {
33
30
  console.log("No input provided.");
34
31
  return;
@@ -44,10 +41,8 @@ capabilities that need documentation, MCP servers, skills, and hooks together.
44
41
  return;
45
42
  }
46
43
  const state = await readState();
47
- // add only needs config files — source files are irrelevant and waste tokens
48
44
  const collected = await collectProjectFiles(process.cwd(), "configOnly");
49
45
  const content = buildAddCommand(userInput, collected, state);
50
- // Token tracking
51
46
  const tokens = estimateTokens(content);
52
47
  const cost = estimateCost(tokens);
53
48
  ensureDir(".claude/commands");
@@ -57,8 +52,5 @@ capabilities that need documentation, MCP servers, skills, and hooks together.
57
52
  estimatedTokens: tokens,
58
53
  estimatedCost: cost,
59
54
  });
60
- console.log(`\n${c.green("✅")} Ready. Open Claude Code and run:\n ${c.cyan("/stack-add")}`);
61
- section("Token cost");
62
- console.log(` ~${tokens.toLocaleString()} input tokens (${c.dim(`${formatCost(cost)}`)})`);
63
- console.log("");
55
+ console.log(`\n${c.green("✅")} Ready. Open Claude Code and run:\n ${c.cyan("/stack-add")}\n`);
64
56
  }