@gavana.ai/cli 0.2.0 → 0.2.2

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 (42) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +42 -2
  3. package/guides/creative-canvas.md +52 -0
  4. package/guides/generated-assets.md +7 -2
  5. package/guides/paid-action-safety.md +1 -1
  6. package/guides/sections-layout.md +3 -3
  7. package/guides/validation-recovery.md +9 -2
  8. package/package.json +1 -1
  9. package/src/canvas-agent-guide.mjs +3 -3
  10. package/src/canvas-agent-validation.mjs +30 -15
  11. package/src/capabilities.mjs +3 -1
  12. package/src/client.mjs +252 -0
  13. package/src/commands.mjs +25 -3
  14. package/src/config.mjs +50 -17
  15. package/src/guide-sources.mjs +12 -4
  16. package/src/mcp-targets.mjs +72 -0
  17. package/src/runner.mjs +205 -58
  18. package/src/tools/campaign_plan.mjs +2 -2
  19. package/src/tools/campaign_review.mjs +2 -2
  20. package/src/tools/campaign_start.mjs +2 -2
  21. package/src/tools/definitions.mjs +34 -0
  22. package/src/tools/element_archive.mjs +12 -0
  23. package/src/tools/element_collection_create.mjs +11 -0
  24. package/src/tools/element_collection_delete.mjs +12 -0
  25. package/src/tools/element_collection_list.mjs +13 -0
  26. package/src/tools/element_collection_update.mjs +12 -0
  27. package/src/tools/element_create.mjs +11 -0
  28. package/src/tools/element_get.mjs +12 -0
  29. package/src/tools/element_history.mjs +13 -0
  30. package/src/tools/element_list.mjs +13 -0
  31. package/src/tools/element_restore.mjs +12 -0
  32. package/src/tools/element_update.mjs +21 -0
  33. package/src/tools/element_update_collections.mjs +12 -0
  34. package/src/tools/image_tool.mjs +3 -3
  35. package/src/tools/registry.mjs +202 -0
  36. package/src/tools/schemas.mjs +63 -1
  37. package/src/tools/work_continue.mjs +42 -0
  38. package/src/tools/work_execute.mjs +12 -0
  39. package/src/tools/work_get.mjs +12 -0
  40. package/src/tools/work_prepare.mjs +21 -0
  41. package/src/tools/work_refresh.mjs +12 -0
  42. package/src/version.mjs +5 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog — @gavana.ai/cli
2
2
 
3
+ ## 0.2.2
4
+
5
+ ### Changed
6
+
7
+ - Image commands and MCP tools now return immediately after the durable Canvas
8
+ targets and Run are queued. Use `--wait` in the CLI or `wait: true` in an MCP
9
+ call when the completed image is required in the same interaction.
10
+ - Distinct local image references upload concurrently while their original
11
+ reference order and duplicate-upload reuse remain stable.
12
+
13
+ ## 0.2.1
14
+
15
+ ### Fixed
16
+
17
+ - macOS Keychain-backed profiles now distinguish a credential that is genuinely
18
+ absent from one that the current process cannot access. Restricted processes
19
+ report `keychain_inaccessible` with an actionable explanation instead of
20
+ sending users through login again.
21
+
3
22
  ## 0.2.0
4
23
 
5
24
  First release published to npm. Version 0.1.0 existed in this repository but was
package/README.md CHANGED
@@ -103,6 +103,9 @@ retried automatically.
103
103
  gavana canvas list
104
104
  gavana canvas list --limit 25 --jq '.canvases[].handle' -r
105
105
  gavana asset get asset:OWNER_UID:ASSET_ID
106
+ gavana element list
107
+ gavana element get element:ELEMENT_ID@v3
108
+ gavana element create --name "Soft window light" --type lighting --guidelines "Keep diffuse, cool window light."
106
109
  gavana recipe search "product visual"
107
110
  gavana recipe run recipe:product-visual-direction --input product-context="A matte black travel bottle" --destination agent-canvas
108
111
  gavana model list --capability image.generate
@@ -111,6 +114,7 @@ gavana action list
111
114
  gavana action get action:resize
112
115
  gavana action run action:resize --input ./product.png --destination agent-canvas --width 1080 --height 1350
113
116
  gavana image generate --destination agent-canvas --model model:OPAQUE_MODEL_KEY --prompt "A studio product photograph"
