@gavana.ai/cli 0.2.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.
Files changed (77) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/LICENSE.md +7 -0
  3. package/README.md +237 -0
  4. package/bin/craftboard.mjs +5 -0
  5. package/bin/gavana.mjs +5 -0
  6. package/guides/connections.md +35 -0
  7. package/guides/examples-common-mistakes.md +29 -0
  8. package/guides/existing-canvases.md +19 -0
  9. package/guides/generated-assets.md +29 -0
  10. package/guides/getting-started.md +26 -0
  11. package/guides/notes-text-sections.md +44 -0
  12. package/guides/paid-action-safety.md +22 -0
  13. package/guides/prompt-lists.md +20 -0
  14. package/guides/sections-layout.md +43 -0
  15. package/guides/validation-recovery.md +33 -0
  16. package/package.json +44 -0
  17. package/src/canvas-agent-guide.mjs +133 -0
  18. package/src/canvas-agent-validation.mjs +554 -0
  19. package/src/canvas-layout.mjs +287 -0
  20. package/src/capabilities.mjs +61 -0
  21. package/src/client.mjs +1141 -0
  22. package/src/commands.mjs +259 -0
  23. package/src/config.mjs +197 -0
  24. package/src/guide-sources.mjs +86 -0
  25. package/src/runner.mjs +1968 -0
  26. package/src/tools/action_get.mjs +16 -0
  27. package/src/tools/action_list.mjs +21 -0
  28. package/src/tools/action_run.mjs +60 -0
  29. package/src/tools/agent_canvas_get.mjs +15 -0
  30. package/src/tools/asset_get.mjs +16 -0
  31. package/src/tools/asset_list.mjs +17 -0
  32. package/src/tools/asset_upload.mjs +24 -0
  33. package/src/tools/campaign_cancel.mjs +16 -0
  34. package/src/tools/campaign_get.mjs +16 -0
  35. package/src/tools/campaign_plan.mjs +31 -0
  36. package/src/tools/campaign_review.mjs +24 -0
  37. package/src/tools/campaign_start.mjs +19 -0
  38. package/src/tools/canvas_apply_batch.mjs +35 -0
  39. package/src/tools/canvas_create.mjs +15 -0
  40. package/src/tools/canvas_get.mjs +16 -0
  41. package/src/tools/canvas_list.mjs +17 -0
  42. package/src/tools/canvas_render.mjs +34 -0
  43. package/src/tools/canvas_validate.mjs +34 -0
  44. package/src/tools/connection_create.mjs +38 -0
  45. package/src/tools/connection_delete.mjs +31 -0
  46. package/src/tools/definitions.mjs +111 -0
  47. package/src/tools/guide_get.mjs +16 -0
  48. package/src/tools/guide_search.mjs +16 -0
  49. package/src/tools/helpers.mjs +66 -0
  50. package/src/tools/image_edit.mjs +8 -0
  51. package/src/tools/image_generate.mjs +8 -0
  52. package/src/tools/image_tool.mjs +56 -0
  53. package/src/tools/image_variations.mjs +8 -0
  54. package/src/tools/job_cancel.mjs +16 -0
  55. package/src/tools/job_get.mjs +17 -0
  56. package/src/tools/job_wait.mjs +18 -0
  57. package/src/tools/model_get.mjs +16 -0
  58. package/src/tools/model_list.mjs +23 -0
  59. package/src/tools/node_create.mjs +36 -0
  60. package/src/tools/node_delete.mjs +31 -0
  61. package/src/tools/node_get.mjs +16 -0
  62. package/src/tools/node_move.mjs +37 -0
  63. package/src/tools/node_resize.mjs +37 -0
  64. package/src/tools/node_update.mjs +36 -0
  65. package/src/tools/progress.mjs +101 -0
  66. package/src/tools/provider_list.mjs +17 -0
  67. package/src/tools/recipe_fork.mjs +32 -0
  68. package/src/tools/recipe_get.mjs +19 -0
  69. package/src/tools/recipe_run.mjs +61 -0
  70. package/src/tools/recipe_search.mjs +17 -0
  71. package/src/tools/registry.mjs +550 -0
  72. package/src/tools/run_cancel.mjs +16 -0
  73. package/src/tools/run_get.mjs +17 -0
  74. package/src/tools/run_wait.mjs +18 -0
  75. package/src/tools/schemas.mjs +165 -0
  76. package/src/tools/video_generate.mjs +37 -0
  77. package/src/version.mjs +12 -0
