claude-setup 1.1.2 → 1.1.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
@@ -2,9 +2,9 @@
2
2
 
3
3
  Setup layer for Claude Code. Reads your project, writes command files, Claude Code does the rest.
4
4
 
5
- **The CLI has zero intelligence.** All reasoning is delegated to Claude Code via the command files. The CLI reads files. Claude Code decides.
5
+ **The CLI has zero intelligence.** All reasoning is delegated to Claude Code via the command files.
6
6
 
7
- ## Install & Quick Start
7
+ ## Install
8
8
 
9
9
  ```bash
10
10
  npx claude-setup init
@@ -16,70 +16,128 @@ Then open Claude Code and run `/stack-init`.
16
16
 
17
17
  | Command | What it does |
18
18
  |---------|-------------|
19
- | `npx claude-setup init` | Full project setup — new or existing. Detects empty projects automatically. |
20
- | `npx claude-setup add` | Add a multi-file capability (MCP + hooks + skills together) |
21
- | `npx claude-setup sync` | Update setup after project changes (uses diff, not full re-scan) |
22
- | `npx claude-setup status` | Show current setup state OS, servers, hooks, staleness |
23
- | `npx claude-setup doctor` | Validate environment — OS/MCP format, hook quoting, env vars, stale skills |
24
- | `npx claude-setup remove` | Remove a capability cleanly with dangling reference detection |
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 |
25
28
 
26
29
  ### Flags
27
30
 
28
31
  ```bash
29
- npx claude-setup init --dry-run # Preview without writing
30
- npx claude-setup sync --dry-run # Show changes without writing
31
- npx claude-setup doctor --verbose # Include passing checks in output
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
32
39
  ```
33
40
 
34
41
  ## How it works
35
42
 
36
- 1. **CLI collects** — reads project files (configs, source samples) with strict token cost controls
37
- 2. **CLI writes command files** — assembles markdown instructions into `.claude/commands/`
38
- 3. **Claude Code executes** — you run `/stack-init` (or `/stack-sync`, etc.) in Claude Code
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.
39
46
 
40
- ## Three project states
47
+ ## What it creates
41
48
 
42
- - **Empty project** Claude Code asks 3 discovery questions, then sets up a tailored environment
43
- - **In development** — reads existing files, writes setup that references actual code patterns
44
- - **Production** same as development; merge rules protect existing Claude config (append only, never rewrite)
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) |
45
57
 
46
- ## What it creates
58
+ ## Snapshots
59
+
60
+ Every `init` and `sync` creates a snapshot node — a checkpoint on a timeline. Snapshots store the content of changed files only.
61
+
62
+ ```
63
+ init ──→ sync#1 ──→ sync#2 ──→ sync#3 (current)
64
+ │ │
65
+ │ └─ bug introduced here
66
+ └─ jump back here
67
+ ```
68
+
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
72
+
73
+ ## Templates
47
74
 
48
- - `CLAUDE.md` project-specific context for Claude Code
49
- - `.mcp.json` — MCP server connections (only if evidenced by project files, OS-correct format)
50
- - `.claude/settings.json` — hooks (only if warranted, OS-correct shell format)
51
- - `.claude/skills/` reusable patterns (only if recurring, with `applies-when` frontmatter)
52
- - `.claude/commands/` — project-specific slash commands
53
- - `.github/workflows/` CI workflows (only if `.github/` exists)
54
-
55
- ## Token cost controls
56
-
57
- Every byte injected into command files costs tokens. The CLI enforces:
58
-
59
- | Control | Default |
60
- |---------|---------|
61
- | Init token budget | 12,000 |
62
- | Sync token budget | 6,000 |
63
- | Add token budget | 3,000 |
64
- | Remove token budget | 2,000 |
65
- | Max source files sampled | 15 |
66
- | Max file size | 80KB |
67
- | Max depth | 6 levels |
68
-
69
- ### File-specific truncation
70
-
71
- | File | Strategy |
72
- |------|----------|
73
- | `package-lock.json` | Extract `{ name, version, lockfileVersion }` only |
74
- | `Dockerfile` | First 50 lines |
75
- | `docker-compose.yml` | First 100 lines if > 8KB |
76
- | `pom.xml`, `build.gradle*` | First 80 lines |
77
- | `setup.py` | First 60 lines |
78
- | `*.config.{js,ts,mjs}` | First 100 lines |
75
+ Save your setup and reuse it across projects.
76
+
77
+ ```bash
78
+ # Export current setup
79
+ npx claude-setup export
80
+ # creates my-template.claude-template.json
81
+
82
+ # Apply to a new project
83
+ npx claude-setup init --template my-template.claude-template.json
84
+
85
+ # Apply from a URL
86
+ npx claude-setup init --template https://example.com/template.json
87
+ ```
88
+
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
93
+
94
+ ## Token Cost Tracking
95
+
96
+ Every command shows estimated token usage and cost across all Claude models.
97
+
98
+ ```
99
+ Token cost
100
+ ~2,450 input tokens (Opus $0.0368 | Sonnet $0.0074 | Haiku $0.0006)
101
+ ```
102
+
103
+ Status shows cumulative stats, per-command averages, and cost trends. Use `--budget` on sync to override the token limit for a single run.
104
+
105
+ ## Doctor
106
+
107
+ Validates your entire setup and reports issues by severity.
108
+
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
113
+ ```
114
+
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
127
+
128
+ ## Marketplace
129
+
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.
131
+
132
+ ```bash
133
+ npx claude-setup add
134
+ # → "Stripe and frontend skills"
135
+ # → generates stack-add.md with marketplace search + install instructions
136
+ ```
79
137
 