117
+ gavana image generate --destination agent-canvas --prompt "A studio product photograph" --wait
114
118
  gavana model list --capability video.generate
115
119
  gavana video generate --model model:OPAQUE_MODEL_KEY --prompt "A slow product turntable" --duration 15 --aspect-ratio 9:16 --download ./turntable.mp4
116
120
  gavana video generate --model model:OPAQUE_MODEL_KEY --prompt "Animate the fabric naturally" --first-frame ./product.png --no-wait
@@ -176,8 +180,13 @@ text-only Recipes.
176
180
 
177
181
  Recipe, image, and Action work returns a shared `run:` handle with typed outputs,
178
182
  duration estimates, observed queue/execution timing, and stable retry guidance.
179
- Default waiting and `run get|wait|cancel` require `job:manage`; a start-only
180
- token can use `--no-wait` with a signed webhook.
183
+ Image commands return as soon as Gavana has created the durable Canvas targets
184
+ and queued the Run, so the caller can continue while generation proceeds. Add
185
+ `--wait` only when the completed image is needed in the same command. `--no-wait`
186
+ remains accepted for existing image scripts. Recipe and Action commands retain
187
+ their existing wait-by-default behavior. Waiting and `run get|wait|cancel`
188
+ require `job:manage`; a start-only token can queue image work directly or use
189
+ `--no-wait` with a signed webhook.
181
190
  The legacy `job:` handle remains an image and Action compatibility alias; it is
182
191
  never used for Recipes. Image and Action `run:` and `job:` handles point to the
183
192
  same temporary record and expire together:
