@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.
Files changed (39) hide show
  1. package/AGENTS.md +7 -9
  2. package/README.md +88 -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 +1 -0
  10. package/dist/http.d.ts.map +1 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +31 -850
  13. package/dist/index.js.map +1 -1
  14. package/dist/knowledge/index.d.ts +27 -1
  15. package/dist/knowledge/index.d.ts.map +1 -1
  16. package/dist/{knowledge-CY6sQzpj.js → knowledge-BOsSAdPo.js} +81 -713
  17. package/dist/knowledge-BOsSAdPo.js.map +1 -0
  18. package/dist/knowledge.js +2 -2
  19. package/dist/observation-VJgHaPps.js +802 -0
  20. package/dist/observation-VJgHaPps.js.map +1 -0
  21. package/dist/runtime.d.ts +21 -0
  22. package/dist/runtime.d.ts.map +1 -0
  23. package/dist/runtime.js +18 -0
  24. package/dist/runtime.js.map +1 -0
  25. package/dist/tool-catalog-Zl-bcimC.js +643 -0
  26. package/dist/tool-catalog-Zl-bcimC.js.map +1 -0
  27. package/dist/tool-catalog.d.ts.map +1 -1
  28. package/dist/tools/introspect-project.d.ts +8 -0
  29. package/dist/tools/introspect-project.d.ts.map +1 -1
  30. package/dist/tools/runtime/boot.d.ts +10 -0
  31. package/dist/tools/runtime/boot.d.ts.map +1 -1
  32. package/dist/tools/runtime/connection.d.ts +19 -0
  33. package/dist/tools/runtime/connection.d.ts.map +1 -1
  34. package/dist/tools/runtime/observation.d.ts +12 -0
  35. package/dist/tools/runtime/observation.d.ts.map +1 -1
  36. package/dist/tools/runtime/tools.d.ts.map +1 -1
  37. package/package.json +13 -5
  38. package/skills/smrt-code-review/SKILL.md +1 -1
  39. 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
- | `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) |
@@ -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
- `smrt-architecture`/`smrt-review`/`reflect-*` results and prompt bundles.
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 `smrt-review` for
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 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
  |-----------|------|----------|-------------|
@@ -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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"}