80
138
  ## Configuration
81
139
 
82
- Create `.claude-setup.json` in your project root to customize:
140
+ Auto-generated on first run. Edit `.claude-setup.json` to customize:
83
141
 
84
142
  ```json
85
143
  {
@@ -93,27 +151,11 @@ Create `.claude-setup.json` in your project root to customize:
93
151
  "remove": 2000
94
152
  },
95
153
  "digestMode": true,
96
- "extraBlockedDirs": ["my-custom-dir"],
97
- "sourceDirs": ["src", "lib"]
154
+ "extraBlockedDirs": [],
155
+ "sourceDirs": []
98
156
  }
99
157
  ```
100
158
 
101
- ## Digest mode
102
-
103
- When `digestMode` is enabled (default), the CLI extracts compact signal instead of dumping raw file content:
104
-
105
- - **Config files found** — just names, not content
106
- - **Dependencies** — extracted from any package manifest
107
- - **Scripts** — available commands/tasks
108
- - **Env vars** — names from `.env.example`
109
- - **Directory tree** — compact structure (3 levels deep)
110
- - **Source signatures** — imports, exports, declarations (not full content)
111
-
112
- ## OS detection
113
-
114
- The CLI detects your OS and ensures command files tell Claude Code to use the correct format:
115
-
116
- - **Windows**: `{ "command": "cmd", "args": ["/c", "npx", "<package>"] }`
117
- - **macOS/Linux**: `{ "command": "npx", "args": ["<package>"] }`
159
+ ## License
118
160
 
119
- `doctor` checks for mismatches and reports them as critical issues.
161
+ MIT
package/dist/builder.js CHANGED
@@ -2,7 +2,8 @@ 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 } from "./os.js";
5
+ import { detectOS, VERIFIED_MCP_PACKAGES } from "./os.js";
6
+ import { buildMarketplaceInstructions } from "./marketplace.js";
6
7
  const __dirname = dirname(fileURLToPath(import.meta.url));
7
8
  const TEMPLATES_DIR = join(__dirname, "..", "templates");
8
9
  function estimateTokens(content) {
@@ -97,6 +98,7 @@ function buildFlags(_collected, state) {
97
98
  HAS_MCP_JSON: state.mcpJson.exists,
98
99
  HAS_SETTINGS: state.settings.exists,
99
100
  HAS_GITHUB_DIR: state.hasGithubDir,
101
+ IS_WINDOWS: detectOS() === "Windows",
100
102
  };
101
103
  }
