@mushi-mushi/cli 0.8.0 → 0.11.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.
package/README.md CHANGED
@@ -1,446 +1,170 @@
1
- # `@mushi-mushi/cli`
1
+ # @mushi-mushi/cli
2
2
 
3
- > **The mutation that closes the loop** run Mushi Mushi bug-intelligence from
4
- > your terminal and CI pipelines, without ever opening a browser.
3
+ CLI for Mushi Mushi set up the SDK in one command, then triage reports and monitor the pipeline from your terminal.
5
4
 
6
- <div align="center">
7
-
8
- <a href="https://kensaur.us/mushi-mushi/docs/" title="Full docs with screenshots">
9
- <img src="https://raw.githubusercontent.com/kensaurus/mushi-mushi/main/docs/screenshots/tour-pdca-loop.gif" alt="Admin console PDCA tour — what mushi init wires your project into" width="100%" />
10
- </a>
11
-
12
- <sub>↑ what the CLI connects to · <a href="https://kensaur.us/mushi-mushi/docs/admin/">admin docs with screenshots</a></sub>
13
-
14
- </div>
15
-
16
- ## What it does
17
-
18
- Like DNA repair enzymes that scan a genome for transcription errors and patch
19
- them before the next cell division, `mushi-mushi` scans your live project for
20
- bug patterns, feeds them back into your toolchain, and tells you which ones are
21
- still open. The CLI is the command-line face of that repair loop:
22
-
23
- | Before `@mushi-mushi/cli` | After `@mushi-mushi/cli` |
24
- |---|---|
25
- | Open the console to check if the bug you fixed is actually resolved | `mushi reports show <id>` in 1 second |
26
- | Manually copy SDK snippets into each new project | `mushi init` auto-detects your framework and installs everything |
27
- | No idea which mistake rules are active | `mushi lessons list` shows the current rule genome |
28
- | CI doesn't know about lesson files | `mushi sync-lessons` writes `.mushi/lessons.json` every deploy |
29
- | Debug auth failures by staring at headers | `mushi whoami` confirms key + endpoint in one shot |
30
-
31
- ---
32
-
33
- ## Quick start
34
-
35
- ```bash
36
- # 1. Install globally (or use npx without installing)
37
- npm install -g @mushi-mushi/cli # or: pnpm add -g / yarn global add
38
-
39
- # 2. Get your credentials from the Mushi console:
40
- # Project ID → https://kensaur.us/mushi-mushi/projects (copy chip)
41
- # API key → https://kensaur.us/mushi-mushi/settings/api-keys
42
-
43
- # 3. Save credentials
44
- mushi login \
45
- --api-key mushi_xxxxxxxxxxxxxxxxxxxx \
46
- --endpoint https://<ref>.supabase.co/functions/v1/api \
47
- --project-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
48
-
49
- # 4. Verify the connection
50
- mushi whoami
51
-
52
- # 5. Set up the SDK in a project
53
- cd my-app && mushi init
54
- ```
55
-
56
- ---
57
-
58
- ## Environment variables
59
-
60
- All credentials can be supplied via environment variables — ideal for CI
61
- where a config file per runner is impractical:
62
-
63
- | Variable | Description |
64
- |---|---|
65
- | `MUSHI_API_KEY` | SDK API key, looks like `mushi_...` |
66
- | `MUSHI_PROJECT_ID` | Project UUID, from the Projects page |
67
- | `MUSHI_API_ENDPOINT` | Supabase edge function URL |
68
-
69
- Environment variables override `~/.mushirc`. Explicit command-line flags
70
- override both.
71
-
72
- ```bash
73
- # Example: CI usage without any persistent config file
74
- export MUSHI_API_KEY=mushi_xxxx
75
- export MUSHI_PROJECT_ID=542b34e0-019e-41fe-b900-7b637717bb86
76
- export MUSHI_API_ENDPOINT=https://xyz.supabase.co/functions/v1/api
77
-
78
- mushi sync-lessons # writes .mushi/lessons.json
79
- mushi status # print project stats
80
- mushi ping # smoke-test connectivity
81
- ```
82
-
83
- ---
84
-
85
- ## Finding your credentials
86
-
87
- ### API key
88
-
89
- 1. Open the Mushi console → **Settings → API Keys**
90
- (`https://kensaur.us/mushi-mushi/settings`)
91
- 2. Click **Create API key**
92
- 3. Copy the value — it starts with `mushi_`
93
-
94
- ### Project ID
95
-
96
- 1. Open the Mushi console → **Projects**
97
- (`https://kensaur.us/mushi-mushi/projects`)
98
- 2. On the project card, click the UUID chip to copy it
99
- 3. The UUID looks like `542b34e0-019e-41fe-b900-7b637717bb86`
100
-
101
- ### API endpoint
102
-
103
- Unless you are self-hosting, use:
104
- ```
105
- https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api
106
- ```
107
-
108
- ---
109
-
110
- ## Commands
111
-
112
- ### `mushi init`
113
-
114
- Set up the Mushi SDK in the current project. Auto-detects framework, installs
115
- the right package, and writes a minimal config file.
116
-
117
- ```bash
118
- mushi init
119
- mushi init --project-id <uuid> --api-key <key> # non-interactive (CI)
120
- mushi init --framework next # force a framework
121
- mushi init --skip-install # print install command only
122
- mushi init --yes # skip confirmation prompts
123
- ```
124
-
125
- Supported frameworks: `next`, `react`, `vue`, `nuxt`, `svelte`, `sveltekit`,
126
- `angular`, `expo`, `react-native`, `capacitor`, `vanilla`.
127
-
128
- ---
129
-
130
- ### `mushi login`
131
-
132
- Save API credentials to `~/.mushirc` (mode `0o600`, readable only by you).
133
-
134
- ```bash
135
- mushi login \
136
- --api-key mushi_xxx \
137
- --endpoint https://xyz.supabase.co/functions/v1/api \
138
- --project-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
139
- ```
140
-
141
- ---
142
-
143
- ### `mushi whoami`
144
-
145
- Verify the API key is valid and print which project it belongs to.
146
-
147
- ```bash
148
- mushi whoami
149
- mushi whoami --json # machine-readable
150
- ```
151
-
152
- Example output:
153
- ```
154
- ✓ Authenticated
155
- Project: My App (542b34e0-019e-41fe-b900-7b637717bb86)
156
- Endpoint: https://xyz.supabase.co/functions/v1/api
157
- Reports: 47 total · 3 open
158
- ```
159
-
160
- ---
161
-
162
- ### `mushi ping`
163
-
164
- Check that the Mushi backend is reachable. Useful as a CI health gate.
165
-
166
- ```bash
167
- mushi ping
168
- mushi ping --json # { ok: true, status: 200, latency_ms: 42 }
169
- ```
170
-
171
- ---
172
-
173
- ### `mushi status`
174
-
175
- Print a project health summary: report counts by status and severity, fix and
176
- lesson totals.
5
+ ## One-command setup
177
6
 
