@gavana.ai/cli 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +34 -0
- package/guides/creative-canvas.md +52 -0
- package/guides/generated-assets.md +6 -1
- package/guides/sections-layout.md +3 -3
- package/guides/validation-recovery.md +9 -2
- package/package.json +1 -1
- package/src/canvas-agent-guide.mjs +3 -3
- package/src/canvas-agent-validation.mjs +30 -15
- package/src/capabilities.mjs +3 -1
- package/src/client.mjs +252 -0
- package/src/commands.mjs +23 -1
- package/src/config.mjs +50 -17
- package/src/guide-sources.mjs +11 -3
- package/src/mcp-targets.mjs +72 -0
- package/src/runner.mjs +191 -39
- package/src/tools/campaign_plan.mjs +2 -2
- package/src/tools/campaign_review.mjs +2 -2
- package/src/tools/campaign_start.mjs +2 -2
- package/src/tools/definitions.mjs +34 -0
- package/src/tools/element_archive.mjs +12 -0
- package/src/tools/element_collection_create.mjs +11 -0
- package/src/tools/element_collection_delete.mjs +12 -0
- package/src/tools/element_collection_list.mjs +13 -0
- package/src/tools/element_collection_update.mjs +12 -0
- package/src/tools/element_create.mjs +11 -0
- package/src/tools/element_get.mjs +12 -0
- package/src/tools/element_history.mjs +13 -0
- package/src/tools/element_list.mjs +13 -0
- package/src/tools/element_restore.mjs +12 -0
- package/src/tools/element_update.mjs +21 -0
- package/src/tools/element_update_collections.mjs +12 -0
- package/src/tools/image_tool.mjs +2 -2
- package/src/tools/registry.mjs +202 -0
- package/src/tools/schemas.mjs +62 -0
- package/src/tools/work_continue.mjs +42 -0
- package/src/tools/work_execute.mjs +12 -0
- package/src/tools/work_get.mjs +12 -0
- package/src/tools/work_prepare.mjs +21 -0
- package/src/tools/work_refresh.mjs +12 -0
- package/src/version.mjs +5 -7
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { listOptions } from "./helpers.mjs";
|
|
3
|
+
import { listCursor, listLimit } from "./schemas.mjs";
|
|
4
|
+
|
|
5
|
+
export function defineElementList(client) {
|
|
6
|
+
return {
|
|
7
|
+
title: "List Gavana Elements",
|
|
8
|
+
description: "Search active or archived reusable visual Elements. Each result includes its current version-pinned handle.",
|
|
9
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
10
|
+
inputSchema: z.object({ query: z.string().max(240).optional(), state: z.enum(["active", "archived"]).optional(), limit: listLimit(100), cursor: listCursor }),
|
|
11
|
+
handler: ({ query, state, limit, cursor }) => client.listElements({ ...(query ? { query } : {}), ...(state ? { state } : {}) }, listOptions(limit, cursor)),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { mutableElementReference } from "./schemas.mjs";
|
|
3
|
+
|
|
4
|
+
export function defineElementRestore(client) {
|
|
5
|
+
return {
|
|
6
|
+
title: "Restore a Gavana Element",
|
|
7
|
+
description: "Restore an archived Element when all of its source assets remain available.",
|
|
8
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
9
|
+
inputSchema: z.object({ elementId: mutableElementReference }),
|
|
10
|
+
handler: ({ elementId }) => client.restoreElement(elementId),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { elementType, mutableElementReference, assetReference } from "./schemas.mjs";
|
|
3
|
+
|
|
4
|
+
export function defineElementUpdate(client) {
|
|
5
|
+
return {
|
|
6
|
+
title: "Update a Gavana Element",
|
|
7
|
+
description: "Create a new immutable revision for the current Element. Historical version handles stay unchanged.",
|
|
8
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
9
|
+
inputSchema: z
|
|
10
|
+
.object({
|
|
11
|
+
elementId: mutableElementReference,
|
|
12
|
+
name: z.string().min(1).max(160),
|
|
13
|
+
type: elementType,
|
|
14
|
+
sourceAssetIds: z.array(assetReference).max(8).default([]),
|
|
15
|
+
guidelines: z.string().max(2_000).optional(),
|
|
16
|
+
})
|
|
17
|
+
.strict()
|
|
18
|
+
.refine((value) => value.sourceAssetIds.length > 0 || Boolean(value.guidelines?.trim()), "Add at least one source asset or guideline."),
|
|
19
|
+
handler: ({ elementId, ...input }) => client.updateElement(elementId, input),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { elementCollectionReference, mutableElementReference } from "./schemas.mjs";
|
|
3
|
+
|
|
4
|
+
export function defineElementUpdateCollections(client) {
|
|
5
|
+
return {
|
|
6
|
+
title: "Organize an Element in collections",
|
|
7
|
+
description: "Replace this Element's collection memberships without changing its visual revision.",
|
|
8
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
9
|
+
inputSchema: z.object({ elementId: mutableElementReference, collectionIds: z.array(elementCollectionReference).max(24) }),
|
|
10
|
+
handler: ({ elementId, collectionIds }) => client.updateElementCollections(elementId, collectionIds),
|
|
11
|
+
};
|
|
12
|
+
}
|
package/src/tools/image_tool.mjs
CHANGED
|
@@ -11,9 +11,9 @@ export function imageToolDefinition(operation, client) {
|
|
|
11
11
|
title: `${operation === "generate" ? "Generate" : operation === "edit" ? "Edit" : "Vary"} canvas images`,
|
|
12
12
|
description:
|
|
13
13
|
operation === "generate"
|
|
14
|
-
? "Queue image generation into existing target image nodes. For an exact product, logo, face, garment, or other visual identity, do not rely on prompt-only generation: use
|
|
14
|
+
? "Queue image generation into existing target image nodes. Campaign work needs a visible reference-led concept before output; reuse existing Canvas node:/asset: handles for product identity, brand-world, and typography/layout references. For an exact product, logo, face, garment, or other visual identity, do not rely on prompt-only generation: use a user-provided local image (or an existing node:/asset: handle), then call image_edit with references."
|
|
15
15
|
: operation === "edit"
|
|
16
|
-
? "Queue an image edit using stable node: or asset: references. Use this for exact product or visual identity work; call asset_upload first when the user supplied a local image."
|
|
16
|
+
? "Queue an image edit using stable node: or asset: references. Reuse a Canvas image by its existing handle rather than re-uploading it. Use this for exact product or visual identity work; call asset_upload first only when the user supplied a local image."
|
|
17
17
|
: "Queue variations using an existing node: or asset: source.",
|
|
18
18
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
19
19
|
inputSchema: imageSchema(),
|
package/src/tools/registry.mjs
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* @property {("local"|"hosted")[]} surfaces Which servers advertise it.
|
|
19
19
|
* @property {string} [hostedAlias] Deprecated verb-object name the hosted server still accepts.
|
|
20
20
|
* @property {string[]} [scopes] OAuth scopes the hosted surface requires.
|
|
21
|
+
* @property {Record<string, string[]>} [conditionalScopes] Additional hosted OAuth scopes required when the named input field is present.
|
|
21
22
|
* @property {boolean} [embedImage] Hosted surface inlines an image into the result.
|
|
22
23
|
* @property {boolean} [legacyCampaign] Deprecated campaign tool, hidden unless explicitly enabled.
|
|
23
24
|
* @property {boolean} [readOnlySurface] Advertised on the read-only surface.
|
|
@@ -278,6 +279,144 @@ export const GAVANA_TOOL_REGISTRY = Object.freeze([
|
|
|
278
279
|
hermesDefault: false,
|
|
279
280
|
annotations: {"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},
|
|
280
281
|
},
|
|
282
|
+
{
|
|
283
|
+
name: "element_archive",
|
|
284
|
+
toolset: "elements",
|
|
285
|
+
surfaces: ["hosted","local"],
|
|
286
|
+
scopes: ["element:read","element:write"],
|
|
287
|
+
hostedOrder: 17,
|
|
288
|
+
hostedReadOnly: false,
|
|
289
|
+
hostedToolset: "elements",
|
|
290
|
+
localOrder: 48,
|
|
291
|
+
hermesDefault: false,
|
|
292
|
+
annotations: {"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
name: "element_collection_create",
|
|
296
|
+
toolset: "elements",
|
|
297
|
+
surfaces: ["hosted","local"],
|
|
298
|
+
scopes: ["element:read","element:write"],
|
|
299
|
+
hostedOrder: 18,
|
|
300
|
+
hostedReadOnly: false,
|
|
301
|
+
hostedToolset: "elements",
|
|
302
|
+
localOrder: 50,
|
|
303
|
+
annotations: {"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
name: "element_collection_delete",
|
|
307
|
+
toolset: "elements",
|
|
308
|
+
surfaces: ["hosted","local"],
|
|
309
|
+
scopes: ["element:read","element:write"],
|
|
310
|
+
hostedOrder: 19,
|
|
311
|
+
hostedReadOnly: false,
|
|
312
|
+
hostedToolset: "elements",
|
|
313
|
+
localOrder: 53,
|
|
314
|
+
hermesDefault: false,
|
|
315
|
+
annotations: {"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
name: "element_collection_list",
|
|
319
|
+
toolset: "elements",
|
|
320
|
+
surfaces: ["hosted","local"],
|
|
321
|
+
scopes: ["element:read"],
|
|
322
|
+
readOnlySurface: true,
|
|
323
|
+
hostedOrder: 20,
|
|
324
|
+
hostedReadOnly: true,
|
|
325
|
+
hostedToolset: "elements",
|
|
326
|
+
localOrder: 49,
|
|
327
|
+
annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
name: "element_collection_update",
|
|
331
|
+
toolset: "elements",
|
|
332
|
+
surfaces: ["hosted","local"],
|
|
333
|
+
scopes: ["element:read","element:write"],
|
|
334
|
+
hostedOrder: 21,
|
|
335
|
+
hostedReadOnly: false,
|
|
336
|
+
hostedToolset: "elements",
|
|
337
|
+
localOrder: 52,
|
|
338
|
+
annotations: {"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
name: "element_create",
|
|
342
|
+
toolset: "elements",
|
|
343
|
+
surfaces: ["hosted","local"],
|
|
344
|
+
scopes: ["element:read","element:write"],
|
|
345
|
+
hostedOrder: 22,
|
|
346
|
+
hostedReadOnly: false,
|
|
347
|
+
hostedToolset: "elements",
|
|
348
|
+
localOrder: 45,
|
|
349
|
+
annotations: {"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
name: "element_get",
|
|
353
|
+
toolset: "elements",
|
|
354
|
+
surfaces: ["hosted","local"],
|
|
355
|
+
scopes: ["element:read"],
|
|
356
|
+
readOnlySurface: true,
|
|
357
|
+
hostedOrder: 23,
|
|
358
|
+
hostedReadOnly: true,
|
|
359
|
+
hostedToolset: "elements",
|
|
360
|
+
localOrder: 43,
|
|
361
|
+
annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
name: "element_history",
|
|
365
|
+
toolset: "elements",
|
|
366
|
+
surfaces: ["hosted","local"],
|
|
367
|
+
scopes: ["element:read"],
|
|
368
|
+
readOnlySurface: true,
|
|
369
|
+
hostedOrder: 24,
|
|
370
|
+
hostedReadOnly: true,
|
|
371
|
+
hostedToolset: "elements",
|
|
372
|
+
localOrder: 44,
|
|
373
|
+
annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
name: "element_list",
|
|
377
|
+
toolset: "elements",
|
|
378
|
+
surfaces: ["hosted","local"],
|
|
379
|
+
scopes: ["element:read"],
|
|
380
|
+
readOnlySurface: true,
|
|
381
|
+
hostedOrder: 25,
|
|
382
|
+
hostedReadOnly: true,
|
|
383
|
+
hostedToolset: "elements",
|
|
384
|
+
localOrder: 42,
|
|
385
|
+
annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
name: "element_restore",
|
|
389
|
+
toolset: "elements",
|
|
390
|
+
surfaces: ["hosted","local"],
|
|
391
|
+
scopes: ["element:read","element:write"],
|
|
392
|
+
hostedOrder: 26,
|
|
393
|
+
hostedReadOnly: false,
|
|
394
|
+
hostedToolset: "elements",
|
|
395
|
+
localOrder: 47,
|
|
396
|
+
annotations: {"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
name: "element_update",
|
|
400
|
+
toolset: "elements",
|
|
401
|
+
surfaces: ["hosted","local"],
|
|
402
|
+
scopes: ["element:read","element:write"],
|
|
403
|
+
hostedOrder: 27,
|
|
404
|
+
hostedReadOnly: false,
|
|
405
|
+
hostedToolset: "elements",
|
|
406
|
+
localOrder: 46,
|
|
407
|
+
annotations: {"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
name: "element_update_collections",
|
|
411
|
+
toolset: "elements",
|
|
412
|
+
surfaces: ["hosted","local"],
|
|
413
|
+
scopes: ["element:read","element:write"],
|
|
414
|
+
hostedOrder: 28,
|
|
415
|
+
hostedReadOnly: false,
|
|
416
|
+
hostedToolset: "elements",
|
|
417
|
+
localOrder: 51,
|
|
418
|
+
annotations: {"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},
|
|
419
|
+
},
|
|
281
420
|
{
|
|
282
421
|
name: "guide_get",
|
|
283
422
|
toolset: "canvas",
|
|
@@ -315,6 +454,7 @@ export const GAVANA_TOOL_REGISTRY = Object.freeze([
|
|
|
315
454
|
surfaces: ["hosted","local"],
|
|
316
455
|
hostedAlias: "generate_image_in_canvas",
|
|
317
456
|
scopes: ["canvas:read","canvas:write","asset:read","image:generate","job:manage"],
|
|
457
|
+
conditionalScopes: { elements: ["element:read"] },
|
|
318
458
|
hostedOrder: 13,
|
|
319
459
|
paid: true,
|
|
320
460
|
hostedReadOnly: false,
|
|
@@ -517,6 +657,68 @@ export const GAVANA_TOOL_REGISTRY = Object.freeze([
|
|
|
517
657
|
hostedToolset: "models",
|
|
518
658
|
annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},
|
|
519
659
|
},
|
|
660
|
+
{
|
|
661
|
+
name: "work_continue",
|
|
662
|
+
toolset: "canvas",
|
|
663
|
+
surfaces: ["hosted","local"],
|
|
664
|
+
scopes: ["canvas:read","canvas:write"],
|
|
665
|
+
hostedOrder: 31,
|
|
666
|
+
hostedReadOnly: false,
|
|
667
|
+
hostedToolset: "canvas",
|
|
668
|
+
localOrder: 56,
|
|
669
|
+
hermesDefault: false,
|
|
670
|
+
annotations: {"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},
|
|
671
|
+
},
|
|
672
|
+
{
|
|
673
|
+
name: "work_execute",
|
|
674
|
+
toolset: "canvas",
|
|
675
|
+
surfaces: ["hosted","local"],
|
|
676
|
+
scopes: ["canvas:read","canvas:write","asset:read","image:generate"],
|
|
677
|
+
hostedOrder: 32,
|
|
678
|
+
paid: true,
|
|
679
|
+
hostedReadOnly: false,
|
|
680
|
+
hostedToolset: "canvas",
|
|
681
|
+
localOrder: 57,
|
|
682
|
+
hermesDefault: false,
|
|
683
|
+
annotations: {"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true},
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
name: "work_get",
|
|
687
|
+
toolset: "canvas",
|
|
688
|
+
surfaces: ["hosted","local"],
|
|
689
|
+
scopes: ["canvas:read"],
|
|
690
|
+
readOnlySurface: true,
|
|
691
|
+
hostedOrder: 30,
|
|
692
|
+
hostedReadOnly: true,
|
|
693
|
+
hostedToolset: "canvas",
|
|
694
|
+
localOrder: 55,
|
|
695
|
+
hermesDefault: false,
|
|
696
|
+
annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
name: "work_prepare",
|
|
700
|
+
toolset: "canvas",
|
|
701
|
+
surfaces: ["hosted","local"],
|
|
702
|
+
scopes: ["canvas:read","canvas:write","asset:read"],
|
|
703
|
+
hostedOrder: 29,
|
|
704
|
+
hostedReadOnly: false,
|
|
705
|
+
hostedToolset: "canvas",
|
|
706
|
+
localOrder: 54,
|
|
707
|
+
hermesDefault: false,
|
|
708
|
+
annotations: {"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
name: "work_refresh",
|
|
712
|
+
toolset: "canvas",
|
|
713
|
+
surfaces: ["hosted","local"],
|
|
714
|
+
scopes: ["canvas:read","canvas:write","image:generate"],
|
|
715
|
+
hostedOrder: 33,
|
|
716
|
+
hostedReadOnly: false,
|
|
717
|
+
hostedToolset: "canvas",
|
|
718
|
+
localOrder: 58,
|
|
719
|
+
hermesDefault: false,
|
|
720
|
+
annotations: {"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true},
|
|
721
|
+
},
|
|
520
722
|
]);
|
|
521
723
|
|
|
522
724
|
/** Canonical name for a tool name or deprecated hosted alias. */
|
package/src/tools/schemas.mjs
CHANGED
|
@@ -14,6 +14,29 @@ const assetReference = z
|
|
|
14
14
|
.string()
|
|
15
15
|
.regex(/^asset:(?:[A-Za-z0-9_-]{1,180}:)?[A-Za-z0-9_-]{1,180}$/)
|
|
16
16
|
.describe("Stable asset:<id> or shared asset:<ownerUid>:<id> handle.");
|
|
17
|
+
const pinnedElementReference = z
|
|
18
|
+
.string()
|
|
19
|
+
.regex(/^element:[A-Za-z0-9_-]{1,180}@v[1-9][0-9]*$/)
|
|
20
|
+
.describe("Exact immutable Element revision handle element:<id>@v<n>.");
|
|
21
|
+
const mutableElementReference = z
|
|
22
|
+
.string()
|
|
23
|
+
.regex(/^element:[A-Za-z0-9_-]{1,180}$/)
|
|
24
|
+
.describe("Current Element handle element:<id>. Mutations never target a historical revision.");
|
|
25
|
+
const elementCollectionReference = z
|
|
26
|
+
.string()
|
|
27
|
+
.regex(/^element-collection:[A-Za-z0-9_-]{1,180}$/)
|
|
28
|
+
.describe("Stable Element collection handle element-collection:<id>.");
|
|
29
|
+
const elementType = z.enum(["character", "product/object", "environment", "style", "material/texture", "lighting"]);
|
|
30
|
+
const elementInput = z
|
|
31
|
+
.object({
|
|
32
|
+
name: z.string().min(1).max(160),
|
|
33
|
+
type: elementType,
|
|
34
|
+
sourceAssetIds: z.array(assetReference).max(8).default([]),
|
|
35
|
+
guidelines: z.string().max(2_000).optional(),
|
|
36
|
+
collectionIds: z.array(elementCollectionReference).max(24).optional(),
|
|
37
|
+
})
|
|
38
|
+
.strict()
|
|
39
|
+
.refine((value) => value.sourceAssetIds.length > 0 || Boolean(value.guidelines?.trim()), "Add at least one source asset or guideline.");
|
|
17
40
|
const imageReferenceInput = z
|
|
18
41
|
.union([
|
|
19
42
|
z.union([nodeReference, assetReference]),
|
|
@@ -66,6 +89,18 @@ const runReference = z
|
|
|
66
89
|
.string()
|
|
67
90
|
.regex(/^run:[A-Za-z0-9_-]{1,180}$/)
|
|
68
91
|
.describe("Opaque run:<id> handle. Image and Action Runs are temporary; Recipe Runs currently persist.");
|
|
92
|
+
const workReference = z
|
|
93
|
+
.string()
|
|
94
|
+
.regex(/^work:[A-Za-z0-9_-]{1,180}$/)
|
|
95
|
+
.describe("Stable work:<id> handle returned by work_prepare.");
|
|
96
|
+
const workReferenceHandle = z.string().regex(/^(?:node|asset):(?:[A-Za-z0-9_-]{1,180}:)?[A-Za-z0-9_-]{1,180}$/);
|
|
97
|
+
const workReferenceInput = z
|
|
98
|
+
.union([
|
|
99
|
+
workReferenceHandle,
|
|
100
|
+
z.object({ handle: workReferenceHandle, role: z.enum(["identity", "style", "product"]).optional() }).strict(),
|
|
101
|
+
])
|
|
102
|
+
.describe("Durable node: or asset: reference, optionally with an identity, style, or product role.");
|
|
103
|
+
const workIdempotencyKey = z.string().min(8).max(200).describe("Required caller-stable retry key. Reuse it only for the exact same work action.");
|
|
69
104
|
const campaignProductReference = z
|
|
70
105
|
.string()
|
|
71
106
|
.max(400)
|
|
@@ -84,6 +119,18 @@ const approvedOutputReferences = z
|
|
|
84
119
|
const campaignIdempotencyKey = z.string().min(8).max(200).describe("Required caller-stable retry key. Reuse it only for the exact same campaign action.");
|
|
85
120
|
const recipeForkIdempotencyKey = z.string().min(8).max(200).describe("Required caller-stable retry key. Reuse it only for the exact same Recipe fork.");
|
|
86
121
|
const campaignAspectRatio = z.enum(["1:1", "4:5", "3:4", "16:9", "9:16"]);
|
|
122
|
+
const elementGenerationInput = z
|
|
123
|
+
.union([
|
|
124
|
+
pinnedElementReference,
|
|
125
|
+
z
|
|
126
|
+
.object({
|
|
127
|
+
handle: pinnedElementReference,
|
|
128
|
+
role: z.enum(["identity", "construction", "texture", "fit", "style"]).optional(),
|
|
129
|
+
influence: z.number().min(0).max(1).optional(),
|
|
130
|
+
})
|
|
131
|
+
.strict(),
|
|
132
|
+
])
|
|
133
|
+
.describe("A version-pinned Element, optionally with the visual role and influence to apply.");
|
|
87
134
|
const MAX_LOCAL_REFERENCE_IMAGE_BYTES = 50 * 1024 * 1024;
|
|
88
135
|
const revisionFields = {
|
|
89
136
|
baseRevision: z.string().min(1).optional().describe("Revision returned by canvas_get. Omit to read the latest revision immediately before the write."),
|
|
@@ -107,6 +154,12 @@ function imageSchema() {
|
|
|
107
154
|
.array(imageReferenceInput)
|
|
108
155
|
.max(16)
|
|
109
156
|
.optional(),
|
|
157
|
+
elements: z
|
|
158
|
+
.array(elementGenerationInput)
|
|
159
|
+
.max(8)
|
|
160
|
+
.refine((items) => new Set(items.map((item) => (typeof item === "string" ? item : item.handle))).size === items.length, "Element handles must be unique.")
|
|
161
|
+
.optional()
|
|
162
|
+
.describe("Up to eight version-pinned Elements. Element source images share the 16-image reference limit."),
|
|
110
163
|
source: z.union([nodeReference, assetReference]).optional(),
|
|
111
164
|
connectionId: z.string().max(180).optional(),
|
|
112
165
|
model: z.union([modelReference, rawModelId]).optional(),
|
|
@@ -140,6 +193,10 @@ export {
|
|
|
140
193
|
actionReference,
|
|
141
194
|
approvedOutputReferences,
|
|
142
195
|
assetReference,
|
|
196
|
+
elementCollectionReference,
|
|
197
|
+
elementGenerationInput,
|
|
198
|
+
elementInput,
|
|
199
|
+
elementType,
|
|
143
200
|
campaignAspectRatio,
|
|
144
201
|
campaignIdempotencyKey,
|
|
145
202
|
campaignProductReference,
|
|
@@ -154,7 +211,9 @@ export {
|
|
|
154
211
|
listCursor,
|
|
155
212
|
listLimit,
|
|
156
213
|
modelReference,
|
|
214
|
+
mutableElementReference,
|
|
157
215
|
nodeReference,
|
|
216
|
+
pinnedElementReference,
|
|
158
217
|
rawModelId,
|
|
159
218
|
recipeForkIdempotencyKey,
|
|
160
219
|
recipeReference,
|
|
@@ -162,4 +221,7 @@ export {
|
|
|
162
221
|
runReference,
|
|
163
222
|
validateImageInput,
|
|
164
223
|
videoImageReference,
|
|
224
|
+
workIdempotencyKey,
|
|
225
|
+
workReference,
|
|
226
|
+
workReferenceInput,
|
|
165
227
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { workIdempotencyKey, workReference } from "./schemas.mjs";
|
|
3
|
+
|
|
4
|
+
const workDecision = z
|
|
5
|
+
.object({
|
|
6
|
+
workId: workReference,
|
|
7
|
+
action: z.enum(["answer", "select_direction", "adjust", "acknowledge_canvas"]).optional(),
|
|
8
|
+
rebase: z.literal(true).optional(),
|
|
9
|
+
answer: z.string().min(1).max(2_000).optional(),
|
|
10
|
+
directionId: z.string().min(1).max(400).optional(),
|
|
11
|
+
adjustment: z.string().min(1).max(2_000).optional(),
|
|
12
|
+
idempotencyKey: workIdempotencyKey,
|
|
13
|
+
})
|
|
14
|
+
.strict()
|
|
15
|
+
.superRefine((value, context) => {
|
|
16
|
+
if (value.rebase === true && value.action && value.action !== "acknowledge_canvas") context.addIssue({ code: z.ZodIssueCode.custom, path: ["action"], message: "rebase may only be used with acknowledge_canvas." });
|
|
17
|
+
if (value.rebase === true || value.action === "acknowledge_canvas") {
|
|
18
|
+
for (const field of ["answer", "directionId", "adjustment"]) {
|
|
19
|
+
if (value[field] !== undefined) context.addIssue({ code: z.ZodIssueCode.custom, path: [field], message: `${field} is not allowed when acknowledging Canvas changes.` });
|
|
20
|
+
}
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (!value.action) {
|
|
24
|
+
context.addIssue({ code: z.ZodIssueCode.custom, path: ["action"], message: "action is required unless rebase is true." });
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const required = value.action === "answer" ? "answer" : value.action === "select_direction" ? "directionId" : "adjustment";
|
|
28
|
+
if (!value[required]) context.addIssue({ code: z.ZodIssueCode.custom, path: [required], message: `${required} is required for ${value.action}.` });
|
|
29
|
+
for (const field of ["answer", "directionId", "adjustment"]) {
|
|
30
|
+
if (field !== required && value[field] !== undefined) context.addIssue({ code: z.ZodIssueCode.custom, path: [field], message: `${field} is not allowed for ${value.action}.` });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export function defineWorkContinue(client) {
|
|
35
|
+
return {
|
|
36
|
+
title: "Continue a Gavana campaign work",
|
|
37
|
+
description: "Answer one critical question, select one direction, adjust the brief, or acknowledge a changed Canvas with rebase. This updates planning only and never starts paid generation.",
|
|
38
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
39
|
+
inputSchema: workDecision,
|
|
40
|
+
handler: ({ workId, ...input }) => client.continueWork(workId, input),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { workIdempotencyKey, workReference } from "./schemas.mjs";
|
|
3
|
+
|
|
4
|
+
export function defineWorkExecute(client) {
|
|
5
|
+
return {
|
|
6
|
+
title: "Execute one selected Gavana campaign direction",
|
|
7
|
+
description: "Start the selected work only after explicit confirmation. This may incur provider cost and returns immediately with durable work progress; do not retry automatically.",
|
|
8
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
9
|
+
inputSchema: z.object({ workId: workReference, confirm: z.literal(true), idempotencyKey: workIdempotencyKey }).strict(),
|
|
10
|
+
handler: ({ workId, ...input }) => client.executeWork(workId, input),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { workReference } from "./schemas.mjs";
|
|
3
|
+
|
|
4
|
+
export function defineWorkGet(client) {
|
|
5
|
+
return {
|
|
6
|
+
title: "Read a Gavana work",
|
|
7
|
+
description: "Read a durable snapshot of the brief, directions, selection, delivery status, and Canvas synchronization state. This never polls providers or writes Work/Canvas.",
|
|
8
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
9
|
+
inputSchema: z.object({ workId: workReference }).strict(),
|
|
10
|
+
handler: ({ workId }) => client.getWork(workId),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { workIdempotencyKey, workReferenceInput } from "./schemas.mjs";
|
|
3
|
+
|
|
4
|
+
const canvasId = z.string().regex(/^canvas:[A-Za-z0-9_-]{1,180}(?::[A-Za-z0-9_-]{1,180})?$/).describe("Optional existing Canvas for the Work projection.");
|
|
5
|
+
|
|
6
|
+
export function defineWorkPrepare(client) {
|
|
7
|
+
return {
|
|
8
|
+
title: "Prepare a chat-first Gavana campaign",
|
|
9
|
+
description: "Create a social-campaign brief, exactly three creative directions, and a recommendation without starting paid generation. Non-social-only campaigns must use another workflow. Stop for a user choice after this call.",
|
|
10
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
11
|
+
inputSchema: z
|
|
12
|
+
.object({
|
|
13
|
+
request: z.string().min(1).max(8_000).describe("The user's campaign request."),
|
|
14
|
+
references: z.array(workReferenceInput).max(12).optional(),
|
|
15
|
+
canvasId: canvasId.optional(),
|
|
16
|
+
idempotencyKey: workIdempotencyKey,
|
|
17
|
+
})
|
|
18
|
+
.strict(),
|
|
19
|
+
handler: (input) => client.prepareWork(input),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { workReference } from "./schemas.mjs";
|
|
3
|
+
|
|
4
|
+
export function defineWorkRefresh(client) {
|
|
5
|
+
return {
|
|
6
|
+
title: "Refresh a Gavana work",
|
|
7
|
+
description: "Poll the selected provider job and reconcile progress into durable Work and Canvas state. This is owner-only and may write status or finalized output metadata.",
|
|
8
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
9
|
+
inputSchema: z.object({ workId: workReference }).strict(),
|
|
10
|
+
handler: ({ workId }) => client.refreshWork(workId),
|
|
11
|
+
};
|
|
12
|
+
}
|
package/src/version.mjs
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
// The single source of the CLI package version.
|
|
2
2
|
//
|
|
3
|
-
// Its own module because
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// report 0.1.0 for the whole life of 0.1.1, and let the MCP server advertise
|
|
8
|
-
// 0.1.0 while packaged as 0.1.1.
|
|
3
|
+
// Its own module because the client stamps every request's User-Agent while the
|
|
4
|
+
// CLI reports and re-exports the same version without dragging in the tool
|
|
5
|
+
// registry. Reading it from a literal is what previously let published package
|
|
6
|
+
// metadata and the runtime version drift apart.
|
|
9
7
|
//
|
|
10
8
|
// scripts/gavana-mcp-tool-contract.test.mjs asserts this equals
|
|
11
9
|
// packages/cli/package.json, so the two cannot drift.
|
|
12
|
-
export const GAVANA_CLI_VERSION = "0.2.
|
|
10
|
+
export const GAVANA_CLI_VERSION = "0.2.1";
|