@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.
- package/dist/ops-apps/set-app-theme.d.ts +129 -0
- package/dist/ops-apps/set-app-theme.d.ts.map +1 -1
- package/dist/ops-apps/set-app-theme.js +10 -2
- package/dist/ops-blueprint/generate.d.ts +1 -0
- package/dist/ops-blueprint/generate.d.ts.map +1 -1
- package/dist/ops-blueprint/generate.js +30 -3
- package/dist/ops-blueprint/register.d.ts.map +1 -1
- package/dist/ops-blueprint/register.js +16 -6
- package/dist/renders/consume.js +1 -1
- package/dist/renders/runtime-pull.d.ts +9 -0
- package/dist/renders/runtime-pull.d.ts.map +1 -1
- package/dist/renders/runtime-pull.js +37 -4
- package/dist/renders/slice-meta-derivation.d.ts +9 -1
- package/dist/renders/slice-meta-derivation.d.ts.map +1 -1
- package/dist/renders/slice-meta-derivation.js +32 -9
- package/package.json +8 -8
|
@@ -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,
|
|
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;
|
|
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:
|
|
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.
|
|
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;;;;;;;;;;;;;;;;;;;
|
|
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.
|
package/dist/renders/consume.js
CHANGED
|
@@ -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
|
|
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
|
|
141
|
-
//
|
|
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 ||
|
|
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
|
-
|
|
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
|
|
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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,EAKL,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAGL,KAAK,sBAAsB,EAC5B,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAMhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,CACZ,IAAI,CACF,gBAAgB,EAChB,WAAW,GAAG,YAAY,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAChE,CACF,GACA;IAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAY7D;AA6ED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GACzC,OAAO,CAAC,WAAW,CAAC,CAoCtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,WAAW,GAChB,aAAa,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,SAAS,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC,GAAG,SAAS,CA+Cb;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,WAAW,GAChB,SAAS,MAAM,EAAE,GAAG,SAAS,CA4B/B;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAEnE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,WAAW,GAChB;IAAE,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,CA+DjG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,
|
|
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
|
-
|
|
504
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
74
|
-
"@ggui-ai/negotiator": "0.
|
|
75
|
-
"@ggui-ai/
|
|
76
|
-
"@ggui-ai/
|
|
77
|
-
"@ggui-ai/ui-registry": "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.
|
|
84
|
-
"@ggui-ai/protocol-conformance": "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",
|