102
104
  // --- Token budget enforcement ---
@@ -137,10 +139,18 @@ export function buildInitCommand(collected, state) {
137
139
  }
138
140
  export function buildEmptyProjectCommand() {
139
141
  const template = loadTemplate("init-empty.md");
140
- return replaceVars(template, { VERSION: getVersion(), DATE: new Date().toISOString().split("T")[0] });
142
+ const vars = { VERSION: getVersion(), DATE: new Date().toISOString().split("T")[0], DETECTED_OS: detectOS() };
143
+ const flags = { IS_WINDOWS: detectOS() === "Windows" };
144
+ let content = replaceVars(template, vars);
145
+ content = processConditionals(content, flags);
146
+ return content;
141
147
  }
142
148
  export function buildAddCommand(input, collected, state) {
143
- return applyTemplate("add.md", collected, state, { USER_INPUT: input }, "add");
149
+ const marketplaceSection = buildMarketplaceInstructions(input);
150
+ return applyTemplate("add.md", collected, state, {
151
+ USER_INPUT: input,
152
+ MARKETPLACE_INSTRUCTIONS: marketplaceSection,
153
+ }, "add");
144
154
  }
145
155
  export function buildSyncCommand(diff, collected, state) {
146
156
  // Compact diff format — paths + one-line summary, not full content
@@ -214,20 +224,52 @@ export function buildAtomicSteps(collected, state) {
214
224
  ? `### Current content — MERGE ONLY, never remove existing entries:\n${vars.MCP_JSON_CONTENT}\n\n`
215
225
  : `Does not exist.\n\n`) +
216
226
  `### When to create/update\n` +
217
- `Add an MCP server ONLY if you find evidence in /stack-0-context:\n` +
218
- `- Import statement referencing an external service\n` +
219
- `- docker-compose service (database, cache, queue)\n` +
220
- `- Env var name in .env.example matching a known service pattern\n` +
221
- `- Explicit dependency on an MCP-compatible package\n\n` +
227
+ `Add an MCP server if you find ANY of these signals in /stack-0-context:\n` +
228
+ `- Import statement referencing an external service (e.g., pg, mysql2, mongoose, redis, stripe)\n` +
229
+ `- docker-compose service (database, cache, queue, message broker)\n` +
230
+ `- Env var name in .env.example matching a known service pattern (DATABASE_URL, REDIS_URL, STRIPE_KEY, etc.)\n` +
231
+ `- Explicit dependency on an MCP-compatible package\n` +
232
+ `- User mentioned external services during init questions\n\n` +
233
+ `If ANY evidence is found, create .mcp.json with the corresponding servers.\n` +
222
234
  `No evidence = no server. Do not invent services.\n\n` +
235
+ `### Verified MCP package names — ONLY use these\n` +
236
+ `\`\`\`\n` +
237
+ Object.entries(VERIFIED_MCP_PACKAGES).map(([k, v]) => `${k.padEnd(12)} → ${v}`).join("\n") +
238
+ `\n\`\`\`\n` +
239
+ `If the service is not in this list, print:\n` +
240
+ `\`⚠️ UNKNOWN PACKAGE — [service] MCP server not added: package name unverified. Find it at https://github.com/modelcontextprotocol/servers\`\n` +
241
+ `Do not add a placeholder. Do not guess.\n\n` +
223
242
  `### OS-correct format (detected: ${os})\n` +
224
243
  (os === "Windows"
225
- ? `Use: \`{ "command": "cmd", "args": ["/c", "npx", "<package>"] }\`\n`
226
- : `Use: \`{ "command": "npx", "args": ["<package>"] }\`\n`) +
244
+ ? `Use: \`{ "command": "cmd", "args": ["/c", "npx", "-y", "<package>"] }\`\n`
245
+ : `Use: \`{ "command": "npx", "args": ["-y", "<package>"] }\`\n`) +
246
+ `Always include \`-y\` in npx args to prevent install hangs.\n` +
247
+ `\n### Connection strings — NEVER hardcode\n` +
248
+ `Wrong: \`"args": [..., "postgresql://localhost:5432/db"]\`\n` +
249
+ `Right: \`"env": { "DATABASE_URL": "\${DATABASE_URL}" }\`\n` +
250
+ `All credentials and connection strings must go in \`env\` using \`\${VARNAME}\` syntax.\n` +
251
+ `After adding any server with env vars, flag them:\n` +
252
+ `\`⚠️ Add DATABASE_URL to .env.example and populate before starting Claude Code\`\n\n` +
227
253
  `\n### Rules\n` +
