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 +113 -71
- package/dist/builder.js +202 -42
- package/dist/commands/add.js +14 -3
- package/dist/commands/compare.d.ts +1 -0
- package/dist/commands/compare.js +84 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/export.d.ts +25 -0
- package/dist/commands/export.js +289 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +45 -9
- package/dist/commands/remove.js +14 -3
- package/dist/commands/restore.d.ts +1 -0
- package/dist/commands/restore.js +61 -0
- package/dist/commands/status.js +189 -16
- package/dist/commands/sync.d.ts +1 -0
- package/dist/commands/sync.js +100 -10
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +355 -46
- package/dist/index.js +28 -3
- package/dist/manifest.d.ts +12 -0
- package/dist/manifest.js +14 -0
- package/dist/marketplace.d.ts +21 -0
- package/dist/marketplace.js +159 -0
- package/dist/os.d.ts +6 -1
- package/dist/os.js +22 -3
- package/dist/snapshot.d.ts +71 -0
- package/dist/snapshot.js +195 -0
- package/dist/state.js +5 -1
- package/dist/tokens.d.ts +58 -0
- package/dist/tokens.js +132 -0
- package/package.json +49 -49
- package/templates/add.md +122 -3
- package/templates/init-empty.md +58 -1
- package/templates/init.md +53 -16
- package/templates/remove.md +48 -2
- package/templates/sync.md +20 -1
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.
|
|
5
|
+
**The CLI has zero intelligence.** All reasoning is delegated to Claude Code via the command files.
|
|
6
6
|
|
|
7
|
-
## Install
|
|
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
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
22
|
-
| `
|
|
23
|
-
| `
|
|
24
|
-
| `
|
|
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
|
|
30
|
-
npx claude-setup
|
|
31
|
-
npx claude-setup
|
|
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
|
|
37
|
-
2. **CLI writes
|
|
38
|
-
3. **Claude Code executes** — you run `/stack-init
|
|
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
|
-
##
|
|
47
|
+
## What it creates
|
|
41
48
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
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": [
|
|
97
|
-
"sourceDirs": [
|
|
154
|
+
"extraBlockedDirs": [],
|
|
155
|
+
"sourceDirs": []
|
|
98
156
|
}
|
|
99
157
|
```
|
|
100
158
|
|
|
101
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
`###
|
|
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
|
-
?
|
|
249
|
-
:
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
|
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
|
|
346
|
+
`Create a skill if:\n` +
|
|
268
347
|
`- A recurring multi-step project-specific pattern exists in /stack-0-context\n` +
|
|
269
|
-
`-
|
|
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 \`
|
|
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
|
|
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
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
`-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
|
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 — [
|
|
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
|
-
`
|
|
326
|
-
`
|
|
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
|
}
|
package/dist/commands/add.js
CHANGED
|
@@ -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 {
|
|
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, {
|
|
52
|
-
|
|
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>;
|