178
7
  ```bash
179
- mushi status
180
- mushi status --json
8
+ npx @mushi-mushi/cli init
9
+ # equivalently:
10
+ npx mushi-mushi
181
11
  ```
182
12
 
183
- ---
13
+ The wizard:
184
14
 
185
- ### `mushi config`
15
+ 1. Detects your framework (Next.js, Nuxt, SvelteKit, Angular, Expo, Capacitor, plain React/Vue/Svelte, or vanilla JS) from `package.json` and config files.
16
+ 2. Picks the right SDK package (`@mushi-mushi/react`, `@mushi-mushi/vue`, etc.) plus `@mushi-mushi/web` when the framework SDK is API-only.
17
+ 3. Detects your package manager (npm / pnpm / yarn / bun) from your lockfile and installs with that — `shell: false`, with Windows `.cmd` shim resolution.
18
+ 4. Writes `MUSHI_PROJECT_ID` and `MUSHI_API_KEY` (with the right framework prefix — `NEXT_PUBLIC_`, `NUXT_PUBLIC_`, `VITE_`) to `.env.local` (or `.env`).
19
+ 5. Warns you if `.env.local` isn't in `.gitignore` (covers `.env*.local`, `*.local`, etc.).
20
+ 6. Prints the framework-specific provider snippet to copy-paste.
21
+ 7. Offers to **send a real test report** so you see your first classified bug in the console immediately. Opt out via `--skip-test-report`.
186
22
 
187
- View or update the config stored in `~/.mushirc`.
23
+ It never silently overwrites existing env vars or modifies application code. Pasted credentials are sanitized (stripped of quotes / CR / LF / NUL) and validated against `^proj_[A-Za-z0-9_-]{10,}$` / `^mushi_[A-Za-z0-9_-]{10,}$` before anything is written to disk.
188
24
 