228
- `- All env var refs use \`\${VARNAME}\` syntax\n` +
254
+ `- All env var refs use \`\${VARNAME}\` syntax — never literal values\n` +
229
255
  `- Produce valid JSON only\n` +
230
256
  `- If creating: document every new env var in .env.example\n\n` +
257
+ `### Channels (Telegram, Discord) — special MCP servers\n` +
258
+ `Channels are MCP servers that push events INTO a session. They require:\n` +
259
+ `- Claude Code v2.1.80+\n` +
260
+ `- claude.ai login (not API key / Console)\n` +
261
+ `- Bun runtime installed\n` +
262
+ `- \`--channels\` flag at EVERY session launch\n\n` +
263
+ `Verified channel plugins:\n` +
264
+ `\`\`\`\n` +
265
+ `Telegram → plugin:telegram@claude-plugins-official\n` +
266
+ `Discord → plugin:discord@claude-plugins-official\n` +
267
+ `\`\`\`\n\n` +
268
+ `If adding a channel-type server, bot tokens must NEVER be hardcoded:\n` +
269
+ (os === "Windows"
270
+ ? `\`{ "command": "cmd", "args": ["/c", "bun", "run", "\${CLAUDE_PLUGIN_ROOT}/servers/telegram"], "env": { "TELEGRAM_BOT_TOKEN": "\${TELEGRAM_BOT_TOKEN}" } }\`\n`
271
+ : `\`{ "command": "bun", "args": ["run", "\${CLAUDE_PLUGIN_ROOT}/servers/telegram"], "env": { "TELEGRAM_BOT_TOKEN": "\${TELEGRAM_BOT_TOKEN}" } }\`\n`) +
272
+ `After adding, flag: \`⚠️ CHANNEL ACTIVATION REQUIRED — launch with: claude --channels plugin:telegram@claude-plugins-official\`\n\n` +
231
273
  `### Output\n` +
232
274
  `Created/Updated: ✅ .mcp.json — [what server and evidence source]\n` +
233
275
  `Skipped: ⏭ .mcp.json — checked [files], found [nothing], no action\n`,
