@happyvertical/smrt-dev-mcp 0.47.2 → 0.49.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/AGENTS.md +7 -9
- package/README.md +88 -66
- package/dist/dev-plane.d.ts +48 -0
- package/dist/dev-plane.d.ts.map +1 -0
- package/dist/dev-plane.js +211 -0
- package/dist/dev-plane.js.map +1 -0
- package/dist/http-TeoaK9Xr.js +168 -0
- package/dist/http-TeoaK9Xr.js.map +1 -0
- package/dist/http.d.ts +1 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -850
- package/dist/index.js.map +1 -1
- package/dist/knowledge/index.d.ts +27 -1
- package/dist/knowledge/index.d.ts.map +1 -1
- package/dist/{knowledge-CY6sQzpj.js → knowledge-BOsSAdPo.js} +81 -713
- package/dist/knowledge-BOsSAdPo.js.map +1 -0
- package/dist/knowledge.js +2 -2
- package/dist/observation-VJgHaPps.js +802 -0
- package/dist/observation-VJgHaPps.js.map +1 -0
- package/dist/runtime.d.ts +21 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +18 -0
- package/dist/runtime.js.map +1 -0
- package/dist/tool-catalog-Zl-bcimC.js +643 -0
- package/dist/tool-catalog-Zl-bcimC.js.map +1 -0
- package/dist/tool-catalog.d.ts.map +1 -1
- package/dist/tools/introspect-project.d.ts +8 -0
- package/dist/tools/introspect-project.d.ts.map +1 -1
- package/dist/tools/runtime/boot.d.ts +10 -0
- package/dist/tools/runtime/boot.d.ts.map +1 -1
- package/dist/tools/runtime/connection.d.ts +19 -0
- package/dist/tools/runtime/connection.d.ts.map +1 -1
- package/dist/tools/runtime/observation.d.ts +12 -0
- package/dist/tools/runtime/observation.d.ts.map +1 -1
- package/dist/tools/runtime/tools.d.ts.map +1 -1
- package/package.json +13 -5
- package/skills/smrt-code-review/SKILL.md +1 -1
- package/dist/knowledge-CY6sQzpj.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
|
-
| `
|
|
17
|
-
| `
|
|
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
|
-
| `
|
|
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) |
|
|
@@ -100,7 +96,7 @@ Per package, objects resolve in this order, and the winner is recorded in
|
|
|
100
96
|
The index exposes `coverage` and `diagnostics` (added in `schemaVersion: 2`). Zero
|
|
101
97
|
discovered objects is an **error-grade** diagnostic that names the roots and
|
|
102
98
|
artifact paths checked plus the fix, and it propagates into
|
|
103
|
-
`
|
|
99
|
+
`build-context`/`reflect-*` results and prompt bundles.
|
|
104
100
|
|
|
105
101
|
A workspace-root package has an empty `relativeDirectory`, so package paths are
|
|
106
102
|
built with `packageRelativePath`/`packageDocPaths` rather than interpolation —
|
|
@@ -116,7 +112,7 @@ with YAML frontmatter (`name` and `description`) and harness-neutral body text.
|
|
|
116
112
|
Skill-aware harnesses can parse the frontmatter; other harnesses can ignore it.
|
|
117
113
|
|
|
118
114
|
- `skills/smrt-code-review/SKILL.md` — downstream SMRT code review workflow.
|
|
119
|
-
Agents should fetch it with `get-agent-skill`, then call `
|
|
115
|
+
Agents should fetch it with `get-agent-skill`, then call `build-context` (`task: review`) for
|
|
120
116
|
deterministic context, inspect the actual diff, and produce a findings-first
|
|
121
117
|
review.
|
|
122
118
|
|
|
@@ -147,6 +143,8 @@ launcher or a small wrapper script with an absolute Node path.
|
|
|
147
143
|
- `skills/smrt-code-review/SKILL.md` — downstream SMRT review procedure
|
|
148
144
|
- `src/tools/generate-smrt-class.ts` — class generation logic and package-ready templates
|
|
149
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)
|
|
150
148
|
- `src/tools/review-smrt-project.ts` — advisory ecosystem-alignment checks for downstream projects
|
|
151
149
|
|
|
152
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
|
|
152
|
-
exceeds its character budget
|
|
153
|
-
|
|
154
|
-
budget
|
|
155
|
-
|
|
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
|
-
### `
|
|
352
|
+
### `build-context`
|
|
341
353
|
|
|
342
|
-
|
|
343
|
-
`
|
|
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
|
-
| `
|
|
349
|
-
| `
|
|
350
|
-
| `
|
|
351
|
-
| `
|
|
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
|
-
|
|
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
|
-
|
|
435
|
-
|
|
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
|
|-----------|------|----------|-------------|
|
|
@@ -548,6 +521,8 @@ provenance (`booted (registry)`); read-only.
|
|
|
548
521
|
| `projectPath` | `string` | No | Project root to boot manifests from (default: the server working directory; ignored by the HTTP host, which boots once) |
|
|
549
522
|
| `objects` | `string[]` | No | Restrict field/method detail to these simple or qualified object names |
|
|
550
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) |
|
|
551
526
|
|
|
552
527
|
### `runtime-object`
|
|
553
528
|
|
|
@@ -592,6 +567,17 @@ anywhere → every runtime tool returns a successful static-only result
|
|
|
592
567
|
(`provenance: 'static'`, `connected: false`) and the server starts and serves
|
|
593
568
|
all static tools unaffected.
|
|
594
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
|
+
|
|
595
581
|
**Provenance labeling.** Live results carry `provenance: 'runtime (live DB)'`;
|
|
596
582
|
static-only results carry `provenance: 'static'`. Never conflate the two: the
|
|
597
583
|
manifest reports what the code declares, runtime tools report what the running
|
|
@@ -632,6 +618,42 @@ SMRT_DEV_MCP_TOKEN=dev-secret smrt-dev-mcp --http --port 3939 --project .
|
|
|
632
618
|
# → [smrt-dev-mcp] runtime dev-plane listening at http://127.0.0.1:3939/mcp
|
|
633
619
|
```
|
|
634
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
|
+
|
|
635
657
|
## MCP Resources And Prompts
|
|
636
658
|
|
|
637
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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"}
|