189
- ```bash
190
- mushi config # show all config
191
- mushi config apiKey mushi_xxx # update a value
192
- mushi config endpoint https://... # update endpoint
193
- mushi config projectId <uuid> # update project ID
194
- ```
195
-
196
- ---
197
-
198
- ### `mushi reports list`
199
-
200
- List recent reports for the project.
201
-
202
- ```bash
203
- mushi reports list
204
- mushi reports list --status new --severity critical
205
- mushi reports list --search "login button"
206
- mushi reports list --limit 50 --json
207
- ```
208
-
209
- Options:
210
- - `--limit <n>` — max results, 1–100 (default: 20)
211
- - `--status` — filter: `new`, `triaged`, `in_progress`, `resolved`, `dismissed`
212
- - `--severity` — filter: `critical`, `high`, `medium`, `low`
213
- - `--search <query>` — full-text search in summary and description
214
- - `--json` — machine-readable output
215
-
216
- ---
217
-
218
- ### `mushi reports show <id>`
219
-
220
- Print full details for a single report including environment, breadcrumbs, and
221
- linked fix.
222
-
223
- ```bash
224
- mushi reports show 7f3e8c20-...
225
- mushi reports show 7f3e8c20-... --json
226
- ```
227
-
228
- ---
229
-
230
- ### `mushi reports triage <id>`
231
-
232
- Update the status and/or severity of a report, and optionally add a note.
25
+ ### Flags
233
26
 
234
27
  ```bash
235
- mushi reports triage <id> --status triaged --severity high
236
- mushi reports triage <id> --status in_progress --note "assigned to @alice"
237
- mushi reports triage <id> --severity critical --json
28
+ mushi init --framework next # skip framework detection
29
+ mushi init --project-id proj_xxx --api-key mushi_xxx # skip credential prompts
30
+ mushi init --skip-install # print the install command instead
31
+ mushi init --skip-test-report # don't offer to send a test report
32
+ mushi init --cwd apps/web # run in a sub-package of a monorepo
33
+ mushi init --endpoint https://mushi.your-company.com # self-hosted Mushi API
34
+ mushi init -y # accept the detected framework
238
35
  ```
239
36
 
240
- ---
241
-
242
- ### `mushi reports resolve <id>`
243
-
244
- Mark a report resolved. Shorthand for `triage --status resolved`.
37
+ Non-interactive use (CI): pass `--yes --project-id proj_xxx --api-key mushi_xxx` or the wizard exits with a clear error instead of hanging on a prompt.
245
38
 
246
- ```bash
247
- mushi reports resolve <id>
248
- mushi reports resolve <id> --note "fixed in PR #123"
249
- ```
39
+ Stale-version hint: the wizard checks the npm registry (2s timeout) and prints a one-line upgrade nudge if a newer stable is published. Opt out with `MUSHI_NO_UPDATE_CHECK=1`.
250
40
 
251
- ---
41
+ Monorepo awareness: if you run the wizard at a workspace root with no framework dep, it scans `apps/*`, `packages/*`, `examples/*` and tells you which sub-package you probably meant (`mushi init --cwd apps/web`).
252
42
 
253
- ### `mushi reports reopen <id>`
254
-
255
- Reopen a resolved or dismissed report.
43
+ ## Install globally
256
44
 
257
45
  ```bash
258
- mushi reports reopen <id>
259
- mushi reports reopen <id> --note "regression in v2.1"
46
+ npm install -g @mushi-mushi/cli
47
+ mushi --help
48
+ mushi --version
260
49
  ```
261
50
 
262
- ---
263
-
264
- ### `mushi reports dismiss <id>`
265
-
266
- Dismiss a report (not a real bug / out of scope).
51
+ ## Other commands
267
52
 
268
53
  ```bash
269
- mushi reports dismiss <id>
270
- mushi reports dismiss <id> --note "working as intended"
54
+ mushi login --api-key mushi_xxx # store credentials in ~/.mushirc (mode 0o600)
55
+ mushi status # project overview
56
+ mushi reports list # recent reports
57
+ mushi reports show <id> # one report
58
+ mushi reports triage <id> --status acknowledged --severity high
59
+ mushi deploy check # edge-function health probe
60
+ mushi index <path> # walk a local repo and feed RAG
61
+ mushi test # submit a test report end-to-end
62
+ mushi migrate # suggest the most relevant migration guide
63
+ mushi migrate --json # machine-readable JSON for CI
64
+ mushi config endpoint https://... # set API endpoint (https:// required outside localhost)
65
+ mushi sourcemaps upload --release <ver> --dir <dist> # upload .js.map / .css.map (sha256-idempotent)
271
66
  ```