@@ -243,16 +285,53 @@ export function buildAtomicSteps(collected, state) {
243
285
  `### When to create/update\n` +
244
286
  `Add a hook ONLY if it runs on a pattern that repeats every session AND the cost is justified.\n` +
245
287
  `Every hook adds overhead on every Claude Code action. Only add if clearly earned.\n\n` +
246
- `### OS-correct hook format (detected: ${os})\n` +
288
+ `### CORRECT Claude Code hooks format USE THIS EXACTLY\n` +
289
+ `The hooks object must be nested inside a top-level \`"hooks"\` key.\n` +
290
+ `Each event contains an array of matcher objects, each with its own \`"hooks"\` array.\n\n` +
291
+ `\`\`\`json\n` +
292
+ `{\n` +
293
+ ` "hooks": {\n` +
294
+ ` "PostToolUse": [\n` +
295
+ ` {\n` +
296
+ ` "matcher": "Edit|Write",\n` +
297
+ ` "hooks": [\n` +
298
+ ` {\n` +
299
+ ` "type": "command",\n` +
300
+ ` "command": "<shell command here>"\n` +
301
+ ` }\n` +
302
+ ` ]\n` +
303
+ ` }\n` +
304
+ ` ]\n` +
305
+ ` }\n` +
306
+ `}\n` +
307
+ `\`\`\`\n\n` +
308
+ `**WRONG formats (do NOT use):**\n` +
309
+ `- \`"hooks": { "post-edit": ["mvn compile"] }\` — INVALID event name and structure\n` +
310
+ `- \`"PostToolUse": [{ "command": "bash", "args": [...] }]\` — missing top-level "hooks" key\n` +
311
+ `- \`{ "command": "cmd", "args": ["/c", "..."] }\` — old format, must use "type": "command"\n\n` +
312
+ `### Valid hook event names — use ONLY these\n` +
313
+ `\`PreToolUse\`, \`PostToolUse\`, \`PostToolUseFailure\`, \`Stop\`, \`SessionStart\`,\n` +
314
+ `\`Notification\`, \`UserPromptSubmit\`, \`PermissionRequest\`, \`ConfigChange\`,\n` +
315
+ `\`SubagentStart\`, \`SubagentStop\`, \`SessionEnd\`\n\n` +
316
+ `### Matcher patterns\n` +
317
+ `- \`"Edit|Write"\` — fires only on file edits\n` +
318
+ `- \`"Bash"\` — fires only on shell commands\n` +
319
+ `- \`""\` (empty) — fires on all occurrences of the event\n\n` +
320
+ `### BUG 8 FIX: Verify build tools exist BEFORE adding hooks\n` +
321
+ `Before adding any hook that runs a build tool, verify it is installed:\n` +
247
322
  (os === "Windows"
248
- ? `Use: \`{ "command": "cmd", "args": ["/c", "<command>"] }\`\n`
249
- : `Use: \`{ "command": "bash", "args": ["-c", "<command>"] }\`\n` +
250
- `**Bash quoting rule**: never use bare \`"\` inside \`-c "..."\` — use \`\\x22\` instead.\n` +
251
- `Replace \`'\` with \`\\x27\`, \`$\` in character classes with \`\\x24\`.\n`) +
252
- `\n### Rules\n` +
323
+ ? `\`\`\`\nwhere mvn 2>nul && mvn compile -q\nwhere gradle 2>nul && gradle build\nwhere npm 2>nul && npm run build\n\`\`\`\n`
324
+ : `\`\`\`\ncommand -v mvn && mvn compile -q\ncommand -v gradle && gradle build\ncommand -v npm && npm run build\n\`\`\`\n`) +
325
+ `If the tool is NOT installed:\n` +
326
+ `- Wrap the command with an existence check: \`command -v mvn && mvn compile -q\`\n` +
327
+ `- OR skip the hook and print: \`⚠️ SKIPPED mvn hook — Maven not found. Install Maven first.\`\n` +
328
+ `- NEVER add a hook for a tool that doesn't exist on the system\n\n` +
329
+ `### Rules\n` +
330
+ `- **NEVER write a "model" key into settings.json** — it overrides the user's model selection silently\n` +
253
331
  `- If it exists above: audit quoting of existing hooks first, fix broken ones\n` +
254
332
  `- Only add hooks for patterns that genuinely recur for this project type\n` +
255
- `- Produce valid JSON only\n\n` +
333
+ `- Produce valid JSON only\n` +
334
+ `- The \`"type"\` field in each hook must be one of: \`"command"\`, \`"prompt"\`, \`"agent"\`, \`"http"\`\n\n` +
256
335
  `### Output\n` +
257
336
  `Created/Updated: ✅ settings.json — [hook name and justification]\n` +
258
337
  `Skipped: ⏭ settings.json — [why no hooks warranted]\n`,
