@ggui-ai/mcp-server-handlers 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -65,6 +65,39 @@ declare const outputSchema: {
65
65
  dark: z.ZodOptional<z.ZodString>;
66
66
  }, z.core.$strict>>;
67
67
  frameless: z.ZodOptional<z.ZodBoolean>;
68
+ fonts: z.ZodOptional<z.ZodArray<z.ZodObject<{
69
+ family: z.ZodString;
70
+ src: z.ZodString;
71
+ weight: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
72
+ style: z.ZodOptional<z.ZodString>;
73
+ display: z.ZodOptional<z.ZodString>;
74
+ }, z.core.$strict>>>;
75
+ imagery: z.ZodOptional<z.ZodObject<{
76
+ mark: z.ZodOptional<z.ZodObject<{
77
+ src: z.ZodString;
78
+ alt: z.ZodOptional<z.ZodString>;
79
+ tone: z.ZodOptional<z.ZodEnum<{
80
+ light: "light";
81
+ dark: "dark";
82
+ }>>;
83
+ }, z.core.$strict>>;
84
+ hero: z.ZodOptional<z.ZodObject<{
85
+ src: z.ZodString;
86
+ alt: z.ZodOptional<z.ZodString>;
87
+ tone: z.ZodOptional<z.ZodEnum<{
88
+ light: "light";
89
+ dark: "dark";
90
+ }>>;
91
+ }, z.core.$strict>>;
92
+ pattern: z.ZodOptional<z.ZodObject<{
93
+ src: z.ZodString;
94
+ alt: z.ZodOptional<z.ZodString>;
95
+ tone: z.ZodOptional<z.ZodEnum<{
96
+ light: "light";
97
+ dark: "dark";
98
+ }>>;
99
+ }, z.core.$strict>>;
100
+ }, z.core.$strict>>;
68
101
  }, z.core.$strict>>;
69
102
  readonly updatedAt: z.ZodOptional<z.ZodString>;
70
103
  /** Present on a refusal: the one refusal class this door emits. */
@@ -84,6 +117,8 @@ declare const outputSchema: {
84
117
  overlayHash: z.ZodLiteral<"mismatch">;
85
118
  }, z.core.$strict>, z.ZodObject<{
86
119
  refused: z.ZodLiteral<"v1 shape">;
120
+ }, z.core.$strict>, z.ZodObject<{
121
+ wouldDrop: z.ZodArray<z.ZodString>;
87
122
  }, z.core.$strict>]>>;
88
123
  /** Present on a shape refusal the schema itself raised — its messages, one per issue. */
89
124
  readonly issues: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -132,6 +167,39 @@ export declare function createSetAppThemeHandler(deps: SetAppThemeDeps): import(
132
167
  dark: z.ZodOptional<z.ZodString>;
133
168
  }, z.core.$strict>>;
134
169
  frameless: z.ZodOptional<z.ZodBoolean>;
170
+ fonts: z.ZodOptional<z.ZodArray<z.ZodObject<{
171
+ family: z.ZodString;
172
+ src: z.ZodString;
173
+ weight: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
174
+ style: z.ZodOptional<z.ZodString>;
175
+ display: z.ZodOptional<z.ZodString>;
176
+ }, z.core.$strict>>>;
177
+ imagery: z.ZodOptional<z.ZodObject<{
178
+ mark: z.ZodOptional<z.ZodObject<{
179
+ src: z.ZodString;
180
+ alt: z.ZodOptional<z.ZodString>;
181
+ tone: z.ZodOptional<z.ZodEnum<{
182
+ light: "light";
183
+ dark: "dark";
184
+ }>>;
185
+ }, z.core.$strict>>;
186
+ hero: z.ZodOptional<z.ZodObject<{
187
+ src: z.ZodString;
188
+ alt: z.ZodOptional<z.ZodString>;
189
+ tone: z.ZodOptional<z.ZodEnum<{
190
+ light: "light";
191
+ dark: "dark";
192
+ }>>;
193
+ }, z.core.$strict>>;
194
+ pattern: z.ZodOptional<z.ZodObject<{
195
+ src: z.ZodString;
196
+ alt: z.ZodOptional<z.ZodString>;
197
+ tone: z.ZodOptional<z.ZodEnum<{
198
+ light: "light";
199
+ dark: "dark";
200
+ }>>;
201
+ }, z.core.$strict>>;
202
+ }, z.core.$strict>>;
135
203
  }, z.core.$strict>;
