@womp/mcp-ui 0.1.6 → 0.1.8

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
@@ -11,12 +11,14 @@ in a sandboxed iframe, pushing tool data in over postMessage.
11
11
  generate_image ──► ui://womp/image-<version>.html (280 KB) image card
12
12
  image_to_mesh ──► ui://womp/mesh-<version>.html (900 KB) 3D GLB viewer
13
13
  get_generation ──► ui://womp/mesh-<version>.html (copes with either)
14
- estimate_print ──► ui://womp/print-<version>.html (260 KB) configurator: re-quotes + add to cart
14
+ estimate_print ──► ui://womp/print-<version>.html (321 KB) the print panel as a card: size, material, finish, colour, style, qty
15
15
  prepare_print ──► ui://womp/print-<version>.html (static receipt mode)
16
16
  add_to_cart ──► ui://womp/cart-<version>.html (260 KB) cart rows + checkout link-out
17
17
  view_cart ──► ui://womp/cart-<version>.html (self-fills thumbnails via app-callable view_cart)
18
18
  get_print_order ──► ui://womp/order-<version>.html (258 KB) status chips, tracking, diff-charge strip
19
19
  list_print_orders ─► ui://womp/order-<version>.html
20
+ create_upload ──► ui://womp/upload-<version>.html (266 KB) drop zone: the user's mesh file goes to the ticket URL from the chat
21
+ get_upload ──► ui://womp/upload-<version>.html (app-callable — the card polls it)
20
22
  ```
21
23
 
22
24
  ## What it exports
@@ -30,6 +32,7 @@ const {
30
32
  PRINT_APP_URI, PRINT_APP_CSP, PRINT_APP_HTML,
31
33
  CART_APP_URI, CART_APP_CSP, CART_APP_HTML,
32
34
  ORDER_APP_URI, ORDER_APP_CSP, ORDER_APP_HTML,
35
+ UPLOAD_APP_URI, UPLOAD_APP_CSP, UPLOAD_APP_HTML,
33
36
  APP_MIME_TYPE,
34
37
  } = require("@womp/mcp-ui");
35
38
  ```
@@ -180,6 +183,84 @@ inline (360px) so they do not wall off the transcript — which made fullscreen
180
183
  useless until CSS started keying off `:root[data-display-mode="fullscreen"]`.
181
184
  **PiP is untested.**
182
185
 
