vibe-splain 3.4.2 → 4.0.0

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.
Files changed (87) hide show
  1. package/README.md +110 -158
  2. package/dist/commands/install.d.ts +0 -5
  3. package/dist/commands/install.js +5 -55
  4. package/dist/commands/serve.js +1 -1
  5. package/dist/export/ArtifactBundleWriter.js +3 -3
  6. package/dist/export/ExportOrchestrator.d.ts +2 -20
  7. package/dist/export/ExportOrchestrator.js +5 -116
  8. package/dist/export/Watcher.js +5 -5
  9. package/dist/export/renderers/AgentMarkdownRenderer.d.ts +1 -1
  10. package/dist/export/renderers/GraphRenderer.d.ts +2 -2
  11. package/dist/export/renderers/HtmlRenderer.d.ts +1 -1
  12. package/dist/export/renderers/HtmlRenderer.js +1 -1
  13. package/dist/export/renderers/JsonRenderer.d.ts +1 -1
  14. package/dist/export/renderers/RawAnalysisRenderer.d.ts +1 -1
  15. package/dist/export/renderers/Renderer.d.ts +1 -1
  16. package/dist/export/renderers/ValidationRenderer.d.ts +1 -1
  17. package/dist/index.js +1425 -6511
  18. package/dist/mcp/server.js +6 -46
  19. package/dist/mcp/tools/get_file_context.js +1 -1
  20. package/dist/mcp/tools/get_project_map.js +1 -1
  21. package/dist/mcp/tools/get_strategic_overview.js +1 -1
  22. package/dist/mcp/tools/get_wild_discoveries.js +1 -1
  23. package/dist/mcp/tools/inspect_pillar.js +1 -1
  24. package/dist/mcp/tools/mark_stale.js +1 -1
  25. package/dist/mcp/tools/scan_project.d.ts +2 -3
  26. package/dist/mcp/tools/scan_project.js +12 -13
  27. package/dist/mcp/tools/set_project_brief.js +1 -1
  28. package/dist/mcp/tools/write_decision_card.d.ts +1 -1
  29. package/dist/mcp/tools/write_decision_card.js +2 -2
  30. package/dist/ui/index.html +1 -1
  31. package/package.json +9 -14
  32. package/dist/commands/bundle.d.ts +0 -4
  33. package/dist/commands/bundle.js +0 -68
  34. package/dist/commands/export.d.ts +0 -1
  35. package/dist/commands/export.js +0 -19
  36. package/dist/commands/gc.d.ts +0 -3
  37. package/dist/commands/gc.js +0 -59
  38. package/dist/commands/hook.d.ts +0 -9
  39. package/dist/commands/hook.js +0 -84
  40. package/dist/commands/importBundle.d.ts +0 -4
  41. package/dist/commands/importBundle.js +0 -80
  42. package/dist/commands/network.d.ts +0 -1
  43. package/dist/commands/network.js +0 -91
  44. package/dist/commands/scan.d.ts +0 -13
  45. package/dist/commands/scan.js +0 -97
  46. package/dist/export/renderers/DeltaRenderer.d.ts +0 -6
  47. package/dist/export/renderers/DeltaRenderer.js +0 -22
  48. package/dist/hook/preToolUse.d.ts +0 -30
  49. package/dist/hook/preToolUse.js +0 -81
  50. package/dist/hook-entry.d.ts +0 -2
  51. package/dist/hook-entry.js +0 -8
  52. package/dist/hook.d.ts +0 -1
  53. package/dist/hook.js +0 -337
  54. package/dist/mcp/BudgetGuard.d.ts +0 -13
  55. package/dist/mcp/BudgetGuard.js +0 -55
  56. package/dist/mcp/SessionScope.d.ts +0 -26
  57. package/dist/mcp/SessionScope.js +0 -56
  58. package/dist/mcp/tools/apply_patch.d.ts +0 -37
  59. package/dist/mcp/tools/apply_patch.js +0 -103
  60. package/dist/mcp/tools/explainSpecialistScope.d.ts +0 -15
  61. package/dist/mcp/tools/explainSpecialistScope.js +0 -30
  62. package/dist/mcp/tools/get_call_chain.d.ts +0 -42
  63. package/dist/mcp/tools/get_call_chain.js +0 -50
  64. package/dist/mcp/tools/get_file_skeleton.d.ts +0 -23
  65. package/dist/mcp/tools/get_file_skeleton.js +0 -124
  66. package/dist/mcp/tools/hydration/get_evidence_slice.d.ts +0 -31
  67. package/dist/mcp/tools/hydration/get_evidence_slice.js +0 -57
  68. package/dist/mcp/tools/hydration/get_project_summary.d.ts +0 -23
  69. package/dist/mcp/tools/hydration/get_project_summary.js +0 -58
  70. package/dist/mcp/tools/hydration/get_start_here.d.ts +0 -23
  71. package/dist/mcp/tools/hydration/get_start_here.js +0 -52
  72. package/dist/mcp/tools/prepareTaskContext.d.ts +0 -38
  73. package/dist/mcp/tools/prepareTaskContext.js +0 -93
  74. package/dist/mcp/tools/read_file.d.ts +0 -31
  75. package/dist/mcp/tools/read_file.js +0 -90
  76. package/dist/mcp/tools/set_session_scope.d.ts +0 -19
  77. package/dist/mcp/tools/set_session_scope.js +0 -40
  78. package/dist/mcp/tools/submit_receipt.d.ts +0 -68
  79. package/dist/mcp/tools/submit_receipt.js +0 -94
  80. package/dist/mcp/tools/work_orders.d.ts +0 -79
  81. package/dist/mcp/tools/work_orders.js +0 -126
  82. package/dist/mcp/tools/yield_for_scope_expansion.d.ts +0 -29
  83. package/dist/mcp/tools/yield_for_scope_expansion.js +0 -59
  84. package/dist/store/BlobStore.d.ts +0 -22
  85. package/dist/store/BlobStore.js +0 -96
  86. package/dist/store/PointerStore.d.ts +0 -52
  87. package/dist/store/PointerStore.js +0 -154
