@diffui.mcp/install 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,10 +14,14 @@ Thin Node launcher for the diffui MCP server. Cursor (and other MCP hosts) run:
14
14
  }
15
15
  ```
16
16
 
17
- On first start, the launcher downloads the platform `diffui-mcp` binary from
18
- `{DIFFUI_API_BASE}/mcp/` into `~/.diffui/bin/diffui-mcp`, then execs it with
19
- inherited stdio. Credentials can also come from the MCP `authenticate` tool
20
- (`~/.diffui/credentials`).
17
+ On first start, the launcher:
18
+
19
+ 1. Copies the bundled design-first skill to `~/.cursor/skills/diffui/SKILL.md` (updates when
20
+ the launcher npm version changes; set `DIFFUI_SKIP_SKILL_INSTALL=1` to skip).
21
+ 2. Downloads the platform `diffui-mcp` binary from `{DIFFUI_API_BASE}/mcp/` into
22
+ `~/.diffui/bin/diffui-mcp`, then execs it with inherited stdio.
23
+
24
+ Credentials can also come from the MCP `authenticate` tool (`~/.diffui/credentials`).
21
25
 
22
26
  ## Publish to npm
23
27
 
@@ -28,8 +32,14 @@ Prerequisites:
28
32
  2. npm account in the [@diffui.mcp](https://www.npmjs.com/org/diffui.mcp) org.
29
33
 
30
34
  ```bash
35
+ ./scripts/publish-mcp-install.sh
36
+ ```
37
+
38
+ This syncs `skills/diffui/SKILL.md` into the package, then publishes. Or manually:
39
+
40
+ ```bash
41
+ ./scripts/sync-mcp-skill.sh
31
42
  cd packages/mcp-install
32
- npm login
33
43
  npm publish --access public