@@ -217,6 +226,37 @@ commands for canvases, recipes, assets, Actions, models, and providers accept `-
217
226
  `--jq` selector supports property paths, array indexes, and `[]` projections
218
227
  without requiring a separate jq installation.
219
228
 
229
+ ## Elements
230
+
231
+ Elements are reusable visual references, not copied image files. Use
232
+ `element list`, `element get element:<id>@v<n>`, and `element history` to
233
+ inspect current or immutable historical revisions. Create or update with one
234
+ or more `--source-asset asset:<id>` references, `--guidelines`, or both.
235
+ `element archive` asks for interactive confirmation; in scripts and other
236
+ non-interactive environments it requires `--yes`. An archived Element remains
237
+ restorable with `element restore`. `element collection-delete` follows the same
238
+ confirmation rule and never deletes the Elements it organized.
239
+
240
+ Apply an exact immutable revision during image work with repeatable
241
+ `--element element:<id>@v<n>` flags. JSON callers may also pass
242
+ `{ "handle": "element:<id>@v<n>", "role": "style", "influence": 0.8 }`.
243
+ An image job accepts up to eight Elements; their source images share the
244
+ existing 16-reference limit.
245
+
246
+ ## Chat-first work
247
+
248
+ Use `work_prepare` or `gavana work prepare` for a broad campaign request. It
249
+ returns exactly three directions and a recommendation without paid generation.
250
+ Use `work_continue` or `gavana work continue` to answer a factual question,
251
+ select one direction, adjust the brief, or acknowledge a changed Canvas with
252
+ `--rebase`. `work_execute` and `gavana work execute work:<id> --confirm
253
+ --idempotency-key KEY` send `confirm: true`, start only the selected direction,
254
+ and return durable progress immediately; they never wait or automatically
255
+ retry paid work. `work_get` is read-only and never polls providers or writes
256
+ state; use `gavana work refresh work:<id>` to reconcile provider progress.
257
+ The snapshot returns the latest brief, choice, outputs, and Canvas
258
+ synchronization state.
259
+
220
260
  ## JavaScript client
221
261
 
222
262
  The same dependency-free client is exported for Node.js applications:
@@ -0,0 +1,52 @@
1
+ ---
2
+ id: creative-canvas
3
+ title: Creative Canvas
4
+ description: Keep creative work on the Canvas without lifecycle states.
5
+ keywords: ["creative", "ideas", "directions", "brainstorm", "refine", "compose", "campaign"]
6
+ order: 11
7
+ ---
8
+
9
+ ## The Canvas is the memory
10
+
11
+ Every generated image, written thought, reference, and experiment remains on the Canvas until a person deletes it. Do not assign creative output a draft, rejected, accepted, approved, or final lifecycle state. A retained node has value even when it is not currently selected.
12
+
13
+ Reference handles and connections are durable provenance. They explain where a creative result came from; they do not require a user to click Keep or clear a review gate.
14
+
15
+ ## Spatial structure, not stages
16
+
17
+ Use an ordinary Section only when the person explicitly asks to organize work. Name it for their brief; it is never a required left-to-right workflow. Any node may move between Sections, appear in more than one discussion, become a reference for later work, or remain untouched. Do not move, rename, or create Sections unless the user requests structure.
18
+
19
+ ## Campaign assistance
20
+
21
+ When a person supplies only a product and a broad ask, do not jump straight to a
22
+ generic photoshoot, poster, or banner. First make a visible reference-led
23
+ concept cluster with three roles:
24
+
25
+ - **Product identity:** the exact supplied product, logo, garment, or other
26
+ identity reference when one exists.
27
+ - **Brand-world:** the lighting, material, setting, and cultural visual world.
28
+ - **Typography/layout:** the editorial hierarchy, copy placement, crop, and
29
+ composition reference.
30
+
31
+ Connect each source to the work it informs. If inspiration is missing and the
32
+ current request explicitly authorizes generation, autonomously create small,
33
+ clearly labelled concept-reference images or boards for every missing role: a
34
+ product-identity concept study, brand-world, and typography/layout. A
35
+ product-identity study is provisional when no exact product source exists; none
36
+ of these generated concept references may be claimed as product evidence,
37
+ official assets, or real campaigns. If the request authorizes preparation only,
38
+ create editable prompt and Text references without starting a paid image job.
39
+
40
+ Infer a concise brief and create at least three materially different directions.
41
+ Vary the central idea, composition, setting, copy hierarchy, typography/layout
42
+ concept, or audience — not merely the pose or crop. Give every direction a
43
+ short rationale Text node and preserve all attempts on the Canvas. Add one
44
+ **Recommended next move** Text node that explains the strongest direction; this
45
+ is editorial advice, not approval.
46
+
47
+ Do not create a default Section set. If a person asks for a structured campaign
48
+ area, use only the ordinary Sections they request. Ask one short question only
49
+ when a missing product-versus-style distinction would materially change the
50
+ work. Otherwise make a useful first pass and let the person point to, combine,
51
+ or refine any result. Exporting or publishing is an explicit action from any
52
+ selected node or Section, not a status transition.
@@ -10,20 +10,25 @@ order: 6
10
10
 
11
11
  - Read the destination canvas and relevant source nodes.
12
12
  - Use exact source `node:` or `asset:` handles.
13
+ - Before image or video generation, call `model_list` for the required capability and pass its exact `model:` handle. A bare model name does not select a saved connection. If no matching model is returned, report that the agent account cannot access that connection; do not ask the user to add a key again.
13
14
  - For a standalone image request, pass every visual source in `references`.
14
15
  Use `{ "handle": "node:...", "role": "identity" }` when its
15
16
  responsibility is known; valid roles are `identity`, `construction`,
16
17
  `texture`, `fit`, and `style`. Do not flatten multi-reference work
17
18
  into prompt prose or omit a source during fallback.
19
+ - Reuse existing Canvas `node:` or `asset:` handles directly. Do not download
20
+ and re-upload a generated Canvas image merely to use it as the next
21
+ generation's reference. State whether a style reference establishes the
22
+ brand-world or typography/layout direction in the prompt.
18
23
  - Create an empty image or video target only through supported operations. Do not write media bytes, storage keys, or arbitrary output URLs into metadata.
19
24
  - Connect prompts, products, references, Lists, and frame inputs to their target with the correct direction and mode.
20
25
 
21
26
  ## Paid execution
22
27
 
23
- Generation is allowed only after explicit current-turn user intent. Start one run with one caller-stable idempotency key. Poll the returned Run or Job; do not start another run while waiting. A terminal failure must be reported without automatic retry.
28
+ Generation is allowed only after explicit current-turn user intent. Start one run with one caller-stable idempotency key. Image tools return durable queued progress by default; report that progress immediately and do not automatically call `run_wait`. Call `run_wait` only when the current user explicitly needs the completed asset in this same interaction. Otherwise, a later `run_get` or Canvas read can observe progress and the durable output. Do not start another run while one is pending. A terminal failure must be reported without automatic retry.
24
29
 
25
30
  ## Completion
26
31
 
27
32
  Do not claim a generated image is durable until the result returns a target `node:`, durable `asset:`, and the final canvas read shows server-owned media fields. A video Job may return a protected download without materializing a native video node; report exactly what the server returned and do not invent durability.
28
33
 
29
- Keep generated output spatially near its input stage and connected to its source, prompt, List, or workflow. After finalization, run `canvas_validate` and read `completionReview`: it reports overlap, full-frame Section containment, reference lineage, durable output count, and product-fidelity review state. Do not claim Done while it says `doneClaimAllowed: false`. Product-fidelity uncertainty requires human review; never create another paid provider call automatically.
34
+ Keep generated output spatially near its input stage and connected to its source, prompt, List, or workflow. After finalization, run `canvas_validate` and read `completionReview`: it reports overlap, full-frame Section containment, reference lineage, and delivery state. Do not claim Done while it says `doneClaimAllowed: false`, including when delivery is pending, failed, or non-durable. Render the Canvas for visual inspection when the request includes a campaign, poster, banner, or multi-direction composition. Reference provenance is not a user workflow state and never requires a Keep action. Never create another paid provider call automatically.
@@ -15,7 +15,7 @@ Start paid work only when the current user message explicitly asks to run or gen
15
15
  ## Retry boundary
16
16
 
17
17
  - Use one stable idempotency key for one intended paid operation.
18
- - Poll the returned handle with status tools.
18
+ - Return an image Run's durable queued progress immediately. Do not call `run_wait` unless the current user explicitly needs the completed asset in this same interaction; otherwise observe it later with `run_get` or a Canvas read.
19
19
  - Never automatically retry a terminal failure, timeout, disconnect, or ambiguous provider response with a new key.
20
20
  - Ask for new user intent before any new paid attempt.
21
21
 
@@ -10,10 +10,10 @@ order: 3
10
10
 
11
11
  - Treat the current canvas as user-owned. Preserve existing coordinates unless reorganization was explicitly requested.
12
12
  - For additions to an existing canvas, compute its visible bounding box and place the new Section to the right with at least 160 canvas units of outer spacing. If right-side placement would make the canvas excessively wide, place it below with the same spacing.
13
- - Use 48 units of inner Section padding, 32 units between sibling nodes, and at least 80 units between major stages.
14
- - Keep workflow direction consistent, normally left to right. Keep inputs before transformations and outputs after them.
13
+ - Use 48 units of inner Section padding, 32 units between sibling nodes, and at least 80 units between major clusters.
14
+ - Keep a left-to-right direction only when the user asks for a linear workflow. For creative exploration, use Sections as optional spatial places rather than a required sequence.
15
15
  - Use compact rows or columns. Avoid extremely long, thin canvases that become unreadable at Fit Canvas.
16
- - For 2-8 generated image outputs, reserve each requested final aspect frame before work begins and pack the complete result cluster as a grid. The usual four-image photoshoot is a 2x2 grid; do not stack it as a tall output column that can overlap when images finalize.
16
+ - For 2-8 generated image outputs, reserve each requested final aspect frame before work begins and pack the complete result cluster as a grid. A normal feed photoshoot uses 4:5 portrait frames in its own 2x2 Section. Put horizontal 16:9 campaign ads in a separate Section with their own targets; do not mix formats unless the user explicitly asks for a mixed-format deliverable.
17
17
  - Size Sections after their contents. Do not use Section overlap as a substitute for node placement.
18
18
  - Run `canvas_validate` before and after a multi-node layout change.
19
19
 
@@ -12,7 +12,14 @@ Call it with only `canvasId` to audit the current graph. Pass the proposed `oper
12
12
 