186
+ ### The print card is the web print panel, compressed
187
+
188
+ `src/print/` follows swan-frontend's `NewPrintingPanel` step for step — Size,
189
+ Material (finish and colour controls inside the selection), Print style, then a
190
+ review row with quantity and price — so a person who has printed on womp.com
191
+ recognises it. Where the card differs, it is because MCP differs:
192
+
193
+ - **Size is W/H/D in cm or inches, but scales uniformly.** The tool contract
194
+ is `longestSideCm`, so editing one axis rescales the other two and the
195
+ longest side is what gets sent. The panel's 60 × 60 × 40 cm ceiling blocks the
196
+ button here as it does there.
197
+ - **Colour is a hex, snapped to Pantone.** The panel snaps a pick to the
198
+ nearest of 2390 Pantone coated shades and sends the code; MCP orders carry a
199
+ hex. The card snaps the same way (`src/print/pantone.ts`, CIEDE2000 like the
200
+ panel's `color-diff`) and sends the snapped shade's own hex, so both paths
201
+ print the same colour and show the same "Pantone 2386 C". The palette is
202
+ packed into `src/print/pantone-coated.ts` (28 KB) by
203
+ `scripts/gen-pantone.mjs <path to swan-frontend's PantoneCoatedColors.js>`;
204
+ regenerate it if the frontend's list changes. Colour never re-quotes — it
205
+ never changes the price.
206
+ - **Hollow never orders.** Escape holes are placed in the editor, so choosing
207
+ Hollow shows its price and turns the button into "Continue on womp.com",
208
+ which calls `prepare_print` and opens the project. The backend refuses
209
+ `hollow: true` outright; the card never sends it.
210
+ - **Gated Enterprise materials stay visible**, with a crown, behind a
211
+ disclosure. Tapping one keeps the current selection and shows the
212
+ contact-sales note (the backend's `contactUrl`) — the panel's dialog, flattened.
213
+ - **Tool errors are rewritten for a person.** "resin-clear-tinted is a dyed
214
+ material — pass a color as a #rrggbb hex" is for the model; the card says
215
+ "Pick a colour for this material first."
216
+
217
+ What it reads off `estimate_print` beyond the price rows: `material` (the
218
+ catalog KEY it sent — the backend echoes it unchanged; echoing the priced id
219
+ snapped Tinted clear back to Clear on every re-quote), `materialLabel`,
220
+ `finish`, `color`, `repaired` / `nonManifold`, and a role-aware `materials`
221
+ list with `swatchUrl`, `finishes`, `colorRequired` / `colorOptional`,
222
+ `available` and `contactUrl`.
223
+
224
+ **Layout trap that cost an hour:** a grid container's implicit `auto` track
225
+ grows to its items' min-content, and a bare `<input type="number">` is ~150px
226
+ wide intrinsically — three of them widened every row past the card's edge while
227
+ the card itself stayed 360px. Every grid in the card is
228
+ `grid-template-columns: minmax(0, 1fr)` and the inputs have `width: 0` as their
229
+ flex basis. If a row overflows, look there first.
230
+
231
+ The stub takes three switches for the states a default account never shows:
232
+ `FAKE_ENTERPRISE=1` (Enterprise materials orderable), `FAKE_PRO=1` (hollow
233
+ priced as available), `FAKE_REPAIRED=1` (the repaired / non-manifold callouts).
234
+
235
+ ### The upload card sends bytes from inside the iframe
236
+
237
+ `src/upload/` exists because MCP has no client→server file channel and a chat
238
+ host's sandbox usually cannot reach Womp — so a file the user had just attached
239
+ to the chat could only reach the print pipeline via a womp.com page. The card
240
+ is that page, in the conversation: drop zone + picker, XHR `PUT` of the raw file
241
+ to the ticket URL swan-backend minted (`create_upload`), progress, the server's
242
+ own refusal text on 4xx, 409/410 terminal. It never touches the model: the
243
+ bytes go disk → API.
244
+
245
+ Two things outside this repo make that PUT possible, and both fail as a bare
246
+ network error inside the card if missing (which it turns into an "open the
247
+ upload page instead" button rather than a dead end):
248
+
249
+ - **`connectDomains` must name the API origin**, and the origin differs per
250
+ environment — so `bake-html.mjs` bakes `{}` for this card and swan-backend
251
+ completes the CSP with its own origin at read time. The dev stub does the
252
+ same with `http://localhost:3001`.
253
+ - **The backend answers with open CORS on `/mcp/v1/uploads`** because a
254
+ sandboxed iframe's origin is opaque (`Origin: null`). The ticket in the URL is
255
+ the security boundary, not the origin.
256
+
257
+ While pending the card polls the app-callable `get_upload`, so a file the agent
258
+ pushed itself (`curl -T` from a shell that has it) flips the card to done
259
+ instead of leaving a drop zone for a file that already landed. The dev stub
260
+ (`dev/server.mjs`) carries `create_upload` / `get_upload` and a `PUT
261
+ /mcp/v1/uploads/:token` sink with the GLB-magic sniff, so the refusal strip is
262
+ reachable locally too.
263
+
183
264
  ## Development
184
265
 
185
266
  **Do not iterate through Claude.** A card change reaches a connector only after
@@ -212,7 +293,10 @@ It is deliberately faithful where being unfaithful would hide a bug:
212
293
  | **"built resource" mode** — the exact HTML `resources/read` returns, in a sandboxed opaque-origin iframe | an asset `vite-plugin-singlefile` failed to inline (blank card) |
213
294
 
214
295
  `FAKE_DURATION_MS=8000 yarn dev:mcp` lengthens a fake generation, so the
215
- running → polling → complete transition is worth watching.
296
+ running → polling → complete transition is worth watching. The print stubs
297
+ validate like the real tools (dyed material without a colour, Enterprise
298
+ material, hollow intent, bad finish) so every refusal the card must render is
299
+ reachable locally.
216
300
 
217
301
  **Keep the tab visible.** A backgrounded tab does not run
218
302
  `requestAnimationFrame` and clamps `setTimeout`, so auto-resize stops reporting
package/dist/index.d.ts CHANGED
@@ -26,3 +26,7 @@ export declare const CART_APP_HTML: string;
26
26
  export declare const ORDER_APP_URI: string;
27
27
  export declare const ORDER_APP_CSP: AppCsp;
28
28
  export declare const ORDER_APP_HTML: string;
29
+
30
+ export declare const UPLOAD_APP_URI: string;
31
+ export declare const UPLOAD_APP_CSP: AppCsp;
32
+ export declare const UPLOAD_APP_HTML: string;