claude-setup 1.1.3 → 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 +111 -46
- package/dist/builder.js +94 -29
- 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 +71 -8
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +307 -59
- package/dist/index.js +28 -3
- package/dist/manifest.d.ts +12 -0
- package/dist/manifest.js +2 -0
- package/dist/marketplace.d.ts +21 -0
- package/dist/marketplace.js +159 -0
- package/dist/os.js +5 -0
- package/dist/snapshot.d.ts +71 -0
- package/dist/snapshot.js +195 -0
- 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 +27 -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,47 +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
|
|
74
|
+
|
|
75
|
+
Save your setup and reuse it across projects.
|
|
47
76
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
|
54
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
|
+
```
|
|
55
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
|
+
```
|
|
56
137
|
|
|
57
138
|
## Configuration
|
|
58
139
|
|
|
59
|
-
|
|
140
|
+
Auto-generated on first run. Edit `.claude-setup.json` to customize:
|
|
60
141
|
|
|
61
142
|
```json
|
|
62
143
|
{
|
|
@@ -70,27 +151,11 @@ Create `.claude-setup.json` in your project root to customize:
|
|
|
70
151
|
"remove": 2000
|
|
71
152
|
},
|
|
72
153
|
"digestMode": true,
|
|
73
|
-
"extraBlockedDirs": [
|
|
74
|
-
"sourceDirs": [
|
|
154
|
+
"extraBlockedDirs": [],
|
|
155
|
+
"sourceDirs": []
|
|
75
156
|
}
|
|
76
157
|
```
|
|
77
158
|
|
|
78
|
-
##
|
|
79
|
-
|
|
80
|
-
When `digestMode` is enabled (default), the CLI extracts compact signal instead of dumping raw file content:
|
|
81
|
-
|
|
82
|
-
- **Config files found** — just names, not content
|
|
83
|
-
- **Dependencies** — extracted from any package manifest
|
|
84
|
-
- **Scripts** — available commands/tasks
|
|
85
|
-
- **Env vars** — names from `.env.example`
|
|
86
|
-
- **Directory tree** — compact structure (3 levels deep)
|
|
87
|
-
- **Source signatures** — imports, exports, declarations (not full content)
|
|
88
|
-
|
|
89
|
-
## OS detection
|
|
90
|
-
|
|
91
|
-
The CLI detects your OS and ensures command files tell Claude Code to use the correct format:
|
|
92
|
-
|
|
93
|
-
- **Windows**: `{ "command": "cmd", "args": ["/c", "npx", "<package>"] }`
|
|
94
|
-
- **macOS/Linux**: `{ "command": "npx", "args": ["<package>"] }`
|
|
159
|
+
## License
|
|
95
160
|
|
|
96
|
-
|
|
161
|
+
MIT
|
package/dist/builder.js
CHANGED
|
@@ -3,6 +3,7 @@ import { join, dirname } from "path";
|
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
4
|
import { loadConfig } from "./config.js";
|
|
5
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,11 +224,13 @@ 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` +
|
|
223
235
|
`### Verified MCP package names — ONLY use these\n` +
|
|
224
236
|
`\`\`\`\n` +
|
|
@@ -273,21 +285,53 @@ export function buildAtomicSteps(collected, state) {
|
|
|
273
285
|
`### When to create/update\n` +
|
|
274
286
|
`Add a hook ONLY if it runs on a pattern that repeats every session AND the cost is justified.\n` +
|
|
275
287
|
`Every hook adds overhead on every Claude Code action. Only add if clearly earned.\n\n` +
|
|
276
|
-
`###
|
|
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` +
|
|
277
322
|
(os === "Windows"
|
|
278
|
-
?
|
|
279
|
-
:
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
`If unsure which event name to use: do not write the hook. Print:\n` +
|
|
285
|
-
`\`SKIPPED — hook event name uncertain. Valid names: PreToolUse, PostToolUse, PostToolUseFailure, Stop, SessionStart\`\n\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` +
|
|
286
329
|
`### Rules\n` +
|
|
287
330
|
`- **NEVER write a "model" key into settings.json** — it overrides the user's model selection silently\n` +
|
|
288
331
|
`- If it exists above: audit quoting of existing hooks first, fix broken ones\n` +
|
|
289
332
|
`- Only add hooks for patterns that genuinely recur for this project type\n` +
|
|
290
|
-
`- 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` +
|
|
291
335
|
`### Output\n` +
|
|
292
336
|
`Created/Updated: ✅ settings.json — [hook name and justification]\n` +
|
|
293
337
|
`Skipped: ⏭ settings.json — [why no hooks warranted]\n`,
|
|
@@ -299,16 +343,37 @@ export function buildAtomicSteps(collected, state) {
|
|
|
299
343
|
`## Target: .claude/skills/\n` +
|
|
300
344
|
`Installed: ${vars.SKILLS_LIST}\n\n` +
|
|
301
345
|
`### When to create\n` +
|
|
302
|
-
`Create a skill
|
|
346
|
+
`Create a skill if:\n` +
|
|
303
347
|
`- A recurring multi-step project-specific pattern exists in /stack-0-context\n` +
|
|
304
|
-
`-
|
|
348
|
+
`- The project type has standard workflows worth automating (build, deploy, test patterns)\n` +
|
|
305
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` +
|
|
306
370
|
`### Rules\n` +
|
|
307
|
-
`- Use \`
|
|
371
|
+
`- Use \`description:\` frontmatter so Claude knows when to load the skill\n` +
|
|
308
372
|
`- If a similar skill already exists above: extend it, don't create a parallel one\n` +
|
|
309
|
-
`- 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` +
|
|
310
375
|
`### Output\n` +
|
|
311
|
-
`Created: ✅ .claude/skills/[name] — [what pattern it captures]\n` +
|
|
376
|
+
`Created: ✅ .claude/skills/[name]/SKILL.md — [what pattern it captures]\n` +
|
|
312
377
|
`Skipped: ⏭ skills — checked [patterns], found [nothing project-specific]\n`,
|
|
313
378
|
},
|
|
314
379
|
// --- Step 5: .claude/commands/ ---
|
|
@@ -431,12 +496,12 @@ export function buildOrchestratorCommand(steps) {
|
|
|
431
496
|
const stepList = runSteps
|
|
432
497
|
.map((s, i) => `${i + 1}. /${s.filename.replace(".md", "")}`)
|
|
433
498
|
.join("\n");
|
|
434
|
-
return `<!-- claude-setup ${version} ${date} -->
|
|
435
|
-
|
|
436
|
-
Run these in order. If one fails, fix and continue from that step.
|
|
437
|
-
|
|
438
|
-
${stepList}
|
|
439
|
-
|
|
440
|
-
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.
|
|
441
506
|
`;
|
|
442
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>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { readTimeline, compareSnapshots } from "../snapshot.js";
|
|
2
|
+
import { c, section } from "../output.js";
|
|
3
|
+
import { createInterface } from "readline";
|
|
4
|
+
async function promptFreeText(question) {
|
|
5
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
rl.question(question + " ", (answer) => {
|
|
8
|
+
rl.close();
|
|
9
|
+
resolve(answer.trim());
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
export async function runCompare() {
|
|
14
|
+
const cwd = process.cwd();
|
|
15
|
+
const timeline = readTimeline(cwd);
|
|
16
|
+
if (timeline.nodes.length < 2) {
|
|
17
|
+
console.log(`${c.yellow("⚠️")} Need at least 2 snapshots to compare. ` +
|
|
18
|
+
`Run ${c.cyan("npx claude-setup sync")} to create more.`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
// Display available nodes
|
|
22
|
+
section("Available snapshots");
|
|
23
|
+
console.log("");
|
|
24
|
+
for (let i = 0; i < timeline.nodes.length; i++) {
|
|
25
|
+
const node = timeline.nodes[i];
|
|
26
|
+
const date = new Date(node.timestamp).toLocaleString();
|
|
27
|
+
const inputStr = node.input ? ` "${node.input}"` : "";
|
|
28
|
+
console.log(` ${c.cyan(node.id)} ${node.command}${inputStr} ${c.dim(date)} ${node.summary}`);
|
|
29
|
+
}
|
|
30
|
+
console.log("");
|
|
31
|
+
const idA = await promptFreeText("Enter first snapshot ID (older):");
|
|
32
|
+
if (!idA) {
|
|
33
|
+
console.log("No input provided.");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const idB = await promptFreeText("Enter second snapshot ID (newer):");
|
|
37
|
+
if (!idB) {
|
|
38
|
+
console.log("No input provided.");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const nodeA = timeline.nodes.find(n => n.id === idA);
|
|
42
|
+
const nodeB = timeline.nodes.find(n => n.id === idB);
|
|
43
|
+
if (!nodeA) {
|
|
44
|
+
console.log(`${c.red("🔴")} Snapshot "${idA}" not found.`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (!nodeB) {
|
|
48
|
+
console.log(`${c.red("🔴")} Snapshot "${idB}" not found.`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
console.log(`\nComparing ${c.cyan(idA)} → ${c.cyan(idB)}...\n`);
|
|
52
|
+
const result = compareSnapshots(cwd, idA, idB);
|
|
53
|
+
if (result.onlyInA.length) {
|
|
54
|
+
section(`Only in ${idA} (removed after)`);
|
|
55
|
+
for (const f of result.onlyInA) {
|
|
56
|
+
console.log(` ${c.red("-")} ${f}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (result.onlyInB.length) {
|
|
60
|
+
section(`Only in ${idB} (added after)`);
|
|
61
|
+
for (const f of result.onlyInB) {
|
|
62
|
+
console.log(` ${c.green("+")} ${f}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (result.changed.length) {
|
|
66
|
+
section("Changed between snapshots");
|
|
67
|
+
for (const f of result.changed) {
|
|
68
|
+
console.log(` ${c.yellow("~")} ${f.path} (${f.linesA} → ${f.linesB} lines)`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (result.identical.length) {
|
|
72
|
+
console.log(`\n ${c.dim(`${result.identical.length} file(s) identical between snapshots`)}`);
|
|
73
|
+
}
|
|
74
|
+
const totalDiffs = result.onlyInA.length + result.onlyInB.length + result.changed.length;
|
|
75
|
+
if (totalDiffs === 0) {
|
|
76
|
+
console.log(`\n${c.green("✅")} Snapshots are identical — no differences found.`);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
console.log(`\n${c.bold(`${totalDiffs} difference(s)`)} between ${c.cyan(idA)} and ${c.cyan(idB)}.`);
|
|
80
|
+
if (result.changed.length) {
|
|
81
|
+
console.log(`${c.dim("Use")} ${c.cyan("npx claude-setup restore")} ${c.dim("to jump to either snapshot.")}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface ConfigTemplate {
|
|
2
|
+
name: string;
|
|
3
|
+
version: "1";
|
|
4
|
+
exportedAt: string;
|
|
5
|
+
exportedFrom: string;
|
|
6
|
+
os: string;
|
|
7
|
+
claudeMd?: string;
|
|
8
|
+
mcpJson?: Record<string, unknown>;
|
|
9
|
+
settings?: Record<string, unknown>;
|
|
10
|
+
skills: Array<{
|
|
11
|
+
name: string;
|
|
12
|
+
content: string;
|
|
13
|
+
}>;
|
|
14
|
+
commands: Array<{
|
|
15
|
+
name: string;
|
|
16
|
+
content: string;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
export declare function runExport(): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Apply a template to the current project.
|
|
22
|
+
* Merge logic: existing content kept, new content added.
|
|
23
|
+
* OS adaptation: MCP commands auto-converted for target OS.
|
|
24
|
+
*/
|
|
25
|
+
export declare function applyTemplate(templateSource: string): Promise<void>;
|