@happyvertical/smrt-dev-mcp 0.47.1 → 0.48.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 (43) hide show
  1. package/AGENTS.md +10 -9
  2. package/README.md +151 -66
  3. package/dist/dev-plane.d.ts +48 -0
  4. package/dist/dev-plane.d.ts.map +1 -0
  5. package/dist/dev-plane.js +211 -0
  6. package/dist/dev-plane.js.map +1 -0
  7. package/dist/http-TeoaK9Xr.js +168 -0
  8. package/dist/http-TeoaK9Xr.js.map +1 -0
  9. package/dist/http.d.ts +96 -0
  10. package/dist/http.d.ts.map +1 -0
  11. package/dist/index.d.ts +11 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +86 -428
  14. package/dist/index.js.map +1 -1
  15. package/dist/knowledge/index.d.ts +27 -1
  16. package/dist/knowledge/index.d.ts.map +1 -1
  17. package/dist/{knowledge-DmZ-7GO9.js → knowledge-BOsSAdPo.js} +82 -655
  18. package/dist/knowledge-BOsSAdPo.js.map +1 -0
  19. package/dist/knowledge.js +2 -2
  20. package/dist/observation-VJgHaPps.js +802 -0
  21. package/dist/observation-VJgHaPps.js.map +1 -0
  22. package/dist/runtime.d.ts +21 -0
  23. package/dist/runtime.d.ts.map +1 -0
  24. package/dist/runtime.js +18 -0
  25. package/dist/runtime.js.map +1 -0
  26. package/dist/server-info.d.ts +3 -0
  27. package/dist/server-info.d.ts.map +1 -0
  28. package/dist/tool-catalog-Zl-bcimC.js +643 -0
  29. package/dist/tool-catalog-Zl-bcimC.js.map +1 -0
  30. package/dist/tool-catalog.d.ts.map +1 -1
  31. package/dist/tools/introspect-project.d.ts +8 -0
  32. package/dist/tools/introspect-project.d.ts.map +1 -1
  33. package/dist/tools/runtime/boot.d.ts +70 -0
  34. package/dist/tools/runtime/boot.d.ts.map +1 -0
  35. package/dist/tools/runtime/connection.d.ts +19 -0
  36. package/dist/tools/runtime/connection.d.ts.map +1 -1
  37. package/dist/tools/runtime/observation.d.ts +43 -0
  38. package/dist/tools/runtime/observation.d.ts.map +1 -0
  39. package/dist/tools/runtime/tools.d.ts +19 -0
  40. package/dist/tools/runtime/tools.d.ts.map +1 -1
  41. package/package.json +14 -6
  42. package/skills/smrt-code-review/SKILL.md +1 -1
  43. package/dist/knowledge-DmZ-7GO9.js.map +0 -1
package/AGENTS.md CHANGED
@@ -13,14 +13,10 @@ deterministic SMRT ecosystem knowledge, and portable agent workflows.
13
13
  | `reflect-knowledge` | Reports deterministic SMRT + HappyVertical SDK knowledge coverage and freshness |
14
14
  | `reflect-domain-knowledge` | Reports downstream/domain artifact coverage and freshness |
15
15
  | `check-knowledge-freshness` | Runs deterministic agent-doc and stale-reference checks |
