@vantageos/mosaic 0.4.0 → 0.5.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/CHANGELOG.md +39 -15
- package/README.md +114 -5
- package/dist/PipelineBoard-FucyGArR.d.cts +759 -0
- package/dist/PipelineBoard-FucyGArR.d.ts +759 -0
- package/dist/PipelineBoard.markdown-DIcvrS-2.d.cts +16 -0
- package/dist/PipelineBoard.markdown-DIcvrS-2.d.ts +16 -0
- package/dist/{StatusBadge.schema-1tOjB4Ir.d.cts → StatusBadge.schema-BEjSH2_4.d.cts} +2 -2
- package/dist/{StatusBadge.schema-1tOjB4Ir.d.ts → StatusBadge.schema-BEjSH2_4.d.ts} +2 -2
- package/dist/{Tabs.schema-BzcEyeq8.d.cts → Tabs.schema-Dqr6vwV3.d.cts} +2 -2
- package/dist/{Tabs.schema-BzcEyeq8.d.ts → Tabs.schema-Dqr6vwV3.d.ts} +2 -2
- package/dist/Timeline-Coo_3tA_.d.cts +114 -0
- package/dist/Timeline-Coo_3tA_.d.ts +114 -0
- package/dist/Timeline.markdown-C6UPDv1H.d.cts +4 -0
- package/dist/Timeline.markdown-C6UPDv1H.d.ts +4 -0
- package/dist/TransactionPreview-BzWDn8kE.d.cts +391 -0
- package/dist/TransactionPreview-BzWDn8kE.d.ts +391 -0
- package/dist/TransactionPreview.markdown-Dpb0VYgN.d.cts +7 -0
- package/dist/TransactionPreview.markdown-Dpb0VYgN.d.ts +7 -0
- package/dist/artifacts.cjs +186 -2
- package/dist/artifacts.cjs.map +1 -1
- package/dist/artifacts.js +186 -2
- package/dist/artifacts.js.map +1 -1
- package/dist/confirmation.cjs +724 -2
- package/dist/confirmation.cjs.map +1 -1
- package/dist/confirmation.d.cts +2 -1
- package/dist/confirmation.d.ts +2 -1
- package/dist/confirmation.js +722 -4
- package/dist/confirmation.js.map +1 -1
- package/dist/display.cjs +1551 -203
- package/dist/display.cjs.map +1 -1
- package/dist/display.d.cts +6 -229
- package/dist/display.d.ts +6 -229
- package/dist/display.js +1535 -206
- package/dist/display.js.map +1 -1
- package/dist/forms.cjs +139 -46
- package/dist/forms.cjs.map +1 -1
- package/dist/forms.d.cts +2 -2
- package/dist/forms.d.ts +2 -2
- package/dist/forms.js +139 -46
- package/dist/forms.js.map +1 -1
- package/dist/host.cjs +822 -0
- package/dist/host.cjs.map +1 -0
- package/dist/host.d.cts +287 -0
- package/dist/host.d.ts +287 -0
- package/dist/host.js +794 -0
- package/dist/host.js.map +1 -0
- package/dist/{index-CwXVgtGb.d.cts → index-BadRcCbm.d.cts} +28 -11
- package/dist/{index-CwXVgtGb.d.ts → index-BadRcCbm.d.ts} +28 -11
- package/dist/index.cjs +2198 -247
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +42 -8
- package/dist/index.d.ts +42 -8
- package/dist/index.js +2163 -251
- package/dist/index.js.map +1 -1
- package/dist/input.d.cts +2 -2
- package/dist/input.d.ts +2 -2
- package/dist/media.cjs +186 -2
- package/dist/media.cjs.map +1 -1
- package/dist/media.d.cts +1 -1
- package/dist/media.d.ts +1 -1
- package/dist/media.js +186 -2
- package/dist/media.js.map +1 -1
- package/dist/preact/artifacts.js +186 -2
- package/dist/preact/artifacts.js.map +1 -1
- package/dist/preact/confirmation.d.ts +321 -1
- package/dist/preact/confirmation.js +625 -4
- package/dist/preact/confirmation.js.map +1 -1
- package/dist/preact/display.d.ts +544 -47
- package/dist/preact/display.js +1190 -126
- package/dist/preact/display.js.map +1 -1
- package/dist/preact/forms.d.ts +32 -15
- package/dist/preact/forms.js +139 -46
- package/dist/preact/forms.js.map +1 -1
- package/dist/preact/host.d.ts +307 -0
- package/dist/preact/host.js +875 -0
- package/dist/preact/host.js.map +1 -0
- package/dist/preact/media.d.ts +37 -1
- package/dist/preact/media.js +423 -0
- package/dist/preact/media.js.map +1 -1
- package/dist/preact/progress.d.ts +92 -1
- package/dist/preact/progress.js +465 -3
- package/dist/preact/progress.js.map +1 -1
- package/dist/progress.cjs +521 -2
- package/dist/progress.cjs.map +1 -1
- package/dist/progress.d.cts +2 -1
- package/dist/progress.d.ts +2 -1
- package/dist/progress.js +518 -3
- package/dist/progress.js.map +1 -1
- package/dist/react/artifacts.cjs +186 -2
- package/dist/react/artifacts.cjs.map +1 -1
- package/dist/react/artifacts.js +186 -2
- package/dist/react/artifacts.js.map +1 -1
- package/dist/react/confirmation.cjs +626 -2
- package/dist/react/confirmation.cjs.map +1 -1
- package/dist/react/confirmation.d.cts +3 -3
- package/dist/react/confirmation.d.ts +3 -3
- package/dist/react/confirmation.js +625 -4
- package/dist/react/confirmation.js.map +1 -1
- package/dist/react/display.cjs +1076 -123
- package/dist/react/display.cjs.map +1 -1
- package/dist/react/display.d.cts +13 -27
- package/dist/react/display.d.ts +13 -27
- package/dist/react/display.js +1064 -126
- package/dist/react/display.js.map +1 -1
- package/dist/react/forms.cjs +139 -46
- package/dist/react/forms.cjs.map +1 -1
- package/dist/react/forms.d.cts +1 -1
- package/dist/react/forms.d.ts +1 -1
- package/dist/react/forms.js +139 -46
- package/dist/react/forms.js.map +1 -1
- package/dist/react/host.cjs +910 -0
- package/dist/react/host.cjs.map +1 -0
- package/dist/react/host.d.cts +24 -0
- package/dist/react/host.d.ts +24 -0
- package/dist/react/host.js +875 -0
- package/dist/react/host.js.map +1 -0
- package/dist/react/input.d.cts +1 -1
- package/dist/react/input.d.ts +1 -1
- package/dist/react/media.cjs +426 -0
- package/dist/react/media.cjs.map +1 -1
- package/dist/react/media.d.cts +19 -1
- package/dist/react/media.d.ts +19 -1
- package/dist/react/media.js +423 -0
- package/dist/react/media.js.map +1 -1
- package/dist/react/progress.cjs +467 -2
- package/dist/react/progress.cjs.map +1 -1
- package/dist/react/progress.d.cts +1 -1
- package/dist/react/progress.d.ts +1 -1
- package/dist/react/progress.js +465 -3
- package/dist/react/progress.js.map +1 -1
- package/dist/server/resource.cjs +151 -0
- package/dist/server/resource.cjs.map +1 -0
- package/dist/server/resource.d.cts +90 -0
- package/dist/server/resource.d.ts +90 -0
- package/dist/server/resource.js +147 -0
- package/dist/server/resource.js.map +1 -0
- package/dist/server.cjs +1100 -25
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +84 -5
- package/dist/server.d.ts +84 -5
- package/dist/server.js +1087 -27
- package/dist/server.js.map +1 -1
- package/package.json +250 -233
- package/registry.yaml +44 -2
- package/dist/Alert.schema-LPJE5gFP.d.cts +0 -71
- package/dist/Alert.schema-LPJE5gFP.d.ts +0 -71
- package/dist/ProgressBar.schema-CdVYx0Wq.d.cts +0 -22
- package/dist/ProgressBar.schema-CdVYx0Wq.d.ts +0 -22
- package/dist/{ConfirmDialog-B3CQQGmJ.d.cts → ConfirmDialog-BCtOcmHe.d.cts} +1 -1
- package/dist/{ConfirmDialog-B3CQQGmJ.d.ts → ConfirmDialog-BCtOcmHe.d.ts} +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,22 +9,24 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
- **D-PR1 — Pre-publish dry-run evidence for v0.3.0 GA.** New doc `docs/D-PR1-PRE-PUBLISH-DRY-RUN-V0.3.0.md` (bilingual EN+FR) capturing the hard-evidence pre-publish gate run in a fresh sandbox worktree off `origin/main` @ `7ae5450`: sandbox build-pass (RULE #19, `SANDBOX_BUILD_PASS_ID=7ae5450`, build exit 0), Gate 1 build-parity (exit 0), `npm pack --dry-run` (150 files / 511.8 kB / unpacked 3.0 MB / version 0.3.0 / sha `31caed2f`, CHANGELOG + README + package.json + registry.yaml + full `dist/` surface present — **no real publish**), corrected vendored cross-runtime subpath coverage gate (`--ga-mode`, exit 0, 0 missing), and the full gate set re-run green (tsc, biome, vitest 854, playwright-axe 29, size-limit, registry-drift, storybook-test 103, Gate 2 peer-resolution, Gate 3 coherence 10). Documents the **D-T1 blocker**: the canonical B-PR1 skill / B-PR2 publish hook carry a category-prefixed layout defect (`./forms/react`) vs Mosaic's runtime-prefixed layout (`./react/forms`) and **false-block** the real publish — must be fixed before `tag v0.3.0` (Sigma task `k176e5rpz`); plus `ETA_APPROVED_TASK_ID` must be set after Eta approval. Mission `k57b6d1b` · task `k177e1wr`. No source/build/gate code changed — docs-only.
|
|
14
|
-
- **CI Gate 4 — Cross-runtime subpath coverage (B-PR3).** New fail-fast CI gate asserting that **every bare component category** in `packages/mosaic/package.json` `exports` (`./forms`, `./progress`, `./display`, `./artifacts`, `./confirmation`, `./media`, `./input`) also exports a **non-empty** `dist` artifact under **both** `./react/<cat>` and `./preact/<cat>`. This is the gate that would have caught the original v0.3.0 GA blocker (foundation components present as bare exports but missing/empty under `/react` + `/preact`).
|
|
15
|
-
- New vendored script `packages/mosaic/scripts/cross-runtime-subpath-coverage-check.py` — vendored from the canonical B-PR1 skill `mosaic-cross-runtime-subpath-coverage-check` (VantageRegistry; PR #20). Stdlib-only, with an optional PyYAML registry cross-check that degrades gracefully when PyYAML is absent (no Python dependency added to CI). Carries one documented deviation: a `RUNTIME_PREFIXED` toggle adapting the canonical category-prefixed layout (`./forms/react`) to this repo's runtime-prefixed layout (`./react/forms`).
|
|
16
|
-
- New job `cross-runtime-subpath-coverage` (`needs: build-parity-cross-runtime`) builds tokens + mosaic so `dist/` exists, then runs `python3 .../cross-runtime-subpath-coverage-check.py --package-root packages/mosaic --ga-mode` (exit 1 fails CI with a `component × runtime` diagnostic). CI-side equivalent of the B-PR2 npm-publish hook.
|
|
17
|
-
- New doc `docs/CROSS-RUNTIME-GATE.md` (bilingual EN+FR). Additive change — no existing gate (Gate 1 build-parity, Gate 2 peerDeps smoke, Gate 3 coherence, `ci` job) weakened or replaced. Mission `k57b6d1b` · task `k176pzsszyy4v3f505khwg33gx88j36n`.
|
|
18
|
-
- Wave 3 components TBD (DatePicker, Avatar, FilterChip, Pagination — demand-driven T21+).
|
|
12
|
+
---
|
|
19
13
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
- `
|
|
26
|
-
-
|
|
27
|
-
-
|
|
14
|
+
## [0.5.0] — 2026-10-11 — MCP App kit for ChatGPT and Claude (D0)
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- **Behaviour change — declared secrets never reach `content[]`.** `createMosaicResource` (published `./server`) now strips every field declared in `MOSAIC_NEVER_SERIALISE` from the embedded props BY DEFAULT; pass `includeSecrets: true` to keep the previous behaviour. `createMosaicToolResult` carries a declared secret only in `_meta["mosaic/secrets"]` and throws `MosaicSecretLeakError` (naming the field, never the value) if one appears in `content[]`, or if a declared field does not exist on the view. A `TableView` column flagged `sensitive` is masked in markdown and stripped from the embedded props. `TokenDisplayOnceModal`'s fallback carries label, scope, expiry and an issuer-supplied fingerprint, never the token.
|
|
18
|
+
- **Behaviour notes for the #75 fallbacks.** `openLink` now hands the host the PARSED href, so `https://x.example` is sent as `https://x.example/` (trailing slash; a raw string with an embedded newline can no longer reach the host). The TransactionPreview markdown fallback joins the swap route with `→` instead of `>` (`USDC → WFUSE → FUSE`), because `>` is escaped as markdown. The secret guard in `createMosaicToolResult` compares case-folded and NFKC-normalised text on both sides.
|
|
19
|
+
- **Gate 4 script fail-closed** (`scripts/cross-runtime-subpath-coverage-check.py`): exit 2 naming the input for any unreadable input (package root, `package.json`, registry, built entry, empty category set, a registry that yields no categories or has no `components` list, or the PyYAML and built-in readers disagreeing) and exit 1 only for a real coverage gap; the default `--package-root` is the package the script lives in, not the working directory; the registry cross-check no longer skips without PyYAML (built-in reader) or with a missing registry (`--skip-registry-check` is the explicit opt-out).
|
|
20
|
+
- **MCP Apps views and host layer, delivery 2 (task k17ehg71z31ec50fkh95p3xxr58fjm98; Eta corrections k178bt8enj99wv1gtc8h3315kx8g0w13).**
|
|
21
|
+
- **Views** (React + Preact barrels, FR+EN, Zod, Skeleton loading, `{}` parses as an empty state, A-1 markdown): `StatCard` (R08) and `BalanceCard` (R09, Fuse balance, exact decimal strings) in `display`; `MessageFeed` (R03, read-only, plain text, safe links) and `PipelineBoard` (R06, read-only, fullscreen board / inline summary, stage filter chips) in `display`; `Timeline` (R02) in `progress`; `TransactionPreview` (R11, prepare-only, swap-quote variant, **no sign / send / approve control**, "NOT SIGNED - preparation only") in `confirmation`.
|
|
22
|
+
- **`TableView` extended** (R01 / R10, every new prop optional): sortable columns with `aria-sort`, `single` / `multiple` selection (`onSelectionChange` rows + keys), sticky header, compact density, column `align` / `width`, `amount` (exact decimal string compare) and `icon` cell kinds, `loading` Skeleton, serialisable `rows` in the schema.
|
|
23
|
+
- **`RadioGroup` / `MultiSelect`** (R25): `appearance` `segmented` | `chips` (RadioGroup) and `chips` (MultiSelect: visible toggle buttons, `aria-pressed`, no dropdown).
|
|
24
|
+
- **Host layer** (`./host`, `./react/host`, `./preact/host`): safe-area insets (H01), host style variables bridged onto mosaic-tokens + host fonts + transparent background (H02), `sendMessage` / `openLink` helpers that refuse what the host cannot honour (H04, H18), typed model-context blocks + `openai/modelContext` read + `selectionModelContext` (H03), hooks `useMosaicHostLayout`, `useSendMessage`, `useOpenLink`.
|
|
25
|
+
- **Server**: `buildMcpAppResource({ visibility, hostFonts })` (H05); `createMosaicToolResult` returning `content: [text, ui:// resource]` (A-1) and a `<name>ToMarkdown` for all 12 components (H17). `createMosaicResource` now supports 12 components, honours its `uri` and `markdownFallback` options, and `_meta.ui.fallback` (kept: published contract) carries the data instead of a title and note.
|
|
26
|
+
- **Adapter**: `startSizeReporting` / `postSizeChanged` send `ui/notifications/size-changed` from the raw adapter (H15).
|
|
27
|
+
- **Fix — host-context dispatcher** (Eta #74 re-gate): a foreign handler that overwrites `app.onhostcontextchanged` while subscribers are live is adopted as `previous` and the dispatcher reinstalled on the next subscribe; resubscribe-after-full-unsubscribe is pinned by a test that goes RED when `dispatchers.delete(app)` is removed.
|
|
28
|
+
- **MCP Apps host layer for ChatGPT and Claude (task k17ehg71z31ec50fkh95p3xxr58fjm98, items 1-2).** New subpaths `./host` (framework-agnostic core: host theme/display mode/locale/container dimensions, `openai/deepLink` when present, `requestDisplayMode` limited to inline | fullscreen with a typed AND runtime refusal of `pip` for a ChatGPT host, `updateModelContext` over `ui/update-model-context`, host theme mapped onto mosaic-tokens `data-theme`), `./react/host` and `./preact/host` (hooks over the core) and `./server/resource` (`buildMcpAppResource`: pure, no React/DOM; `_meta.ui` standard keys first with the four csp arrays explicit, `domain` derived from `servedUrl` for Claude, `openai/*` keys only when passed: `_meta["openai/ui"]` display modes on the resource, `openai/outputTemplate` and `openai/ui` entrypoints on the tool; deepLink typed as `{ url }`; ChatGPT detected from `openai/*` keys, no user-agent sniffing). Composes with ext-apps `registerAppResource`/`registerAppTool`, which pass `_meta` through. No new dependency: the ext-apps `App` is typed structurally.
|
|
29
|
+
- **Fix — `react/media` and `preact/media` were empty barrels; Gate 4 passed anyway.** Both now re-export `StatusBadge` (+ props type, schema, validator) from the existing `display` components (display exports kept, no new component), and Gate 4 now fails any runtime subpath entry whose built `.js` or `.d.ts` exports zero symbols, naming the entry (`exports-zero-symbols`).
|
|
28
30
|
|
|
29
31
|
---
|
|
30
32
|
|
|
@@ -88,6 +90,28 @@ the items above are the entire delta a consumer receives — derived by locating
|
|
|
88
90
|
the version to `0.3.1` and listing what touched `packages/mosaic` after it, not by reading a date
|
|
89
91
|
window (a date window includes the release commits themselves and reported 19).
|
|
90
92
|
|
|
93
|
+
|
|
94
|
+
### Recorded late — shipped by 0.4.0 at the latest, never listed in a release section
|
|
95
|
+
|
|
96
|
+
These entries sat under `[Unreleased]` after their code had shipped. Each one's commit is an ancestor of the 0.4.0 release commit `12475a6` (`git merge-base --is-ancestor <sha> 12475a6`).
|
|
97
|
+
|
|
98
|
+
- **D-PR1 — Pre-publish dry-run evidence for v0.3.0 GA.** New doc `docs/D-PR1-PRE-PUBLISH-DRY-RUN-V0.3.0.md` (bilingual EN+FR) capturing the hard-evidence pre-publish gate run in a fresh sandbox worktree off `origin/main` @ `7ae5450`: sandbox build-pass (RULE #19, `SANDBOX_BUILD_PASS_ID=7ae5450`, build exit 0), Gate 1 build-parity (exit 0), `npm pack --dry-run` (150 files / 511.8 kB / unpacked 3.0 MB / version 0.3.0 / sha `31caed2f`, CHANGELOG + README + package.json + registry.yaml + full `dist/` surface present — **no real publish**), corrected vendored cross-runtime subpath coverage gate (`--ga-mode`, exit 0, 0 missing), and the full gate set re-run green (tsc, biome, vitest 854, playwright-axe 29, size-limit, registry-drift, storybook-test 103, Gate 2 peer-resolution, Gate 3 coherence 10). Documents the **D-T1 blocker**: the canonical B-PR1 skill / B-PR2 publish hook carry a category-prefixed layout defect (`./forms/react`) vs Mosaic's runtime-prefixed layout (`./react/forms`) and **false-block** the real publish — must be fixed before `tag v0.3.0` (Sigma task `k176e5rpz`); plus `ETA_APPROVED_TASK_ID` must be set after Eta approval. Mission `k57b6d1b` · task `k177e1wr`. No source/build/gate code changed — docs-only.
|
|
99
|
+
- **CI Gate 4 — Cross-runtime subpath coverage (B-PR3).** New fail-fast CI gate asserting that **every bare component category** in `packages/mosaic/package.json` `exports` (`./forms`, `./progress`, `./display`, `./artifacts`, `./confirmation`, `./media`, `./input`) also exports a **non-empty** `dist` artifact under **both** `./react/<cat>` and `./preact/<cat>`. This is the gate that would have caught the original v0.3.0 GA blocker (foundation components present as bare exports but missing/empty under `/react` + `/preact`).
|
|
100
|
+
- New vendored script `packages/mosaic/scripts/cross-runtime-subpath-coverage-check.py` — vendored from the canonical B-PR1 skill `mosaic-cross-runtime-subpath-coverage-check` (VantageRegistry; PR #20). Stdlib-only, with an optional PyYAML registry cross-check that degrades gracefully when PyYAML is absent (no Python dependency added to CI). Carries one documented deviation: a `RUNTIME_PREFIXED` toggle adapting the canonical category-prefixed layout (`./forms/react`) to this repo's runtime-prefixed layout (`./react/forms`).
|
|
101
|
+
- New job `cross-runtime-subpath-coverage` (`needs: build-parity-cross-runtime`) builds tokens + mosaic so `dist/` exists, then runs `python3 .../cross-runtime-subpath-coverage-check.py --package-root packages/mosaic --ga-mode` (exit 1 fails CI with a `component × runtime` diagnostic). CI-side equivalent of the B-PR2 npm-publish hook.
|
|
102
|
+
- New doc `docs/CROSS-RUNTIME-GATE.md` (bilingual EN+FR). Additive change — no existing gate (Gate 1 build-parity, Gate 2 peerDeps smoke, Gate 3 coherence, `ci` job) weakened or replaced. Mission `k57b6d1b` · task `k176pzsszyy4v3f505khwg33gx88j36n`.
|
|
103
|
+
|
|
104
|
+
#### Fixed
|
|
105
|
+
- CI Gate 2 (PeerDeps optionality smoke) now runs GREEN (unblocks v0.3.0 GA publish gate). Two layered bugs, both packaging-scope:
|
|
106
|
+
- **Build (tsup):** the preact runtime bundles that re-export the shared React implementation (`preact/progress`, `preact/input`, `preact/confirmation`, `preact/forms`) shipped `import … from "react/jsx-runtime"` and `import … from "react"`. `esbuildOptions.alias` (`react → preact/compat`) never fired because tsup auto-externalises peerDeps (`react`, `react/jsx-runtime`) *before* alias resolution, so the alias was a no-op for those specifiers. A react-only consumer (which has react) could therefore resolve `@vantageos/mosaic/preact/*` even with preact absent — optionality broken in both directions. Fix: replaced the alias with an esbuild `onResolve` plugin (`mosaic-react-to-preact`) that deterministically rewrites the whole react family (`react`, `react-dom`, `react-dom/client`, `react/jsx-runtime`, `react/jsx-dev-runtime`) to their preact equivalents and marks them external; paired with `noExternal: [/^react…/]` on the preact pass so tsup's own external plugin returns undefined for the react family and lets the rewrite run. Added `preact/jsx-runtime` to `PREACT_EXTERNAL`. Preact bundles now import only preact specifiers; react bundles unchanged.
|
|
107
|
+
- **Smoke fixture (run-smoke.sh):** the fixtures installed mosaic via `npm install file:../../../packages/mosaic`, which npm symlinks into the monorepo source tree; Node then resolved the bundle's runtime imports by climbing out of the fixture into the monorepo root `node_modules` (where both react and preact are hoisted devDeps), producing a false PASS. Rewrote the driver to model a real npm consumer faithfully: `pnpm pack` both packages (rewriting the `workspace:*` tokens dep to a concrete version) and install the tarballs into an isolated `mktemp -d` consumer outside the repo tree, with `--legacy-peer-deps` so npm does not auto-install the *transitive* peer react pulled by `@tanstack/react-virtual` into a preact-only consumer. Fixture assertions (`index.mjs`) untouched. Smoke now PASSES: react-only resolves `react/*` and fails `preact/*`; preact-only resolves `preact/*` and fails `react/*`.
|
|
108
|
+
- CI `biome check --error-on-warnings` now exits 0 on `main` (unblocks v0.3.0 GA publish gate): suppressed 6 `noNonNullAssertion` lint errors in VirtualList tests (React + Preact) with justified `biome-ignore` comments matching repo convention, plus format/organizeImports auto-fixes across 7 files.
|
|
109
|
+
- `forms/Select.tsx` (React + Preact) biome a11y gate: replaced the blanket `biome.json` per-file rule override with scoped, justified `biome-ignore` comments on exactly the 6 flagged ARIA roles per runtime (`useSemanticElements` on the `combobox`/`listbox`/`option` roles, `noNoninteractiveElementToInteractiveRole` on `ul`→`listbox` + `li`→`option`, `useFocusableInteractive` on the `li`). These are biome heuristic false-positives on the WAI-ARIA APG combobox + listbox pattern (options managed via `aria-activedescendant`, intentionally not in the tab order). Comments mirror the existing `noAutofocus` APG-pattern suppression; no JSX/logic changed. Added `tests/a11y/Select.spec.ts` (axe-core) proving 0 violations on the pattern.
|
|
110
|
+
- CI `playwright-axe` step now runs GREEN (unblocks v0.3.0 GA `npm-publish` gate, which is `needs: ci`). Root cause from real CI logs: the runner ships no browsers, so every a11y spec died at `browserType.launch` ("Executable doesn't exist"). Fixes: (1) added a `playwright install --with-deps chromium` step before `playwright-axe` in `.github/workflows/ci.yml`; (2) normalized the stale `/storybook/?story=` spec URLs (StatusBadge, MarkdownRenderer, ConfirmDialog, TokenDisplayOnceModal, ProgressBar) to the working `/iframe.html?id=` convention used by `Select.spec.ts`, corrected three wrong story-id slugs (`media-statusbadge--error-state`, `artifacts-markdownrenderer--error-state`, `progress-progressbar--default`), and scoped axe to `#storybook-root` so the Storybook iframe shell's page-level best-practice rules no longer mask component results; (3) `TableView.spec.ts` now waits via `getByRole("table")` (matches the native `<table>` implicit role; the CSS `[role="table"]` selector never matched) and scopes axe to `#storybook-root`.
|
|
111
|
+
- `display/TableView.tsx`: fixed a real axe violation (`scrollable-region-focusable`, WCAG 2.1.1 / 2.1.3, serious) — the virtualized scroll viewport is scrollable but was not keyboard-operable. Added `tabIndex={0}` + `role="region"` + `aria-label` (justified `biome-ignore` comments matching repo convention). Full `tests/a11y/` suite now passes 29/29 with axe 0 violations under `CI=true` against the Playwright `webServer`.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
91
115
|
---
|
|
92
116
|
|
|
93
117
|
## [0.3.1] — 2026-06-13 — hotfix: workspace:* leak in published 0.3.0 manifest (Path B — root-cause fix)
|
package/README.md
CHANGED
|
@@ -6,10 +6,10 @@ Fleet-wide MCP UI design system. Zod-validated, taxonomy-organized (7 categories
|
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
8
|
# React 19
|
|
9
|
-
npm install @vantageos/mosaic@^0.
|
|
9
|
+
npm install @vantageos/mosaic@^0.5.0 @vantageos/mosaic-tokens@^0.7.0 react react-dom
|
|
10
10
|
|
|
11
11
|
# Preact 10
|
|
12
|
-
npm install @vantageos/mosaic@^0.
|
|
12
|
+
npm install @vantageos/mosaic@^0.5.0 @vantageos/mosaic-tokens@^0.7.0 preact
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
All runtime peers are marked optional via `peerDependenciesMeta` — install only what your runtime needs.
|
|
@@ -38,6 +38,9 @@ This constraint is codified locally via the `build` script (the `NODE_OPTIONS` p
|
|
|
38
38
|
| `@vantageos/mosaic/preact/<cat>` | Preact 10 | Tree-shakable category imports under preact/ prefix |
|
|
39
39
|
| `@vantageos/mosaic/tokens` | runtime-free | Re-export of `@vantageos/mosaic-tokens` |
|
|
40
40
|
| `@vantageos/mosaic/server` | Node | `createMosaicResource()` MCP UI builder (runtime-agnostic) |
|
|
41
|
+
| `@vantageos/mosaic/server/resource` | Node | `buildMcpAppResource()` MCP Apps `_meta` helper (pure, no React, no DOM) |
|
|
42
|
+
| `@vantageos/mosaic/host` | runtime-free | Host-context core (theme, display mode, locale, model context) |
|
|
43
|
+
| `@vantageos/mosaic/react/host` · `/preact/host` | React 19 · Preact 10 | Hooks over the host-context core |
|
|
41
44
|
|
|
42
45
|
`<cat>` = `progress` | `input` | `display` | `artifacts` | `confirmation` | `media`.
|
|
43
46
|
|
|
@@ -208,6 +211,112 @@ const resource = createMosaicResource({
|
|
|
208
211
|
```
|
|
209
212
|
|
|
210
213
|
|
|
214
|
+
## MCP Apps host layer (ChatGPT and Claude)
|
|
215
|
+
|
|
216
|
+
Standard MCP Apps keys come first; `openai/*` keys are strictly additive. A view built
|
|
217
|
+
on this layer works with no `openai` key at all, and never requests `pip` for ChatGPT.
|
|
218
|
+
`@modelcontextprotocol/ext-apps` is **not** a dependency: the core types the `App`
|
|
219
|
+
structurally, so any `App` instance fits.
|
|
220
|
+
|
|
221
|
+
### Resource helper (server, pure)
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
import { buildMcpAppResource } from "@vantageos/mosaic/server/resource";
|
|
225
|
+
|
|
226
|
+
const { resource, toolMeta } = buildMcpAppResource({
|
|
227
|
+
uri: "ui://mosaic/tasks",
|
|
228
|
+
html, // your bundled single-file view
|
|
229
|
+
csp: { connectDomains: ["https://api.example.com"] }, // the 4 arrays are always emitted
|
|
230
|
+
servedUrl: "https://example.com/mcp", // Claude `ui.domain` is DERIVED from it, never typed
|
|
231
|
+
prefersBorder: true,
|
|
232
|
+
openai: { outputTemplate: "ui://mosaic/tasks", preferredDisplayMode: "inline" }, // optional
|
|
233
|
+
});
|
|
234
|
+
// resource._meta = { ui: { csp, prefersBorder, domain }, "openai/ui"?: { availableDisplayModes?, preferredDisplayMode? } }
|
|
235
|
+
// toolMeta = { ui: { resourceUri }, "openai/outputTemplate"?, "openai/ui"?: { entrypoints } }
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
`domain` is `{sha256(servedUrl) first 32 hex}.claudemcpcontent.com` and is absent when
|
|
239
|
+
`servedUrl` is not given. `openai.availableDisplayModes` / `preferredDisplayMode` accept
|
|
240
|
+
`inline` | `fullscreen` only; `pip` throws.
|
|
241
|
+
|
|
242
|
+
It composes with `@modelcontextprotocol/ext-apps/server`: `registerAppResource` and
|
|
243
|
+
`registerAppTool` pass `_meta` through (they only default the MIME type and back-fill the
|
|
244
|
+
deprecated flat `ui/resourceUri`), so feed them `resource._meta` and `toolMeta`; this helper adds
|
|
245
|
+
the csp defaults, the derived Claude `domain` and the additive `openai/*` keys they do not produce.
|
|
246
|
+
|
|
247
|
+
### Host context (view)
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
import { useMosaicHostTheme, useRequestDisplayMode, useUpdateModelContext } from "@vantageos/mosaic/react/host";
|
|
251
|
+
// Preact: the same names from "@vantageos/mosaic/preact/host"
|
|
252
|
+
|
|
253
|
+
const ctx = useMosaicHostTheme(app); // theme, displayMode, locale, containerDimensions, deepLink
|
|
254
|
+
const goFullscreen = useRequestDisplayMode(app); // "inline" | "fullscreen"; pip refused for ChatGPT
|
|
255
|
+
const tellModel = useUpdateModelContext(app); // ui/update-model-context
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`ctx.theme` is mapped onto mosaic-tokens (`data-theme` light/dark, applied to `<html>`).
|
|
259
|
+
`ctx.deepLink` reads `hostContext["openai/deepLink"]` (`{ url }`) when present and is `undefined`
|
|
260
|
+
otherwise. ChatGPT is detected from `openai/*` keys in the host context or experimental host
|
|
261
|
+
capabilities (the spec defines no host-identification field; no user-agent sniffing). Framework-free equivalents (`readHostContext`, `requestDisplayMode`,
|
|
262
|
+
`updateModelContext`, `subscribeHostContext`, `applyMosaicTheme`) live in
|
|
263
|
+
`@vantageos/mosaic/host`.
|
|
264
|
+
|
|
265
|
+
### Host layout, messages and links (view)
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
import { useMosaicHostLayout, useSendMessage, useOpenLink } from "@vantageos/mosaic/react/host";
|
|
269
|
+
|
|
270
|
+
useMosaicHostLayout(app); // data-theme + safe-area padding + host style variables + host fonts
|
|
271
|
+
const send = useSendMessage(app); // ui/message: await send("Show the overdue tasks")
|
|
272
|
+
const open = useOpenLink(app); // ui/open-link: await open("https://wallet.example/swap?q=1")
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
* **Safe-area insets** (`hostContext.safeAreaInsets`, MCP Apps spec): applied as root padding and as
|
|
276
|
+
`--mosaic-safe-area-<side>` variables (for `scroll-padding`).
|
|
277
|
+
* **Host style variables** (`hostContext.styles.variables`, 76 standardized keys) are written on the
|
|
278
|
+
root and bridged onto the mosaic-tokens custom properties they correspond to (`HOST_TO_MOSAIC_TOKENS`);
|
|
279
|
+
variables the host does not pass leave the mosaic-tokens defaults untouched. Host fonts
|
|
280
|
+
(`styles.css.fonts`) are injected once; add the Claude font origin to `csp.resourceDomains` with
|
|
281
|
+
`buildMcpAppResource({ hostFonts: true })`. `applyTransparentBackground(document)` sets html/body to
|
|
282
|
+
`transparent` (Claude transparent theming).
|
|
283
|
+
* **`sendMessage`**: options `{ target, send }` need the host to advertise `openai/message` and a
|
|
284
|
+
non-mobile platform; otherwise it THROWS rather than silently dropping `send: false`.
|
|
285
|
+
* **`openLink`**: http(s) only; the host's denial reason is thrown (`HostRequestError`).
|
|
286
|
+
* **Typed model context**: `textBlock(text, { title, thumbnail, background })` builds blocks with
|
|
287
|
+
`_meta["openai/title"]`, `_meta["openai/thumbnail"]` and `annotations.audience: ["assistant"]`;
|
|
288
|
+
`selectionModelContext(rows, columns, locale)` turns a table selection into one titled block (feed it
|
|
289
|
+
to `updateModelContext` from `onSelectionChange`); `hostContext["openai/modelContext"]` is read into
|
|
290
|
+
`ctx.modelContext` (`null` = cleared by the user).
|
|
291
|
+
* **Tool visibility**: `buildMcpAppResource({ visibility: ["app"] })` emits `_meta.ui.visibility`
|
|
292
|
+
(omitted = the spec default `["model", "app"]`).
|
|
293
|
+
* **Size reporting**: a view that talks to the host through the raw adapter calls
|
|
294
|
+
`startSizeReporting()` (`ui/notifications/size-changed` through a ResizeObserver). The ext-apps `App`
|
|
295
|
+
does this itself with `autoResize`.
|
|
296
|
+
|
|
297
|
+
### Tool results with an A-1 markdown fallback (server)
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
import { createMosaicToolResult } from "@vantageos/mosaic/server";
|
|
301
|
+
|
|
302
|
+
return createMosaicToolResult("PipelineBoard", { stages, currency: "EUR" }, "en");
|
|
303
|
+
// { content: [ { type: "text", text: "# Pipeline\n\n| Stage | Deals | Total | ..." },
|
|
304
|
+
// { type: "resource", resource: { uri: "ui://mosaic/pipelineboard", ... } } ] }
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
The text block carries the view's DATA (App standard A-1: a client with no UI layer gets an equivalent,
|
|
308
|
+
meaningful answer). All 12 supported components have a pure `<name>ToMarkdown(props, locale)`, also
|
|
309
|
+
exported from `@vantageos/mosaic/server`. `_meta.ui.fallback` is kept (it is part of the published
|
|
310
|
+
`createMosaicResource` result) and now holds the same text instead of a title and a note. A one-time
|
|
311
|
+
token's value is never written into `content[]`.
|
|
312
|
+
|
|
313
|
+
**Secret guard.** `MOSAIC_NEVER_SERIALISE` lists, per view, the fields whose value must never reach
|
|
314
|
+
`content[]`. `createMosaicToolResult` renders the fallback from the props without them, delivers them in
|
|
315
|
+
the result `_meta["mosaic/secrets"]`, and refuses (`MosaicSecretLeakError`) if any non-empty declared
|
|
316
|
+
value still appears, at any length. The comparison is case-folded and NFKC-normalised on both sides, so
|
|
317
|
+
`ABCD` is an echo of `abcd`; a very short secret can therefore also collide with unrelated text and
|
|
318
|
+
refuse loudly (the issuer keeps it out of the other props).
|
|
319
|
+
|
|
211
320
|
## Components
|
|
212
321
|
|
|
213
322
|
### What each subpath actually exports
|
|
@@ -223,10 +332,10 @@ node -e '...' # see the release PR for the exact script
|
|
|
223
332
|
| Subpath | Exports |
|
|
224
333
|
|---|---|
|
|
225
334
|
| `forms` | Checkbox, ErrorDisplay, FieldArray, FormField, FormProvider, Input, MultiSelect, RadioGroup, Select, SubmitButton, Textarea |
|
|
226
|
-
| `display` | Badge, EmptyState, Skeleton, StatusBadge, StreamingTableView, TableView, VirtualList |
|
|
227
|
-
| `progress` | ProgressBar |
|
|
335
|
+
| `display` | BalanceCard, Badge, EmptyState, MessageFeed, PipelineBoard, Skeleton, StatCard, StatusBadge, StreamingTableView, TableView, VirtualList |
|
|
336
|
+
| `progress` | ProgressBar, Timeline |
|
|
228
337
|
| `input` | Tabs |
|
|
229
|
-
| `confirmation` | Alert, ConfirmDialog, ConfirmModal, TokenDisplayOnceModal |
|
|
338
|
+
| `confirmation` | Alert, ConfirmDialog, ConfirmModal, TokenDisplayOnceModal, TransactionPreview |
|
|
230
339
|
| `artifacts` | MarkdownRenderer |
|
|
231
340
|
| `media` | *(none)* |
|
|
232
341
|
|