@@ -264,16 +343,37 @@ export function buildAtomicSteps(collected, state) {
264
343
  `## Target: .claude/skills/\n` +
265
344
  `Installed: ${vars.SKILLS_LIST}\n\n` +
266
345
  `### When to create\n` +
267
- `Create a skill ONLY if:\n` +
346
+ `Create a skill if:\n` +
268
347
  `- A recurring multi-step project-specific pattern exists in /stack-0-context\n` +
269
- `- It is NOT something Claude already knows (standard patterns don't need skills)\n` +
348
+ `- The project type has standard workflows worth automating (build, deploy, test patterns)\n` +
270
349
  `- It will save time across multiple Claude Code sessions\n\n` +
350
+ `### Correct skill file format\n` +
351
+ `Skills must be created as \`.claude/skills/<skill-name>/SKILL.md\` with YAML frontmatter:\n\n` +
352
+ `\`\`\`yaml\n` +
353
+ `---\n` +
354
+ `name: skill-name\n` +
355
+ `description: What this skill does and when to use it\n` +
356
+ `---\n\n` +
357
+ `Skill instructions here...\n` +
358
+ `\`\`\`\n\n` +
359
+ `Optional frontmatter fields:\n` +
360
+ `- \`disable-model-invocation: true\` — only user can invoke (for commands with side effects)\n` +
361
+ `- \`allowed-tools: Read, Grep\` — restrict which tools the skill can use\n` +
362
+ `- \`context: fork\` — run in isolated subagent\n` +
363
+ `- \`agent: Explore\` — which agent type to use with context: fork\n\n` +
364
+ `### Project-specific skills to consider\n` +
365
+ `Based on what you see in /stack-0-context, consider creating skills for:\n` +
366
+ `- Build/deploy workflows specific to this stack\n` +
367
+ `- Code review patterns specific to this codebase\n` +
368
+ `- Database migration patterns if migration files exist\n` +
369
+ `- Testing patterns if test infrastructure exists\n\n` +
271
370
  `### Rules\n` +
272
- `- Use \`applies-when:\` frontmatter so skills load only when relevant, not every message\n` +
371
+ `- Use \`description:\` frontmatter so Claude knows when to load the skill\n` +
273
372
  `- If a similar skill already exists above: extend it, don't create a parallel one\n` +
274
- `- Empty is valid — no skills is better than useless skills\n\n` +
373
+ `- Empty is valid — no skills is better than useless skills\n` +
374
+ `- Each skill directory MUST contain a SKILL.md file\n\n` +
275
375
  `### Output\n` +
276
- `Created: ✅ .claude/skills/[name] — [what pattern it captures]\n` +
376
+ `Created: ✅ .claude/skills/[name]/SKILL.md — [what pattern it captures]\n` +
277
377
  `Skipped: ⏭ skills — checked [patterns], found [nothing project-specific]\n`,
278
378
  },
279
379
  // --- Step 5: .claude/commands/ ---