136
204
  }, {
137
205
  readonly ok: z.ZodBoolean;
@@ -153,6 +221,39 @@ export declare function createSetAppThemeHandler(deps: SetAppThemeDeps): import(
153
221
  dark: z.ZodOptional<z.ZodString>;
154
222
  }, z.core.$strict>>;
155
223
  frameless: z.ZodOptional<z.ZodBoolean>;
224
+ fonts: z.ZodOptional<z.ZodArray<z.ZodObject<{
225
+ family: z.ZodString;
226
+ src: z.ZodString;
227
+ weight: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
228
+ style: z.ZodOptional<z.ZodString>;
229
+ display: z.ZodOptional<z.ZodString>;
230
+ }, z.core.$strict>>>;
231
+ imagery: z.ZodOptional<z.ZodObject<{
232
+ mark: z.ZodOptional<z.ZodObject<{
233
+ src: z.ZodString;
234
+ alt: z.ZodOptional<z.ZodString>;
235
+ tone: z.ZodOptional<z.ZodEnum<{
236
+ light: "light";
237
+ dark: "dark";
238
+ }>>;
239
+ }, z.core.$strict>>;
240
+ hero: z.ZodOptional<z.ZodObject<{
241
+ src: z.ZodString;
242
+ alt: z.ZodOptional<z.ZodString>;
243
+ tone: z.ZodOptional<z.ZodEnum<{
244
+ light: "light";
245
+ dark: "dark";
246
+ }>>;
247
+ }, z.core.$strict>>;
248
+ pattern: z.ZodOptional<z.ZodObject<{
249
+ src: z.ZodString;
250
+ alt: z.ZodOptional<z.ZodString>;
251
+ tone: z.ZodOptional<z.ZodEnum<{
252
+ light: "light";
253
+ dark: "dark";
254
+ }>>;
255
+ }, z.core.$strict>>;
256
+ }, z.core.$strict>>;
156
257
  }, z.core.$strict>>;
157
258
  readonly updatedAt: z.ZodOptional<z.ZodString>;
158
259
  /** Present on a refusal: the one refusal class this door emits. */
@@ -172,6 +273,8 @@ export declare function createSetAppThemeHandler(deps: SetAppThemeDeps): import(
172
273
  overlayHash: z.ZodLiteral<"mismatch">;
173
274
  }, z.core.$strict>, z.ZodObject<{
174
275
  refused: z.ZodLiteral<"v1 shape">;
276
+ }, z.core.$strict>, z.ZodObject<{
277
+ wouldDrop: z.ZodArray<z.ZodString>;
175
278
  }, z.core.$strict>]>>;
176
279
  /** Present on a shape refusal the schema itself raised — its messages, one per issue. */
177
280
  readonly issues: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -192,6 +295,30 @@ export declare function createSetAppThemeHandler(deps: SetAppThemeDeps): import(
192
295
  dark?: string | undefined;
193
296
  } | undefined;
194
297
  frameless?: boolean | undefined;
298
+ fonts?: {
299
+ family: string;
300
+ src: string;
301
+ weight?: string | number | undefined;
302
+ style?: string | undefined;
303
+ display?: string | undefined;
304
+ }[] | undefined;
305
+ imagery?: {
306
+ mark?: {
307
+ src: string;
308
+ alt?: string | undefined;
309
+ tone?: "light" | "dark" | undefined;
310
+ } | undefined;
311
+ hero?: {
312
+ src: string;
313
+ alt?: string | undefined;
314
+ tone?: "light" | "dark" | undefined;
315
+ } | undefined;
316
+ pattern?: {
317
+ src: string;
318
+ alt?: string | undefined;
319
+ tone?: "light" | "dark" | undefined;
320
+ } | undefined;
321
+ } | undefined;
195
322
  } | undefined;
196
323
  updatedAt?: string | undefined;
197
324
  code?: "invalid_app_config" | undefined;
@@ -209,6 +336,8 @@ export declare function createSetAppThemeHandler(deps: SetAppThemeDeps): import(
209
336
  overlayHash: "mismatch";
210
337
  } | {
211
338
  refused: "v1 shape";
339
+ } | {
340
+ wouldDrop: string[];
212
341
  } | undefined;
213
342
  issues?: string[] | undefined;
214
343
  }>>;
