@ggui-ai/mcp-server-handlers 0.24.0 → 0.26.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/README.md +2 -2
- package/dist/blueprints/search-blueprints.d.ts +5 -5
- package/dist/blueprints/search-blueprints.js +5 -5
- package/dist/credits/index.d.ts +2 -2
- package/dist/credits/index.d.ts.map +1 -1
- package/dist/credits/index.js +1 -1
- package/dist/credits/list-credit-transactions.d.ts +21 -7
- package/dist/credits/list-credit-transactions.d.ts.map +1 -1
- package/dist/credits/list-credit-transactions.js +12 -2
- package/dist/index.d.ts +2 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -9
- package/dist/ops-apps/create-app.d.ts +10 -11
- package/dist/ops-apps/create-app.d.ts.map +1 -1
- package/dist/ops-apps/create-app.js +12 -13
- package/dist/ops-apps/identity.d.ts +9 -8
- package/dist/ops-apps/identity.d.ts.map +1 -1
- package/dist/ops-apps/identity.js +2 -1
- package/dist/ops-apps/index.d.ts +2 -2
- package/dist/ops-apps/index.js +2 -2
- package/dist/ops-apps/list-apps.d.ts +5 -6
- package/dist/ops-apps/list-apps.d.ts.map +1 -1
- package/dist/ops-apps/list-apps.js +6 -7
- package/dist/ops-apps/set-app-theme.d.ts +12 -8
- package/dist/ops-apps/set-app-theme.d.ts.map +1 -1
- package/dist/ops-apps/set-app-theme.js +11 -7
- package/dist/ops-apps/set-default-app.d.ts +1 -2
- package/dist/ops-apps/set-default-app.d.ts.map +1 -1
- package/dist/ops-apps/set-default-app.js +1 -2
- package/dist/ops-apps/types.d.ts +20 -23
- package/dist/ops-apps/types.d.ts.map +1 -1
- package/dist/ops-apps/types.js +4 -6
- package/dist/ops-blueprint/cache-mirror.d.ts +41 -0
- package/dist/ops-blueprint/cache-mirror.d.ts.map +1 -0
- package/dist/ops-blueprint/cache-mirror.js +19 -0
- package/dist/ops-blueprint/delete.d.ts +18 -0
- package/dist/ops-blueprint/delete.d.ts.map +1 -1
- package/dist/ops-blueprint/delete.js +21 -2
- package/dist/ops-blueprint/errors.d.ts +23 -0
- package/dist/ops-blueprint/errors.d.ts.map +1 -1
- package/dist/ops-blueprint/errors.js +29 -0
- package/dist/ops-blueprint/generate.d.ts +1 -3
- package/dist/ops-blueprint/generate.d.ts.map +1 -1
- package/dist/ops-blueprint/generate.js +47 -58
- package/dist/ops-blueprint/index.d.ts +1 -1
- package/dist/ops-blueprint/index.d.ts.map +1 -1
- package/dist/ops-blueprint/index.js +1 -1
- package/dist/ops-blueprint/list.d.ts.map +1 -1
- package/dist/ops-blueprint/list.js +1 -2
- package/dist/ops-blueprint/register.d.ts +83 -6
- package/dist/ops-blueprint/register.d.ts.map +1 -1
- package/dist/ops-blueprint/register.js +261 -158
- package/dist/ops-blueprint/update.d.ts +3 -2
- package/dist/ops-blueprint/update.d.ts.map +1 -1
- package/dist/ops-blueprint/update.js +4 -3
- package/dist/renders/blueprint-coverage.d.ts +23 -4
- package/dist/renders/blueprint-coverage.d.ts.map +1 -1
- package/dist/renders/blueprint-coverage.js +45 -5
- package/dist/renders/blueprint-durability.d.ts.map +1 -1
- package/dist/renders/blueprint-durability.js +36 -21
- package/dist/renders/blueprint-matcher.d.ts +57 -7
- package/dist/renders/blueprint-matcher.d.ts.map +1 -1
- package/dist/renders/blueprint-matcher.js +154 -36
- package/dist/renders/blueprint-registry.d.ts +154 -1
- package/dist/renders/blueprint-registry.d.ts.map +1 -1
- package/dist/renders/blueprint-registry.js +337 -10
- package/dist/renders/build-seed-pool.d.ts.map +1 -1
- package/dist/renders/build-seed-pool.js +6 -0
- package/dist/renders/cache-trace-sink.d.ts +12 -0
- package/dist/renders/cache-trace-sink.d.ts.map +1 -1
- package/dist/renders/cache-trace-sink.js +15 -1
- package/dist/renders/consume.d.ts +3 -2
- package/dist/renders/consume.d.ts.map +1 -1
- package/dist/renders/consume.js +50 -15
- package/dist/renders/cross-app-refused.d.ts +17 -0
- package/dist/renders/cross-app-refused.d.ts.map +1 -0
- package/dist/renders/cross-app-refused.js +23 -0
- package/dist/renders/decide-handshake.d.ts +47 -1
- package/dist/renders/decide-handshake.d.ts.map +1 -1
- package/dist/renders/decide-handshake.js +74 -6
- package/dist/renders/declare-tool-catalog.d.ts.map +1 -1
- package/dist/renders/declare-tool-catalog.js +20 -17
- package/dist/renders/export-registry.d.ts +8 -1
- package/dist/renders/export-registry.d.ts.map +1 -1
- package/dist/renders/export-registry.js +3 -0
- package/dist/renders/fits.d.ts +60 -0
- package/dist/renders/fits.d.ts.map +1 -0
- package/dist/renders/fits.js +114 -0
- package/dist/renders/handshake-generation-inputs.d.ts +89 -0
- package/dist/renders/handshake-generation-inputs.d.ts.map +1 -0
- package/dist/renders/handshake-generation-inputs.js +65 -0
- package/dist/renders/handshake.d.ts +6 -42
- package/dist/renders/handshake.d.ts.map +1 -1
- package/dist/renders/handshake.js +1 -1
- package/dist/renders/index.d.ts +10 -5
- package/dist/renders/index.d.ts.map +1 -1
- package/dist/renders/index.js +10 -3
- package/dist/renders/installed-blueprints-provider.d.ts.map +1 -1
- package/dist/renders/installed-blueprints-provider.js +3 -1
- package/dist/renders/match-precision/pairs.d.ts +6 -5
- package/dist/renders/match-precision/pairs.d.ts.map +1 -1
- package/dist/renders/match-precision/run-probe.js +1 -2
- package/dist/renders/match-precision/topk-probe.js +13 -8
- package/dist/renders/record-committed-one-shot.d.ts +18 -3
- package/dist/renders/record-committed-one-shot.d.ts.map +1 -1
- package/dist/renders/record-committed-one-shot.js +14 -7
- package/dist/renders/refresh-ws-token.d.ts +66 -87
- package/dist/renders/refresh-ws-token.d.ts.map +1 -1
- package/dist/renders/refresh-ws-token.js +93 -89
- package/dist/renders/render-identity.d.ts +16 -5
- package/dist/renders/render-identity.d.ts.map +1 -1
- package/dist/renders/render-identity.js +26 -10
- package/dist/renders/render-read-gate.d.ts +85 -0
- package/dist/renders/render-read-gate.d.ts.map +1 -0
- package/dist/renders/render-read-gate.js +57 -0
- package/dist/renders/render.d.ts +77 -27
- package/dist/renders/render.d.ts.map +1 -1
- package/dist/renders/render.js +269 -95
- package/dist/renders/report-render-failure.d.ts +69 -0
- package/dist/renders/report-render-failure.d.ts.map +1 -0
- package/dist/renders/report-render-failure.js +83 -0
- package/dist/renders/runtime-pull.d.ts.map +1 -1
- package/dist/renders/runtime-pull.js +6 -0
- package/dist/renders/slice-meta-derivation.d.ts +8 -1
- package/dist/renders/slice-meta-derivation.d.ts.map +1 -1
- package/dist/renders/slice-meta-derivation.js +1 -0
- package/dist/renders/submit-action.d.ts +47 -78
- package/dist/renders/submit-action.d.ts.map +1 -1
- package/dist/renders/submit-action.js +312 -84
- package/dist/renders/sync-context.d.ts +3 -1
- package/dist/renders/sync-context.d.ts.map +1 -1
- package/dist/renders/sync-context.js +53 -20
- package/dist/types.d.ts +71 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +32 -0
- package/package.json +8 -20
- package/dist/ops-connector-keys/in-memory-fake.test-util.d.ts +0 -26
- package/dist/ops-connector-keys/in-memory-fake.test-util.d.ts.map +0 -1
- package/dist/ops-connector-keys/in-memory-fake.test-util.js +0 -60
- package/dist/ops-connector-keys/index.d.ts +0 -19
- package/dist/ops-connector-keys/index.d.ts.map +0 -1
- package/dist/ops-connector-keys/index.js +0 -14
- package/dist/ops-connector-keys/issue-connector-key.d.ts +0 -76
- package/dist/ops-connector-keys/issue-connector-key.d.ts.map +0 -1
- package/dist/ops-connector-keys/issue-connector-key.js +0 -84
- package/dist/ops-connector-keys/list-connector-keys.d.ts +0 -58
- package/dist/ops-connector-keys/list-connector-keys.d.ts.map +0 -1
- package/dist/ops-connector-keys/list-connector-keys.js +0 -39
- package/dist/ops-connector-keys/revoke-connector-key.d.ts +0 -32
- package/dist/ops-connector-keys/revoke-connector-key.d.ts.map +0 -1
- package/dist/ops-connector-keys/revoke-connector-key.js +0 -49
- package/dist/ops-connector-keys/types.d.ts +0 -91
- package/dist/ops-connector-keys/types.d.ts.map +0 -1
- package/dist/ops-connector-keys/types.js +0 -24
- package/dist/ops-coupon/in-memory-fake.test-util.d.ts +0 -28
- package/dist/ops-coupon/in-memory-fake.test-util.d.ts.map +0 -1
- package/dist/ops-coupon/in-memory-fake.test-util.js +0 -66
- package/dist/ops-coupon/index.d.ts +0 -15
- package/dist/ops-coupon/index.d.ts.map +0 -1
- package/dist/ops-coupon/index.js +0 -12
- package/dist/ops-coupon/redeem-coupon.d.ts +0 -51
- package/dist/ops-coupon/redeem-coupon.d.ts.map +0 -1
- package/dist/ops-coupon/redeem-coupon.js +0 -61
- package/dist/ops-coupon/types.d.ts +0 -59
- package/dist/ops-coupon/types.d.ts.map +0 -1
- package/dist/ops-coupon/types.js +0 -38
- package/dist/ops-orgs/create-org.d.ts +0 -45
- package/dist/ops-orgs/create-org.d.ts.map +0 -1
- package/dist/ops-orgs/create-org.js +0 -55
- package/dist/ops-orgs/get-org-balance.d.ts +0 -29
- package/dist/ops-orgs/get-org-balance.d.ts.map +0 -1
- package/dist/ops-orgs/get-org-balance.js +0 -45
- package/dist/ops-orgs/in-memory-fake.test-util.d.ts +0 -84
- package/dist/ops-orgs/in-memory-fake.test-util.d.ts.map +0 -1
- package/dist/ops-orgs/in-memory-fake.test-util.js +0 -209
- package/dist/ops-orgs/index.d.ts +0 -33
- package/dist/ops-orgs/index.d.ts.map +0 -1
- package/dist/ops-orgs/index.js +0 -24
- package/dist/ops-orgs/invite-to-org.d.ts +0 -56
- package/dist/ops-orgs/invite-to-org.d.ts.map +0 -1
- package/dist/ops-orgs/invite-to-org.js +0 -72
- package/dist/ops-orgs/list-orgs.d.ts +0 -53
- package/dist/ops-orgs/list-orgs.d.ts.map +0 -1
- package/dist/ops-orgs/list-orgs.js +0 -38
- package/dist/ops-orgs/remove-org-member.d.ts +0 -42
- package/dist/ops-orgs/remove-org-member.d.ts.map +0 -1
- package/dist/ops-orgs/remove-org-member.js +0 -67
- package/dist/ops-orgs/rename-org.d.ts +0 -33
- package/dist/ops-orgs/rename-org.d.ts.map +0 -1
- package/dist/ops-orgs/rename-org.js +0 -57
- package/dist/ops-orgs/revoke-invite.d.ts +0 -38
- package/dist/ops-orgs/revoke-invite.d.ts.map +0 -1
- package/dist/ops-orgs/revoke-invite.js +0 -53
- package/dist/ops-orgs/types.d.ts +0 -209
- package/dist/ops-orgs/types.d.ts.map +0 -1
- package/dist/ops-orgs/types.js +0 -60
|
@@ -42,8 +42,7 @@ const opsOutputSchema = {
|
|
|
42
42
|
};
|
|
43
43
|
/**
|
|
44
44
|
* Sort blueprints by `createdAt desc`, then `blueprintId asc` as
|
|
45
|
-
* stable tiebreaker.
|
|
46
|
-
* ladder ordering (see `@ggui-ai/mcp-server-core/blueprint-selector`).
|
|
45
|
+
* stable tiebreaker.
|
|
47
46
|
*/
|
|
48
47
|
function sortBlueprintsByCreatedAtDesc(rows) {
|
|
49
48
|
return [...rows].sort((a, b) => {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Sibling of `ggui_ops_generate_blueprint`. Same persistence seams +
|
|
6
6
|
* dual-write (BlueprintStore + cache vectorStore via registerBlueprint),
|
|
7
|
-
* same variance + default
|
|
7
|
+
* same variance + operator-default mark semantics. The only difference is the
|
|
8
8
|
* code body: instead of dispatching through `generator.generate(...)`
|
|
9
9
|
* to produce componentCode, the operator supplies the bytes directly
|
|
10
10
|
* and the handler persists them verbatim.
|
|
@@ -36,16 +36,19 @@
|
|
|
36
36
|
* ops_generate — schema-compat + hygiene-3 lint live elsewhere.
|
|
37
37
|
*/
|
|
38
38
|
import type { AppMetadataStore, BlueprintStore, TelemetrySink } from "@ggui-ai/mcp-server-core";
|
|
39
|
-
import { type Blueprint, type DataContract, type UserBlueprintSource } from "@ggui-ai/protocol";
|
|
39
|
+
import { type Blueprint, type DataContract, type GeneratorBuild, type LlmBlueprintSource, type UserBlueprintSource } from "@ggui-ai/protocol";
|
|
40
40
|
import { z } from "zod";
|
|
41
41
|
import { type BlueprintRegistryDeps } from "../renders/index.js";
|
|
42
|
+
import { type HandlerContext } from "../types.js";
|
|
42
43
|
import { type OpsBlueprintAppAuthorizer } from "./app-access.js";
|
|
43
44
|
import type { PutCodeHook } from "./generate.js";
|
|
44
45
|
/**
|
|
45
|
-
* Deps
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* no slug to resolve
|
|
46
|
+
* Deps shared by `ggui_ops_register_blueprint` and the in-process
|
|
47
|
+
* {@link createRegisterGeneratedBlueprint}. Mirrors `*_generate_*`'s deps
|
|
48
|
+
* minus `resolveLlm`, `blueprints` and `registry`: neither entry dispatches
|
|
49
|
+
* a generator, so there is no slug to resolve. The operator door stamps
|
|
50
|
+
* `{kind: 'user'}`; the generated entry takes the generation's own `llm`
|
|
51
|
+
* record.
|
|
49
52
|
*/
|
|
50
53
|
export interface GguiOpsRegisterBlueprintDeps {
|
|
51
54
|
/**
|
|
@@ -117,7 +120,19 @@ export declare function createGguiOpsRegisterBlueprintHandler(deps: GguiOpsRegis
|
|
|
117
120
|
aesthetic: z.ZodOptional<z.ZodString>;
|
|
118
121
|
context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<import("@ggui-ai/protocol").JsonValue, unknown, z.core.$ZodTypeInternals<import("@ggui-ai/protocol").JsonValue, unknown>>>>;
|
|
119
122
|
seedPrompt: z.ZodOptional<z.ZodString>;
|
|
123
|
+
intent: z.ZodOptional<z.ZodString>;
|
|
124
|
+
judgedCanvases: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
125
|
+
aestheticPreset: z.ZodOptional<z.ZodObject<{
|
|
126
|
+
id: z.ZodString;
|
|
127
|
+
version: z.ZodOptional<z.ZodString>;
|
|
128
|
+
}, z.core.$strict>>;
|
|
129
|
+
directionDigest: z.ZodOptional<z.ZodString>;
|
|
130
|
+
directionScope: z.ZodOptional<z.ZodEnum<{
|
|
131
|
+
app: "app";
|
|
132
|
+
request: "request";
|
|
133
|
+
}>>;
|
|
120
134
|
setAsOperatorDefault: z.ZodOptional<z.ZodBoolean>;
|
|
135
|
+
clonedFrom: z.ZodOptional<z.ZodString>;
|
|
121
136
|
}, {
|
|
122
137
|
blueprintId: z.ZodString;
|
|
123
138
|
codeHash: z.ZodString;
|
|
@@ -129,4 +144,66 @@ export declare function createGguiOpsRegisterBlueprintHandler(deps: GguiOpsRegis
|
|
|
129
144
|
codeHash: string;
|
|
130
145
|
source: UserBlueprintSource;
|
|
131
146
|
}>;
|
|
147
|
+
/**
|
|
148
|
+
* Engine-generated bytes and the authored source they were compiled
|
|
149
|
+
* from — what {@link createRegisterGeneratedBlueprint} registers.
|
|
150
|
+
*/
|
|
151
|
+
export interface GeneratedBlueprintBytes {
|
|
152
|
+
/**
|
|
153
|
+
* The authored (pre-compile) source that `componentCode` was compiled
|
|
154
|
+
* from. **Caller obligation:** it MUST be that exact pair, produced by
|
|
155
|
+
* one generation (for example, the authored `.tsx` a generation wrote
|
|
156
|
+
* and the module compiled from it). Nothing here recompiles it to check — that is why
|
|
157
|
+
* this entry is in-process only and the public operator door takes no
|
|
158
|
+
* source. A pair that is byte-identical records no source (the
|
|
159
|
+
* registry's collapse rule), which is the honest answer for a
|
|
160
|
+
* generation that produced no distinct authored form.
|
|
161
|
+
*/
|
|
162
|
+
readonly sourceCode: string;
|
|
163
|
+
/**
|
|
164
|
+
* The generation's own provenance, read from what the generation itself
|
|
165
|
+
* reported — never a placeholder or a configured default. An `llm` record with a guessed model is a provenance
|
|
166
|
+
* claim nobody made. Validated against the protocol's schema.
|
|
167
|
+
*/
|
|
168
|
+
readonly source: LlmBlueprintSource;
|
|
169
|
+
/**
|
|
170
|
+
* ggui#1280 — the build the generation reported (`metadata.build`),
|
|
171
|
+
* verbatim. Admitted by the registry's one rule (`admitGeneratorBuild`):
|
|
172
|
+
* a stamp that fails the protocol's `generatorBuildSchema` is dropped
|
|
173
|
+
* with a `blueprint_build_stamp_dropped` line and the row registers
|
|
174
|
+
* unstamped, so a bad stamp never refuses a registration.
|
|
175
|
+
*/
|
|
176
|
+
readonly build?: GeneratorBuild;
|
|
177
|
+
}
|
|
178
|
+
/** What {@link createRegisterGeneratedBlueprint}'s entry returns. */
|
|
179
|
+
export interface RegisterGeneratedBlueprintOutput {
|
|
180
|
+
readonly blueprintId: string;
|
|
181
|
+
readonly codeHash: string;
|
|
182
|
+
readonly source: LlmBlueprintSource;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* The in-process generated-bytes registration entry. `input` is the same
|
|
186
|
+
* RAW input `ggui_ops_register_blueprint` takes — parsed with its schema
|
|
187
|
+
* on entry, so a value the schema refuses throws, exactly as it would
|
|
188
|
+
* through the operator door.
|
|
189
|
+
*/
|
|
190
|
+
export type RegisterGeneratedBlueprint = (input: Record<string, unknown>, generated: GeneratedBlueprintBytes, ctx: HandlerContext) => Promise<RegisterGeneratedBlueprintOutput>;
|
|
191
|
+
/**
|
|
192
|
+
* ggui#1493 (ggui#1477's source half) — register ENGINE-GENERATED bytes
|
|
193
|
+
* with the authored source they were compiled from, in-process.
|
|
194
|
+
*
|
|
195
|
+
* Same body as `ggui_ops_register_blueprint` (one durable row, one cache
|
|
196
|
+
* mirror, the same gates and variance), with three differences: provenance
|
|
197
|
+
* is the generation's `llm` arm; the authored source reaches the cache
|
|
198
|
+
* registry, so a render that reuses the registration serves it
|
|
199
|
+
* (`ggui_get_render_source`, save-to-library); and the generation's build,
|
|
200
|
+
* when the caller passes one, is stamped on the durable rows (ggui#1280).
|
|
201
|
+
* It is NOT an MCP tool and
|
|
202
|
+
* is on no wire: the public operator door stays source-free, because it
|
|
203
|
+
* cannot verify that supplied source compiles to the supplied code.
|
|
204
|
+
*
|
|
205
|
+
* Refuses, before anything is persisted, provenance the protocol's
|
|
206
|
+
* `llmBlueprintSourceSchema` rejects and an empty `sourceCode`.
|
|
207
|
+
*/
|
|
208
|
+
export declare function createRegisterGeneratedBlueprint(deps: GguiOpsRegisterBlueprintDeps): RegisterGeneratedBlueprint;
|
|
132
209
|
//# sourceMappingURL=register.d.ts.map
|
|
@@ -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,
|
|
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,EAGL,KAAK,SAAS,EAEd,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EAGvB,KAAK,mBAAmB,EACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAuB,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEtF,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAyB,KAAK,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AACxF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAkBjD;;;;;;;GAOG;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;AA0QD,wBAAgB,qCAAqC,CACnD,IAAI,EAAE,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BnC;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;;;;;;OASG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,qEAAqE;AACrE,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;CACrC;AAED;;;;;GAKG;AACH,MAAM,MAAM,0BAA0B,GAAG,CACvC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,uBAAuB,EAClC,GAAG,EAAE,cAAc,KAChB,OAAO,CAAC,gCAAgC,CAAC,CAAC;AAE/C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,4BAA4B,GACjC,0BAA0B,CAkB5B"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Sibling of `ggui_ops_generate_blueprint`. Same persistence seams +
|
|
6
6
|
* dual-write (BlueprintStore + cache vectorStore via registerBlueprint),
|
|
7
|
-
* same variance + default
|
|
7
|
+
* same variance + operator-default mark semantics. The only difference is the
|
|
8
8
|
* code body: instead of dispatching through `generator.generate(...)`
|
|
9
9
|
* to produce componentCode, the operator supplies the bytes directly
|
|
10
10
|
* and the handler persists them verbatim.
|
|
@@ -35,15 +35,17 @@
|
|
|
35
35
|
* - Validate the contract beyond Zod parsing. Same posture as
|
|
36
36
|
* ops_generate — schema-compat + hygiene-3 lint live elsewhere.
|
|
37
37
|
*/
|
|
38
|
-
import { opsRegisterBlueprintInputSchema, } from "@ggui-ai/protocol";
|
|
38
|
+
import { llmBlueprintSourceSchema, opsRegisterBlueprintInputSchema, } from "@ggui-ai/protocol";
|
|
39
39
|
import { blueprintKey } from "@ggui-ai/protocol/blueprint-key";
|
|
40
40
|
import { createHash, randomUUID } from "node:crypto";
|
|
41
41
|
import { z } from "zod";
|
|
42
42
|
import { assertContractNoRetiredFields } from "../renders/assert-contract-no-retired-fields.js";
|
|
43
43
|
import { assertGadgetsRegistered } from "../renders/assert-gadgets.js";
|
|
44
|
-
import {
|
|
44
|
+
import { admitGeneratorBuild } from "../renders/index.js";
|
|
45
|
+
import { mirrorIntoCache } from "./cache-mirror.js";
|
|
45
46
|
import { defineHandler } from "../types.js";
|
|
46
47
|
import { resolveEffectiveAppId } from "./app-access.js";
|
|
48
|
+
import { ClonedFromRefusedError, DirectionScopeWithoutDigestError } from "./errors.js";
|
|
47
49
|
import { findNearDuplicatePersona, normalizePersona } from "./persona-normalization.js";
|
|
48
50
|
const opsInputSchema = opsRegisterBlueprintInputSchema.shape;
|
|
49
51
|
const opsOutputSchema = z.object({
|
|
@@ -57,153 +59,58 @@ const opsOutputSchema = z.object({
|
|
|
57
59
|
* no engine claim because none exists to record.
|
|
58
60
|
*/
|
|
59
61
|
const USER_SOURCE = { kind: "user" };
|
|
60
|
-
|
|
62
|
+
/**
|
|
63
|
+
* The registration body both entries share: app resolution, the
|
|
64
|
+
* contract gates, the durable row, the cache mirror, the operator-default mark and
|
|
65
|
+
* the event. The two entries differ only in the provenance they pass.
|
|
66
|
+
*/
|
|
67
|
+
function makeRegisterCore(deps) {
|
|
61
68
|
const now = deps.now ?? (() => new Date().toISOString());
|
|
62
69
|
const mintBlueprintId = deps.mintBlueprintId ?? (() => `bp_${randomUUID()}`);
|
|
63
|
-
return
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (normalizedPersona !== undefined && deps.listAllForApp) {
|
|
98
|
-
try {
|
|
99
|
-
const allForApp = await deps.listAllForApp(appId);
|
|
100
|
-
const existingPersonas = allForApp
|
|
101
|
-
.map((bp) => bp.variance.persona)
|
|
102
|
-
.filter((p) => typeof p === "string");
|
|
103
|
-
const dup = findNearDuplicatePersona(normalizedPersona, existingPersonas);
|
|
104
|
-
if (dup && dup.nearestExisting !== null) {
|
|
105
|
-
try {
|
|
106
|
-
deps.telemetry?.emit({
|
|
107
|
-
name: "near-duplicate-persona",
|
|
108
|
-
at: Date.now(),
|
|
109
|
-
attributes: {
|
|
110
|
-
appId,
|
|
111
|
-
requestId: ctx.requestId,
|
|
112
|
-
candidate: normalizedPersona,
|
|
113
|
-
existing: dup.nearestExisting,
|
|
114
|
-
distance: dup.nearestDistance,
|
|
115
|
-
},
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
// Swallow telemetry-side throws.
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
catch {
|
|
124
|
-
// Swallow enumeration failures — the near-dup warning is
|
|
125
|
-
// an early-detection signal, not a gate.
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
// 2. Compute canonical hashes.
|
|
129
|
-
const contract = parsed.contract;
|
|
130
|
-
const contractHash = blueprintKey(contract);
|
|
131
|
-
const componentCode = parsed.componentCode;
|
|
132
|
-
const codeHash = createHash("sha256").update(componentCode).digest("hex");
|
|
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
|
-
};
|
|
146
|
-
const blueprint = {
|
|
147
|
-
blueprintId,
|
|
148
|
-
contractHash,
|
|
149
|
-
appId,
|
|
150
|
-
codeHash,
|
|
151
|
-
// Operator-supplied bytes, no LLM dispatch — provenance is the
|
|
152
|
-
// user arm on BOTH stores this handler writes (MVB row here,
|
|
153
|
-
// cache mirror below). No engine claim exists to record.
|
|
154
|
-
source: USER_SOURCE,
|
|
155
|
-
variance,
|
|
156
|
-
createdAt: now(),
|
|
157
|
-
createdBy: "operator",
|
|
158
|
-
contract,
|
|
159
|
-
};
|
|
160
|
-
// 3. Persist the blueprint + code body.
|
|
161
|
-
await deps.blueprintStore.put(blueprint);
|
|
162
|
-
if (deps.putCode) {
|
|
163
|
-
await deps.putCode(codeHash, componentCode);
|
|
164
|
-
}
|
|
165
|
-
// 3.5 Mirror into the cache vectorStore so the agent-facing
|
|
166
|
-
// matchBlueprint exact-key probe (handshake + render) finds this
|
|
167
|
-
// operator-registered blueprint. Symmetric with ops_generate's
|
|
168
|
-
// dual-write — see #358.
|
|
169
|
-
if (deps.cacheRegistry) {
|
|
170
|
-
try {
|
|
171
|
-
const intentForCache = parsed.seedPrompt ??
|
|
172
|
-
normalizedPersona ??
|
|
173
|
-
`operator-registered blueprint (${blueprintId})`;
|
|
174
|
-
await registerBlueprint(deps.cacheRegistry, appId, {
|
|
175
|
-
kind: "template",
|
|
176
|
-
contract,
|
|
177
|
-
intent: intentForCache,
|
|
178
|
-
// ggui#1275 — only a seed prompt states the UI's task. A
|
|
179
|
-
// persona describes the agent and the placeholder describes
|
|
180
|
-
// nothing: both are stand-ins the matcher's judge never sees.
|
|
181
|
-
intentSource: parsed.seedPrompt !== undefined ? "authored" : "fallback",
|
|
182
|
-
componentCode,
|
|
183
|
-
// Same user-arm provenance as the MVB row above — one
|
|
184
|
-
// handler call, one provenance claim across both stores.
|
|
185
|
-
source: USER_SOURCE,
|
|
186
|
-
// The cache row MUST carry the same variance as the MVB row —
|
|
187
|
-
// its exact key is `variantKey(variance)`.
|
|
188
|
-
variance,
|
|
189
|
-
// An operator invoked this tool. Without it the durable
|
|
190
|
-
// record would claim the standard agent flow minted a row
|
|
191
|
-
// that is retained permanently.
|
|
192
|
-
createdBy: "operator",
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
catch (err) {
|
|
70
|
+
return async function registerVariant(parsed, ctx, provenance) {
|
|
71
|
+
const appId = await resolveEffectiveAppId({
|
|
72
|
+
toolName: "ggui_ops_register_blueprint",
|
|
73
|
+
inputAppId: parsed.appId,
|
|
74
|
+
ctx,
|
|
75
|
+
...(deps.authorizeAppAccess ? { authorize: deps.authorizeAppAccess } : {}),
|
|
76
|
+
});
|
|
77
|
+
// Reject retired top-level contract fields BEFORE any
|
|
78
|
+
// persistence so an operator-supplied row can't smuggle
|
|
79
|
+
// deprecated vocabulary (`terminal`, `consumeSpec`,
|
|
80
|
+
// `interaction`, `commandSpec`, `behaviorSpec`) into the
|
|
81
|
+
// registry. The same gate fires on the render + handshake seams
|
|
82
|
+
// in `renders/`.
|
|
83
|
+
assertContractNoRetiredFields(parsed.contract);
|
|
84
|
+
// Every `contract.clientCapabilities.gadgets[*]` MUST resolve
|
|
85
|
+
// in `App.gadgets` by `(package, export name)` — the wire
|
|
86
|
+
// carries no version; the operator's catalog is the version
|
|
87
|
+
// pin. Fails fast with a precise reject before any state
|
|
88
|
+
// mutation. No-op when no `appMetadataStore` is bound.
|
|
89
|
+
if (deps.appMetadataStore) {
|
|
90
|
+
const appRecord = await deps.appMetadataStore.get(appId);
|
|
91
|
+
assertGadgetsRegistered(parsed.contract, appRecord?.gadgets);
|
|
92
|
+
}
|
|
93
|
+
// 1. Normalize the persona + run near-dup detection. Same
|
|
94
|
+
// posture as ops_generate.
|
|
95
|
+
const normalizedPersona = normalizePersona(parsed.persona);
|
|
96
|
+
if (normalizedPersona !== undefined && deps.listAllForApp) {
|
|
97
|
+
try {
|
|
98
|
+
const allForApp = await deps.listAllForApp(appId);
|
|
99
|
+
const existingPersonas = allForApp
|
|
100
|
+
.map((bp) => bp.variance.persona)
|
|
101
|
+
.filter((p) => typeof p === "string");
|
|
102
|
+
const dup = findNearDuplicatePersona(normalizedPersona, existingPersonas);
|
|
103
|
+
if (dup && dup.nearestExisting !== null) {
|
|
196
104
|
try {
|
|
197
105
|
deps.telemetry?.emit({
|
|
198
|
-
name: "
|
|
106
|
+
name: "near-duplicate-persona",
|
|
199
107
|
at: Date.now(),
|
|
200
108
|
attributes: {
|
|
201
109
|
appId,
|
|
202
110
|
requestId: ctx.requestId,
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
errorMessage: err instanceof Error ? err.message : String(err),
|
|
111
|
+
candidate: normalizedPersona,
|
|
112
|
+
existing: dup.nearestExisting,
|
|
113
|
+
distance: dup.nearestDistance,
|
|
207
114
|
},
|
|
208
115
|
});
|
|
209
116
|
}
|
|
@@ -212,29 +119,191 @@ export function createGguiOpsRegisterBlueprintHandler(deps) {
|
|
|
212
119
|
}
|
|
213
120
|
}
|
|
214
121
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
122
|
+
catch {
|
|
123
|
+
// Swallow enumeration failures — the near-dup warning is
|
|
124
|
+
// an early-detection signal, not a gate.
|
|
218
125
|
}
|
|
126
|
+
}
|
|
127
|
+
// 2. Compute canonical hashes.
|
|
128
|
+
const contract = parsed.contract;
|
|
129
|
+
const contractHash = blueprintKey(contract);
|
|
130
|
+
const componentCode = parsed.componentCode;
|
|
131
|
+
const codeHash = createHash("sha256").update(componentCode).digest("hex");
|
|
132
|
+
// ggui#1427 — a scope without a digest is a scope for nothing: refused
|
|
133
|
+
// before anything is persisted (see DirectionScopeWithoutDigestError).
|
|
134
|
+
if (parsed.directionScope !== undefined && parsed.directionDigest === undefined) {
|
|
135
|
+
throw new DirectionScopeWithoutDigestError();
|
|
136
|
+
}
|
|
137
|
+
const blueprintId = mintBlueprintId();
|
|
138
|
+
// ggui#1570 — a copy (`clonedFrom`, the door's input member, which the
|
|
139
|
+
// in-process generated-bytes entry parses too) names another row of this
|
|
140
|
+
// app that the store holds. Checked after the id is minted (a copy never
|
|
141
|
+
// names itself) and before anything is persisted. The cache mirror's own
|
|
142
|
+
// durable write-through, when it writes to a store other than this one,
|
|
143
|
+
// does not carry it: that copy serves re-mint, which ignores provenance.
|
|
144
|
+
if (parsed.clonedFrom !== undefined) {
|
|
145
|
+
const parentId = parsed.clonedFrom;
|
|
146
|
+
const parent = parentId.length > 0 && parentId !== blueprintId ? await deps.blueprintStore.get(parentId) : null;
|
|
147
|
+
if (parent === null || parent.appId !== appId)
|
|
148
|
+
throw new ClonedFromRefusedError(parentId);
|
|
149
|
+
}
|
|
150
|
+
// ONE variance for BOTH stores. The cache row's exact key is
|
|
151
|
+
// `variantKey(variance)`; omitting it on the cache call filed every
|
|
152
|
+
// variant under the default-variant key, where an earlier registration
|
|
153
|
+
// of the same contract already sat — the mirror then returned THAT row
|
|
154
|
+
// and the new variant was never bound (the durable row said one thing,
|
|
155
|
+
// the served index another). Same rule as ops_generate.
|
|
156
|
+
const variance = {
|
|
157
|
+
...(normalizedPersona !== undefined ? { persona: normalizedPersona } : {}),
|
|
158
|
+
...(parsed.aesthetic !== undefined ? { aesthetic: parsed.aesthetic } : {}),
|
|
159
|
+
...(parsed.context !== undefined ? { context: parsed.context } : {}),
|
|
160
|
+
...(parsed.seedPrompt !== undefined ? { seedPrompt: parsed.seedPrompt } : {}),
|
|
161
|
+
};
|
|
162
|
+
const blueprint = {
|
|
163
|
+
blueprintId,
|
|
164
|
+
contractHash,
|
|
165
|
+
appId,
|
|
166
|
+
codeHash,
|
|
167
|
+
// The caller's provenance, on BOTH stores this call writes (MVB
|
|
168
|
+
// row here, cache mirror below): the user arm for operator-
|
|
169
|
+
// supplied bytes, the llm arm for engine-generated ones.
|
|
170
|
+
source: provenance.source,
|
|
171
|
+
// ggui#1280 — the minting build, on a generation mint's bytes only.
|
|
172
|
+
...(provenance.build !== undefined ? { build: provenance.build } : {}),
|
|
173
|
+
// ggui#1570 — provenance about the row: the row whose bytes it copies.
|
|
174
|
+
...(parsed.clonedFrom !== undefined ? { clonedFrom: parsed.clonedFrom } : {}),
|
|
175
|
+
variance,
|
|
176
|
+
createdAt: now(),
|
|
177
|
+
createdBy: "operator",
|
|
178
|
+
contract,
|
|
179
|
+
};
|
|
180
|
+
// 3. Persist the blueprint + code body.
|
|
181
|
+
await deps.blueprintStore.put(blueprint);
|
|
182
|
+
if (deps.putCode) {
|
|
183
|
+
await deps.putCode(codeHash, componentCode);
|
|
184
|
+
}
|
|
185
|
+
// 3.5 Mirror into the cache vectorStore so the agent-facing
|
|
186
|
+
// matchBlueprint exact-key probe (handshake + render) finds this
|
|
187
|
+
// operator-registered blueprint. Symmetric with ops_generate's
|
|
188
|
+
// dual-write — see #358.
|
|
189
|
+
if (deps.cacheRegistry) {
|
|
219
190
|
try {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
191
|
+
// ggui#1427 — the request's own sentence, when the caller has it
|
|
192
|
+
// (symmetric with `*_generate_*`'s `intent`): prompt-only, never
|
|
193
|
+
// part of the cache identity.
|
|
194
|
+
const intentForCache = parsed.intent ??
|
|
195
|
+
parsed.seedPrompt ??
|
|
196
|
+
normalizedPersona ??
|
|
197
|
+
`operator-registered blueprint (${blueprintId})`;
|
|
198
|
+
// ggui#1497 — ONE id per registration: the cache row serves the
|
|
199
|
+
// durable row's id (see `mirrorIntoCache` for what else it writes).
|
|
200
|
+
await mirrorIntoCache({
|
|
201
|
+
cacheRegistry: deps.cacheRegistry,
|
|
202
|
+
writerStore: deps.blueprintStore,
|
|
203
|
+
appId,
|
|
204
|
+
blueprintId,
|
|
205
|
+
input: {
|
|
206
|
+
kind: "template",
|
|
207
|
+
contract,
|
|
208
|
+
intent: intentForCache,
|
|
209
|
+
// ggui#1275 — an explicit intent or a seed prompt states the
|
|
210
|
+
// UI's task. A persona describes the agent and the placeholder
|
|
211
|
+
// describes nothing: both are stand-ins the matcher's judge
|
|
212
|
+
// never sees.
|
|
213
|
+
intentSource: parsed.intent !== undefined || parsed.seedPrompt !== undefined
|
|
214
|
+
? "authored"
|
|
215
|
+
: "fallback",
|
|
216
|
+
// ggui#1427 — the fit facts `fits()` reads before the judge
|
|
217
|
+
// ranks this row. Absent inputs write nothing (not-evaluated).
|
|
218
|
+
...(parsed.judgedCanvases !== undefined ? { judgedCanvases: parsed.judgedCanvases } : {}),
|
|
219
|
+
...(parsed.aestheticPreset !== undefined ? { aestheticPreset: parsed.aestheticPreset } : {}),
|
|
220
|
+
...(parsed.directionDigest !== undefined ? { directionDigest: parsed.directionDigest } : {}),
|
|
221
|
+
...(parsed.directionDigest !== undefined && parsed.directionScope !== undefined
|
|
222
|
+
? { directionScope: parsed.directionScope }
|
|
223
|
+
: {}),
|
|
224
|
+
componentCode,
|
|
225
|
+
// ggui#1493 — the authored form of `componentCode`, when the
|
|
226
|
+
// caller has one (the in-process generated-bytes path only).
|
|
227
|
+
// The registry persists its hash and body only when a code
|
|
228
|
+
// store is bound and the pair is not byte-identical.
|
|
229
|
+
...(provenance.sourceCode !== undefined ? { sourceCode: provenance.sourceCode } : {}),
|
|
230
|
+
// Same provenance as the MVB row above — one call, one
|
|
231
|
+
// provenance claim across both stores.
|
|
232
|
+
source: provenance.source,
|
|
233
|
+
// ggui#1280 — the same stamp, onto the durable row a mirror
|
|
234
|
+
// writes through to (never onto its vector-store row).
|
|
235
|
+
...(provenance.build !== undefined ? { build: provenance.build } : {}),
|
|
236
|
+
// The cache row MUST carry the same variance as the MVB row —
|
|
237
|
+
// its exact key is `variantKey(variance)`.
|
|
238
|
+
variance,
|
|
239
|
+
// An operator invoked this tool. Without it the durable
|
|
240
|
+
// record would claim the standard agent flow minted a row
|
|
241
|
+
// that is retained permanently.
|
|
230
242
|
createdBy: "operator",
|
|
231
|
-
setAsOperatorDefault: parsed.setAsOperatorDefault === true,
|
|
232
243
|
},
|
|
233
244
|
});
|
|
234
245
|
}
|
|
235
|
-
catch {
|
|
236
|
-
|
|
246
|
+
catch (err) {
|
|
247
|
+
try {
|
|
248
|
+
deps.telemetry?.emit({
|
|
249
|
+
name: "blueprint.cache_mirror_failed",
|
|
250
|
+
at: Date.now(),
|
|
251
|
+
attributes: {
|
|
252
|
+
appId,
|
|
253
|
+
requestId: ctx.requestId,
|
|
254
|
+
blueprintId,
|
|
255
|
+
contractHash,
|
|
256
|
+
errorClass: err instanceof Error ? err.name : "unknown",
|
|
257
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
// Swallow telemetry-side throws.
|
|
263
|
+
}
|
|
237
264
|
}
|
|
265
|
+
}
|
|
266
|
+
// 4. Mark as operator default when requested.
|
|
267
|
+
if (parsed.setAsOperatorDefault === true) {
|
|
268
|
+
await deps.blueprintStore.setOperatorDefault(blueprintId);
|
|
269
|
+
}
|
|
270
|
+
try {
|
|
271
|
+
deps.telemetry?.emit({
|
|
272
|
+
name: "blueprint.registered",
|
|
273
|
+
at: Date.now(),
|
|
274
|
+
attributes: {
|
|
275
|
+
appId,
|
|
276
|
+
requestId: ctx.requestId,
|
|
277
|
+
blueprintId,
|
|
278
|
+
contractHash,
|
|
279
|
+
// Flat-codec provenance key — 'user' on the operator door,
|
|
280
|
+
// 'llm' on the generated-bytes path.
|
|
281
|
+
sourceKind: provenance.source.kind,
|
|
282
|
+
createdBy: "operator",
|
|
283
|
+
setAsOperatorDefault: parsed.setAsOperatorDefault === true,
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
// Swallow telemetry-side throws.
|
|
289
|
+
}
|
|
290
|
+
return { blueprintId, codeHash };
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
export function createGguiOpsRegisterBlueprintHandler(deps) {
|
|
294
|
+
const registerVariant = makeRegisterCore(deps);
|
|
295
|
+
return defineHandler({
|
|
296
|
+
name: "ggui_ops_register_blueprint",
|
|
297
|
+
title: "Register blueprint",
|
|
298
|
+
audience: ["ops"],
|
|
299
|
+
description: "Register a pre-built blueprint variant (operator-supplied componentCode bytes, no LLM dispatch). Sibling of `ggui_ops_generate_blueprint` — same persistence + dual-write semantics, same variance + operator-default mark behavior (the mark orders blueprint listings; it does not decide which blueprint serves a render). Use for fixture seeding, export/reimport round-trips, and manual recovery. Returns `{blueprintId, codeHash, source}` where `source` is always `{kind: 'user'}` — hand-supplied bytes carry no engine claim, so none is recorded. App-scoped variant curation for an app you operate — distinct from the personal saved-blueprint library (the _my_ tools).",
|
|
300
|
+
inputSchema: opsInputSchema,
|
|
301
|
+
outputSchema: opsOutputSchema,
|
|
302
|
+
async handler(rawInput, ctx) {
|
|
303
|
+
const parsed = opsRegisterBlueprintInputSchema.parse(rawInput);
|
|
304
|
+
// Operator-supplied bytes, no LLM dispatch: the user arm, and no
|
|
305
|
+
// authored source (this door never carries one — ggui#1477).
|
|
306
|
+
const { blueprintId, codeHash } = await registerVariant(parsed, ctx, { source: USER_SOURCE });
|
|
238
307
|
return {
|
|
239
308
|
blueprintId,
|
|
240
309
|
codeHash,
|
|
@@ -243,3 +312,37 @@ export function createGguiOpsRegisterBlueprintHandler(deps) {
|
|
|
243
312
|
},
|
|
244
313
|
});
|
|
245
314
|
}
|
|
315
|
+
/**
|
|
316
|
+
* ggui#1493 (ggui#1477's source half) — register ENGINE-GENERATED bytes
|
|
317
|
+
* with the authored source they were compiled from, in-process.
|
|
318
|
+
*
|
|
319
|
+
* Same body as `ggui_ops_register_blueprint` (one durable row, one cache
|
|
320
|
+
* mirror, the same gates and variance), with three differences: provenance
|
|
321
|
+
* is the generation's `llm` arm; the authored source reaches the cache
|
|
322
|
+
* registry, so a render that reuses the registration serves it
|
|
323
|
+
* (`ggui_get_render_source`, save-to-library); and the generation's build,
|
|
324
|
+
* when the caller passes one, is stamped on the durable rows (ggui#1280).
|
|
325
|
+
* It is NOT an MCP tool and
|
|
326
|
+
* is on no wire: the public operator door stays source-free, because it
|
|
327
|
+
* cannot verify that supplied source compiles to the supplied code.
|
|
328
|
+
*
|
|
329
|
+
* Refuses, before anything is persisted, provenance the protocol's
|
|
330
|
+
* `llmBlueprintSourceSchema` rejects and an empty `sourceCode`.
|
|
331
|
+
*/
|
|
332
|
+
export function createRegisterGeneratedBlueprint(deps) {
|
|
333
|
+
const registerVariant = makeRegisterCore(deps);
|
|
334
|
+
return async (input, generated, ctx) => {
|
|
335
|
+
const parsed = opsRegisterBlueprintInputSchema.parse(input);
|
|
336
|
+
const source = llmBlueprintSourceSchema.parse(generated.source);
|
|
337
|
+
if (generated.sourceCode.length === 0) {
|
|
338
|
+
throw new Error("registerGeneratedBlueprint: sourceCode must be the non-empty authored source componentCode was compiled from");
|
|
339
|
+
}
|
|
340
|
+
const build = admitGeneratorBuild(source, generated.build);
|
|
341
|
+
const { blueprintId, codeHash } = await registerVariant(parsed, ctx, {
|
|
342
|
+
source,
|
|
343
|
+
sourceCode: generated.sourceCode,
|
|
344
|
+
...(build !== undefined ? { build } : {}),
|
|
345
|
+
});
|
|
346
|
+
return { blueprintId, codeHash, source };
|
|
347
|
+
};
|
|
348
|
+
}
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Patches the two mutable surfaces of a blueprint:
|
|
5
5
|
*
|
|
6
|
-
* 1. `isOperatorDefault` —
|
|
7
|
-
* blueprint's `(appId, contractHash)` group
|
|
6
|
+
* 1. `isOperatorDefault` — mark as the operator default for the
|
|
7
|
+
* blueprint's `(appId, contractHash)` group (orders listings; no
|
|
8
|
+
* render path reads it to choose what serves). The store
|
|
8
9
|
* automatically clears any prior default in the same group
|
|
9
10
|
* (see `BlueprintStore.setOperatorDefault`).
|
|
10
11
|
* 2. `variance` — partial merge into the persisted variance. Keys
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/ops-blueprint/update.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/ops-blueprint/update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAGL,KAAK,iBAAiB,EAGvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,cAAc,EACf,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAyB,KAAK,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AASxF;;;;;;;;;GASG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,IAAI,EAAG,wBAAwB,CAAU;gBACtC,WAAW,EAAE,MAAM;CAMhC;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,yBAAyB,CAAC;CACzD;AAuCD,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,0BAA0B;;;;;;;;;;;GAwEjC"}
|