@ggui-ai/protocol 0.1.0-rc.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/LICENSE +201 -0
- package/README.md +46 -0
- package/dist/bridge/invoke-agent.d.ts +65 -0
- package/dist/bridge/invoke-agent.d.ts.map +1 -0
- package/dist/bridge/invoke-agent.js +113 -0
- package/dist/envelope-adapters.d.ts +24 -0
- package/dist/envelope-adapters.d.ts.map +1 -0
- package/dist/envelope-adapters.js +14 -0
- package/dist/envelopes/builders.d.ts +145 -0
- package/dist/envelopes/builders.d.ts.map +1 -0
- package/dist/envelopes/builders.js +113 -0
- package/dist/errors/unknown-permission-name.d.ts +12 -0
- package/dist/errors/unknown-permission-name.d.ts.map +1 -0
- package/dist/errors/unknown-permission-name.js +29 -0
- package/dist/errors/version-mismatch.d.ts +55 -0
- package/dist/errors/version-mismatch.d.ts.map +1 -0
- package/dist/errors/version-mismatch.js +52 -0
- package/dist/gadgets/resolve-contract-gadgets.d.ts +93 -0
- package/dist/gadgets/resolve-contract-gadgets.d.ts.map +1 -0
- package/dist/gadgets/resolve-contract-gadgets.js +119 -0
- package/dist/gadgets/stdlib-gadgets.d.ts +43 -0
- package/dist/gadgets/stdlib-gadgets.d.ts.map +1 -0
- package/dist/gadgets/stdlib-gadgets.js +161 -0
- package/dist/iframe-bridge.d.ts +63 -0
- package/dist/iframe-bridge.d.ts.map +1 -0
- package/dist/iframe-bridge.js +166 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +79 -0
- package/dist/integrations/mcp-apps.d.ts +1218 -0
- package/dist/integrations/mcp-apps.d.ts.map +1 -0
- package/dist/integrations/mcp-apps.js +427 -0
- package/dist/navigation/index.d.ts +3 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +1 -0
- package/dist/navigation/stack-navigation.d.ts +55 -0
- package/dist/navigation/stack-navigation.d.ts.map +1 -0
- package/dist/navigation/stack-navigation.js +80 -0
- package/dist/recommended-prompts.d.ts +56 -0
- package/dist/recommended-prompts.d.ts.map +1 -0
- package/dist/recommended-prompts.js +55 -0
- package/dist/registry/blueprint-key.d.ts +9 -0
- package/dist/registry/blueprint-key.d.ts.map +1 -0
- package/dist/registry/blueprint-key.js +28 -0
- package/dist/registry/canonicalize-contract.d.ts +35 -0
- package/dist/registry/canonicalize-contract.d.ts.map +1 -0
- package/dist/registry/canonicalize-contract.js +166 -0
- package/dist/registry/summarize-contract.d.ts +46 -0
- package/dist/registry/summarize-contract.d.ts.map +1 -0
- package/dist/registry/summarize-contract.js +63 -0
- package/dist/schema-learning/derive-contract.d.ts +67 -0
- package/dist/schema-learning/derive-contract.d.ts.map +1 -0
- package/dist/schema-learning/derive-contract.js +117 -0
- package/dist/schema-learning/merge.d.ts +32 -0
- package/dist/schema-learning/merge.d.ts.map +1 -0
- package/dist/schema-learning/merge.js +146 -0
- package/dist/schemas/blueprint.d.ts +32 -0
- package/dist/schemas/blueprint.d.ts.map +1 -0
- package/dist/schemas/blueprint.js +92 -0
- package/dist/schemas/data-contract.d.ts +750 -0
- package/dist/schemas/data-contract.d.ts.map +1 -0
- package/dist/schemas/data-contract.js +663 -0
- package/dist/schemas/gadget-name-grammar.d.ts +29 -0
- package/dist/schemas/gadget-name-grammar.d.ts.map +1 -0
- package/dist/schemas/gadget-name-grammar.js +28 -0
- package/dist/schemas/handshake-suggestion.d.ts +46 -0
- package/dist/schemas/handshake-suggestion.d.ts.map +1 -0
- package/dist/schemas/handshake-suggestion.js +107 -0
- package/dist/schemas/invoke.d.ts +337 -0
- package/dist/schemas/invoke.d.ts.map +1 -0
- package/dist/schemas/invoke.js +169 -0
- package/dist/schemas/mcp.d.ts +301 -0
- package/dist/schemas/mcp.d.ts.map +1 -0
- package/dist/schemas/mcp.js +373 -0
- package/dist/schemas/ops-blueprint.d.ts +176 -0
- package/dist/schemas/ops-blueprint.d.ts.map +1 -0
- package/dist/schemas/ops-blueprint.js +259 -0
- package/dist/schemas/sync-check.d.ts +11 -0
- package/dist/schemas/sync-check.d.ts.map +1 -0
- package/dist/schemas/sync-check.js +60 -0
- package/dist/screen-blueprints/define.d.ts +22 -0
- package/dist/screen-blueprints/define.d.ts.map +1 -0
- package/dist/screen-blueprints/define.js +3 -0
- package/dist/screen-blueprints/index.d.ts +4 -0
- package/dist/screen-blueprints/index.d.ts.map +1 -0
- package/dist/screen-blueprints/index.js +3 -0
- package/dist/screen-blueprints/match.d.ts +35 -0
- package/dist/screen-blueprints/match.d.ts.map +1 -0
- package/dist/screen-blueprints/match.js +51 -0
- package/dist/screen-blueprints/types.d.ts +164 -0
- package/dist/screen-blueprints/types.d.ts.map +1 -0
- package/dist/screen-blueprints/types.js +1 -0
- package/dist/stream/stream-parser.d.ts +62 -0
- package/dist/stream/stream-parser.d.ts.map +1 -0
- package/dist/stream/stream-parser.js +199 -0
- package/dist/transport/websocket.d.ts +178 -0
- package/dist/transport/websocket.d.ts.map +1 -0
- package/dist/transport/websocket.js +1 -0
- package/dist/types/app-config.d.ts +61 -0
- package/dist/types/app-config.d.ts.map +1 -0
- package/dist/types/app-config.js +1 -0
- package/dist/types/auth.d.ts +61 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +1 -0
- package/dist/types/blueprint.d.ts +206 -0
- package/dist/types/blueprint.d.ts.map +1 -0
- package/dist/types/blueprint.js +1 -0
- package/dist/types/canvas-lifecycle.d.ts +105 -0
- package/dist/types/canvas-lifecycle.d.ts.map +1 -0
- package/dist/types/canvas-lifecycle.js +38 -0
- package/dist/types/capabilities.d.ts +40 -0
- package/dist/types/capabilities.d.ts.map +1 -0
- package/dist/types/capabilities.js +19 -0
- package/dist/types/contract-inference.d.ts +401 -0
- package/dist/types/contract-inference.d.ts.map +1 -0
- package/dist/types/contract-inference.js +44 -0
- package/dist/types/credential.d.ts +41 -0
- package/dist/types/credential.d.ts.map +1 -0
- package/dist/types/credential.js +32 -0
- package/dist/types/data-bindings.d.ts +322 -0
- package/dist/types/data-bindings.d.ts.map +1 -0
- package/dist/types/data-bindings.js +29 -0
- package/dist/types/data-contract.d.ts +1296 -0
- package/dist/types/data-contract.d.ts.map +1 -0
- package/dist/types/data-contract.js +111 -0
- package/dist/types/events.d.ts +182 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +8 -0
- package/dist/types/feedback.d.ts +24 -0
- package/dist/types/feedback.d.ts.map +1 -0
- package/dist/types/feedback.js +7 -0
- package/dist/types/gadget.d.ts +121 -0
- package/dist/types/gadget.d.ts.map +1 -0
- package/dist/types/gadget.js +24 -0
- package/dist/types/handshake-suggestion.d.ts +264 -0
- package/dist/types/handshake-suggestion.d.ts.map +1 -0
- package/dist/types/handshake-suggestion.js +70 -0
- package/dist/types/host-context.d.ts +163 -0
- package/dist/types/host-context.d.ts.map +1 -0
- package/dist/types/host-context.js +142 -0
- package/dist/types/interface-context.d.ts +105 -0
- package/dist/types/interface-context.d.ts.map +1 -0
- package/dist/types/interface-context.js +115 -0
- package/dist/types/invoke.d.ts +28 -0
- package/dist/types/invoke.d.ts.map +1 -0
- package/dist/types/invoke.js +7 -0
- package/dist/types/live-channel.d.ts +613 -0
- package/dist/types/live-channel.d.ts.map +1 -0
- package/dist/types/live-channel.js +1 -0
- package/dist/types/llm.d.ts +61 -0
- package/dist/types/llm.d.ts.map +1 -0
- package/dist/types/llm.js +186 -0
- package/dist/types/mcp-proxy.d.ts +67 -0
- package/dist/types/mcp-proxy.d.ts.map +1 -0
- package/dist/types/mcp-proxy.js +46 -0
- package/dist/types/mcp.d.ts +637 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +30 -0
- package/dist/types/openrouter-models.d.ts +22 -0
- package/dist/types/openrouter-models.d.ts.map +1 -0
- package/dist/types/openrouter-models.js +4843 -0
- package/dist/types/region.d.ts +26 -0
- package/dist/types/region.d.ts.map +1 -0
- package/dist/types/region.js +36 -0
- package/dist/types/session.d.ts +419 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +1 -0
- package/dist/types/thread.d.ts +207 -0
- package/dist/types/thread.d.ts.map +1 -0
- package/dist/types/thread.js +57 -0
- package/dist/types/ui-generator.d.ts +100 -0
- package/dist/types/ui-generator.d.ts.map +1 -0
- package/dist/types/ui-generator.js +53 -0
- package/dist/validation/ajv-runtime.d.ts +140 -0
- package/dist/validation/ajv-runtime.d.ts.map +1 -0
- package/dist/validation/ajv-runtime.js +452 -0
- package/dist/validation/content-hash.d.ts +3 -0
- package/dist/validation/content-hash.d.ts.map +1 -0
- package/dist/validation/content-hash.js +21 -0
- package/dist/validation/contract-validator.d.ts +244 -0
- package/dist/validation/contract-validator.d.ts.map +1 -0
- package/dist/validation/contract-validator.js +711 -0
- package/dist/validation/cross-references.d.ts +105 -0
- package/dist/validation/cross-references.d.ts.map +1 -0
- package/dist/validation/cross-references.js +164 -0
- package/dist/validation/hygiene-rules.d.ts +250 -0
- package/dist/validation/hygiene-rules.d.ts.map +1 -0
- package/dist/validation/hygiene-rules.js +564 -0
- package/dist/validation/lint-contract.d.ts +130 -0
- package/dist/validation/lint-contract.d.ts.map +1 -0
- package/dist/validation/lint-contract.js +225 -0
- package/dist/validation/name-invariants.d.ts +117 -0
- package/dist/validation/name-invariants.d.ts.map +1 -0
- package/dist/validation/name-invariants.js +172 -0
- package/dist/validation/reserved-channels.d.ts +156 -0
- package/dist/validation/reserved-channels.d.ts.map +1 -0
- package/dist/validation/reserved-channels.js +356 -0
- package/dist/validation/resolve-stream-channel.d.ts +78 -0
- package/dist/validation/resolve-stream-channel.d.ts.map +1 -0
- package/dist/validation/resolve-stream-channel.js +64 -0
- package/dist/validation/sanitize-error.d.ts +46 -0
- package/dist/validation/sanitize-error.d.ts.map +1 -0
- package/dist/validation/sanitize-error.js +88 -0
- package/dist/validation/schema-compat-invariants.d.ts +140 -0
- package/dist/validation/schema-compat-invariants.d.ts.map +1 -0
- package/dist/validation/schema-compat-invariants.js +220 -0
- package/dist/validation/schema-meta-validation.d.ts +60 -0
- package/dist/validation/schema-meta-validation.d.ts.map +1 -0
- package/dist/validation/schema-meta-validation.js +131 -0
- package/dist/validation/schema-subset.d.ts +165 -0
- package/dist/validation/schema-subset.d.ts.map +1 -0
- package/dist/validation/schema-subset.js +295 -0
- package/dist/validation/ui-security.d.ts +54 -0
- package/dist/validation/ui-security.d.ts.map +1 -0
- package/dist/validation/ui-security.js +138 -0
- package/dist/validation/zod-to-json-schema.d.ts +63 -0
- package/dist/validation/zod-to-json-schema.d.ts.map +1 -0
- package/dist/validation/zod-to-json-schema.js +126 -0
- package/dist/version.d.ts +1458 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +1459 -0
- package/package.json +113 -0
package/dist/version.js
ADDED
|
@@ -0,0 +1,1459 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Current protocol version. Used for cache invalidation and capability discovery.
|
|
3
|
+
*
|
|
4
|
+
* The block comment below is a chronological changelog of protocol
|
|
5
|
+
* wire-shape changes. Each dated entry describes a wire-shape or
|
|
6
|
+
* schema change; the most recent change anchors {@link PROTOCOL_VERSION}.
|
|
7
|
+
*
|
|
8
|
+
* --------------------------------------------------------------------
|
|
9
|
+
* `GguiBootstrapMeta.compiledValidators` — precompiled eval-free
|
|
10
|
+
* runtime validators (ADDITIVE, non-breaking):
|
|
11
|
+
*
|
|
12
|
+
* - `GguiBootstrapMeta` (and the server's `StackItemBootstrapView`
|
|
13
|
+
* projection) gain an optional `compiledValidators` field —
|
|
14
|
+
* `CompiledContractValidators`: ESM validator-module source
|
|
15
|
+
* strings, one per `propsSpec` / `actionSpec` entry / `streamSpec`
|
|
16
|
+
* channel / `contextSpec` slot, compiled server-side by
|
|
17
|
+
* `compileValidatorModule`.
|
|
18
|
+
* - The renderer iframe runs under a strict CSP with no
|
|
19
|
+
* `'unsafe-eval'`, so it cannot run `ajv.compile()` (which builds
|
|
20
|
+
* validators via `new Function`). Validators are now compiled at
|
|
21
|
+
* push time — where `eval` is legal and the contract schema is
|
|
22
|
+
* fixed — and shipped; the iframe loads them via `blob:` dynamic
|
|
23
|
+
* import and only ever RUNS them.
|
|
24
|
+
* - Additive + optional: a bootstrap without the field is valid;
|
|
25
|
+
* a consumer that ignores it falls back to the server as the sole
|
|
26
|
+
* contract authority.
|
|
27
|
+
*
|
|
28
|
+
* --------------------------------------------------------------------
|
|
29
|
+
* Wire `GadgetRef` retired — `clientCapabilities.gadgets` package-keyed,
|
|
30
|
+
* `version` dropped from the wire (BREAKING, pre-launch):
|
|
31
|
+
*
|
|
32
|
+
* w1. **`clientCapabilities.gadgets` is package-keyed.** The wire map
|
|
33
|
+
* flipped from `Record<bindingName, GadgetRef>` to
|
|
34
|
+
* `Record<packageName, GadgetPackageUse>`, where
|
|
35
|
+
* `GadgetPackageUse = Record<exportName, GadgetExportUse>` and
|
|
36
|
+
* `GadgetExportUse = { description?, usage? }`. A package entry IS
|
|
37
|
+
* its export map — the wire has no package-level field, so there
|
|
38
|
+
* is no `exports` wrapper. The export NAME is the inner map key;
|
|
39
|
+
* its grammar (`use`-prefixed hook vs PascalCase component)
|
|
40
|
+
* discriminates kind — there is no `hook` / `component` field and
|
|
41
|
+
* no arbitrary `binding` name.
|
|
42
|
+
*
|
|
43
|
+
* w2. **`version` is OFF the wire.** A wire gadget reference carries
|
|
44
|
+
* identity only — `(package, export name)`. `version` is the
|
|
45
|
+
* operator's deployment pin in `App.gadgets`, not the agent's to
|
|
46
|
+
* author: the ggui server resolves the full `GadgetDescriptor`
|
|
47
|
+
* (version + transport metadata) from the catalog at push time.
|
|
48
|
+
* The catalog lint enforces ≤1 descriptor per package, so
|
|
49
|
+
* `(name, package)` resolves to exactly one registered export.
|
|
50
|
+
*
|
|
51
|
+
* w3. **`GadgetRef` / `GadgetHookRef` / `GadgetComponentRef` /
|
|
52
|
+
* `GadgetRefBase` + schema `gadgetRefSchema` + helper
|
|
53
|
+
* `gadgetPackageKey` deleted.** New: `GadgetPackageUse`,
|
|
54
|
+
* `GadgetExportUse`, `GadgetUse` (a flattened `{ package, name,
|
|
55
|
+
* description?, usage? }` view) + `listContractGadgets(contract)`
|
|
56
|
+
* flatten helper. `gadgetIdentityKey` re-keyed to `(name, package)`.
|
|
57
|
+
*
|
|
58
|
+
* w4. **Push reject `gadget_version_not_registered` removed.** With no
|
|
59
|
+
* wire `version` there is nothing to mismatch;
|
|
60
|
+
* `assertGadgetsRegistered` keeps `gadget_not_registered` +
|
|
61
|
+
* `gadget_package_mismatch`. New fatal catalog lint
|
|
62
|
+
* `LINT_GADGET_DUPLICATE_PACKAGE` enforces ≤1 descriptor per
|
|
63
|
+
* package in an app's `App.gadgets`.
|
|
64
|
+
*
|
|
65
|
+
* --------------------------------------------------------------------
|
|
66
|
+
* `loadGadgets()` retired — gadgets direct-imported, runtime registry
|
|
67
|
+
* per-package (BREAKING, pre-launch):
|
|
68
|
+
*
|
|
69
|
+
* v1. **`GguiBootstrapMeta.gadgets` is per-package.** The channel
|
|
70
|
+
* flipped from one entry per hook (`{hook, package?, bundleUrl?,
|
|
71
|
+
* bundleSri?}`) to one entry per registered gadget PACKAGE
|
|
72
|
+
* (`{package, bundleUrl?, bundleSri?}` — `package` REQUIRED). The
|
|
73
|
+
* iframe-runtime loads each package's module namespace once and
|
|
74
|
+
* stores it under `globalThis.__ggui__.gadgets[package]`, so every
|
|
75
|
+
* hook AND component export the package ships is reachable. The
|
|
76
|
+
* runtime `gadgets` slot is correspondingly keyed by package name
|
|
77
|
+
* (`Record<package, ModuleNamespace>`), not flat by hook name.
|
|
78
|
+
*
|
|
79
|
+
* v2. **`loadGadgets()` removed from `@ggui-ai/gadgets`.** Generated
|
|
80
|
+
* component code now direct-imports gadget exports
|
|
81
|
+
* (`import { useLeafletMap } from '@my-org/leaflet'`) — one idiom
|
|
82
|
+
* with the design-system primitives. The `loadGadgets()` accessor
|
|
83
|
+
* + its `GadgetsCatalog` Proxy are gone; the 7 STDLIB hooks stay
|
|
84
|
+
* as plain named exports of `@ggui-ai/gadgets`. The iframe-runtime
|
|
85
|
+
* rewriter resolves every gadget package specifier to a
|
|
86
|
+
* per-package data-URL shim (hook exports → lazy thunks, component
|
|
87
|
+
* exports → error-boundary-wrapped components).
|
|
88
|
+
*
|
|
89
|
+
* --------------------------------------------------------------------
|
|
90
|
+
* Component gadgets — `GadgetDescriptor` normalized to a package
|
|
91
|
+
* (BREAKING, pre-launch):
|
|
92
|
+
*
|
|
93
|
+
* u1. **`GadgetDescriptor` is now a PACKAGE.** A descriptor carries
|
|
94
|
+
* package identity (`package`, `version`) + transport metadata
|
|
95
|
+
* (`bundleUrl`, `bundleHost`, `bundleSri`, `styleUrl`, `connect`,
|
|
96
|
+
* `requires`, `typesUrl`, `typesSri`) once at the package level,
|
|
97
|
+
* plus an `exports: GadgetExport[]` array (≥1, enforced by the
|
|
98
|
+
* schema). The per-export fields that used to sit flat on the
|
|
99
|
+
* descriptor — `hook`, `description`, `usage`, `example`,
|
|
100
|
+
* `gotchas`, `permission`, `required` — MOVED onto each
|
|
101
|
+
* `exports[*]`. A gadget package can now ship more than one
|
|
102
|
+
* export behind a single npm identity + bundle.
|
|
103
|
+
*
|
|
104
|
+
* u2. **`GadgetExport` is a union discriminated by field presence
|
|
105
|
+
* (`hook` vs `component`) — no `kind` field.**
|
|
106
|
+
* `GadgetExport = GadgetHookExport | GadgetComponentExport`,
|
|
107
|
+
* told apart by which identifier field is present: `{hook, …}` is
|
|
108
|
+
* a `use`-prefixed React hook the generated component calls;
|
|
109
|
+
* `{component, …}` is a PascalCase React component the generated
|
|
110
|
+
* code renders as JSX. Both share the per-export teaching text
|
|
111
|
+
* (`description` / `usage` / `example` / `gotchas`) + runtime
|
|
112
|
+
* gates (`permission` / `required`) via `GadgetExportBase`. New
|
|
113
|
+
* schemas `gadgetExportSchema` (wire-permissive) +
|
|
114
|
+
* `strictGadgetExportSchema` (registry — teaching text required,
|
|
115
|
+
* `permission` enum-tight).
|
|
116
|
+
*
|
|
117
|
+
* u3. **`GadgetRef` (wire) is a union discriminated by field
|
|
118
|
+
* presence (`hook` vs `component`) — no `kind` field.**
|
|
119
|
+
* `GadgetRef = GadgetHookRef | GadgetComponentRef` — the wire
|
|
120
|
+
* ref selects ONE export of a registered package:
|
|
121
|
+
* `{hook, package, version, description?, usage?}`
|
|
122
|
+
* or `{component, package, version, description?, usage?}`.
|
|
123
|
+
* `gadgetRefSchema` is a `z.union([…])` of two `.strict()`
|
|
124
|
+
* members — transport fields + per-export registry metadata stay
|
|
125
|
+
* off the wire.
|
|
126
|
+
*
|
|
127
|
+
* u4. **`descriptorToJSDoc` → `exportToJSDoc`.** The codegen helper
|
|
128
|
+
* now takes a `GadgetExport` (`exportToJSDoc(entry: GadgetExport)`)
|
|
129
|
+
* and projects its per-export teaching text. `catalogToAugmentationDts`
|
|
130
|
+
* walks `descriptor.exports`, emitting one `typeof import(...)`
|
|
131
|
+
* declaration per HOOK export (component exports are skipped —
|
|
132
|
+
* `GadgetsCatalog` is the `loadGadgets()` hook surface).
|
|
133
|
+
* (`catalogToAugmentationDts` retired GG.8.3 — the descriptor-
|
|
134
|
+
* derived TS augmentation supersedes it.)
|
|
135
|
+
*
|
|
136
|
+
* u5. **New helpers `gadgetExportName` / `gadgetPackageKey`.**
|
|
137
|
+
* `gadgetExportName(x: GadgetRef | GadgetExport)` returns the
|
|
138
|
+
* `hook` | `component` name — the single accessor every site
|
|
139
|
+
* that used to read `.hook` now calls. `gadgetPackageKey({package,
|
|
140
|
+
* version})` is the canonical `(package, version)` dedup key the
|
|
141
|
+
* resolver keys on; `gadgetIdentityKey(ref)` is the full
|
|
142
|
+
* `(name, package, version)` export-identity key the push-time
|
|
143
|
+
* gates agree on (the hook / component name grammars are
|
|
144
|
+
* disjoint, so the name itself is kind-disambiguating).
|
|
145
|
+
* (`gadgetPackageKey` + `GadgetRef` retired in GG.8.8 — the wire
|
|
146
|
+
* went package-keyed, so `version` left the wire and the
|
|
147
|
+
* `(package, version)` key collapsed to package-only; see the
|
|
148
|
+
* w-block. `gadgetIdentityKey` now keys `(name, package)`.)
|
|
149
|
+
*
|
|
150
|
+
* u6. **New name grammars `HOOK_NAME_RE` + `COMPONENT_NAME_RE`.**
|
|
151
|
+
* `HOOK_NAME_RE` (`/^use[A-Z][A-Za-z0-9]*$/`) pins the
|
|
152
|
+
* `use`-prefixed hook grammar; `COMPONENT_NAME_RE`
|
|
153
|
+
* (`/^[A-Z][A-Za-z0-9]*$/`) pins the PascalCase component
|
|
154
|
+
* grammar. Both the wire `gadgetRefSchema` and the registry
|
|
155
|
+
* `gadget(Strict)ExportSchema` enforce them, so a malformed
|
|
156
|
+
* export name fails loudly at parse time.
|
|
157
|
+
* (`gadgetRefSchema` retired GG.8.8 with the wire shift to the
|
|
158
|
+
* package-keyed `clientCapabilities.gadgets` map; the grammars
|
|
159
|
+
* themselves stay live — see the w-block.)
|
|
160
|
+
*
|
|
161
|
+
* `STDLIB_GADGETS` collapses to a 1-element array — the
|
|
162
|
+
* `@ggui-ai/gadgets` package descriptor whose `exports` are the
|
|
163
|
+
* seven stdlib hook exports. `loadGadgets()` + component-gadget
|
|
164
|
+
* rendering are GG.8.2+ work; GG.8.1 is the type/schema layer only.
|
|
165
|
+
*
|
|
166
|
+
* --------------------------------------------------------------------
|
|
167
|
+
* Client-library plugin SDK + registry-membership gate (additive, no
|
|
168
|
+
* wire breakage):
|
|
169
|
+
*
|
|
170
|
+
* p1. **`createGguiGadget` SDK** in `@ggui-ai/gadgets`.
|
|
171
|
+
* Authors a single wrapper that publishes a stable React hook
|
|
172
|
+
* contract atop a 3rd-party library (Leaflet, Mapbox, Stripe,
|
|
173
|
+
* Chart.js, …) so the LLM never sees raw library APIs. Every
|
|
174
|
+
* wrapper carries `{description, usage, example}` (required) +
|
|
175
|
+
* optional `{gotchas, version, package, bundleUrl, styleUrl,
|
|
176
|
+
* connect[]}`. The factory zod-validates the spec at module load
|
|
177
|
+
* and throws `WrapperConformanceError` with field-path violations
|
|
178
|
+
* on shape misses. Returns a callable hook whose immutable
|
|
179
|
+
* `.descriptor` is what operators register on
|
|
180
|
+
* `App.gadgets`.
|
|
181
|
+
*
|
|
182
|
+
* p2. **Two-schema strictness pattern on `GadgetDescriptor`.** A
|
|
183
|
+
* single TS type drives both the registry (strict —
|
|
184
|
+
* `strictGadgetDescriptorSchema` requires `description` /
|
|
185
|
+
* `usage` / `example` and at least one of `package` /
|
|
186
|
+
* `bundleUrl`) and the contract refs (permissive —
|
|
187
|
+
* `gadgetDescriptorSchema` for wire/contract use). Strictness
|
|
188
|
+
* lives in the validators, not the type, so consumers don't
|
|
189
|
+
* duplicate type defs.
|
|
190
|
+
*
|
|
191
|
+
* p3. **Registry-membership gate at push validation.**
|
|
192
|
+
* `assertGadgetsRegistered(contract, appGadgets)`
|
|
193
|
+
* walks `contract.clientCapabilities.gadgets[*].hook` and
|
|
194
|
+
* throws `GadgetNotRegisteredError` on any reference not
|
|
195
|
+
* present in `App.gadgets`. Carries did-you-mean
|
|
196
|
+
* suggestions via `findClosestRegisteredHook` (Levenshtein < 3
|
|
197
|
+
* cutoff). Push falls back to `STDLIB_GADGETS` when the
|
|
198
|
+
* `App` row exists but doesn't carry an explicit catalog —
|
|
199
|
+
* symmetric with handshake.ts and list-gadgets.ts so
|
|
200
|
+
* every default-configured server enforces the gate without
|
|
201
|
+
* explicit operator config.
|
|
202
|
+
*
|
|
203
|
+
* p4. **Push-time enrichment of `StackItem.clientCapabilities`.**
|
|
204
|
+
* Thin contract Refs are merged with the canonical registry
|
|
205
|
+
* descriptor so the persisted StackItem carries the FULL entry
|
|
206
|
+
* (teaching text + bundleUrl + styleUrl + connect[]).
|
|
207
|
+
* Contract-side overrides win on conflict so agents may author
|
|
208
|
+
* intent-specific description/usage at the mount site.
|
|
209
|
+
*
|
|
210
|
+
* p5. **CSP derivation from registered gadget origins.** New
|
|
211
|
+
* `deriveBundleOrigins(item)` reads `bundleUrl` / `styleUrl` /
|
|
212
|
+
* `connect[]` off the enriched StackItem and emits per-directive
|
|
213
|
+
* origin buckets. `composeContentSecurityPolicy(origins)` formats
|
|
214
|
+
* them into a `Content-Security-Policy` header value
|
|
215
|
+
* (`script-src 'self' 'unsafe-inline' <origins>` so the inline
|
|
216
|
+
* `__GGUI_BOOTSTRAP__` survives, `style-src 'self' 'unsafe-inline'
|
|
217
|
+
* <origins>`, `connect-src 'self' <origins>`, `img-src 'self'
|
|
218
|
+
* data: <connect-origins>` so map tiles load). The renderer route
|
|
219
|
+
* attaches the header on `/r/<shortCode>` ONLY when libraries
|
|
220
|
+
* declare external origins — pre-plugin scenarios stay
|
|
221
|
+
* header-clean.
|
|
222
|
+
*
|
|
223
|
+
* p6. **Boilerplate generator prefers `bundleUrl` over `package`.**
|
|
224
|
+
* Imports group by `bundleUrl ?? package` so a gadget with a
|
|
225
|
+
* hosted bundle emits
|
|
226
|
+
* `import { useLeafletMap } from 'https://registry.ggui.ai/leaflet@0.0.1/bundle.js'`,
|
|
227
|
+
* while npm-packaged-only libraries fall through to the existing
|
|
228
|
+
* bare-specifier path.
|
|
229
|
+
*
|
|
230
|
+
* p7. **Teaching-text plumb into BOTH LLM paths.** The same
|
|
231
|
+
* `composeAvailableGadgetsSection(libraries)` helper feeds the
|
|
232
|
+
* synth prompt (`synthesize-contract.ts`) AND the decision-LLM
|
|
233
|
+
* prompt (`decision.ts`'s `buildDecisionUserMessage`). Both paths
|
|
234
|
+
* now see `description` + `usage` for every registered gadget
|
|
235
|
+
* with bounded per-entry (300 chars) + total (3 KB) budgets, so
|
|
236
|
+
* `App.gadgets`-registered plugins instruct the LLM
|
|
237
|
+
* uniformly without per-gadget prompt engineering.
|
|
238
|
+
*
|
|
239
|
+
* p8. **CLI seed via `ggui.json#app.gadgets`.** Manifest
|
|
240
|
+
* schema gains an optional array of full registry descriptors;
|
|
241
|
+
* the CLI threads them into `InMemoryAppMetadataStore` so the
|
|
242
|
+
* same in-process singleton powers `ggui_list_gadgets`,
|
|
243
|
+
* handshake, push validation + enrichment, and CSP derivation.
|
|
244
|
+
*
|
|
245
|
+
* p9. **Reference plugin + e2e gate.** `@ggui-samples/gadget-leaflet`
|
|
246
|
+
* ships as the canonical wrapper-author example;
|
|
247
|
+
* `@ggui-samples/ggui-leaflet-demo` is a sample server with the
|
|
248
|
+
* Leaflet plugin pre-registered. e2e/scenarios/19 pins the
|
|
249
|
+
* registry-membership gate end-to-end on the wire (registered
|
|
250
|
+
* hook accepts, unregistered hook rejects with
|
|
251
|
+
* `gadget_not_registered`, typo gets did-you-mean).
|
|
252
|
+
* Live-verified against `ggui-default` with a real LLM-backed
|
|
253
|
+
* negotiator.
|
|
254
|
+
*
|
|
255
|
+
* --------------------------------------------------------------------
|
|
256
|
+
* Ajv layered validation (single source of truth for inner JSON
|
|
257
|
+
* Schema + runtime data validation):
|
|
258
|
+
*
|
|
259
|
+
* v1. **All four runtime validators use Ajv + closed-shape.** The
|
|
260
|
+
* hand-rolled JSON-Schema-subset validator is retired.
|
|
261
|
+
* `validatePropsData` / `validateActionData` / `validateStreamData`
|
|
262
|
+
* / `validateContextData` now share one seam — `compileForValidation()`
|
|
263
|
+
* from `@ggui-ai/protocol/validation/ajv-runtime` — which injects
|
|
264
|
+
* `additionalProperties: false` at every object node before Ajv
|
|
265
|
+
* compiles. Closed-shape applies uniformly at any depth (arrays
|
|
266
|
+
* of objects, oneOf branches, additionalProperties-as-schema).
|
|
267
|
+
* The `done`-vs-declared-`completed` class of bug — and any
|
|
268
|
+
* similar field-name divergence — surfaces as a wire-time
|
|
269
|
+
* `ContractViolationError` with the exact path (`todos[0].done`)
|
|
270
|
+
* instead of rendering silently as `undefined`.
|
|
271
|
+
* Authors who genuinely want an opaque-object escape hatch set
|
|
272
|
+
* `additionalProperties: true` explicitly on the schema; the
|
|
273
|
+
* injector preserves author intent (boolean kept, schema-form
|
|
274
|
+
* recursed into).
|
|
275
|
+
* Tolerated keywords: `example` (OpenAPI metadata) and
|
|
276
|
+
* `nullable` (OpenAPI 3.0 shorthand) registered as no-ops so
|
|
277
|
+
* Ajv strict mode doesn't reject schemas that carry them.
|
|
278
|
+
* Pre-launch no-backcompat: stream / action / context schemas
|
|
279
|
+
* authored as `{type: 'object'}` with no `properties` now mean
|
|
280
|
+
* "empty object only" (not "any object"). Migrate to explicit
|
|
281
|
+
* `properties` declarations OR set `additionalProperties: true`.
|
|
282
|
+
*
|
|
283
|
+
* v2. **Layer-B meta-validation at handshake + push.**
|
|
284
|
+
* `assertContractSchemasValid(contract)` walks the six inner
|
|
285
|
+
* JSON Schema fields (`propsSpec.properties[*].schema`,
|
|
286
|
+
* `actionSpec[*].schema`, `streamSpec[*].schema`,
|
|
287
|
+
* `contextSpec[*].schema`, `agentCapabilities.tools[*].inputSchema`,
|
|
288
|
+
* `agentCapabilities.tools[*].outputSchema`) and runs
|
|
289
|
+
* `compileForValidation()` on each. Ajv strict mode throws at
|
|
290
|
+
* compile-time on malformed schemas (unknown keywords, properties
|
|
291
|
+
* values that aren't schemas, array schemas with non-schema
|
|
292
|
+
* items). Every offender collects into one
|
|
293
|
+
* `ContractSchemaMetaError` so the agent fixes them all in one
|
|
294
|
+
* round rather than retry-per-field. Called BEFORE the
|
|
295
|
+
* negotiator runs (handshake) and BEFORE any state mutation
|
|
296
|
+
* (push). Same fail-fast posture as the cross-reference +
|
|
297
|
+
* name-invariant + schema-compat assertions already in place.
|
|
298
|
+
*
|
|
299
|
+
* v3. **Wrapper zod schemas are `.strict()`.** Seven entry/spec
|
|
300
|
+
* wrappers in `@ggui-ai/protocol/schemas/data-contract` flipped
|
|
301
|
+
* from `.passthrough()` to `.strict()`:
|
|
302
|
+
* `propEntrySchema`, `propsSpecSchema`, `actionEntrySchema`,
|
|
303
|
+
* `streamChannelEntrySchema` (+ its inner `source` schema),
|
|
304
|
+
* `contextEntrySchema`, `agentToolEntrySchema` (+ its inner
|
|
305
|
+
* `example` schema), `gadgetDescriptorSchema`. Extras at the
|
|
306
|
+
* wrapper layer now reject — symmetric with the closed-shape
|
|
307
|
+
* rigor at the data layer. `jsonSchemaSchema` and the outer
|
|
308
|
+
* `dataContractSchema` envelope stay permissive (vendor JSON
|
|
309
|
+
* Schema extensions + forward-compatibility for future top-
|
|
310
|
+
* level fields).
|
|
311
|
+
* Pre-launch no-backcompat: agents that put unknown fields at
|
|
312
|
+
* wrapper layers MUST migrate. Common offender: `required: []`
|
|
313
|
+
* on the `propsSpec` wrapper (required lives per-entry, not at
|
|
314
|
+
* the spec level).
|
|
315
|
+
*
|
|
316
|
+
* --------------------------------------------------------------------
|
|
317
|
+
* propsSpec closed-shape (strict mode) + wire-schema trim:
|
|
318
|
+
*
|
|
319
|
+
* u3. **`pushOutputSchema` + `updateOutputSchema` + `handshakeOutputSchema`
|
|
320
|
+
* trimmed to match handler reality.** Three response schemas in
|
|
321
|
+
* `@ggui-ai/protocol/schemas/mcp` were carrying retired fields
|
|
322
|
+
* that handlers had already stopped emitting (zod strips them
|
|
323
|
+
* before serialization). Public schema now mirrors what flows on
|
|
324
|
+
* the wire — third-party importers see the same shape the
|
|
325
|
+
* structuredContent carries:
|
|
326
|
+
* - `handshakeOutputSchema`: dropped `reason`, `target`,
|
|
327
|
+
* `alternatives`, `contractHash`, `serverCapabilities`.
|
|
328
|
+
* `serverCapabilities` flows via `_meta.ggui.bootstrap` instead.
|
|
329
|
+
* - `pushOutputSchema`: dropped `sessionId`, `shortCode`,
|
|
330
|
+
* `codeReady`, `handshakeId`, `decision`, `contract`,
|
|
331
|
+
* `interaction`, `contractHash`, `cache.*`, `codeUrl`,
|
|
332
|
+
* `codeHash`. Wire shape is now `{stackItemId, url, action,
|
|
333
|
+
* nextStep?}` — 90% byte reduction at the trim layer.
|
|
334
|
+
* - `updateOutputSchema`: dropped `sessionId`, `decision`,
|
|
335
|
+
* `contract`, `interaction`, `contractHash`. Wire shape is
|
|
336
|
+
* now `{stackItemId, updated}`.
|
|
337
|
+
* Pre-launch no-backcompat: consumers that read any of the dropped
|
|
338
|
+
* fields off the wire response MUST migrate. Internal telemetry
|
|
339
|
+
* threading via TS-only `HandshakeOutput` / `PushOutput` /
|
|
340
|
+
* `UpdateOutput` shapes is preserved for handler-side callers.
|
|
341
|
+
*
|
|
342
|
+
* u2. **`validatePropsData` is closed-shape (strict mode).** Keys
|
|
343
|
+
* not declared on `propsSpec.properties` are now rejected with
|
|
344
|
+
* `ContractViolationError{tool:'ggui_update'}` (or `'ggui_push'`
|
|
345
|
+
* depending on call site). Load-bearing for `ggui_update kind:'merge'`
|
|
346
|
+
* — without it, a typo'd patch field would silently land on the
|
|
347
|
+
* stack item with no propsSpec coverage. Symmetric with
|
|
348
|
+
* `validateActionData`'s allowlist enforcement; intentionally
|
|
349
|
+
* asymmetric with `actionSpec.data` / `streamSpec.payload` /
|
|
350
|
+
* `contextSpec.value` (those validate type-only, forward-compatible).
|
|
351
|
+
* Pre-launch no-backcompat: agents that sent extra metadata fields
|
|
352
|
+
* alongside declared props MUST refine the contract's `propsSpec`
|
|
353
|
+
* to declare them, or drop them from the wire payload.
|
|
354
|
+
*
|
|
355
|
+
* --------------------------------------------------------------------
|
|
356
|
+
* `ggui_update` replace + merge modes:
|
|
357
|
+
*
|
|
358
|
+
* u1. **`kind: 'replace' | 'merge'` discriminator on `ggui_update`.**
|
|
359
|
+
* Wire input reshaped from `{stackItemId, props}` to a
|
|
360
|
+
* discriminated union:
|
|
361
|
+
* - `{stackItemId, kind:'replace', props}` — full props
|
|
362
|
+
* replacement; the map IS the new state. Same semantics as
|
|
363
|
+
* the pre-discriminator wire.
|
|
364
|
+
* - `{stackItemId, kind:'merge', patch}` — RFC 7396 JSON Merge
|
|
365
|
+
* Patch (top-level shallow merge; nested objects recurse;
|
|
366
|
+
* `null` deletes the key; arrays fully replace). Use when
|
|
367
|
+
* most props stay the same and the agent only needs to send
|
|
368
|
+
* a delta — typical after a single domain-tool mutation.
|
|
369
|
+
* Both modes validate the FINAL props (post-merge for `merge`)
|
|
370
|
+
* against the stack item's `propsSpec` and reject on violation.
|
|
371
|
+
* Missing the required field for a mode (e.g. `kind:'merge'`
|
|
372
|
+
* without `patch`) throws `ContractViolationError{tool:
|
|
373
|
+
* 'ggui_update'}` pre-mutation.
|
|
374
|
+
* Pre-launch no-backcompat: agents that issued the old
|
|
375
|
+
* `{stackItemId, props}` shape MUST migrate to
|
|
376
|
+
* `{stackItemId, kind:'replace', props}`. The OSS handler's
|
|
377
|
+
* handshakeId arm was retired in the same pass; protocol schema
|
|
378
|
+
* now mirrors the handler's direct-only surface.
|
|
379
|
+
*
|
|
380
|
+
* --------------------------------------------------------------------
|
|
381
|
+
* Pipe-as-single-source-of-truth pivot:
|
|
382
|
+
*
|
|
383
|
+
* t1. **`ggui_runtime_claim_pending` retired.** The iframe-side rescue
|
|
384
|
+
* drain + its 10s claim timer + per-action `pendingActions` map
|
|
385
|
+
* are gone. The pipe is now the single source of truth: every
|
|
386
|
+
* `submit_action` either succeeds (event lands on the pipe; agent
|
|
387
|
+
* drains via `ggui_consume`) or fails (`PIPE_NOT_FOUND` / transport
|
|
388
|
+
* error; iframe emits the action inline via `ui/message`). No
|
|
389
|
+
* timer, no rescue, no race between two atomic-pop callers.
|
|
390
|
+
*
|
|
391
|
+
* t2. **`_meta.ggui.userAction` unifies `fallback` + `nudge`.** New
|
|
392
|
+
* single discriminator on `ui/message` envelopes replacing the
|
|
393
|
+
* separate `_meta.ggui.fallback` (reason: pipe_not_found | timeout)
|
|
394
|
+
* + `_meta.ggui.nudge` (no_active_consumer) split:
|
|
395
|
+
*
|
|
396
|
+
* - `kind: 'queued'` — pipe HAS the event; agent SHOULD dispatch
|
|
397
|
+
* the prepared `{tool: 'ggui_consume', args: {stackItemId}}`
|
|
398
|
+
* nextStep to drain. Emitted when `submit_action` returned
|
|
399
|
+
* `{ok:true, consumerPresent:false}`.
|
|
400
|
+
* - `kind: 'inline'` — pipe is GONE; action data + uiContext
|
|
401
|
+
* delivered inline in `payload`. Agent MUST act directly on
|
|
402
|
+
* `payload.actionData`; calling `ggui_consume` would return
|
|
403
|
+
* empty. Emitted when `submit_action` returned PIPE_NOT_FOUND,
|
|
404
|
+
* INVALID_ACTION_KIND, or any transport/relay error. Optional
|
|
405
|
+
* `nextStep: string` hint surfaces the contract's bound agent
|
|
406
|
+
* tool when present.
|
|
407
|
+
*
|
|
408
|
+
* Type guard `isGguiUserActionMeta` lives on
|
|
409
|
+
* `@ggui-ai/protocol/integrations/mcp-apps`.
|
|
410
|
+
*
|
|
411
|
+
* t3. **Per-event `uiContext` on the pipe.** `submit_action`'s
|
|
412
|
+
* `dispatch` payload reshaped from `{intent, data}` to `{intent,
|
|
413
|
+
* actionData, uiContext}`. The iframe captures the contract's
|
|
414
|
+
* `contextSpec` snapshot at gesture time and stores it on the
|
|
415
|
+
* pipe entry alongside the action data — `consume`'s output
|
|
416
|
+
* events now carry `{intent, actionData, uiContext, actionId,
|
|
417
|
+
* firedAt}` per event.
|
|
418
|
+
*
|
|
419
|
+
* t4. **`GguiConsumeOutput.contextSnapshot` retired.** The top-level
|
|
420
|
+
* contextSpec snapshot on consume's output is gone. Per-event
|
|
421
|
+
* `uiContext` (t3) replaces it. Agents read state AS OF the
|
|
422
|
+
* moment the user acted — not the post-action state that might
|
|
423
|
+
* have already mutated by the time consume returns.
|
|
424
|
+
*
|
|
425
|
+
* --------------------------------------------------------------------
|
|
426
|
+
* No-active-consumer fast-path:
|
|
427
|
+
*
|
|
428
|
+
* s1. **`consumerPresent` on `ggui_runtime_submit_action` output.** New
|
|
429
|
+
* optional `consumerPresent?: boolean` field on the dispatch
|
|
430
|
+
* success branch. When `true`, at least one `ggui_consume`
|
|
431
|
+
* long-poll is currently registered against the targeted stack
|
|
432
|
+
* item — iframe takes today's path (10s claim timer + drain_ack
|
|
433
|
+
* race). When `false`, no consumer is registered: the action IS
|
|
434
|
+
* on the pipe, but the agent won't wake on its own. Iframe
|
|
435
|
+
* SHOULD immediately emit a `ui/message` nudge instead of
|
|
436
|
+
* waiting on the 10s timer. When `undefined`, the server doesn't
|
|
437
|
+
* have an active-consumer registry wired (graceful degradation;
|
|
438
|
+
* iframe falls back to the timer). Additive — agnostic consumers
|
|
439
|
+
* ignore the field.
|
|
440
|
+
*
|
|
441
|
+
* s2. **`_meta.ggui.nudge` discriminator on `ui/message`.** New
|
|
442
|
+
* structured fingerprint paired with the free-form text nudge:
|
|
443
|
+
* `{reason: 'no_active_consumer', stackItemId, actionId,
|
|
444
|
+
* submittedAt}`. Sibling of `_meta.ggui.fallback` but
|
|
445
|
+
* semantically distinct — the nudge carries NO action payload
|
|
446
|
+
* (the pipe holds the data); it's a pure wake-up signal telling
|
|
447
|
+
* the agent to `ggui_consume({stackItemId})`. Type guard
|
|
448
|
+
* `isGguiNudgeMeta` mirrors `isGguiFallbackMeta` so ggui-aware
|
|
449
|
+
* SDKs route deterministically. Additive — agnostic hosts ignore
|
|
450
|
+
* the field; free-form text alone is enough to act on.
|
|
451
|
+
*
|
|
452
|
+
* s3. **`ActiveConsumerRegistry` seam (`@ggui-ai/mcp-server-core`).**
|
|
453
|
+
* Optional in-process reference-count seam tracking which stack
|
|
454
|
+
* items currently have an in-flight `ggui_consume` long-poll.
|
|
455
|
+
* `consume.ts` wraps its long-poll in `enter`/`exit`;
|
|
456
|
+
* `submit-action.ts` queries `hasActive` after a successful pipe
|
|
457
|
+
* append. Reference impl `InMemoryActiveConsumerRegistry` ships;
|
|
458
|
+
* cloud/multi-pod deployments wire a Redis-backed adapter
|
|
459
|
+
* against the same interface. Mirrors the optional-seam pattern
|
|
460
|
+
* of `DrainAckNotifier` / `ObserverNotifier` / `ConsumeLogger`.
|
|
461
|
+
*
|
|
462
|
+
* --------------------------------------------------------------------
|
|
463
|
+
* Action drain guarantee:
|
|
464
|
+
*
|
|
465
|
+
* r1. **Drain-guarantee envelope + WS channel.** New optional
|
|
466
|
+
* `_meta.ggui.fallback` discriminator on `ui/message` envelopes
|
|
467
|
+
* (`reason: 'pipe_not_found' | 'timeout'`) so ggui-aware SDKs
|
|
468
|
+
* can route fallback gestures through their tool-result loop
|
|
469
|
+
* instead of injecting as a synthetic user prompt. New
|
|
470
|
+
* server→client `drain_ack` WS frame so the iframe-runtime can
|
|
471
|
+
* cancel its per-action 10s claim timer + dismiss the toast as
|
|
472
|
+
* `consumed` when an event drains via `ggui_consume`.
|
|
473
|
+
* Additive — agnostic hosts ignore the `_meta.ggui.fallback`
|
|
474
|
+
* field and the unrecognized WS frame (no protocol break).
|
|
475
|
+
*
|
|
476
|
+
* r2. **`ggui_runtime_claim_pending` wire.** New `audience: 'runtime'`
|
|
477
|
+
* tool the iframe calls from its per-action 10s timer to
|
|
478
|
+
* atomically pop a stale pipe entry when the host agent isn't
|
|
479
|
+
* draining. Same `consumeAndClear` primitive `ggui_consume` uses
|
|
480
|
+
* (one caller wins; race resolves at the server-side lock). The
|
|
481
|
+
* tool isn't agent-addressable; it surfaces on `/mcp` only and
|
|
482
|
+
* gates through the postMessage relay.
|
|
483
|
+
*
|
|
484
|
+
* r3. **Drain-guarantee telemetry.** New `action_consume_slow`
|
|
485
|
+
* info-event (submit → drain latency >2s) and
|
|
486
|
+
* `action_claim_timeout` warn-event (claim_pending fired because
|
|
487
|
+
* nobody drained for 10s). Operators derive the fallback-ratio
|
|
488
|
+
* protocol-adherence metric from these.
|
|
489
|
+
*
|
|
490
|
+
* --------------------------------------------------------------------
|
|
491
|
+
* Bootstrap-meta cleanup:
|
|
492
|
+
*
|
|
493
|
+
* q1. **`_meta.ggui.bootstrap.componentCode` retired.** The
|
|
494
|
+
* inline base64 ESM channel on the bootstrap envelope is deleted.
|
|
495
|
+
* Static-component bootstraps now travel exclusively via the
|
|
496
|
+
* content-addressable `codeUrl` channel composed by the push
|
|
497
|
+
* handler from its `codeStore` + `codeBaseUrl` deps. The
|
|
498
|
+
* `hasPushBootstrapMeta` discriminator collapses from
|
|
499
|
+
* `{wsUrl-with-token, componentCode, codeUrl, kind}` to
|
|
500
|
+
* `{wsUrl-with-token, codeUrl, kind}`. `StackItemBootstrapView`
|
|
501
|
+
* drops the field on the projection layer. `buildSelfContainedShell`
|
|
502
|
+
* accepts `{codeUrl, codeHash}` (or `systemKind`, or live-mode
|
|
503
|
+
* trio); throws when none are set. `/r/<shortCode>` mints
|
|
504
|
+
* codeUrl via codeStore.hashOf + put; falls through to live-mode
|
|
505
|
+
* when codeStore isn't wired. Iframe-runtime parser drops
|
|
506
|
+
* `componentCode` read + the inline-base64 `decodeBase64Utf8`
|
|
507
|
+
* helper. Saves 5-50KB per push.
|
|
508
|
+
*
|
|
509
|
+
* q2. **`_meta.ggui.bootstrap.adapters` retired.** The
|
|
510
|
+
* dormant dynamic-import-at-boot adapter loader is deleted from
|
|
511
|
+
* the wire surface. `GguiBootstrapMeta.adapters?` field removed;
|
|
512
|
+
* `parseAdapterSpecs` + `installAdapters` + the
|
|
513
|
+
* `globalThis.__ggui__.adapters` registry slot retired from
|
|
514
|
+
* iframe-runtime. An earlier change had already moved capability
|
|
515
|
+
* hooks to `@ggui-ai/gadgets`; this cleanup closes the
|
|
516
|
+
* dead surface. Native shells (`@ggui-ai/camera`,
|
|
517
|
+
* `@ggui-ai/ggui-react-native`) unchanged — they register
|
|
518
|
+
* adapters via their own `<GguiProvider>` React Context, never
|
|
519
|
+
* via bootstrap-meta.
|
|
520
|
+
*
|
|
521
|
+
* --------------------------------------------------------------------
|
|
522
|
+
* MCP Apps compliance & update fan-out:
|
|
523
|
+
*
|
|
524
|
+
* p1. **`ggui_stream` → `ggui_emit` rename (wire name + symbol prefix).**
|
|
525
|
+
* The send-from-agent-to-iframe tool was named `ggui_stream`, which
|
|
526
|
+
* reads as a noun referring to the stream object rather than the
|
|
527
|
+
* imperative act of emitting. `ggui_emit` reads correctly as an
|
|
528
|
+
* action and disambiguates from the wire field `streamSpec` (which
|
|
529
|
+
* keeps its name — it describes channels, not the act of emitting).
|
|
530
|
+
* Mechanical sweep across `@ggui-ai/protocol`, `@ggui-ai/mcp-server-handlers`,
|
|
531
|
+
* `@ggui-ai/mcp-server`, `@ggui-ai/ggui-cli`, `@ggui-ai/ggui-react-native`,
|
|
532
|
+
* `cloud/ggui-protocol-pod`, `cloud/generation-runtime`, and `cloud/cdk`:
|
|
533
|
+
*
|
|
534
|
+
* - Wire-name literal `'ggui_stream'` → `'ggui_emit'`
|
|
535
|
+
* - Pascal symbol prefix `GguiStream` → `GguiEmit` (covers
|
|
536
|
+
* `GguiEmitInput`, `GguiEmitOutput`, `GguiEmitHandlerDeps`,
|
|
537
|
+
* `createGguiEmitHandler`)
|
|
538
|
+
* - Test-d file rename `ggui-stream.test-d.ts` → `ggui-emit.test-d.ts`
|
|
539
|
+
*
|
|
540
|
+
* Untouched (NOT the tool name): `streamSpec`, `StreamChannelEntry`,
|
|
541
|
+
* `StreamEnvelope`, `SessionChannelServer`, `streamReplayOps`, and
|
|
542
|
+
* file paths like `session-mutations/stream.ts`. These describe the
|
|
543
|
+
* channel data plane, not the imperative emit action.
|
|
544
|
+
* Pre-launch breaking rename; no compatibility shim.
|
|
545
|
+
*
|
|
546
|
+
* p2. **`ggui_update` emits `_meta.ggui.bootstrap` on tool result.**
|
|
547
|
+
* Previously, the canonical re-apply path
|
|
548
|
+
* (MCP Apps `ui/notifications/tool-result` → host postMessage → iframe
|
|
549
|
+
* `_meta.ggui.bootstrap` consumer in `@ggui-ai/iframe-runtime`) had
|
|
550
|
+
* no envelope to deliver: `ggui_update`'s `resultMeta` was empty.
|
|
551
|
+
* Hosts that forwarded tool results couldn't trigger the spec-compliant
|
|
552
|
+
* live-update path. `createGguiUpdateHandler` now accepts the same
|
|
553
|
+
* bootstrap-emitting deps as `ggui_push` (`mintBootstrap`, `runtimeUrl`,
|
|
554
|
+
* `themeId`, `themeMode`, `themeProvider`, `appCallableTools`,
|
|
555
|
+
* `streamWebSocketLocalTools`) and emits `_meta.ggui.bootstrap`
|
|
556
|
+
* derived from the just-patched stack item via the shared
|
|
557
|
+
* `deriveStackItemBootstrapView` projection — byte-identical to
|
|
558
|
+
* `ggui_push`'s bootstrap envelope at the projection boundary.
|
|
559
|
+
* Strictly additive: prior consumers that ignored `resultMeta` are
|
|
560
|
+
* unaffected; hosts that DO forward `_meta.ggui.bootstrap` now
|
|
561
|
+
* receive the new envelope and can re-render without losing client
|
|
562
|
+
* state. Follows the MCP Apps tool-result forwarding rule.
|
|
563
|
+
* No wire-shape change; behavior change on `ggui_update`'s response
|
|
564
|
+
* `_meta` only.
|
|
565
|
+
*
|
|
566
|
+
* p3. **`/r/<shortCode>` mints the live trio (`wsUrl + token + expiresAt`)
|
|
567
|
+
* and inlines it in `__GGUI_BOOTSTRAP__`.** Previously the public
|
|
568
|
+
* render route minted no bootstrap token, so iframe-runtime's
|
|
569
|
+
* `subscribe.ts` rejected the envelope as "live-mode required" and
|
|
570
|
+
* never opened a WS — `props_update` and stream frames never reached
|
|
571
|
+
* the iframe even when the server fan-out fired. The route now calls
|
|
572
|
+
* `mintBootstrap(sessionId, appId)` when the minter is wired,
|
|
573
|
+
* rewrites localhost wsUrl to the request host (mirroring
|
|
574
|
+
* `/api/bootstrap/<shortCode>`), and threads the three fields into
|
|
575
|
+
* `buildSelfContainedShell`. `SelfContainedShellInputs` gains the
|
|
576
|
+
* three optional live-trio fields. Strictly additive — pre-existing
|
|
577
|
+
* static-only renders behave identically when no minter is wired.
|
|
578
|
+
*
|
|
579
|
+
* --------------------------------------------------------------------
|
|
580
|
+
* Multi-variant Blueprints — three-step handshake protocol:
|
|
581
|
+
*
|
|
582
|
+
* o. **Three-step handshake protocol.** `match` / `plan` /
|
|
583
|
+
* `hint` / `provisional` / `contractHash` (the previous
|
|
584
|
+
* top-level shape) DELETED from `handshakeOutputSchema`; replaced
|
|
585
|
+
* by a
|
|
586
|
+
* single `suggestion: HandshakeSuggestion` carrying a
|
|
587
|
+
* `origin: 'cache' | 'agent' | 'synth'` enum that routes the
|
|
588
|
+
* agent's next decision. `blueprintMeta` is ALWAYS present.
|
|
589
|
+
* `handshakeInputSchema` reshape: `contract?` + `hint?` ⇒ single
|
|
590
|
+
* `blueprintDraft: {contract, variance?, generator?}` (top-level
|
|
591
|
+
* `hint` field deleted in this slice). `handshakeOutputSchema`
|
|
592
|
+
* gains optional `alternatives: Blueprint[]` (top-N search misses
|
|
593
|
+
* below threshold so the agent can override into one).
|
|
594
|
+
* `pushInputSchema` reshape: `contract?` + `contractHash?` triad
|
|
595
|
+
* DELETED; replaced by a `decision` discriminator
|
|
596
|
+
* (`{kind: 'accept'} | {kind: 'override', blueprintDraft: {...}}`).
|
|
597
|
+
* `accept` reuses the provisional `blueprintId` from the
|
|
598
|
+
* handshake's `suggestion.blueprintMeta`; `override` mints a
|
|
599
|
+
* fresh `blueprintId` against a NEW draft. New types
|
|
600
|
+
* `BlueprintDraft`, `BlueprintMeta`, `SuggestionOrigin`,
|
|
601
|
+
* `HandshakeSuggestion`, `PushDecision`, `JsonPatch` ship in
|
|
602
|
+
* `@ggui-ai/protocol/types/handshake-suggestion` with zod mirrors
|
|
603
|
+
* in `@ggui-ai/protocol/schemas/handshake-suggestion`. A breaking
|
|
604
|
+
* reshape.
|
|
605
|
+
*
|
|
606
|
+
* --------------------------------------------------------------------
|
|
607
|
+
* Multi-variant Blueprints — operator-class blueprint tools:
|
|
608
|
+
*
|
|
609
|
+
* o. **Operator-class blueprint tool schemas** added to
|
|
610
|
+
* `@ggui-ai/protocol/schemas/ops-blueprint`. Four input/output
|
|
611
|
+
* pairs for the operator MCP tools:
|
|
612
|
+
*
|
|
613
|
+
* - `opsGenerateBlueprintInputSchema` /
|
|
614
|
+
* `opsGenerateBlueprintOutputSchema` — `ggui_ops_generate_blueprint`.
|
|
615
|
+
* Operator-authored blueprint generation, persona-tagged,
|
|
616
|
+
* optional `setAsOperatorDefault` flag.
|
|
617
|
+
* - `opsListBlueprintsInputSchema` /
|
|
618
|
+
* `opsListBlueprintsOutputSchema` — `ggui_ops_list_blueprints`.
|
|
619
|
+
* Indexed `(appId, contractHash)` list OR semantic search via
|
|
620
|
+
* `BlueprintSearch` when `intentKeywords` / `persona` is set.
|
|
621
|
+
* - `opsUpdateBlueprintInputSchema` /
|
|
622
|
+
* `opsUpdateBlueprintOutputSchema` — `ggui_ops_update_blueprint`.
|
|
623
|
+
* Mutable-field patch — `isOperatorDefault?: true` + partial
|
|
624
|
+
* `variance?`. Immutable fields (contractHash, appId,
|
|
625
|
+
* codeS3Url, codeHash, generator, createdAt, createdBy) are
|
|
626
|
+
* absent from the schema.
|
|
627
|
+
* - `opsDeleteBlueprintInputSchema` /
|
|
628
|
+
* `opsDeleteBlueprintOutputSchema` — `ggui_ops_delete_blueprint`.
|
|
629
|
+
* Idempotent — second delete returns `{deleted: true}`.
|
|
630
|
+
*
|
|
631
|
+
* All four tools tag `audience: ['ops']`; agents on `/mcp` do
|
|
632
|
+
* not see them. Strictly additive — existing handshake / push /
|
|
633
|
+
* list paths unchanged. No agent companion tool — agent
|
|
634
|
+
* blueprint authoring stays through the normal handshake → push
|
|
635
|
+
* flow.
|
|
636
|
+
*
|
|
637
|
+
* --------------------------------------------------------------------
|
|
638
|
+
* Multi-variant Blueprints — multi-axis blueprint search:
|
|
639
|
+
*
|
|
640
|
+
* n. **`Blueprint.contractEmbedding?: readonly number[]`** added —
|
|
641
|
+
* cached embedding vector written by `BlueprintStore.put` when an
|
|
642
|
+
* `EmbeddingProvider` is wired; read by `BlueprintSearch` on the
|
|
643
|
+
* embed axis (cosine similarity). Strictly additive — every
|
|
644
|
+
* existing `Blueprint` row deserializes with `contractEmbedding:
|
|
645
|
+
* undefined`, and the search layer's embed axis contributes zero
|
|
646
|
+
* in that case. Other axes (hash, structural, variance, intent)
|
|
647
|
+
* still carry the decision.
|
|
648
|
+
* nn. **`BlueprintSearchWeights` + `AppBlueprintSearchConfig`** types
|
|
649
|
+
* + zod schemas added. Per-app blueprint-search configuration
|
|
650
|
+
* lives on the `App` record in `@ggui-ai/mcp-server-core` as
|
|
651
|
+
* `App.blueprintSearchConfig?`; the wire shape stays in protocol
|
|
652
|
+
* so cloud-DDB + OSS in-memory adapters share one source of
|
|
653
|
+
* truth. Defaults applied at the impl layer
|
|
654
|
+
* (`DEFAULT_BLUEPRINT_SEARCH_WEIGHTS` / `THRESHOLD` / `TOP_K`
|
|
655
|
+
* in `@ggui-ai/mcp-server-core/blueprint-search`).
|
|
656
|
+
*
|
|
657
|
+
* --------------------------------------------------------------------
|
|
658
|
+
* Multi-variant Blueprints — the `Blueprint` record:
|
|
659
|
+
*
|
|
660
|
+
* m. **`Blueprint` type + zod schema** added to `@ggui-ai/protocol`.
|
|
661
|
+
* Represents the variant-unit between a `DataContract` and the
|
|
662
|
+
* generated UI code that renders it. Multiple `Blueprint` rows
|
|
663
|
+
* MAY share `(appId, contractHash)`; they differ on `generator`
|
|
664
|
+
* and/or `variance`. Fields: `blueprintId`, `contractHash`,
|
|
665
|
+
* `appId`, optional `codeS3Url + codeHash` (cached code pointer),
|
|
666
|
+
* `generator` (slug), optional `validatorScore`, `variance`
|
|
667
|
+
* (`{persona?, context?, seedPrompt?}`), optional
|
|
668
|
+
* `isOperatorDefault: true`, `createdAt`, `createdBy`
|
|
669
|
+
* ('agent' | 'operator'), and a read-cache copy of `contract`.
|
|
670
|
+
* Strictly additive — no fields removed; no consumer sees a
|
|
671
|
+
* schema-incompatible change. Consumers using `BlueprintProvider`
|
|
672
|
+
* see no break.
|
|
673
|
+
*
|
|
674
|
+
* --------------------------------------------------------------------
|
|
675
|
+
* Wire-shape v2 — contract vocabulary reshape:
|
|
676
|
+
*
|
|
677
|
+
* 0. `broadcast` field deleted; channel data sources move inline as
|
|
678
|
+
* `streamSpec[ch].source = { tool, args? }`. Server-side
|
|
679
|
+
* `runBroadcastLoop` removed entirely (no replacement on server;
|
|
680
|
+
* transport now runtime-negotiated by `@ggui-ai/wire`).
|
|
681
|
+
*
|
|
682
|
+
* 00. `DataContract.props` → `DataContract.propsSpec` rename. Aligns the
|
|
683
|
+
* contract-level declaration with the other three typed surfaces
|
|
684
|
+
* (`actionSpec` / `streamSpec` / `contextSpec`). Wire-side `props`
|
|
685
|
+
* field on `ggui_push.input` / `ggui_update.input` stays as `props`
|
|
686
|
+
* — those carry values, not the spec.
|
|
687
|
+
*
|
|
688
|
+
* 000. `DataContract.wiredTools` → `DataContract.agentTools` rename +
|
|
689
|
+
* entry restructure: drop `label`, rename `requestSchema`/`responseSchema`
|
|
690
|
+
* → `inputSchema`/`outputSchema` (MCP alignment), rename
|
|
691
|
+
* `example: {request, response}` → `example: {input, output}`, add
|
|
692
|
+
* `usage?: string` field. All `WiredTool*` types rename to `AgentTool*`.
|
|
693
|
+
* Hook name `useWiredTool` retired in a follow-up commit (paired
|
|
694
|
+
* with kind removal). `PushStory.wiredTools?: string[]` shorthand
|
|
695
|
+
* input ALSO renamed to `agentTools` in the same follow-up.
|
|
696
|
+
*
|
|
697
|
+
* 000a. `DataContract.agentTools` → `DataContract.agentCapabilities`
|
|
698
|
+
* rename. The catalog parent is renamed for symmetry with
|
|
699
|
+
* `clientCapabilities` — both are capability declarations grouped
|
|
700
|
+
* under a `*Capabilities` parent so the protocol's capability
|
|
701
|
+
* namespace reads as `{agent,client}Capabilities`. Inner map stays
|
|
702
|
+
* as `.tools` (e.g., `agentCapabilities.tools.fetch_quote`). Type
|
|
703
|
+
* alias `AgentToolSpec` → `AgentCapabilitiesSpec`; `AgentToolEntry`
|
|
704
|
+
* unchanged. Catalog-level `description?` field dropped (vestigial,
|
|
705
|
+
* no consumer). Linter rule messages + paths updated. `PushStory`
|
|
706
|
+
* shorthand input `agentTools: string[]` is left under its current
|
|
707
|
+
* name (retired later alongside PushStory itself).
|
|
708
|
+
*
|
|
709
|
+
* 000b. `DataContract.clientCapabilities.capabilities` →
|
|
710
|
+
* `DataContract.clientCapabilities.gadgets` rename + reshape.
|
|
711
|
+
* Inner map renamed for vocabulary parity with the agent side
|
|
712
|
+
* (`agentCapabilities.tools` vs `clientCapabilities.gadgets`).
|
|
713
|
+
* Per-entry type renamed: `ClientCapabilityEntry` →
|
|
714
|
+
* `GadgetDescriptor`; spec renamed: `ClientCapabilitySpec` →
|
|
715
|
+
* `ClientCapabilitiesSpec`. Hook generic renamed:
|
|
716
|
+
* `ClientCapabilityHook` → `GadgetHook`; lifecycle types
|
|
717
|
+
* `CapabilityStatus` → `GadgetStatus`, `CapabilityError` →
|
|
718
|
+
* `GadgetError`. Catalog-level `description?` dropped (vestigial,
|
|
719
|
+
* no consumer). New optional `example?: JsonValue` on
|
|
720
|
+
* `GadgetDescriptor` parallels `AgentToolEntry.example` so the
|
|
721
|
+
* agent has a concrete shape to reference for unfamiliar libraries.
|
|
722
|
+
* Hygiene rule codes renamed: `LINT_CAP_*` → `LINT_LIB_*`.
|
|
723
|
+
* Helper `getClientCapabilityNames` → `getGadgetNames` in
|
|
724
|
+
* `@ggui-ai/ui-gen/evaluation/axis-checks`. The
|
|
725
|
+
* `@ggui-ai/client-tools` package literal is renamed separately
|
|
726
|
+
* (see entry 000c) alongside the workspace directory move.
|
|
727
|
+
*
|
|
728
|
+
* 000e. Per-app library discovery. Three changes ship together
|
|
729
|
+
* (the data-plane half of the per-app library story; UX +
|
|
730
|
+
* renderer follow up):
|
|
731
|
+
*
|
|
732
|
+
* a. **App model** — the OSS `@ggui-ai/mcp-server-core` adds an
|
|
733
|
+
* `App` type with `gadgets: readonly GadgetDescriptor[]`
|
|
734
|
+
* and an `AppMetadataStore` seam. Reference `InMemoryAppMetadataStore` seeds
|
|
735
|
+
* every registered app with `STDLIB_GADGETS`.
|
|
736
|
+
* b. **Cloud DDB adapter** — `AppRecord.gadgets` added.
|
|
737
|
+
* `getApp` applies the **default-on-read** pattern at the row
|
|
738
|
+
* projection site so existing rows without the column survive.
|
|
739
|
+
* c. **New tool `ggui_list_gadgets`** — audience `['agent']`,
|
|
740
|
+
* bare `ggui_*` prefix (NOT `ggui_protocol_*` — fetches runtime,
|
|
741
|
+
* per-app data, not static spec). Input `{appId?: string}` —
|
|
742
|
+
* defaults to `ctx.appId`; explicit mismatch throws
|
|
743
|
+
* `AppAccessDeniedError` (code `app_access_denied`). App-not-found
|
|
744
|
+
* falls back to `STDLIB_GADGETS` (sandbox-app permitted-
|
|
745
|
+
* error path).
|
|
746
|
+
*
|
|
747
|
+
* Operator console UX to mutate per-app lists and renderer support for
|
|
748
|
+
* serving operator-added custom libraries are deferred to later
|
|
749
|
+
* work; initially every app's `gadgets` == stdlib by default.
|
|
750
|
+
*
|
|
751
|
+
* 000g. Generation triad vocabulary sweep. `@ggui-ai/ui-gen`'s
|
|
752
|
+
* HOW / WHAT / CHECK surfaces all speak the renamed contract
|
|
753
|
+
* paths (`agentCapabilities.tools`, `clientCapabilities.gadgets`).
|
|
754
|
+
*
|
|
755
|
+
* a. **HOW prompts** (`harness/prompts.ts`) — every reference to
|
|
756
|
+
* the catalog now uses `agentCapabilities.tools` /
|
|
757
|
+
* `clientCapabilities.gadgets`; pre-rename hook identifiers
|
|
758
|
+
* (`useWiredTool` / `useAgentTool` / `useClientTool`) are
|
|
759
|
+
* described as retired rather than mentioned by name.
|
|
760
|
+
* b. **WHAT classifier** (`classifier/inspect.ts`) — the inner
|
|
761
|
+
* `clientCapabilities.capabilities` read path was stale; now
|
|
762
|
+
* reads `clientCapabilities.gadgets` to match the current
|
|
763
|
+
* wire shape.
|
|
764
|
+
* c. **CHECK Tier 0** (`check/run-tier0.ts`) — `wire_undeclared`
|
|
765
|
+
* remediation messages no longer reference the retired
|
|
766
|
+
* `story.contract`; they name the flat `contract` field on
|
|
767
|
+
* `ggui_push`.
|
|
768
|
+
* d. **CHECK evaluator** (`evaluation/llm-evaluator.ts`,
|
|
769
|
+
* `evaluation/types-public.ts`) — eval criteria descriptions
|
|
770
|
+
* use `agentCapabilities.tools` and `clientCapabilities.gadgets`.
|
|
771
|
+
* e. **Anti-pattern grep gate** (`evaluation/axis-checks/checks/
|
|
772
|
+
* tooling.ts`) — `RETIRED_IDENTIFIERS` extended with
|
|
773
|
+
* `useAgentTool`, `callWiredTool`, `agentTools` (top-level
|
|
774
|
+
* field), `clientCapabilities.capabilities`,
|
|
775
|
+
* `@ggui-ai/client-tools` (package), `PushStory`,
|
|
776
|
+
* `pushStorySchema`, `story.adapters`, `declaredAdapters`,
|
|
777
|
+
* `assertAdaptersDeclared`, `HandshakeStoredStory`, and
|
|
778
|
+
* `record.story`. Each emits one issue per detection so the
|
|
779
|
+
* LLM rewrites toward the current shape before evaluation
|
|
780
|
+
* completes.
|
|
781
|
+
*
|
|
782
|
+
* 000h. Bench corpus rebuild. The static bench corpora carried
|
|
783
|
+
* example contracts and prose docstrings on the old catalog
|
|
784
|
+
* shape; this sweep updates them so every fixture and comment
|
|
785
|
+
* reads as a valid contract under the new wire shape.
|
|
786
|
+
*
|
|
787
|
+
* a. **Negotiator synth corpus** (`packages/negotiator/src/
|
|
788
|
+
* synth-bench/corpus.ts`) — docstring path `agentTools[*]` /
|
|
789
|
+
* `agentTools.tools[*]` → `agentCapabilities.tools[*]`.
|
|
790
|
+
* Fixture data already carried the new shape; only the prose
|
|
791
|
+
* drifted.
|
|
792
|
+
* b. **Multi-SDK gen fixtures** (`packages/benchmark/src/multi-
|
|
793
|
+
* sdk/commits.ts` + `fixtures/{activity-feed,inbox-triage,
|
|
794
|
+
* place-search,uber-ride}.fixture.ts`) — `agentCapabilities.
|
|
795
|
+
* tools` entries reshaped: drop `label`,
|
|
796
|
+
* `requestSchema`/`responseSchema` → `inputSchema`/
|
|
797
|
+
* `outputSchema`, `example: {request, response}` →
|
|
798
|
+
* `example: {input, output}`. `clientCapabilities.
|
|
799
|
+
* capabilities` → `clientCapabilities.gadgets`.
|
|
800
|
+
* c. **Floor-test contract** (`packages/benchmark/src/multi-sdk/
|
|
801
|
+
* floor.test.ts`) — sample `{ props: { properties: {} } }`
|
|
802
|
+
* → `{ propsSpec: { properties: {} } }` per the
|
|
803
|
+
* DataContract.props → propsSpec rename.
|
|
804
|
+
*
|
|
805
|
+
* 000f. Permissions-Policy derivation from
|
|
806
|
+
* `DataContract.clientCapabilities.gadgets[*].permission`.
|
|
807
|
+
* Replaces the previous App-level `declaredAdapters` runtime
|
|
808
|
+
* gate with per-contract derivation. `StackItem` gains an
|
|
809
|
+
* optional `clientCapabilities?: ClientCapabilitiesSpec` field
|
|
810
|
+
* so push commit-time persists the catalog onto the active stack
|
|
811
|
+
* item. `StackItemBootstrapView.permissionsPolicy?: readonly
|
|
812
|
+
* string[]` projects the union-deduplicated directive list every
|
|
813
|
+
* transport reads — public-render `/r/<shortCode>` emits a
|
|
814
|
+
* `Permissions-Policy` HTTP response header (`<directive>=(self)`
|
|
815
|
+
* per W3C Permissions Policy), MCP-Apps `_meta.ui.permissions`
|
|
816
|
+
* forwards into the iframe host's `allow=""` attribute, and the
|
|
817
|
+
* inline bootstrap mirrors `permissionsPolicy` so the
|
|
818
|
+
* iframe-runtime can surface the gate set to in-iframe consumers.
|
|
819
|
+
* Browser-enforced gates flow from the parent transport; the
|
|
820
|
+
* iframe-runtime itself cannot mutate Permissions-Policy
|
|
821
|
+
* post-load. `GguiBootstrapMeta` gains an optional matching
|
|
822
|
+
* `permissionsPolicy?: readonly string[]` field;
|
|
823
|
+
* `validateGguiBootstrapMeta` validates the array shape.
|
|
824
|
+
* Boilerplate generator (`@ggui-ai/ui-gen`) reads
|
|
825
|
+
* `clientCapabilities.gadgets` and emits
|
|
826
|
+
* one combined `import { hookA, hookB } from '<pkg>'` per
|
|
827
|
+
* declared package, alphabetically sorted within each group for
|
|
828
|
+
* stable diffs. The intermediate inner key
|
|
829
|
+
* `clientCapabilities.capabilities` is fully retired in the
|
|
830
|
+
* generator surface.
|
|
831
|
+
*
|
|
832
|
+
* 000d. Handshake input redesigned to flat fields + hint group.
|
|
833
|
+
* `handshakeInputSchema` was `{sessionId, story: {intent, data?, sourceTools?,
|
|
834
|
+
* agentTools?, prompt?, context?, contract?}, forceCreate?}`. The story
|
|
835
|
+
* nesting is dismantled: `intent` and `contract` are promoted to top-level
|
|
836
|
+
* on the input; `data`/`prompt`/`context`/`availableAgentTools`/`sourceTools`
|
|
837
|
+
* move under a labeled `hint?: HandshakeHint` group (cold-path synth signal).
|
|
838
|
+
* `agentTools` rename → `availableAgentTools` clarifies role (catalog seed,
|
|
839
|
+
* not authority). `PushStory` interface + `pushStorySchema` Zod retired
|
|
840
|
+
* entirely (no consumer left). Vestigial sub-schemas `pushSessionSchema`/
|
|
841
|
+
* `pushRenderingSchema`/`pushInfraSchema`/`pushShortcutsSchema` + their
|
|
842
|
+
* TS interfaces (`PushSession`/`PushRendering`/`PushInfra`/`PushShortcuts`)
|
|
843
|
+
* also dropped — dead code (no consumer outside sync-check).
|
|
844
|
+
* OSS handler's internal `HandshakeStoredStory` → `HandshakeStoredInput`
|
|
845
|
+
* reshape: `{intent, contract?, forceCreate?, hint?}` (drops legacy
|
|
846
|
+
* `context`/`schema`/`adapters` passthrough plumbing — schema lives in
|
|
847
|
+
* `contract.propsSpec`; adapters retire alongside the
|
|
848
|
+
* `declaredAdapters` deployment-policy field, replaced by per-app
|
|
849
|
+
* `gadgets` permissions). Negotiator
|
|
850
|
+
* `decide({story, sessionId, ctx})` → `decide({intent, contract?, hint?,
|
|
851
|
+
* sessionId, ctx})`. Push consumers (`push.ts`, `update.ts`) read
|
|
852
|
+
* `record.input.*` not `record.story.*`. `provisional-preview.ts` field
|
|
853
|
+
* `story` → `input` to match.
|
|
854
|
+
*
|
|
855
|
+
* 000g. Negotiator synth refactor. Synth now reads + writes the
|
|
856
|
+
* renamed catalog paths and threads per-app library context
|
|
857
|
+
* through.
|
|
858
|
+
*
|
|
859
|
+
* a. **Synth prompt + DECISION_TOOL JSON-schema** flipped from
|
|
860
|
+
* `clientCapabilities.capabilities` → `clientCapabilities.gadgets`.
|
|
861
|
+
* Inner field shape unchanged ({hook, package?, permission?,
|
|
862
|
+
* usage?}); only the parent key renamed. Worked examples in the
|
|
863
|
+
* synth system prompt match.
|
|
864
|
+
* b. **`parseToolInput` + `buildContract`** now extract
|
|
865
|
+
* `agentCapabilities.tools` AND `clientCapabilities.gadgets`
|
|
866
|
+
* from the LLM tool output and populate them on the assembled
|
|
867
|
+
* contract. Previously both catalogs were dropped silently —
|
|
868
|
+
* the LLM authored entries the contract never carried.
|
|
869
|
+
* c. **`NegotiatorInput.agent.gadgets?: readonly GadgetDescriptor[]`**
|
|
870
|
+
* + **`NegotiatorDecisionInput.gadgets?`**. The
|
|
871
|
+
* handshake handler reads `app.gadgets` via the bound
|
|
872
|
+
* `AppMetadataStore` and threads the catalog to the
|
|
873
|
+
* negotiator. The decision-prompt user message gains a
|
|
874
|
+
* "Client-side libraries available" section listing each
|
|
875
|
+
* hook + permission so the LLM authors valid bindings.
|
|
876
|
+
* d. **`mergeAgentTools` → `mergeAgentCapabilities`** rename.
|
|
877
|
+
* Behavior unchanged.
|
|
878
|
+
* e. **`mergeGadgets(contract, appGadgets)`** new
|
|
879
|
+
* function — enriches partial LLM-emitted gadget entries
|
|
880
|
+
* (missing package/permission) from the app's canonical
|
|
881
|
+
* catalog. Bindings whose `hook` doesn't match any app entry
|
|
882
|
+
* are preserved verbatim (third-party packages outside the
|
|
883
|
+
* seed). Wires into all three return paths (structured-output
|
|
884
|
+
* success, regex JSON fallback, buildFallbackDecision).
|
|
885
|
+
* f. **HandshakeNegotiator.decide** interface gains optional
|
|
886
|
+
* `gadgets`. OSS llm-backed-negotiator + cloud pod's
|
|
887
|
+
* Bedrock negotiator forward to `negotiate(input.agent.gadgets)`.
|
|
888
|
+
* g. **GguiHandshakeHandlerDeps.appMetadataStore** new optional field.
|
|
889
|
+
* OSS `createGguiServer` resolves it from `deps.handshake.appMetadataStore`
|
|
890
|
+
* or top-level `deps.appMetadataStore` (same store the
|
|
891
|
+
* `ggui_list_gadgets` tool uses).
|
|
892
|
+
* h. **Anti-pattern list** extended in synth + decision prompts
|
|
893
|
+
* with retired identifiers — `clientCapabilities.capabilities`,
|
|
894
|
+
* `PushStory`/`story.*`, `@ggui-ai/client-tools`,
|
|
895
|
+
* `story.adapters`/`declaredAdapters`, `useAgentTool`. Prevents
|
|
896
|
+
* LLM regression on older training data.
|
|
897
|
+
*
|
|
898
|
+
* 000c. `@ggui-ai/client-tools` → `@ggui-ai/gadgets` package
|
|
899
|
+
* rename. The workspace directory moves from `packages/client-tools`
|
|
900
|
+
* to `packages/gadgets`; the published package name
|
|
901
|
+
* changes from `@ggui-ai/client-tools` to `@ggui-ai/gadgets`.
|
|
902
|
+
* All import strings across the workspace flip simultaneously
|
|
903
|
+
* (negotiator synth prompt, ui-gen boilerplate + system prompt +
|
|
904
|
+
* eval axis checks, design rewrite-imports, ggui-react test
|
|
905
|
+
* fixtures, mcp-server-handlers blueprint docs, hygiene-rules
|
|
906
|
+
* `DEFAULT_GADGET_PACKAGE` literal). The exported hook surface
|
|
907
|
+
* (`useGeolocation`, `useClipboardWrite`, `useClipboardPaste`,
|
|
908
|
+
* `useNotifications`, `useFilePicker`, `useMicrophone`,
|
|
909
|
+
* `useCamera`) is unchanged. Package version stays at 0.1.0.
|
|
910
|
+
*
|
|
911
|
+
* 00000000. Protocol-level schema-compat invariant in
|
|
912
|
+
* `@ggui-ai/protocol/validation/schema-compat-invariants`:
|
|
913
|
+
* `CTR_SCHEMA_INCOMPAT` validates `actionSpec[*].schema` is a
|
|
914
|
+
* subset of the referenced `agentCapabilities.tools[*].inputSchema`,
|
|
915
|
+
* and `streamSpec[*].schema` is a superset of the referenced
|
|
916
|
+
* `agentCapabilities.tools[*].outputSchema`. Compares against the
|
|
917
|
+
* contract's OWN agentCapabilities catalog (no runtime tool registry,
|
|
918
|
+
* no zod conversion) — author-visible bug class. Distinct from
|
|
919
|
+
* and complementary to the server-level F4 check
|
|
920
|
+
* (`checkStackItemSchemaCompat` in `@ggui-ai/mcp-server`),
|
|
921
|
+
* which compares the same action/stream schemas against the
|
|
922
|
+
* live tool registry's zod schemas. Folded into
|
|
923
|
+
* `validateContractStructure` and wired into the push handler
|
|
924
|
+
* via `assertSchemaCompat(contract)`.
|
|
925
|
+
*
|
|
926
|
+
* 0000000. Name-invariant rules in
|
|
927
|
+
* `@ggui-ai/protocol/validation/name-invariants`:
|
|
928
|
+
* `CTR_DUP_NAME` (no name collision across `actionSpec` /
|
|
929
|
+
* `streamSpec` / `contextSpec` keys — boilerplate generator emits
|
|
930
|
+
* identifiers from these; a collision shadows or compiles
|
|
931
|
+
* ambiguously) + `CTR_RESERVED_NAME` (no `_ggui:`-prefixed keys on
|
|
932
|
+
* `actionSpec` or `contextSpec` — the streamSpec equivalent
|
|
933
|
+
* already fires in `validateContractStructure`; this extends the
|
|
934
|
+
* rule uniformly to the other two inbound spec maps). Both folded
|
|
935
|
+
* into `validateContractStructure` and into the push handler via
|
|
936
|
+
* `assertNameInvariants(contract)`, which throws
|
|
937
|
+
* `NameInvariantError` listing every offending name. Companion
|
|
938
|
+
* to the `CTR_REF_*` cross-reference rules in
|
|
939
|
+
* `@ggui-ai/protocol/validation/cross-references`.
|
|
940
|
+
*
|
|
941
|
+
* 000000. Cross-reference invariants in `@ggui-ai/protocol/validation/cross-references`:
|
|
942
|
+
* `CTR_REF_NEXT_STEP` (validates `actionSpec[*].nextStep` resolves
|
|
943
|
+
* to `agentCapabilities.tools[*]`) + `CTR_REF_STREAM_SOURCE` (validates
|
|
944
|
+
* `streamSpec[*].source.tool` resolves to `agentCapabilities.tools[*]`).
|
|
945
|
+
* Both wired into `validateContractStructure` (so blueprint-registry +
|
|
946
|
+
* future structural-validator callers get cross-refs free) and into
|
|
947
|
+
* the push handler via `assertCrossReferences(contract)`, which
|
|
948
|
+
* throws `CrossReferenceError` listing every dangling reference in
|
|
949
|
+
* one pass. Separate from `assertActionRoutingTargets` (which checks
|
|
950
|
+
* `nextStep` against the SERVER's `knownTools` registry); both run
|
|
951
|
+
* at push and surface author-recoverable failures before any state
|
|
952
|
+
* mutation.
|
|
953
|
+
* No migration doc — purely additive enforcement of invariants
|
|
954
|
+
* already documented in the type-system (`StreamChannelEntry.source`,
|
|
955
|
+
* `ActionEntry.nextStep` reference `CTR_REF_*` linter rules in their
|
|
956
|
+
* docstrings; this commit ships the linter behind those mentions).
|
|
957
|
+
*
|
|
958
|
+
* 00000. `ActionEntry.dispatch` discriminated-union collapsed to a
|
|
959
|
+
* single shape with an optional `nextStep?: string` hint. All
|
|
960
|
+
* actions are agent-routed by default; the pre-rename
|
|
961
|
+
* `kind: 'tool'` synchronous-tool dispatch path is retired (it
|
|
962
|
+
* silently bypassed the agent's reasoning loop, which conflicted
|
|
963
|
+
* with the actions-vs-context placement rule). Removed:
|
|
964
|
+
* `ActionDispatch` type, `dispatchTo` helper namespace,
|
|
965
|
+
* `actionDispatchSchema` zod variant. Renamed: `dispatch.tool` →
|
|
966
|
+
* `nextStep`, `dispatch.intendedTool` → `nextStep` (the two collapse
|
|
967
|
+
* into one optional advisory hint). The cross-ref linter
|
|
968
|
+
* (`CTR_REF_NEXT_STEP`) enforces that `nextStep` resolves to a
|
|
969
|
+
* declared `agentCapabilities.tools[*]` key on the same
|
|
970
|
+
* contract. `UnknownActionToolError` retained but reframed
|
|
971
|
+
* to fire on `nextStep` resolution rather than `dispatch.tool`.
|
|
972
|
+
*
|
|
973
|
+
* 0000. `DataContract.clientTools` → `DataContract.clientCapabilities`
|
|
974
|
+
* complete reframe. The pre-rename `ClientToolEntry` carried
|
|
975
|
+
* `argsSchema`/`responseSchema`/`example` as if the agent invoked
|
|
976
|
+
* the tool RPC-style; that was inverted — browser-capability hooks
|
|
977
|
+
* are owned by the UI, fire from the user side, and only become
|
|
978
|
+
* agent-observable when the UI threads their value into a
|
|
979
|
+
* `contextSpec` slot or an `actionSpec` payload. New entry shape:
|
|
980
|
+
* `{description?, usage?, hook, package?, permission?, required?}`
|
|
981
|
+
* — pure declaration, no input/output, no example. The catalog map
|
|
982
|
+
* key rename `tools` → `capabilities` mirrors the conceptual shift.
|
|
983
|
+
* `ClientCapabilityHook<TOutput, TOptions=void>` generic + `CapabilityStatus`
|
|
984
|
+
* + `CapabilityError` ship in `@ggui-ai/protocol`'s
|
|
985
|
+
* `types/gadget.ts` to lock the runtime contract every
|
|
986
|
+
* hook in the planned `@ggui-ai/gadgets` v1 catalog MUST
|
|
987
|
+
* satisfy. `useClientTool` React hook + `registerClientTool` /
|
|
988
|
+
* `WireClientToolArgs` / `WireClientToolResult` types + iframe
|
|
989
|
+
* `tool:<name>` channel RPC path are deleted — no RPC channel
|
|
990
|
+
* surface remains.
|
|
991
|
+
*
|
|
992
|
+
* --------------------------------------------------------------------
|
|
993
|
+
* Four wire-shape changes:
|
|
994
|
+
*
|
|
995
|
+
* 1. `ActionEntry` discriminated-union dispatch: collapsed
|
|
996
|
+
* `{tool, mode}` into `dispatch: {kind: 'tool', tool} | {kind:
|
|
997
|
+
* 'agent', intendedTool?}`. Renamed `mode: 'host-routed'` →
|
|
998
|
+
* `kind: 'agent'` for vendor-neutrality. Deleted
|
|
999
|
+
* `OrphanActionError` + `AmbiguousActionRoutingError`
|
|
1000
|
+
* (structurally impossible).
|
|
1001
|
+
*
|
|
1002
|
+
* 2. F4 schema-compat fail-fast at push validation: agent-recoverable
|
|
1003
|
+
* schema violations throw `SchemaCompatError` at push time instead
|
|
1004
|
+
* of silently committing a fallback error stack item. Eliminates
|
|
1005
|
+
* the "stuck on Generating UI…" trap.
|
|
1006
|
+
*
|
|
1007
|
+
* 3. `ggui_new_session` introduced + `sessionId` REQUIRED on
|
|
1008
|
+
* `ggui_handshake`: server-mints / agent-threads (SEP-2567 aligned).
|
|
1009
|
+
* Optional `seed` enables deterministic idempotent derivation.
|
|
1010
|
+
* Three-tool flow: `ggui_new_session` → `ggui_handshake` → `ggui_push`.
|
|
1011
|
+
*
|
|
1012
|
+
* 4. `pageId` → `stackItemId` rename: mechanical 1:1 sweep across
|
|
1013
|
+
* protocol/handlers/server/SDKs/cloud. `getSessionByPageId` →
|
|
1014
|
+
* `getSessionByStackItemId`; `PageNotFoundError` →
|
|
1015
|
+
* `StackItemNotFoundError`; `targetPageId` → `targetStackItemId`.
|
|
1016
|
+
*
|
|
1017
|
+
* --------------------------------------------------------------------
|
|
1018
|
+
* Marketplace registry:
|
|
1019
|
+
*
|
|
1020
|
+
* 1. `GadgetDescriptor.bundleSri?: string` — additive optional
|
|
1021
|
+
* field carrying the registry-emitted SHA-384 SRI hash of the
|
|
1022
|
+
* bundle bytes (`sha384-<base64>` format, validated via
|
|
1023
|
+
* `BUNDLE_SRI_RE`). When present, the iframe-runtime emits the
|
|
1024
|
+
* bundle import as a `<link rel="modulepreload" integrity>`
|
|
1025
|
+
* element so a CDN compromise can't silently swap the bundle.
|
|
1026
|
+
* Both `gadgetDescriptorSchema` (wire) and
|
|
1027
|
+
* `strictGadgetDescriptorSchema` (registry) carry the
|
|
1028
|
+
* same regex. Authors do NOT set this manually; registry
|
|
1029
|
+
* install writes it.
|
|
1030
|
+
*
|
|
1031
|
+
* 2. Marketplace registry HTTP API (`/search` / `/pkg` /
|
|
1032
|
+
* `/publish` / `/conformance/check`). Off the WS wire surface
|
|
1033
|
+
* — a distinct HTTP service, not a wire-protocol surface, and
|
|
1034
|
+
* therefore not a conformance-kit bump.
|
|
1035
|
+
*
|
|
1036
|
+
* --------------------------------------------------------------------
|
|
1037
|
+
* Canvas mode (additive):
|
|
1038
|
+
*
|
|
1039
|
+
* 1. `GguiBootstrapMeta.canvasMode?: boolean` — discriminator for
|
|
1040
|
+
* the iframe-runtime canvas-mount path. When `true`, the runtime
|
|
1041
|
+
* mounts a session-scoped `CanvasShell` (one iframe for the
|
|
1042
|
+
* whole session) instead of the legacy per-stack-item iframe.
|
|
1043
|
+
* Mutually exclusive with `stackItemId`. Producers SHOULD reject
|
|
1044
|
+
* bootstraps with both fields set; the protocol does not
|
|
1045
|
+
* require them to. Absent / `false` ⇒ existing inline behavior.
|
|
1046
|
+
*
|
|
1047
|
+
* 2. `_ggui:lifecycle` reserved channel + `CanvasLifecyclePayload`
|
|
1048
|
+
* discriminated union. Server publishes lifecycle envelopes
|
|
1049
|
+
* (`handshake_started` / `handshake_completed` /
|
|
1050
|
+
* `push_started` / `consume_polling`) on the reserved channel;
|
|
1051
|
+
* the canvas animator pill state machine advances on each kind.
|
|
1052
|
+
* Wire shape lives in `@ggui-ai/protocol/types/canvas-lifecycle`;
|
|
1053
|
+
* structural validator registered in `BUILTIN_RESERVED_VALIDATORS`.
|
|
1054
|
+
*
|
|
1055
|
+
* 3. `canvas_navigated` WS message type (Client → Server) with
|
|
1056
|
+
* `CanvasNavigatedPayload`. Emitted by the canvas iframe when
|
|
1057
|
+
* the user back-navigates; the server updates
|
|
1058
|
+
* `Session.activeStackItemId` and MAY abort in-flight cold-gen
|
|
1059
|
+
* for the popped item. Payload carries `sessionId` +
|
|
1060
|
+
* `previousActiveItemId` + `activeItemId` (no `appId` — the
|
|
1061
|
+
* subscriber binding is the authoritative scope).
|
|
1062
|
+
*
|
|
1063
|
+
* 4. `host_context_observed` WS message type (Client → Server) with
|
|
1064
|
+
* `HostContextObservedPayload`. The iframe echoes the
|
|
1065
|
+
* `McpUiHostContext` it received from `ui/initialize` so the
|
|
1066
|
+
* server can persist a `HostContextProjection` on the session.
|
|
1067
|
+
* Updates flow on every `host-context-changed` notification so
|
|
1068
|
+
* the projection stays current for canvas display-mode policy.
|
|
1069
|
+
*
|
|
1070
|
+
* --------------------------------------------------------------------
|
|
1071
|
+
* Schema hardening:
|
|
1072
|
+
*
|
|
1073
|
+
* 1. `StackItem.adapters?: AdapterType[]` — DELETED. Grant model now
|
|
1074
|
+
* lives entirely on `clientCapabilities.gadgets[*].permission`
|
|
1075
|
+
* which projects to the iframe's `Permissions-Policy` header.
|
|
1076
|
+
* `AdapterType` / `ADAPTER_TYPES` / `AdapterTypeSchema` removed
|
|
1077
|
+
* from `@ggui-ai/protocol`. SDK + cloud-pod call sites that
|
|
1078
|
+
* threaded `adapters: []` now drop the field entirely. The
|
|
1079
|
+
* runtime `AdapterPermissions` permission-state interface +
|
|
1080
|
+
* `AdapterRegistry` impl slot stay (orthogonal to the grant model
|
|
1081
|
+
* retired here).
|
|
1082
|
+
*
|
|
1083
|
+
* 2. `ggui.json#registryAuth` — DELETED. Source-controlled config no
|
|
1084
|
+
* longer carries Cognito pool ids. The publish CLI reads from
|
|
1085
|
+
* env exclusively: canonical `GGUI_REGISTRY_COGNITO_POOL_ID` /
|
|
1086
|
+
* `GGUI_REGISTRY_COGNITO_APP_CLIENT_ID`, legacy-fallback
|
|
1087
|
+
* `GGUI_COGNITO_POOL_ID` / `GGUI_COGNITO_APP_CLIENT_ID`. No
|
|
1088
|
+
* filesystem walk-up for ggui.json#registryAuth. Per-project
|
|
1089
|
+
* pinning still possible via `.envrc` / shell wrapper.
|
|
1090
|
+
*
|
|
1091
|
+
* 3. Blueprint name regex unified under gadget rules.
|
|
1092
|
+
* `BLUEPRINT_NAME_RE` is retired; both gadgets and blueprints now
|
|
1093
|
+
* share `GADGET_NAME_RE` (`/^[a-z][a-z0-9-]{1,62}[a-z0-9]$/` —
|
|
1094
|
+
* kebab-case, 2–64 chars, no underscores, no single-char). Names
|
|
1095
|
+
* that previously passed the looser blueprint regex (e.g.
|
|
1096
|
+
* `weather_card`, single-char `a`) now reject at publish + at
|
|
1097
|
+
* `register_blueprint`. The sample fixture `weather_card` was
|
|
1098
|
+
* renamed to `weather-card` to satisfy the unified rule.
|
|
1099
|
+
*
|
|
1100
|
+
* 4. `pluginId` → `artifactId` wire-side rename in
|
|
1101
|
+
* `@ggui-ai/registry-core` and the cloud Lambda env. The
|
|
1102
|
+
* registry stores both gadgets and blueprints under one row
|
|
1103
|
+
* family keyed by `kind: 'gadget' | 'blueprint'`; `artifactId`
|
|
1104
|
+
* matches what the field actually carries. Renames:
|
|
1105
|
+
* `PLUGINS_METADATA_SK → ARTIFACTS_METADATA_SK`,
|
|
1106
|
+
* `Plugins/Plugin*Row → Artifacts/Artifact*Row`,
|
|
1107
|
+
* `Row.pluginId → Row.artifactId`,
|
|
1108
|
+
* `SearchResultEntry.pluginId → .artifactId`,
|
|
1109
|
+
* `PublishResponseBody.pluginId → .artifactId`,
|
|
1110
|
+
* RegistryStorage methods (`getPluginMetadata` etc.) → `…Artifact…`,
|
|
1111
|
+
* CDK tables `<env>-Plugins` / `<env>-PluginVersions` →
|
|
1112
|
+
* `…-Artifacts` / `…-ArtifactVersions`, Lambda env vars
|
|
1113
|
+
* `PLUGINS_TABLE` / `PLUGIN_VERSIONS_TABLE` → `ARTIFACTS_TABLE` /
|
|
1114
|
+
* `ARTIFACT_VERSIONS_TABLE`.
|
|
1115
|
+
*
|
|
1116
|
+
* 5. Schema tighten-ups — the protocol+handler boundaries now
|
|
1117
|
+
* hard-reject misconfigured input that previously silently rode
|
|
1118
|
+
* through:
|
|
1119
|
+
*
|
|
1120
|
+
* - `clientCapabilitiesSpecSchema` is `.strict()` — the retired
|
|
1121
|
+
* `libraries` field name fails parse instead of being
|
|
1122
|
+
* silently dropped.
|
|
1123
|
+
* - `LINT_CONTRACT_RETIRED_FIELD` / `RETIRED_CONTRACT_FIELDS` /
|
|
1124
|
+
* `assertContractNoRetiredFields` — push + handshake reject
|
|
1125
|
+
* contracts that carry `libraries`, `dispatch`, `wiredTools`,
|
|
1126
|
+
* `clientTools`, `broadcast`, `capabilities`.
|
|
1127
|
+
* - `strictGadgetDescriptorSchema.permission` is
|
|
1128
|
+
* `z.enum(KNOWN_PERMISSION_NAMES)` — typos
|
|
1129
|
+
* (`geolocaiton`) fail at parse.
|
|
1130
|
+
* - `bundleUrl` / `styleUrl` / `connect[]` use `z.url()` not
|
|
1131
|
+
* `z.string().min(1)`.
|
|
1132
|
+
* - `tags` capped: ≤20 entries, each ≤64 chars, charset
|
|
1133
|
+
* `[a-z0-9-]`.
|
|
1134
|
+
* - `InMemoryAppMetadataStore` + cloud `dynamoAppMetadataStore`
|
|
1135
|
+
* re-validate every gadget through `strictGadgetDescriptorSchema`
|
|
1136
|
+
* on register + on read — strict-schema posture at the store
|
|
1137
|
+
* seam.
|
|
1138
|
+
* - `resolveGadgetUrls` uses `bundleHostScheme()` — `http://`
|
|
1139
|
+
* for loopback, `https://` elsewhere.
|
|
1140
|
+
* - `enrichContractGadgets` hoisted to `@ggui-ai/protocol` —
|
|
1141
|
+
* one canonical site shared by push (handlers) and
|
|
1142
|
+
* generation-dispatch (ui-gen).
|
|
1143
|
+
* - `assertGeneratorRegistered` extracted — handshake + push
|
|
1144
|
+
* share one allow-list check.
|
|
1145
|
+
* - `gadgetRequiresSchema` extracted — single source for the
|
|
1146
|
+
* `requires[]` field across wire / registry / artifact-manifest
|
|
1147
|
+
* schemas.
|
|
1148
|
+
* - `baseGadgetFieldsShape` extracted — both gadgetEntry
|
|
1149
|
+
* schemas spread from one shape constant.
|
|
1150
|
+
* - `manifestToRegistryEntry` helper hoisted from CLI to
|
|
1151
|
+
* `@ggui-ai/artifact-manifest`; install CLI imports the
|
|
1152
|
+
* canonical helper.
|
|
1153
|
+
* - `ReadErrorCode` adds `'yanked'` for the 410-Gone path;
|
|
1154
|
+
* `SearchErrorCode` defined as a closed enum; both are
|
|
1155
|
+
* closed unions.
|
|
1156
|
+
* - `conformanceFailureCode` sub-discriminator added on the
|
|
1157
|
+
* publish conformance-failed response.
|
|
1158
|
+
* - `GadgetGateErrorCode` closed enum union — single-source
|
|
1159
|
+
* for push-gate error codes (`gadget_not_registered`,
|
|
1160
|
+
* `gadget_public_env_missing`, `unknown_generator`).
|
|
1161
|
+
* - `handshakeOutputSchema.reason?: string (≤280 chars)` —
|
|
1162
|
+
* optional truncated diagnostic.
|
|
1163
|
+
* - `assertNoDuplicateGadgetHooks` (slug:
|
|
1164
|
+
* `duplicate_gadget_hook`) — hard reject when two bindings
|
|
1165
|
+
* declare the same `(package, hook)` pair.
|
|
1166
|
+
* - `resolveGadgetUrls` memoized — WeakMap-keyed cache on
|
|
1167
|
+
* entry object identity.
|
|
1168
|
+
*
|
|
1169
|
+
* --------------------------------------------------------------------
|
|
1170
|
+
* Blueprint conformance gate:
|
|
1171
|
+
*
|
|
1172
|
+
* 1. `ConformanceErrorCode` (closed union, exported from
|
|
1173
|
+
* `@ggui-ai/registry-core`) gains six new entries. The blueprint
|
|
1174
|
+
* branch of `checkConformance()` was previously a no-op
|
|
1175
|
+
* short-circuit; it is now five mandatory static gates plus one
|
|
1176
|
+
* opt-in runtime probe:
|
|
1177
|
+
*
|
|
1178
|
+
* - `blueprint_source_too_large` — `manifest.source` exceeds
|
|
1179
|
+
* {@link MAX_BLUEPRINT_SOURCE_BYTES} (5 MiB, symmetric with
|
|
1180
|
+
* the gadget bundle ceiling).
|
|
1181
|
+
* - `blueprint_compile_error` — `esbuild.transformSync({
|
|
1182
|
+
* loader: 'tsx' })` rejects the TSX source.
|
|
1183
|
+
* - `blueprint_disallowed_import` — `oxc-parser` walks the
|
|
1184
|
+
* source TSX (not compiled JS — esbuild tree-shakes unused
|
|
1185
|
+
* imports even with `treeShaking: false`) and rejects any
|
|
1186
|
+
* import outside `{ react, react/jsx-runtime, react-dom,
|
|
1187
|
+
* @ggui-ai/gadgets }`. Blueprints have no `peerDeps` channel.
|
|
1188
|
+
* - `blueprint_missing_default_export` — iframe runtime mounts
|
|
1189
|
+
* the default export as the root component.
|
|
1190
|
+
* - `fixture_props_shape_mismatch` — when both
|
|
1191
|
+
* `manifest.fixtureProps` and `manifest.contract.propsSpec`
|
|
1192
|
+
* are present, every key marked `required: true` on
|
|
1193
|
+
* `propsSpec.properties` must appear on the fixture.
|
|
1194
|
+
* - `blueprint_runtime_probe_failed` — opt-in via
|
|
1195
|
+
* `PublishArtifactDeps.blueprintProbe`. Probe compiles TSX →
|
|
1196
|
+
* CJS, evaluates in Node `vm.runInContext` with a `require`
|
|
1197
|
+
* shim, mounts the default export via
|
|
1198
|
+
* `react-dom/server.renderToString` with the manifest's
|
|
1199
|
+
* fixtureProps; any thrown error during compile / module
|
|
1200
|
+
* load / mount / render surfaces this code.
|
|
1201
|
+
*
|
|
1202
|
+
* Consumers with an exhaustive `switch` on
|
|
1203
|
+
* `ConformanceErrorCode` MUST add the six new branches. Closed-
|
|
1204
|
+
* union semantics mean prior-version exhaustive consumers
|
|
1205
|
+
* silently fall through on the new codes.
|
|
1206
|
+
*
|
|
1207
|
+
* 2. New constant `MAX_BLUEPRINT_SOURCE_BYTES` (= `5 * 1024 * 1024`)
|
|
1208
|
+
* exported from `@ggui-ai/registry-core`. Symmetric with the
|
|
1209
|
+
* gadget bundle ceiling so publishers can pre-check source size
|
|
1210
|
+
* before invoking `ggui blueprint publish`.
|
|
1211
|
+
*
|
|
1212
|
+
* 3. New optional `PublishArtifactDeps.blueprintProbe?:
|
|
1213
|
+
* BlueprintProbeRunner` deps slot on the publish op. Implementa-
|
|
1214
|
+
* tions wiring this slot get the 6th conformance gate (the
|
|
1215
|
+
* runtime probe); leaving it `undefined` preserves the
|
|
1216
|
+
* static-only behavior. Reference implementation:
|
|
1217
|
+
* `@ggui-ai/blueprint-probe`.
|
|
1218
|
+
*
|
|
1219
|
+
* 4. `POST /conformance` runs the 5 static gates only. `POST
|
|
1220
|
+
* /publish` MAY additionally run the runtime probe when the
|
|
1221
|
+
* deploy wires `blueprintProbe`. A blueprint passing
|
|
1222
|
+
* `/conformance` MAY still be rejected by `/publish` with
|
|
1223
|
+
* `blueprint_runtime_probe_failed`. Publishers SHOULD run the
|
|
1224
|
+
* local probe before publishing.
|
|
1225
|
+
*
|
|
1226
|
+
* Security posture for the runtime probe (read before wiring it).
|
|
1227
|
+
* `vm.runInContext` is NOT a security sandbox — it's a JavaScript-
|
|
1228
|
+
* isolation primitive, not an adversarial-code-execution boundary.
|
|
1229
|
+
* A blueprint that passes all five static gates can climb the
|
|
1230
|
+
* prototype chain of the injected `react` module to reach the parent
|
|
1231
|
+
* process's `Function` constructor and execute arbitrary code in the
|
|
1232
|
+
* parent context.
|
|
1233
|
+
*
|
|
1234
|
+
* Because of this, **the cloud-hosted publish Lambda's default deps
|
|
1235
|
+
* do NOT wire `blueprintProbe`.** The static gates still run on every
|
|
1236
|
+
* publish. The runtime probe is local-trust-boundary-only by default
|
|
1237
|
+
* — CLI on the publisher's own machine, self-hosted registries with
|
|
1238
|
+
* a closed publisher pool. A fully isolated probe (isolated-vm,
|
|
1239
|
+
* separate process, execution timeout) is future work.
|
|
1240
|
+
*
|
|
1241
|
+
* --------------------------------------------------------------------
|
|
1242
|
+
* Sigstore signing for public-visibility artifacts. The trust chain
|
|
1243
|
+
* bifurcates: private artifacts → Ed25519 (existing); public
|
|
1244
|
+
* artifacts → sigstore (Fulcio short-lived cert + Rekor transparency
|
|
1245
|
+
* log + cosign bundle).
|
|
1246
|
+
*
|
|
1247
|
+
* 1. **`SigstoreSignature` widened** to embed a serialized cosign
|
|
1248
|
+
* bundle (per `@sigstore/bundle` v0.3 spec) — `{ algorithm:
|
|
1249
|
+
* 'sigstore-cosign', bundleSha384, bundle: <serialized-json>,
|
|
1250
|
+
* signedAt }`. Old narrow shape (`{ uuid, logIndex }`) carried
|
|
1251
|
+
* only Rekor coordinates and was insufficient for offline
|
|
1252
|
+
* verification. The widened shape ships everything a verifier
|
|
1253
|
+
* needs: cert chain, inclusion proof, signed entry timestamp.
|
|
1254
|
+
*
|
|
1255
|
+
* 2. **`PublishArtifactInput.signature`** now typed
|
|
1256
|
+
* `GadgetSignature = Ed25519Signature | SigstoreSignature`
|
|
1257
|
+
* (discriminated union over `algorithm`). The publish op
|
|
1258
|
+
* dispatches on the discriminator after a single-shape guard
|
|
1259
|
+
* (`isGadgetSignature` from `@ggui-ai/gadget-signing`):
|
|
1260
|
+
* - `'ed25519'` → AuthorKeys-rooted flow (unchanged).
|
|
1261
|
+
* - `'sigstore-cosign'` → `verifyBundleSigstore` flow; on
|
|
1262
|
+
* verify-OK the leaf cert PEM is extracted from
|
|
1263
|
+
* `bundle.verificationMaterial.x509CertificateChain.certificates[0].rawBytes`
|
|
1264
|
+
* and pinned as `ArtifactVersionRow.authorPublicKey`.
|
|
1265
|
+
*
|
|
1266
|
+
* 3. **`@ggui-ai/gadget-signing` exports** new canonical type
|
|
1267
|
+
* guards `isEd25519Signature` / `isSigstoreSignature` /
|
|
1268
|
+
* `isGadgetSignature` (collapsing 3 duplicated inline guards)
|
|
1269
|
+
* and new error class `SigstoreSigningError` with discriminated
|
|
1270
|
+
* `code: 'oidc_invalid' | 'fulcio_error' | 'rekor_error' |
|
|
1271
|
+
* 'unknown'`. The `SigstoreNotImplementedError` stub class is
|
|
1272
|
+
* DELETED (pre-launch posture — no shims).
|
|
1273
|
+
*
|
|
1274
|
+
* 4. **`PublishError.error` gains** `oidc_resolution_failed`
|
|
1275
|
+
* (sub-discriminated by `oidcCode`) for CLI publish-side failure
|
|
1276
|
+
* to acquire an OIDC token. Server-side never returns this code
|
|
1277
|
+
* — it's CLI-internal — but the wire shape allows for it so the
|
|
1278
|
+
* same error envelope flows through the CLI's error printer.
|
|
1279
|
+
*
|
|
1280
|
+
* 5. **CLI publish dispatches on `manifest.visibility`**: `'public'`
|
|
1281
|
+
* → sigstore flow (calls `resolveOidcToken` then
|
|
1282
|
+
* `signBundleSigstore`); `'private'` → Ed25519 flow (unchanged).
|
|
1283
|
+
* New `--identity-token <jwt>` flag + `GGUI_OIDC_TOKEN` env var.
|
|
1284
|
+
* Resolution order: flag → env → GitHub Actions ambient (via
|
|
1285
|
+
* `ACTIONS_ID_TOKEN_REQUEST_URL`) → interactive PKCE browser
|
|
1286
|
+
* flow on a TTY.
|
|
1287
|
+
*
|
|
1288
|
+
* 6. **CLI install dispatches on `signature.algorithm`**:
|
|
1289
|
+
* `'sigstore-cosign'` → `verifyBundleSigstore` with optional
|
|
1290
|
+
* `--verify-identity <pattern>` (literal or `/regex/[flags]`
|
|
1291
|
+
* form). The flag enforces that the bundle's Fulcio leaf cert
|
|
1292
|
+
* SAN matches the supplied identity. Ed25519 unchanged.
|
|
1293
|
+
*
|
|
1294
|
+
* No exhaustive-switch concerns — `GadgetSignature` was already a
|
|
1295
|
+
* discriminated union; the changes widen the SigstoreSignature
|
|
1296
|
+
* variant in-place. Consumers that always hit the Ed25519 branch
|
|
1297
|
+
* keep working without modification.
|
|
1298
|
+
*
|
|
1299
|
+
* Trust chain table:
|
|
1300
|
+
*
|
|
1301
|
+
* | visibility | trust chain |
|
|
1302
|
+
* | ---------- | ---------------------------------------------- |
|
|
1303
|
+
* | `private` | Ed25519 author key pinned in registry's |
|
|
1304
|
+
* | | AuthorKeys table, base-rooted at the |
|
|
1305
|
+
* | | publisher's Cognito subject. |
|
|
1306
|
+
* | `public` | Fulcio short-lived X.509 cert (OIDC-backed, |
|
|
1307
|
+
* | | Sigstore-keyless) + Rekor inclusion proof, |
|
|
1308
|
+
* | | offline-verifiable via the embedded cosign |
|
|
1309
|
+
* | | bundle. |
|
|
1310
|
+
*
|
|
1311
|
+
* --------------------------------------------------------------------
|
|
1312
|
+
* Two-layer storage for blueprint compiled bytes (TSX → JS compile
|
|
1313
|
+
* boundary):
|
|
1314
|
+
*
|
|
1315
|
+
* - Blueprint version rows now carry a `compiledDigest` pointer
|
|
1316
|
+
* (lowercase hex SHA-256 of the compiled bytes) into a new
|
|
1317
|
+
* `<envName>-CompiledBlobs` DDB table; the previous
|
|
1318
|
+
* `blueprintSource` column is deleted (raw TSX stays on
|
|
1319
|
+
* `manifest.source` for audit / future-recompile).
|
|
1320
|
+
* - `ReadPkgResponse` exposes `compiledDigest` + `compiledBytes`
|
|
1321
|
+
* (base64); install consumers MUST read compiledBytes — the
|
|
1322
|
+
* registry is now the trust boundary for the compile step.
|
|
1323
|
+
* - `CompiledBlobRow` reserves `manifestSig` + `compiledSig`
|
|
1324
|
+
* columns for a future signing wave; this change writes neither.
|
|
1325
|
+
* - esbuild pinned to 0.25.12 (was `^0.25.0`) for digest stability.
|
|
1326
|
+
*
|
|
1327
|
+
* `compiledDigest` is the shareable cache key for cross-app cache
|
|
1328
|
+
* sharing and cross-registry federation; the reserved signature
|
|
1329
|
+
* columns ride on the blob row for a later signing wave.
|
|
1330
|
+
*
|
|
1331
|
+
* --------------------------------------------------------------------
|
|
1332
|
+
* `package.json`-style gadget refs + `GadgetRef` / `GadgetDescriptor`
|
|
1333
|
+
* split. The wire shape
|
|
1334
|
+
* `DataContract.clientCapabilities.gadgets[*]` carries the identity
|
|
1335
|
+
* tuple `{ hook, package, version, description?, usage? }`. Transport
|
|
1336
|
+
* metadata (`bundleUrl` / `bundleHost` / `bundleSri` / `typesUrl` /
|
|
1337
|
+
* `typesSri` / `permission` / `connect` / `requires` / `styleUrl` /
|
|
1338
|
+
* `required` / `gotchas` / `example`) stays on the registered
|
|
1339
|
+
* `GadgetDescriptor` resolved server-side from `App.gadgets`. The
|
|
1340
|
+
* resolved descriptor subset rides alongside the wire on
|
|
1341
|
+
* `SessionStackEntry.gadgetDescriptors` as a sidecar — no enrichment
|
|
1342
|
+
* overlay on the contract surface.
|
|
1343
|
+
*
|
|
1344
|
+
* 1. **`GadgetRef = { hook, package, version, description?, usage? }`**
|
|
1345
|
+
* Wire-side identity matches `package.json` dependency pins:
|
|
1346
|
+
* bare npm package name + exact semver pin (no ranges). Schema
|
|
1347
|
+
* `gadgetRefSchema` is `.strict()` and rejects transport fields
|
|
1348
|
+
* + range syntax at parse time.
|
|
1349
|
+
*
|
|
1350
|
+
* 2. **`GadgetEntry` → `GadgetDescriptor`** (TS interface rename).
|
|
1351
|
+
* Sibling renames: `gadgetEntrySchema` →
|
|
1352
|
+
* `gadgetDescriptorSchema`; `registryGadgetEntrySchema` →
|
|
1353
|
+
* `strictGadgetDescriptorSchema`; `gadgetManifestToGadgetEntry`
|
|
1354
|
+
* → `gadgetManifestToGadgetDescriptor`. No back-compat aliases.
|
|
1355
|
+
*
|
|
1356
|
+
* 3. **`ClientCapabilitiesSpec` is non-generic** — values are wire-side
|
|
1357
|
+
* `GadgetRef` only. Post-resolution descriptors live on the
|
|
1358
|
+
* `SessionStackEntry.gadgetDescriptors` sidecar (filtered subset
|
|
1359
|
+
* of `App.gadgets`). `filterDescriptorsToContract(contract,
|
|
1360
|
+
* appGadgets) → readonly GadgetDescriptor[]` replaces the prior
|
|
1361
|
+
* `enrichContractGadgets` overlay.
|
|
1362
|
+
*
|
|
1363
|
+
* 4. **`assertNoDuplicateGadgetHooks` keys on `hook` alone.** Hook
|
|
1364
|
+
* unique-per-app at registration time (`lintGadgetCatalog`);
|
|
1365
|
+
* LLM-generated component code wouldn't disambiguate two
|
|
1366
|
+
* destructure bindings with the same name. Operators pre-alias
|
|
1367
|
+
* at registration if they want both.
|
|
1368
|
+
*
|
|
1369
|
+
* 5. **New `@ggui-ai/gadgets` adapter port**:
|
|
1370
|
+
* `GadgetCatalogAdapter { list(appId): Promise<readonly
|
|
1371
|
+
* GadgetDescriptor[]> }` + `InMemoryGadgetCatalog` (static map +
|
|
1372
|
+
* `withDefault()` factory) + `CachingGadgetCatalog` (per-appId
|
|
1373
|
+
* TTL + single-flight dedup + `invalidate(appId?)`). One batch
|
|
1374
|
+
* method by design — never N+1 per-hook. Per-environment adapter
|
|
1375
|
+
* implementations (JSON / DynamoDB) land separately.
|
|
1376
|
+
*
|
|
1377
|
+
* 6. **`NPM_PACKAGE_NAME_RE` + `SEMVER_PIN_RE`** schema constants
|
|
1378
|
+
* published from `@ggui-ai/protocol`. Loose `z.string()` checks
|
|
1379
|
+
* retired; agent prompts show exact pinned identity. Cache key
|
|
1380
|
+
* `hashContract(wire, intent)` is a pure function of the wire
|
|
1381
|
+
* bytes (no canonicalize step) — version bumps invalidate caches
|
|
1382
|
+
* automatically.
|
|
1383
|
+
*
|
|
1384
|
+
* No exhaustive-switch concerns. Agents that previously omitted
|
|
1385
|
+
* `package` / `version` on a wire ref now fail at parse — the loud
|
|
1386
|
+
* failure is the design intent (a caller bug, not a forward-compat
|
|
1387
|
+
* hedge).
|
|
1388
|
+
*/
|
|
1389
|
+
export const PROTOCOL_VERSION = 'draft-2026-05-24';
|
|
1390
|
+
/**
|
|
1391
|
+
* Schema version stamped onto wire envelopes that opt into the
|
|
1392
|
+
* `schemaVersion` forward-compat field (see {@link ActionEnvelope},
|
|
1393
|
+
* {@link StreamEnvelope}, {@link ContractErrorPayload}).
|
|
1394
|
+
*
|
|
1395
|
+
* Pre-launch semantics (current): producers SHOULD stamp; consumers
|
|
1396
|
+
* SHOULD NOT reject on mismatch — the field is advisory and lets old
|
|
1397
|
+
* clients recognize the protocol generation their server emits.
|
|
1398
|
+
*
|
|
1399
|
+
* Launch-cutover semantics (future): a later change promotes this to
|
|
1400
|
+
* required on producers and tightens client-side policy (e.g.,
|
|
1401
|
+
* reject-with-UPGRADE-REQUIRED when the received version's major bumps
|
|
1402
|
+
* past the client's known major).
|
|
1403
|
+
*
|
|
1404
|
+
* Kept as a string so SemVer-like extensions (`'1.0-rc.2'`,
|
|
1405
|
+
* `'1.1'`) don't require retyping consumers. Value equals
|
|
1406
|
+
* {@link PROTOCOL_VERSION} today — the alias exists so envelope-layer
|
|
1407
|
+
* consumers can reference schema-versioning specifically without
|
|
1408
|
+
* coupling to the broader cache-invalidation constant.
|
|
1409
|
+
*/
|
|
1410
|
+
export const PROTOCOL_SCHEMA_VERSION = PROTOCOL_VERSION;
|
|
1411
|
+
/**
|
|
1412
|
+
* Canonical live-channel error code emitted when a peer's declared
|
|
1413
|
+
* {@link SubscribePayload.supportedVersions} /
|
|
1414
|
+
* {@link AckPayload.serverVersion} does not overlap the receiver's
|
|
1415
|
+
* known compatible set.
|
|
1416
|
+
*
|
|
1417
|
+
* `ErrorPayload.code` is typed as `string` (open) rather than a closed
|
|
1418
|
+
* union — this constant anchors the canonical literal so consumers can
|
|
1419
|
+
* pattern-match against a typed reference instead of string-sniffing.
|
|
1420
|
+
*
|
|
1421
|
+
* Policy posture:
|
|
1422
|
+
*
|
|
1423
|
+
* - OSS `createSessionChannelServer` default
|
|
1424
|
+
* `versionPolicy: 'reject'`: server emits `UPGRADE_REQUIRED` AND
|
|
1425
|
+
* closes the connection so the caller cannot proceed against a
|
|
1426
|
+
* version-mismatched session. Canonical first-party posture.
|
|
1427
|
+
* - `versionPolicy: 'advisory'` (legacy opt-out): server emits an
|
|
1428
|
+
* `UPGRADE_REQUIRED` error envelope on mismatch but keeps the
|
|
1429
|
+
* connection open. Use only for controlled migration windows
|
|
1430
|
+
* during which legacy-version clients must remain attached.
|
|
1431
|
+
*
|
|
1432
|
+
* Consumers (clients and servers alike) MUST handle the code as a
|
|
1433
|
+
* string — the constant exists for authoring ergonomics, not to imply
|
|
1434
|
+
* a closed union on `ErrorPayload.code`.
|
|
1435
|
+
*/
|
|
1436
|
+
export const UPGRADE_REQUIRED = 'UPGRADE_REQUIRED';
|
|
1437
|
+
/**
|
|
1438
|
+
* Versions of the ggui protocol this client library accepts on the
|
|
1439
|
+
* wire.
|
|
1440
|
+
*
|
|
1441
|
+
* The first-party client declares this set on every subscribe via
|
|
1442
|
+
* {@link SubscribePayload.supportedVersions}. A server whose
|
|
1443
|
+
* {@link PROTOCOL_SCHEMA_VERSION} is NOT a member of this list is a
|
|
1444
|
+
* version mismatch — the server replies with an `UPGRADE_REQUIRED`
|
|
1445
|
+
* error envelope (see {@link UPGRADE_REQUIRED}). Symmetrically, if a
|
|
1446
|
+
* server returns {@link AckPayload.serverVersion} not in this set,
|
|
1447
|
+
* the client surfaces `UPGRADE_REQUIRED` to the caller.
|
|
1448
|
+
*
|
|
1449
|
+
* Seeded with {@link PROTOCOL_SCHEMA_VERSION}. Future minor-compatible
|
|
1450
|
+
* versions are added here as the protocol evolves — a client that
|
|
1451
|
+
* accepts both `"1.0"` and `"1.1"` ships with `['1.0', '1.1']`, and
|
|
1452
|
+
* `PROTOCOL_SCHEMA_VERSION` advances independently.
|
|
1453
|
+
*
|
|
1454
|
+
* Frozen so runtime consumers can't mutate the module-level array
|
|
1455
|
+
* (would be a cross-session leak).
|
|
1456
|
+
*/
|
|
1457
|
+
export const CLIENT_SUPPORTED_VERSIONS = Object.freeze([
|
|
1458
|
+
PROTOCOL_SCHEMA_VERSION,
|
|
1459
|
+
]);
|