@@ -1 +1 @@
1
- {"version":3,"file":"set-app-theme.d.ts","sourceRoot":"","sources":["../../src/ops-apps/set-app-theme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,mBAAmB,EACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,aAAa,CAAC;AAGrB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KAAK;IACpF,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC,CAAC;AAcF,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;IAKhB,mEAAmE;;IAEnE,sGAAsG;;;;;;;;;;;;;;;;IAEtG,yFAAyF;;CAEjF,CAAC;AAEX,uEAAuE;AACvE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC;AAE1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,8FAA8F;IAC9F,QAAQ,CAAC,eAAe,EAAE,wBAAwB,CAAC;CACpD;AAED,0EAA0E;AAC1E,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,GAC/C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAA;CAAE,GAC7D;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAY/D;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,OAAO,EACZ,eAAe,EAAE,wBAAwB,GACxC,OAAO,CAAC,iBAAiB,CAAC,CAsB5B;AAWD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA3E5D,mEAAmE;;IAEnE,sGAAsG;;;;;;;;;;;;;;;;IAEtG,yFAAyF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4G1F"}
1
+ {"version":3,"file":"set-app-theme.d.ts","sourceRoot":"","sources":["../../src/ops-apps/set-app-theme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,mBAAmB,EAEzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,aAAa,CAAC;AAGrB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KAAK;IACpF,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC,CAAC;AAcF,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAKhB,mEAAmE;;IAEnE,sGAAsG;;;;;;;;;;;;;;;;;;IAEtG,yFAAyF;;CAEjF,CAAC;AAEX,uEAAuE;AACvE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC;AAE1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,8FAA8F;IAC9F,QAAQ,CAAC,eAAe,EAAE,wBAAwB,CAAC;CACpD;AAED,0EAA0E;AAC1E,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,GAC/C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAA;CAAE,GAC7D;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAY/D;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,OAAO,EACZ,eAAe,EAAE,wBAAwB,GACxC,OAAO,CAAC,iBAAiB,CAAC,CAsB5B;AAmBD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAnF5D,mEAAmE;;IAEnE,sGAAsG;;;;;;;;;;;;;;;;;;IAEtG,yFAAyF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAoH1F"}
@@ -31,7 +31,7 @@
31
31
  *
32
32
  * Pure over the {@link AppsSource} seam + the injected validator.
33
33
  */
34
- import { appThemeSchema, appThemeRefusalBodySchema, canonicalOverlayHash, } from '@ggui-ai/protocol';
34
+ import { appThemeSchema, appThemeRefusalBodySchema, canonicalOverlayHash, appThemeWouldDropRefusalText, } from '@ggui-ai/protocol';
35
35
  import { z } from 'zod';
36
36
  import { defineHandler, handlerFailure, } from '../types.js';
37
37
  import { resolveOwnerSub } from './identity.js';
@@ -41,7 +41,7 @@ const inputSchema = {
41
41
  .string()
42
42
  .min(1)
43
43
  .describe('Target `GguiApp.appId` — must be one the calling user owns. Discover via `ggui_ops_list_apps`.'),
44
- theme: appThemeSchema.describe('The app theme: `overlays.light` / `overlays.dark` are the derived `--ggui-*` sets (every consumed token, minus the floor the renderer owns), `overlayHash` = canonicalOverlayHash({ overlays, cssVariables, keyframes }); optional `mode` (the default when no host announces one), `name` (a label), `cssVariables` (mode-agnostic overrides), `keyframes` (per mode), `frameless`. Refused with `invalid_app_config` when a mode leaves a token uncovered, names a token outside the manifest, the attestation mismatches, or the body is the retired one-palette shape.'),
44
+ theme: appThemeSchema.describe('The app theme: `overlays.light` / `overlays.dark` are the derived `--ggui-*` sets (every consumed token, minus the floor the renderer owns), `overlayHash` = canonicalOverlayHash({ overlays, cssVariables, keyframes }); optional `mode` (the default when no host announces one), `name` (a label), `cssVariables` (mode-agnostic overrides), `keyframes` (per mode), `frameless`. Refused with `invalid_app_config` when a mode leaves a token uncovered, names a token outside the manifest, the attestation mismatches, or the body is the retired one-palette shape. Optional declared assets (ggui#1093): `fonts` — 1..16 faces, https-only `src`, the host admits their origins and the shell inlines them — and `imagery` — `mark` / `hero` / `pattern`, each `{ src, alt?, tone? }`, https-only; both outside the attestation.'),
45
45
  };
46
46
  const outputSchema = {
47
47
  ok: z.boolean(),
@@ -101,6 +101,14 @@ function refusalText(admission) {
101
101
  return 'invalid_app_config: the one-palette theme body is retired — send { overlays: { light, dark }, overlayHash, … }';
102
102
  if ('overlayHash' in r)
103
103
  return 'invalid_app_config: overlayHash does not match canonicalOverlayHash({ overlays, cssVariables, keyframes })';
104
+ if ('wouldDrop' in r) {
105
+ // ggui#1124 — the write would have DESTROYED stored members it did not
106
+ // carry. The wording is the protocol's ONE text, not this handler's:
107
+ // every door that refuses a destructive write says the same words, and
108
+ // the refusal names the compliance path so it is an instruction rather
109
+ // than a verdict (founder's ruling, 2026-09-16).
110
+ return `invalid_app_config: ${appThemeWouldDropRefusalText(r.wouldDrop)}`;
111
+ }
104
112
  if ('unknown' in r)
105
113
  return `invalid_app_config: keys outside the consumed-token manifest — light: [${r.unknown.light.join(', ')}] dark: [${r.unknown.dark.join(', ')}]`;
106
114
  return `invalid_app_config: consumed tokens left uncovered — light: [${r.uncovered.light.join(', ')}] dark: [${r.uncovered.dark.join(', ')}]`;
@@ -172,6 +172,7 @@ export declare function createGguiOpsGenerateBlueprintHandler(deps: GguiOpsGener
172
172
  aesthetic: z.ZodOptional<z.ZodString>;
173
173
  context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<import("@ggui-ai/protocol").JsonValue, unknown, z.core.$ZodTypeInternals<import("@ggui-ai/protocol").JsonValue, unknown>>>>;
174
174
  seedPrompt: z.ZodOptional<z.ZodString>;
175
+ intent: z.ZodOptional<z.ZodString>;
175
176
  setAsOperatorDefault: z.ZodOptional<z.ZodBoolean>;
176
177
  }, {
177
178
  blueprintId: z.ZodString;
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/ops-blueprint/generate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,aAAa,EAGd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,YAAY,EAIlB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAyB,KAAK,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAsBxF;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;IAC1E;;;;;;;OAOG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,CACnB,GAAG,EAAE,cAAc,KAChB,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,GAAG,qBAAqB,GAAG,IAAI,CAAC;IAC1E;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,qBAAqB,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IACxC;;;;;;;OAOG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,yBAAyB,CAAC;CACzD;AAmCD,wBAAgB,qCAAqC,CACnD,IAAI,EAAE,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;GA4QnC"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/ops-blueprint/generate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,aAAa,EAGd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,YAAY,EAIlB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAyB,KAAK,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAsBxF;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;IAC1E;;;;;;;OAOG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,CACnB,GAAG,EAAE,cAAc,KAChB,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,GAAG,qBAAqB,GAAG,IAAI,CAAC;IAC1E;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,qBAAqB,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IACxC;;;;;;;OAOG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,yBAAyB,CAAC;CACzD;AA2CD,wBAAgB,qCAAqC,CACnD,IAAI,EAAE,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;GA+RnC"}
@@ -103,6 +103,13 @@ function resolveGenerator(registry, slug) {
103
103
  }
104
104
  return found;
105
105
  }
106
+ /**
107
+ * The generation prompt when a call carries neither `intent` nor
108
+ * `seedPrompt`. Kept for one release with the observable
109
+ * `blueprint.generate_prompt_placeholder` event; the following release
110
+ * refuses such a call (`prompt_required`) instead.
111
+ */
112
+ const GENERATION_PROMPT_PLACEHOLDER = "Operator-authored blueprint variant";
106
113
  export function createGguiOpsGenerateBlueprintHandler(deps) {
107
114
  const now = deps.now ?? (() => new Date().toISOString());
108
115
  const mintBlueprintId = deps.mintBlueprintId ?? (() => `bp_${randomUUID()}`);
@@ -194,11 +201,30 @@ export function createGguiOpsGenerateBlueprintHandler(deps) {
194
201
  if (creds === null) {
195
202
  throw new MissingCredentialsError();
196
203
  }
197
- // 5. Dispatch through the generator.
204
+ // 5. Dispatch through the generator. The generation prompt is the
205
+ // request's own sentence: `intent` (prompt-only, never persisted —
206
+ // not a variance member, so the cache identity is unchanged), else
207
+ // the variance's `seedPrompt`. Neither present: the placeholder,
208
+ // made observable — the classifier reads the render axis from THIS
209
+ // prompt, and a placeholder reads every board as a list.
210
+ const generationPrompt = parsed.intent ?? parsed.seedPrompt;
211
+ if (generationPrompt === undefined) {
212
+ try {
213
+ deps.telemetry?.emit({
214
+ name: "blueprint.generate_prompt_placeholder",
215
+ at: Date.now(),
216
+ attributes: { appId, requestId: ctx.requestId, reason: "no-intent-no-seedPrompt" },
217
+ });
218
+ }
219
+ catch {
220
+ // Swallow telemetry-side throws — they MUST NOT affect
221
+ // handler correctness.
222
+ }
223
+ }
198
224
  const generateInput = {
199
225
  request: {
200
226
  sessionId: `ops_gen_${randomUUID()}`,
201
- prompt: parsed.seedPrompt ?? "Operator-authored blueprint variant",
227
+ prompt: generationPrompt ?? GENERATION_PROMPT_PLACEHOLDER,
202
228
  },
203
229
  blueprints: deps.blueprints,
204
230
  contract,
@@ -271,7 +297,8 @@ export function createGguiOpsGenerateBlueprintHandler(deps) {
271
297
  // ops call since the primary store.put already succeeded.
272
298
  if (deps.cacheRegistry) {
273
299
  try {
274
- const intentForCache = parsed.seedPrompt ??
300
+ const intentForCache = parsed.intent ??
301
+ parsed.seedPrompt ??
275
302
  normalizedPersona ??
276
303
  `operator-authored blueprint (${blueprintId})`;
277
304
  await registerBlueprint(deps.cacheRegistry, appId, {
@@ -1 +1 @@
1
- {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/ops-blueprint/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,aAAa,EACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,YAAY,EAGjB,KAAK,mBAAmB,EACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAqB,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEpF,OAAO,EAAyB,KAAK,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AACxF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAiBjD;;;;;GAKG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;IAC1E;;;;;;;OAOG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B;;;;;;;;OAQG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,qBAAqB,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC;;OAEG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B;;OAEG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IACxC;;;;;;;OAOG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,yBAAyB,CAAC;CACzD;AAED,wBAAgB,qCAAqC,CACnD,IAAI,EAAE,4BAA4B;;;;;;;;;;;;;;;;;;;GAwLnC"}
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/ops-blueprint/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,aAAa,EACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,YAAY,EAGjB,KAAK,mBAAmB,EACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAqB,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEpF,OAAO,EAAyB,KAAK,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AACxF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAiBjD;;;;;GAKG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;IAC1E;;;;;;;OAOG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B;;;;;;;;OAQG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,qBAAqB,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC;;OAEG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B;;OAEG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IACxC;;;;;;;OAOG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,yBAAyB,CAAC;CACzD;AAED,wBAAgB,qCAAqC,CACnD,IAAI,EAAE,4BAA4B;;;;;;;;;;;;;;;;;;;GAkMnC"}
@@ -131,6 +131,18 @@ export function createGguiOpsRegisterBlueprintHandler(deps) {
131
131
  const componentCode = parsed.componentCode;
132
132
  const codeHash = createHash("sha256").update(componentCode).digest("hex");
133
133
  const blueprintId = mintBlueprintId();
134
+ // ONE variance for BOTH stores. The cache row's exact key is
135
+ // `variantKey(variance)`; omitting it on the cache call filed every
136
+ // variant under the default-variant key, where an earlier registration
137
+ // of the same contract already sat — the mirror then returned THAT row
138
+ // and the new variant was never bound (the durable row said one thing,
139
+ // the served index another). Same rule as ops_generate.
140
+ const variance = {
141
+ ...(normalizedPersona !== undefined ? { persona: normalizedPersona } : {}),
142
+ ...(parsed.aesthetic !== undefined ? { aesthetic: parsed.aesthetic } : {}),
143
+ ...(parsed.context !== undefined ? { context: parsed.context } : {}),
144
+ ...(parsed.seedPrompt !== undefined ? { seedPrompt: parsed.seedPrompt } : {}),
145
+ };
134
146
  const blueprint = {
135
147
  blueprintId,
136
148
  contractHash,
@@ -140,12 +152,7 @@ export function createGguiOpsRegisterBlueprintHandler(deps) {
140
152
  // user arm on BOTH stores this handler writes (MVB row here,
141
153
  // cache mirror below). No engine claim exists to record.
142
154
  source: USER_SOURCE,
143
- variance: {
144
- ...(normalizedPersona !== undefined ? { persona: normalizedPersona } : {}),
145
- ...(parsed.aesthetic !== undefined ? { aesthetic: parsed.aesthetic } : {}),
146
- ...(parsed.context !== undefined ? { context: parsed.context } : {}),
147
- ...(parsed.seedPrompt !== undefined ? { seedPrompt: parsed.seedPrompt } : {}),
148
- },
155
+ variance,
149
156
  createdAt: now(),
150
157
  createdBy: "operator",
151
158
  contract,
@@ -172,6 +179,9 @@ export function createGguiOpsRegisterBlueprintHandler(deps) {
172
179
  // Same user-arm provenance as the MVB row above — one
173
180
  // handler call, one provenance claim across both stores.
174
181
  source: USER_SOURCE,
182
+ // The cache row MUST carry the same variance as the MVB row —
183
+ // its exact key is `variantKey(variance)`.
184
+ variance,
175
185
  // An operator invoked this tool. Without it the durable
176
186
  // record would claim the standard agent flow minted a row
177
187
  // that is retained permanently.
@@ -68,7 +68,7 @@ export function createGguiConsumeHandler(deps) {
68
68
  name: 'ggui_consume',
69
69
  title: 'Consume',
70
70
  audience: ['agent'],
71
- description: 'Long-poll for buffered events on a GguiSession. CALL THIS RIGHT AFTER EVERY `ggui_render` THAT RETURNS `nextStep.tool === "ggui_consume"` — that hint is your cue to start listening for the user\'s gesture. Keyed by sessionId (global UUID); app-scoped via ctx.appId. Inline long-poll: `timeout` is an integer in [0, 25] seconds (default 0 — an instant non-blocking drain; values outside reject INVALID_PARAMS — host MCP clients abort longer tool calls; pick 5-15s typical, 25 max). Returns `{events, status}` — each event carries `{type: "action", sessionId, intent, actionData, uiContext, actionId, firedAt}`: `actionData` is WHAT the user did, `uiContext` is the iframe-local snapshot of the contract\'s contextSpec slots AT THE MOMENT they did it. Both inform your reaction without a second round trip. Returns immediately when an action event arrives OR the render completes OR the timeout elapses. On timeout with no event you may re-call once, then end your turn — a later gesture arrives as a new user message. THE LOOP: when `events` is non-empty, REACT, then re-call `ggui_consume` for the next gesture; when `events` is empty, end your turn — a later gesture arrives as a new user message carrying its own consume directive. status:"expired" means the render is gone. IMPORTANT — the iframe state is independent of your backend state: after you mutate via domain tools (todo_toggle, cart_add, etc.), the UI still shows the OLD props until you call `ggui_amend`. If the events caused observable state changes the user is looking at, your reaction MUST include `ggui_amend` somewhere before re-consuming; otherwise the user sees stale props (the #1 wire compliance bug). Pure-info events that don\'t change displayed state can skip it. `ggui_amend` repaints the SAME card in place (the default move in this loop); `ggui_update` instead renders the state as a NEW card and advances the history number — reserve it for milestones worth a card in the transcript. HOSTS WITH PROGRESSIVE TOOL DISCOVERY (claude.ai-style connectors): if a call here errors with "tool not loaded yet" or "wrong parameter names," call `tool_search({query:"ggui_consume"})` once to warm the tool, then retry with the same args. DO NOT skip the consume — silent gesture drops are the worst protocol failure.',
71
+ description: 'Long-poll for buffered events on a GguiSession. CALL THIS RIGHT AFTER EVERY `ggui_render` THAT RETURNS `nextStep.tool === "ggui_consume"` — that hint is your cue to start listening for the user\'s gesture. Keyed by sessionId (global UUID); app-scoped via ctx.appId. Inline long-poll: `timeout` is an integer in [0, 25] seconds (default 0 — an instant non-blocking drain; values outside reject INVALID_PARAMS — host MCP clients abort longer tool calls; pick 5-15s typical, 25 max). Returns `{events, status}` — each event carries `{type: "action", sessionId, intent, actionData, uiContext, actionId, firedAt}`: `actionData` is WHAT the user did, `uiContext` is the iframe-local snapshot of the contract\'s contextSpec slots AT THE MOMENT they did it. Both inform your reaction without a second round trip. Returns immediately when an action event arrives OR the render completes OR the timeout elapses. On timeout with no event you may re-call once, then end your turn — a later gesture arrives as a new user message. THE LOOP: when `events` is non-empty, REACT, then re-call `ggui_consume` for the next gesture; when `events` is empty, end your turn — a later gesture arrives as a new user message carrying its own consume directive. status:"expired" means the render is gone. IMPORTANT — the iframe state is independent of your backend state: after you mutate via domain tools (todo_toggle, cart_add, etc.), the UI still shows the OLD props until you call `ggui_amend`. If the events caused observable state changes the user is looking at, your reaction MUST include `ggui_amend` somewhere before re-consuming; otherwise the user sees stale props (the #1 wire compliance bug). Pure-info events that don\'t change displayed state can skip it. `ggui_amend` repaints the SAME card in place (the default move in this loop); `ggui_update` instead renders the state as a NEW card and advances the history number — reserve it for milestones worth a card in the transcript. HOSTS WITH PROGRESSIVE TOOL DISCOVERY (claude.ai-style connectors): if a call here errors with "tool not loaded yet" or "wrong parameter names," call `tool_search({query:"ggui_consume"})` once to warm the tool, then retry with the same args. DO NOT skip the consume — silent gesture drops are the worst protocol failure. IDEMPOTENCY: treat the `actionId` on each entry as an idempotency key and apply a side-effecting action AT MOST ONCE per `actionId` — the same id delivered twice is one gesture replayed, never two. This holds for EVERY action, not only those a contract marks `oneShot`: a card served mid-rollout may be running a runtime that suppresses nothing, and keying on the marker would leave a hole exactly there. Two DISTINCT ids are two distinct gestures and both are real.',
72
72
  inputSchema,
73
73
  outputSchema,
74
74
  async handler(rawInput, ctx) {
@@ -48,6 +48,15 @@
48
48
  * retention window). Client recovery: re-mount from a fresh
49
49
  * snapshot and reset the cursor to `currentSequence`.
50
50
  *
51
+ * **The puller's obligation (ggui#1030).** `wait` MUST NOT exceed the
52
+ * `tools/call` timeout of the host relaying the call, minus a margin; a
53
+ * host that relays a pull MUST clamp the forwarded `wait` to its own
54
+ * timeout − 1 s. A host timeout below the hold is a CALLER-side failure:
55
+ * the server's `success` after the socket closed is not a server fault,
56
+ * and the rung MUST demote to sparse un-held pulls on such failures as it
57
+ * does on consecutive empties — otherwise a hot `wait` under a short host
58
+ * timeout is a polling storm that never demotes.
59
+ *
51
60
  * **Failure modes:**
52
61
  * - Unknown sessionId, cross-app sessionId, and a render deleted
53
62
  * mid-read all surface uniformly as
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-pull.d.ts","sourceRoot":"","sources":["../../src/renders/runtime-pull.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAiCjE,MAAM,WAAW,0BAA0B;IACzC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC;;;;;;;;OAQG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,0BAA0B;;;;;;IArC3E,4EAA4E;;;;;;;IAE5E,6FAA6F;;IAE7F,sFAAsF;;IAEtF,qGAAqG;;IAErG,kFAAkF;;;;;;;;;;;;;GAgInF"}
1
+ {"version":3,"file":"runtime-pull.d.ts","sourceRoot":"","sources":["../../src/renders/runtime-pull.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAiCjE,MAAM,WAAW,0BAA0B;IACzC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC;;;;;;;;OAQG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,0BAA0B;;;;;;IArC3E,4EAA4E;;;;;;;IAE5E,6FAA6F;;IAE7F,sFAAsF;;IAEtF,qGAAqG;;IAErG,kFAAkF;;;;;;;;;;;;;GAwJnF"}
@@ -48,6 +48,15 @@
48
48
  * retention window). Client recovery: re-mount from a fresh
49
49
  * snapshot and reset the cursor to `currentSequence`.
50
50
  *
51
+ * **The puller's obligation (ggui#1030).** `wait` MUST NOT exceed the
52
+ * `tools/call` timeout of the host relaying the call, minus a margin; a
53
+ * host that relays a pull MUST clamp the forwarded `wait` to its own
54
+ * timeout − 1 s. A host timeout below the hold is a CALLER-side failure:
55
+ * the server's `success` after the socket closed is not a server fault,
56
+ * and the rung MUST demote to sparse un-held pulls on such failures as it
57
+ * does on consecutive empties — otherwise a hot `wait` under a short host
58
+ * timeout is a polling storm that never demotes.
59
+ *
51
60
  * **Failure modes:**
52
61
  * - Unknown sessionId, cross-app sessionId, and a render deleted
53
62
  * mid-read all surface uniformly as
@@ -137,8 +146,14 @@ export function createGguiRuntimePullHandler(deps) {
137
146
  }
138
147
  const deadline = Date.now() + waitMs;
139
148
  // Hold loop: one immediate read, then — empty page + time left —
140
- // probe the store at `probeIntervalMs` until an event lands or
141
- // the hold elapses. The probe is a STORE read on purpose: the
149
+ // probe the store at `probeIntervalMs` until an event lands, the
150
+ // hold elapses, or the CALLER GOES AWAY (`ctx.signal`: the MCP
151
+ // cancel notification or the transport closing — ggui#1026: a
152
+ // relay that times out its own call at 5 s used to leave this
153
+ // loop probing the store into a closed socket for the full hold).
154
+ // An aborted hold resolves the empty page — never a throw — so
155
+ // the caller-side contract is the same as a hold that elapsed.
156
+ // The probe is a STORE read on purpose: the
142
157
  // event that ends this hold may be committed by another replica, and
143
158
  // the store is the only cross-replica truth available here. Horizon
144
159
  // results and non-empty pages return immediately regardless of
@@ -164,7 +179,9 @@ export function createGguiRuntimePullHandler(deps) {
164
179
  currentSequence: result.lastSequence,
165
180
  };
166
181
  }
167
- if (result.events.length > 0 || Date.now() >= deadline) {
182
+ if (result.events.length > 0 ||
183
+ Date.now() >= deadline ||
184
+ ctx.signal?.aborted === true) {
168
185
  // Events to deliver, or the hold elapsed — an empty page
169
186
  // after a full hold is a NORMAL result (the client stays
170
187
  // subscribed by immediately re-pulling).
@@ -175,8 +192,24 @@ export function createGguiRuntimePullHandler(deps) {
175
192
  hasMore: result.hasMore,
176
193
  };
177
194
  }
195
+ // Sleep one probe interval, or less: the caller aborting ends
196
+ // the wait immediately (the loop then returns the empty page).
178
197
  await new Promise((resolve) => {
179
- setTimeout(resolve, probeIntervalMs);
198
+ const signal = ctx.signal;
199
+ const onAbort = () => {
200
+ clearTimeout(timer);
201
+ resolve();
202
+ };
203
+ const timer = setTimeout(() => {
204
+ signal?.removeEventListener('abort', onAbort);
205
+ resolve();
206
+ }, probeIntervalMs);
207
+ if (signal !== undefined) {
208
+ if (signal.aborted)
209
+ onAbort();
210
+ else
211
+ signal.addEventListener('abort', onAbort, { once: true });
212
+ }
180
213
  });
181
214
  }
182
215
  },
@@ -288,7 +288,15 @@ export declare function deriveBundleOrigins(item: GguiSession): {
288
288
  * doesn't need to know about CSP directive serialization details;
289
289
  * this is the one place that maps the buckets to header syntax.
290
290
  */
291
- export declare function composeContentSecurityPolicy(origins: ReturnType<typeof deriveBundleOrigins>): string | undefined;
291
+ export declare function composeContentSecurityPolicy(origins: ReturnType<typeof deriveBundleOrigins>,
292
+ /**
293
+ * The render's stored theme (ggui#1093): a declared face's origin is
294
+ * admitted under `font-src`, an imagery slot's under `img-src`. The
295
+ * schema already guarantees `https:` + a well-formed host, so the
296
+ * origin is read, never re-validated. Absent, or a theme declaring
297
+ * neither, leaves the CSP byte-identical to the gadget-only form.
298
+ */
299
+ theme?: Pick<AppTheme, 'fonts' | 'imagery'>): string | undefined;
292
300
  /**
293
301
  * JSON-stringify the active render's `props` field. Returns
294
302
  * `undefined` when no props are present or when serialization fails
@@ -1 +1 @@
1
- {"version":3,"file":"slice-meta-derivation.d.ts","sourceRoot":"","sources":["../../src/renders/slice-meta-derivation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"slice-meta-derivation.d.ts","sourceRoot":"","sources":["../../src/renders/slice-meta-derivation.ts"],"names":[],"mappings":"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"}
@@ -499,24 +499,45 @@ export function deriveBundleOrigins(item) {
499
499
  * doesn't need to know about CSP directive serialization details;
500
500
  * this is the one place that maps the buckets to header syntax.
501
501
  */
502
- export function composeContentSecurityPolicy(origins) {
503
- if (origins === undefined)
504
- return undefined;
502
+ export function composeContentSecurityPolicy(origins,
503
+ /**
504
+ * The render's stored theme (ggui#1093): a declared face's origin is
505
+ * admitted under `font-src`, an imagery slot's under `img-src`. The
506
+ * schema already guarantees `https:` + a well-formed host, so the
507
+ * origin is read, never re-validated. Absent, or a theme declaring
508
+ * neither, leaves the CSP byte-identical to the gadget-only form.
509
+ */
510
+ theme) {
505
511
  const directives = [];
506
- if (origins.script.length > 0) {
512
+ if (origins !== undefined && origins.script.length > 0) {
507
513
  directives.push(`script-src 'self' 'unsafe-inline' ${origins.script.join(' ')}`);
508
514
  }
509
- if (origins.style.length > 0) {
515
+ if (origins !== undefined && origins.style.length > 0) {
510
516
  directives.push(`style-src 'self' 'unsafe-inline' ${origins.style.join(' ')}`);
511
517
  }
512
- if (origins.connect.length > 0) {
518
+ if (origins !== undefined && origins.connect.length > 0) {
513
519
  directives.push(`connect-src 'self' ${origins.connect.join(' ')}`);
514
- directives.push(`img-src 'self' data: ${origins.connect.join(' ')}`);
520
+ }
521
+ // `img-src` is the union of the connect origins (a gadget's tiles)
522
+ // and the theme's imagery origins — deduped, declaration order.
523
+ const imageOrigins = dedupe([
524
+ ...(origins?.connect ?? []),
525
+ ...Object.values(theme?.imagery ?? {}).flatMap((slot) => slot !== undefined ? [new URL(slot.src).origin] : []),
526
+ ]);
527
+ if (imageOrigins.length > 0) {
528
+ directives.push(`img-src 'self' data: ${imageOrigins.join(' ')}`);
529
+ }
530
+ const fontOrigins = dedupe((theme?.fonts ?? []).map((face) => new URL(face.src).origin));
531
+ if (fontOrigins.length > 0) {
532
+ directives.push(`font-src 'self' data: ${fontOrigins.join(' ')}`);
515
533
  }
516
534
  if (directives.length === 0)
517
535
  return undefined;
518
536
  return directives.join('; ');
519
537
  }
538
+ function dedupe(values) {
539
+ return [...new Set(values)];
540
+ }
520
541
  /**
521
542
  * JSON-stringify the active render's `props` field. Returns
522
543
  * `undefined` when no props are present or when serialization fails
@@ -784,12 +805,14 @@ export function deriveRenderMeta(item) {
784
805
  // Component variant.
785
806
  const slots = deriveContextSlots(item);
786
807
  const permissionsPolicy = derivePermissionsPolicy(item);
787
- const contentSecurityPolicy = composeContentSecurityPolicy(deriveBundleOrigins(item));
788
- const gadgets = deriveGadgetRegistrations(item);
789
808
  // Per-app theme overlay (sidecar). Component-only for this stage —
790
809
  // system cards theme via the SystemCardHost→ThemeProvider path, not
791
810
  // this slice, so `SystemGguiSession` never carries a `theme` sidecar.
811
+ // Derived before the CSP: the theme's faces and imagery are inputs to
812
+ // it (ggui#1093).
792
813
  const theme = deriveTheme(item);
814
+ const contentSecurityPolicy = composeContentSecurityPolicy(deriveBundleOrigins(item), theme);
815
+ const gadgets = deriveGadgetRegistrations(item);
793
816
  const codeB64 = deriveCodeB64(item);
794
817
  return {
795
818
  // History head epoch (#483) — the mount reads this as its OWN
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggui-ai/mcp-server-handlers",
3
- "version": "0.16.0",
3
+ "version": "0.18.0",
4
4
  "description": "MCP tool handler logic for the ggui protocol. Pure over @ggui-ai/mcp-server-core seams and consumed by @ggui-ai/mcp-server. Never imports AWS, HTTP transports, or CLI concerns.",
5
5
  "keywords": [
6
6
  "ggui",
@@ -70,18 +70,18 @@
70
70
  "dependencies": {
71
71
  "canonicalize": "^2.0.0",
72
72
  "zod": "^4.3.6",
73
- "@ggui-ai/mcp-server-core": "0.16.0",
74
- "@ggui-ai/negotiator": "0.16.0",
75
- "@ggui-ai/protocol": "0.16.0",
76
- "@ggui-ai/ui-gen": "0.16.0",
77
- "@ggui-ai/ui-registry": "0.16.0"
73
+ "@ggui-ai/mcp-server-core": "0.18.0",
74
+ "@ggui-ai/negotiator": "0.18.0",
75
+ "@ggui-ai/ui-gen": "0.18.0",
76
+ "@ggui-ai/protocol": "0.18.0",
77
+ "@ggui-ai/ui-registry": "0.18.0"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@types/node": "^22.0.0",
81
81
  "typescript": "^5.0.0",
82
82
  "vitest": "^3.2.6",
83
- "@ggui-ai/embedding-local": "0.16.0",
84
- "@ggui-ai/protocol-conformance": "0.16.0"
83
+ "@ggui-ai/embedding-local": "0.18.0",
84
+ "@ggui-ai/protocol-conformance": "0.18.0"
85
85
  },
86
86
  "repository": {
87
87
  "type": "git",