272
67
 
273
- ---
274
-
275
- ### `mushi reports search <query>`
276
-
277
- Search reports by keyword. Equivalent to `reports list --search <query>`.
278
-
279
- ```bash
280
- mushi reports search "button not working"
281
- mushi reports search "404" --status new --limit 20 --json
282
- ```
283
-
284
- ---
285
-
286
- ### `mushi lessons list`
287
-
288
- List active mistake rules (lessons) extracted from past bug reports.
289
-
290
- ```bash
291
- mushi lessons list
292
- mushi lessons list --severity critical
293
- mushi lessons list --limit 100 --json
294
- ```
295
-
296
- ---
297
-
298
- ### `mushi lessons show <id>`
299
-
300
- Print full detail for a lesson: rule text, anti-pattern, and summary paragraph.
301
-
302
- ```bash
303
- mushi lessons show <lesson-uuid>
304
- mushi lessons show <lesson-uuid> --json
305
- ```
306
-
307
- ---
308
-
309
- ### `mushi sync-lessons`
68
+ ### `mushi sourcemaps upload`
310
69
 
311
- Pull all active lessons from the Mushi API and write `.mushi/lessons.json`
312
- into the repo. Used in CI to keep the lesson file fresh for the Mushi MCP
313
- server and Cursor rules.
70
+ Recursively scans `--dir` for `.js.map` and `.css.map` files and uploads them
71
+ under the given `--release`. Each file is hashed (sha256) and skipped if the
72
+ server already has it for that release, so the command is safe to run from
73
+ every CI build without churning storage.
314
74
 
315
75
  ```bash
316
- mushi sync-lessons # writes .mushi/lessons.json
317
- mushi sync-lessons --dry-run # print JSON without writing
318
- mushi sync-lessons --json # { ok: true, path: "...", count: 12 }
319
- mushi sync-lessons --cwd ./apps/mobile
320
- ```
321
-
322
- CI example (GitHub Actions):
323
- ```yaml
324
- - name: Sync Mushi lessons
325
- env:
326
- MUSHI_API_KEY: ${{ secrets.MUSHI_API_KEY }}
327
- MUSHI_PROJECT_ID: ${{ secrets.MUSHI_PROJECT_ID }}
328
- MUSHI_API_ENDPOINT: https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api
329
- run: npx @mushi-mushi/cli sync-lessons
76
+ mushi sourcemaps upload --release 1.4.2 --dir ./dist
77
+ mushi sourcemaps upload --release "$GITHUB_SHA" --dir ./build --dry-run
78
+ mushi sourcemaps upload --release "$GITHUB_SHA" --dir ./build --silent
330
79
  ```
331
80
 
332
- ---
81
+ Requires `MUSHI_API_ENDPOINT` and `MUSHI_API_KEY` (or pass `--endpoint` /
82
+ `--api-key`). Exits non-zero on any upload failure so CI gates fail fast.
333
83
 
334
- ### `mushi test`
335
-
336
- Submit a synthetic test report to verify the ingestion pipeline end-to-end.
337
- Run this after deployment to confirm the SDK → API → DB path is healthy.
338
-
339
- ```bash
340
- mushi test
341
- mushi test --json
342
- ```
84
+ ### `mushi migrate`
343
85
 
344
- ---
86
+ Reads `package.json` (deps + devDeps + peerDeps) and prints links to the
87
+ matching guides on the docs site. Detects:
345
88
 
346
- ### `mushi index <path>`
89
+ - **In-transition shapes** — Capacitor + React Native side-by-side, Cordova
90
+ (or `cordova-ios`/`cordova-android`), Create React App.
91
+ - **Competitor SDKs** — Instabug / Luciq, Shake, LogRocket Feedback,
92
+ BugHerd, Pendo Feedback.
347
93
 
348
- Walk a local repo and upload source code to the Mushi RAG vector index. Used
349
- for private repos that cannot be auto-indexed via the GitHub App integration.
94
+ Exits non-zero when nothing matches, so it composes in shell scripts:
350
95
 