16
- | `check-domain-knowledge` | Alias for deterministic domain artifact freshness checks |
17
- | `build-review-context` | Builds model-ready SMRT review context and package expert routing |
18
- | `build-domain-review-context` | Domain-scoped review context builder with `scope`/`package` filters |
19
- | `smrt-review` | Returns deterministic review findings and a reusable review prompt bundle |
20
- | `build-architecture-context` | Builds architecture planning context from an idea or docs |
16
+ | `build-context` | One context entry: `task: review` (file-anchored findings + `reviewHints` + prompt bundle) or `task: architecture` (ranked packages + recommendations); replaces the four `build-*-context` tools (#2780) |
17
+ | `smrt-review` | Deprecated name for `build-context` `task: review`; removed next minor |
21
18
  | `build-package-specialist-context` | Builds deterministic package-specific Workbench context and source references |
22
- | `build-domain-architecture-context` | Domain-scoped architecture context builder with `scope`/`package` filters |
23
- | `smrt-architecture` | Recommends SMRT/SDK packages, object-model sketch, risks, and questions |
19
+ | `smrt-architecture` | Deprecated name for `build-context` `task: architecture`; removed next minor |
24
20
  | `list-agent-skills` | Lists bundled harness-agnostic agent skills |
25
21
  | `get-agent-skill` | Returns a bundled agent skill as Markdown plus optional references |
26
22
  | `migration-status` | Live migration status from the `_smrt_schema_migrations` system table — completed/running/failed/rolled_back counts, latest completed and failed migrations (runtime provenance; read-only; optional live DB, #1824) |
@@ -29,6 +25,9 @@ deterministic SMRT ecosystem knowledge, and portable agent workflows.
29
25
  | `dispatch-health` | Live dispatch health from the `_smrt_dispatch`/`_smrt_dispatch_subscriptions` system tables — stuck/pending by type/status, subscription topology; payloads/metadata never read (runtime provenance; read-only, #1824) |
30
26
  | `recent-changes` | Tail of the `_smrt_changes` append-only change feed with cursor semantics, filterable by table and tenant (runtime provenance; read-only, #1824) |
31
27
  | `registry-drift` | Registry drift report — `_smrt_registry` is retired and reported as such, never queried or fabricated (read-only, #1824) |
28
+ | `runtime-registry` | Sanitized snapshot of the booted `ObjectRegistry` from project + installed manifests; no project code executed (booted provenance; read-only, #1831) |
29
+ | `runtime-object` | One booted object's sanitized definition plus generated DDL (booted provenance; read-only, #1831) |
30
+ | `runtime-schema-diff` | Booted registry schemas vs live dev DB via the `db:diff` comparer; introspection only, no drops/relaxations (runtime provenance; read-only, #1831) |
32
31
 
33
32
  `pnpm knowledge:check --strict --format markdown` compares this catalog and the
34
33
  README parameter tables to the exported `TOOLS` definitions. Add or change a
@@ -97,7 +96,7 @@ Per package, objects resolve in this order, and the winner is recorded in
97
96
  The index exposes `coverage` and `diagnostics` (added in `schemaVersion: 2`). Zero
98
97
  discovered objects is an **error-grade** diagnostic that names the roots and
99
98
  artifact paths checked plus the fix, and it propagates into
100
- `smrt-architecture`/`smrt-review`/`reflect-*` results and prompt bundles.
99
+ `build-context`/`reflect-*` results and prompt bundles.
101
100
 
102
101
  A workspace-root package has an empty `relativeDirectory`, so package paths are
103
102
  built with `packageRelativePath`/`packageDocPaths` rather than interpolation —
@@ -113,7 +112,7 @@ with YAML frontmatter (`name` and `description`) and harness-neutral body text.
113
112
  Skill-aware harnesses can parse the frontmatter; other harnesses can ignore it.
114
113
 
115
114
  - `skills/smrt-code-review/SKILL.md` — downstream SMRT code review workflow.
116
- Agents should fetch it with `get-agent-skill`, then call `smrt-review` for
115
+ Agents should fetch it with `get-agent-skill`, then call `build-context` (`task: review`) for
117
116
  deterministic context, inspect the actual diff, and produce a findings-first
118
117
  review.
119
118
 
@@ -144,6 +143,8 @@ launcher or a small wrapper script with an absolute Node path.
144
143
  - `skills/smrt-code-review/SKILL.md` — downstream SMRT review procedure
145
144
  - `src/tools/generate-smrt-class.ts` — class generation logic and package-ready templates
146
145
  - `src/tools/introspect-project.ts` — manifest-first project scanning, falling back to `@happyvertical/smrt-scanner`
146
+ - `src/dev-plane.ts` — in-app runtime dev-plane (#2782): `createDevPlane({ token, projectRoot, db })` serves JSON + MCP on one mount with loopback/bearer guards and a positive catalog (`registry-live` + the nine runtime tools); mounted by the generated `_dev/[...tool]` SvelteKit route
147
+ - `src/runtime.ts` — `RUNTIME_TOOLS` map for in-process callers (`smrt dev:runtime` fallback)
147
148
  - `src/tools/review-smrt-project.ts` — advisory ecosystem-alignment checks for downstream projects
148
149
 
149
150
  ## Gotchas
package/README.md CHANGED
@@ -6,6 +6,12 @@ or architecture prompt bundles.
6
6
 
7
7
  ## Installation
8
8
 
9
+ New to agent-assisted s-m-r-t development? Start with the end-to-end guide on
10
+ the docs site: [Developing a s-m-r-t app with an agent](https://s-m-r-t.dev/docs/agent-tooling)
11
+ (source: `docs/content/agent-tooling.md`). It walks through install, the
12
+ calls that matter in order, provenance labels, and the optional live-database
13
+ and HTTP setups this README details.
14
+
9
15
  ```bash
10
16
  pnpm install @happyvertical/smrt-dev-mcp
11
17
  ```
@@ -148,11 +154,15 @@ Knowledge and introspection tools return a **summary** by default and accept
148
154
 
149
155
  - `introspect-project` summary returns one compact record per object
150
156
  (`className`, `qualifiedName`, `extends`, `tableName`, `tenantScope`,
151
- `fieldCount`, compact relationship strings, `mcpOperations`). A response that
152
- exceeds its character budget reports a `truncated` block with the omitted count
153
- and filter guidance instead of being silently cut. `maxChars` overrides the
154
- budget.
155
- - `smrt-architecture`, `smrt-review`, and the `build-*-context` tools list
157
+ `fieldCount`, compact relationship strings, `mcpOperations`). A response
158
+ that exceeds its character budget, or that was cut short by `limit`, reports
159
+ a `truncated` block with the omitted count and guidance instead of being
160
+ silently cut. `maxChars` overrides the budget, and any truncated response
161
+ carries `nextCursor`; pass it back as `cursor` to read the next alphabetical
162
+ page. `runtime-registry` pages the
163
+ same way (`page.nextCursor`, `limit` default 50) while its summary stays
164
+ global.
165
+ - `build-context` (and its deprecated names `smrt-review`/`smrt-architecture`) lists
156
166
  authored `AGENTS.md` and module docs **by path** rather than embedding them,
157
167
  and return compact package records. With `detail: "full"`, they embed the package
158
168
  AGENTS doc plus module docs matching changed files or request text. Source paths and globs
@@ -287,6 +297,8 @@ available it falls back to `@happyvertical/smrt-scanner`.
287
297
  | `manifestPath` | `string` | No | Explicit manifest artifact path |
288
298
  | `detail` | `'summary' \| 'full'` | No | Default `summary`. `full` returns field, schema, and method detail |
289
299
  | `maxChars` | `number` | No | Response character budget; overflow is reported under `truncated` |
300
+ | `cursor` | `string` | No | Resume after this `className` (alphabetical); pass a previous response's `nextCursor` |
301
+ | `limit` | `number` | No | Maximum objects per page, applied before the character budget |
290
302
  | `includeFields` | `boolean` | No | Include field details (`detail: "full"` only) |
291
303
  | `includeRelationships` | `boolean` | No | Analyze relationships (`detail: "full"` only) |
292
304
  | `includeMethods` | `boolean` | No | Include public method details (`detail: "full"` only) |
@@ -337,49 +349,36 @@ Run the same deterministic freshness checks exposed by `pnpm knowledge:check`.
337
349
  | `changed` | `boolean` | No | Limit stale-pattern checks to changed files |
338
350
  | `strict` | `boolean` | No | Treat stale-pattern findings as errors |
339
351
 
340
- ### `check-domain-knowledge`
352
+ ### `build-context`
341
353
 
342
- Alias over the deterministic checker that emphasizes downstream
343
- `smrt-knowledge.json` artifact freshness.
354
+ Build model-ready context for a task. `task: "review"` routes `changedFiles`
355
+ and `focus` to package experts and returns file-anchored deterministic
356
+ findings, package-level `reviewHints` (relationship features, generated MCP
357
+ surface: context for a reviewer, not defects), and a prompt bundle.
358
+ `task: "architecture"` ranks packages by the idea text (package names, object
359
+ classes, tables, fields, tags) and returns the bundle plus recommendations.
360
+ Replaces `build-review-context`, `build-domain-review-context`,
361
+ `build-architecture-context`, and `build-domain-architecture-context`, which
362
+ dispatched to the same code.
344
363
 
345
364
  | Parameter | Type | Required | Description |
346
365
  |-----------|------|----------|-------------|
366
+ | `task` | `'review' \| 'architecture'` | Yes | What the context is for |
347
367
  | `rootDir` | `string` | No | Project root directory (default: cwd) |
348
- | `changed` | `boolean` | No | Limit stale-pattern checks to changed files |
349
- | `strict` | `boolean` | No | Treat stale-pattern findings as errors |
350
- | `scope` | `'project' \| 'local' \| 'package' \| 'sdk' \| 'installed'` | No | Knowledge source scope (default: `project`) |
351
- | `package` | `string` | No | Package name or short name to focus |
352
-
353
- ### `build-review-context`
354
-
355
- Select relevant s-m-r-t and HappyVertical SDK package expertise for changed files,
356
- then return a model-ready prompt bundle.
357
-
358
- | Parameter | Type | Required | Description |
359
- |-----------|------|----------|-------------|
360
- | `rootDir` | `string` | No | Project root directory (default: cwd) |
361
- | `changedFiles` | `string[]` | No | Files to route to package experts |
362
- | `focus` | `string` | No | Review focus or concern |
363
- | `documentation` | `string` | No | Additional docs or notes to include |
364
- | `detail` | `'summary' \| 'full' \| 'complete'` | No | Default `summary`; `full` embeds package docs and matching modules; `complete` embeds all modules and full package records |
365
-
366
- ### `build-domain-review-context`
367
-
368
- Domain-scoped alias for `build-review-context`.
369
-
370
- | Parameter | Type | Required | Description |
371
- |-----------|------|----------|-------------|
372
- | `rootDir` | `string` | No | Project root directory (default: cwd) |
373
- | `changedFiles` | `string[]` | No | Files to route to package experts |
374
- | `focus` | `string` | No | Review focus or concern |
375
- | `documentation` | `string` | No | Additional docs or notes to include |
368
+ | `changedFiles` | `string[]` | No | Files to route to package experts (`task: "review"`) |
369
+ | `focus` | `string` | No | Concern to prioritise |
370
+ | `documentation` | `string` | No | Existing docs, notes, or requirements |
371
+ | `idea` | `string` | No | Product or implementation idea (`task: "architecture"`) |
376
372
  | `scope` | `'project' \| 'local' \| 'package' \| 'sdk' \| 'installed'` | No | Knowledge source scope (default: `project`) |
377
373
  | `package` | `string` | No | Package name or short name to focus |
374
+ | `mode` | `'findings' \| 'prompt-bundle' \| 'both'` | No | Response mode for `task: "review"` (default: `both`) |
378
375
  | `detail` | `'summary' \| 'full' \| 'complete'` | No | Default `summary`; `full` embeds package docs and matching modules; `complete` embeds all modules and full package records |
379
376
 
380
377
  ### `smrt-review`
381
378
 
382
- Return deterministic review findings, a prompt bundle, or both.
379
+ Deprecated compatibility name for `build-context` with `task: "review"`;
380
+ removed in the next minor release. Responses carry a `deprecated_tool_name`
381
+ diagnostic.
383
382
 
384
383
  | Parameter | Type | Required | Description |
385
384
  |-----------|------|----------|-------------|
@@ -390,19 +389,6 @@ Return deterministic review findings, a prompt bundle, or both.
390
389
  | `mode` | `'findings' \| 'prompt-bundle' \| 'both'` | No | Response mode (default: `both`) |
391
390
  | `detail` | `'summary' \| 'full' \| 'complete'` | No | Default `summary`; `full` embeds package docs and matching modules; `complete` embeds all modules and full package records |
392
391
 
393
- ### `build-architecture-context`
394
-
395
- Select relevant s-m-r-t and SDK package expertise for an idea or documentation,
396
- then return a model-ready architecture prompt bundle.
397
-
398
- | Parameter | Type | Required | Description |
399
- |-----------|------|----------|-------------|
400
- | `rootDir` | `string` | No | Project root directory (default: cwd) |
401
- | `idea` | `string` | No | Product or implementation idea |
402
- | `documentation` | `string` | No | Existing docs or requirements |
403
- | `focus` | `string` | No | Architecture concern to prioritize |
404
- | `detail` | `'summary' \| 'full' \| 'complete'` | No | Default `summary`; `full` embeds package docs and matching modules; `complete` embeds all modules and full package records |
405
-
406
392
  ### `build-package-specialist-context`
407
393
 
408
394
  Build deterministic package-specific context for the Workbench, including the
@@ -415,24 +401,11 @@ context.
415
401
  | `package` | `string` | Yes | Package name or short package query |
416
402
  | `focus` | `string` | No | Package concern to prioritize |
417
403
 
418
- ### `build-domain-architecture-context`
419
-
420
- Domain-scoped alias for `build-architecture-context`.
421
-
422
- | Parameter | Type | Required | Description |
423
- |-----------|------|----------|-------------|
424
- | `rootDir` | `string` | No | Project root directory (default: cwd) |
425
- | `idea` | `string` | No | Product or implementation idea |
426
- | `documentation` | `string` | No | Existing docs or requirements |
427
- | `focus` | `string` | No | Architecture concern to prioritize |
428
- | `scope` | `'project' \| 'local' \| 'package' \| 'sdk' \| 'installed'` | No | Knowledge source scope (default: `project`) |
429
- | `package` | `string` | No | Package name or short name to focus |
430
- | `detail` | `'summary' \| 'full' \| 'complete'` | No | Default `summary`; `full` embeds package docs and matching modules; `complete` embeds all modules and full package records |
431
-
432
404
  ### `smrt-architecture`
433
405
 
434
- Return package recommendations, SDK recommendations, an object-model sketch,
435
- risks, questions, and the reusable architecture prompt bundle.
406
+ Deprecated compatibility name for `build-context` with `task: "architecture"`;
407
+ removed in the next minor release. Responses carry a `deprecated_tool_name`
408
+ diagnostic.
436
409
 
437
410
  | Parameter | Type | Required | Description |
438
411
  |-----------|------|----------|-------------|
@@ -535,6 +508,46 @@ static manifest tools. Read-only.
535
508
  | `dbUrl` | `string` | No | Optional dev database URL override (read-only diagnostics); prefer `SMRT_DEV_DB_URL` or `cli.database` config |
536
509
  | `dbType` | `'sqlite' \| 'postgres' \| 'duckdb'` | No | Optional engine hint for `dbUrl` or the environment connection; inferred from the URL scheme when omitted |
537
510
 
511
+ ### `runtime-registry`
512
+
513
+ Sanitized snapshot of the booted `ObjectRegistry`: objects, packages, tables,
514
+ fields, methods, tenancy, and inheritance, projected through a plain-JSON DTO.
515
+ The boot registers the project's `.smrt/manifest.json` (or `dist/manifest.json`)
516
+ and every installed s-m-r-t package manifest; no project code is imported. Booted
517
+ provenance (`booted (registry)`); read-only.
518
+
519
+ | Parameter | Type | Required | Description |
520
+ |-----------|------|----------|-------------|
521
+ | `projectPath` | `string` | No | Project root to boot manifests from (default: the server working directory; ignored by the HTTP host, which boots once) |
522
+ | `objects` | `string[]` | No | Restrict field/method detail to these simple or qualified object names |
523
+ | `detail` | `boolean` | No | Include field and method detail for every object (default: only when `objects` is given) |
524
+ | `cursor` | `string` | No | Resume after this qualified object name; pass a previous response's `page.nextCursor` |
525
+ | `limit` | `number` | No | Objects per page (default 50, capped at 500) |
526
+
527
+ ### `runtime-object`
528
+
529
+ One booted object: sanitized fields, methods, tenancy, inheritance, and the
530
+ DDL the registry would generate for it. Booted provenance; read-only.
531
+
532
+ | Parameter | Type | Required | Description |
533
+ |-----------|------|----------|-------------|
534
+ | `projectPath` | `string` | No | Project root to boot manifests from (default: the server working directory; ignored by the HTTP host, which boots once) |
535
+ | `name` | `string` | Yes | Simple or qualified object name |
536
+ | `engine` | `'sqlite' \| 'postgres' \| 'duckdb'` | No | Engine for the DDL preview (default: registry default) |
537
+
538
+ ### `runtime-schema-diff`
539
+
540
+ Booted registry schemas versus the live dev database, using the same comparer
541
+ as `db:diff`/`db:migrate`. Introspection only: drops and relaxations are never
542
+ proposed and nothing is executed. Runtime provenance; read-only. Without a
543
+ configured connection it returns a successful static-only result.
544
+
545
+ | Parameter | Type | Required | Description |
546
+ |-----------|------|----------|-------------|
547
+ | `projectPath` | `string` | No | Project root to boot manifests from (default: the server working directory; ignored by the HTTP host, which boots once) |
548
+ | `dbUrl` | `string` | No | Optional dev database URL override (read-only diagnostics); prefer `SMRT_DEV_DB_URL` or `cli.database` config |
549
+ | `dbType` | `'sqlite' \| 'postgres' \| 'duckdb'` | No | Optional engine hint for `dbUrl` or the environment connection; inferred from the URL scheme when omitted |
550
+
538
551
  ## Runtime Diagnostics (Optional Live DB)
539
552
 
540
553
  The six runtime-diagnostics tools above (`migration-status`, `job-health`,
@@ -554,6 +567,17 @@ anywhere → every runtime tool returns a successful static-only result
554
567
  (`provenance: 'static'`, `connected: false`) and the server starts and serves
555
568
  all static tools unaffected.
556
569
 
570
+ Accepted URL forms: `file:///abs/dev.db`, `sqlite:///abs/dev.db`
571
+ (`sqlite:` is normalised to a `file:` URL; a relative `sqlite:` path resolves
572
+ against the server's working directory), a bare path, `postgres://…`, or
573
+ `duckdb:…`. `:memory:` is treated as not configured.
574
+
575
+ Older dev databases whose `_smrt_*` tables predate a column are still
576
+ answered: each reader selects only the columns that exist and reports the rest
577
+ in a `schema_behind` diagnostic (and `schemaBehind` on the data) rather than
578
+ failing the category. A read that does fail carries the redacted driver
579
+ message as its cause.
580
+
557
581
  **Provenance labeling.** Live results carry `provenance: 'runtime (live DB)'`;
558
582
  static-only results carry `provenance: 'static'`. Never conflate the two: the
559
583
  manifest reports what the code declares, runtime tools report what the running
@@ -569,6 +593,67 @@ not `smrt-app-mcp` and never writes.
569
593
  (passwords and token query params masked); driver errors pass through a
570
594
  redacting normalizer before they can appear in a diagnostic.
571
595
 
596
+ ## Runtime Dev-Plane Host (HTTP, Level 2)
597
+
598
+ `smrt-dev-mcp --http [--port N] [--project DIR]` boots the confined runtime
599
+ once and serves a **positive, read-only** catalog over the stateless
600
+ Streamable HTTP transport (no SSE, no `Mcp-Session-Id`, no sticky routing):
601
+ `runtime-registry`, `runtime-object`, `runtime-schema-diff`, and the six
602
+ live-DB diagnostics above. The static stdio catalog is not mounted, and
603
+ generated CRUD, custom actions, `do()`, and tool-backed `is()` are never
604
+ exposed.
605
+
606
+ - Binds loopback only; the SDK's localhost Host and Origin validation runs on
607
+ every request.
608
+ - Every request needs `Authorization: Bearer <token>`. Set
609
+ `SMRT_DEV_MCP_TOKEN`, or let the process mint one and print it once to
610
+ stderr. A supplied token is never echoed.
611
+ - No authenticated principal exists on this plane, so scope is fail-closed
612
+ global-only exactly as for the stdio diagnostics.
613
+ - Per-request `projectPath` arguments are ignored: the booted project is fixed
614
+ at start. Restart the process to observe a rebuilt manifest.
615
+
616
+ ```bash
617
+ SMRT_DEV_MCP_TOKEN=dev-secret smrt-dev-mcp --http --port 3939 --project .
618
+ # → [smrt-dev-mcp] runtime dev-plane listening at http://127.0.0.1:3939/mcp
619
+ ```
620
+
621
+ ## In-App Dev-Plane (Level 3)
622
+
623
+ The same read-only runtime tools can run *inside* a SvelteKit app's dev
624
+ server, where the real decorated `ObjectRegistry` is already live and the
625
+ app's own database configuration is at hand. Enable the generated route in
626
+ the Vite plugin and install this package as a devDependency of the app:
627
+
628
+ ```ts
629
+ smrtPlugin({ sveltekit: { enabled: true, devPlaneRoute: { enabled: true } } })
630
+ ```
631
+
632
+ The generator writes `src/routes/api/_dev/[...tool]/+server.ts` (marked
633
+ auto-generated), which mounts `createDevPlane` from
634
+ `@happyvertical/smrt-dev-mcp/dev-plane`:
635
+
636
+ - **JSON**: `GET /api/_dev` lists the catalog; `GET|POST /api/_dev/<tool>`
637
+ returns the tool's envelope (arguments from the query string or a JSON
638
+ body). `curl -H "Authorization: Bearer $SMRT_DEV_MCP_TOKEN" http://127.0.0.1:5173/api/_dev/registry-live`
639
+ - **MCP**: `POST /api/_dev/mcp`, the same stateless Streamable HTTP contract
640
+ as `--http`.
641
+ - **Catalog**: `registry-live` (the app's live registry, no manifest boot,
642
+ provenance `live (app registry)`) plus the nine Level 2 tools. The static
643
+ stdio catalog, generated CRUD, custom actions, and `do()` are never mounted.
644
+
645
+ Boundary: the route 404s outside SvelteKit dev mode and returns 503 until
646
+ `SMRT_DEV_MCP_TOKEN` is set; every request must present that bearer token from
647
+ a loopback `Host` (and loopback `Origin` when present). Per-request
648
+ `projectPath`, `dbUrl`, and `dbType` are dropped: calls are pinned to the app's
649
+ root and to the database from `getSmrtConfig(...).db`, so the SDK's connection
650
+ cache hands the plane the app's own handle. Vite's SSR HMR re-registers classes
651
+ on change, so `registry-live` needs no restart.
652
+
653
+ From a terminal, `smrt dev:runtime <tool> [--arg key=value]...` calls the
654
+ route when `--url`/`SMRT_DEV_PLANE_URL` is set and otherwise runs the Level 2
655
+ boot locally, so the same envelope is available either way.
656
+
572
657
  ## MCP Resources And Prompts
573
658
 
574
659
  Resources:
@@ -0,0 +1,48 @@
1
+ /**
2
+ * In-app runtime dev-plane (#2782, Level 3 of #2307).
3
+ *
4
+ * The standalone `--http` host (Level 2) boots manifests in its own process.
5
+ * This module runs *inside* the application's dev server, where the real
6
+ * decorated `ObjectRegistry` is already live and the app's own database
7
+ * configuration is at hand. It serves the same read-only runtime tools as
8
+ * Level 2 plus `registry-live`, over two surfaces on one mount:
9
+ *
10
+ * - JSON: `GET <base>` (catalog), `GET|POST <base>/<tool>` (envelope);
11
+ * arguments come from the query string or a JSON body.
12
+ * - MCP: `POST <base>/mcp`, stateless Streamable HTTP (#2147).
13
+ *
14
+ * Security boundary: the caller (a generated SvelteKit route) only mounts
15
+ * this in dev mode; every request must present `Authorization: Bearer` with
16
+ * the configured token and arrive on a loopback `Host`. No principal exists,
17
+ * so scope is fail-closed global-only. The catalog is positive: generated
18
+ * CRUD, custom actions, `do()`, and tool-backed `is()` are never mounted.
19
+ */
20
+ /** Provenance label for the application's own live registry. */
21
+ export declare const LIVE_REGISTRY_PROVENANCE = "live (app registry)";
22
+ export interface DevPlaneDatabase {
23
+ url?: string;
24
+ type?: string;
25
+ }
26
+ export interface DevPlaneOptions {
27
+ /** Bearer token every request must present. */
28
+ token: string;
29
+ /** Project root; used only to relativize paths in snapshots. */
30
+ projectRoot?: string;
31
+ /**
32
+ * The app's database configuration (typically `getSmrtConfig(name).db`
33
+ * from the generated `$lib/server/smrt`). Passed to the runtime tools as
34
+ * `dbUrl`/`dbType`, so the SDK's connection cache hands back the same
35
+ * handle the app uses. `:memory:` or absent means static-only answers.
36
+ */
37
+ db?: DevPlaneDatabase;
38
+ }
39
+ export interface DevPlane {
40
+ /** Tool names served, in catalog order. */
41
+ tools: readonly string[];
42
+ /** Serve one request mounted at `basePath` (e.g. `/api/_dev`). */
43
+ handleRequest(request: Request, basePath: string): Promise<Response>;
44
+ }
45
+ /** Positive catalog: the nine Level 2 tools plus the in-process-only one. */
46
+ export declare const DEV_PLANE_TOOL_NAMES: readonly ["registry-live", "runtime-registry", "runtime-object", "runtime-schema-diff", "migration-status", "job-health", "schedule-health", "dispatch-health", "recent-changes", "registry-drift"];
47
+ export declare function createDevPlane(options: DevPlaneOptions): DevPlane;
48
+ //# sourceMappingURL=dev-plane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-plane.d.ts","sourceRoot":"","sources":["../src/dev-plane.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA6BH,gEAAgE;AAChE,eAAO,MAAM,wBAAwB,wBAAwB,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,EAAE,CAAC,EAAE,gBAAgB,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,2CAA2C;IAC3C,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,kEAAkE;IAClE,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtE;AAID,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,qMAWvB,CAAC;AAwFX,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,QAAQ,CA+IjE"}
@@ -0,0 +1,211 @@
1
+ import { i as SERVER_VERSION, r as SERVER_NAME, t as bearerMatches } from "./http-TeoaK9Xr.js";
2
+ import { n as TOOLS } from "./tool-catalog-Zl-bcimC.js";
3
+ import { c as runtimeMigrationStatus, d as runtimeScheduleHealth, i as RUNTIME_PROVENANCE, l as runtimeRecentChanges, n as runtimeRegistry, o as runtimeDispatchHealth, p as safeErrorMessage, r as runtimeSchemaDiff, s as runtimeJobHealth, t as runtimeObject, u as runtimeRegistryDrift } from "./observation-VJgHaPps.js";
4
+ import { Server, createMcpHandler } from "@modelcontextprotocol/server";
5
+ import { snapshotRegistry } from "@happyvertical/smrt-core";
6
+ //#region src/dev-plane.ts
7
+ /**
8
+ * In-app runtime dev-plane (#2782, Level 3 of #2307).
9
+ *
10
+ * The standalone `--http` host (Level 2) boots manifests in its own process.
11
+ * This module runs *inside* the application's dev server, where the real
12
+ * decorated `ObjectRegistry` is already live and the app's own database
13
+ * configuration is at hand. It serves the same read-only runtime tools as
14
+ * Level 2 plus `registry-live`, over two surfaces on one mount:
15
+ *
16
+ * - JSON: `GET <base>` (catalog), `GET|POST <base>/<tool>` (envelope);
17
+ * arguments come from the query string or a JSON body.
18
+ * - MCP: `POST <base>/mcp`, stateless Streamable HTTP (#2147).
19
+ *
20
+ * Security boundary: the caller (a generated SvelteKit route) only mounts
21
+ * this in dev mode; every request must present `Authorization: Bearer` with
22
+ * the configured token and arrive on a loopback `Host`. No principal exists,
23
+ * so scope is fail-closed global-only. The catalog is positive: generated
24
+ * CRUD, custom actions, `do()`, and tool-backed `is()` are never mounted.
25
+ */
26
+ /** Provenance label for the application's own live registry. */
27
+ var LIVE_REGISTRY_PROVENANCE = "live (app registry)";
28
+ /** Positive catalog: the nine Level 2 tools plus the in-process-only one. */
29
+ var DEV_PLANE_TOOL_NAMES = [
30
+ "registry-live",
31
+ "runtime-registry",
32
+ "runtime-object",
33
+ "runtime-schema-diff",
34
+ "migration-status",
35
+ "job-health",
36
+ "schedule-health",
37
+ "dispatch-health",
38
+ "recent-changes",
39
+ "registry-drift"
40
+ ];
41
+ var LOOPBACK = /* @__PURE__ */ new Set([
42
+ "127.0.0.1",
43
+ "localhost",
44
+ "::1",
45
+ "[::1]"
46
+ ]);
47
+ function hostIsLoopback(request) {
48
+ const hostname = (request.headers.get("host") ?? "").replace(/:\d+$/, "").toLowerCase();
49
+ if (!LOOPBACK.has(hostname)) return false;
50
+ const origin = request.headers.get("origin");
51
+ if (!origin) return true;
52
+ try {
53
+ return LOOPBACK.has(new URL(origin).hostname.toLowerCase());
54
+ } catch {
55
+ return false;
56
+ }
57
+ }
58
+ function json(status, body, headers = {}) {
59
+ return new Response(JSON.stringify(body, null, 2), {
60
+ status,
61
+ headers: {
62
+ "content-type": "application/json",
63
+ ...headers
64
+ }
65
+ });
66
+ }
67
+ /**
68
+ * `registry-live`: snapshot the registry as the app has it right now. No
69
+ * manifest boot; the app's own imports (via `$lib/server/smrt`) registered
70
+ * these classes, and Vite's SSR HMR re-registers them on change.
71
+ */
72
+ async function registryLive(args, projectRoot) {
73
+ const objects = Array.isArray(args.objects) ? args.objects.map(String) : typeof args.objects === "string" ? args.objects.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
74
+ return {
75
+ ok: true,
76
+ coverage: null,
77
+ diagnostics: [],
78
+ data: {
79
+ provenance: LIVE_REGISTRY_PROVENANCE,
80
+ registrySource: "live",
81
+ snapshot: snapshotRegistry({
82
+ projectRoot,
83
+ objects,
84
+ detail: typeof args.detail === "boolean" ? args.detail : args.detail === "true" || Boolean(objects?.length)
85
+ })
86
+ }
87
+ };
88
+ }
89
+ async function parseArgs(request, url) {
90
+ const args = {};
91
+ for (const [key, value] of url.searchParams) if (value === "true") args[key] = true;
92
+ else if (value === "false") args[key] = false;
93
+ else if (/^-?\d+(\.\d+)?$/.test(value)) args[key] = Number(value);
94
+ else args[key] = value;
95
+ if (request.method === "POST") {
96
+ if ((request.headers.get("content-type") ?? "").includes("application/json")) {
97
+ const body = await request.json().catch(() => null);
98
+ if (body && typeof body === "object" && !Array.isArray(body)) Object.assign(args, body);
99
+ }
100
+ }
101
+ return args;
102
+ }
103
+ function createDevPlane(options) {
104
+ if (!options.token) throw new Error("createDevPlane requires a non-empty bearer token");
105
+ const projectRoot = options.projectRoot;
106
+ const dbArgs = options.db?.url && options.db.url !== ":memory:" ? {
107
+ dbUrl: options.db.url,
108
+ ...options.db.type ? { dbType: options.db.type } : {}
109
+ } : {};
110
+ const pin = (args) => {
111
+ const { projectPath: _p, dbUrl: _u, dbType: _t, ...rest } = args;
112
+ return {
113
+ ...rest,
114
+ projectPath: projectRoot,
115
+ ...dbArgs
116
+ };
117
+ };
118
+ const handlers = {
119
+ "registry-live": (args) => registryLive(args, projectRoot),
120
+ "runtime-registry": (args) => runtimeRegistry(pin(args)),
121
+ "runtime-object": (args) => runtimeObject(pin(args)),
122
+ "runtime-schema-diff": (args) => runtimeSchemaDiff(pin(args)),
123
+ "migration-status": (args) => runtimeMigrationStatus(pin(args)),
124
+ "job-health": (args) => runtimeJobHealth(pin(args)),
125
+ "schedule-health": (args) => runtimeScheduleHealth(pin(args)),
126
+ "dispatch-health": (args) => runtimeDispatchHealth(pin(args)),
127
+ "recent-changes": (args) => runtimeRecentChanges(pin(args)),
128
+ "registry-drift": (args) => runtimeRegistryDrift(pin(args))
129
+ };
130
+ const catalogTools = () => {
131
+ const known = new Map(TOOLS.map((tool) => [tool.name, tool]));
132
+ return DEV_PLANE_TOOL_NAMES.map((name) => known.get(name) ?? {
133
+ name,
134
+ description: "Sanitized snapshot of the application's live ObjectRegistry (no manifest boot; live provenance; read-only)",
135
+ inputSchema: {
136
+ type: "object",
137
+ properties: {
138
+ objects: {
139
+ type: "array",
140
+ items: { type: "string" }
141
+ },
142
+ detail: { type: "boolean" }
143
+ }
144
+ }
145
+ });
146
+ };
147
+ const mcp = createMcpHandler(() => {
148
+ const server = new Server({
149
+ name: `${SERVER_NAME}-dev-plane`,
150
+ version: SERVER_VERSION
151
+ }, { capabilities: { tools: {} } });
152
+ server.setRequestHandler("tools/list", async () => ({ tools: catalogTools() }));
153
+ server.setRequestHandler("tools/call", async (request) => {
154
+ const name = request.params.name;
155
+ const handler = handlers[name];
156
+ if (!handler) throw new Error(`Unknown dev-plane tool: ${String(name)}`);
157
+ const result = await handler(request.params.arguments ?? {});
158
+ return {
159
+ content: [{
160
+ type: "text",
161
+ text: JSON.stringify(result, null, 2)
162
+ }],
163
+ structuredContent: result
164
+ };
165
+ });
166
+ return server;
167
+ }, {
168
+ legacy: "reject",
169
+ maxSubscriptions: 0
170
+ });
171
+ return {
172
+ tools: DEV_PLANE_TOOL_NAMES,
173
+ async handleRequest(request, basePath) {
174
+ if (!hostIsLoopback(request)) return json(403, { error: "dev-plane requests must arrive on loopback" });
175
+ if (!bearerMatches(request.headers.get("authorization") ?? void 0, options.token)) return json(401, { error: "missing or invalid bearer token" }, { "www-authenticate": "Bearer realm=\"smrt dev-plane\"" });
176
+ const url = new URL(request.url);
177
+ const base = basePath.replace(/\/+$/, "");
178
+ if (!url.pathname.startsWith(base)) return json(404, { error: "not found" });
179
+ const rest = url.pathname.slice(base.length).replace(/^\/+/, "");
180
+ if (rest === "") return json(200, {
181
+ provenance: LIVE_REGISTRY_PROVENANCE,
182
+ tools: catalogTools().map((t) => ({
183
+ name: t.name,
184
+ description: t.description
185
+ })),
186
+ mcp: `${base}/mcp`
187
+ });
188
+ if (rest === "mcp") return mcp.fetch(request);
189
+ const handler = handlers[rest];
190
+ if (!handler || request.method !== "GET" && request.method !== "POST") return json(404, { error: `unknown dev-plane tool: ${rest}` });
191
+ try {
192
+ return json(200, await handler(await parseArgs(request, url)));
193
+ } catch (error) {
194
+ return json(200, {
195
+ ok: false,
196
+ coverage: null,
197
+ diagnostics: [{
198
+ severity: "warning",
199
+ code: "dev_plane_tool_error",
200
+ message: safeErrorMessage(error)
201
+ }],
202
+ data: { provenance: RUNTIME_PROVENANCE }
203
+ });
204
+ }
205
+ }
206
+ };
207
+ }
208
+ //#endregion
209
+ export { DEV_PLANE_TOOL_NAMES, LIVE_REGISTRY_PROVENANCE, createDevPlane };
210
+
211
+ //# sourceMappingURL=dev-plane.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-plane.js","names":[],"sources":["../src/dev-plane.ts"],"sourcesContent":["/**\n * In-app runtime dev-plane (#2782, Level 3 of #2307).\n *\n * The standalone `--http` host (Level 2) boots manifests in its own process.\n * This module runs *inside* the application's dev server, where the real\n * decorated `ObjectRegistry` is already live and the app's own database\n * configuration is at hand. It serves the same read-only runtime tools as\n * Level 2 plus `registry-live`, over two surfaces on one mount:\n *\n * - JSON: `GET <base>` (catalog), `GET|POST <base>/<tool>` (envelope);\n * arguments come from the query string or a JSON body.\n * - MCP: `POST <base>/mcp`, stateless Streamable HTTP (#2147).\n *\n * Security boundary: the caller (a generated SvelteKit route) only mounts\n * this in dev mode; every request must present `Authorization: Bearer` with\n * the configured token and arrive on a loopback `Host`. No principal exists,\n * so scope is fail-closed global-only. The catalog is positive: generated\n * CRUD, custom actions, `do()`, and tool-backed `is()` are never mounted.\n */\n\nimport { snapshotRegistry } from '@happyvertical/smrt-core';\nimport {\n type CallToolResult,\n createMcpHandler,\n Server,\n type Tool,\n} from '@modelcontextprotocol/server';\nimport { bearerMatches } from './http.js';\nimport { SERVER_NAME, SERVER_VERSION } from './server-info.js';\nimport { TOOLS } from './tool-catalog.js';\nimport { safeErrorMessage } from './tools/runtime/connection.js';\nimport {\n runtimeObject,\n runtimeRegistry,\n runtimeSchemaDiff,\n} from './tools/runtime/observation.js';\nimport {\n RUNTIME_PROVENANCE,\n type RuntimeToolEnvelope,\n runtimeDispatchHealth,\n runtimeJobHealth,\n runtimeMigrationStatus,\n runtimeRecentChanges,\n runtimeRegistryDrift,\n runtimeScheduleHealth,\n} from './tools/runtime/tools.js';\n\n/** Provenance label for the application's own live registry. */\nexport const LIVE_REGISTRY_PROVENANCE = 'live (app registry)';\n\nexport interface DevPlaneDatabase {\n url?: string;\n type?: string;\n}\n\nexport interface DevPlaneOptions {\n /** Bearer token every request must present. */\n token: string;\n /** Project root; used only to relativize paths in snapshots. */\n projectRoot?: string;\n /**\n * The app's database configuration (typically `getSmrtConfig(name).db`\n * from the generated `$lib/server/smrt`). Passed to the runtime tools as\n * `dbUrl`/`dbType`, so the SDK's connection cache hands back the same\n * handle the app uses. `:memory:` or absent means static-only answers.\n */\n db?: DevPlaneDatabase;\n}\n\nexport interface DevPlane {\n /** Tool names served, in catalog order. */\n tools: readonly string[];\n /** Serve one request mounted at `basePath` (e.g. `/api/_dev`). */\n handleRequest(request: Request, basePath: string): Promise<Response>;\n}\n\ntype ToolHandler = (args: Record<string, unknown>) => Promise<unknown>;\n\n/** Positive catalog: the nine Level 2 tools plus the in-process-only one. */\nexport const DEV_PLANE_TOOL_NAMES = [\n 'registry-live',\n 'runtime-registry',\n 'runtime-object',\n 'runtime-schema-diff',\n 'migration-status',\n 'job-health',\n 'schedule-health',\n 'dispatch-health',\n 'recent-changes',\n 'registry-drift',\n] as const;\n\nconst LOOPBACK = new Set(['127.0.0.1', 'localhost', '::1', '[::1]']);\n\nfunction hostIsLoopback(request: Request): boolean {\n const host = request.headers.get('host') ?? '';\n const hostname = host.replace(/:\\d+$/, '').toLowerCase();\n if (!LOOPBACK.has(hostname)) return false;\n const origin = request.headers.get('origin');\n if (!origin) return true;\n try {\n return LOOPBACK.has(new URL(origin).hostname.toLowerCase());\n } catch {\n return false;\n }\n}\n\nfunction json(\n status: number,\n body: unknown,\n headers: Record<string, string> = {},\n): Response {\n return new Response(JSON.stringify(body, null, 2), {\n status,\n headers: { 'content-type': 'application/json', ...headers },\n });\n}\n\n/**\n * `registry-live`: snapshot the registry as the app has it right now. No\n * manifest boot; the app's own imports (via `$lib/server/smrt`) registered\n * these classes, and Vite's SSR HMR re-registers them on change.\n */\nasync function registryLive(\n args: Record<string, unknown>,\n projectRoot: string | undefined,\n): Promise<RuntimeToolEnvelope> {\n const objects = Array.isArray(args.objects)\n ? args.objects.map(String)\n : typeof args.objects === 'string'\n ? args.objects\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n : undefined;\n const snapshot = snapshotRegistry({\n projectRoot,\n objects,\n detail:\n typeof args.detail === 'boolean'\n ? args.detail\n : args.detail === 'true' || Boolean(objects?.length),\n });\n return {\n ok: true,\n coverage: null,\n diagnostics: [],\n data: {\n provenance: LIVE_REGISTRY_PROVENANCE,\n registrySource: 'live',\n snapshot,\n },\n };\n}\n\nasync function parseArgs(\n request: Request,\n url: URL,\n): Promise<Record<string, unknown>> {\n const args: Record<string, unknown> = {};\n for (const [key, value] of url.searchParams) {\n if (value === 'true') args[key] = true;\n else if (value === 'false') args[key] = false;\n else if (/^-?\\d+(\\.\\d+)?$/.test(value)) args[key] = Number(value);\n else args[key] = value;\n }\n if (request.method === 'POST') {\n const type = request.headers.get('content-type') ?? '';\n if (type.includes('application/json')) {\n const body = (await request.json().catch(() => null)) as unknown;\n if (body && typeof body === 'object' && !Array.isArray(body)) {\n Object.assign(args, body as Record<string, unknown>);\n }\n }\n }\n return args;\n}\n\nexport function createDevPlane(options: DevPlaneOptions): DevPlane {\n if (!options.token) {\n throw new Error('createDevPlane requires a non-empty bearer token');\n }\n const projectRoot = options.projectRoot;\n const dbArgs =\n options.db?.url && options.db.url !== ':memory:'\n ? {\n dbUrl: options.db.url,\n ...(options.db.type ? { dbType: options.db.type } : {}),\n }\n : {};\n\n // Every call is pinned to the app's root and database; client-supplied\n // projectPath/dbUrl/dbType are dropped so a caller cannot re-point it.\n const pin = (args: Record<string, unknown>): Record<string, unknown> => {\n const { projectPath: _p, dbUrl: _u, dbType: _t, ...rest } = args;\n return { ...rest, projectPath: projectRoot, ...dbArgs };\n };\n\n const handlers: Record<(typeof DEV_PLANE_TOOL_NAMES)[number], ToolHandler> = {\n 'registry-live': (args) => registryLive(args, projectRoot),\n 'runtime-registry': (args) => runtimeRegistry(pin(args) as never),\n 'runtime-object': (args) => runtimeObject(pin(args) as never),\n 'runtime-schema-diff': (args) => runtimeSchemaDiff(pin(args) as never),\n 'migration-status': (args) => runtimeMigrationStatus(pin(args) as never),\n 'job-health': (args) => runtimeJobHealth(pin(args) as never),\n 'schedule-health': (args) => runtimeScheduleHealth(pin(args) as never),\n 'dispatch-health': (args) => runtimeDispatchHealth(pin(args) as never),\n 'recent-changes': (args) => runtimeRecentChanges(pin(args) as never),\n 'registry-drift': (args) => runtimeRegistryDrift(pin(args) as never),\n };\n\n const catalogTools = (): Tool[] => {\n const known = new Map(TOOLS.map((tool) => [tool.name, tool]));\n return DEV_PLANE_TOOL_NAMES.map(\n (name) =>\n known.get(name) ?? {\n name,\n description:\n \"Sanitized snapshot of the application's live ObjectRegistry (no manifest boot; live provenance; read-only)\",\n inputSchema: {\n type: 'object',\n properties: {\n objects: { type: 'array', items: { type: 'string' } },\n detail: { type: 'boolean' },\n },\n },\n },\n ) as Tool[];\n };\n\n const mcp = createMcpHandler(\n () => {\n const server = new Server(\n { name: `${SERVER_NAME}-dev-plane`, version: SERVER_VERSION },\n { capabilities: { tools: {} } },\n );\n server.setRequestHandler('tools/list', async () => ({\n tools: catalogTools(),\n }));\n server.setRequestHandler('tools/call', async (request) => {\n const name = request.params\n .name as (typeof DEV_PLANE_TOOL_NAMES)[number];\n const handler = handlers[name];\n if (!handler)\n throw new Error(`Unknown dev-plane tool: ${String(name)}`);\n const result = await handler(\n (request.params.arguments ?? {}) as Record<string, unknown>,\n );\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n structuredContent: result as Record<string, unknown>,\n } satisfies CallToolResult;\n });\n return server;\n },\n { legacy: 'reject', maxSubscriptions: 0 },\n );\n\n return {\n tools: DEV_PLANE_TOOL_NAMES,\n async handleRequest(request, basePath) {\n if (!hostIsLoopback(request)) {\n return json(403, {\n error: 'dev-plane requests must arrive on loopback',\n });\n }\n if (\n !bearerMatches(\n request.headers.get('authorization') ?? undefined,\n options.token,\n )\n ) {\n return json(\n 401,\n { error: 'missing or invalid bearer token' },\n {\n 'www-authenticate': 'Bearer realm=\"smrt dev-plane\"',\n },\n );\n }\n const url = new URL(request.url);\n const base = basePath.replace(/\\/+$/, '');\n if (!url.pathname.startsWith(base))\n return json(404, { error: 'not found' });\n const rest = url.pathname.slice(base.length).replace(/^\\/+/, '');\n if (rest === '') {\n return json(200, {\n provenance: LIVE_REGISTRY_PROVENANCE,\n tools: catalogTools().map((t) => ({\n name: t.name,\n description: t.description,\n })),\n mcp: `${base}/mcp`,\n });\n }\n if (rest === 'mcp') {\n return mcp.fetch(request);\n }\n const handler = handlers[rest as (typeof DEV_PLANE_TOOL_NAMES)[number]];\n if (!handler || (request.method !== 'GET' && request.method !== 'POST')) {\n return json(404, { error: `unknown dev-plane tool: ${rest}` });\n }\n try {\n return json(200, await handler(await parseArgs(request, url)));\n } catch (error) {\n return json(200, {\n ok: false,\n coverage: null,\n diagnostics: [\n {\n severity: 'warning',\n code: 'dev_plane_tool_error',\n // Same redaction the runtime tools apply to driver errors.\n message: safeErrorMessage(error),\n },\n ],\n data: { provenance: RUNTIME_PROVENANCE },\n });\n }\n },\n };\n}\n"],"mappings":"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"}