pi-show-me 0.1.0-alpha.1

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/CONTEXT.md ADDED
@@ -0,0 +1,54 @@
1
+ # show-me-mcp
2
+
3
+ Domain vocabulary for helping agents choose and organize explanations while ensuring the quality of display artifacts.
4
+
5
+ ## Language
6
+
7
+ **Expression intent**: What the reader needs to understand, including the relationships, order, ownership, and emphasis that must be preserved.
8
+
9
+ **Display form**: The structure used to express intent: pseudocode, text trees, Mermaid, diff, or HTML.
10
+ _Avoid_: Image type, terminal mode
11
+
12
+ **Expression element**: A semantic building block that helps an agent organize content, such as an entity, step, group, relation, branch, note, comparison, or emphasis.
13
+ _Avoid_: Coordinates, drawing controls
14
+
15
+ **Expression recipe**: A reference example that combines expression elements for a particular explanation task without requiring a single display form.
16
+
17
+ **Expression library**: A collection of domain-specific expression elements, recipes, and their documentation, supplied by the project or a user.
18
+
19
+ **Component library**: A collection of visual components and style resources for a display form. It can represent expression elements but is distinct from their semantic definitions.
20
+
21
+ **Display adaptation**: Rules mapping expression elements to a display form and its components, including supported capabilities and limitations.
22
+
23
+ **Extension contract**: The shared rules expression and component libraries follow when participating in discovery, validation, display, and quality checks.
24
+
25
+ **Display artifact**: The text, diagram, or page actually presented to the reader. A single display form can be delivered in different file formats.
26
+ _Avoid_: Display form
27
+
28
+ **Display environment**: The client that presents an artifact, together with constraints such as dimensions, fonts, and rendering capabilities.
29
+
30
+ **Display defect**: A layout problem that impedes understanding, including occlusion, overlap, clipping, overflow, or ambiguous connector endpoints.
31
+
32
+ **Automatic repair**: Adjusting layout to eliminate display defects while preserving expression intent.
33
+
34
+ **Quality check**: Assessing the readability and semantic fidelity of an actual display artifact in a specified environment.
35
+
36
+ **Quality boundary**: The range of input sizes and display environments in which display quality can currently be verified and guaranteed.
37
+
38
+ **Template**: Reusable organization rules for a recurring explanation task; these may reference expression recipes and elements.
39
+
40
+ ## Existing diagram primitives
41
+
42
+ **VisualSpec**: A versioned specification describing a structured diagram.
43
+
44
+ **Stack**: An arrangement expressing explicit horizontal or vertical reading order without implying relationships.
45
+
46
+ **Group**: A grouping that expresses ownership or containment.
47
+
48
+ **Card**: An addressable entity or step in a diagram.
49
+
50
+ **Note**: A non-addressable annotation expressing an explanation, risk, or constraint.
51
+
52
+ **Relation**: An explicitly declared relationship between entities.
53
+
54
+ **Legend**: An explanation of the symbols, states, or visual markings used in a diagram.
package/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # pi-show-me
2
+
3
+ Source repository: [alchemistklk/show-me-mcp](https://github.com/alchemistklk/show-me-mcp).
4
+
5
+ Help agents explain complex ideas clearly and automatically fix layout problems in the resulting artifacts.
6
+
7
+ The agent chooses the display form and organizes the content. The MCP handles layout, detects and repairs occlusion, overlap, text overflow, and connector conflicts, and verifies the final artifact. The intended workflow does not require agents or users to repeatedly adjust diagrams by hand.
8
+
9
+ ## Project documentation
10
+
11
+ - [Project specification](docs/project-spec.md): goals, responsibilities, five display forms, quality assurance, and delivery scope.
12
+ - [Expression elements](docs/expression-elements.md): element meanings, use cases, and composition examples.
13
+ - [Extensibility](docs/extensibility.md): separation between user expression libraries, component libraries, and the core engine.
14
+ - [Module design](docs/module-design.md): the adopted design, seams, and incremental validation strategy.
15
+ - [First quality slice](docs/quality-slice.md): implemented HTML layout repair, expression libraries, and MCP tools.
16
+ - [Four built-in forms](docs/native-forms.md): input, repair, and delivery contracts for Mermaid, pseudocode, text trees, and diff.
17
+ - [Acceptance criteria](docs/acceptance.md): quality checks, failure examples, existing evidence, and upcoming milestones.
18
+ - [Domain glossary](CONTEXT.md): shared project terminology.
19
+ - [Existing prototype](docs/prototype-status.md): operation and limitations.
20
+ - [Primitive contract v0.1](docs/primitive-contract-v0.1.md): compatibility reference for the existing interface.
21
+
22
+ ## Goals and current status
23
+
24
+ | Goal | Current implementation |
25
+ | --- | --- |
26
+ | Five forms: pseudocode, text trees, Mermaid, diff, and HTML | All five are available through the new interface. HTML supports declarative libraries; the other four are built-in capabilities, each with a defined support scope. |
27
+ | Automatic layout repair inside the MCP | HTML label avoidance, Mermaid reflow and reinspection, text wrapping by display width, and diff display formatting are implemented. Arbitrarily complex diagrams are not guaranteed to be repairable. |
28
+ | Final display quality verification | HTML and Mermaid artifacts are verified in Chromium; text forms validate width and content preservation. Evidence records the verification scope and content hashes. |
29
+ | Public repository and Pi plugin distribution | The repository is public on GitHub. The native Pi extension is distributed as `pi-show-me` on npm. |
30
+
31
+ PNG is an optional artifact format, not a core display category. The existing `terminal | image | both` options and PNG fallback belong to the legacy prototype, not the target design.
32
+
33
+ ## Install in Pi
34
+
35
+ The native Pi entry registers `describe_display` and `render_display` directly, without an MCP adapter. The alpha package is published on npm. Install it with `pi install npm:pi-show-me@alpha`. To try this checkout:
36
+
37
+ ```bash
38
+ pi install /absolute/path/to/show-me-mcp
39
+ ```
40
+
41
+ Disable duplicate tools from an existing MCP adapter before enabling the native extension. Reload Pi after installation.
42
+
43
+ Artifacts are saved under `.pi/artifacts/show-me` in the current project. Override this with `SHOW_ME_ARTIFACT_DIR`. Text layout uses the current terminal width, or `SHOW_ME_TERMINAL_COLUMNS` when set; supported widths are 24–240 columns. Non-interactive sessions default to 120 columns. HTML and Mermaid return file paths; text forms also return a fenced preview. Diff keeps the applicable patch separate from its wrapped preview.
44
+
45
+ The npm package also exposes `show-me-mcp` as a stdio MCP command. Pi exposes only the two current tools; the MCP command retains legacy `render_visual` support.
46
+
47
+ ## Run locally
48
+
49
+ Node.js and npm are required. Text trees, pseudocode, and diff do not need a browser. HTML, Mermaid, and the full test suite require a local Chrome or Chromium executable, which can be specified with `SHOW_ME_CHROMIUM_BIN`. The legacy image path also requires `rsvg-convert`. The project does not automatically download a browser or use your personal browser profile.
50
+
51
+ ```bash
52
+ npm ci
53
+ npm test
54
+ npm run render:fixture
55
+ npm run render:composition
56
+ npm run render:quality-demo
57
+ npm run render:native-demo
58
+ node bin/mcp-server.mjs
59
+ ```
60
+
61
+ If your machine uses the `with-env` environment wrapper, prefix the commands with it. Examples write their artifacts to `artifacts/`. Local Pi configuration, tool caches, dependencies, and generated artifacts are excluded from Git.
62
+
63
+ The MCP tools `describe_display` and `render_display` map to `describe` and `render`, supporting `html | mermaid | pseudocode | tree | diff`. Query a form's schema and examples before using an unfamiliar input format. Only HTML accepts expression-library references. The legacy `render_visual` tool remains available for compatibility; see the [prototype guide](docs/prototype-status.md) for its inputs.
64
+
65
+ Licensed under [Apache-2.0](LICENSE). The first npm release is `0.1.0-alpha.1` (tag: `alpha`).
66
+
67
+ ## Migrating from show-me-mcp
68
+
69
+ The npm package has been renamed to `pi-show-me`. The repository and MCP command retain the name `show-me-mcp`. Replace the old Pi package and reload Pi:
70
+
71
+ ```bash
72
+ pi remove npm:show-me-mcp
73
+ pi install npm:pi-show-me@alpha
74
+ ```
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env node
2
+ import { createInterface } from "node:readline";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { writeFile, mkdir } from "node:fs/promises";
6
+ import { randomUUID } from "node:crypto";
7
+ import { compositionInputSchema, renderMermaid, renderToFiles, visualSpecInputSchema, createShowMe, displayRequestSchema, catalogQuerySchema } from "../src/index.mjs";
8
+ import { createChromiumHost } from "../src/hosts/chromium.mjs";
9
+
10
+ const here = path.dirname(fileURLToPath(import.meta.url));
11
+ const defaultArtifacts = path.resolve(process.env.SHOW_ME_ARTIFACT_DIR ?? path.resolve(here, "../artifacts"));
12
+ const textOptions = { terminalColumns: Number(process.env.SHOW_ME_TERMINAL_COLUMNS ?? 120) };
13
+ const catalog = createShowMe(textOptions);
14
+ let displayHost;
15
+ let displayEngine;
16
+
17
+ async function closeDisplayHost() { await displayHost?.close(); }
18
+ process.once("SIGTERM", () => { closeDisplayHost().finally(() => process.exit(0)); });
19
+ process.once("SIGINT", () => { closeDisplayHost().finally(() => process.exit(0)); });
20
+
21
+ function send(message) {
22
+ process.stdout.write(`${JSON.stringify(message)}\n`);
23
+ }
24
+
25
+ function result(id, value) {
26
+ send({ jsonrpc: "2.0", id, result: value });
27
+ }
28
+
29
+ function error(id, code, message) {
30
+ send({ jsonrpc: "2.0", id, error: { code, message } });
31
+ }
32
+
33
+ function fencedText(text) {
34
+ const longest = Math.max(0, ...[...text.matchAll(/`+/g)].map(m => m[0].length));
35
+ const fence = "`".repeat(Math.max(3, longest + 1));
36
+ return `${fence}text\n${text}\n${fence}`;
37
+ }
38
+
39
+ async function handle(request) {
40
+ const { id, method, params = {} } = request;
41
+ if (method === "initialize") {
42
+ result(id, {
43
+ protocolVersion: "2025-11-25",
44
+ capabilities: { tools: { listChanged: false } },
45
+ serverInfo: { name: "show-me-mcp", version: "0.0.0-prototype" },
46
+ });
47
+ return;
48
+ }
49
+ if (method === "notifications/initialized") return;
50
+ if (method === "ping") {
51
+ result(id, {});
52
+ return;
53
+ }
54
+ if (method === "tools/list") {
55
+ result(id, {
56
+ tools: [
57
+ {
58
+ name: "render_visual",
59
+ title: "Render structured visual",
60
+ description: "Legacy template/primitive renderer for terminal Mermaid and image artifacts. Prefer render_display for the verified five-form interface; this tool retains the original compatibility behavior.",
61
+ inputSchema: {
62
+ type: "object",
63
+ additionalProperties: false,
64
+ required: ["spec"],
65
+ properties: {
66
+ spec: { anyOf: [visualSpecInputSchema, compositionInputSchema] },
67
+ outputName: { type: "string", description: "Safe artifact basename without an extension." },
68
+ presentation: {
69
+ type: "string",
70
+ enum: ["terminal", "image", "both"],
71
+ default: "image",
72
+ description: "terminal returns fenced Mermaid; image returns PNG; both returns both presentations.",
73
+ },
74
+ },
75
+ },
76
+ },
77
+ { name: "describe_display", description: "Discover native Mermaid flowcharts, pseudocode, text trees and diff schemas, plus extensible HTML elements. Only HTML uses expression libraries.", inputSchema: catalogQuerySchema },
78
+ { name: "render_display", description: "Render and verify HTML, Mermaid flowcharts, pseudocode, text trees or diff. Automatically repair layout within declared limits; preserve semantics and selected form. Text forms need no browser; HTML and Mermaid require local Chromium. Diff delivers an applicable patch separately from its wrapped display. Only HTML accepts external elements.", inputSchema: displayRequestSchema },
79
+ ],
80
+ });
81
+ return;
82
+ }
83
+ if (method === "tools/call") {
84
+ if (["describe_display", "render_display"].includes(params.name)) {
85
+ try {
86
+ let value;
87
+ const content = [];
88
+ if (params.name === "describe_display") value = await catalog.describe(params.arguments ?? {});
89
+ else {
90
+ // Input/capability errors do not require launching a browser.
91
+ value = await catalog.render(params.arguments);
92
+ if (value.reason === "environment-unavailable") {
93
+ try {
94
+ if (!displayEngine) {
95
+ displayHost = await createChromiumHost();
96
+ displayEngine = createShowMe({ host: displayHost, ...textOptions });
97
+ }
98
+ value = await displayEngine.render(params.arguments);
99
+ } catch (caught) {
100
+ value = { ...value, details: caught instanceof Error ? caught.message : String(caught) };
101
+ }
102
+ }
103
+ if (value.status === "ready") {
104
+ const base = path.join(defaultArtifacts, `display-${randomUUID()}`);
105
+ const extension = { html: "html", mermaid: "svg", tree: "txt", pseudocode: "txt", diff: "diff" }[value.artifact.form];
106
+ const artifactPath = `${base}.${extension}`;
107
+ await mkdir(defaultArtifacts, { recursive: true });
108
+ await writeFile(artifactPath, value.artifact.content, "utf8");
109
+ const artifact = { form: value.artifact.form, mimeType: value.artifact.mimeType, path: artifactPath };
110
+ if (value.artifact.source) {
111
+ await writeFile(`${base}.mmd`, value.artifact.source.content, "utf8");
112
+ artifact.source = { mimeType: value.artifact.source.mimeType, path: `${base}.mmd` };
113
+ }
114
+ if (value.artifact.presentation) {
115
+ await writeFile(`${base}.display.txt`, value.artifact.presentation.content, "utf8");
116
+ artifact.presentation = { path: `${base}.display.txt`, notice: value.artifact.presentation.notice };
117
+ }
118
+ if (["tree", "pseudocode", "diff"].includes(artifact.form)) {
119
+ const text = value.artifact.presentation?.content ?? value.artifact.content;
120
+ if (text.length <= 24000) content.push({ type: "text", text: (value.artifact.presentation?.notice ? `${value.artifact.presentation.notice}\n\n` : "") + fencedText(text) });
121
+ }
122
+ value = { ...value, artifact };
123
+ }
124
+ }
125
+ content.push({ type: "text", text: JSON.stringify(value) });
126
+ result(id, { content, structuredContent: value, isError: value.status === "not-ready" });
127
+ } catch (caught) {
128
+ result(id, { content: [{ type: "text", text: caught instanceof Error ? caught.message : String(caught) }], isError: true });
129
+ }
130
+ return;
131
+ }
132
+ if (params.name !== "render_visual") {
133
+ error(id, -32602, `unknown tool: ${params.name}`);
134
+ return;
135
+ }
136
+ try {
137
+ const args = params.arguments ?? {};
138
+ const outputName = String(args.outputName ?? `visual-${Date.now()}`)
139
+ .replace(/[^a-zA-Z0-9_-]+/g, "-")
140
+ .replace(/^-+|-+$/g, "") || "visual";
141
+ const requestedPresentation = args.presentation ?? "image";
142
+ if (!["terminal", "image", "both"].includes(requestedPresentation)) throw new TypeError("presentation must be terminal, image, or both");
143
+ const rendered = await renderToFiles(args.spec, path.join(defaultArtifacts, outputName));
144
+ const terminal = requestedPresentation === "terminal" || requestedPresentation === "both" ? renderMermaid(args.spec) : null;
145
+ const fallback = terminal?.diagnostics.terminal.fallbackRecommended ?? false;
146
+ const presentation = fallback ? "image" : requestedPresentation;
147
+ const structuredContent = {
148
+ presentation,
149
+ requestedPresentation,
150
+ pngPath: rendered.pngPath,
151
+ svgPath: rendered.svgPath,
152
+ ...(terminal ? { mermaidDiagnostics: terminal.diagnostics } : {}),
153
+ ...(terminal && !fallback ? { mermaid: terminal.mermaid } : {}),
154
+ diagnostics: rendered.diagnostics,
155
+ };
156
+ const content = [];
157
+ if (terminal && !fallback) content.push({ type: "text", text: `\`\`\`mermaid\n${terminal.mermaid}\n\`\`\`` });
158
+ if (presentation === "image" || presentation === "both") {
159
+ content.push({ type: "image", data: rendered.png.toString("base64"), mimeType: "image/png" });
160
+ }
161
+ content.push({ type: "text", text: JSON.stringify(structuredContent) });
162
+ result(id, {
163
+ content,
164
+ structuredContent,
165
+ isError: false,
166
+ });
167
+ } catch (caught) {
168
+ result(id, {
169
+ content: [{ type: "text", text: caught instanceof Error ? caught.message : String(caught) }],
170
+ isError: true,
171
+ });
172
+ }
173
+ return;
174
+ }
175
+ if (id !== undefined) error(id, -32601, `method not found: ${method}`);
176
+ }
177
+
178
+ const lines = createInterface({ input: process.stdin, crlfDelay: Infinity });
179
+ try {
180
+ for await (const line of lines) {
181
+ if (!line.trim()) continue;
182
+ try {
183
+ await handle(JSON.parse(line));
184
+ } catch (caught) {
185
+ console.error(caught);
186
+ error(null, -32700, "parse error");
187
+ }
188
+ }
189
+ } finally { await closeDisplayHost(); }
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import { readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { renderToFiles } from "../src/index.mjs";
5
+
6
+ const [inputPath, outputBase] = process.argv.slice(2);
7
+ if (!inputPath || !outputBase) {
8
+ console.error("usage: node bin/render-visual.mjs <visual-spec.json> <output-base>");
9
+ process.exit(2);
10
+ }
11
+
12
+ const spec = JSON.parse(await readFile(path.resolve(inputPath), "utf8"));
13
+ const result = await renderToFiles(spec, outputBase);
14
+ console.log(JSON.stringify({ svgPath: result.svgPath, pngPath: result.pngPath, diagnostics: result.diagnostics }, null, 2));
@@ -0,0 +1,64 @@
1
+ # Quality and acceptance criteria
2
+
3
+ Status: target acceptance specification, 2026-09-08. All five forms have limited-scope implementations and tests; this does not establish quality guarantees for arbitrary inputs or every client.
4
+
5
+ ## Common gates
6
+
7
+ - Semantic fidelity: preserve identities, endpoints, relation types and directions, groups, and reading order; do not silently omit or truncate content.
8
+ - Complete text: no container clipping or unreadable overlap; measure long text and mixed English/Chinese content for the display environment.
9
+ - Clear graphics: labels must not obscure arrows, connectors must not cross unrelated nodes, and endpoints must be identifiable. Necessary crossings should be distinguishable; do not promise zero crossings for arbitrary graphs.
10
+ - Correct form: layout must not change tree hierarchy, pseudocode branch ownership, or diff addition/deletion semantics.
11
+ - Explicit environment: record the renderer, dimensions, fonts, and other conditions affecting the result.
12
+ - Terminating repair: the loop has a budget; distinguish passing, failing, and unsupported cases.
13
+ - Reproducibility: identical inputs and environments produce stable results; record initial defects, repairs, and final checks.
14
+
15
+ ## Failure examples and existing evidence
16
+
17
+ | Example | Expected result | Current evidence / gap |
18
+ | --- | --- | --- |
19
+ | Card ID is `note-1` or `derived-legend` | Arrows point only to the Card | Endpoint-collision regression in `test/render.test.mjs` |
20
+ | Relation labels contain `&`, `"`, `|`, or Chinese text | No lost relations or invented nodes | Text-preservation checks for four relation kinds in `test/mermaid.test.mjs` |
21
+ | Card/Relation IDs contain surrounding whitespace | Endpoints remain consistent after normalization | Covered by Mermaid regressions |
22
+ | Horizontal flow between Cards of different heights | No meaningless short dogleg | `fixtures/horizontal-dogleg-regression.json` and horizontal-connector tests |
23
+ | A Stack directly contains another Stack | Reading direction and structure are preserved | The legacy path diagnoses and falls back to PNG; automatic Mermaid repair for this input remains incomplete |
24
+ | Complex diagrams reach 176/360 columns | Automatic repair and acceptance in the declared environment | Reproducible with the two complex fixtures; the legacy path only detects width and falls back |
25
+ | A label covers an arrow | Automatic avoidance makes both readable | HTML sequence tests in `test/show-me.test.mjs` verify single-call repair and final HTML reinspection; general routing remains incomplete |
26
+ | Connectors cross unrelated nodes / nodes overlap | Automatic avoidance, spacing adjustments, and reinspection | Native Mermaid has geometry checks and bounded reflow; path checks are sampled, not a guarantee for arbitrary graphs |
27
+ | Long labels, mixed-language widths, deep trees | Full text and hierarchy survive | Text-tree tests cover Unicode grapheme wrapping, hierarchy prefixes, reconstruction, and explicit limit failures |
28
+ | Pseudocode branches and long diff lines | No branch-ownership or addition/deletion changes | Pseudocode tests cover nested branches and loops; diff tests cover patch application and a separate wrapped view |
29
+ | Complex HTML in narrow and wide windows | No clipping or occlusion; relationships remain clear | Simple HTML sequences are verified; complex responsive layout is not implemented |
30
+
31
+ Run `npm test`. The current baseline has 31 local tests covering legacy MCP, HTML, the four built-in forms, and delivered files. The full suite requires local Chromium and runs test files serially to prevent browser/rasterizer contention from causing protocol timeouts. Test count is not a completion metric.
32
+
33
+ ## Record for each acceptance run
34
+
35
+ 1. Input fixture, selected form, and required semantic invariants.
36
+ 2. Display environment and tool versions.
37
+ 3. Initial defects and reproducible checks.
38
+ 4. Repairs actually performed and budget consumed.
39
+ 5. Final artifact, automated checks, and any necessary visual review.
40
+ 6. Whether the agent had to intervene in layout, plus remaining limitations.
41
+
42
+ Mark unverified surfaces as UNKNOWN. A PNG file does not establish visual acceptance; a passing Pi parser does not establish an interactive Pi window check; local tests do not establish CI, release, or all-client acceptance.
43
+
44
+ ## Extension acceptance
45
+
46
+ The following are extension goals. Current tests cover adding/removing the declarative example library, shared validation, discovery, duplicate identities, missing elements, and input schemas. Arbitrary UI components, resource changes, dynamic loading, and cross-client reproduction remain uncovered:
47
+
48
+ - Register, discover, use, and remove an example library outside the core source without modifying the engine.
49
+ - Default and example libraries use the same contract and quality workflow; one artifact can combine elements from both.
50
+ - Namespaces distinguish same-named elements. Missing libraries or incompatible versions produce explicit errors rather than substitution.
51
+ - Agents can discover custom element meanings, constraints, examples, and supported forms. Unsupported forms are not presented as supported.
52
+ - Long labels, font loading, or dimension changes in user components trigger measurement and avoidance again; third-party components cannot bypass final checks.
53
+ - Unmeasurable components, unsuccessful repairs, or unsupported environments cannot receive a quality pass.
54
+ - Record library, adaptation, and core versions; results must be reproducible for fixed inputs and environments.
55
+
56
+ ## Implementation sequence
57
+
58
+ 1. Complete the failure examples and define supported input sizes and environments. Turn pending examples into checks that can fail. Validate the extension seam with an independent library rather than hard-coding the default catalog.
59
+ 2. Establish a complete detect → repair → recheck loop for the first selected defects, such as label occlusion, text overflow, or node overlap.
60
+ 3. Extend each of the five forms with recipes, checks, repair strategies, and final display evidence.
61
+ 4. Define verifiable Pi and desktop display paths and test client differences.
62
+ 5. Complete remaining license, package-release, and Pi plugin distribution work. The repository is already public on GitHub.
63
+
64
+ This specification does not assume one layout engine for every form or PNG/Mermaid as the only artifact format.
@@ -0,0 +1,57 @@
1
+ # Expression elements and recipes
2
+
3
+ Status: agreed first-batch expression references. These are semantic terms, not a newly implemented input schema, and need not map one-to-one to existing diagram primitives.
4
+
5
+ This catalog provides expression references and a starting point for the default HTML library. HTML users may supply their own elements, recipes, and component mappings under the [extension contract](extensibility.md). Mermaid, pseudocode, text trees, and diff use built-in native structures only, with no external expression libraries.
6
+
7
+ ## Element catalog
8
+
9
+ | Element | Meaning and use cases | Composition example |
10
+ | --- | --- | --- |
11
+ | Entity / step | A system, role, operation, or capability | Client and server; send request and handle response |
12
+ | Group | Ownership, containment, stage, or responsibility | Group authentication and request handling under the server |
13
+ | Relation | A call, dependency, data flow, or feedback | Client calls server; failure feeds back to a retry step |
14
+ | Branch | An explicit condition and its outcome | Finish on success; retry on failure while below the limit |
15
+ | Note | An explanation, constraint, risk, or conclusion | At most 3 retries; the note is not a request recipient |
16
+ | Comparison / change | A before-and-after difference or alternative | The old flow fails immediately; the new flow adds bounded retries |
17
+ | Emphasis | A focus, critical path, or important object | Emphasize the retry limit without treating it as a new state |
18
+
19
+ Grouping creates no relationship; spatial order creates no causality; emphasis creates no business state. The agent must declare semantics explicitly.
20
+
21
+ ## Recipe: explain failure and retry
22
+
23
+ ```text
24
+ Steps: send request → handle request
25
+ Branch: success / failure
26
+ Feedback: failure below the retry limit → send again
27
+ Note: at most 3 retries
28
+ Emphasis: retry limit
29
+ ```
30
+
31
+ Use pseudocode to explain logic, Mermaid to explain interactions, or diff to explain the change that introduced retries. One recipe does not mandate a single form. The tool must retain conditions and limits rather than omit them to simplify the diagram.
32
+
33
+ ## Recipe: explain module responsibilities
34
+
35
+ ```text
36
+ Groups: client / server
37
+ Entities: page, request entry point, permission check
38
+ Relations: page calls entry point; entry point depends on permission check
39
+ Note: permission failure prevents further processing
40
+ ```
41
+
42
+ Use a text tree when explaining ownership alone and Mermaid when explaining calls. A text tree should not disguise a call relationship as directory containment.
43
+
44
+ ## Recipe: explain a change
45
+
46
+ ```text
47
+ Comparison: before / after
48
+ Steps: save → return result
49
+ Change: check whether content has changed before saving
50
+ Emphasis: return the cache immediately when unchanged
51
+ ```
52
+
53
+ Use diff for small changes, retaining enough original steps to identify the context. Choose HTML when several interactive states are needed. Automatic wrapping must not change diff markers or the meaning of original lines.
54
+
55
+ ## Relationship to the prototype
56
+
57
+ Existing Card, Group, Relation, and Note primitives can represent some of these elements; Stack specifies reading order and layout constraints. Cross-form interfaces for branches, comparison, and emphasis are not yet finalized. Do not mistake this catalog for the current MCP tool parameter schema.