13
13
  Warning- and info-level findings are advisory. Error-severity findings caused by the proposed agent write have teeth: `canvas_apply_batch` rejects that batch and writes nothing. Historical findings remain visible for review but do not turn an unrelated scoped write into a forced cleanup. Validation never mutates the canvas or consumes an idempotency key.
14
14
 
15
- `summary.passed` means there is no structural error. `summary.reviewRequired` is true when errors, warnings, or truncated findings still require agent or human review. `completionReview` is the finalization-ready structured view: it names overlap, containment, reference lineage, output count, and product-fidelity state. Never claim Done unless `completionReview.doneClaimAllowed` is true.
15
+ `summary.passed` means there is no structural error. `summary.reviewRequired` is true when errors, warnings, or truncated findings still require agent or human review. `completionReview` is the finalization-ready structured view: it names overlap, containment, reference lineage, and delivery state. Never claim Done unless `completionReview.doneClaimAllowed` is true; pending, failed, or non-durable generated outputs block that claim even when the geometry is clean.
16
+
17
+ For a campaign, poster, banner, or multi-direction composition, structural
18
+ validation is necessary but not visual proof. Render the completed Canvas and
19
+ check the actual composition, distinctness of directions, visible product and
20
+ layout, and separation of 4:5 feed work from 16:9 ads. Report an unavailable
21
+ render or incomplete visual check as a limitation rather than claiming it was
22
+ verified.
16
23
 
