@instruktlabs/kiln 1.1.0 → 1.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 (47) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +12 -0
  4. package/dist/agent-run.mjs +220 -150
  5. package/dist/build.json +22 -22
  6. package/dist/cli.mjs +225 -150
  7. package/dist/mcp-engine.mjs +398 -144
  8. package/dist/mcp-server.mjs +1 -1
  9. package/docs/sdk.md +23 -0
  10. package/docs/tools-operations.md +1529 -0
  11. package/lib/discovery/index.d.ts +1 -1
  12. package/lib/discovery/index.js +2 -2
  13. package/lib/discovery/service.d.ts +3 -1
  14. package/lib/discovery/service.js +4 -2
  15. package/lib/engine-identity.d.ts +1 -1
  16. package/lib/engine-identity.js +1 -1
  17. package/lib/mcp-core.d.ts +2 -1
  18. package/lib/mcp-core.js +1 -0
  19. package/lib/mcp-engine.d.ts +2 -0
  20. package/lib/mcp-engine.js +8 -3
  21. package/lib/tools/discovery.d.ts +1 -1
  22. package/lib/tools/discovery.js +11 -9
  23. package/lib/tools/materials.d.ts +1 -1
  24. package/lib/tools/materials.js +44 -14
  25. package/lib/tools/operation-contract.d.ts +8 -0
  26. package/lib/tools/operation-contract.js +37 -0
  27. package/lib/tools/operations.d.ts +3 -0
  28. package/lib/tools/operations.js +154 -0
  29. package/lib/tools/registry.d.ts +6 -2
  30. package/lib/tools/registry.js +71 -23
  31. package/package.json +2 -1
  32. package/plugin.json +1 -1
  33. package/plugins/kiln-engine/.claude-plugin/plugin.json +1 -1
  34. package/plugins/kiln-engine/README.md +3 -3
  35. package/plugins/kiln-engine/package-provenance.json +6 -6
  36. package/plugins/kiln-engine/plugin.json +1 -1
  37. package/plugins/kiln-engine/runtime.json +1 -1
  38. package/src/discovery/index.ts +2 -0
  39. package/src/discovery/service.ts +3 -1
  40. package/src/engine-identity.ts +1 -1
  41. package/src/mcp-core.ts +3 -0
  42. package/src/mcp-engine.ts +11 -1
  43. package/src/tools/discovery.ts +20 -10
  44. package/src/tools/materials.ts +59 -15
  45. package/src/tools/operation-contract.ts +51 -0
  46. package/src/tools/operations.ts +177 -0
  47. package/src/tools/registry.ts +100 -20
