@adia-ai/a2ui-mcp 0.6.2 → 0.6.5
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 +23 -0
- package/package.json +1 -1
- package/server.js +236 -329
- package/tools/synthesis.js +143 -174
package/server.js
CHANGED
|
@@ -1,115 +1,74 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* Tools:
|
|
10
|
-
* generate_ui — Generate A2UI components from intent
|
|
11
|
-
* validate_schema — Validate A2UI messages
|
|
12
|
-
* lookup_component — Component API lookup
|
|
13
|
-
* get_component_map — Full catalog
|
|
14
|
-
* search_patterns — Composition library search (kept for back-compat; backed by composition-library since §64)
|
|
15
|
-
* classify_intent — Domain classification
|
|
16
|
-
*
|
|
17
|
-
* Usage:
|
|
18
|
-
* node packages/a2ui/mcp/server.js
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
// ── Load .env for API keys (Node doesn't read .env automatically) ──
|
|
22
|
-
import '../../../scripts/load-env.mjs';
|
|
23
|
-
|
|
24
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
25
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
26
|
-
import { z } from 'zod';
|
|
27
|
-
|
|
28
|
-
// ── Import from a2ui ──
|
|
29
|
-
import { generateUI } from '../compose/core/generator.js';
|
|
30
|
-
import { validateSchema } from '../validator/validator.js';
|
|
31
|
-
import { validateMessages as validateCatalogMessages } from '../validator/catalog-validator.js';
|
|
2
|
+
import "../../../scripts/load-env.mjs";
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { generateUI } from "../compose/core/generator.js";
|
|
7
|
+
import { validateSchema } from "../validator/validator.js";
|
|
8
|
+
import { validateMessages as validateCatalogMessages } from "../validator/catalog-validator.js";
|
|
32
9
|
import {
|
|
33
10
|
getCatalog,
|
|
34
11
|
getComponent,
|
|
35
|
-
getComponentsByCategory,
|
|
12
|
+
getComponentsByCategory as _getComponentsByCategory,
|
|
36
13
|
getTraits,
|
|
37
14
|
getTraitsByCategory,
|
|
38
|
-
getFullCatalog
|
|
39
|
-
} from
|
|
40
|
-
import { serializeEntry } from
|
|
41
|
-
import { classifyIntent, getDomain, getAllDomains } from
|
|
42
|
-
import { getAntiPatterns, checkAllAntiPatterns } from
|
|
43
|
-
import { assembleContext } from
|
|
44
|
-
|
|
45
|
-
// ── Zettel (composition) engine ──
|
|
15
|
+
getFullCatalog
|
|
16
|
+
} from "../retrieval/catalog.js";
|
|
17
|
+
import { serializeEntry } from "../retrieval/component-entry.js";
|
|
18
|
+
import { classifyIntent, getDomain, getAllDomains } from "../retrieval/domain-router.js";
|
|
19
|
+
import { getAntiPatterns, checkAllAntiPatterns } from "../retrieval/anti-patterns.js";
|
|
20
|
+
import { assembleContext } from "../retrieval/context-assembler.js";
|
|
46
21
|
import {
|
|
47
22
|
loadAll as loadZettelCorpus,
|
|
48
23
|
getComposition as getZettelComposition,
|
|
49
24
|
getAllCompositions as getAllZettelCompositions,
|
|
50
25
|
getGraph as getZettelGraph,
|
|
51
|
-
searchAll as searchCompositions
|
|
52
|
-
} from
|
|
26
|
+
searchAll as searchCompositions
|
|
27
|
+
} from "../compose/strategies/zettel/composition-library.js";
|
|
53
28
|
import {
|
|
54
29
|
resolveComposition as resolveZettelComposition,
|
|
55
|
-
templateToMessages as zettelTemplateToMessages
|
|
56
|
-
} from
|
|
57
|
-
// Zettel bootstrap is still needed for get_fragment/resolve_composition tools;
|
|
58
|
-
// the generate_ui tool now dispatches through the unified registry in gen-ui.
|
|
59
|
-
|
|
60
|
-
// Bootstrap zettel composition corpus
|
|
30
|
+
templateToMessages as zettelTemplateToMessages
|
|
31
|
+
} from "../compose/strategies/zettel/composer.js";
|
|
61
32
|
const _zettelBoot = loadZettelCorpus();
|
|
62
33
|
console.error(
|
|
63
|
-
`[adiaui-mcp] zettel corpus: ${_zettelBoot.compositionCount} compositions
|
|
34
|
+
`[adiaui-mcp] zettel corpus: ${_zettelBoot.compositionCount} compositions`
|
|
64
35
|
);
|
|
65
|
-
|
|
66
|
-
// ── Gen-UI training-chunk corpus ──
|
|
67
36
|
import {
|
|
68
37
|
getChunk as getGenUIChunk,
|
|
69
38
|
getChunkIndex,
|
|
70
39
|
lookupChunksByPrimary,
|
|
71
|
-
searchChunks as searchGenUIChunks
|
|
72
|
-
} from
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
import {
|
|
76
|
-
import {
|
|
77
|
-
import {
|
|
78
|
-
import { feedbackStore } from '../retrieval/feedback/feedback-store.js';
|
|
79
|
-
|
|
80
|
-
// ── Tools extracted to tools/ for modularity ──
|
|
81
|
-
import { registerSynthesisTools } from './tools/synthesis.js';
|
|
82
|
-
|
|
40
|
+
searchChunks as searchGenUIChunks
|
|
41
|
+
} from "../corpus/scripts/chunk-library.js";
|
|
42
|
+
import { transpileHTML } from "../compose/transpiler/transpiler.js";
|
|
43
|
+
import { getWiringCatalog } from "../retrieval/wiring-catalog.js";
|
|
44
|
+
import { FeedbackCollector } from "../retrieval/feedback/feedback.js";
|
|
45
|
+
import { feedbackStore } from "../retrieval/feedback/feedback-store.js";
|
|
46
|
+
import { registerSynthesisTools } from "./tools/synthesis.js";
|
|
83
47
|
const _chunkIndex = getChunkIndex();
|
|
84
48
|
if (_chunkIndex) {
|
|
49
|
+
const idx = _chunkIndex;
|
|
50
|
+
const byKind = idx["by_kind"] ?? {};
|
|
85
51
|
console.error(
|
|
86
|
-
`[adiaui-mcp] gen-ui chunks: ${
|
|
52
|
+
`[adiaui-mcp] gen-ui chunks: ${idx["unique_names"]} unique chunks (${idx["total_instances"]} instances; block=${byKind["block"] ?? 0}, panel=${byKind["panel"] ?? 0}, page=${byKind["page"] ?? 0})`
|
|
87
53
|
);
|
|
88
54
|
} else {
|
|
89
|
-
console.error(
|
|
55
|
+
console.error("[adiaui-mcp] gen-ui chunks: index not found \u2014 run `npm run harvest:chunks`");
|
|
90
56
|
}
|
|
91
|
-
|
|
92
|
-
// ── Server ──
|
|
93
|
-
|
|
94
57
|
const server = new McpServer({
|
|
95
|
-
name:
|
|
96
|
-
version:
|
|
58
|
+
name: "adia-ui",
|
|
59
|
+
version: "0.1.0"
|
|
97
60
|
});
|
|
98
|
-
|
|
99
61
|
server.tool(
|
|
100
|
-
|
|
62
|
+
"plan_app_state",
|
|
101
63
|
`Analyze a natural language prompt and extract the top-level Generative UI Ontology structures (Intent, Domain, Tasks, Experience).
|
|
102
64
|
|
|
103
65
|
Use this tool BEFORE generating UI to ensure you have walked the Reasoning Ladder and properly modeled the nouns and verbs of the feature. This bounds hallucination and forces a focus on tasks over raw layouts.`,
|
|
104
66
|
{
|
|
105
|
-
prompt: z.string().describe('The natural language request (e.g., "Build a dashboard for incoming sales leads")')
|
|
67
|
+
prompt: z.string().describe('The natural language request (e.g., "Build a dashboard for incoming sales leads")')
|
|
106
68
|
},
|
|
107
69
|
async ({ prompt }) => {
|
|
108
|
-
|
|
109
|
-
// This is a minimal, fast call designed to output structured JSON.
|
|
110
|
-
const { createAdapter } = await import('../../llm/llm-bridge.js');
|
|
70
|
+
const { createAdapter } = await import("../../llm/llm-bridge.js");
|
|
111
71
|
const llm = await createAdapter();
|
|
112
|
-
|
|
113
72
|
const systemPrompt = `You are the A2UI Ontology Planner.
|
|
114
73
|
Given a user prompt, you must extract the Core App State using the 5-Gate Reasoning Ladder.
|
|
115
74
|
|
|
@@ -132,59 +91,55 @@ Output ONLY a JSON object matching this schema, nothing else:
|
|
|
132
91
|
"shell": "admin-shell | chat-shell | a2ui-root"
|
|
133
92
|
}
|
|
134
93
|
}`;
|
|
135
|
-
|
|
136
94
|
try {
|
|
137
95
|
const response = await llm.complete({
|
|
138
|
-
messages: [{ role:
|
|
96
|
+
messages: [{ role: "user", content: prompt }],
|
|
139
97
|
system: systemPrompt,
|
|
140
98
|
temperature: 0.2
|
|
141
99
|
});
|
|
142
|
-
|
|
143
|
-
let jsonMatch = response.text.match(/\{[\s\S]*\}/);
|
|
100
|
+
const jsonMatch = response.content.match(/\{[\s\S]*\}/);
|
|
144
101
|
if (!jsonMatch) {
|
|
145
|
-
|
|
102
|
+
throw new Error("LLM failed to output valid JSON for the ontology plan.");
|
|
146
103
|
}
|
|
147
|
-
|
|
148
104
|
const plan = JSON.parse(jsonMatch[0]);
|
|
149
|
-
|
|
150
105
|
return {
|
|
151
106
|
content: [
|
|
152
107
|
{
|
|
153
|
-
type:
|
|
154
|
-
text: JSON.stringify(plan, null, 2)
|
|
155
|
-
}
|
|
156
|
-
]
|
|
108
|
+
type: "text",
|
|
109
|
+
text: JSON.stringify(plan, null, 2)
|
|
110
|
+
}
|
|
111
|
+
]
|
|
157
112
|
};
|
|
158
113
|
} catch (e) {
|
|
114
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
159
115
|
return {
|
|
160
116
|
content: [
|
|
161
|
-
{ type:
|
|
117
|
+
{ type: "text", text: `Failed to plan app state: ${err.message}` }
|
|
162
118
|
],
|
|
163
|
-
isError: true
|
|
164
|
-
}
|
|
119
|
+
isError: true
|
|
120
|
+
};
|
|
165
121
|
}
|
|
166
122
|
}
|
|
167
123
|
);
|
|
168
|
-
|
|
169
124
|
server.tool(
|
|
170
|
-
|
|
125
|
+
"generate_ui",
|
|
171
126
|
`Generate A2UI components from a natural language description.
|
|
172
127
|
|
|
173
128
|
Engine selection:
|
|
174
|
-
- "monolithic" (default)
|
|
175
|
-
- "zettel"
|
|
129
|
+
- "monolithic" (default) \u2014 pattern-match + adapt. Searches a corpus of 96+ pre-authored monolithic templates and adapts the best match. Battle-tested; highest F1 on held-out intents.
|
|
130
|
+
- "zettel" \u2014 fragment-graph composer. Composes UI from named atomic fragments (labeled-input, card-header-with-description, etc.) with a precomputed backlink graph. Higher reusability; supports composition-iterated refinement on multi-turn edits.
|
|
176
131
|
|
|
177
132
|
Mode selection (monolithic only; zettel uses "instant"):
|
|
178
|
-
- "pro" (default)
|
|
179
|
-
- "thinking"
|
|
180
|
-
- "instant"
|
|
133
|
+
- "pro" (default) \u2014 LLM-powered generation with pattern adaptation.
|
|
134
|
+
- "thinking" \u2014 Full LLM-powered generation with semantic search, decomposition, and streaming.
|
|
135
|
+
- "instant" \u2014 fast pattern matching, no LLM.
|
|
181
136
|
|
|
182
137
|
The generator knows 96+ UI patterns across 5 domains: forms, data, layout, agent, navigation.`,
|
|
183
138
|
{
|
|
184
|
-
intent: z.string().describe(
|
|
185
|
-
engine: z.enum([
|
|
186
|
-
mode: z.enum([
|
|
187
|
-
sessionId: z.string().optional().describe(
|
|
139
|
+
intent: z.string().describe("Description of the UI to generate"),
|
|
140
|
+
engine: z.enum(["monolithic", "zettel"]).optional().describe('Generation engine. "monolithic" (default) is pattern-match + adapt. "zettel" is fragment-graph composition.'),
|
|
141
|
+
mode: z.enum(["instant", "pro", "thinking"]).optional().describe('Generation mode (monolithic). "pro" (default) uses LLM with pattern adaptation. "thinking" uses full LLM generation. "instant" uses fast pattern matching.'),
|
|
142
|
+
sessionId: z.string().optional().describe("Opaque session identifier for multi-turn iteration (zettel only). When provided, follow-up calls with the same sessionId modify the prior turn's canvas instead of regenerating from scratch. Omit for stateless generation."),
|
|
188
143
|
context: z.object({
|
|
189
144
|
domain: z.object({
|
|
190
145
|
entities: z.array(z.string()).optional(),
|
|
@@ -194,200 +149,186 @@ The generator knows 96+ UI patterns across 5 domains: forms, data, layout, agent
|
|
|
194
149
|
primary: z.array(z.string()).optional(),
|
|
195
150
|
inspection: z.array(z.string()).optional()
|
|
196
151
|
}).optional()
|
|
197
|
-
}).optional().describe(
|
|
152
|
+
}).optional().describe("Ontology context parsed by plan_app_state. If provided, the generator uses these constraints to bound hallucinations and strictly align components with domain tasks.")
|
|
198
153
|
},
|
|
199
154
|
async ({ intent, engine, mode, sessionId, context }) => {
|
|
200
155
|
try {
|
|
201
|
-
const selectedEngine = engine
|
|
202
|
-
const effectiveMode = selectedEngine ===
|
|
156
|
+
const selectedEngine = engine ?? "monolithic";
|
|
157
|
+
const effectiveMode = selectedEngine === "zettel" ? "instant" : mode ?? "pro";
|
|
203
158
|
const result = await generateUI({
|
|
204
159
|
intent,
|
|
205
160
|
engine: selectedEngine,
|
|
206
161
|
mode: effectiveMode,
|
|
207
162
|
sessionId,
|
|
208
|
-
context
|
|
163
|
+
context
|
|
164
|
+
// Pass the ontology context down to the composer
|
|
209
165
|
});
|
|
210
166
|
return {
|
|
211
167
|
content: [{
|
|
212
|
-
type:
|
|
168
|
+
type: "text",
|
|
213
169
|
text: JSON.stringify({
|
|
214
|
-
engine: result
|
|
215
|
-
executionId: result
|
|
216
|
-
strategy: result
|
|
217
|
-
messages: result
|
|
218
|
-
validation: result
|
|
219
|
-
suggestions: result
|
|
220
|
-
composition: result
|
|
221
|
-
fragments_used: result
|
|
222
|
-
sessionTurns: result
|
|
223
|
-
}, null, 2)
|
|
224
|
-
}]
|
|
170
|
+
engine: result["engine"] ?? selectedEngine,
|
|
171
|
+
executionId: result["executionId"],
|
|
172
|
+
strategy: result["strategy"],
|
|
173
|
+
messages: result["messages"],
|
|
174
|
+
validation: result["validation"],
|
|
175
|
+
suggestions: result["suggestions"],
|
|
176
|
+
composition: result["composition"],
|
|
177
|
+
fragments_used: result["fragments_used"],
|
|
178
|
+
sessionTurns: result["sessionTurns"]
|
|
179
|
+
}, null, 2)
|
|
180
|
+
}]
|
|
225
181
|
};
|
|
226
182
|
} catch (err) {
|
|
227
|
-
|
|
183
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
184
|
+
return { content: [{ type: "text", text: `Generation error: ${e.message}` }], isError: true };
|
|
228
185
|
}
|
|
229
186
|
}
|
|
230
187
|
);
|
|
231
|
-
|
|
232
188
|
server.tool(
|
|
233
|
-
|
|
234
|
-
|
|
189
|
+
"validate_schema",
|
|
190
|
+
"Validate A2UI messages against schema rules.",
|
|
235
191
|
{
|
|
236
|
-
messages: z.string().describe(
|
|
192
|
+
messages: z.string().describe("JSON array of A2UI messages")
|
|
237
193
|
},
|
|
238
194
|
async ({ messages }) => {
|
|
239
195
|
try {
|
|
240
196
|
const parsed = JSON.parse(messages);
|
|
241
197
|
const msgs = Array.isArray(parsed) ? parsed : [parsed];
|
|
242
|
-
// Two orthogonal checks:
|
|
243
|
-
// 1. scored — weighted heuristic validator (intent alignment, card model, etc.)
|
|
244
|
-
// 2. catalog — AJV against v0.9 catalog schema (type-level structural correctness)
|
|
245
|
-
// Both run; results returned together so callers see structural + quality signal.
|
|
246
198
|
const scored = validateSchema(msgs);
|
|
247
199
|
const catalog = await validateCatalogMessages(msgs);
|
|
248
200
|
const result = { ...scored, catalog };
|
|
249
|
-
return { content: [{ type:
|
|
201
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
250
202
|
} catch (err) {
|
|
251
|
-
|
|
203
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
204
|
+
return { content: [{ type: "text", text: `Parse error: ${e.message}` }], isError: true };
|
|
252
205
|
}
|
|
253
206
|
}
|
|
254
207
|
);
|
|
255
|
-
|
|
256
208
|
server.tool(
|
|
257
|
-
|
|
258
|
-
|
|
209
|
+
"lookup_component",
|
|
210
|
+
"Look up a AdiaUI component by type name.",
|
|
259
211
|
{
|
|
260
212
|
type: z.string().describe('Component type (e.g., "Card", "Button")'),
|
|
261
|
-
level: z.enum([
|
|
213
|
+
level: z.enum(["index", "summary", "reference"]).optional().describe("Detail level (default: reference)")
|
|
262
214
|
},
|
|
263
215
|
async ({ type, level }) => {
|
|
264
216
|
const entry = await getComponent(type);
|
|
265
|
-
if (!entry) return { content: [{ type:
|
|
266
|
-
const serialized = serializeEntry(entry, level
|
|
267
|
-
return { content: [{ type:
|
|
217
|
+
if (!entry) return { content: [{ type: "text", text: `Not found: ${type}` }], isError: true };
|
|
218
|
+
const serialized = serializeEntry(entry, level ?? "reference");
|
|
219
|
+
return { content: [{ type: "text", text: JSON.stringify(serialized, null, 2) }] };
|
|
268
220
|
}
|
|
269
221
|
);
|
|
270
|
-
|
|
271
222
|
server.tool(
|
|
272
|
-
|
|
273
|
-
|
|
223
|
+
"get_component_map",
|
|
224
|
+
"Get the full AdiaUI component catalog.",
|
|
274
225
|
{},
|
|
275
226
|
async () => {
|
|
276
227
|
const catalog = await getCatalog();
|
|
277
|
-
const summary = [...catalog.entries.values()]
|
|
278
|
-
|
|
279
|
-
.
|
|
280
|
-
|
|
228
|
+
const summary = [...catalog.entries.values()].map((e) => {
|
|
229
|
+
const entry = e;
|
|
230
|
+
const desc = typeof entry["description"] === "string" ? entry["description"].slice(0, 80) : "";
|
|
231
|
+
return `${entry["type"]} -> <${entry["tag"]}>: ${desc}`;
|
|
232
|
+
}).join("\n");
|
|
233
|
+
return { content: [{ type: "text", text: summary }] };
|
|
281
234
|
}
|
|
282
235
|
);
|
|
283
|
-
|
|
284
236
|
server.tool(
|
|
285
|
-
|
|
237
|
+
"search_patterns",
|
|
286
238
|
`Search the composition library for reusable UI templates. Returns matching compositions with full A2UI component trees that can be used directly or adapted.
|
|
287
239
|
|
|
288
240
|
Use this to find a starting point before generating from scratch. If a good composition exists, pass it to generate_ui with instant mode. If no composition matches, use generate_ui with thinking mode.
|
|
289
241
|
|
|
290
|
-
Keyword search (
|
|
242
|
+
Keyword search (\xA764 v0.4.6 migration: now backed by composition-library; the historical "pattern" library is retired).`,
|
|
291
243
|
{
|
|
292
|
-
query: z.string().describe(
|
|
244
|
+
query: z.string().describe("Search query (natural language)")
|
|
293
245
|
},
|
|
294
246
|
async ({ query }) => {
|
|
295
247
|
const results = searchCompositions(query);
|
|
296
|
-
return { content: [{ type:
|
|
248
|
+
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
|
297
249
|
}
|
|
298
250
|
);
|
|
299
|
-
|
|
300
251
|
server.tool(
|
|
301
|
-
|
|
302
|
-
|
|
252
|
+
"classify_intent",
|
|
253
|
+
"Classify intent into a UI domain.",
|
|
303
254
|
{
|
|
304
|
-
text: z.string().describe(
|
|
255
|
+
text: z.string().describe("Intent text")
|
|
305
256
|
},
|
|
306
257
|
async ({ text }) => {
|
|
307
|
-
return { content: [{ type:
|
|
258
|
+
return { content: [{ type: "text", text: JSON.stringify(classifyIntent(text), null, 2) }] };
|
|
308
259
|
}
|
|
309
260
|
);
|
|
310
|
-
|
|
311
261
|
server.tool(
|
|
312
|
-
|
|
262
|
+
"assemble_context",
|
|
313
263
|
`Assemble progressive-disclosure context for a given intent and budget tier. Returns domain-relevant components, matching patterns, and anti-patterns.
|
|
314
264
|
|
|
315
265
|
Tier 0: domain only. Tier 1: components. Tier 2: +patterns. Tier 3: +anti-patterns. Tier 4: full catalog.
|
|
316
266
|
|
|
317
267
|
Use this when you want to manually compose A2UI output rather than using generate_ui. The returned context gives you the building blocks.`,
|
|
318
268
|
{
|
|
319
|
-
intent: z.string().describe(
|
|
320
|
-
tier: z.number().min(0).max(4).optional().describe(
|
|
269
|
+
intent: z.string().describe("Natural language intent"),
|
|
270
|
+
tier: z.number().min(0).max(4).optional().describe("Budget tier 0-4 (default: 1)")
|
|
321
271
|
},
|
|
322
272
|
async ({ intent, tier }) => {
|
|
323
273
|
const result = assembleContext({ intent, tier: tier ?? 1 });
|
|
324
|
-
return { content: [{ type:
|
|
274
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
325
275
|
}
|
|
326
276
|
);
|
|
327
|
-
|
|
328
277
|
server.tool(
|
|
329
|
-
|
|
330
|
-
|
|
278
|
+
"check_anti_patterns",
|
|
279
|
+
"Check HTML against all anti-patterns. Returns only violations.",
|
|
331
280
|
{
|
|
332
|
-
html: z.string().describe(
|
|
281
|
+
html: z.string().describe("HTML string to check")
|
|
333
282
|
},
|
|
334
283
|
async ({ html }) => {
|
|
335
284
|
const violations = checkAllAntiPatterns(html);
|
|
336
|
-
return { content: [{ type:
|
|
285
|
+
return { content: [{ type: "text", text: JSON.stringify(violations, null, 2) }] };
|
|
337
286
|
}
|
|
338
287
|
);
|
|
339
|
-
|
|
340
288
|
server.tool(
|
|
341
|
-
|
|
342
|
-
|
|
289
|
+
"get_traits",
|
|
290
|
+
"Get the trait catalog, optionally filtered by category.",
|
|
343
291
|
{
|
|
344
|
-
category: z.string().optional().describe('Trait category filter (e.g., "input-interaction", "motion-positioning")')
|
|
292
|
+
category: z.string().optional().describe('Trait category filter (e.g., "input-interaction", "motion-positioning")')
|
|
345
293
|
},
|
|
346
294
|
async ({ category }) => {
|
|
347
295
|
const traits = category ? getTraitsByCategory(category) : getTraits();
|
|
348
|
-
return { content: [{ type:
|
|
296
|
+
return { content: [{ type: "text", text: JSON.stringify(traits, null, 2) }] };
|
|
349
297
|
}
|
|
350
298
|
);
|
|
351
|
-
|
|
352
|
-
// ── Transpiler & Wiring Tools ──
|
|
353
|
-
|
|
354
299
|
server.tool(
|
|
355
|
-
|
|
356
|
-
|
|
300
|
+
"convert_html",
|
|
301
|
+
"Convert HTML markup to A2UI flat adjacency component messages. Maps HTML tags to AdiaUI components, infers layout from styles, enforces Card content model.",
|
|
357
302
|
{
|
|
358
|
-
html: z.string().describe(
|
|
359
|
-
mode: z.enum([
|
|
303
|
+
html: z.string().describe("HTML markup to convert"),
|
|
304
|
+
mode: z.enum(["instant", "reasoning"]).optional().describe("instant = rules only, reasoning = LLM for complex layouts")
|
|
360
305
|
},
|
|
361
306
|
async ({ html, mode }) => {
|
|
362
307
|
try {
|
|
363
|
-
const result = await transpileHTML(html, { mode: mode
|
|
364
|
-
return { content: [{ type:
|
|
308
|
+
const result = await transpileHTML(html, { mode: mode ?? "instant" });
|
|
309
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
365
310
|
} catch (err) {
|
|
366
|
-
|
|
311
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
312
|
+
return { content: [{ type: "text", text: `Transpile error: ${e.message}` }], isError: true };
|
|
367
313
|
}
|
|
368
314
|
}
|
|
369
315
|
);
|
|
370
|
-
|
|
371
316
|
server.tool(
|
|
372
|
-
|
|
373
|
-
|
|
317
|
+
"get_wiring_catalog",
|
|
318
|
+
"Get the AdiaUI wiring catalog: available controllers, action handlers, refresh strategies, value sources, and association types.",
|
|
374
319
|
{},
|
|
375
320
|
async () => {
|
|
376
321
|
const catalog = getWiringCatalog();
|
|
377
|
-
return { content: [{ type:
|
|
322
|
+
return { content: [{ type: "text", text: JSON.stringify(catalog, null, 2) }] };
|
|
378
323
|
}
|
|
379
324
|
);
|
|
380
|
-
|
|
381
|
-
// ── Feedback Tools ──
|
|
382
|
-
|
|
383
325
|
const feedbackCollector = new FeedbackCollector();
|
|
384
|
-
|
|
385
326
|
server.tool(
|
|
386
|
-
|
|
387
|
-
|
|
327
|
+
"submit_feedback",
|
|
328
|
+
"Submit structured feedback for a generation execution. Used by the evolution engine to learn from each generation.",
|
|
388
329
|
{
|
|
389
|
-
executionId: z.string().describe(
|
|
390
|
-
rating: z.number().min(1).max(5).describe(
|
|
330
|
+
executionId: z.string().describe("Execution ID from generate_ui"),
|
|
331
|
+
rating: z.number().min(1).max(5).describe("Overall quality 1-5"),
|
|
391
332
|
intent: z.string().optional(),
|
|
392
333
|
domain: z.string().optional(),
|
|
393
334
|
intentAlignment: z.number().min(1).max(5).optional(),
|
|
@@ -397,7 +338,7 @@ server.tool(
|
|
|
397
338
|
editSummary: z.string().optional(),
|
|
398
339
|
notes: z.string().optional(),
|
|
399
340
|
shouldBePattern: z.boolean().optional(),
|
|
400
|
-
suggestedName: z.string().optional()
|
|
341
|
+
suggestedName: z.string().optional()
|
|
401
342
|
},
|
|
402
343
|
async (args) => {
|
|
403
344
|
feedbackCollector.collectFeedback(args.executionId, {
|
|
@@ -407,198 +348,179 @@ server.tool(
|
|
|
407
348
|
componentChoice: args.componentChoice,
|
|
408
349
|
userEdited: args.userEdited,
|
|
409
350
|
editSummary: args.editSummary,
|
|
410
|
-
notes: args.notes
|
|
351
|
+
notes: args.notes
|
|
411
352
|
});
|
|
412
353
|
if (args.shouldBePattern != null) {
|
|
413
354
|
feedbackCollector.collectPatternFeedback(args.executionId, {
|
|
414
355
|
shouldBePattern: args.shouldBePattern,
|
|
415
|
-
suggestedName: args.suggestedName
|
|
356
|
+
suggestedName: args.suggestedName
|
|
416
357
|
});
|
|
417
358
|
}
|
|
418
|
-
return { content: [{ type:
|
|
359
|
+
return { content: [{ type: "text", text: JSON.stringify({ recorded: true, executionId: args.executionId, totalEntries: feedbackCollector.size }) }] };
|
|
419
360
|
}
|
|
420
361
|
);
|
|
421
|
-
|
|
422
|
-
// ── Quality metrics tool ──
|
|
423
|
-
|
|
424
362
|
server.tool(
|
|
425
|
-
|
|
426
|
-
|
|
363
|
+
"get_quality_metrics",
|
|
364
|
+
"Get aggregated quality metrics from the feedback store: avg score, thumb-up rate, per-domain breakdown, training gaps.",
|
|
427
365
|
{},
|
|
428
366
|
async () => {
|
|
429
367
|
const metrics = await feedbackStore.getQualityMetrics();
|
|
430
|
-
return { content: [{ type:
|
|
368
|
+
return { content: [{ type: "text", text: JSON.stringify(metrics, null, 2) }] };
|
|
431
369
|
}
|
|
432
370
|
);
|
|
433
|
-
|
|
434
371
|
server.tool(
|
|
435
|
-
|
|
436
|
-
|
|
372
|
+
"get_training_gaps",
|
|
373
|
+
"Get training gap signals from LLM self-critique: missing patterns, weak domain keywords, component gaps.",
|
|
437
374
|
{},
|
|
438
375
|
async () => {
|
|
439
376
|
const gaps = await feedbackStore.getGapSummary();
|
|
440
|
-
return { content: [{ type:
|
|
377
|
+
return { content: [{ type: "text", text: JSON.stringify(gaps, null, 2) }] };
|
|
441
378
|
}
|
|
442
379
|
);
|
|
443
|
-
|
|
444
380
|
server.tool(
|
|
445
|
-
|
|
446
|
-
|
|
381
|
+
"run_eval",
|
|
382
|
+
"Run the offline eval harness against the held-out intent set. Returns aggregate scores and per-intent results.",
|
|
447
383
|
{
|
|
448
|
-
domain: z.string().optional().describe(
|
|
449
|
-
limit: z.number().optional().describe(
|
|
384
|
+
domain: z.string().optional().describe("Filter by domain (forms, data, layout, agent, navigation)"),
|
|
385
|
+
limit: z.number().optional().describe("Max intents to evaluate")
|
|
450
386
|
},
|
|
451
387
|
async ({ domain, limit }) => {
|
|
452
388
|
try {
|
|
453
|
-
const { runHarness } = await import(
|
|
389
|
+
const { runHarness } = await import("../a2ui/evals/harness.mjs");
|
|
454
390
|
const summary = await runHarness({
|
|
455
|
-
generate: (args) => generateUI({ intent: args
|
|
391
|
+
generate: (args) => generateUI({ intent: args["intent"], mode: "instant" }),
|
|
456
392
|
domain,
|
|
457
393
|
limit,
|
|
458
|
-
mode:
|
|
394
|
+
mode: "instant"
|
|
459
395
|
});
|
|
460
|
-
return { content: [{ type:
|
|
396
|
+
return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
|
|
461
397
|
} catch (err) {
|
|
462
|
-
|
|
398
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
399
|
+
return { content: [{ type: "text", text: `Eval error: ${e.message}` }], isError: true };
|
|
463
400
|
}
|
|
464
401
|
}
|
|
465
402
|
);
|
|
466
|
-
|
|
467
|
-
// ── Resources ──
|
|
468
|
-
|
|
469
403
|
server.resource(
|
|
470
|
-
|
|
471
|
-
|
|
404
|
+
"catalog",
|
|
405
|
+
"a2ui://catalog/manifest",
|
|
472
406
|
async (uri) => {
|
|
473
407
|
const catalog = await getFullCatalog();
|
|
474
408
|
const serializable = {
|
|
475
409
|
version: catalog.version,
|
|
476
410
|
totalTypes: catalog.totalTypes,
|
|
477
411
|
totalTraits: catalog.totalTraits,
|
|
478
|
-
components: [...catalog.entries.values()].map(e => serializeEntry(e,
|
|
479
|
-
traits: catalog.traits
|
|
412
|
+
components: [...catalog.entries.values()].map((e) => serializeEntry(e, "summary")),
|
|
413
|
+
traits: catalog.traits
|
|
480
414
|
};
|
|
481
415
|
return {
|
|
482
416
|
contents: [{
|
|
483
417
|
uri: uri.href,
|
|
484
|
-
mimeType:
|
|
485
|
-
text: JSON.stringify(serializable, null, 2)
|
|
486
|
-
}]
|
|
418
|
+
mimeType: "application/json",
|
|
419
|
+
text: JSON.stringify(serializable, null, 2)
|
|
420
|
+
}]
|
|
487
421
|
};
|
|
488
422
|
}
|
|
489
423
|
);
|
|
490
|
-
|
|
491
424
|
server.resource(
|
|
492
|
-
|
|
493
|
-
|
|
425
|
+
"compositions",
|
|
426
|
+
"a2ui://catalog/compositions",
|
|
494
427
|
async (uri) => ({
|
|
495
428
|
contents: [{
|
|
496
429
|
uri: uri.href,
|
|
497
|
-
mimeType:
|
|
498
|
-
text: JSON.stringify(getAllZettelCompositions(), null, 2)
|
|
499
|
-
}]
|
|
430
|
+
mimeType: "application/json",
|
|
431
|
+
text: JSON.stringify(getAllZettelCompositions(), null, 2)
|
|
432
|
+
}]
|
|
500
433
|
})
|
|
501
434
|
);
|
|
502
|
-
|
|
503
435
|
server.resource(
|
|
504
|
-
|
|
505
|
-
|
|
436
|
+
"anti-patterns",
|
|
437
|
+
"a2ui://catalog/anti-patterns",
|
|
506
438
|
async (uri) => ({
|
|
507
439
|
contents: [{
|
|
508
440
|
uri: uri.href,
|
|
509
|
-
mimeType:
|
|
510
|
-
text: JSON.stringify(getAntiPatterns(), null, 2)
|
|
511
|
-
}]
|
|
441
|
+
mimeType: "application/json",
|
|
442
|
+
text: JSON.stringify(getAntiPatterns(), null, 2)
|
|
443
|
+
}]
|
|
512
444
|
})
|
|
513
445
|
);
|
|
514
|
-
|
|
515
446
|
server.resource(
|
|
516
|
-
|
|
517
|
-
|
|
447
|
+
"domains",
|
|
448
|
+
"a2ui://catalog/domains",
|
|
518
449
|
async (uri) => {
|
|
519
|
-
const domains = getAllDomains().map(name => ({
|
|
450
|
+
const domains = getAllDomains().map((name) => ({
|
|
520
451
|
name,
|
|
521
|
-
...getDomain(name)
|
|
452
|
+
...getDomain(name)
|
|
522
453
|
}));
|
|
523
454
|
return {
|
|
524
455
|
contents: [{
|
|
525
456
|
uri: uri.href,
|
|
526
|
-
mimeType:
|
|
527
|
-
text: JSON.stringify(domains, null, 2)
|
|
528
|
-
}]
|
|
457
|
+
mimeType: "application/json",
|
|
458
|
+
text: JSON.stringify(domains, null, 2)
|
|
459
|
+
}]
|
|
529
460
|
};
|
|
530
461
|
}
|
|
531
462
|
);
|
|
532
|
-
|
|
533
|
-
// ── Zettel composition-inspection tools ────────────────────────────────
|
|
534
|
-
// (Fragment-inspection tools retired in §37; fragments no longer exist as
|
|
535
|
-
// a separate corpus class. Compositions are now flat A2UI templates.)
|
|
536
|
-
|
|
537
463
|
server.tool(
|
|
538
|
-
|
|
539
|
-
|
|
464
|
+
"get_composition",
|
|
465
|
+
"Fetch a composition by name. Returns the flat A2UI template (compositions are pre-inlined; no $fragment refs). Zettel-only.",
|
|
540
466
|
{ name: z.string() },
|
|
541
467
|
async ({ name }) => {
|
|
542
468
|
const c = getZettelComposition(name);
|
|
543
|
-
if (!c) return { content: [{ type:
|
|
544
|
-
return { content: [{ type:
|
|
545
|
-
}
|
|
469
|
+
if (!c) return { content: [{ type: "text", text: `Composition not found: ${name}` }], isError: true };
|
|
470
|
+
return { content: [{ type: "text", text: JSON.stringify(c, null, 2) }] };
|
|
471
|
+
}
|
|
546
472
|
);
|
|
547
|
-
|
|
548
473
|
server.tool(
|
|
549
|
-
|
|
550
|
-
|
|
474
|
+
"resolve_composition",
|
|
475
|
+
"Return the flat A2UI template + updateComponents messages for a composition. Zettel-only. (Pre-inlined since \xA737 \u2014 `resolve` is now a defensive copy + strip pass.)",
|
|
551
476
|
{ name: z.string() },
|
|
552
477
|
async ({ name }) => {
|
|
553
478
|
const c = getZettelComposition(name);
|
|
554
|
-
if (!c) return { content: [{ type:
|
|
479
|
+
if (!c) return { content: [{ type: "text", text: `Composition not found: ${name}` }], isError: true };
|
|
555
480
|
const template = resolveZettelComposition(c);
|
|
556
481
|
const messages = zettelTemplateToMessages(template);
|
|
557
482
|
return {
|
|
558
483
|
content: [{
|
|
559
|
-
type:
|
|
560
|
-
text: JSON.stringify({ template, messages }, null, 2)
|
|
561
|
-
}]
|
|
484
|
+
type: "text",
|
|
485
|
+
text: JSON.stringify({ template, messages }, null, 2)
|
|
486
|
+
}]
|
|
562
487
|
};
|
|
563
|
-
}
|
|
488
|
+
}
|
|
564
489
|
);
|
|
565
|
-
|
|
566
490
|
server.tool(
|
|
567
|
-
|
|
568
|
-
|
|
491
|
+
"get_graph",
|
|
492
|
+
"Return the composition catalog. Zettel-only. (Backlinks to fragments retired in \xA737; only composition nodes remain.)",
|
|
569
493
|
{},
|
|
570
|
-
async () => ({ content: [{ type:
|
|
494
|
+
async () => ({ content: [{ type: "text", text: JSON.stringify(getZettelGraph(), null, 2) }] })
|
|
571
495
|
);
|
|
572
|
-
|
|
573
496
|
server.tool(
|
|
574
|
-
|
|
575
|
-
|
|
497
|
+
"zettel_stats",
|
|
498
|
+
"Zettel corpus stats \u2014 composition count + average node count. (Fragment stats retired in \xA737.)",
|
|
576
499
|
{},
|
|
577
500
|
async () => {
|
|
578
501
|
const comps = getAllZettelCompositions();
|
|
579
|
-
const totalNodes = comps.reduce((s, c) =>
|
|
502
|
+
const totalNodes = comps.reduce((s, c) => {
|
|
503
|
+
const comp = c;
|
|
504
|
+
const tpl = comp["template"];
|
|
505
|
+
return s + (Array.isArray(tpl) ? tpl.length : 0);
|
|
506
|
+
}, 0);
|
|
580
507
|
return {
|
|
581
508
|
content: [{
|
|
582
|
-
type:
|
|
509
|
+
type: "text",
|
|
583
510
|
text: JSON.stringify({
|
|
584
511
|
compositions: comps.length,
|
|
585
512
|
avg_nodes_per_composition: comps.length ? Math.round(totalNodes / comps.length) : 0,
|
|
586
|
-
total_nodes: totalNodes
|
|
587
|
-
}, null, 2)
|
|
588
|
-
}]
|
|
513
|
+
total_nodes: totalNodes
|
|
514
|
+
}, null, 2)
|
|
515
|
+
}]
|
|
589
516
|
};
|
|
590
|
-
}
|
|
517
|
+
}
|
|
591
518
|
);
|
|
592
|
-
|
|
593
|
-
// ── Gen-UI training-chunk tools ──────────────────────────────────────
|
|
594
|
-
// Spec: docs/specs/genui-chunk-marker.md (Draft v0.1.0).
|
|
595
|
-
// Plan: docs/plans/training-pipeline-chunk-harvest-2026-04-27.md.
|
|
596
|
-
|
|
597
519
|
server.tool(
|
|
598
|
-
|
|
520
|
+
"search_chunks",
|
|
599
521
|
`Search the gen-UI training-chunk corpus by keyword.
|
|
600
522
|
|
|
601
|
-
The chunk corpus comes from \`packages/a2ui/corpus/chunks/\`
|
|
523
|
+
The chunk corpus comes from \`packages/a2ui/corpus/chunks/\` \u2014 JSON records
|
|
602
524
|
extracted from every \`[data-chunk]\` element in site/pages/* and the corpus
|
|
603
525
|
exemplars. There are three kinds:
|
|
604
526
|
- block (default): atomic UI fragment (KPI grid, sign-in form, table)
|
|
@@ -609,49 +531,47 @@ Returns ranked candidates with chunk name, kind, primary tag, and a relevance
|
|
|
609
531
|
score. Use \`get_chunk\` to fetch the full record (HTML + slot bindings + nested
|
|
610
532
|
chunks) for a specific name.`,
|
|
611
533
|
{
|
|
612
|
-
query: z.string().describe(
|
|
613
|
-
kind: z.enum([
|
|
614
|
-
limit: z.number().int().min(1).max(50).default(20).describe(
|
|
534
|
+
query: z.string().describe("Keyword query \u2014 chunk name fragment, intent words, primary-tag name"),
|
|
535
|
+
kind: z.enum(["block", "panel", "page"]).optional().describe("Filter by chunk kind"),
|
|
536
|
+
limit: z.number().int().min(1).max(50).default(20).describe("Max results")
|
|
615
537
|
},
|
|
616
538
|
async ({ query, kind, limit }) => {
|
|
617
539
|
const results = searchGenUIChunks(query, { kind, limit });
|
|
618
540
|
return {
|
|
619
541
|
content: [{
|
|
620
|
-
type:
|
|
621
|
-
text: JSON.stringify({ query, kind: kind
|
|
622
|
-
}]
|
|
542
|
+
type: "text",
|
|
543
|
+
text: JSON.stringify({ query, kind: kind ?? "any", count: results.length, results }, null, 2)
|
|
544
|
+
}]
|
|
623
545
|
};
|
|
624
|
-
}
|
|
546
|
+
}
|
|
625
547
|
);
|
|
626
|
-
|
|
627
548
|
server.tool(
|
|
628
|
-
|
|
549
|
+
"get_chunk",
|
|
629
550
|
`Fetch the full record for a single gen-UI training chunk by name.
|
|
630
551
|
|
|
631
552
|
Returns the chunk's bounding HTML, slot annotations, nested chunk names, and
|
|
632
553
|
metadata (primary tag, kind, source page). For chunks that appear on multiple
|
|
633
554
|
pages (reusable slot chunks like \`auth-card-header\`, \`reg-step-header\`),
|
|
634
|
-
returns an \`instances\` array
|
|
555
|
+
returns an \`instances\` array \u2014 one entry per page where the chunk appears.
|
|
635
556
|
|
|
636
557
|
The HTML is suitable for direct rendering / inclusion in an A2UI message
|
|
637
558
|
construction prompt.`,
|
|
638
559
|
{
|
|
639
|
-
name: z.string().describe('The chunk name, e.g. "dashboard-kpi-grid", "auth-signin-card-email", "code-language"')
|
|
560
|
+
name: z.string().describe('The chunk name, e.g. "dashboard-kpi-grid", "auth-signin-card-email", "code-language"')
|
|
640
561
|
},
|
|
641
562
|
async ({ name }) => {
|
|
642
563
|
const rec = getGenUIChunk(name);
|
|
643
564
|
if (!rec) {
|
|
644
565
|
return {
|
|
645
566
|
isError: true,
|
|
646
|
-
content: [{ type:
|
|
567
|
+
content: [{ type: "text", text: JSON.stringify({ error: "chunk not found", name }, null, 2) }]
|
|
647
568
|
};
|
|
648
569
|
}
|
|
649
|
-
return { content: [{ type:
|
|
650
|
-
}
|
|
570
|
+
return { content: [{ type: "text", text: JSON.stringify(rec, null, 2) }] };
|
|
571
|
+
}
|
|
651
572
|
);
|
|
652
|
-
|
|
653
573
|
server.tool(
|
|
654
|
-
|
|
574
|
+
"lookup_chunk",
|
|
655
575
|
`List every chunk whose primary element is \`<component_name>\`.
|
|
656
576
|
|
|
657
577
|
Useful for "show me every page that opens with a \`<card-ui raw>\`" or "every
|
|
@@ -659,54 +579,41 @@ chunk built around a \`<grid-ui>\` root." Returns chunk names + kinds + sources.
|
|
|
659
579
|
|
|
660
580
|
Pair with \`get_chunk\` to fetch full records for any of the returned names.`,
|
|
661
581
|
{
|
|
662
|
-
component_name: z.string().describe('Component tag name, e.g. "card-ui", "grid-ui", "drawer-ui"')
|
|
582
|
+
component_name: z.string().describe('Component tag name, e.g. "card-ui", "grid-ui", "drawer-ui"')
|
|
663
583
|
},
|
|
664
584
|
async ({ component_name }) => {
|
|
665
585
|
const recs = lookupChunksByPrimary(component_name);
|
|
666
586
|
return {
|
|
667
587
|
content: [{
|
|
668
|
-
type:
|
|
588
|
+
type: "text",
|
|
669
589
|
text: JSON.stringify({
|
|
670
590
|
component: component_name,
|
|
671
591
|
count: recs.length,
|
|
672
|
-
chunks: recs.map((r) =>
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
slots
|
|
677
|
-
nested
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
592
|
+
chunks: recs.map((r) => {
|
|
593
|
+
const rec = r;
|
|
594
|
+
const instances = rec["instances"];
|
|
595
|
+
const firstInstance = instances?.[0];
|
|
596
|
+
const slots = rec["slots"] ?? firstInstance?.["slots"] ?? [];
|
|
597
|
+
const nested = rec["nested"] ?? firstInstance?.["nested"] ?? [];
|
|
598
|
+
return {
|
|
599
|
+
name: rec["name"],
|
|
600
|
+
kind: rec["kind"],
|
|
601
|
+
page: rec["page"] ?? firstInstance?.["page"],
|
|
602
|
+
slots: slots.map((s) => s.name),
|
|
603
|
+
nested
|
|
604
|
+
};
|
|
605
|
+
})
|
|
606
|
+
}, null, 2)
|
|
607
|
+
}]
|
|
681
608
|
};
|
|
682
|
-
}
|
|
609
|
+
}
|
|
683
610
|
);
|
|
684
|
-
|
|
685
|
-
// ── Chunk-aware composition + multi-turn refinement ──────────────────
|
|
686
|
-
// `compose_from_chunks`, `refine_composition`, `get_state`, `report_issue`
|
|
687
|
-
// share the LLM bridge + state-cache + issue-reporter + chunk-refiner
|
|
688
|
-
// stack. Extracted to tools/synthesis.js.
|
|
689
|
-
//
|
|
690
|
-
// Spec: docs/specs/genui-multiturn-architecture.md (Phase A) +
|
|
691
|
-
// docs/specs/genui-chunk-marker.md.
|
|
692
|
-
|
|
693
611
|
registerSynthesisTools(server);
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
// ── Start ──
|
|
697
|
-
|
|
698
612
|
async function main() {
|
|
699
613
|
const transport = new StdioServerTransport();
|
|
700
|
-
|
|
701
|
-
// (Auto-ingest of exemplar-derived patterns retired 2026-04-28 in
|
|
702
|
-
// mcp 0.0.5. The chunk corpus + chunk-aware synthesizer are the
|
|
703
|
-
// training surface now; the legacy extract → ingest path that pulled
|
|
704
|
-
// 70 patterns from prose exemplars on every server boot is gone.)
|
|
705
|
-
|
|
706
614
|
await server.connect(transport);
|
|
707
615
|
const catalog = await getCatalog();
|
|
708
616
|
const traits = getTraits();
|
|
709
617
|
console.error(`AdiaUI MCP Server running (${catalog.totalTypes} components, ${traits.length} traits, ${_zettelBoot.compositionCount} compositions)`);
|
|
710
618
|
}
|
|
711
|
-
|
|
712
619
|
main().catch(console.error);
|