17
24
  ## Blocked writes
18
25
 
@@ -30,4 +37,4 @@ When a batch is rejected with error-severity findings:
30
37
  - Use a new idempotency key if the corrected payload represents a changed intent.
31
38
  - Read and validate again after a successful write.
32
39
 
33
- Common findings include ordinary-node overlap, Section content overflow, generated output without an incoming relationship, text imitating a Section header, broken lineage handles, unclear media connections, and proposed deletions. Product-fidelity uncertainty is a review state, not authorization to regenerate.
40
+ Common findings include ordinary-node overlap, Section content overflow, generated output without an incoming relationship, text imitating a Section header, broken lineage handles, unclear media connections, and proposed deletions. Reference provenance is not authorization to regenerate.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gavana.ai/cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "JSON-first command-line client for the Gavana Canvas API",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,13 +1,13 @@
1
1
  // Guide metadata, lookup, and search. The prose itself lives in ../guides/*.md
2
2
  // and is loaded through ./guide-sources.mjs, so editing a guide is a content
3
3
  // change rather than a code change. Graph validation moved to
4
- // ./canvas-agent-validation.mjs in guide version 1.2.0.
4
+ // ./canvas-agent-validation.mjs in guide version 1.5.0.
5
5
  import { GAVANA_CANVAS_GUIDE_SOURCES } from "./guide-sources.mjs";
6
6
 
7
- export const GAVANA_CANVAS_GUIDE_VERSION = "1.2.0";
7
+ export const GAVANA_CANVAS_GUIDE_VERSION = "1.5.1";
8
8
  export const GAVANA_CANVAS_GUIDE_INDEX_URI = `gavana://guides/canvas/v${GAVANA_CANVAS_GUIDE_VERSION.split(".")[0]}/index`;
9
9
  export const GAVANA_CANVAS_GUIDE_WORKFLOW_INSTRUCTION =
10
- "For the first canvas task in a session, and before any unfamiliar canvas operation, inspect the relevant guide through MCP resources or call guide_search then guide_get. Before changing an existing canvas, call canvas_get. For spatial, multi-node, or destructive work, call canvas_validate with the proposed operations, apply one revision-safe atomic batch, then call canvas_validate again. When a standalone image fallback uses visual references, forward every exact node:/asset: handle (and each known role) in the image request; never reduce that work to a prompt-only generation. After an image or workflow finishes, read completionReview. Never claim Done while completionReview.doneClaimAllowed is false, blocking findings remain, or product-fidelity review is needed. Treat legacy warnings as review items, not permission to rewrite unrelated work.";
10
+ "For the first canvas task in a session, and before any unfamiliar canvas operation, inspect the relevant guide through MCP resources or call guide_search then guide_get. Before changing an existing canvas, call canvas_get. For spatial, multi-node, or destructive work, call canvas_validate with the proposed operations, apply one revision-safe atomic batch, then call canvas_validate again. Campaign work must read creative-canvas and use a reference-led concept before image output. Before image or video generation, call model_list for the required capability and use its exact model: handle; a bare model name does not select a saved connection. If no matching model is returned, report that the agent account cannot access the connection instead of asking the user to add a key again. When a standalone image fallback uses visual references, forward every exact node:/asset: handle (and each known role) in the image request; never reduce that work to a prompt-only generation. Image tools return durable queued progress by default; report it immediately and call run_wait only when the current user explicitly needs the completed asset in the same interaction. A later run_get or Canvas read can observe progress. After an image or workflow finishes, read completionReview. Never claim Done while completionReview.doneClaimAllowed is false, delivery is pending, failed, or non-durable, or blocking findings remain. Render campaign compositions for visual inspection. Treat legacy warnings as review items, not permission to rewrite unrelated work.";
11
11
  export const GAVANA_CANVAS_GUIDE_READ_ONLY_INSTRUCTION =