351
96
  ```bash
352
- mushi index ./src
353
- mushi index ./src --language ts --dry-run
354
- mushi index . --json # { ok: true, files: 42, bytes: 123456 }
97
+ mushi migrate || echo "no migration suggestions for this project"
355
98
  ```
356
99
 
357
- ---
100
+ Only `published` guides ever surface — `draft` entries are filtered out so
101
+ the CLI never points users at a 404. This safety property is unit-pinned in
102
+ `packages/cli/src/migrate.test.ts` (positive control + negative control +
103
+ real-catalog regression guard).
358
104
 
359
- ### `mushi sourcemaps upload`
105
+ ### `mushi doctor`
360
106
 
361
- Upload source map files (`.map`) for stack trace symbolication.
107
+ Checks CLI and SDK health. Without flags it verifies local config and endpoint
108
+ reachability only.
362
109
 
363
110
  ```bash
364
- mushi sourcemaps upload --release 1.0.0
365
- mushi sourcemaps upload --release $(git rev-parse --short HEAD) --dir ./dist
366
- mushi sourcemaps upload --release 1.0.0 --dry-run --silent
111
+ mushi doctor # local checks only
112
+ mushi doctor --server # + calls /preflight on the backend (all 4 dispatch checks)
113
+ mushi doctor --json # machine-readable JSON output (exits 1 if any check fails)
367
114
  ```
368
115
 
369
- ---
116
+ Local checks performed:
370
117
 
371
- ### `mushi migrate`
118
+ | Check | What it verifies |
119
+ |---|---|
120
+ | CLI config | `~/.mushirc` exists, `projectId` and `apiKey` fields are present |
121
+ | Endpoint reachability | `GET /v1/sdk/config?project_id=...` returns 200 |
122
+ | SDK install | `@mushi-mushi/web` or framework-specific SDK is in `node_modules` |
372
123
 
373
- Suggest the most relevant migration guide based on your `package.json`.
124
+ With `--server`, also calls `GET /v1/admin/projects/:id/preflight` (same 4 checks
125
+ the admin console dispatch popover uses) and merges the results. The four
126
+ server checks (`key` values returned by the endpoint):
374
127
 
375
- ```bash
376
- mushi migrate
377
- mushi migrate --json
378
- ```
128
+ | `key` | What it verifies |
129
+ |---|---|
130
+ | `github` | A GitHub repo URL is linked (`project_repos.repo_url` or `project_settings.codebase_repo_url`) |
131
+ | `codebase` | Codebase indexing is enabled AND `pgvector` has at least one non-tombstoned file AND `last_indexed_at` is set |
132
+ | `anthropic` | A BYOK Anthropic key is stored in Supabase Vault (`project_settings.byok_anthropic_key_ref`) |
133
+ | `autofix` | The autofix toggle is ON (`project_settings.autofix_enabled = true`) |
379
134
 
380
- ---
135
+ `--server` requires `adminOrApiKey` credentials — set `MUSHI_API_KEY` to an
136
+ admin key (not a public SDK key).
381
137
 
382
- ### `mushi deploy check`
138
+ ### `mushi reset <projectId>`
383
139
 
384
- Check that the Mushi edge function is healthy and measure round-trip latency.
140
+ Archives a project and wipes its test data so the full onboarding flow can be
141
+ re-run. Useful for development and QA.
385
142
 
386
143
  ```bash
387
- mushi deploy check
388
- mushi deploy check --json # { ok: true, status: 200, latency_ms: 38 }
144
+ mushi reset proj_xxx --confirm # required flag prevents accidental wipes
389
145
  ```
390
146
 
391
- ---
392
-
393
- ## Exit codes
147
+ Wipes: `fix_attempts`, `project_codebase_files`, `reports`, `fix_dispatch_jobs`.
148
+ Sets `projects.archived_at`. **Irreversible.**
394
149
 
395
- | Code | Meaning |
396
- |------|---------|
397
- | `0` | Success |
398
- | `1` | API or runtime error |
399
- | `2` | Configuration error (missing credentials or endpoint) |
400
- | `3` | Not found (report or lesson ID does not exist) |
150
+ ### `mushi fixes tail --report-id <id>`
401
151
 
402
- ---
403
-
404
- ## Self-hosted Mushi
405
-
406
- If you run a self-hosted Mushi instance, point the CLI at your edge function:
152
+ Streams dispatch events for a report in real-time via SSE. Pairs with
153
+ `mushi doctor --server` for headless debugging without opening the admin console.
407
154
 