@@ -0,0 +1,16 @@
1
+ // Tool definition: action_get
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { actionReference } from "./schemas.mjs";
7
+
8
+ export function defineActionGet(client) {
9
+ return {
10
+ title: "Read an image Action schema",
11
+ description: "Inspect one deterministic Action's exact input order and accepted parameters before running it.",
12
+ annotations: { readOnlyHint: true, openWorldHint: false },
13
+ inputSchema: z.object({ actionId: actionReference }),
14
+ handler: ({ actionId }) => client.getAction(actionId),
15
+ };
16
+ }
@@ -0,0 +1,21 @@
1
+ // Tool definition: action_list
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { listOptions } from "./helpers.mjs";
7
+ import { listCursor, listLimit } from "./schemas.mjs";
8
+
9
+ export function defineActionList(client) {
10
+ return {
11
+ title: "List deterministic image Actions",
12
+ description: "Discover the available credit-free image transforms and their typed inputs and parameters.",
13
+ annotations: { readOnlyHint: true, openWorldHint: false },
14
+ inputSchema: z.object({
15
+ query: z.string().max(240).optional(),
16
+ limit: listLimit(100),
17
+ cursor: listCursor,
18
+ }),
19
+ handler: ({ query, limit, cursor }) => client.listActions(query, listOptions(limit, cursor)),
20
+ };
21
+ }
@@ -0,0 +1,60 @@
1
+ // Tool definition: action_run
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { actionReference, assetReference, canvasReference, imageDestination, nodeReference, revisionFields } from "./schemas.mjs";
7
+ import { withProgress } from "./progress.mjs";
8
+
9
+ export function defineActionRun(client) {
10
+ return {
11
+ title: "Run a deterministic image Action",
12
+ description: "Queue one credit-free transform into a durable canvas image target. Inputs must follow the order declared by action_get.",
13
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
14
+ inputSchema: z.object({
15
+ actionId: actionReference,
16
+ canvasId: canvasReference.optional(),
17
+ destination: imageDestination.optional(),
18
+ canvasTitle: z.string().min(1).max(160).optional(),
19
+ targetNodeId: nodeReference.optional(),
20
+ inputs: z
21
+ .array(z.union([nodeReference, assetReference]))
22
+ .min(1)
23
+ .max(2),
24
+ params: z.record(z.union([z.string(), z.number().finite(), z.boolean()])).default({}),
25
+ ...revisionFields,
26
+ wait: z.boolean().default(true),
27
+ timeoutSeconds: z.number().min(1).max(3_600).default(900),
28
+ }),
29
+ markdown: true,
30
+ handler: async (input, extra) => {
31
+ const destination = input.destination || input.canvasId;
32
+ if (!destination) throw Object.assign(new Error("Input validation error: Provide destination or canvasId."), { code: "invalid_action_input" });
33
+ if (destination === "new-canvas" && !input.canvasTitle) throw Object.assign(new Error("Input validation error: new-canvas requires canvasTitle."), { code: "invalid_action_input" });
34
+ const definition = (await client.getAction(input.actionId)).action;
35
+ const prepared = await client.prepareImageDestination({
36
+ destination,
37
+ canvasId: input.canvasId,
38
+ canvasTitle: input.canvasTitle,
39
+ targetNodeId: input.targetNodeId,
40
+ baseRevision: input.baseRevision,
41
+ idempotencyKey: input.idempotencyKey,
42
+ operation: "action",
43
+ count: 1,
44
+ targetTitle: `${definition.title} result`,
45
+ });
46
+ const queued = await client.startAction(input.actionId, {
47
+ canvasId: prepared.canvasId,
48
+ baseRevision: prepared.baseRevision,
49
+ idempotencyKey: input.idempotencyKey,
50
+ targetNodeId: prepared.targetNodeIds[0],
51
+ inputs: input.inputs,
52
+ params: input.params,
53
+ });
54
+ const destinationResult = { requested: destination, canvasId: prepared.canvasId, targetNodeIds: prepared.targetNodeIds };
55
+ if (input.wait === false) return { ...queued, destination: destinationResult };
56
+ const result = await client.waitForRun(queued.run || queued.id, withProgress({ timeoutMs: (input.timeoutSeconds || 900) * 1000 }, extra));
57
+ return { ...result, destination: destinationResult };
58
+ },
59
+ };
60
+ }
@@ -0,0 +1,15 @@
1
+ // Tool definition: agent_canvas_get
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+
7
+ export function defineAgentCanvasGet(client) {
8
+ return {
9
+ title: "Open Agent Canvas",
10
+ description: "Get or create this user's persistent Agent Canvas and return its stable handle and current revision.",
11
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
12
+ inputSchema: z.object({}),
13
+ handler: () => client.getOrCreateAgentCanvas(),
14
+ };
15
+ }
@@ -0,0 +1,16 @@
1
+ // Tool definition: asset_get
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { assetReference } from "./schemas.mjs";
7
+
8
+ export function defineAssetGet(client) {
9
+ return {
10
+ title: "Read a Gavana asset",
11
+ description: "Read asset metadata and receive a scoped expiring preview link for an image.",
12
+ annotations: { readOnlyHint: true, openWorldHint: false },
13
+ inputSchema: z.object({ assetId: assetReference }),
14
+ handler: ({ assetId }) => client.getAsset(assetId),
15
+ };
16
+ }
@@ -0,0 +1,17 @@
1
+ // Tool definition: asset_list
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { listOptions } from "./helpers.mjs";
7
+ import { canvasReference, listCursor, listLimit } from "./schemas.mjs";
8
+
9
+ export function defineAssetList(client) {
10
+ return {
11
+ title: "List Gavana assets",
12
+ description: "List durable assets, optionally limited to one canvas.",
13
+ annotations: { readOnlyHint: true, openWorldHint: false },
14
+ inputSchema: z.object({ canvasId: canvasReference.optional(), limit: listLimit(200), cursor: listCursor }),
15
+ handler: ({ canvasId, limit, cursor }) => client.listAssets(canvasId, listOptions(limit, cursor)),
16
+ };
17
+ }
@@ -0,0 +1,24 @@
1
+ // Tool definition: asset_upload
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { readLocalReferenceImage } from "./helpers.mjs";
7
+ import { canvasReference } from "./schemas.mjs";
8
+
9
+ export function defineAssetUpload(client) {
10
+ return {
11
+ title: "Upload a user-provided local image",
12
+ description:
13
+ "Upload one local PNG, JPEG, WebP, or GIF that the user explicitly supplied or selected. This local stdio tool reads that file from this machine and returns a durable asset: handle for image_edit; never use it to inspect unrelated local files.",
14
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
15
+ inputSchema: z.object({
16
+ filePath: z.string().min(1).max(4_096).describe("Absolute or relative path to a local image explicitly supplied or selected by the user."),
17
+ canvasId: canvasReference.optional().describe("Optional canvas:<id> handle to associate with the uploaded reference."),
18
+ }),
19
+ handler: async ({ filePath, canvasId }) => {
20
+ const reference = await readLocalReferenceImage(filePath);
21
+ return client.uploadAsset({ ...reference, ...(canvasId ? { canvasReference: canvasId } : {}) });
22
+ },
23
+ };
24
+ }
@@ -0,0 +1,16 @@
1
+ // Tool definition: campaign_cancel
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { runReference } from "./schemas.mjs";
7
+
8
+ export function defineCampaignCancel(client) {
9
+ return {
10
+ title: "Cancel a legacy campaign run",
11
+ description: "Compatibility operation for an existing campaign run. Use only after explicit user intent.",
12
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
13
+ inputSchema: z.object({ runId: runReference }),
14
+ handler: ({ runId }) => client.cancelCampaign(runId),
15
+ };
16
+ }
@@ -0,0 +1,16 @@
1
+ // Tool definition: campaign_get
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { runReference } from "./schemas.mjs";
7
+
8
+ export function defineCampaignGet(client) {
9
+ return {
10
+ title: "Read legacy campaign run state",
11
+ description: "Compatibility read for a legacy campaign record. This may reconcile durable historical runner state.",
12
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
13
+ inputSchema: z.object({ runId: runReference }),
14
+ handler: ({ runId }) => client.getCampaign(runId),
15
+ };
16
+ }
@@ -0,0 +1,31 @@
1
+ // Tool definition: campaign_plan
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { campaignAspectRatio, campaignIdempotencyKey, campaignProductReference, exactCanvasReference, recipeReference } from "./schemas.mjs";
7
+
8
+ export function defineCampaignPlan(client) {
9
+ return {
10
+ title: "Legacy campaign plan",
11
+ description: "Compatibility operation for an existing campaign integration. Do not use it for new work; use editable canvas blocks and explicit image jobs instead.",
12
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
13
+ inputSchema: z.object({
14
+ canvasId: exactCanvasReference,
15
+ recipeId: recipeReference,
16
+ recipeVersion: z.string().min(1).max(80).optional().describe("Exact published Recipe version. Omit only to use the Recipe's current version."),
17
+ product: campaignProductReference.optional(),
18
+ brandKitId: z
19
+ .string()
20
+ .regex(/^[A-Za-z0-9_-]{1,180}$/)
21
+ .optional()
22
+ .describe("Exact Brand Kit ID selected by the user."),
23
+ brandKitRevision: z.number().int().min(1).optional().describe("Exact approved Brand Kit revision. Never substitute the latest revision."),
24
+ brief: z.string().max(8_000).optional().describe("Plain-language campaign concept, audience, tone, and visual direction."),
25
+ finalOutputCount: z.number().int().min(1).max(4).optional().describe("Number of final campaign images to create after review."),
26
+ aspectRatios: z.array(campaignAspectRatio).length(1).optional().describe("Optional one-item array containing the V1 final output ratio. Defaults to 1:1."),
27
+ idempotencyKey: campaignIdempotencyKey,
28
+ }),
29
+ handler: (input) => client.planCampaign(input),
30
+ };
31
+ }
@@ -0,0 +1,24 @@
1
+ // Tool definition: campaign_review
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { approvedOutputReferences, campaignIdempotencyKey, runReference } from "./schemas.mjs";
7
+
8
+ export function defineCampaignReview(client) {
9
+ return {
10
+ title: "Legacy campaign review",
11
+ description: "Compatibility operation for an existing campaign record. New work should remain editable on the canvas.",
12
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
13
+ inputSchema: z.object({
14
+ runId: runReference,
15
+ approvedOutputNodeIds: approvedOutputReferences,
16
+ idempotencyKey: campaignIdempotencyKey,
17
+ }),
18
+ handler: ({ runId, approvedOutputNodeIds, idempotencyKey }) =>
19
+ client.reviewCampaign(runId, {
20
+ approvedOutputNodeIds,
21
+ idempotencyKey,
22
+ }),
23
+ };
24
+ }
@@ -0,0 +1,19 @@
1
+ // Tool definition: campaign_start
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { campaignIdempotencyKey, campaignReference } from "./schemas.mjs";
7
+
8
+ export function defineCampaignStart(client) {
9
+ return {
10
+ title: "Legacy campaign start",
11
+ description: "Compatibility operation for an existing campaign record. Do not use it as a new-work workflow.",
12
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
13
+ inputSchema: z.object({
14
+ campaignId: campaignReference,
15
+ idempotencyKey: campaignIdempotencyKey,
16
+ }),
17
+ handler: (input) => client.startCampaign(input),
18
+ };
19
+ }
@@ -0,0 +1,35 @@
1
+ // Tool definition: canvas_apply_batch
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { validateCanvasGraph } from "../canvas-agent-validation.mjs";
7
+ import { canvasReference, revisionFields } from "./schemas.mjs";
8
+
9
+ export function defineCanvasApplyBatch(client) {
10
+ return {
11
+ title: "Apply an atomic canvas batch",
12
+ description:
13
+ "Atomically validate and apply related canvas, node, and connection operations. Batch-local client:<id> references resolve in the response. New agent-owned overlap or full-frame Section overflow is rejected without writing; historical user-canvas warnings remain advisory. Fix blocking findings, or pass force only when the user explicitly accepts them.",
14
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
15
+ inputSchema: z.object({
16
+ canvasId: canvasReference,
17
+ ...revisionFields,
18
+ operations: z.array(z.record(z.unknown())).min(1).max(200),
19
+ force: z.boolean().default(false).describe("Apply even when the projected graph has error-severity validation findings. Use only after canvas_validate, and only when the user explicitly accepts the listed findings."),
20
+ }),
21
+ handler: async ({ canvasId, baseRevision, idempotencyKey, operations, force }) => {
22
+ const current = baseRevision ? null : await client.getCanvas(canvasId);
23
+ const result = await client.applyOperations(canvasId, {
24
+ baseRevision: baseRevision || current?.canvas.revision,
25
+ idempotencyKey,
26
+ operations,
27
+ ...(force ? { force: true } : {}),
28
+ });
29
+ return {
30
+ ...result,
31
+ validation: validateCanvasGraph(result.canvas),
32
+ };
33
+ },
34
+ };
35
+ }
@@ -0,0 +1,15 @@
1
+ // Tool definition: canvas_create
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+
7
+ export function defineCanvasCreate(client) {
8
+ return {
9
+ title: "Create a Gavana canvas",
10
+ description: "Create an empty canvas and return its stable handle and initial revision.",
11
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
12
+ inputSchema: z.object({ title: z.string().min(1).max(160), id: z.string().min(1).max(180).optional() }),
13
+ handler: (input) => client.createCanvas(input),
14
+ };
15
+ }
@@ -0,0 +1,16 @@
1
+ // Tool definition: canvas_get
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { canvasReference } from "./schemas.mjs";
7
+
8
+ export function defineCanvasGet(client) {
9
+ return {
10
+ title: "Read a Gavana canvas",
11
+ description: "Read the complete canvas graph, node metadata, connections, permissions, activity, and current revision.",
12
+ annotations: { readOnlyHint: true, openWorldHint: false },
13
+ inputSchema: z.object({ canvasId: canvasReference }),
14
+ handler: ({ canvasId }) => client.getCanvas(canvasId),
15
+ };
16
+ }
@@ -0,0 +1,17 @@
1
+ // Tool definition: canvas_list
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { listOptions } from "./helpers.mjs";
7
+ import { listCursor, listLimit } from "./schemas.mjs";
8
+
9
+ export function defineCanvasList(client) {
10
+ return {
11
+ title: "List Gavana canvases",
12
+ description: "List canvases this actor owns or can access, including stable handles, revisions, roles, and graph counts.",
13
+ annotations: { readOnlyHint: true, openWorldHint: false },
14
+ inputSchema: z.object({ limit: listLimit(25), cursor: listCursor }),
15
+ handler: ({ limit, cursor }) => client.listCanvases(listOptions(limit, cursor)),
16
+ };
17
+ }
@@ -0,0 +1,34 @@
1
+ // Tool definition: canvas_render
2
+ //
3
+ // Registered through ./definitions.mjs. Unlike every other tool it returns an MCP
4
+ // resource (an SVG) rather than a JSON result, so it sets rawResult and the server
5
+ // passes its output through untouched.
6
+ import { z } from "zod";
7
+
8
+ import { canvasReference } from "./schemas.mjs";
9
+
10
+ export function defineCanvasRender(client) {
11
+ return {
12
+ rawResult: true,
13
+ title: "Render a Gavana canvas",
14
+ description: "Render the current canvas as an SVG resource for multimodal or spatial inspection.",
15
+ annotations: { readOnlyHint: true, openWorldHint: false },
16
+ inputSchema: z.object({ canvasId: canvasReference }),
17
+ handler: async ({ canvasId }) => {
18
+ const svg = await client.renderCanvas(canvasId);
19
+ return {
20
+ content: [
21
+ {
22
+ type: "resource",
23
+ resource: {
24
+ uri: `gavana://canvas/${encodeURIComponent(canvasId)}/render.svg`,
25
+ mimeType: "image/svg+xml",
26
+ text: svg,
27
+ },
28
+ },
29
+ ],
30
+ structuredContent: { canvasId, mediaType: "image/svg+xml", bytes: Buffer.byteLength(svg) },
31
+ };
32
+ },
33
+ };
34
+ }
@@ -0,0 +1,34 @@
1
+ // Tool definition: canvas_validate
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { validateCanvasGraph } from "../canvas-agent-validation.mjs";
7
+ import { canvasReference } from "./schemas.mjs";
8
+
9
+ export function defineCanvasValidate(client) {
10
+ return {
11
+ title: "Validate a Gavana canvas",
12
+ description:
13
+ "Read and lint the current canvas, or run a canonical server-side dry-run of a proposed atomic batch without mutating it. Checks overlap, full-frame Section containment, generated lineage, connection semantics, destructive impact, and completionReview. Do not claim Done while completionReview.doneClaimAllowed is false.",
14
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
15
+ inputSchema: z.object({
16
+ canvasId: canvasReference,
17
+ baseRevision: z.string().min(1).max(200).optional().describe("Optional revision returned by canvas_get for proposed operations. Validation returns 409 if the canvas has changed."),
18
+ operations: z.array(z.record(z.unknown())).max(200).optional().describe("Optional proposed canvas_apply_batch operations for a canonical dry-run. Validation never applies them."),
19
+ }),
20
+ handler: async ({ canvasId, baseRevision, operations }) => {
21
+ if (operations?.length) {
22
+ const result = await client.validateOperations(canvasId, { ...(baseRevision ? { baseRevision } : {}), operations });
23
+ return {
24
+ ...result.validation,
25
+ currentCanvas: result.canvas,
26
+ proposal: result.proposal,
27
+ destructiveImpact: result.destructiveImpact,
28
+ };
29
+ }
30
+ const current = await client.getCanvas(canvasId);
31
+ return validateCanvasGraph(current.canvas);
32
+ },
33
+ };
34
+ }
@@ -0,0 +1,38 @@
1
+ // Tool definition: connection_create
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ // Graph mutation: resolves baseRevision, then applies one operation atomically.
6
+ import { z } from "zod";
7
+ import { canvasReference, nodeReference, revisionFields } from "./schemas.mjs";
8
+
9
+ export function defineConnectionCreate(client) {
10
+ const config = {
11
+ title: "Connect canvas nodes",
12
+ description: "Create a directed connection between two stable node handles.",
13
+ destructiveHint: false,
14
+ schema: z.object({
15
+ canvasId: canvasReference,
16
+ ...revisionFields,
17
+ from: nodeReference,
18
+ to: nodeReference,
19
+ mode: z.enum(["list", "reference", "first-frame", "last-frame", "prompt"]).optional(),
20
+ clientId: z.string().min(1).max(100).optional(),
21
+ }),
22
+ operation: ({ from, to, mode, clientId }) => ({ type: "connection.create", from, to, ...(mode ? { mode } : {}), ...(clientId ? { clientId } : {}) }),
23
+ };
24
+ return {
25
+ title: config.title,
26
+ description: config.description,
27
+ annotations: { readOnlyHint: false, destructiveHint: config.destructiveHint, idempotentHint: true, openWorldHint: false },
28
+ inputSchema: config.schema,
29
+ handler: async (input) => {
30
+ const baseRevision = input.baseRevision || (await client.getCanvas(input.canvasId)).canvas.revision;
31
+ return client.applyOperations(input.canvasId, {
32
+ baseRevision,
33
+ idempotencyKey: input.idempotencyKey,
34
+ operations: [config.operation(input)],
35
+ });
36
+ },
37
+ };
38
+ }
@@ -0,0 +1,31 @@
1
+ // Tool definition: connection_delete
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ // Graph mutation: resolves baseRevision, then applies one operation atomically.
6
+ import { z } from "zod";
7
+ import { canvasReference, connectionReference, revisionFields } from "./schemas.mjs";
8
+
9
+ export function defineConnectionDelete(client) {
10
+ const config = {
11
+ title: "Disconnect canvas nodes",
12
+ description: "Delete one connection. This is destructive and should follow explicit user intent.",
13
+ destructiveHint: true,
14
+ schema: z.object({ canvasId: canvasReference, ...revisionFields, connectionId: connectionReference }),
15
+ operation: ({ connectionId }) => ({ type: "connection.delete", connectionId }),
16
+ };
17
+ return {
18
+ title: config.title,
19
+ description: config.description,
20
+ annotations: { readOnlyHint: false, destructiveHint: config.destructiveHint, idempotentHint: true, openWorldHint: false },
21
+ inputSchema: config.schema,
22
+ handler: async (input) => {
23
+ const baseRevision = input.baseRevision || (await client.getCanvas(input.canvasId)).canvas.revision;
24
+ return client.applyOperations(input.canvasId, {
25
+ baseRevision,
26
+ idempotencyKey: input.idempotencyKey,
27
+ operations: [config.operation(input)],
28
+ });
29
+ },
30
+ };
31
+ }
@@ -0,0 +1,111 @@
1
+ // Tool behaviour, keyed by canonical name.
2
+ //
3
+ // ./registry.mjs declares which tools exist and which surfaces advertise them.
4
+ // This module binds each name to the factory that builds its config for a given
5
+ // client. Keeping the two apart is what lets the catalog be asserted against a
6
+ // server without importing every handler.
7
+ //
8
+ // scripts/canvas-agent-tool-registry.test.ts asserts this map and the registry
9
+ // cover exactly the same local tools, so adding one without the other fails.
10
+
11
+ import { defineCanvasRender } from "./canvas_render.mjs";
12
+ import { defineImageEdit } from "./image_edit.mjs";
13
+ import { defineImageGenerate } from "./image_generate.mjs";
14
+ import { defineImageVariations } from "./image_variations.mjs";
15
+ import { defineActionGet } from "./action_get.mjs";
16
+ import { defineActionList } from "./action_list.mjs";
17
+ import { defineActionRun } from "./action_run.mjs";
18
+ import { defineAgentCanvasGet } from "./agent_canvas_get.mjs";
19
+ import { defineAssetGet } from "./asset_get.mjs";
20
+ import { defineAssetList } from "./asset_list.mjs";
21
+ import { defineAssetUpload } from "./asset_upload.mjs";
22
+ import { defineCampaignCancel } from "./campaign_cancel.mjs";
23
+ import { defineCampaignGet } from "./campaign_get.mjs";
24
+ import { defineCampaignPlan } from "./campaign_plan.mjs";
25
+ import { defineCampaignReview } from "./campaign_review.mjs";
26
+ import { defineCampaignStart } from "./campaign_start.mjs";
27
+ import { defineCanvasApplyBatch } from "./canvas_apply_batch.mjs";
28
+ import { defineCanvasCreate } from "./canvas_create.mjs";
29
+ import { defineCanvasGet } from "./canvas_get.mjs";
30
+ import { defineCanvasList } from "./canvas_list.mjs";
31
+ import { defineCanvasValidate } from "./canvas_validate.mjs";
32
+ import { defineConnectionCreate } from "./connection_create.mjs";
33
+ import { defineConnectionDelete } from "./connection_delete.mjs";
34
+ import { defineGuideGet } from "./guide_get.mjs";
35
+ import { defineGuideSearch } from "./guide_search.mjs";
36
+ import { defineJobCancel } from "./job_cancel.mjs";
37
+ import { defineJobGet } from "./job_get.mjs";
38
+ import { defineJobWait } from "./job_wait.mjs";
39
+ import { defineModelGet } from "./model_get.mjs";
40
+ import { defineModelList } from "./model_list.mjs";
41
+ import { defineNodeCreate } from "./node_create.mjs";
42
+ import { defineNodeDelete } from "./node_delete.mjs";
43
+ import { defineNodeGet } from "./node_get.mjs";
44
+ import { defineNodeMove } from "./node_move.mjs";
45
+ import { defineNodeResize } from "./node_resize.mjs";
46
+ import { defineNodeUpdate } from "./node_update.mjs";
47
+ import { defineProviderList } from "./provider_list.mjs";
48
+ import { defineRecipeFork } from "./recipe_fork.mjs";
49
+ import { defineRecipeGet } from "./recipe_get.mjs";
50
+ import { defineRecipeRun } from "./recipe_run.mjs";
51
+ import { defineRecipeSearch } from "./recipe_search.mjs";
52
+ import { defineRunCancel } from "./run_cancel.mjs";
53
+ import { defineRunGet } from "./run_get.mjs";
54
+ import { defineRunWait } from "./run_wait.mjs";
55
+ import { defineVideoGenerate } from "./video_generate.mjs";
56
+
57
+ /** @type {Record<string, (client: unknown) => object>} */
58
+ export const GAVANA_TOOL_DEFINITIONS = Object.freeze({
59
+ image_variations: defineImageVariations,
60
+ image_generate: defineImageGenerate,
61
+ image_edit: defineImageEdit,
62
+ canvas_render: defineCanvasRender,
63
+ action_get: defineActionGet,
64
+ action_list: defineActionList,
65
+ action_run: defineActionRun,
66
+ agent_canvas_get: defineAgentCanvasGet,
67
+ asset_get: defineAssetGet,
68
+ asset_list: defineAssetList,
69
+ asset_upload: defineAssetUpload,
70
+ campaign_cancel: defineCampaignCancel,
71
+ campaign_get: defineCampaignGet,
72
+ campaign_plan: defineCampaignPlan,
73
+ campaign_review: defineCampaignReview,
74
+ campaign_start: defineCampaignStart,
75
+ canvas_apply_batch: defineCanvasApplyBatch,
76
+ canvas_create: defineCanvasCreate,
77
+ canvas_get: defineCanvasGet,
78
+ canvas_list: defineCanvasList,
79
+ canvas_validate: defineCanvasValidate,
80
+ connection_create: defineConnectionCreate,
81
+ connection_delete: defineConnectionDelete,
82
+ guide_get: defineGuideGet,
83
+ guide_search: defineGuideSearch,
84
+ job_cancel: defineJobCancel,
85
+ job_get: defineJobGet,
86
+ job_wait: defineJobWait,
87
+ model_get: defineModelGet,
88
+ model_list: defineModelList,
89
+ node_create: defineNodeCreate,
90
+ node_delete: defineNodeDelete,
91
+ node_get: defineNodeGet,
92
+ node_move: defineNodeMove,
93
+ node_resize: defineNodeResize,
94
+ node_update: defineNodeUpdate,
95
+ provider_list: defineProviderList,
96
+ recipe_fork: defineRecipeFork,
97
+ recipe_get: defineRecipeGet,
98
+ recipe_run: defineRecipeRun,
99
+ recipe_search: defineRecipeSearch,
100
+ run_cancel: defineRunCancel,
101
+ run_get: defineRunGet,
102
+ run_wait: defineRunWait,
103
+ video_generate: defineVideoGenerate,
104
+ });
105
+
106
+ /** Build every local tool config for a client, in registry order. */
107
+ export function gavanaToolConfig(name, client) {
108
+ const factory = GAVANA_TOOL_DEFINITIONS[name];
109
+ if (!factory) throw new Error(`No Gavana tool definition for ${name}`);
110
+ return factory(client);
111
+ }
@@ -0,0 +1,16 @@
1
+ // Tool definition: guide_get
2
+ //
3
+ // Registered through ./definitions.mjs. ./registry.mjs is the catalog that says
4
+ // this tool exists and on which surfaces; this file is what it does.
5
+ import { z } from "zod";
6
+ import { GAVANA_CANVAS_GUIDE_INDEX_URI, getCanvasGuide } from "../canvas-agent-guide.mjs";
7
+
8
+ export function defineGuideGet(client) {
9
+ return {
10
+ title: "Read a Canvas Agent Guide",
11
+ description: `Read one canonical Gavana Canvas Agent Guide topic. Start at ${GAVANA_CANVAS_GUIDE_INDEX_URI} or use guide_search to find an exact topic ID.`,
12
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
13
+ inputSchema: z.object({ guideId: z.string().min(1).max(600).describe("Guide topic ID or exact gavana:// guide URI returned by guide_search or resources/list.") }),
14
+ handler: ({ guideId }) => getCanvasGuide(guideId),
15
+ };
16
+ }