package/README.md CHANGED
@@ -1,26 +1,25 @@
1
1
  <p align="center">
2
- <strong>◈ vibe-splain</strong>
3
- <br />
4
- <em>Map architectural DNA and behavioral call-chains in complex codebases.</em>
2
+ <strong>◈ vibesplain</strong><br/>
3
+ <em>Give your AI agent an architectural map of any codebase.</em>
5
4
  </p>
6
5
 
7
6
  <p align="center">
8
7
  <a href="#install">Install</a> ·
9
- <a href="#how-it-works">How It Works</a> ·
8
+ <a href="#usage">Usage</a> ·
10
9
  <a href="#mcp-tools">MCP Tools</a> ·
11
- <a href="#dossier-ui">Dossier UI</a> ·
10
+ <a href="#how-it-works">How It Works</a> ·
12
11
  <a href="#development">Development</a>
13
12
  </p>
14
13
 
15
14
  ---
16
15
 
17
- vibe-splain is a high-fidelity **static analysis engine** and MCP server. It uses [Tree-Sitter](https://tree-sitter.github.io/tree-sitter/) to extract the structural and behavioral patterns of a codebaseidentifying high-gravity components, mapping semantic actions, and tracing call-chains between entrypoints and side effects.
16
+ **vibesplain** is an MCP server that scans a codebase with Tree-Sitter, scores every file by importance and complexity, and produces an **Architectural Dossier** a structured set of decision cards your agent writes after analyzing the code.
18
17
 
19
- While vibe-splain is built on a language-agnostic foundation, the current toolset is **highly optimized for TypeScript and JavaScript** (especially Next.js, Prisma, and tRPC environments).
18
+ The output is a self-contained HTML file you can open in any browser.
20
19
 
21
- **Zero LLM calls. Zero API keys. Pure static analysis.**
20
+ **Zero LLM calls. Zero API keys. Zero network. Pure static analysis.**
22
21
 
23
- Your coding agent does all the thinking — vibe-splain just gives it the right data.
22
+ ---
24
23
 
25
24
  ## Install
26
25
 
@@ -28,215 +27,168 @@ Your coding agent does all the thinking — vibe-splain just gives it the right
28
27
  npx vibe-splain install
29
28
  ```
30
29
 
31
- That's it. This patches your coding agent's MCP config so it can call vibe-splain's tools. Restart your agent.
32
-
33
- ### Running the Analysis
34
-
35
- You don't need to write a complex prompt. vibe-splain provides a built-in MCP Prompt called `build_dossier` that automatically tells your agent exactly what to do.
36
-
37
- **In Claude Code / Gemini CLI:**
38
- Type `/prompt build_dossier` and press enter.
30
+ This patches your coding agent's config to register vibesplain as an MCP server. Restart your agent afterward.
39
31
 
40
- **In Cursor / Windsurf:**
41
- Open the MCP panel or agent chat, select the `build_dossier` prompt from the vibe-splain server, and run it.
42
-
43
- Your agent will loop through the high-gravity files, analyze each one, and build an **Architectural Dossier** — a structured set of **Decision Cards** explaining the technical rationale of the code.
44
-
45
- ### Supported Agents
46
-
47
- | Agent | Config File |
48
- |-------|------------|
49
- | Claude Code | `~/.claude/claude_desktop_config.json` |
32
+ | Agent | Config patched |
33
+ |-------|---------------|
34
+ | Claude Code | `~/.claude/settings.json` |
35
+ | Claude Desktop | `~/.claude/claude_desktop_config.json` |
50
36
  | Gemini CLI | `~/.gemini/settings.json` |
51
37
  | Cursor | `~/.cursor/mcp.json` |
52
38
  | Windsurf | `~/.codeium/windsurf/mcp_config.json` |
53
39
 
54
- ## How It Works
40
+ ---
41
+
42
+ ## Usage
55
43
 
44
+ Once installed, open a project in your agent and run the built-in prompt:
45
+
46
+ **Claude Code / Gemini CLI:**
56
47
  ```
57
- ┌─────────────────────────────────────────────────────────┐
58
- │ Your Coding Agent (Claude / Gemini / Cursor) │
59
- │ │
60
- │ "Scan this project" ──► scan_project ──► get_file_ctx │
61
- │ │ │ │
62
- │ Agent synthesizes ◄──────┘ ◄──────────────┘ │
63
- │ narratives + diagrams │
64
- │ │ │
65
- │ ▼ │
66
- │ write_decision_card ──► .vibe-splainer/dossier.json │
67
- │ │ │
68
- │ ▼ │
69
- │ file:// Dossier UI │
70
- └─────────────────────────────────────────────────────────┘
48
+ /prompt build_dossier
71
49
  ```
72
50
 
73
- ### Three Levels of Analysis
74
- 1. **Level 0 — Semantic Classification**: Maps files to architectural "pillars" (Auth, Payments, Database, etc.) using import-path heuristics and library signatures.
75
- 2. **Level 1 — Structural and Behavioral Gravity**: Core computes `staticGravity` using Tree-Sitter AST analysis based on link density, nesting depth, and mutation counts. **Bundled Adapters** (like Cal.com and n8n) interpret product semantics to add `behavioralLift` for critical dynamic execution paths. Final `gravity` is the combination of static evidence and adapter interpretation.
76
- 3. **Level 2 — Behavioral Traceability**: Tree-Sitter powered call-graph analysis. It maps function-level dependencies and identifies **Critical Functions** (entrypoints, semantic actions, or high-outbound callers).
51
+ **Cursor / Windsurf:** Select the `build_dossier` prompt from the vibesplain MCP panel.
77
52
 
78
- ### Claude Code PreToolUse Hook
53
+ Your agent will:
54
+ 1. Scan the project and rank files by architectural importance
55
+ 2. Read each high-importance file in depth
56
+ 3. Write a **Decision Card** for each — thesis, blast radius, evidence, optional diagram
57
+ 4. Return a `file://` link to the Dossier UI
79
58
 
80
- `vibe-splain` integrates directly with Claude Code's hook system to prevent AI agents from accidentally breaking your codebase:
59
+ Open the link. Done.
81
60
 
82
- - **Ultra-Fast Local Gating**: Installs a standalone entrypoint (`dist/hook.js`) that runs in **< 15ms** with zero network calls, avoiding heavy WASM/tree-sitter load overhead.
83
- - **Hybrid Blast-Radius Logic**: Combines static gravity and substance-based direct dependents to protect important files (e.g. dynamically-loaded execution nodes or central utility modules) even if they lack standard entrypoints.
84
- - **Developer Friction Suppression**: Automatically demotes generated, minified, or vendored files to a `low` blast-radius, ensuring the agent is never blocked when editing build targets or lockfiles.
85
- - **Warn-Once session behavior**: If `.vibe-splainer/gate.json` is missing, the hook notifies you exactly once per session to run a project scan, then gracefully gets out of the way.
61
+ ---
86
62
 
87
63
  ## MCP Tools
88
64
 
89
- vibe-splain exposes **8 tools** over MCP stdio:
65
+ The `build_dossier` prompt orchestrates these tools automatically. You can also call them manually.
66
+
67
+ | Tool | What it does |
68
+ |------|-------------|
69
+ | `scan_project` | Scans the repo. Returns ranked files grouped by architectural pillar. Call this first. |
70
+ | `get_project_map` | Returns the pillar map, top-gravity files, and wild-discovery candidates. |
71
+ | `set_project_brief` | Stores a 3–5 sentence project summary. Write this before any decision cards. |
72
+ | `get_file_context` | Returns full source + import graph + hot spans for a specific file. |
73
+ | `write_decision_card` | Persists a decision card (thesis, category, evidence, optional Mermaid diagram). |
74
+ | `get_strategic_overview` | Returns dossier state without evidence snippets — useful for quick status checks. |
75
+ | `inspect_pillar` | Returns all decision cards for a given architectural pillar. |
76
+ | `get_wild_discoveries` | Returns the highest-complexity files that don't fit standard patterns. |
77
+ | `mark_stale` | Marks a file's decision card as stale after you edit it. |
90
78
 
91
- | Tool | Purpose |
92
- |------|---------|
93
- | `scan_project` | **Call first.** Scans the codebase, returns high-gravity files grouped by pillar. Starts file watcher. |
94
- | `get_file_context` | Returns full source + import graph neighbors for a specific file. |
95
- | `write_decision_card` | Persists a Decision Card (narrative + evidence + optional Mermaid diagram). |
96
- | `get_strategic_overview` | Returns dossier state without evidence snippets (saves tokens). |
97
- | `inspect_pillar` | Returns all Decision Cards for a pillar with full evidence. |
98
- | `get_wild_discoveries` | Returns the most complex files that don't fit standard patterns. |
99
- | `mark_stale` | Marks cards as stale when you modify files during a session. |
79
+ ---
80
+
81
+ ## How It Works
100
82
 
101
- ### Recommended Agent Workflow
83
+ vibesplain runs a deterministic static analysis pipeline — no model calls, no network:
102
84
 
103
85
  ```
104
- 1. scan_project → get high-gravity files
105
- 2. For each file: get_file_context → read source + neighbors
106
- 3. Synthesize: "WHY does this code exist?"
107
- 5. write_decision_card → persist the narrative
108
- 6. Share the file:// UI link with the user
86
+ Your project
87
+
88
+
89
+ Tree-Sitter AST parsing
90
+
91
+ ├── Gravity score (0–100)
92
+ │ PageRank centrality × fan-in × cyclomatic complexity
93
+ │ × public surface × nesting depth
94
+
95
+ ├── Heat score (0–100)
96
+ │ Smell density: swallowed catches, deep nesting,
97
+ │ long functions, god files, magic numbers
98
+
99
+ └── Pillar detection
100
+ Auth / Database / Payments / Queue /
101
+ Storage / Config / Email / Realtime / Logic
102
+
103
+
104
+ .vibesplain/
105
+ ├── dossier.json ← agent writes decision cards here
106
+ ├── analysis.json ← raw scored file store
107
+ ├── graph.json ← import graph
108
+ └── ui/index.html ← self-contained dossier viewer
109
109
  ```
110
110
 
111
- ## How It Works
111
+ **Top 12 by gravity** = Start Here (the load-bearing hubs).
112
+ **Top 12 by heat** = Wild Discoveries (the most complex / smelly files).
112
113
 
113
- ### Deep Analysis Pipeline
114
- Unlike simple regex scanners, vibe-splain runs a deterministic **13-stage pipeline**—from AST inventory and alias resolution to semantic classification and function-level scoring—to ensure every Decision Card is grounded in actual code paths.
114
+ The UI is a single self-contained HTML file. Open it with `file://` — no server needed.
115
115
 
116
- ### Semantic Rulesets
117
- vibe-splain uses specialized rulesets to understand framework-specific semantics. Current optimizations include:
118
- - **Next.js**: Server Actions, `cookies()`, `headers()`, and App Router conventions.
119
- - **Database**: Prisma model mutations and raw query patterns.
120
- - **API**: tRPC procedure calls (`mutate`/`query`) and standard `fetch`/`axios` patterns.
121
- - **Auth**: Clerk, NextAuth, and custom rate-limiting/validation logic.
116
+ ---
122
117
 
123
118
  ## Dossier UI
124
119
 
125
- After your agent writes Decision Cards, open the generated file in your browser:
120
+ After your agent writes decision cards, open the generated file:
126
121
 
127
122
  ```
128
- file:///path/to/your/project/.vibe-splainer/ui/index.html
123
+ file:///path/to/your/project/.vibesplain/ui/index.html
129
124
  ```
130
125
 
131
- The UI features:
132
- - **Dark theme** with glassmorphism and subtle grid texture
133
- - **Pillar tabs** for navigating architectural areas
134
- - **Decision Cards** with fresh/stale status badges
135
- - **Mermaid diagrams** rendered inline as SVG
136
- - **Evidence sidebar** with Shiki syntax highlighting (tokyo-night)
137
- - **Wild Discoveries** tab for the most complex outlier files
138
- - Works entirely offline via `file://` — no server needed
126
+ Features:
127
+ - Pillar tabs to navigate architectural areas
128
+ - Decision cards with fresh/stale status
129
+ - Mermaid diagrams rendered inline
130
+ - Syntax-highlighted evidence snippets
131
+ - Works fully offline from `file://`
132
+
133
+ ---
139
134
 
140
135
  ## Architecture
141
136
 
142
137
  ```
143
138
  packages/
144
- ├── brain/ # @vibe-splain/brain — repo-agnostic analysis core + bundled adapters
139
+ ├── brain/ # @vibesplain/brain — pure static analysis, no I/O side effects
145
140
  │ └── src/
146
- │ ├── pipeline/
147
- │ │ └── adapters/ # Bundled product adapters (Cal.com, n8n)
148
- │ ├── scanner.ts # Tree-Sitter AST analysis (static analysis, graph building)
149
- │ ├── dossier.ts # Atomic persistence + UI regeneration
150
- │ ├── graph.ts # Import graph read/write
151
- │ └── watcher.ts # Chokidar file watcher
152
- ├── cli/ # vibe-splain — MCP server + CLI
141
+ │ ├── pipeline/ # 13-stage analysis pipeline
142
+ │ │ └── adapters/ # Optional domain-adapter extension point (none bundled)
143
+ │ ├── scanner.ts # Tree-Sitter AST + gravity/heat scoring
144
+ │ ├── dossier.ts # Atomic dossier persistence + UI injection
145
+ │ ├── analysis.ts # Scored file store + validation report
146
+ │ └── graph.ts # Import graph read/write
147
+
148
+ ├── cli/ # vibesplain — MCP server + CLI (the published npm package)
153
149
  │ └── src/
154
- │ ├── index.ts # #!/usr/bin/env node entry
150
+ │ ├── index.ts # CLI entrypoint
155
151
  │ ├── commands/
156
- │ │ ├── install.ts # Agent config patcher
157
- │ │ └── serve.ts # MCP server launcher
152
+ │ │ ├── install.ts # Patches agent MCP configs
153
+ │ │ └── serve.ts # Starts the MCP server
154
+ │ ├── export/ # Artifact writing (HTML, Markdown, JSON)
158
155
  │ └── mcp/
159
- │ ├── server.ts # @modelcontextprotocol/sdk setup
160
- │ └── tools/ # 7 tool handlers
161
- └── ui/ # @vibe-splain/ui — React dossier viewer
162
- └── src/
163
- ├── App.tsx # Main app (reads window.__VIBE_DOSSIER__)
164
- ├── components/ # Header, PillarTabs, DecisionCard, etc.
165
- └── index.css # Design system
156
+ │ ├── server.ts # MCP tool registration
157
+ │ └── tools/ # One file per tool
158
+
159
+ └── ui/ # @vibesplain/ui — React dossier viewer (embedded into cli at build time)
166
160
  ```
167
161
 
168
- ### Key Design Decisions
162
+ **Build order:** `brain` → `cli` → `ui` → `bundle-ui` (copies `ui/dist/` into `cli/dist/ui/`).
163
+ Only the `cli` package is published to npm.
169
164
 
170
- - **No LLM calls**: vibe-splain is a pure static analysis tool. The coding agent provides all synthesis.
171
- - **`async-mutex`**: All dossier writes are guarded by a mutex with atomic tmp+rename.
172
- - **`startOnLoad: false`**: Mermaid is initialized manually — never auto-scans the DOM.
173
- - **`base: './'`**: Vite builds with relative paths so the UI works from `file://` URLs.
174
- - **`console.log` banned**: Brain and CLI use only `console.error` to avoid corrupting MCP stdio.
175
- - **Tree-Sitter WASM**: Loaded from the `tree-sitter-wasms` npm package — no network calls.
165
+ ---
176
166
 
177
167
  ## Development
178
168
 
179
- ### Prerequisites
180
-
181
- - Node.js ≥ 18
182
- - npm ≥ 9 (for workspaces)
183
-
184
- ### Setup
185
-
186
169
  ```bash
187
- git clone https://github.com/abp2204/vibe-splain.git
188
- cd vibe-splain
170
+ git clone https://github.com/abp2204/vibesplain.git
171
+ cd vibesplain
189
172
  npm install
173
+ npm run build # full build
174
+ npm run dev:ui # Vite dev server for the UI
175
+ npm run test:regression
190
176
  ```
191
177
 
192
- ### Build
193
-
194
- ```bash
195
- npm run build
196
- ```
197
-
198
- This runs in sequence: brain → cli → ui → bundle-ui (copies UI dist into CLI dist).
199
-
200
- ### Dev UI
201
-
202
- ```bash
203
- npm run dev:ui
204
- ```
205
-
206
- Starts the Vite dev server for the UI package at `http://localhost:5173`.
207
-
208
- ### Test Install Locally
178
+ Test locally after build:
209
179
 
210
180
  ```bash
211
181
  node packages/cli/dist/index.js install
212
- ```
213
-
214
- ### Test MCP Server
215
-
216
- ```bash
217
182
  node packages/cli/dist/index.js serve
218
183
  ```
219
184
 
220
- Then send JSON-RPC messages over stdin (see [MCP specification](https://modelcontextprotocol.io)).
221
-
222
- ### Publish
185
+ Publish:
223
186
 
224
187
  ```bash
225
188
  npm run release
226
189
  ```
227
190
 
228
- Builds everything and publishes the `vibe-splain` CLI package to npm.
229
-
230
- ## How the Dossier Stays Fresh
231
-
232
- When `scan_project` runs, it starts a [Chokidar](https://github.com/paulmillr/chokidar) file watcher. When source files change:
233
-
234
- 1. The watcher detects the change
235
- 2. Matching Decision Cards are marked **stale** (amber badge in UI)
236
- 3. The `stalePaths` array in the dossier tracks which files need re-analysis
237
- 4. Your agent can call `get_strategic_overview` to see what's stale, then re-scan
238
-
239
- You can also manually mark files stale with `mark_stale` if you modify code during a session.
191
+ ---
240
192
 
241
193
  ## License
242
194
 
@@ -1,6 +1 @@
1
- /**
2
- * Idempotently register the vibe-splain PreToolUse hook in a Claude Code settings object.
3
- * Pure: takes a config, returns the same object mutated. Safe to run repeatedly.
4
- */
5
- export declare function addPreToolUseHook(config: Record<string, any>, hookPath?: string): Record<string, any>;
6
1
  export declare function installCommand(): Promise<void>;
@@ -1,8 +1,7 @@
1
1
  import { readFile, writeFile } from 'fs/promises';
2
2
  import { existsSync } from 'fs';
3
- import { join, dirname } from 'path';
3
+ import { join } from 'path';
4
4
  import { homedir } from 'os';
5
- import { fileURLToPath } from 'url';
6
5
  function expandPath(p) {
7
6
  if (p.startsWith('~')) {
8
7
  return join(homedir(), p.slice(1));
@@ -25,48 +24,8 @@ const MCP_ENTRY = {
25
24
  command: 'npx',
26
25
  args: ['-y', 'vibe-splain', 'serve'],
27
26
  };
28
- // Claude Code PreToolUse hook: deterministically gate edits to high-blast-radius
29
- // files. Hooks are a Claude Code CLI feature (settings.json) — not Desktop/Cursor.
30
- const HOOK_MATCHER = 'Edit|Write|MultiEdit';
31
- const DEFAULT_HOOK_COMMAND = 'npx -y vibe-splain hook pretooluse';
32
- /**
33
- * Idempotently register the vibe-splain PreToolUse hook in a Claude Code settings object.
34
- * Pure: takes a config, returns the same object mutated. Safe to run repeatedly.
35
- */
36
- export function addPreToolUseHook(config, hookPath) {
37
- if (!config.hooks)
38
- config.hooks = {};
39
- if (!Array.isArray(config.hooks.PreToolUse))
40
- config.hooks.PreToolUse = [];
41
- const hookCommand = hookPath ? `node "${hookPath}"` : DEFAULT_HOOK_COMMAND;
42
- const already = config.hooks.PreToolUse.some((entry) => Array.isArray(entry?.hooks) &&
43
- entry.hooks.some((h) => typeof h?.command === 'string' && (h.command.includes('vibe-splain hook pretooluse') || h.command.includes('hook.js'))));
44
- if (already) {
45
- // Update existing hook command to the resolved hook.js path
46
- config.hooks.PreToolUse = config.hooks.PreToolUse.map((entry) => {
47
- if (Array.isArray(entry?.hooks)) {
48
- return {
49
- ...entry,
50
- hooks: entry.hooks.map((h) => {
51
- if (typeof h?.command === 'string' && (h.command.includes('vibe-splain hook pretooluse') || h.command.includes('hook.js'))) {
52
- return { ...h, command: hookCommand };
53
- }
54
- return h;
55
- })
56
- };
57
- }
58
- return entry;
59
- });
60
- return config;
61
- }
62
- config.hooks.PreToolUse.push({
63
- matcher: HOOK_MATCHER,
64
- hooks: [{ type: 'command', command: hookCommand }],
65
- });
66
- return config;
67
- }
68
27
  export async function installCommand() {
69
- console.error('\n🔧 vibe-splain Installer\n');
28
+ console.error('\n🔧 vibesplain Installer\n');
70
29
  let patchedCount = 0;
71
30
  for (const agent of AGENT_CONFIGS) {
72
31
  const resolvedPath = expandPath(agent.path);
@@ -84,20 +43,11 @@ export async function installCommand() {
84
43
  console.error(` ⚠ Could not parse JSON, skipping`);
85
44
  continue;
86
45
  }
87
- // Patch config (idempotent: only write when something actually changes,
88
- // so existing users still pick up newly-added pieces like the hook).
89
46
  const before = JSON.stringify(config);
90
47
  if (!config.mcpServers)
91
48
  config.mcpServers = {};
92
- if (!config.mcpServers['vibe-splain'])
93
- config.mcpServers['vibe-splain'] = MCP_ENTRY;
94
- // The PreToolUse gate is a Claude Code CLI feature (settings.json hooks).
95
- // Only register it there; Desktop/Gemini/Cursor don't run these hooks.
96
- if (agent.name === 'Claude Code CLI') {
97
- const __dirname = dirname(fileURLToPath(import.meta.url));
98
- const hookPath = join(__dirname, '..', 'hook.js');
99
- addPreToolUseHook(config, hookPath);
100
- }
49
+ if (!config.mcpServers['vibesplain'])
50
+ config.mcpServers['vibesplain'] = MCP_ENTRY;
101
51
  if (JSON.stringify(config) === before) {
102
52
  console.error(` ✓ Already configured, skipping`);
103
53
  patchedCount++;
@@ -116,7 +66,7 @@ export async function installCommand() {
116
66
  console.error(`Add this manually to your agent's MCP config:\n`);
117
67
  console.error(JSON.stringify({
118
68
  mcpServers: {
119
- 'vibe-splain': MCP_ENTRY
69
+ 'vibesplain': MCP_ENTRY
120
70
  }
121
71
  }, null, 2));
122
72
  process.exit(1);
@@ -1,6 +1,6 @@
1
1
  import { startMCPServer } from '../mcp/server.js';
2
2
  export async function serveCommand(options) {
3
- console.error('[vibe-splain] Starting MCP server...');
3
+ console.error('[vibesplain] Starting MCP server...');
4
4
  await startMCPServer(options);
5
5
  // Process stays alive — do NOT call process.exit() here
6
6
  }
@@ -7,9 +7,9 @@ export class ArtifactBundleWriter {
7
7
  this.projectRoot = projectRoot;
8
8
  }
9
9
  async writeBundle(artifacts) {
10
- const outputDir = join(this.projectRoot, '.vibe-splainer');
11
- const stagingDir = join(this.projectRoot, '.vibe-splainer.tmp');
12
- const oldDir = join(this.projectRoot, '.vibe-splainer.old');
10
+ const outputDir = join(this.projectRoot, '.vibesplain');
11
+ const stagingDir = join(this.projectRoot, '.vibesplain.tmp');
12
+ const oldDir = join(this.projectRoot, '.vibesplain.old');
13
13
  try {
14
14
  await rm(stagingDir, { recursive: true, force: true });
15
15
  await rm(oldDir, { recursive: true, force: true });
@@ -1,30 +1,12 @@
1
- import type { Dossier, AnalysisStore, ImportGraph } from '@vibe-splain/brain';
1
+ import type { Dossier, AnalysisStore, ImportGraph } from '@vibesplain/brain';
2
2
  export interface ExportOptions {
3
3
  format?: 'json' | 'html' | 'markdown' | 'delta';
4
4
  budget?: number;
5
5
  scope?: string;
6
6
  }
7
- export interface ManifestArtifactEntry {
8
- name: string;
9
- pointer: string;
10
- contentHash: string;
11
- sizeBytes: number;
12
- indexes?: Record<string, string>;
13
- hydrators?: string[];
14
- }
15
- export interface ScanManifest {
16
- schemaVersion: '2.0.0';
17
- scanId: string;
18
- generatedAt: string;
19
- projectRoot: string;
20
- artifacts: ManifestArtifactEntry[];
21
- }
22
7
  export declare class ExportOrchestrator {
23
8
  private projectRoot;
24
9
  constructor(projectRoot: string);
25
- writeBundle(dossier: Dossier, options?: ExportOptions, store?: AnalysisStore, graph?: ImportGraph, scanId?: string): Promise<{
26
- scanId: string;
27
- manifestPointer: string;
28
- }>;
10
+ writeBundle(dossier: Dossier, options?: ExportOptions, store?: AnalysisStore, graph?: ImportGraph): Promise<void>;
29
11
  private buildViewModel;
30
12
  }
@@ -1,4 +1,4 @@
1
- import { readAnalysis, RecommendationEngine, buildGateIndex } from '@vibe-splain/brain';
1
+ import { readAnalysis } from '@vibesplain/brain';
2
2
  import { ArtifactBundleWriter } from './ArtifactBundleWriter.js';
3
3
  import { JsonRenderer } from './renderers/JsonRenderer.js';
4
4
  import { HtmlRenderer } from './renderers/HtmlRenderer.js';
@@ -6,15 +6,12 @@ import { AgentMarkdownRenderer } from './renderers/AgentMarkdownRenderer.js';
6
6
  import { ValidationRenderer } from './renderers/ValidationRenderer.js';
7
7
  import { RawAnalysisRenderer } from './renderers/RawAnalysisRenderer.js';
8
8
  import { GraphRenderer } from './renderers/GraphRenderer.js';
9
- import { BlobStore } from '../store/BlobStore.js';
10
- import { PointerStore } from '../store/PointerStore.js';
11
- import { v4 as uuidv4 } from 'uuid';
12
9
  export class ExportOrchestrator {
13
10
  projectRoot;
14
11
  constructor(projectRoot) {
15
12
  this.projectRoot = projectRoot;
16
13
  }
17
- async writeBundle(dossier, options = {}, store, graph, scanId) {
14
+ async writeBundle(dossier, options = {}, store, graph) {
18
15
  const finalStore = store || await readAnalysis(this.projectRoot);
19
16
  if (!finalStore) {
20
17
  throw new Error('Analysis store not found. Scan the project first.');
@@ -32,14 +29,7 @@ export class ExportOrchestrator {
32
29
  if (graph) {
33
30
  artifacts.push(...await new GraphRenderer(graph).render(viewModel, finalStore));
34
31
  }
35
- const gateIndex = buildGateIndex(finalStore);
36
- artifacts.push({
37
- type: 'gate',
38
- path: 'gate.json',
39
- content: JSON.stringify(gateIndex, null, 2),
40
- });
41
- // Determine additional formats
42
- const formats = ['html', 'markdown']; // default
32
+ const formats = ['html', 'markdown'];
43
33
  if (options.format && options.format !== 'json' && options.format !== 'delta') {
44
34
  formats.length = 0;
45
35
  formats.push(options.format);
@@ -52,110 +42,9 @@ export class ExportOrchestrator {
52
42
  }
53
43
  const writer = new ArtifactBundleWriter(this.projectRoot);
54
44
  await writer.writeBundle(artifacts);
55
- // Register artifacts in BlobStore + PointerStore and build manifest
56
- const effectiveScanId = scanId ?? `scan_${Date.now()}`;
57
- const blobStore = new BlobStore(this.projectRoot);
58
- const pointerStore = PointerStore.open(this.projectRoot);
59
- const now = Date.now();
60
- const manifestEntries = [];
61
- for (const artifact of artifacts) {
62
- const content = typeof artifact.content === 'string'
63
- ? Buffer.from(artifact.content, 'utf8')
64
- : artifact.content;
65
- const { contentHash, blobPath } = await blobStore.writeAtomic(content);
66
- const pointerId = `ptr_${uuidv4().replace(/-/g, '').slice(0, 16)}`;
67
- await pointerStore.insertPointer({
68
- pointerId,
69
- scanId: effectiveScanId,
70
- artifactName: artifact.type,
71
- contentHash,
72
- blobPath,
73
- schemaVersion: '1.0.0',
74
- createdAt: now,
75
- expiresAt: null,
76
- });
77
- const entry = {
78
- name: artifact.type,
79
- pointer: pointerId,
80
- contentHash,
81
- sizeBytes: content.length,
82
- };
83
- // Attach hydrator hints for the large analysis artifact
84
- if (artifact.type === 'analysis') {
85
- entry.hydrators = ['get_project_summary', 'get_start_here'];
86
- // Generate analysis.index.json (Start-Here + Top-Heat)
87
- const analysisIndex = {
88
- schemaVersion: '1.0.0',
89
- scanId: effectiveScanId,
90
- startHere: dossier.map.topGravity.slice(0, 12),
91
- topHeat: dossier.map.topHeat.slice(0, 12),
92
- pillarSummary: dossier.map.pillars.map(p => ({
93
- name: p.name,
94
- fileCount: p.memberFiles?.length ?? 0,
95
- })),
96
- totalFiles: Object.keys(finalStore.files).length,
97
- realSourceFiles: Object.values(finalStore.files).filter(f => f.isRealSource).length,
98
- };
99
- const indexContent = Buffer.from(JSON.stringify(analysisIndex, null, 2), 'utf8');
100
- const indexWrite = await blobStore.writeAtomic(indexContent);
101
- const indexPointerId = `ptr_${uuidv4().replace(/-/g, '').slice(0, 16)}`;
102
- await pointerStore.insertPointer({
103
- pointerId: indexPointerId,
104
- scanId: effectiveScanId,
105
- artifactName: 'analysis.index',
106
- contentHash: indexWrite.contentHash,
107
- blobPath: indexWrite.blobPath,
108
- schemaVersion: '1.0.0',
109
- createdAt: now,
110
- expiresAt: null,
111
- });
112
- entry.indexes = { startHere: indexPointerId };
113
- }
114
- manifestEntries.push(entry);
115
- }
116
- // Write and register the scan manifest itself
117
- const manifest = {
118
- schemaVersion: '2.0.0',
119
- scanId: effectiveScanId,
120
- generatedAt: new Date(now).toISOString(),
121
- projectRoot: this.projectRoot,
122
- artifacts: manifestEntries,
123
- };
124
- const manifestContent = Buffer.from(JSON.stringify(manifest, null, 2), 'utf8');
125
- const manifestWrite = await blobStore.writeAtomic(manifestContent);
126
- const manifestPointerId = `ptr_manifest_${effectiveScanId}`;
127
- await pointerStore.insertPointer({
128
- pointerId: manifestPointerId,
129
- scanId: effectiveScanId,
130
- artifactName: 'artifact_manifest',
131
- contentHash: manifestWrite.contentHash,
132
- blobPath: manifestWrite.blobPath,
133
- schemaVersion: '2.0.0',
134
- createdAt: now,
135
- expiresAt: null,
136
- });
137
- return { scanId: effectiveScanId, manifestPointer: manifestPointerId };
138
45
  }
139
- buildViewModel(dossier, store) {
140
- const recommendations = {};
141
- for (const file of dossier.map.topGravity) {
142
- const persisted = store.files[file];
143
- if (persisted) {
144
- recommendations[file] = RecommendationEngine.generateRecommendations(persisted);
145
- }
146
- }
147
- for (const file of dossier.map.topHeat) {
148
- if (!recommendations[file]) {
149
- const persisted = store.files[file];
150
- if (persisted) {
151
- recommendations[file] = RecommendationEngine.generateRecommendations(persisted);
152
- }
153
- }
154
- }
155
- return {
156
- ...dossier,
157
- recommendations,
158
- };
46
+ buildViewModel(dossier, _store) {
47
+ return { ...dossier, recommendations: {} };
159
48
  }
160
49
  }
161
50
  //# sourceMappingURL=ExportOrchestrator.js.map