@@ -283,19 +383,55 @@ export function buildAtomicSteps(collected, state) {
283
383
  `## Target: .claude/commands/ (excluding stack-*.md — those are setup artifacts)\n` +
284
384
  `Installed: ${vars.COMMANDS_LIST}\n\n` +
285
385
  `### When to create\n` +
286
- `Create a command ONLY for project-specific multi-step workflows a developer repeats:\n` +
287
- `- Deploy sequences\n` +
288
- `- Database migration + seed\n` +
289
- `- Release workflows\n` +
290
- `- Environment setup for a new contributor\n\n` +
291
- `Do NOT create commands for things expressible as a single shell alias.\n` +
292
- `Look at the scripts in /stack-0-context for evidence of multi-step workflows.\n\n` +
386
+ `Create a command ONLY for project-specific multi-step workflows a developer repeats.\n` +
387
+ `Do NOT create commands for things expressible as a single shell alias.\n\n` +
388
+ `### Smart environment detection\n` +
389
+ `Also scan for missing/incomplete environment setup:\n` +
390
+ `- \`.env.example\` exists but \`.env\` missing → suggest \`/setup-env\`\n` +
391
+ `- \`docker-compose.yml\` with \`depends_on\` suggest \`/up\` with correct startup order\n` +
392
+ `- Database migration files (\`migrations/\`, \`prisma/schema.prisma\`, \`alembic/\`) suggest \`/db:migrate\`, \`/db:rollback\`\n` +
393
+ `- \`package.json\` with \`"prepare"\` or \`"postinstall"\` hooks → suggest \`/install\`\n` +
394
+ `- \`Makefile\` with \`install\`, \`deps\`, \`bootstrap\` → fold into \`/init\`\n` +
395
+ `- README sections ("Environment Variables", "Database Setup") → each can become a command\n\n` +
396
+ `All suggestions must be built from actual project files — never assume fixed commands.\n` +
397
+ `Detect the real tooling (npm vs yarn vs pnpm, docker compose vs docker-compose) from project evidence.\n\n` +
398
+ `### REQUIRED: Scan for multi-step patterns before deciding\n` +
399
+ `You MUST actively scan these sources in /stack-0-context:\n` +
400
+ `- **Makefile targets**: multiple chained commands under one target\n` +
401
+ `- **package.json scripts**: chained commands with && or ;\n` +
402
+ `- **docker-compose.yml**: service dependencies implying a boot order\n` +
403
+ `- **Dockerfile**: multi-stage patterns implying a build sequence\n` +
404
+ `- **README.md / docs**: sections like "Getting Started", "How to run"\n` +
405
+ `- **Shell scripts** in /scripts or /bin\n` +
406
+ `- **.env.example**: many vars suggest a setup sequence\n\n` +
407
+ `### Pattern signatures to detect\n` +
408
+ `| Pattern found | Suggested command |\n` +
409
+ `|---------------|-------------------|\n` +
410
+ `| docker-compose down + volume removal + build + up | /clean-rebuild |\n` +
411
+ `| migrate + seed + start | /fresh-start |\n` +
412
+ `| build + test + deploy | /release |\n` +
413
+ `| lint + format + typecheck all separate | /check |\n` +
414
+ `| setup + install + configure in README or scripts | /init |\n` +
415
+ `| backup/restore scripts or pg_dump/mongodump | /db:backup, /db:restore |\n` +
416
+ `| test + test:watch + test:coverage | /test |\n` +
417
+ `| dev + start + debug in package.json | /dev |\n` +
418
+ `| >2 manual steps in README "how to run" | candidate for /start |\n\n` +
419
+ `For each pattern found, suggest to the user:\n` +
420
+ `\`\`\`\n` +
421
+ `## Suggested command: /[name]\n\n` +
422
+ `I found a multi-step pattern in [source]:\n` +
423
+ ` 1. [step]\n` +
424
+ ` 2. [step]\n\n` +
425
+ `Create .claude/commands/[name].md?\n` +
426
+ `\`\`\`\n\n` +
293
427
  `### Rules\n` +
294
428
  `- If existing commands cover the same workflow: skip\n` +
295
- `- Commands should be specific to this project, not generic\n\n` +
429
+ `- Commands should be specific to this project, not generic\n` +
430
+ `- Adapt exact commands from actual project files — never hardcode\n` +
431
+ `- Never skip with a blanket "no workflows found" without scanning all sources above\n\n` +
296
432
  `### Output\n` +
297
433
  `Created: ✅ .claude/commands/[name].md — [what workflow and why useful]\n` +
298
- `Skipped: ⏭ commands — [why no project-specific workflows found]\n`,
434
+ `Skipped: ⏭ commands — scanned [list each source checked and result]. Nothing warranted.\n`,
299
435
  },
300
436
  // --- Step 6: .github/workflows/ ---