34
44
  ```
35
45
 
package/launcher.mjs CHANGED
@@ -1,20 +1,33 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * diffui MCP launcher for Cursor / Claude / npx.
4
- * Ensures ~/.diffui/bin/diffui-mcp exists, then execs it with inherited stdio.
4
+ * Ensures ~/.diffui/bin/diffui-mcp exists, installs the Cursor skill to
5
+ * ~/.cursor/skills/diffui on first start (or when the launcher version changes),
6
+ * then execs the MCP binary with inherited stdio.
5
7
  *
6
8
  * Env (from Cursor mcp.json or shell):
7
9
  * DIFFUI_API_BASE — API origin (default https://diffui.ai)
8
10
  * DIFFUI_API_KEY — optional; authenticate tool can store ~/.diffui/credentials
11
+ * DIFFUI_SKIP_SKILL_INSTALL — set to 1 to skip copying SKILL.md
9
12
  */
10
13
  import { spawn, spawnSync } from "node:child_process";
11
- import { chmodSync, createWriteStream, existsSync, mkdirSync } from "node:fs";
14
+ import {
15
+ chmodSync,
16
+ copyFileSync,
17
+ createWriteStream,
18
+ existsSync,
19
+ mkdirSync,
20
+ readFileSync,
21
+ writeFileSync,
22
+ } from "node:fs";
12
23
  import { arch, homedir, platform } from "node:os";
13
24
  import { dirname, join } from "node:path";
25
+ import { fileURLToPath } from "node:url";
14
26
  import { pipeline } from "node:stream/promises";
15
27
  import { get as httpsGet } from "node:https";
16
28
  import { get as httpGet } from "node:http";
17
29
 
30
+ const launcherDir = dirname(fileURLToPath(import.meta.url));
18
31
  const base = String(process.env.DIFFUI_API_BASE || "https://diffui.ai").replace(/\/+$/, "");
19
32
  const dest = join(homedir(), ".diffui", "bin", "diffui-mcp");
20
33
 
@@ -31,6 +44,43 @@ function binaryName() {
31
44
  throw new Error(`diffui-mcp: unsupported platform ${platform()}-${arch()}`);
32
45
  }
33
46
 
47
+ function launcherVersion() {
48
+ try {
49
+ const pkg = JSON.parse(readFileSync(join(launcherDir, "package.json"), "utf8"));
50
+ return String(pkg.version || "0.0.0");
51
+ } catch {
52
+ return "0.0.0";
53
+ }
54
+ }
55
+
56
+ function ensureCursorSkill() {
57
+ if (process.env.DIFFUI_SKIP_SKILL_INSTALL === "1") return;
58
+
59
+ const skillSrc = join(launcherDir, "skill", "SKILL.md");
60
+ if (!existsSync(skillSrc)) return;
61
+
62
+ const skillDir = join(homedir(), ".cursor", "skills", "diffui");
63
+ const skillDest = join(skillDir, "SKILL.md");
64
+ const versionStamp = join(skillDir, ".diffui-install-version");
65
+ const version = launcherVersion();
66
+
67
+ let installed = "";
68
+ if (existsSync(versionStamp)) {
69
+ try {
70
+ installed = readFileSync(versionStamp, "utf8").trim();
71
+ } catch {
72
+ installed = "";
73
+ }
74
+ }
75
+
76
+ if (installed === version && existsSync(skillDest)) return;
77
+
78
+ mkdirSync(skillDir, { recursive: true });
79
+ copyFileSync(skillSrc, skillDest);
80
+ writeFileSync(versionStamp, `${version}\n`, "utf8");
81
+ process.stderr.write(`diffui-mcp: installed Cursor skill at ${skillDest}\n`);
82
+ }
83
+
34
84
  async function download(url, path) {
35
85
  const getter = url.startsWith("https:") ? httpsGet : httpGet;
36
86
  await new Promise((resolve, reject) => {
@@ -72,6 +122,7 @@ async function ensureBinary() {
72
122
  return dest;
73
123
  }
74
124
 
125
+ ensureCursorSkill();
75
126
  const bin = await ensureBinary();
76
127
  const child = spawn(bin, [], {
77
128
  stdio: "inherit",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@diffui.mcp/install",
3
- "version": "0.1.0",
4
- "description": "Launcher for the diffui MCP server (stdio). Used by Cursor Add to Cursor.",
3
+ "version": "0.2.0",
4
+ "description": "Launcher for the diffui MCP server (stdio). Installs the Cursor skill on first start.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "bin": {
@@ -9,7 +9,8 @@
9
9
  },
10
10
  "files": [
11
11
  "launcher.mjs",
12
- "README.md"
12
+ "README.md",
13
+ "skill/SKILL.md"
13
14
  ],
14
15
  "engines": {
15
16
  "node": ">=18"
package/skill/SKILL.md ADDED
@@ -0,0 +1,231 @@
1
+ ---
2
+ name: diffui-designer
3
+ description: >-
4
+ Runs the diffui MCP workflow before any HTML/CSS/JS is written: create_project,
5
+ generate_options (4 variants), generate_page, create_build_link, then implement
6
+ code from the build markdown. Auth (whoami/authenticate) only on tool errors —
7
+ installs usually include DIFFUI_API_KEY already. REQUIRED when the user asks to
8
+ create, build, or design a webpage, website, landing page, app screen, dashboard,
9
+ or UI — including "create a webpage for …", "design first then build/create in …",
10
+ themed sites (jungle, arctic, etc.), and output paths like demoBuild/. Do NOT
11
+ skip diffui and design manually in prose or jump straight to coding when the
12
+ diffui MCP server is available. Also use when the user mentions diffui.
13
+ ---
14
+
15
+ # Diffui designer
16
+
17
+ You orchestrate diffui (an AI design-generation canvas) through its **MCP tools**.
18
+ The user sees the images you return inline, and can also watch the canvas live
19
+ in their browser. Follow this choreography.
20
+
21
+ ## When this skill applies (required)
22
+
23
+ If the **diffui MCP server** is enabled and the user wants a new webpage or UI
24
+ look — even when they also name an output folder (`demoBuild/bongo`,
25
+ `demoBuild/svalbardLan`, etc.) — you **must** use diffui for the design phase.
26
+ Treat these as the same class of request:
27
+
28
+ - "Create a webpage for …"
29
+ - "Design a landing page …"
30
+ - "Design first, then create/build it in …"
31
+ - "Build a website for …" (when no existing diffui designs are referenced)
32
+
33
+ **Two phases — never merge them:**
34
+
35
+ 1. **Design (diffui MCP)** — `create_project` → `open_canvas` →
36
+ `generate_options` → pick/iterate → (optional `generate_page` for multi-page) →
37
+ `create_build_link`.
38
+ 2. **Implementation (code)** — write HTML/CSS/JS only **after** phase 1, following
39
+ the build markdown from `create_build_link` into the user's target path.
40
+
41
+ **Minimal path (single landing page):** `generate_options` → user picks →
42
+ `create_build_link` → code. Do not require brand creation or extra `generate_page`
43
+ calls for a one-page request.
44
+
45
+ **Forbidden before `generate_options`:**
46
+
47
+ - Creating `index.html`, stylesheets, or app UI files
48
+ - Choosing colors, typography, and layout entirely from scratch
49
+ - "Designing conceptually" in prose instead of calling `generate_options`
50
+
51
+ **After `generate_options`:**
52
+
53
+ - Present options as Option A–D with imageIds
54
+ - User present → ask which to build
55
+ - User said "surprise me" / full trust → pick the strongest fit and say why
56
+ - User unavailable mid-run → wait; do not proceed to code without a pick
57
+
58
+ **Auth (reactive only):** Do not call `whoami` or `authenticate` before starting — the MCP
59
+ install usually includes credentials. If any tool returns not-authenticated, call
60
+ `authenticate` once, then retry. Do not silently fall back to hand-designed UI.
61
+
62
+ **Prompt writing:** Turn the user's request into a visual design prompt (audience, tone,
63
+ sections, layout, color/mood). Do not substitute concept bullets for `generate_options`.
64
+
65
+ **Do not:**
66
+
67
+ - Skip diffui because you can write vanilla HTML/CSS/JS directly.
68
+ - "Design" in chain-of-thought or bullet lists instead of calling `generate_options`.
69
+ - Read `generate_options` tool docs and then decide to design manually.
70
+ - Start creating files in the target directory before diffui options exist.
71
+
72
+ **Only skip diffui** when the user explicitly says not to ("skip design", "no diffui",
73
+ "just code it"), for pure backend tasks, small non-visual edits, or they point you at
74
+ finished diffui designs / a build link with no new design work. If you skip, say so in
75
+ one sentence.
76
+
77
+ ### Example triggers
78
+
79
+ | User says | You do first |
80
+ |---|---|
81
+ | Create a jungle-themed coffee shop page in `demoBuild/bongo` | diffui `generate_options`; code goes in `demoBuild/bongo` after build link |
82
+ | Design the page first, then create it in `demoBuild/svalbardLan` | diffui design phase — "design first" means MCP, not manual concept art |
83
+ | Build me a SaaS pricing page | diffui options → pages → build link → code |
84
+
85
+ ## 0. Setup
86
+
87
+ 1. For a new design session, call `create_project`, then `open_canvas` so the
88
+ user can watch generations stream in. Reuse the same `project_id` for the
89
+ whole session.
90
+ 2. **Auth only on error.** Do not proactively call `whoami`. If a tool fails with
91
+ not-authenticated, call `authenticate` — a browser window opens for one-click
92
+ connect, or pass an API key from diffui → Settings → API as `api_key`. Then
93
+ retry the failed call.
94
+
95
+ ## 1. New design → 4 options
96
+
97
+ When the user describes a design they want:
98
+
99
+ - Call `generate_options` with `count: 4` and **no** `brand_id` (a fresh
100
+ canvas auto-diversifies styles across the options, which is what you want).
101
+ - Present the four images labeled **Option 1–4** and keep the
102
+ `option → imageId` ledger from the tool result. You will need those
103
+ imageIds for every later step — always carry the ledger forward in your
104
+ reasoning.
105
+ - Offer three paths: pick one, see more options (`generate_options` again,
106
+ passing the same `prompt_node_id` to append), or mix elements of options
107
+ (see "Generating with inputs").
108
+
109
+ ## 2. Generating with inputs
110
+
111
+ `generate_with_inputs` handles any request where existing images should
112
+ shape the result. Each input gets a short label; write the prompt
113
+ referencing the labels with `@` — diffui rigs the labeled images as named
114
+ references. Inputs can come from three sources, mixed freely:
115
+
116
+ - **Earlier options** (`image_id` from your ledger) — "combine the top of
117
+ the first option and the bottom of the second":
118
+ `inputs: [{image_id: <opt1>, label: "option-1"}, {image_id: <opt2>,
119
+ label: "option-2"}]`, prompt "Use the top section of @option-1 and the
120
+ bottom section of @option-2, merged into one cohesive page."
121
+ - **Local files** (`file_path`, uploaded automatically) — "use logo.png and
122
+ create a landing page with it in the top right":
123
+ `inputs: [{file_path: "/path/to/logo.png", label: "logo"}]`, prompt
124
+ "Landing page for ... with @logo placed in the top right of the header."
125
+ - **Uploaded assets** (`asset_id` from an earlier `upload_reference`) —
126
+ e.g. a screenshot of the user's current app: "generate a settings page
127
+ matching @screenshot's visual style."
128
+
129
+ Keep spatial phrases tied to their labels ("the header from @option-4",
130
+ "@logo in the top right") — diffui resolves positions per named reference.
131
+ Present the results as new numbered options and update your ledger. Use
132
+ `upload_reference` first when a file will be reused across several
133
+ generations; pass `file_path` directly for one-offs.
134
+
135
+ ## 3. Chosen option → build out the rest of the site
136
+
137
+ When the user settles on an option, **do not lock anything** — the chosen
138
+ option's imageId (from your ledger) is the only handle you need. Immediately:
139
+
140
+ 1. **Read the header to find the pages.** Look at the chosen design and read
141
+ the navigation links in its header — those *are* the site's page list. A nav
142
+ reading "Menu · Our Story · Visit · Contact" means those are the pages to
143
+ build. Add any obvious page the design implies but the nav omits (a cart /
144
+ checkout behind a cart icon, a sign-up behind a "Get started" button). List
145
+ the pages you inferred and confirm or adjust with the user before generating.
146
+ 2. **Generate each page from the chosen image.** For every accepted page, call
147
+ `generate_page` with `input_image_id` set to the **chosen option's imageId**
148
+ so the header, footer, palette, and type carry over. In the prompt, mention
149
+ `@reference` for what must stay consistent and describe what changes (the
150
+ page's own content and layout).
151
+ 3. **Track page name → imageId** in your ledger as each page returns. No lock
152
+ step is involved; the imageId is the durable handle for brands and the build.
153
+
154
+ If the header nav is missing or ambiguous, fall back to domain conventions:
155
+
156
+ - e-commerce: product listing, product detail, cart, checkout
157
+ - SaaS: pricing, features, sign-up, dashboard, settings
158
+ - restaurant: menu, reservations, about, contact
159
+
160
+ ## 4. Auto-create a brand (≥5 screens)
161
+
162
+ Track the screens kept this session. When **five or more visually consistent
163
+ screens** exist and the conversation suggests more screens are coming,
164
+ proactively offer to create a brand:
165
+
166
+ > "You now have N screens in a consistent style. Want me to create a brand
167
+ > from them? Future screens will then match automatically."
168
+
169
+ On yes: `create_brand_from_images` with those imageIds and a name derived
170
+ from the project. After the brand exists:
171
+
172
+ - Pass `brand_id` on every `generate_options` / `generate_page` call and
173
+ **stop** manual input rigging — diffui auto-selects the best brand
174
+ references per prompt via embedding matching.
175
+ - After each new screen the user keeps that fits the brand, call
176
+ `add_image_to_brand`.
177
+
178
+ ## 5. Brands by name
179
+
180
+ - If the user names a brand ("use the Acme brand"), call `list_brands`,
181
+ match by name, and pass its id.
182
+ - If a new request clearly resembles an existing brand (same product,
183
+ company, or style), proactively suggest using it: check `list_brands`
184
+ early in a session when the user's intent hints at existing work.
185
+
186
+ ## 6. Convert to code
187
+
188
+ When the user named an output folder up front (e.g. `demoBuild/bongo`), you still
189
+ complete the diffui design phase first. Remember that path; use it when writing
190
+ files after `create_build_link`.
191
+
192
+ When the design flow feels complete (pages generated, user satisfied), ask:
193
+ **"Ready to convert these designs to code?"** On yes:
194
+
195
+ 1. Call `create_build_link` with every page you kept — the imageIds in your
196
+ ledger — (`image_id`, `name`, `original_prompt`, and `brand_id` if one
197
+ exists) and `include_markdown: true`.
198
+ 2. Follow the returned build instructions markdown exactly — it is the
199
+ source of truth for implementation.
200
+ 3. For **all** asset needs during the build, use the diffui build API
201
+ endpoints documented in the markdown with its `authToken`:
202
+ - `POST /api/build/generate-image` for photos/illustrations
203
+ - `POST /api/build/generate-svg` for icons and vector art
204
+ - `POST /api/build/remove-background` for cutouts
205
+ - `POST /api/build/create-texture` for seamless background textures
206
+ Never hotlink canvas/preview URLs into the built code; download assets
207
+ locally as the markdown instructs.
208
+ 4. If you cannot write code in the current environment (e.g. chat-only),
209
+ give the user the `handoff` string from the tool result to paste into
210
+ their coding agent.
211
+
212
+ ## Ground rules
213
+
214
+ - **Design before code.** If you have not called `generate_options` this session,
215
+ you are not allowed to create webpage files yet.
216
+ - Always show generated images inline right after each tool call returns.
217
+ - Keep a running ledger of option numbers → imageIds → page names; restate
218
+ it briefly when the user refers to options by number.
219
+ - Generations block for the whole render (up to a few minutes) and stream
220
+ progress updates. A quiet call is working, not stuck — **never re-issue a
221
+ generation to "retry" a slow one.** A duplicate run desyncs the canvas and
222
+ leaves you holding imageIds that aren't in committed state. If you truly need
223
+ longer, raise `timeout_seconds` on a fresh call, don't fire a second one
224
+ alongside the first.
225
+ - Generation costs the user wallet credits per image. Use the defaults
226
+ (4 options for explorations, 1 for pages); confirm before unusually large
227
+ batches or regenerating many screens at once.
228
+ - If a generation fails with a billing error, tell the user their diffui
229
+ wallet needs funds.
230
+ - If a tool errors with authentication problems, call `authenticate` once and
231
+ retry — do not open with a proactive whoami check.