@@ -32234,7 +32234,7 @@ import {
32234
32234
  // src/tools/registry.ts
32235
32235
  init_capture_cache();
32236
32236
  init_assets();
32237
- import { z as z20 } from "zod";
32237
+ import { z as z22 } from "zod";
32238
32238
 
32239
32239
  // src/requirements-assets.ts
32240
32240
  init_requirements_context();
@@ -32939,7 +32939,7 @@ function createKilnSourceDef(store) {
32939
32939
  }
32940
32940
 
32941
32941
  // src/engine-identity.ts
32942
- var ENGINE_VERSION = "1.1.0";
32942
+ var ENGINE_VERSION = "1.2.0";
32943
32943
  var ENGINE_INSTALL_URL = new URL("../", import.meta.url).href;
32944
32944
  function engineIdentity() {
32945
32945
  return { version: ENGINE_VERSION, installUrl: ENGINE_INSTALL_URL };
@@ -36395,7 +36395,7 @@ var MAX_RESPONSE_BYTES = 64 * 1024;
36395
36395
  var MAX_TEXT_CHARS = 16 * 1024;
36396
36396
  var DETAIL_RESULT_BUDGET = 15000;
36397
36397
  var compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
36398
- function createDiscoveryService(source, index, capabilities, retirements = {}, notes = async () => []) {
36398
+ function createDiscoveryService(source, index, capabilities, retirements = {}, notes = async () => [], capabilitiesCall = "capabilities:true") {
36399
36399
  const entries = parseCatalog(source);
36400
36400
  const byId = new Map(entries.map((entry) => [entry.id, entry]));
36401
36401
  const byName = new Map(entries.filter((entry) => entry.kind !== "recipe").map((entry) => [entry.name, entry]));
@@ -36418,7 +36418,7 @@ function createDiscoveryService(source, index, capabilities, retirements = {}, n
36418
36418
  "Parts auto-add to opts.parent; do not wrap createPart in parent.add. Part rotation uses degrees.",
36419
36419
  "Custom THREE.BufferGeometry and ordinary JavaScript functions remain available. Recipes offer guidance and never restrict modeling.",
36420
36420
  "Send source once and reuse programRef for reads, edits, inspection and rendering. Review geometry, materials and destination constraints separately.",
36421
- "Search for the operation you need in ordinary language, then fetch exact contracts with ids. Use capabilities:true for the current host."
36421
+ `Search for the operation you need in ordinary language, then fetch exact contracts with ids. Use ${capabilitiesCall} for the current host.`
36422
36422
  ]
36423
36423
  };
36424
36424
  const error = (mode, code, message) => ({
@@ -36599,12 +36599,12 @@ var snapshot;
36599
36599
  function createDiscovery(capabilities = async () => ({
36600
36600
  host: "No host capability provider was supplied.",
36601
36601
  discovery: { mode: "lexical", offline: true, requiresModel: false }
36602
- }), notes = async () => []) {
36602
+ }), notes = async () => [], capabilitiesCall = "capabilities:true") {
36603
36603
  snapshot ??= (() => {
36604
36604
  const entries = listDiscoveryEntries();
36605
36605
  return { entries, index: createLexicalDiscoveryIndex(entries) };
36606
36606
  })();
36607
- return createDiscoveryService(snapshot.entries, snapshot.index, capabilities, REMOVED_AUTHORING_HELPERS, notes);
36607
+ return createDiscoveryService(snapshot.entries, snapshot.index, capabilities, REMOVED_AUTHORING_HELPERS, notes, capabilitiesCall);
36608
36608
  }
36609
36609
 
36610
36610
  // src/tools/discovery.ts
@@ -36613,8 +36613,8 @@ init_capture_limits();
36613
36613
  init_geometry_export();
36614
36614
  init_community_exporter();
36615
36615
  init_material_resources();
36616
- function createKilnDiscoveryDef(context) {
36617
- const run = createDiscovery(() => currentCapabilities(context), async () => projectNotes(context));
36616
+ function createKilnDiscoveryDef(context, presentation = "grouped") {
36617
+ const run = createDiscovery(() => currentCapabilities(context, presentation), async () => projectNotes(context), presentation === "operations" ? "kiln_capabilities({})" : "capabilities:true");
36618
36618
  return {
36619
36619
  name: "kiln_discover",
36620
36620
  description: "Discover Kiln operations, assemblies, recipes, tool-input shapes and current host capabilities. Omit arguments for a compact overview. Search with ordinary modeling language using query; refine with family, kind or tags. Fetch complete contracts/examples with ids (up to six exact IDs, executable names or shape: ids). Overview/search pages default to six summaries. Recipes guide construction without restricting the asset. Search runs locally without models or network calls.",
@@ -36638,7 +36638,7 @@ function projectNotes(context) {
36638
36638
  `Project ${projectId} is configured for this workspace and applies when projectId is omitted: read its brief, design, inventory and material pins first with kiln_project { action: "get", projectId: "${projectId}" }; projectId: null selects standalone work.`
36639
36639
  ] : [];
36640
36640
  }
36641
- async function currentCapabilities(context) {
36641
+ async function currentCapabilities(context, presentation) {
36642
36642
  const externalEvaluator = Boolean(context.evaluatorPort) || context.evaluatorProfile === "evaluator-required";
36643
36643
  const approvedTextures = context.approvedTextureResources ? context.approvedTextureResources() : externalEvaluator ? null : approvedTextureCatalogV1();
36644
36644
  const textureSlots = approvedTextures === null ? null : {};
@@ -36667,7 +36667,7 @@ async function currentCapabilities(context) {
36667
36667
  requiresModel: false
36668
36668
  },
36669
36669
  engine: engineIdentity(),
36670
- project: {
36670
+ project: presentation === "operations" && !context.projectStore ? { available: false } : {
36671
36671
  configured: configuredProject(context),
36672
36672
  select: "projectId per call; omitted uses the configured project, null selects standalone work",
36673
36673
  read: 'kiln_project { action: "get", projectId } returns the brief, design, inventory and material pins'
@@ -36686,7 +36686,7 @@ async function currentCapabilities(context) {
36686
36686
  available: Boolean(context.assetLibrary),
36687
36687
  collections: context.assetLibrary?.collections() ?? [],
36688
36688
  save: "kiln_save persists exact GLB, source and provenance; draft renders do not populate collections",
36689
- resume: "kiln_assets action=restore imports a saved revision into the current program store",
36689
+ resume: `${presentation === "operations" ? "kiln_assets_restore" : "kiln_assets action=restore"} imports a saved revision into the current program store`,
36690
36690
  downloads: "kiln_export returns GLB/source/ZIP resource links; client presentation varies",
36691
36691
  viewer: "kiln_present opens a saved revision in supporting chat clients with 3D viewing and downloads; kiln view opens a local collection or standalone GLB/ZIP"
36692
36692
  },
@@ -37071,13 +37071,39 @@ var MATERIAL_ACTIONS = [
37071
37071
  "create-procedural",
37072
37072
  "import"
37073
37073
  ];
37074
- var REQUIREMENTS2 = {
37075
- presets: { required: [] },
37076
- "create-preset": { required: ["presetId", "seed", "creator", "license"] },
37077
- list: { required: [] },
37078
- get: { required: ["materialId"] },
37079
- "create-procedural": { required: ["draft"], shapes: { draft: "shape:material-draft" } },
37080
- import: { required: ["payload"], shapes: { payload: "shape:material-import" } }
37074
+ var MATERIAL_CONTRACT = {
37075
+ presets: {
37076
+ fields: ["tag"],
37077
+ required: [],
37078
+ description: "List shipped material recipes, optionally filtered by tag."
37079
+ },
37080
+ "create-preset": {
37081
+ fields: ["presetId", "seed", "creator", "license", "size", "materialId"],
37082
+ required: ["presetId", "seed", "creator", "license"],
37083
+ description: "Create an immutable material from a shipped preset with explicit seed, creator and license."
37084
+ },
37085
+ list: {
37086
+ fields: ["tag"],
37087
+ required: [],
37088
+ description: "List saved immutable material revisions, optionally filtered by tag."
37089
+ },
37090
+ get: {
37091
+ fields: ["materialId", "revisionId"],
37092
+ required: ["materialId"],
37093
+ description: "Read a material revision, provenance and portable specification. Omit revisionId only when exactly one revision exists."
37094
+ },
37095
+ "create-procedural": {
37096
+ fields: ["draft"],
37097
+ required: ["draft"],
37098
+ shapes: { draft: "shape:material-draft" },
37099
+ description: "Create an immutable material from a bounded procedural draft. Does not fetch URLs or execute source."
37100
+ },
37101
+ import: {
37102
+ fields: ["payload"],
37103
+ required: ["payload"],
37104
+ shapes: { payload: "shape:material-import" },
37105
+ description: "Import complete normalized material records and embedded PNGs. Does not fetch URLs or execute source."
37106
+ }
37081
37107
  };
37082
37108
  var record7 = (description) => z16.record(z16.string(), z16.unknown()).optional().describe(description);
37083
37109
  var tag = z16.string().min(1).max(80).optional().describe("presets, list: keep one tag.");
@@ -37099,13 +37125,13 @@ var materialResult = (material) => ({
37099
37125
  material,
37100
37126
  portableSpec: materialLibraryPortableSpec(material)
37101
37127
  });
37102
- var unknownMaterial = (materialId, revisionId) => new Error(`Unknown material ${materialId}${revisionId ? ` at ${revisionId}` : ""}. kiln_material { action: 'list' } lists the materials in this workspace with their revision IDs.`);
37103
- async function onlyRevision(library, materialId) {
37128
+ var unknownMaterial = (materialId, revisionId, listCall) => new Error(`Unknown material ${materialId}${revisionId ? ` at ${revisionId}` : ""}. ${listCall} lists the materials in this workspace with their revision IDs.`);
37129
+ async function onlyRevision(library, materialId, listCall) {
37104
37130
  const revisions = (await library.list()).filter((material) => material.materialId === materialId).map((material) => material.revisionId).sort();
37105
37131
  if (revisions.length === 1)
37106
37132
  return revisions[0];
37107
37133
  if (revisions.length === 0)
37108
- throw unknownMaterial(materialId);
37134
+ throw unknownMaterial(materialId, undefined, listCall);
37109
37135
  throw new Error(`Material ${materialId} has ${revisions.length} revisions: ${revisions.join(", ")}. Pass revisionId to get one.`);
37110
37136
  }
37111
37137
  function aliasMaterialId(raw) {
@@ -37118,11 +37144,13 @@ function aliasMaterialId(raw) {
37118
37144
  throw new Error(`kiln_material: resourceId (${String(resourceId)}) and materialId (${String(rest.materialId)}) name different materials; pass materialId alone.`);
37119
37145
  return { ...rest, materialId: resourceId };
37120
37146
  }
37121
- function createKilnMaterialDef(library) {
37147
+ function createKilnMaterialDef(library, presentation = "grouped") {
37148
+ const listCall = presentation === "operations" ? 'kiln_material_search({ scope: "saved" })' : "kiln_material { action: 'list' }";
37122
37149
  return {
37123
37150
  name: "kiln_material",
37124
37151
  description: "Manage optional immutable material resources in this workspace. presets discovers shipped architecture, wood, metal, fabric and ground recipes; create-preset bakes one with an explicit seed, creator and license; list returns compact material/revision summaries; get returns full provenance, hashes, map conventions, physical repeat scale and a code-ready portable material spec; create-procedural bakes bounded editable layer recipes including optional height-derived normals; import accepts complete normalized records with embedded PNG bytes. No action downloads URLs or executes source. Pin the returned materialId/revisionId through per-invocation materialDependencies or project dependencies before authored evaluation resolves the resources; no project is required.",
37125
37152
  inputSchema: materialToolInput,
37153
+ actionContract: MATERIAL_CONTRACT,
37126
37154
  annotations: {
37127
37155
  readOnlyHint: false,
37128
37156
  destructiveHint: false,
@@ -37132,7 +37160,7 @@ function createKilnMaterialDef(library) {
37132
37160
  async run(raw) {
37133
37161
  assertMaterialJson(raw);
37134
37162
  const input = materialToolInput.parse(aliasMaterialId(raw));
37135
- requireActionFields("kiln_material", input.action, input, REQUIREMENTS2[input.action]);
37163
+ requireActionFields("kiln_material", input.action, input, MATERIAL_CONTRACT[input.action]);
37136
37164
  switch (input.action) {
37137
37165
  case "presets":
37138
37166
  return {
@@ -37168,12 +37196,12 @@ function createKilnMaterialDef(library) {
37168
37196
  };
37169
37197
  }
37170
37198
  case "get": {
37171
- const revisionId = input.revisionId ?? await onlyRevision(library, input.materialId);
37199
+ const revisionId = input.revisionId ?? await onlyRevision(library, input.materialId, listCall);
37172
37200
  try {
37173
37201
  return materialResult((await library.read(input.materialId, revisionId)).manifest);
37174
37202
  } catch (error) {
37175
37203
  if (error.code === "ENOENT")
37176
- throw unknownMaterial(input.materialId, revisionId);
37204
+ throw unknownMaterial(input.materialId, revisionId, listCall);
37177
37205
  throw error;
37178
37206
  }
37179
37207
  }
@@ -37224,7 +37252,7 @@ async function persistedPreviewFidelity(fidelity, glb) {
37224
37252
  var operationId = z17.string().regex(/^op_[a-f0-9-]{36}$/);
37225
37253
  var assetId = z17.string().regex(/^[a-z][a-z0-9_-]{0,79}$/);
37226
37254
  var REVIEW_ACTIONS = ["list", "get", "pin", "save"];
37227
- var REQUIREMENTS3 = {
37255
+ var REQUIREMENTS2 = {
37228
37256
  list: { required: [] },
37229
37257
  get: { required: ["operationId"] },
37230
37258
  pin: { required: ["operationId", "pinned"] },
@@ -37306,7 +37334,7 @@ function createKilnReviewDef(context) {
37306
37334
  },
37307
37335
  async run(raw) {
37308
37336
  const input = reviewToolInput.parse(raw);
37309
- requireActionFields("kiln_review", input.action, input, REQUIREMENTS3[input.action]);
37337
+ requireActionFields("kiln_review", input.action, input, REQUIREMENTS2[input.action]);
37310
37338
  if (input.action === "list") {
37311
37339
  const snapshot = await store.snapshot({ projectId: input.projectId });
37312
37340
  const offset = input.offset ?? 0;
@@ -37496,6 +37524,12 @@ function withWorkspaceContext(def, context) {
37496
37524
  };
37497
37525
  }
37498
37526
 
37527
+ // src/tools/operations.ts
37528
+ import { z as z21 } from "zod";
37529
+
37530
+ // src/tools/operation-contract.ts
37531
+ import { z as z20 } from "zod";
37532
+
37499
37533
  // src/build-cache.ts
37500
37534
  init_protocol();
37501
37535
  init_requirements_context();
@@ -38191,11 +38225,11 @@ function derivativeReviewFidelity(receipts) {
38191
38225
  ...reasonCodes.length ? { reasonCodes } : {}
38192
38226
  };
38193
38227
  }
38194
- var validateInput = z20.object({
38195
- code: z20.string().describe("Kiln source code (defines `meta` + `build()`, optional `animate()`).")
38228
+ var validateInput = z22.object({
38229
+ code: z22.string().describe("Kiln source code (defines `meta` + `build()`, optional `animate()`).")
38196
38230
  });
38197
- var renderInput = z20.object({
38198
- code: z20.string().describe("Kiln source code to execute and render to an in-memory GLB.")
38231
+ var renderInput = z22.object({
38232
+ code: z22.string().describe("Kiln source code to execute and render to an in-memory GLB.")
38199
38233
  });
38200
38234
  var renderViewsInput = renderInput.extend({ capture: captureInput, detail: reviewDetailInput });
38201
38235
  var reviewDetailOptions = (context) => ({
@@ -38208,26 +38242,26 @@ var reviewDetailOptions = (context) => ({
38208
38242
  }
38209
38243
  });
38210
38244
  var renderViewsBufferInput = renderViewsInput.omit({ code: true });
38211
- var screenshotAnimationInput = z20.object({
38245
+ var screenshotAnimationInput = z22.object({
38212
38246
  shot: cameraShotInput.optional(),
38213
- measureParts: z20.array(cameraShotInput.shape.subject.unwrap()).min(1).max(16).optional().describe("Exact names or paths of subtrees measured together at each phase, independent of camera selection."),
38214
- frames: z20.number().int().min(2).max(6).optional(),
38215
- frameTimes: z20.array(z20.number().min(0).max(1)).min(1).max(9).optional().describe("Ordered phase fractions 0..1; mutually exclusive with frames."),
38216
- framing: z20.enum(["locked", "follow"]).optional(),
38217
- size: z20.number().int().min(128).max(1024).optional().describe("Frame size in px; default 256."),
38247
+ measureParts: z22.array(cameraShotInput.shape.subject.unwrap()).min(1).max(16).optional().describe("Exact names or paths of subtrees measured together at each phase, independent of camera selection."),
38248
+ frames: z22.number().int().min(2).max(6).optional(),
38249
+ frameTimes: z22.array(z22.number().min(0).max(1)).min(1).max(9).optional().describe("Ordered phase fractions 0..1; mutually exclusive with frames."),
38250
+ framing: z22.enum(["locked", "follow"]).optional(),
38251
+ size: z22.number().int().min(128).max(1024).optional().describe("Frame size in px; default 256."),
38218
38252
  detail: reviewDetailInput,
38219
- code: z20.string().describe("Kiln source code to execute; must define animate() returning the named clip."),
38220
- clip: z20.string().describe('The animation clip to view, by name (e.g. "walk", "attack"). Must be one your animate() returns.'),
38221
- camera: z20.string().optional().describe("Camera angle: right (default — side profile, best for leg swing + knee bend direction), front " + "(reveals sideways/lateral motion), back, left, top, or three-quarter."),
38222
- perFrame: z20.boolean().optional().describe("Return the frames as separate high-res images instead of one composite grid. Default false.")
38253
+ code: z22.string().describe("Kiln source code to execute; must define animate() returning the named clip."),
38254
+ clip: z22.string().describe('The animation clip to view, by name (e.g. "walk", "attack"). Must be one your animate() returns.'),
38255
+ camera: z22.string().optional().describe("Camera angle: right (default — side profile, best for leg swing + knee bend direction), front " + "(reveals sideways/lateral motion), back, left, top, or three-quarter."),
38256
+ perFrame: z22.boolean().optional().describe("Return the frames as separate high-res images instead of one composite grid. Default false.")
38223
38257
  });
38224
38258
  var screenshotAnimationAdvertisedInput = screenshotAnimationInput.extend({
38225
38259
  shot: cameraShotRecordInput
38226
38260
  });
38227
- var viewInteriorInput = z20.object({
38261
+ var viewInteriorInput = z22.object({
38228
38262
  capture: advancedCaptureInput.optional(),
38229
- code: z20.string().describe("Kiln source code to execute and render with the roof hidden."),
38230
- nodeName: z20.string().optional().describe("Override: lift the roof by exact node name instead of by role. Matches that node and its " + "children. Normally OMIT it — Kiln finds the roof from its semantic role (anything built " + 'with createRoofPlanes/createGableRoof), falling back to historical "Roof" naming.')
38263
+ code: z22.string().describe("Kiln source code to execute and render with the roof hidden."),
38264
+ nodeName: z22.string().optional().describe("Override: lift the roof by exact node name instead of by role. Matches that node and its " + "children. Normally OMIT it — Kiln finds the roof from its semantic role (anything built " + 'with createRoofPlanes/createGableRoof), falling back to historical "Roof" naming.')
38231
38265
  });
38232
38266
  var viewInteriorAdvertisedInput = viewInteriorInput.extend({ capture: captureRecordInput });
38233
38267
  function runValidate(input, context) {
@@ -38242,11 +38276,11 @@ function runValidate(input, context) {
38242
38276
  warnings: result.warnings.map((w) => w.fixHint ? `${w.message} (${w.fixHint})` : w.message)
38243
38277
  };
38244
38278
  }
38245
- var partListInput = z20.object({
38246
- query: z20.string().max(4096).optional().describe("Case-insensitive substring of name or exact encoded path; not a regex."),
38247
- offset: z20.number().int().min(0).optional(),
38248
- limit: z20.number().int().min(1).max(100).optional(),
38249
- placement: z20.boolean().optional().describe("Add world position, rotation, scale, mirroring and bounds per part; pages of 50.")
38279
+ var partListInput = z22.object({
38280
+ query: z22.string().max(4096).optional().describe("Case-insensitive substring of name or exact encoded path; not a regex."),
38281
+ offset: z22.number().int().min(0).optional(),
38282
+ limit: z22.number().int().min(1).max(100).optional(),
38283
+ placement: z22.boolean().optional().describe("Add world position, rotation, scale, mirroring and bounds per part; pages of 50.")
38250
38284
  }).strict();
38251
38285
  var PLACEMENT_PAGE_LIMIT = 50;
38252
38286
  async function listPartNames2(root, options = {}) {
@@ -38713,35 +38747,35 @@ function createKilnViewInteriorDef(context = {}) {
38713
38747
  };
38714
38748
  }
38715
38749
  var kilnViewInteriorDef = createKilnViewInteriorDef();
38716
- var attachmentEndpointInput = z20.object({
38717
- subject: z20.object({ path: z20.string().optional(), name: z20.string().optional() }).strict(),
38750
+ var attachmentEndpointInput = z22.object({
38751
+ subject: z22.object({ path: z22.string().optional(), name: z22.string().optional() }).strict(),
38718
38752
  point: cameraVec3Input.optional()
38719
38753
  }).strict();
38720
- var surfacePairInput = z20.array(z20.string().max(4096)).length(2);
38721
- var inspectInput = z20.object({
38722
- image: z20.boolean().optional().describe("False: requires listParts/measure/surfacePairs/compare; no image or camera controls. Default true."),
38754
+ var surfacePairInput = z22.array(z22.string().max(4096)).length(2);
38755
+ var inspectInput = z22.object({
38756
+ image: z22.boolean().optional().describe("False: requires listParts/measure/surfacePairs/compare; no image or camera controls. Default true."),
38723
38757
  detail: reviewDetailInput,
38724
38758
  listParts: partListInput.optional().describe("List exported-scene paths, including nested parts. Default 80, max 100 per page. Follow partListing.nextOffset with the same programRef/query. image:false avoids rendering."),
38725
- surfacePairs: z20.array(surfacePairInput).min(1).max(12).optional().describe("[from,to] pairs of exact listParts paths or unambiguous node names; check surfaceMeasurements.status and each result."),
38726
- compare: z20.object({
38727
- programRef: z20.string().regex(programRefPattern),
38728
- offset: z20.number().int().min(0).optional(),
38729
- limit: z20.number().int().min(1).max(100).optional(),
38730
- paths: z20.array(z20.string().max(4096)).min(1).max(12).optional().describe("Exact baseline node paths, scene-prefixed without primitive children. Complete subtree summaries.")
38759
+ surfacePairs: z22.array(surfacePairInput).min(1).max(12).optional().describe("[from,to] pairs of exact listParts paths or unambiguous node names; check surfaceMeasurements.status and each result."),
38760
+ compare: z22.object({
38761
+ programRef: z22.string().regex(programRefPattern),
38762
+ offset: z22.number().int().min(0).optional(),
38763
+ limit: z22.number().int().min(1).max(100).optional(),
38764
+ paths: z22.array(z22.string().max(4096)).min(1).max(12).optional().describe("Exact baseline node paths, scene-prefixed without primitive children. Complete subtree summaries.")
38731
38765
  }).strict().optional().describe("Static geometry/material/transform/bounds under current host settings. Follow nextOffset; paths adds complete subtrees."),
38732
- measure: z20.object({
38733
- mode: z20.enum(["anchors", "surface"]).optional(),
38766
+ measure: z22.object({
38767
+ mode: z22.enum(["anchors", "surface"]).optional(),
38734
38768
  from: attachmentEndpointInput,
38735
38769
  to: attachmentEndpointInput
38736
38770
  }).strict().optional().describe("Default anchors: origin/local-point distance. Surface: disjoint mesh triangles, omit points. Rest pose, asset units. Check status/bounds; no solid clearance/attachment proof."),
38737
38771
  shot: cameraShotInput.optional().describe("Exact shot; omit part/view/orbit controls."),
38738
- code: z20.string().describe("Kiln source code to execute and inspect."),
38739
- part: z20.string().optional().describe("Frame named part and descendants (case-insensitive, substring fallback). Omit for whole asset."),
38740
- view: z20.string().optional().describe("front/right/back/left/top/three-quarter (default). Orbit angles override."),
38741
- azimuthDeg: z20.number().optional().describe("Orbit degrees: 0 front, 90 right, 180 back, 270 left. Wraps."),
38742
- elevationDeg: z20.number().optional().describe("Elevation degrees: 0 eye level, positive above. Clamped -89..89."),
38743
- zoom: z20.number().optional().describe("Bounds padding 1..4; default 1.2. Larger = more context."),
38744
- isolate: z20.boolean().optional().describe("Hide surrounding geometry. Requires part; default false.")
38772
+ code: z22.string().describe("Kiln source code to execute and inspect."),
38773
+ part: z22.string().optional().describe("Frame named part and descendants (case-insensitive, substring fallback). Omit for whole asset."),
38774
+ view: z22.string().optional().describe("front/right/back/left/top/three-quarter (default). Orbit angles override."),
38775
+ azimuthDeg: z22.number().optional().describe("Orbit degrees: 0 front, 90 right, 180 back, 270 left. Wraps."),
38776
+ elevationDeg: z22.number().optional().describe("Elevation degrees: 0 eye level, positive above. Clamped -89..89."),
38777
+ zoom: z22.number().optional().describe("Bounds padding 1..4; default 1.2. Larger = more context."),
38778
+ isolate: z22.boolean().optional().describe("Hide surrounding geometry. Requires part; default false.")
38745
38779
  });
38746
38780
  var inspectBufferInput = inspectInput.omit({ code: true });
38747
38781
  var inspectAdvertisedInput = inspectInput.extend({ shot: cameraShotRecordInput });
@@ -38901,15 +38935,15 @@ function createKilnInspectDef(context = {}) {
38901
38935
  };
38902
38936
  }
38903
38937
  var kilnInspectDef = createKilnInspectDef();
38904
- var editOperationInput = z20.object({
38905
- oldString: z20.string().describe("The exact text to replace, copied verbatim from the program (including whitespace and indentation, and with no line-number prefixes). Must be unique unless replaceAll is true."),
38906
- newString: z20.string().describe("The replacement text. Use an empty string to delete."),
38907
- replaceAll: z20.boolean().optional().describe("Replace every occurrence instead of failing when oldString matches more than once.")
38938
+ var editOperationInput = z22.object({
38939
+ oldString: z22.string().describe("The exact text to replace, copied verbatim from the program (including whitespace and indentation, and with no line-number prefixes). Must be unique unless replaceAll is true."),
38940
+ newString: z22.string().describe("The replacement text. Use an empty string to delete."),
38941
+ replaceAll: z22.boolean().optional().describe("Replace every occurrence instead of failing when oldString matches more than once.")
38908
38942
  });
38909
- var editInput = z20.object({
38910
- code: z20.string().describe("The Kiln program to patch. The full current source."),
38911
- edits: z20.array(editOperationInput).min(1).max(20).describe("Edits applied in order against the program. If any one fails to match, none are applied and the reply says which. Batch related changes into a single call."),
38912
- render: z20.boolean().optional().describe("Render the patched program and return the views (default true). false = patch only."),
38943
+ var editInput = z22.object({
38944
+ code: z22.string().describe("The Kiln program to patch. The full current source."),
38945
+ edits: z22.array(editOperationInput).min(1).max(20).describe("Edits applied in order against the program. If any one fails to match, none are applied and the reply says which. Batch related changes into a single call."),
38946
+ render: z22.boolean().optional().describe("Render the patched program and return the views (default true). false = patch only."),
38913
38947
  capture: captureInput,
38914
38948
  detail: reviewDetailInput
38915
38949
  });
@@ -39135,24 +39169,27 @@ function withCaptureCache(context) {
39135
39169
  } : {}
39136
39170
  };
39137
39171
  }
39138
- var rendererInput = z20.strictObject({
39139
- action: z20.enum(["status", "reprobe"]).default("status")
39172
+ var rendererInput = z22.strictObject({
39173
+ action: z22.enum(["status", "reprobe"]).default("status")
39140
39174
  });
39141
- async function readSavedRevision(target, collection, assetId, revisionId) {
39175
+ async function readSavedRevision(target, collection, assetId, revisionId, listCall = `kiln_assets { action: 'list', collection: '${collection}' }`) {
39142
39176
  try {
39143
39177
  return await target.read(collection, assetId, revisionId);
39144
39178
  } catch (error) {
39145
39179
  if (error.code === "ENOENT")
39146
- throw new Error(`Unknown asset ${assetId} revision ${revisionId} in collection ${collection}. kiln_assets { action: 'list', collection: '${collection}' } lists the saved revisions.`);
39180
+ throw new Error(`Unknown asset ${assetId} revision ${revisionId} in collection ${collection}. ${listCall} lists the saved revisions.`);
39147
39181
  throw error;
39148
39182
  }
39149
39183
  }
39150
39184
  function createKilnProgramToolRegistry(suppliedContext = {}) {
39185
+ return createProgramDefs(suppliedContext, "grouped");
39186
+ }
39187
+ function createProgramDefs(suppliedContext, presentation) {
39151
39188
  toolRequirements(suppliedContext);
39152
39189
  const store = suppliedContext.programStore ?? new MemoryProgramStore;
39153
39190
  const context = withCaptureCache(withBuildCache({ ...suppliedContext, programStore: store }));
39154
39191
  return [
39155
- createKilnDiscoveryDef({ ...suppliedContext, programStore: store }),
39192
+ createKilnDiscoveryDef({ ...suppliedContext, programStore: store }, presentation),
39156
39193
  {
39157
39194
  name: "kiln_renderer",
39158
39195
  description: "Inspect status, or reprobe after renderer setup/repair to refresh this session and reset failed starts. Never installs, starts, stops or renders. Preserves CPU/local/remote selection; environment/credential changes require a host restart. Read viewFidelity after rendering.",
@@ -39192,7 +39229,7 @@ function createKilnProgramToolRegistry(suppliedContext = {}) {
39192
39229
  ].map((def) => withProgramReferences(def, store, context.readSourceFile)),
39193
39230
  createKilnSourceDef(store),
39194
39231
  ...context.projectStore ? [createKilnProjectDef(context.projectStore, context.projectBundleReader)] : [],
39195
- ...context.materialLibrary ? [createKilnMaterialDef(context.materialLibrary)] : [],
39232
+ ...context.materialLibrary ? [createKilnMaterialDef(context.materialLibrary, presentation)] : [],
39196
39233
  ...context.reviewStore && context.assetLibrary ? [
39197
39234
  createKilnReviewDef({
39198
39235
  reviewStore: context.reviewStore,
@@ -39200,7 +39237,7 @@ function createKilnProgramToolRegistry(suppliedContext = {}) {
39200
39237
  requirements: context.requirements
39201
39238
  })
39202
39239
  ] : [],
39203
- ...createKilnAssetDefs({ ...context, programStore: store })
39240
+ ...createKilnAssetDefs({ ...context, programStore: store }, presentation)
39204
39241
  ].map((def) => withWorkspaceContext(def, context)).map((def) => ({
39205
39242
  ...def,
39206
39243
  annotations: {
@@ -39220,14 +39257,14 @@ function createKilnNativeToolRegistry(suppliedContext, completion) {
39220
39257
  programStore: suppliedContext.programStore ?? new MemoryProgramStore,
39221
39258
  programArtifacts: suppliedContext.programArtifacts ?? new ProgramArtifactStore
39222
39259
  };
39223
- const inputSchema = z20.strictObject({
39224
- programRef: z20.string().regex(programRefPattern)
39260
+ const inputSchema = z22.strictObject({
39261
+ programRef: z22.string().regex(programRefPattern)
39225
39262
  });
39226
- const skillResourceInput = z20.strictObject({
39227
- skill: z20.string().min(1).max(64),
39228
- path: z20.string().min(1).max(240).optional(),
39229
- offset: z20.number().int().min(0).max(262144).default(0),
39230
- limit: z20.number().int().min(1).max(16000).default(12000)
39263
+ const skillResourceInput = z22.strictObject({
39264
+ skill: z22.string().min(1).max(64),
39265
+ path: z22.string().min(1).max(240).optional(),
39266
+ offset: z22.number().int().min(0).max(262144).default(0),
39267
+ limit: z22.number().int().min(1).max(16000).default(12000)
39231
39268
  });
39232
39269
  const delivery = new Set([
39233
39270
  "kiln_save",
@@ -39278,14 +39315,41 @@ function createKilnNativeToolRegistry(suppliedContext, completion) {
39278
39315
  ];
39279
39316
  }
39280
39317
  var assetSelector = {
39281
- collection: z20.string().regex(/^[a-z][a-z0-9_-]{0,79}$/).describe("Collection ID (list with kiln_assets action=collections): the user destination, else project.").default("project"),
39282
- assetId: z20.string().regex(/^[a-z][a-z0-9_-]{0,79}$/),
39283
- revisionId: z20.string().regex(/^[a-z][a-z0-9_-]{0,79}$/)
39318
+ collection: z22.string().regex(/^[a-z][a-z0-9_-]{0,79}$/).describe("Collection ID (list with kiln_assets action=collections): the user destination, else project.").default("project"),
39319
+ assetId: z22.string().regex(/^[a-z][a-z0-9_-]{0,79}$/),
39320
+ revisionId: z22.string().regex(/^[a-z][a-z0-9_-]{0,79}$/)
39284
39321
  };
39285
- async function newestRevision(target, collection, assetId) {
39322
+ var ASSET_CONTRACT = {
39323
+ collections: {
39324
+ fields: [],
39325
+ required: [],
39326
+ description: "List configured asset storage collections. Collection is not project membership."
39327
+ },
39328
+ catalog: {
39329
+ fields: ["assetId", "query", "offset", "limit"],
39330
+ required: [],
39331
+ description: "Search saved assets across configured collections with pagination."
39332
+ },
39333
+ list: {
39334
+ fields: ["collection", "assetId", "query", "offset", "limit"],
39335
+ required: [],
39336
+ description: "Search saved assets in one collection with pagination."
39337
+ },
39338
+ get: {
39339
+ fields: ["collection", "assetId", "revisionId"],
39340
+ required: ["assetId"],
39341
+ description: "Read a saved revision and its download descriptors. Omit revisionId for the newest revision."
39342
+ },
39343
+ restore: {
39344
+ fields: ["collection", "assetId", "revisionId"],
39345
+ required: ["assetId"],
39346
+ description: "Restore exact saved source as programRef for editing or rendering. Omit revisionId for the newest revision. Does not overwrite the saved revision. Binary-only assets have no source."
39347
+ }
39348
+ };
39349
+ async function newestRevision(target, collection, assetId, listCall = `kiln_assets { action: 'list', collection: '${collection}' }`) {
39286
39350
  const revisions = (await target.list(collection)).filter((a) => a.assetId === assetId);
39287
39351
  if (!revisions.length)
39288
- throw new Error(`Unknown asset ${assetId} in ${collection}; kiln_assets { action: 'list', collection: '${collection}' } lists them.`);
39352
+ throw new Error(`Unknown asset ${assetId} in ${collection}; ${listCall} lists them.`);
39289
39353
  const parents = new Set(revisions.map((a) => a.parentRevision).filter(Boolean));
39290
39354
  const heads = revisions.filter((a) => !parents.has(a.revisionId));
39291
39355
  const newest = (heads.length ? heads : revisions).sort((a, b) => a.createdAt < b.createdAt ? 1 : a.createdAt > b.createdAt ? -1 : 0);
@@ -39350,7 +39414,12 @@ async function buildProgramAssetDraft(code, context, backdrop) {
39350
39414
  }
39351
39415
  };
39352
39416
  }
39353
- function createKilnAssetDefs(context) {
39417
+ function createKilnAssetDefs(context, presentation = "grouped") {
39418
+ const listCall = (collection) => presentation === "operations" ? `kiln_assets_search({ collection: '${collection}' })` : `kiln_assets { action: 'list', collection: '${collection}' }`;
39419
+ const selector = presentation === "operations" ? {
39420
+ ...assetSelector,
39421
+ collection: assetSelector.collection.describe("Collection ID from kiln_assets_collections; default project.")
39422
+ } : assetSelector;
39354
39423
  const library = () => {
39355
39424
  if (!context.assetLibrary)
39356
39425
  throw new Error("No asset library configured. The local CLI/MCP host supplies workspace collections; embedded hosts must inject assetLibrary.");
@@ -39378,38 +39447,38 @@ function createKilnAssetDefs(context) {
39378
39447
  resources: (await Promise.resolve().then(() => (init_assets_resources(), exports_assets_resources))).assetLinks(collection, asset),
39379
39448
  downloadUrls: await context.assetDownloadUrls?.(collection, asset.assetId, asset.revisionId)
39380
39449
  });
39381
- const saveInput = z20.object({
39382
- collection: assetSelector.collection,
39383
- programRef: z20.string(),
39384
- name: z20.string().min(1).max(200),
39385
- assetId: assetSelector.assetId.optional(),
39386
- parentRevision: assetSelector.revisionId.optional(),
39387
- tags: z20.array(z20.string().max(80)).max(30).optional(),
39388
- brief: z20.string().max(8000).optional(),
39389
- description: z20.string().max(4000).optional(),
39390
- attribution: z20.object({
39391
- model: z20.string().max(200).optional(),
39392
- harness: z20.string().max(200).optional(),
39393
- author: z20.string().max(200).optional()
39450
+ const saveInput = z22.object({
39451
+ collection: selector.collection,
39452
+ programRef: z22.string(),
39453
+ name: z22.string().min(1).max(200),
39454
+ assetId: selector.assetId.optional(),
39455
+ parentRevision: selector.revisionId.optional(),
39456
+ tags: z22.array(z22.string().max(80)).max(30).optional(),
39457
+ brief: z22.string().max(8000).optional(),
39458
+ description: z22.string().max(4000).optional(),
39459
+ attribution: z22.object({
39460
+ model: z22.string().max(200).optional(),
39461
+ harness: z22.string().max(200).optional(),
39462
+ author: z22.string().max(200).optional()
39394
39463
  }).optional(),
39395
- backdrop: z20.enum(BACKDROP_IDS).optional().describe("Preview backdrop: the one the reviewed sheet used.")
39396
- });
39397
- const assetsInput = z20.object({
39398
- action: z20.enum(["collections", "catalog", "list", "get", "restore"]).default("list"),
39399
- collection: assetSelector.collection,
39400
- assetId: assetSelector.assetId.optional(),
39401
- revisionId: assetSelector.revisionId.optional().describe("get, restore: the saved revision; omitted, the newest."),
39402
- query: z20.string().max(200).optional(),
39403
- offset: z20.number().int().min(0).default(0),
39404
- limit: z20.number().int().min(1).max(50).default(20)
39405
- });
39406
- const exportInput = z20.object(assetSelector);
39464
+ backdrop: z22.enum(BACKDROP_IDS).optional().describe("Preview backdrop: the one the reviewed sheet used.")
39465
+ });
39466
+ const assetsInput = z22.object({
39467
+ action: z22.enum(["collections", "catalog", "list", "get", "restore"]).default("list"),
39468
+ collection: selector.collection,
39469
+ assetId: selector.assetId.optional(),
39470
+ revisionId: selector.revisionId.optional().describe("get, restore: the saved revision; omitted, the newest."),
39471
+ query: z22.string().max(200).optional(),
39472
+ offset: z22.number().int().min(0).default(0),
39473
+ limit: z22.number().int().min(1).max(50).default(20)
39474
+ });
39475
+ const exportInput = z22.object(selector);
39407
39476
  const profileExportInput = exportInput.extend({
39408
- profile: z20.enum(["editable", "runtime"]).default("editable").describe("editable preserves canonical source/GLB/build resources. runtime returns a standalone GLB and versioned review-metadata sidecar; no source bundle or geometry optimization.")
39477
+ profile: z22.enum(["editable", "runtime"]).default("editable").describe("editable preserves canonical source/GLB/build resources. runtime returns a standalone GLB and versioned review-metadata sidecar; no source bundle or geometry optimization.")
39409
39478
  });
39410
- const importInput = z20.object({
39411
- ...assetSelector,
39412
- sourceCollection: assetSelector.collection
39479
+ const importInput = z22.object({
39480
+ ...selector,
39481
+ sourceCollection: selector.collection
39413
39482
  });
39414
39483
  return [
39415
39484
  {
@@ -39425,7 +39494,7 @@ function createKilnAssetDefs(context) {
39425
39494
  requirements: activeRequirements.binding
39426
39495
  };
39427
39496
  if (input.assetId && input.parentRevision) {
39428
- const previous = await readSavedRevision(target, input.collection, input.assetId, input.parentRevision);
39497
+ const previous = await readSavedRevision(target, input.collection, input.assetId, input.parentRevision, listCall(input.collection));
39429
39498
  assertSavedRequirementsAuthorized(previous.manifest, activeRequirements);
39430
39499
  }
39431
39500
  const code = await context.programStore.get(input.programRef);
@@ -39440,6 +39509,7 @@ function createKilnAssetDefs(context) {
39440
39509
  name: "kiln_assets",
39441
39510
  description: "Browse saved assets: collections discovers storage; catalog searches all configured collections; list searches one. Both searches paginate. get returns a build record/downloads; restore loads exact source for kiln_source/kiln_edit. Collection is not project membership. Binary-only assets cannot restore source.",
39442
39511
  inputSchema: assetsInput,
39512
+ actionContract: ASSET_CONTRACT,
39443
39513
  run: async (raw) => {
39444
39514
  const input = assetsInput.parse(raw);
39445
39515
  const activeRequirements = toolRequirements(context);
@@ -39484,10 +39554,10 @@ function createKilnAssetDefs(context) {
39484
39554
  }))
39485
39555
  };
39486
39556
  }
39487
- if (!input.assetId)
39557
+ if (ASSET_CONTRACT[input.action].required.some((field) => !input[field]))
39488
39558
  throw new Error(`kiln_assets ${input.action} requires assetId; kiln_assets { action: 'list', collection: '${input.collection}' } lists them.`);
39489
- const revisionId = input.revisionId ?? await newestRevision(target, input.collection, input.assetId);
39490
- const record = await readSavedRevision(target, input.collection, input.assetId, revisionId);
39559
+ const revisionId = input.revisionId ?? await newestRevision(target, input.collection, input.assetId, listCall(input.collection));
39560
+ const record = await readSavedRevision(target, input.collection, input.assetId, revisionId, listCall(input.collection));
39491
39561
  if (input.action === "get")
39492
39562
  return links(input.collection, record.manifest);
39493
39563
  const saved = assertSavedRequirementsAuthorized(record.manifest, activeRequirements);
@@ -39507,9 +39577,9 @@ function createKilnAssetDefs(context) {
39507
39577
  name: "kiln_present",
39508
39578
  description: "Present one exact saved revision. Supporting MCP App clients show an interactive 3D card with GLB, editable ZIP, and source downloads. Every host receives exact artifact descriptors with resource URIs in the JSON result; verified hosts may also receive core MCP resource-link blocks. This tool does not launch a local browser in coding harnesses. Call after saving or when the user wants to see or download an asset.",
39509
39579
  inputSchema: exportInput,
39510
- outputSchema: z20.object({
39511
- ok: z20.literal(true),
39512
- collection: z20.string(),
39580
+ outputSchema: z22.object({
39581
+ ok: z22.literal(true),
39582
+ collection: z22.string(),
39513
39583
  asset: assetManifestSchema.pick({
39514
39584
  assetId: true,
39515
39585
  revisionId: true,
@@ -39520,25 +39590,25 @@ function createKilnAssetDefs(context) {
39520
39590
  editable: true,
39521
39591
  files: true
39522
39592
  }).extend({
39523
- build: z20.object({
39524
- engine: z20.string(),
39525
- rebuild: z20.enum(["engine-required", "external-dependencies-required"]),
39526
- warningCount: z20.number().int(),
39527
- warnings: z20.array(z20.string())
39593
+ build: z22.object({
39594
+ engine: z22.string(),
39595
+ rebuild: z22.enum(["engine-required", "external-dependencies-required"]),
39596
+ warningCount: z22.number().int(),
39597
+ warnings: z22.array(z22.string())
39528
39598
  }).optional()
39529
39599
  }),
39530
- resources: z20.array(z20.object({
39531
- type: z20.literal("resource_link"),
39532
- name: z20.string(),
39533
- uri: z20.string(),
39534
- mimeType: z20.string(),
39535
- size: z20.number().int().nonnegative(),
39536
- annotations: z20.object({
39537
- audience: z20.array(z20.enum(["user", "assistant"])),
39538
- priority: z20.number()
39600
+ resources: z22.array(z22.object({
39601
+ type: z22.literal("resource_link"),
39602
+ name: z22.string(),
39603
+ uri: z22.string(),
39604
+ mimeType: z22.string(),
39605
+ size: z22.number().int().nonnegative(),
39606
+ annotations: z22.object({
39607
+ audience: z22.array(z22.enum(["user", "assistant"])),
39608
+ priority: z22.number()
39539
39609
  })
39540
39610
  })),
39541
- downloadUrls: z20.record(z20.string(), z20.string()).optional()
39611
+ downloadUrls: z22.record(z22.string(), z22.string()).optional()
39542
39612
  }),
39543
39613
  ui: {
39544
39614
  resourceUri: KILN_ASSET_WIDGET_URI,
@@ -39555,7 +39625,7 @@ function createKilnAssetDefs(context) {
39555
39625
  inputSchema: profileExportInput,
39556
39626
  run: async (raw) => {
39557
39627
  const input = profileExportInput.parse(raw);
39558
- const record = await readSavedRevision(library(), input.collection, input.assetId, input.revisionId);
39628
+ const record = await readSavedRevision(library(), input.collection, input.assetId, input.revisionId, listCall(input.collection));
39559
39629
  await Promise.resolve().then(() => init_draw_diagnostics());
39560
39630
  if (input.profile === "runtime") {
39561
39631
  const output = await (await Promise.resolve().then(() => (init_asset_export(), exports_asset_export))).exportAssetGlb(record, {
@@ -39589,7 +39659,7 @@ function createKilnAssetDefs(context) {
39589
39659
  run: async (raw) => {
39590
39660
  const input = importInput.parse(raw);
39591
39661
  const target = library();
39592
- const record = await readSavedRevision(target, input.sourceCollection, input.assetId, input.revisionId);
39662
+ const record = await readSavedRevision(target, input.sourceCollection, input.assetId, input.revisionId, listCall(input.sourceCollection));
39593
39663
  await target.import(input.collection, [record]);
39594
39664
  return links(input.collection, record.manifest);
39595
39665
  }