408
155
  ```bash
409
- mushi login \
410
- --api-key mushi_xxx \
411
- --endpoint https://your-ref.supabase.co/functions/v1/api \
412
- --project-id <uuid>
156
+ mushi fixes tail --report-id 11111111-2222-3333-4444-555555555555
413
157
  ```
414
158
 
415
- Or set `MUSHI_API_ENDPOINT` globally in CI.
416
-
417
- ---
418
-
419
- ## Biological evolution analogy
420
-
421
- Mushi Mushi is modelled on **cumulative selection** (Dawkins, _The Blind
422
- Watchmaker_) and **closed-loop error correction** (Black Box Thinking, Matthew
423
- Syed):
424
-
425
- 1. **Variation** — users report bugs via the SDK widget → raw reports accumulate
426
- 2. **Selection pressure** — the clustering pipeline groups similar bugs and
427
- scores them by frequency and severity → weak signals are filtered out
428
- 3. **Memory** — high-signal clusters are promoted to _lessons_ (mistake rules)
429
- → the genome of known failure modes grows
430
- 4. **Expression** — the MCP server and CLI inject lessons into AI code review
431
- → the codebase adapts before the next mutation slips through
432
-
433
- The CLI is the **field instrument** for monitoring this loop:
434
- - `mushi status` — read the current fitness of your bug pipeline
435
- - `mushi sync-lessons` — express the latest genome into your repo
436
- - `mushi reports triage` — apply selection pressure manually when the
437
- automated pipeline needs a nudge
438
-
439
- ---
159
+ Exits automatically when the job reaches a terminal status (`completed`,
160
+ `failed`, `cancelled`, `skipped`).
440
161
 
441
- ## Changelog
162
+ ## Security notes
442
163
 
443
- See [CHANGELOG.md](../../CHANGELOG.md) for release history.
164
+ - `~/.mushirc` is written with mode `0o600` on Unix. Legacy configs with looser permissions are tightened on load.
165
+ - `--endpoint` values are parsed through `new URL()` and required to use `https://` except for `localhost` / `127.0.0.1` / `*.local`.
166
+ - The `--api-key` flag leaks into `ps -ef` — prefer the interactive prompt on shared machines.
167
+ - Full stack traces on error: `DEBUG=mushi mushi init`.
444
168
 
445
169
  ## License
446
170
 
@@ -0,0 +1,6 @@
1
+ // src/version.ts
2
+ var MUSHI_CLI_VERSION = true ? "0.11.0" : "0.0.0-dev";
3
+
4
+ export {
5
+ MUSHI_CLI_VERSION
6
+ };
@@ -12,6 +12,9 @@ var FRAMEWORK_IDS = [
12
12
  "expo",
13
13
  "react-native",
14
14
  "capacitor",
15
+ "express",
16
+ "fastify",
17
+ "hono",
15
18
  "vanilla"
16
19
  ];
