@golemui/gui-mcp 1.0.0-rc.2 → 1.0.0-rc.4

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/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 1.0.0-rc.3 (2026-06-13)
2
+
3
+ This was a version bump only for gui-mcp to align it with other projects, there were no code changes.
4
+
5
+ ## 1.0.0-rc.2 (2026-06-10)
6
+
7
+ This was a version bump only for gui-mcp to align it with other projects, there were no code changes.
8
+
1
9
  ## 1.0.0-rc.1 (2026-06-10)
2
10
 
3
11
  This was a version bump only for gui-mcp to align it with other projects, there were no code changes.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 GolemUI S.L.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -9,6 +9,30 @@ strict enough that one wrong property name breaks the runtime. This server close
9
9
  your AI calls it to **validate** what it wrote and to **generate** forms from existing
10
10
  JSON Schemas or OpenAPI operations, with the bundled GolemUI schemas as the source of truth.
11
11
 
12
+ ## Two entry points (one surface, two ways to author it)
13
+
14
+ A GolemUI form can be written two ways, and the MCP serves both:
15
+
16
+ - a **JSON form definition**: the serializable object `{ form: [...widgets], states?: {...} }`;
17
+ - **`gui.*` DX code**: the fluent TypeScript builder that _produces_ that same definition.
18
+
19
+ There is no toggle. On connect the server sends one block of guidance (the MCP `initialize.instructions`
20
+ field, `SERVER_INSTRUCTIONS` in [`src/cli.ts`](./src/cli.ts)) and the agent self-routes by what it is
21
+ producing:
22
+
23
+ 1. **JSON path**: generate or hand-author, then **always finish with `json_validate_form_definition`**.
24
+ 2. **`gui.*` path**: call **`dx_list_factories` first** (the complete reference), write the form, then
25
+ **always finish with `dx_check_code`**.
26
+
27
+ The two terminal checks are not interchangeable: `dx_check_code` validates `gui.*` _code_,
28
+ `json_validate_form_definition` validates a JSON _object_. Each tool's own `description` reinforces the routing
29
+ (e.g. `json_get_widget_spec` tells a `gui.*` author it isn't needed). To read what a client actually sees, run
30
+ `npm run start:mcp` (the MCP Inspector).
31
+
32
+ The split is structural, not just textual: the two paths live in separate modules
33
+ ([`src/json/`](./src/json) and [`src/dx/`](./src/dx)) over a small shared surface
34
+ ([`src/shared/`](./src/shared)); neither imports the other.
35
+
12
36
  ## Install
13
37
 
14
38
  The server is a standalone Node CLI distributed on npm. Add it to your IDE's MCP config —
@@ -46,7 +70,7 @@ npx -y @golemui/gui-mcp < /dev/null
46
70
 
47
71
  ## Tools
48
72
 
49
- ### `validate_form_definition`
73
+ ### `json_validate_form_definition`
50
74
 
51
75
  Validates a GolemUI form definition against the bundled JSON Schemas. Returns
52
76
  `{ valid: true }` on success, or a structured list of errors with JSON Pointer paths
@@ -56,7 +80,7 @@ like missing `$form.` prefixes, single `=` in equality checks, and unbalanced br
56
80
 
57
81
  **Input:** `{ formDefinition: { form: [...], states?: {...} } }`
58
82
 
59
- ### `generate_from_json_schema`
83
+ ### `json_generate_from_schema`
60
84
 
61
85
  Maps a JSON Schema (the form-data shape, e.g. a Zod-derived schema) into a GolemUI
62
86
  form definition. Handles strings (with `format` → specialized widgets), numbers,
@@ -66,7 +90,7 @@ not be mapped.
66
90
 
67
91
  **Input:** `{ jsonSchema, submitAction?, submitLabel?, layout? }`
68
92
 
69
- ### `generate_from_openapi`
93
+ ### `json_generate_from_openapi`
70
94
 
71
95
  Resolves an OpenAPI 3.x operation (e.g. `"POST /users"` or an `operationId`), dereferences
72
96
  its request body schema, and emits a validated GolemUI form. Falls back to operation
@@ -74,7 +98,7 @@ parameters when no JSON request body is present.
74
98
 
75
99
  **Input:** `{ document | documentUrl, operation, submitAction?, submitLabel? }`
76
100
 
77
- ### `get_widget_spec`
101
+ ### `json_get_widget_spec`
78
102
 
79
103
  Returns the JSON Schema, kind, a minimal working example, and authoring notes for a
80
104
  single GolemUI widget. Cheaper than dumping the whole API into the model's context.
@@ -84,12 +108,42 @@ single GolemUI widget. Cheaper than dumping the whole API into the model's conte
84
108
 
85
109
  ### `get_concept`
86
110
 
87
- Returns a detailed guide for a cross-cutting concept - things that span multiple widgets
88
- and affect the whole form. Use it when you need state-suffixed props
89
- (`"label.stateName": "..."`) or to reuse a condition across multiple widgets via
90
- `include`/`exclude`. Currently supported: `"states"`, `"string-interpolation"`.
111
+ Returns a detailed guide for a cross-cutting concept — things that span multiple widgets
112
+ and affect the whole form: conditional rendering (`include`/`exclude`, named-state and
113
+ inline `when`), state-suffixed props (`"label.stateName": "..."`), the reactive scope
114
+ (`$form`, `$meta`, `$errors`, `$formIsInvalid`), and widget icons.
115
+
116
+ **Input:** `{ concept }` — one of `"states"`, `"string-interpolation"`, `"reactive-scope"`, `"icons"`
117
+
118
+ > The five tools above serve the **JSON** surface. The three below serve the **`gui.*`** (DX code) surface —
119
+ > see [Two entry points](#two-entry-points-one-surface-two-ways-to-author-it).
120
+
121
+ ### `dx_list_factories`
91
122
 
92
- **Input:** `{ concept }` - one of `"states"`, `"string-interpolation"`
123
+ **Call this first when writing `gui.*` code.** Returns the complete `gui.*` DX reference in one call: every
124
+ factory with its namespace, calling convention, a **compile-verified** example, and its gotchas — plus the
125
+ cross-cutting patterns and the common authoring rules. Its imports + render snippet are **tailored to your
126
+ target framework** (`GOLEMUI_FRAMEWORK`). Self-sufficient for most forms; keep it in context and write from it.
127
+
128
+ **Input:** none.
129
+
130
+ ### `dx_get_spec`
131
+
132
+ A rare single-factory deep-dive — one factory's calling convention, example, and notes. Usually unneeded
133
+ (`dx_list_factories` already carries every factory); reach here only to re-confirm one in isolation.
134
+
135
+ **Input:** `{ factory }` — the camelCase name (`textInput`, `dropdown`, `radiogroup`, `button`, …).
136
+
137
+ ### `dx_check_code`
138
+
139
+ **The `gui.*` terminal check** — the counterpart of `json_validate_form_definition` for _code_ instead of a JSON
140
+ _object_. Type-checks the snippet against the **real `@golemui` type declarations** (compile-is-truth: GolemUI
141
+ isn't in any model's training data, so generated `gui.*` is often a confident fabrication that doesn't
142
+ compile). Also catches two compiler-invisible footguns — a misplaced `include`/`exclude` on a `gui.*` spread,
143
+ and reactive-expression mistakes in `when` strings. Returns `{ ok, diagnostics }`; each diagnostic carries a
144
+ fix `hint`. Treat `ok: false` as blocking.
145
+
146
+ **Input:** `{ code }` — the `gui.*` snippet (a bare `gui.inputs.*` array is fine; the import is added if missing).
93
147
 
94
148
  ## Library usage
95
149
 
@@ -126,17 +180,6 @@ const { form } = await generateFromOpenapi({
126
180
  The tool descriptor objects (`VALIDATE_FORM_DEFINITION_TOOL`, `GENERATE_FROM_JSON_SCHEMA_TOOL`, ...)
127
181
  are also exported if you want to register the tools in your own MCP server.
128
182
 
129
- ## How it stays accurate
130
-
131
- The server ships a frozen snapshot of the GolemUI JSON Schemas inside its npm package,
132
- version-locked to a specific GolemUI release. A CI check in this monorepo
133
- (`npm run check:mcp-schemas`) fails if the snapshot drifts from the source schemas in
134
- `@golemui/gui-shared`, so a published `@golemui/gui-mcp@X.Y.Z` always validates
135
- against the exact same schema definitions as `@golemui/gui-*@X.Y.Z`.
136
-
137
- No LLM calls happen inside this server — every tool is deterministic. The MCP is the
138
- _grounding layer_ the host IDE's model calls into.
139
-
140
183
  ## Development
141
184
 
142
185
  ### Interactive testing with MCP Inspector
@@ -174,7 +217,7 @@ Create or edit the project-level MCP config at .mcp.json in the workspace root:
174
217
  }
175
218
  ```
176
219
 
177
- Then reload the VS Code window (Cmd+Shift+P -> "Developer: Reload Window"). The 4 tools will appear in Claude's tool list for this workspace.
220
+ Then reload the VS Code window (Cmd+Shift+P -> "Developer: Reload Window"). The tools will appear in Claude's tool list for this workspace.
178
221
 
179
222
  Remove the entry from .mcp.json when done.
180
223
 
@@ -182,6 +225,4 @@ Remove the entry from .mcp.json when done.
182
225
 
183
226
  ```bash
184
227
  npx nx run gui-mcp:vite:test # run the test suite
185
- npm run sync:mcp-schemas # refresh bundled schemas from libs/gui/shared
186
- npm run check:mcp-schemas # CI mode — exits non-zero if out of sync
187
228
  ```
package/cli.js CHANGED
@@ -5,7 +5,37 @@ import { fileURLToPath } from "node:url";
5
5
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
6
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
7
  import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
8
- import { V as VALIDATE_FORM_DEFINITION_TOOL, G as GENERATE_FROM_JSON_SCHEMA_TOOL, a as GENERATE_FROM_OPENAPI_TOOL, c as GET_WIDGET_SPEC_TOOL, b as GET_CONCEPT_TOOL, e as getConcept, f as getWidgetSpec, d as generateFromOpenapi, g as generateFromJsonSchema, v as validateFormDefinition } from "./get-concept-B7s_l8Qs.js";
8
+ import { r as resolveDxFramework, o as listDxFactoriesCatalog, b as DX_LIST_FACTORIES_TOOL, l as getDxSpec, a as DX_GET_SPEC_TOOL, g as checkDxCode, D as DX_CHECK_CODE_TOOL, v as validateFormDefinition, f as JSON_VALIDATE_FORM_DEFINITION_TOOL, i as generateFromJsonSchema, d as JSON_GENERATE_FROM_SCHEMA_TOOL, j as generateFromOpenapi, J as JSON_GENERATE_FROM_OPENAPI_TOOL, m as getWidgetSpec, e as JSON_GET_WIDGET_SPEC_TOOL, k as getConcept, G as GET_CONCEPT_TOOL } from "./get-concept-DMoitPWv.js";
9
+ const DX_INSTRUCTIONS = "Writing GolemUI as DX code (the `gui.*` fluent builder in TypeScript) instead of a JSON definition? GolemUI is not in any model training data, so `gui.*` code is easy to fabricate — do NOT guess the API. FIRST call `dx_list_factories` once: it is the COMPLETE reference — every factory with its signature, a compile-verified example, and its gotchas, plus the cross-cutting patterns and common rules. Its imports + render snippet are tailored to your target framework (" + resolveDxFramework() + ") — use them verbatim; import `gui` ONLY from `@golemui/gui-shared`, never hand-write raw `{ kind, type, path }` widget JSON or cast to `any`. Keep it in context and write your whole form from it; it is self-sufficient for most forms. `dx_get_spec` is only a rare single-factory deep-dive — you usually will not need it, and you do NOT need `json_get_widget_spec` here (that is the JSON surface). Then ALWAYS finish by calling `dx_check_code` with the snippet — it type-checks against the real `@golemui` declarations and returns `{ ok, diagnostics }` (each with a fix `hint` for recognized mistakes). Treat `ok: false` as blocking: apply the fixes and re-check until `ok` is true. Use `dx_check_code` for `gui.*` *code* and `json_validate_form_definition` for a JSON *definition object* — they are not interchangeable.\n\n";
10
+ function defineTool(tool, handler) {
11
+ return { tool, run: (args) => handler(args) };
12
+ }
13
+ function ok(payload) {
14
+ return {
15
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }]
16
+ };
17
+ }
18
+ function err(message) {
19
+ return {
20
+ isError: true,
21
+ content: [{ type: "text", text: message }]
22
+ };
23
+ }
24
+ const dxTools = [
25
+ // `dx_list_factories` takes no arguments — it defaults the framework from the env, so
26
+ // its handler ignores the (empty) MCP arguments object.
27
+ defineTool(DX_LIST_FACTORIES_TOOL, () => listDxFactoriesCatalog()),
28
+ defineTool(DX_GET_SPEC_TOOL, getDxSpec),
29
+ defineTool(DX_CHECK_CODE_TOOL, checkDxCode)
30
+ ];
31
+ const JSON_INSTRUCTIONS = '1. Starting from an existing schema? Use a generator — both return a pre-validated definition, so check the returned `unmapped` list and surface anything left over to the user. For a raw JSON Schema (e.g. an API request body), call `json_generate_from_schema`. For an OpenAPI 3.x spec, call `json_generate_from_openapi`: pass `operation` as "METHOD /path" (e.g. "POST /users") or an exact operationId, plus the spec as a parsed `document` or a `documentUrl` to fetch — it resolves the operation\'s request body, dereferences `$ref`s, and falls back to the operation\'s parameters when there is no request body.\n2. Building or editing by hand? Look up a single widget with `json_get_widget_spec` (its `kind`, `props`, and `validator` shape), and cross-cutting behavior that spans widgets — conditional rendering, per-state prop overrides — with `get_concept`.\n3. ALWAYS finish by calling `json_validate_form_definition`. It checks the definition against the bundled JSON Schemas and returns `{ valid, errors, warnings, expressionWarnings }`. Treat `errors` as blocking: fix them and re-validate until `valid` is true. `warnings` (likely-custom widgets) and `expressionWarnings` (linted reactive expressions) are advisory — surface them, but they do not flip `valid`.\n\n';
32
+ const jsonTools = [
33
+ defineTool(JSON_VALIDATE_FORM_DEFINITION_TOOL, validateFormDefinition),
34
+ defineTool(JSON_GENERATE_FROM_SCHEMA_TOOL, generateFromJsonSchema),
35
+ defineTool(JSON_GENERATE_FROM_OPENAPI_TOOL, generateFromOpenapi),
36
+ defineTool(JSON_GET_WIDGET_SPEC_TOOL, getWidgetSpec)
37
+ ];
38
+ const sharedTools = [defineTool(GET_CONCEPT_TOOL, getConcept)];
9
39
  function readPackageMeta() {
10
40
  const here = dirname(fileURLToPath(import.meta.url));
11
41
  for (const candidate of [join(here, "package.json"), join(here, "..", "package.json")]) {
@@ -18,51 +48,28 @@ function readPackageMeta() {
18
48
  return { name: "@golemui/gui-mcp", version: "0.0.0" };
19
49
  }
20
50
  const { name: PKG_NAME, version: PKG_VERSION } = readPackageMeta();
21
- const TOOLS = [
22
- VALIDATE_FORM_DEFINITION_TOOL,
23
- GENERATE_FROM_JSON_SCHEMA_TOOL,
24
- GENERATE_FROM_OPENAPI_TOOL,
25
- GET_WIDGET_SPEC_TOOL,
26
- GET_CONCEPT_TOOL
27
- ];
28
- const SERVER_INSTRUCTIONS = 'This server builds and validates GolemUI form definitions — declarative, JSON-serializable forms shaped as `{ form: [...widgets], states?: {...} }`. Its job is to help you produce a form definition that is guaranteed correct before the user pastes it into their codebase.\n\nRecommended workflow:\n1. Starting from an existing schema? Use a generator — both return a pre-validated definition, so check the returned `unmapped` list and surface anything left over to the user. For a raw JSON Schema (e.g. an API request body), call `generate_from_json_schema`. For an OpenAPI 3.x spec, call `generate_from_openapi`: pass `operation` as "METHOD /path" (e.g. "POST /users") or an exact operationId, plus the spec as a parsed `document` or a `documentUrl` to fetch — it resolves the operation\'s request body, dereferences `$ref`s, and falls back to the operation\'s parameters when there is no request body.\n2. Building or editing by hand? Look up a single widget with `get_widget_spec` (its `kind`, `props`, and `validator` shape), and cross-cutting behavior that spans widgets — conditional rendering, per-state prop overrides — with `get_concept`.\n3. ALWAYS finish by calling `validate_form_definition`. It checks the definition against the bundled JSON Schemas and returns `{ valid, errors, warnings, expressionWarnings }`. Treat `errors` as blocking: fix them and re-validate until `valid` is true. `warnings` (likely-custom widgets) and `expressionWarnings` (linted reactive expressions) are advisory — surface them, but they do not flip `valid`.\n\nDo not hand a form definition to the user until `validate_form_definition` reports `valid: true`.';
51
+ const TOOL_ENTRIES = [...jsonTools, ...sharedTools, ...dxTools];
52
+ const TOOL_BY_NAME = new Map(TOOL_ENTRIES.map((e) => [e.tool.name, e]));
53
+ const PREAMBLE = "This server builds and validates GolemUI form definitions — declarative, JSON-serializable forms shaped as `{ form: [...widgets], states?: {...} }`. Its job is to help you produce a form definition that is guaranteed correct before the user pastes it into their codebase.\n\nRecommended workflow:\n";
54
+ const CLOSER = "Do not hand a form definition to the user until `json_validate_form_definition` reports `valid: true`.";
55
+ const SERVER_INSTRUCTIONS = PREAMBLE + JSON_INSTRUCTIONS + DX_INSTRUCTIONS + CLOSER;
29
56
  const server = new Server(
30
57
  { name: PKG_NAME, version: PKG_VERSION },
31
58
  { capabilities: { tools: {} }, instructions: SERVER_INSTRUCTIONS }
32
59
  );
33
- server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
60
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
61
+ tools: TOOL_ENTRIES.map((e) => e.tool)
62
+ }));
34
63
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
35
64
  const { name, arguments: args } = request.params;
65
+ const entry = TOOL_BY_NAME.get(name);
66
+ if (!entry) return err(`Unknown tool: ${name}`);
36
67
  try {
37
- switch (name) {
38
- case "validate_form_definition":
39
- return ok(validateFormDefinition(args));
40
- case "generate_from_json_schema":
41
- return ok(generateFromJsonSchema(args));
42
- case "generate_from_openapi":
43
- return ok(await generateFromOpenapi(args));
44
- case "get_widget_spec":
45
- return ok(getWidgetSpec(args));
46
- case "get_concept":
47
- return ok(getConcept(args));
48
- default:
49
- return err(`Unknown tool: ${name}`);
50
- }
68
+ return ok(await entry.run(args));
51
69
  } catch (e) {
52
70
  return err(e.message);
53
71
  }
54
72
  });
55
- function ok(payload) {
56
- return {
57
- content: [{ type: "text", text: JSON.stringify(payload, null, 2) }]
58
- };
59
- }
60
- function err(message) {
61
- return {
62
- isError: true,
63
- content: [{ type: "text", text: message }]
64
- };
65
- }
66
73
  async function main() {
67
74
  const transport = new StdioServerTransport();
68
75
  await server.connect(transport);
@@ -0,0 +1,25 @@
1
+ import { DxCheckResult } from './typecheck';
2
+ export type CheckDxCodeInput = {
3
+ /** A `gui.*` DX snippet (TypeScript). May be a bare array of `gui.inputs.*` items. */
4
+ code: string;
5
+ };
6
+ export type CheckDxCodeResult = DxCheckResult;
7
+ /**
8
+ * Type-check GolemUI DX code against the real `@golemui` declarations and return
9
+ * compiler diagnostics. Async because the TypeScript compiler is loaded lazily.
10
+ */
11
+ export declare function checkDxCode(input: CheckDxCodeInput): Promise<CheckDxCodeResult>;
12
+ export declare const DX_CHECK_CODE_TOOL: {
13
+ readonly name: "dx_check_code";
14
+ readonly description: string;
15
+ readonly inputSchema: {
16
+ readonly type: "object";
17
+ readonly properties: {
18
+ readonly code: {
19
+ readonly type: "string";
20
+ readonly description: "The GolemUI `gui.*` DX snippet to type-check (TypeScript).";
21
+ };
22
+ };
23
+ readonly required: readonly ["code"];
24
+ };
25
+ };
@@ -0,0 +1,27 @@
1
+ import { ExpressionFinding } from '../shared/lint/reactive-expressions';
2
+ import { DxDiagnostic } from './typecheck';
3
+ import type * as TS from 'typescript';
4
+ /**
5
+ * Static lints over a `gui.*` DX snippet that the TypeScript compiler cannot catch.
6
+ *
7
+ * The compiler is the truthful gate for *type* errors, but two real defects slip past
8
+ * it because the code is structurally valid TypeScript:
9
+ *
10
+ * 1. **Misplaced `include`/`exclude` (the silent no-op).** Spreading a factory result
11
+ * and attaching `include`/`exclude`/`disabled`/`readonly` as a SIBLING
12
+ * (`{ ...gui.inputs.x(...), include: { when } }`) compiles — TS suppresses excess-property
13
+ * checks on object literals containing a spread — but the field never sees the
14
+ * condition, so it renders/behaves unconditionally. The arena caught this on a real
15
+ * "hide when" task. Reported as a blocking `diagnostic`.
16
+ *
17
+ * 2. **Reactive-expression quality.** The `when` strings inside `include`/`exclude`/etc.
18
+ * are opaque to the type-checker. We funnel each through the SAME engine the JSON
19
+ * `json_validate_form_definition` path uses ({@link checkReactiveExpression}), so the two
20
+ * surfaces share one set of rules. Reported as non-blocking `expressionWarnings`,
21
+ * mirroring the JSON path.
22
+ */
23
+ export interface DxLintResult {
24
+ diagnostics: DxDiagnostic[];
25
+ expressionWarnings: ExpressionFinding[];
26
+ }
27
+ export declare function lintDxSnippet(ts: typeof TS, sourceText: string, lineOffset: number): DxLintResult;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * DX grounding registry — the real `gui.*` builder surface, one entry per factory.
3
+ *
4
+ * GolemUI is not in any model's training data, so a cold model fabricates the
5
+ * `gui.*` API wholesale. This registry is what `dx_get_spec` serves so the model
6
+ * writes the real thing. Every `example` here is **compile-verified against the
7
+ * real `@golemui` types** by `dx-specs.spec.ts` — if an example is wrong, the test
8
+ * suite fails. (Hand-written references are unreliable even with repo access; the
9
+ * compile gate is the cure.)
10
+ */
11
+ export type DxNamespace = 'inputs' | 'actions' | 'displays' | 'layouts';
12
+ export interface DxSpec {
13
+ /** Factory name, e.g. `textInput`. */
14
+ factory: string;
15
+ namespace: DxNamespace;
16
+ /** Human-readable calling convention. */
17
+ call: string;
18
+ /** A compiling `gui.*` snippet (verified by the suite). */
19
+ example: string;
20
+ /** Authoring notes and gotchas. */
21
+ notes: string[];
22
+ }
23
+ /**
24
+ * A cross-cutting authoring pattern that is NOT a single factory — e.g. conditional
25
+ * visibility, which is a common field available on every `gui.*` item. Same compile
26
+ * guarantee as `DxSpec`: every `example` is verified by `dx-specs.spec.ts`.
27
+ */
28
+ export interface DxPattern {
29
+ /** Short identifier, e.g. `conditionalVisibility`. */
30
+ name: string;
31
+ /** One-line title. */
32
+ title: string;
33
+ /** A compiling `gui.*` snippet (verified by the suite). */
34
+ example: string;
35
+ notes: string[];
36
+ }
37
+ export type DxFramework = 'react' | 'angular' | 'vue' | 'lit' | 'vanilla';
38
+ export declare function resolveDxFramework(): DxFramework;
39
+ export declare const DX_SPECS: Record<string, DxSpec>;
40
+ export declare function listDxFactories(): string[];
41
+ /**
42
+ * One catalog row — enough to WRITE the factory without a follow-up lookup: name, namespace,
43
+ * signature, a compile-verified example, and the authoring gotchas.
44
+ */
45
+ export interface DxCatalogEntry {
46
+ factory: string;
47
+ namespace: DxNamespace;
48
+ call: string;
49
+ example: string;
50
+ notes: string[];
51
+ }
52
+ export interface DxCatalog {
53
+ /** Every factory, in `inputs → actions → displays → layouts` order — call + example + notes. */
54
+ factories: DxCatalogEntry[];
55
+ /** Cross-cutting patterns (e.g. conditional visibility) — full example + notes, resident once. */
56
+ patterns: DxPattern[];
57
+ /** The cross-cutting authoring note shared by all factories (incl. the validator `type` rule). */
58
+ common: string;
59
+ }
60
+ /**
61
+ * The whole `gui.*` surface as a SELF-SUFFICIENT reference in one payload: every factory's
62
+ * signature, a compile-verified example, and its gotchas, plus the cross-cutting patterns and the
63
+ * common note. Serves `dx_list_factories`. The agentic intent: the model fetches this ONCE, keeps
64
+ * it resident, and writes most forms from it directly — `dx_get_spec` becomes the rare deep-dive,
65
+ * not a per-factory round-trip. (Richer than a name-only index by design: in a resumed session
66
+ * this is paid once and reused, so front-loading the examples removes mid-task lookups and turns.)
67
+ */
68
+ export declare function dxCatalog(framework?: DxFramework): DxCatalog;
69
+ export declare function dxCommonNote(framework?: DxFramework): string;
70
+ export declare function dxPatterns(): DxPattern[];
@@ -0,0 +1,27 @@
1
+ import { DxSpec } from './dx-specs';
2
+ export type GetDxSpecInput = {
3
+ /** The `gui.*` factory name, e.g. `textInput`, `dropdown`, `button`. */
4
+ factory: string;
5
+ };
6
+ export type GetDxSpecResult = DxSpec;
7
+ /**
8
+ * Return the real `gui.*` builder signature, a compile-verified example, and authoring notes
9
+ * for a SINGLE factory — the deep-dive lookup. Lean by design: the cross-cutting common note
10
+ * and patterns are NOT re-shipped here (they ride in `dx_list_factories`, fetched once), so a
11
+ * follow-up lookup adds only the factory's own payload to the agent's context.
12
+ */
13
+ export declare function getDxSpec(input: GetDxSpecInput): GetDxSpecResult;
14
+ export declare const DX_GET_SPEC_TOOL: {
15
+ readonly name: "dx_get_spec";
16
+ readonly description: string;
17
+ readonly inputSchema: {
18
+ readonly type: "object";
19
+ readonly properties: {
20
+ readonly factory: {
21
+ readonly type: "string";
22
+ readonly description: "The gui.* factory name, e.g. \"textInput\", \"dropdown\", \"button\".";
23
+ };
24
+ };
25
+ readonly required: readonly ["factory"];
26
+ };
27
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The `gui.*` DX half of the server's connect-time guidance (the MCP
3
+ * `initialize.instructions` field). Composed with the JSON half in `cli.ts`. The target
4
+ * framework name is interpolated from the environment at module load, the same as the
5
+ * `dx_list_factories` catalog, so the agent is steered to the correct host wiring.
6
+ */
7
+ export declare const DX_INSTRUCTIONS: string;
@@ -0,0 +1,19 @@
1
+ import { DxCatalog, DxFramework } from './dx-specs';
2
+ export type ListDxFactoriesResult = DxCatalog;
3
+ /**
4
+ * Return the entire `gui.*` DX surface in one payload: every factory name + one-line
5
+ * signature, the cross-cutting pattern names, and the common note. The catalog the agent
6
+ * fetches ONCE before authoring, instead of paying a `dx_get_spec` round-trip per factory.
7
+ *
8
+ * The common note's imports + render snippet are tailored to `framework` (defaults to the
9
+ * `GOLEMUI_FRAMEWORK` env, else react) so the agent is shown the correct host wiring.
10
+ */
11
+ export declare function listDxFactoriesCatalog(framework?: DxFramework): ListDxFactoriesResult;
12
+ export declare const DX_LIST_FACTORIES_TOOL: {
13
+ readonly name: "dx_list_factories";
14
+ readonly description: string;
15
+ readonly inputSchema: {
16
+ readonly type: "object";
17
+ readonly properties: {};
18
+ };
19
+ };
package/dx/tools.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { ToolEntry } from '../shared/tool';
2
+ /** The `gui.*` DX path's MCP tools: list the catalog, deep-dive one factory, type-check. */
3
+ export declare const dxTools: ToolEntry[];
@@ -0,0 +1,10 @@
1
+ import type * as TS from 'typescript';
2
+ /** Build the compiler options that resolve `gui.*` against the real `@golemui` types. */
3
+ export declare function resolveTypeCheckOptions(ts: typeof TS): TS.CompilerOptions;
4
+ /**
5
+ * Compile a single in-memory file against the type graph and return ONLY that file's
6
+ * diagnostics (the host serves {@link SNIPPET_FILE} from memory; every other file is read
7
+ * from disk as usual).
8
+ */
9
+ export declare function diagnose(ts: typeof TS, code: string, options: TS.CompilerOptions): readonly TS.Diagnostic[];
10
+ export declare function assertTypesAreLive(ts: typeof TS, options: TS.CompilerOptions): void;
@@ -0,0 +1,41 @@
1
+ import { ExpressionFinding } from '../shared/lint/reactive-expressions';
2
+ /**
3
+ * In-process TypeScript type-check of a `gui.*` DX snippet against the real `@golemui`
4
+ * type graph. This is the *truthful* gate: the arena spike proved that regex and even
5
+ * careful human inspection score hallucinated GolemUI code as "valid" — only the compiler
6
+ * tells the truth.
7
+ *
8
+ * `typescript` is imported lazily (see {@link loadTs}) so this module — and the heavy
9
+ * compiler dependency — is only ever loaded when a DX tool is actually called; the JSON
10
+ * validation path never touches it. The fragile part — locating and compiling against the
11
+ * `@golemui` declarations — lives in `./type-graph`; this file only orchestrates a check
12
+ * and turns compiler output into GolemUI-flavored diagnostics.
13
+ */
14
+ export interface DxDiagnostic {
15
+ /** TypeScript diagnostic code, e.g. 2769. */
16
+ code: number;
17
+ /** Flattened, single-line diagnostic message. */
18
+ message: string;
19
+ /** 1-based line within the submitted snippet (0 if unknown). */
20
+ line: number;
21
+ /** 1-based column within the submitted snippet (0 if unknown). */
22
+ column: number;
23
+ /** A GolemUI-specific fix suggestion, when we recognize the error. */
24
+ hint?: string;
25
+ }
26
+ export interface DxCheckResult {
27
+ /** True when the snippet type-checks clean AND carries no blocking lint diagnostics. */
28
+ ok: boolean;
29
+ diagnostics: DxDiagnostic[];
30
+ /**
31
+ * Non-blocking reactive-expression findings (the `when` strings inside `include`/`exclude`/
32
+ * etc.), linted by the same engine as the JSON path. Advisory — they do not flip `ok`.
33
+ */
34
+ expressionWarnings: ExpressionFinding[];
35
+ }
36
+ /**
37
+ * Type-check a `gui.*` DX snippet against the real `@golemui` types.
38
+ * If the snippet does not import `gui`, a `@golemui/gui-shared` import is prepended,
39
+ * so a bare array of `gui.inputs.*` items can be checked directly.
40
+ */
41
+ export declare function typeCheckDx(code: string): Promise<DxCheckResult>;