12
12
  "For the first canvas task in a session, and before any unfamiliar canvas review, inspect the relevant guide through MCP resources or call guide_search then guide_get. Call canvas_get before reasoning about an existing canvas, and use canvas_validate to audit its current graph. Treat validation warnings as review items and never claim to mutate the canvas.";
13
13
 
@@ -1,6 +1,6 @@
1
1
  // Deterministic canvas graph validation and destructive-impact reporting.
2
2
  //
3
- // Split out of canvas-agent-guide.mjs in guide version 1.2.0: guide prose is now
3
+ // Split out of canvas-agent-guide.mjs in guide version 1.5.0: guide prose is now
4
4
  // editable markdown under ../guides/, and validation is code. The two no longer
5
5
  // share a file. Validation still cites guide topics, so it imports the guide URI
6
6
  // helpers — the dependency runs one way only (validation -> guide).
@@ -333,8 +333,9 @@ function agentOwnsNode(node) {
333
333
  function buildCompletionReview(canvas, findings) {
334
334
  const generatedOutputs = canvas.nodes.filter(isGeneratedOutput);
335
335
  const durableOutputs = generatedOutputs.filter(hasDurableOutput);
336
- const pendingOutputs = generatedOutputs.filter((node) => node.metadata?.aiJobStatus === "queued" || node.metadata?.aiJobStatus === "running" || node.metadata?.outputValidationStatus === "checking");
336
+ const pendingOutputs = generatedOutputs.filter((node) => node.metadata?.aiJobStatus === "queued" || node.metadata?.aiJobStatus === "running");
337
337
  const failedOutputs = generatedOutputs.filter((node) => node.metadata?.status === "error" || node.metadata?.aiJobStatus === "failed" || node.metadata?.aiJobStatus === "canceled");
338
+ const nonDurableOutputs = generatedOutputs.filter((node) => !hasDurableOutput(node) && !pendingOutputs.includes(node) && !failedOutputs.includes(node));
338
339
  const overlap = reviewArea(findings, "node_overlap");
339
340
  const containment = reviewArea(findings, "section_content_overflow", "unsectioned_node");
340
341
  const referenceLineage = reviewArea(findings, "broken_generated_lineage", "unconnected_generated_output", "orphan_media_placeholder");
@@ -342,12 +343,13 @@ function buildCompletionReview(canvas, findings) {
342
343
  const blockingFindings = findings.filter((finding) => finding.blocksWrite === true || finding.blocksCompletion === true);
343
344
  const blockingFindingCodes = uniqueSorted(blockingFindings.map((finding) => finding.code));
344
345
  const advisoryFindingCodes = uniqueSorted(findings.filter((finding) => !blockingFindings.includes(finding)).map((finding) => finding.code));
345
- const doneClaimAllowed = blockingFindings.length === 0 && productFidelity.status !== "needs-review";
346
+ const delivery = deliveryReview(pendingOutputs, failedOutputs, nonDurableOutputs);
347
+ const doneClaimAllowed = blockingFindings.length === 0 && delivery.status === "clear";
346
348
 
347
349
  return {
348
- status: doneClaimAllowed ? "ready" : blockingFindings.length ? "blocked" : "needs-review",
350
+ status: doneClaimAllowed ? "ready" : "blocked",
349
351
  doneClaimAllowed,
350
- instruction: "Do not claim Done while blocking findings remain or product-fidelity review is needed.",
352
+ instruction: "Do not claim Done while blocking findings remain or generated output delivery is pending, failed, or non-durable.",
351
353
  outputs: {
352
354
  count: generatedOutputs.length,
353
355
  durableCount: durableOutputs.length,
@@ -359,11 +361,27 @@ function buildCompletionReview(canvas, findings) {
359
361
  containment,
360
362
  referenceLineage,
361
363
  productFidelity,
364
+ delivery,
362
365
  blockingFindingCodes,
363
366
  advisoryFindingCodes,
364
367
  };
365
368
  }
366
369
 
370
+ function deliveryReview(pendingOutputs, failedOutputs, nonDurableOutputs) {
371
+ const statuses = [
372
+ pendingOutputs.length ? "pending" : "",
373
+ failedOutputs.length ? "failed" : "",
374
+ nonDurableOutputs.length ? "non-durable" : "",
375
+ ].filter(Boolean);
376
+ return {
377
+ status: statuses.length ? "blocked" : "clear",
378
+ ...(statuses.length ? { reasons: statuses } : {}),
379
+ pendingOutputHandles: pendingOutputs.map((node) => nodeHandle(node.id)).sort(),
380
+ failedOutputHandles: failedOutputs.map((node) => nodeHandle(node.id)).sort(),
381
+ nonDurableOutputHandles: nonDurableOutputs.map((node) => nodeHandle(node.id)).sort(),
382
+ };
383
+ }
384
+
367
385
  function reviewArea(findings, ...codes) {
368
386
  const matched = findings.filter((finding) => codes.includes(finding.code));
369
387
  const blocking = matched.some((finding) => finding.blocksWrite === true || finding.blocksCompletion === true);
@@ -385,17 +403,14 @@ function productFidelityReview(canvas, generatedOutputs) {
385
403
  evidenceMissingOutputHandles: [],
386
404
  };
387
405
  }
388
- const needsReview = referenceTargets.filter((node) => node.metadata?.outputValidationStatus === "needs-review" || node.metadata?.outputValidationStatus === "checking");
389
- const evidenceMissing = referenceTargets.filter((node) => !node.metadata?.outputValidationStatus || node.metadata?.outputValidationStatus === "skipped");
390
406
  return {
391
- status: needsReview.length || evidenceMissing.length ? "needs-review" : "passed",
392
- reviewedOutputCount: referenceTargets.length - needsReview.length - evidenceMissing.length,
393
- needsReviewOutputHandles: needsReview.map((node) => nodeHandle(node.id)).sort(),
394
- evidenceMissingOutputHandles: evidenceMissing.map((node) => nodeHandle(node.id)).sort(),
395
- reasons: referenceTargets
396
- .filter((node) => typeof node.metadata?.outputValidationReason === "string" && node.metadata.outputValidationReason)
397
- .map((node) => ({ nodeHandle: nodeHandle(node.id), reason: node.metadata.outputValidationReason }))
398
- .sort((left, right) => left.nodeHandle.localeCompare(right.nodeHandle)),
407
+ // References preserve origin and intent. They never turn a retained
408
+ // creative output into a completion gate.
409
+ status: "passed",
410
+ reviewedOutputCount: referenceTargets.length,
411
+ needsReviewOutputHandles: [],
412
+ evidenceMissingOutputHandles: [],
413
+ reasons: [],
399
414
  };
400
415
  }
401
416
 
@@ -4,7 +4,7 @@
4
4
  import { GAVANA_CLI_VERSION } from "./version.mjs";
5
5
 
6
6
  export { GAVANA_CLI_VERSION };
7
- export const GAVANA_MCP_TOOLSETS = Object.freeze(["canvas", "recipes", "assets", "models", "actions", "images", "videos", "runs", "campaigns"]);
7
+ export const GAVANA_MCP_TOOLSETS = Object.freeze(["canvas", "recipes", "assets", "elements", "models", "actions", "images", "videos", "runs", "campaigns"]);
8
8
 
9
9
  import { GAVANA_TOOL_REGISTRY } from "./tools/registry.mjs";
10
10
 
@@ -37,6 +37,7 @@ const TOOLSET_FOR_PREFIX = Object.freeze([
37
37
  ["node_", "canvas"],
38
38
  ["connection_", "canvas"],
39
39
  ["asset_", "assets"],
40
+ ["element_", "elements"],
40
41
  ["provider_", "models"],
41
42
  ["model_", "models"],
42
43
  ["action_", "actions"],
@@ -44,6 +45,7 @@ const TOOLSET_FOR_PREFIX = Object.freeze([
44
45
  ["video_", "videos"],
45
46
  ["job_", "runs"],
46
47
  ["run_", "runs"],
48
+ ["work_", "canvas"],
47
49
  ]);
48
50
 
49
51
  export function gavanaToolsetForName(name) {