301
437
  {
@@ -321,9 +457,33 @@ export function buildAtomicSteps(collected, state) {
321
457
  `- NEVER create or modify workflows without explicit developer confirmation\n` +
322
458
  `- If existing workflows exist: do not touch them\n` +
323
459
  `- Secrets must use \`\${{ secrets.VARNAME }}\` syntax only\n`)
324
- : (`### .github/ does not exist\n` +
325
- `Do not create workflows. Print:\n` +
326
- `Skipped: ⏭ .github/workflows/ .github/ directory does not exist\n`)),
460
+ : (`### .github/ does not exist — scan for CI/CD evidence before skipping\n\n` +
461
+ `The absence of .github/ is an opportunity to suggest, not a reason to stop.\n\n` +
462
+ `Scan /stack-0-context for CI/CD evidence:\n` +
463
+ `- \`tests/\` or \`__tests__/\` or \`spec/\` directory → test pipeline candidate\n` +
464
+ `- \`Dockerfile\` or \`docker-compose.yml\` → build + deploy pipeline candidate\n` +
465
+ `- \`package.json\` with build/test/lint scripts → Node CI candidate\n` +
466
+ `- \`Makefile\` with test/build/deploy targets → generic CI candidate\n` +
467
+ `- \`pyproject.toml\` with test config → Python CI candidate\n` +
468
+ `- README references to "deploy", "release", "staging", "production"\n\n` +
469
+ `If evidence found, print EXACTLY:\n` +
470
+ `\`\`\`\n` +
471
+ `⚙️ WORKFLOW SUGGESTION — .github/ does not exist\n\n` +
472
+ `Evidence that CI/CD would be useful:\n` +
473
+ ` [list each piece of evidence and its source]\n\n` +
474
+ `I can set up:\n` +
475
+ ` 1. CI pipeline — run tests + build on every push\n` +
476
+ ` 2. Deploy pipeline — build image + push to registry on merge to main\n` +
477
+ ` 3. Both\n\n` +
478
+ `Two questions before I create anything:\n` +
479
+ ` 1. Which of the above? (1 / 2 / 3 / none)\n` +
480
+ ` 2. Is this connected to a remote GitHub repository? (yes / no)\n` +
481
+ `\`\`\`\n\n` +
482
+ `If user confirms: create .github/workflows/ with workflows based on actual project commands.\n` +
483
+ `All secrets must use \`\${{ secrets.VARNAME }}\` syntax — never hardcoded.\n` +
484
+ `After writing, flag every secret: \`⚠️ Add [VARNAME] to GitHub Settings → Secrets\`\n\n` +
485
+ `If NO evidence found:\n` +
486
+ `Skipped: ⏭ .github/workflows/ — scanned: no tests dir, no Dockerfile, no build/deploy scripts, no deployment references. Nothing to automate.\n`)),
327
487
  },
328
488
  ];
329
489
  return steps;
@@ -336,12 +496,12 @@ export function buildOrchestratorCommand(steps) {
336
496
  const stepList = runSteps
337
497
  .map((s, i) => `${i + 1}. /${s.filename.replace(".md", "")}`)
338
498
  .join("\n");
339
- return `<!-- claude-setup ${version} ${date} -->
340
-
341
- Run these in order. If one fails, fix and continue from that step.
342
-
343
- ${stepList}
344
-
345
- After all complete: one-line summary of what was created.
499
+ return `<!-- claude-setup ${version} ${date} -->
500
+
501
+ Run these in order. If one fails, fix and continue from that step.
502
+
503
+ ${stepList}
504
+
505
+ After all complete: one-line summary of what was created.
346
506
  `;
347
507
  }
@@ -4,7 +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 { c } from "../output.js";
7
+ import { estimateTokens, estimateCost } from "../tokens.js";
8
+ import { c, section } from "../output.js";
8
9
  function ensureDir(dir) {
9
10
  if (!existsSync(dir))
10
11
  mkdirSync(dir, { recursive: true });
@@ -46,8 +47,18 @@ capabilities that need documentation, MCP servers, skills, and hooks together.
46
47
  // add only needs config files — source files are irrelevant and waste tokens
47
48
  const collected = await collectProjectFiles(process.cwd(), "configOnly");
48
49
  const content = buildAddCommand(userInput, collected, state);
50
+ // Token tracking
51
+ const tokens = estimateTokens(content);
52
+ const cost = estimateCost(tokens);
49
53
  ensureDir(".claude/commands");
50
54
  writeFileSync(".claude/commands/stack-add.md", content, "utf8");
51
- await updateManifest("add", collected, { input: userInput });
52
- console.log(`\n${c.green("✅")} Ready. Open Claude Code and run:\n ${c.cyan("/stack-add")}\n`);
55
+ await updateManifest("add", collected, {
56
+ input: userInput,
57
+ estimatedTokens: tokens,
58
+ estimatedCost: cost,
59
+ });
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(`Opus $${cost.opus.toFixed(4)} | Sonnet $${cost.sonnet.toFixed(4)} | Haiku $${cost.haiku.toFixed(4)}`)})`);
63
+ console.log("");
53
64
  }
@@ -0,0 +1 @@
1
+ export declare function runCompare(): Promise<void>;