17
20
  function isFrameworkId(value) {
@@ -176,6 +179,71 @@ export default function App() {
176
179
  import { Mushi } from '@mushi-mushi/capacitor'
177
180
 
178
181
  await Mushi.configure({ projectId: '${projectId}', apiKey: '${apiKey}' })`
182
+ },
183
+ express: {
184
+ id: "express",
185
+ label: "Express",
186
+ packageName: "@mushi-mushi/node",
187
+ needsWebPackage: false,
188
+ snippet: (apiKey, projectId) => `// src/instrument.ts \u2014 load with: node --import ./dist/instrument.js
189
+ import { MushiNodeClient, attachUnhandledHook } from '@mushi-mushi/node'
190
+ import { mushiExpressErrorHandler } from '@mushi-mushi/node/express'
191
+ import type { Express } from 'express'
192
+
193
+ export const mushi = new MushiNodeClient({
194
+ projectId: '${projectId}',
195
+ apiKey: '${apiKey}',
196
+ environment: process.env.NODE_ENV ?? 'production',
197
+ })
198
+ attachUnhandledHook({ client: mushi })
199
+
200
+ export function attachMushi(app: Express) {
201
+ app.use(mushiExpressErrorHandler({ client: mushi }))
202
+ }`
203
+ },
204
+ fastify: {
205
+ id: "fastify",
206
+ label: "Fastify",
207
+ packageName: "@mushi-mushi/node",
208
+ needsWebPackage: false,
209
+ snippet: (apiKey, projectId) => `// src/instrument.ts \u2014 load with: node --import ./dist/instrument.js
210
+ import { MushiNodeClient, attachUnhandledHook } from '@mushi-mushi/node'
211
+ import { mushiFastifyPlugin } from '@mushi-mushi/node/fastify'
212
+ import Fastify from 'fastify'
213
+
214
+ export const mushi = new MushiNodeClient({
215
+ projectId: '${projectId}',
216
+ apiKey: '${apiKey}',
217
+ environment: process.env.NODE_ENV ?? 'production',
218
+ })
219
+ attachUnhandledHook({ client: mushi })
220
+
221
+ const app = Fastify()
222
+ mushiFastifyPlugin(app, { client: mushi })`
223
+ },
224
+ hono: {
225
+ id: "hono",
226
+ label: "Hono",
227
+ packageName: "@mushi-mushi/node",
228
+ needsWebPackage: false,
229
+ snippet: (apiKey, projectId) => `// src/instrument.ts \u2014 load with: node --import ./dist/instrument.js
230
+ import { MushiNodeClient, attachUnhandledHook } from '@mushi-mushi/node'
231
+ import { mushiHonoErrorHandler } from '@mushi-mushi/node/hono'
232
+ import { Hono } from 'hono'
233
+
234
+ export const mushi = new MushiNodeClient({
235
+ projectId: '${projectId}',
236
+ apiKey: '${apiKey}',
237
+ environment: process.env.NODE_ENV ?? 'production',
238
+ })
239
+ attachUnhandledHook({ client: mushi })
240
+
241
+ const app = new Hono()
242
+ app.onError(
243
+ mushiHonoErrorHandler({ client: mushi }, (err, c) =>
244
+ c.text('Internal Server Error', 500),
245
+ ),
246
+ )`
179
247
  },
180
248
  vanilla: {
181
249
  id: "vanilla",
@@ -209,6 +277,9 @@ function detectFramework(cwd, pkg) {
209
277
  if (deps.has("svelte")) return FRAMEWORKS.svelte;
210
278
  if (deps.has("vue")) return FRAMEWORKS.vue;
211
279
  if (deps.has("react")) return FRAMEWORKS.react;
280
+ if (deps.has("express")) return FRAMEWORKS.express;
281
+ if (deps.has("fastify")) return FRAMEWORKS.fastify;
282
+ if (deps.has("hono") || deps.has("@hono/hono")) return FRAMEWORKS.hono;
212
283
  if (existsSync(join(cwd, "next.config.js")) || existsSync(join(cwd, "next.config.ts"))) {
213
284
  return FRAMEWORKS.next;
214
285
  }
@@ -234,7 +305,14 @@ function installCommand(pm, packages) {
234
305
  const verb = pm === "npm" ? "install" : "add";
235
306
  return `${pm} ${verb} ${packages.join(" ")}`;
236
307
  }
308
+ var SERVER_FRAMEWORK_IDS = /* @__PURE__ */ new Set(["express", "fastify", "hono"]);
237
309
  function envVarsToWrite(apiKey, projectId, framework) {
310
+ if (SERVER_FRAMEWORK_IDS.has(framework.id)) {
311
+ return [
312
+ `MUSHI_PROJECT_ID=${projectId}`,
313
+ `MUSHI_API_KEY=${apiKey}`
314
+ ].join("\n");
315
+ }
238
316
  const prefix = framework.id === "next" ? "NEXT_PUBLIC_" : framework.id === "nuxt" ? "NUXT_PUBLIC_" : "VITE_";
239
317
  return [
240
318
  `${prefix}MUSHI_PROJECT_ID=${projectId}`,
package/dist/detect.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * PURPOSE: Pure detection helpers for framework, package manager, and project state.
4
4
  * Kept side-effect-free so the wizard remains unit-testable.
5
5
  */
6
- type FrameworkId = 'next' | 'react' | 'vue' | 'nuxt' | 'svelte' | 'sveltekit' | 'angular' | 'expo' | 'react-native' | 'capacitor' | 'vanilla';
6
+ type FrameworkId = 'next' | 'react' | 'vue' | 'nuxt' | 'svelte' | 'sveltekit' | 'angular' | 'expo' | 'react-native' | 'capacitor' | 'express' | 'fastify' | 'hono' | 'vanilla';
7
7
  interface Framework {
8
8
  id: FrameworkId;
9
9
  label: string;