@everfir/az8-cli 0.3.0-preview.1 → 0.3.0-preview.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,29 @@ it does not inherit the Web application or monorepo root version.
5
5
 
6
6
  ## Unreleased
7
7
 
8
+ ## 0.3.0-preview.2 - 2026-07-23
9
+
10
+ ### Added
11
+
12
+ - Cursor-only Awareness acknowledgement after a remote Canvas Watch delivery has been flushed and
13
+ internally acknowledged.
14
+ - Advisory `data.createdByCli` provenance on every View Node created through the CLI.
15
+
16
+ ### Changed
17
+
18
+ - CLI-created Notes retain the authenticated Actor id and display the current client suffix in
19
+ their visible creator label.
20
+ - Ordinary Resource View Nodes no longer receive invented generic creator metadata.
21
+ - The built-in agent Skill recommends early visible generation targets and empty Text Resources
22
+ when artifact type and placement are already unambiguous.
23
+
24
+ ### Safety and compatibility
25
+
26
+ - Delivery Awareness never responds to the CLI's own changes, never publishes Selection, and does
27
+ not represent understanding or completion.
28
+ - Editing an existing View Node preserves its creation provenance; duplicating stamps the new node
29
+ with the current client suffix.
30
+
8
31
  ## 0.3.0-preview.1 - 2026-07-23
9
32
 
10
33
  ### Added
package/README.md CHANGED
@@ -18,7 +18,7 @@ az8 guide
18
18
  For a supplied preview artifact, install the exact immutable tarball instead:
19
19
 
20
20
  ```bash
21
- npm install --global ./everfir-az8-cli-0.3.0-preview.1.tgz
21
+ npm install --global ./everfir-az8-cli-0.3.0-preview.2.tgz
22
22
  az8 --version
23
23
  ```
24
24
 
package/RELEASE.md CHANGED
@@ -60,7 +60,7 @@ authorization:
60
60
  For a preview candidate, publish the exact retained artifact to the preview channel:
61
61
 
62
62
  ```bash
63
- npm publish ./tmp/az8-cli-release/everfir-az8-cli-0.3.0-preview.1.tgz --tag preview
63
+ npm publish ./tmp/az8-cli-release/everfir-az8-cli-0.3.0-preview.2.tgz --tag preview
64
64
  npm view @everfir/az8-cli dist-tags versions --json
65
65
  ```
66
66
 
package/dist/main.js CHANGED
@@ -14175,11 +14175,26 @@ var CANVAS_OPERATION_REGISTRY = [
14175
14175
  },
14176
14176
  required: ["referenceViewNodeId", "viewNodeId"]
14177
14177
  }),
14178
+ write2("insertPromptReference", "Bind one visible image, text, or video View Node and place its platform At token in the Prompt", "silent", {
14179
+ properties: {
14180
+ placement: { enum: ["start", "end"], type: "string" },
14181
+ referenceViewNodeId: stringSchema(),
14182
+ viewNodeId: stringSchema()
14183
+ },
14184
+ required: ["referenceViewNodeId", "viewNodeId"]
14185
+ }),
14178
14186
  write2("removeVisualReference", "Remove one Canvas View Node reference from a generation Draft", "silent", {
14179
14187
  properties: { referenceId: stringSchema(), viewNodeId: stringSchema() },
14180
14188
  required: ["referenceId", "viewNodeId"]
14181
14189
  }),
14182
14190
  write2("startGeneration", "Estimate current Draft inputs, start a Workflow Run, and acknowledge immediate Canvas writes", "barrier", { properties: { viewNodeId: stringSchema() }, required: ["viewNodeId"] }, "workflow-accepted"),
14191
+ write2("reconcileGenerationStart", "Reconcile one known Workflow Run with its target without starting another Run", "barrier", {
14192
+ properties: {
14193
+ viewNodeId: stringSchema(),
14194
+ workflowRunId: stringSchema()
14195
+ },
14196
+ required: ["viewNodeId", "workflowRunId"]
14197
+ }),
14183
14198
  read("getWorkflowRun", "Read one Workflow Run", {
14184
14199
  properties: { workflowRunId: stringSchema() },
14185
14200
  required: ["workflowRunId"]
@@ -14246,10 +14261,25 @@ function sizeSchema() {
14246
14261
  }
14247
14262
 
14248
14263
  // ../../packages/project-canvas-runtime/dist/operation-usage.js
14264
+ function attachCanvasOperationIndeterminateResult(value, result3) {
14265
+ const cause = value instanceof Error ? value : new Error("Unexpected Canvas Operation failure.");
14266
+ const error51 = new Error(cause.message, { cause });
14267
+ return Object.assign(error51, {
14268
+ indeterminate: true,
14269
+ operationResult: structuredClone(result3),
14270
+ ..."timedOut" in cause && cause.timedOut === true ? { timedOut: true } : {}
14271
+ });
14272
+ }
14249
14273
  function attachCanvasOperationUsage(value, usage) {
14250
14274
  const error51 = value instanceof Error ? value : new Error("Unexpected Canvas Operation failure.");
14251
14275
  return Object.assign(error51, { operationUsage: usage });
14252
14276
  }
14277
+ function readCanvasOperationIndeterminateResult(value) {
14278
+ if (typeof value !== "object" || value === null || !("operationResult" in value))
14279
+ return void 0;
14280
+ const result3 = value.operationResult;
14281
+ return typeof result3 === "object" && result3 !== null && !Array.isArray(result3) ? result3 : void 0;
14282
+ }
14253
14283
  function readCanvasOperationUsage(value) {
14254
14284
  if (typeof value !== "object" || value === null || !("operationUsage" in value))
14255
14285
  return void 0;
@@ -15022,6 +15052,37 @@ function addVisualReferenceToDraft(draft, definition, reference, sourceDataType,
15022
15052
  }
15023
15053
  return appendPromptReferenceToken(nextDraft, slot.name, reference.id, reference.viewNodeId, now);
15024
15054
  }
15055
+ function insertPromptReferenceIntoDraft(draft, definition, reference, sourceDataType, placement, now) {
15056
+ const withReference = addVisualReferenceToDraft(draft, definition, reference, sourceDataType, now);
15057
+ const binding = Object.entries(withReference.inputs.slots).flatMap(([slotName, values]) => values.flatMap((value, index) => value.kind === "view-node" && value.id === reference.id ? [{ index, slotName, value }] : []))[0];
15058
+ if (!binding)
15059
+ throw new Error(`Generation Reference ${reference.id} does not exist in the Draft.`);
15060
+ if (binding.value.sourceDataType !== "image" && binding.value.sourceDataType !== "text" && binding.value.sourceDataType !== "video") {
15061
+ throw new Error("Prompt References must resolve to image, text, or video content.");
15062
+ }
15063
+ const promptSlot = requirePromptSlot(definition);
15064
+ const withoutExistingToken = removePromptReferenceToken(withReference, reference.id);
15065
+ const promptValues = withoutExistingToken.inputs.slots[promptSlot.name] ?? [];
15066
+ const existingLiteral = promptValues.find((value) => value.kind === "literal" && value.assetType === "text");
15067
+ const promptInput = existingLiteral ?? literal(withoutExistingToken, promptSlot.name, "text", "");
15068
+ const prompt = promptInput.content;
15069
+ const token = `{{@${binding.value.sourceDataType}:${binding.slotName}:${binding.index}:${reference.id}|view-node|${encodeURIComponent(reference.viewNodeId)}}}`;
15070
+ const content = placement === "start" ? prompt.trim() ? `${token}
15071
+ ${prompt}` : token : prompt.trim() ? `${prompt}${prompt.endsWith("\n") ? "" : "\n"}${token}` : token;
15072
+ return {
15073
+ ...structuredClone(withoutExistingToken),
15074
+ inputs: {
15075
+ slots: {
15076
+ ...structuredClone(withoutExistingToken.inputs.slots),
15077
+ [promptSlot.name]: [
15078
+ { ...promptInput, content },
15079
+ ...promptValues.filter((value) => value.id !== promptInput.id)
15080
+ ]
15081
+ }
15082
+ },
15083
+ updatedAt: now
15084
+ };
15085
+ }
15025
15086
  function removeVisualReferenceFromDraft(draft, referenceId, now) {
15026
15087
  let removed = false;
15027
15088
  let removedTextReference = false;
@@ -15322,7 +15383,8 @@ function createGenerationExecutionOperations(input) {
15322
15383
  if (definitionChanges || Object.keys(editInput).length > 2) {
15323
15384
  operations.push({ input: editInput, name: "editGenerationDraft" });
15324
15385
  }
15325
- const currentReferences = definitionChanges ? [] : readGenerationDraftReferences(input.currentDraft);
15386
+ const promptSlotName = resolvePromptSlot(input.definition)?.name;
15387
+ const currentReferences = (definitionChanges ? [] : readGenerationDraftReferences(input.currentDraft)).filter((reference) => editInput.prompt === void 0 || reference.sourceSlotName !== promptSlotName);
15326
15388
  const desiredKeys = new Set(input.assignments.map((item) => referenceKey(item.reference)));
15327
15389
  for (const current of currentReferences) {
15328
15390
  if (!current.draftInputId || desiredKeys.has(referenceKey(current)))
@@ -15823,7 +15885,14 @@ async function resolveEffectiveTextInputContent(input) {
15823
15885
  if (!literal3)
15824
15886
  return null;
15825
15887
  const fragmentsByBindingId = /* @__PURE__ */ new Map();
15826
- for (const reference of input.references) {
15888
+ const bindingsById = /* @__PURE__ */ new Map();
15889
+ for (const [slotName, references] of Object.entries(input.allReferencesBySlot)) {
15890
+ for (const reference of references) {
15891
+ if (reference.kind !== "literal")
15892
+ bindingsById.set(reference.id, { reference, slotName });
15893
+ }
15894
+ }
15895
+ for (const reference of Object.values(input.allReferencesBySlot).flat()) {
15827
15896
  if (reference.kind !== "view-node" || reference.sourceDataType !== "text")
15828
15897
  continue;
15829
15898
  const content = await input.resolveViewNodeTextContent(reference.viewNodeId);
@@ -15831,8 +15900,17 @@ async function resolveEffectiveTextInputContent(input) {
15831
15900
  fragmentsByBindingId.set(reference.id, content.trim());
15832
15901
  }
15833
15902
  const positionedBindingIds = /* @__PURE__ */ new Set();
15834
- const positionedContent = literal3.content.replace(new RegExp(PROMPT_REFERENCE_TOKEN_PATTERN2, "g"), (token, _contentType, _slotName, _index, bindingId) => {
15903
+ const positionedContent = literal3.content.replace(new RegExp(PROMPT_REFERENCE_TOKEN_PATTERN2, "g"), (token, contentType, slotName, _rawIndex, bindingId, encodedViewNodeId) => {
15835
15904
  if (!bindingId)
15905
+ throw new Error("Prompt contains an At token without a binding identity.");
15906
+ const binding = bindingsById.get(bindingId);
15907
+ if (!binding || binding.slotName !== slotName || binding.reference.sourceDataType !== contentType) {
15908
+ throw new Error(`Prompt At token ${bindingId} does not match its Generation binding.`);
15909
+ }
15910
+ if (encodedViewNodeId && (binding.reference.kind !== "view-node" || binding.reference.viewNodeId !== decodePromptViewNodeId(encodedViewNodeId))) {
15911
+ throw new Error(`Prompt At token ${bindingId} does not match its View Node.`);
15912
+ }
15913
+ if (contentType !== "text")
15836
15914
  return token;
15837
15915
  const content = fragmentsByBindingId.get(bindingId);
15838
15916
  if (content === void 0)
@@ -15841,11 +15919,21 @@ async function resolveEffectiveTextInputContent(input) {
15841
15919
  return content;
15842
15920
  });
15843
15921
  const trailingFragments = [...fragmentsByBindingId.entries()].flatMap(([bindingId, content]) => positionedBindingIds.has(bindingId) ? [] : [content]);
15844
- if (new RegExp(PROMPT_REFERENCE_TOKEN_PATTERN2).test(positionedContent)) {
15922
+ const unresolvedTextToken = [
15923
+ ...positionedContent.matchAll(new RegExp(PROMPT_REFERENCE_TOKEN_PATTERN2, "g"))
15924
+ ].some((match) => match[1] === "text");
15925
+ if (unresolvedTextToken) {
15845
15926
  throw new Error("Prompt contains an unresolved Text View Node reference.");
15846
15927
  }
15847
15928
  return appendUniqueTextFragments(positionedContent, trailingFragments);
15848
15929
  }
15930
+ function decodePromptViewNodeId(value) {
15931
+ try {
15932
+ return decodeURIComponent(value);
15933
+ } catch {
15934
+ throw new Error("Prompt At token contains an invalid View Node identity.");
15935
+ }
15936
+ }
15849
15937
  function appendUniqueTextFragments(base, fragments) {
15850
15938
  let result3 = base;
15851
15939
  for (const fragment of fragments) {
@@ -15865,6 +15953,7 @@ async function prepareGenerationInput(input) {
15865
15953
  for (const slot of input.definition.inputSchema) {
15866
15954
  const references = input.draft.inputs.slots[slot.name] ?? [];
15867
15955
  const effectiveText = slot.name === promptSlot?.name ? await resolveEffectiveTextInputContent({
15956
+ allReferencesBySlot: input.draft.inputs.slots,
15868
15957
  references,
15869
15958
  resolveViewNodeTextContent: input.resolveViewNodeTextContent
15870
15959
  }) : null;
@@ -15981,10 +16070,15 @@ var CoreNodeCreativeLoop = class {
15981
16070
  return this.editDraft(input, timeoutMs);
15982
16071
  if (name === "addVisualReference")
15983
16072
  return this.addVisualReference(input, timeoutMs);
16073
+ if (name === "insertPromptReference")
16074
+ return this.insertPromptReference(input, timeoutMs);
15984
16075
  if (name === "removeVisualReference")
15985
16076
  return this.removeVisualReference(input, timeoutMs);
15986
16077
  if (name === "startGeneration")
15987
16078
  return this.startGeneration(input, timeoutMs);
16079
+ if (name === "reconcileGenerationStart") {
16080
+ return this.reconcileGenerationStart(input, timeoutMs);
16081
+ }
15988
16082
  if (name === "getWorkflowRun")
15989
16083
  return this.getWorkflowRun(input);
15990
16084
  if (name === "waitWorkflowRun")
@@ -16160,23 +16254,28 @@ var CoreNodeCreativeLoop = class {
16160
16254
  const draft = requireDraft(target);
16161
16255
  const definition = await this.requireDefinition(draft.definitionId);
16162
16256
  const referenceViewNodeId = requireString3(input.referenceViewNodeId, "referenceViewNodeId");
16163
- const referenceViewNode = this.requireViewNode(referenceViewNodeId);
16164
- if (referenceViewNode.type !== "resource") {
16165
- throw new Error("Generation References require a resource View Node.");
16166
- }
16167
- let sourceDataType = referenceViewNode.contentType ?? "";
16168
- const referenceCoreNodeId = this.resolveViewNodeCoreNodeId(referenceViewNode);
16169
- if (sourceDataType !== "text" || asRecord3(referenceViewNode.data).mode === "content") {
16170
- if (!referenceCoreNodeId)
16171
- throw new Error("Referenced View Node has no current Core Node.");
16172
- const coreNode = await this.requireCoreNode(referenceCoreNodeId);
16173
- sourceDataType = readCoreNodeDataType2(coreNode);
16174
- }
16257
+ const sourceDataType = await this.resolveReferenceDataType(referenceViewNodeId);
16175
16258
  const referenceId = `input_ref_${crypto.randomUUID().replaceAll("-", "")}`;
16176
16259
  const nextDraft = addVisualReferenceToDraft(draft, definition, { id: referenceId, kind: "view-node", viewNodeId: referenceViewNodeId }, sourceDataType, this.context.now());
16177
16260
  await this.replaceDraft(target, nextDraft, "Add Visual Reference", timeoutMs);
16178
16261
  return attention(target.id, { referenceId, viewNodeId: target.id });
16179
16262
  }
16263
+ async insertPromptReference(input, timeoutMs) {
16264
+ assertOnlyKeys3(input, ["placement", "referenceViewNodeId", "viewNodeId"]);
16265
+ const target = this.requireTarget(requireString3(input.viewNodeId, "viewNodeId"));
16266
+ const draft = requireDraft(target);
16267
+ const definition = await this.requireDefinition(draft.definitionId);
16268
+ const referenceViewNodeId = requireString3(input.referenceViewNodeId, "referenceViewNodeId");
16269
+ const sourceDataType = await this.resolveReferenceDataType(referenceViewNodeId);
16270
+ const existing = Object.values(draft.inputs.slots).flat().find((reference) => reference.kind === "view-node" && reference.viewNodeId === referenceViewNodeId);
16271
+ const referenceId = existing?.id ?? `input_ref_${crypto.randomUUID().replaceAll("-", "")}`;
16272
+ const placement = input.placement === void 0 ? "end" : input.placement === "start" || input.placement === "end" ? input.placement : null;
16273
+ if (!placement)
16274
+ throw new Error("placement must be start or end.");
16275
+ const nextDraft = insertPromptReferenceIntoDraft(draft, definition, { id: referenceId, kind: "view-node", viewNodeId: referenceViewNodeId }, sourceDataType, placement, this.context.now());
16276
+ await this.replaceDraft(target, nextDraft, "Insert Prompt Reference", timeoutMs);
16277
+ return attention(target.id, { placement, referenceId, viewNodeId: target.id });
16278
+ }
16180
16279
  async removeVisualReference(input, timeoutMs) {
16181
16280
  assertOnlyKeys3(input, ["referenceId", "viewNodeId"]);
16182
16281
  const target = this.requireTarget(requireString3(input.viewNodeId, "viewNodeId"));
@@ -16187,7 +16286,8 @@ var CoreNodeCreativeLoop = class {
16187
16286
  }
16188
16287
  async startGeneration(input, timeoutMs) {
16189
16288
  let estimate;
16190
- let runAccepted = false;
16289
+ let acceptedRun;
16290
+ let acceptedTargetId;
16191
16291
  try {
16192
16292
  assertOnlyKeys3(input, ["viewNodeId"]);
16193
16293
  const target = this.requireTarget(requireString3(input.viewNodeId, "viewNodeId"));
@@ -16200,6 +16300,10 @@ var CoreNodeCreativeLoop = class {
16200
16300
  resolveViewNodeCoreNodeId: (id2) => this.resolveViewNodeCoreNodeId(this.requireViewNode(id2)),
16201
16301
  resolveViewNodeTextContent: (id2) => this.resolveViewNodeTextContent(this.requireViewNode(id2))
16202
16302
  });
16303
+ const targetSnapshot = structuredClone(target);
16304
+ const targetData = normalizeOptionalRecord(target.data, "View Node data");
16305
+ const targetHistory = readGenerationHistory(target.history);
16306
+ const effectivePrompt = readPrompt(prepared.effectiveDraft);
16203
16307
  estimate = await this.systems.workflowRuntime.estimateRun({ definitionId: definition.id, inputs: prepared.estimateInputs }, { timeoutMs });
16204
16308
  if (!estimate.canAfford)
16205
16309
  throw new Error("Insufficient credits to start this generation.");
@@ -16218,7 +16322,8 @@ var CoreNodeCreativeLoop = class {
16218
16322
  { slotName: output.slotName, targetId: target.id, targetSlot: draft.id }
16219
16323
  ]
16220
16324
  }, { timeoutMs });
16221
- runAccepted = true;
16325
+ acceptedRun = run;
16326
+ acceptedTargetId = target.id;
16222
16327
  this.runs.set(run.id, run);
16223
16328
  const timestamp = this.context.now();
16224
16329
  const historyEntry = {
@@ -16234,15 +16339,15 @@ var CoreNodeCreativeLoop = class {
16234
16339
  },
16235
16340
  updatedAt: timestamp
16236
16341
  };
16237
- const { creationIntent: _creationIntent, ...data } = asRecord3(target.data);
16342
+ const { creationIntent: _creationIntent, ...data } = targetData;
16238
16343
  const after = {
16239
- ...structuredClone(target),
16344
+ ...targetSnapshot,
16240
16345
  data: {
16241
16346
  ...data,
16242
- ...readPrompt(prepared.effectiveDraft) === null ? {} : { prompt: readPrompt(prepared.effectiveDraft) }
16347
+ ...effectivePrompt === null ? {} : { prompt: effectivePrompt }
16243
16348
  },
16244
16349
  draft: null,
16245
- history: toDocumentJson([...readGenerationHistory(target.history), historyEntry]),
16350
+ history: toDocumentJson([...targetHistory, historyEntry]),
16246
16351
  updatedAt: timestamp
16247
16352
  };
16248
16353
  await this.context.commit({
@@ -16264,8 +16369,15 @@ var CoreNodeCreativeLoop = class {
16264
16369
  usage: estimatedUsage(estimate)
16265
16370
  };
16266
16371
  } catch (error51) {
16267
- const usage = runAccepted && estimate ? estimatedUsage(estimate) : isIndeterminateWrite(error51) ? unknownUsage(estimate) : notConsumedUsage(estimate);
16268
- throw attachCanvasOperationUsage(error51, usage);
16372
+ const failure = acceptedRun && acceptedTargetId ? attachCanvasOperationIndeterminateResult(error51, {
16373
+ canvasAcknowledged: false,
16374
+ reconciliationRequired: true,
16375
+ status: acceptedRun.status,
16376
+ viewNodeId: acceptedTargetId,
16377
+ workflowRunId: acceptedRun.id
16378
+ }) : error51;
16379
+ const usage = acceptedRun && estimate ? estimatedUsage(estimate) : isIndeterminateWrite(error51) ? unknownUsage(estimate) : notConsumedUsage(estimate);
16380
+ throw attachCanvasOperationUsage(failure, usage);
16269
16381
  }
16270
16382
  }
16271
16383
  async getWorkflowRun(input) {
@@ -16273,6 +16385,133 @@ var CoreNodeCreativeLoop = class {
16273
16385
  const run = await this.refreshRun(requireString3(input.workflowRunId, "workflowRunId"), 15e3);
16274
16386
  return { result: { workflowRun: run } };
16275
16387
  }
16388
+ async reconcileGenerationStart(input, timeoutMs) {
16389
+ assertOnlyKeys3(input, ["viewNodeId", "workflowRunId"]);
16390
+ const target = this.requireTarget(requireString3(input.viewNodeId, "viewNodeId"));
16391
+ const workflowRunId = requireString3(input.workflowRunId, "workflowRunId");
16392
+ const run = await this.systems.workflowRuntime.getRun(workflowRunId);
16393
+ if (!run)
16394
+ throw new Error(`Workflow Run ${workflowRunId} does not exist.`);
16395
+ this.recordRun(run);
16396
+ const sync = await this.systems.projectContent.syncProject(this.context.projectId, 0, {
16397
+ timeoutMs
16398
+ });
16399
+ this.projection.merge(sync.contents);
16400
+ const history = readGenerationHistory(target.history);
16401
+ const existing = history.find((entry) => entry.runtime.instanceIds.includes(run.id));
16402
+ if (existing) {
16403
+ if (existing.definitionId !== run.definitionId) {
16404
+ return reconciliationResult(target.id, run.id, "conflict", {
16405
+ reason: "The existing History entry and Workflow Run use different Definitions."
16406
+ });
16407
+ }
16408
+ const repairedPendingState = !isTerminalWorkflowRunStatus(run.status) && !this.isPending(run.id);
16409
+ if (isTerminalWorkflowRunStatus(run.status))
16410
+ await this.settleRun(run, timeoutMs);
16411
+ else if (repairedPendingState) {
16412
+ await this.context.commit({
16413
+ addPendingWorkflowInstanceIds: [run.id],
16414
+ after: [],
16415
+ before: [],
16416
+ history: "barrier",
16417
+ label: "Reconcile generation start",
16418
+ timeoutMs
16419
+ });
16420
+ this.watchRun(run.id, timeoutMs);
16421
+ }
16422
+ return reconciliationResult(target.id, run.id, "consistent", {
16423
+ repairedPendingState,
16424
+ workflowStatus: run.status
16425
+ });
16426
+ }
16427
+ const draft = readGenerationDraft(target.draft);
16428
+ if (!draft) {
16429
+ return reconciliationResult(target.id, run.id, "conflict", {
16430
+ reason: "The target has neither a matching History entry nor its original Draft.",
16431
+ workflowStatus: run.status
16432
+ });
16433
+ }
16434
+ if (draft.definitionId !== run.definitionId) {
16435
+ return reconciliationResult(target.id, run.id, "conflict", {
16436
+ reason: "The target Draft and Workflow Run use different Definitions.",
16437
+ workflowStatus: run.status
16438
+ });
16439
+ }
16440
+ if (!isTerminalWorkflowRunStatus(run.status)) {
16441
+ return reconciliationResult(target.id, run.id, "running-insufficient", {
16442
+ reason: "The running Workflow does not yet expose authoritative target output evidence. Wait for a terminal state; do not start another Run.",
16443
+ workflowStatus: run.status
16444
+ });
16445
+ }
16446
+ if (run.status !== "completed") {
16447
+ return reconciliationResult(target.id, run.id, "terminal", {
16448
+ reason: "The Workflow ended without a completed output, so no History entry was invented.",
16449
+ workflowStatus: run.status
16450
+ });
16451
+ }
16452
+ const submittedAt = parseWorkflowTimestamp(run.createdAt);
16453
+ if (submittedAt === null) {
16454
+ return reconciliationResult(target.id, run.id, "insufficient", {
16455
+ reason: "The completed Workflow Run has no trustworthy submission timestamp.",
16456
+ workflowStatus: run.status
16457
+ });
16458
+ }
16459
+ if ((draft.updatedAt ?? draft.createdAt) > submittedAt) {
16460
+ return reconciliationResult(target.id, run.id, "conflict", {
16461
+ reason: "The target Draft changed after the Workflow Run was submitted.",
16462
+ workflowStatus: run.status
16463
+ });
16464
+ }
16465
+ const definition = await this.requireDefinition(run.definitionId);
16466
+ const primaryOutput = requirePrimaryOutput(definition, target.contentType);
16467
+ const targetOutputs = sync.contents.filter((content) => content.sourceId === run.id || content.workflowInstanceId === run.id).flatMap((content) => content.outputs).filter((output) => output.targetId === target.id && output.targetSlot === draft.id && output.slotName === primaryOutput.slotName);
16468
+ if (targetOutputs.length === 0) {
16469
+ return reconciliationResult(target.id, run.id, "insufficient", {
16470
+ reason: "The completed Workflow Run has no Project Content output bound to this target and Draft.",
16471
+ workflowStatus: run.status
16472
+ });
16473
+ }
16474
+ const outputCoreNodeIds = new Set(run.outputs.map((output) => output.coreNodeId));
16475
+ if (outputCoreNodeIds.size > 0 && targetOutputs.every((output) => !outputCoreNodeIds.has(output.coreNodeId))) {
16476
+ return reconciliationResult(target.id, run.id, "conflict", {
16477
+ reason: "Workflow and Project Content outputs disagree.",
16478
+ workflowStatus: run.status
16479
+ });
16480
+ }
16481
+ const timestamp = this.context.now();
16482
+ const historyEntry = {
16483
+ ...draft,
16484
+ runtime: {
16485
+ ...run.definitionVersion === void 0 ? {} : { expectedDefinitionVersion: run.definitionVersion },
16486
+ instanceIds: [run.id],
16487
+ materializedInputs: inferReconciledMaterializedInputs(draft, run),
16488
+ originClientId: "unknown",
16489
+ submittedAt
16490
+ },
16491
+ updatedAt: timestamp
16492
+ };
16493
+ const { creationIntent: _creationIntent, ...data } = normalizeOptionalRecord(target.data, "View Node data");
16494
+ const prompt = readPrompt(draft);
16495
+ const after = {
16496
+ ...structuredClone(target),
16497
+ data: { ...data, ...prompt === null ? {} : { prompt } },
16498
+ draft: null,
16499
+ history: toDocumentJson([...history, historyEntry]),
16500
+ updatedAt: timestamp
16501
+ };
16502
+ await this.context.commit({
16503
+ after: [after],
16504
+ before: [target],
16505
+ history: "barrier",
16506
+ label: "Reconcile generation start",
16507
+ ...this.isPending(run.id) ? { removePendingWorkflowInstanceIds: [run.id] } : {},
16508
+ timeoutMs
16509
+ });
16510
+ return reconciliationResult(target.id, run.id, "repaired", {
16511
+ outputCoreNodeIds: [...new Set(targetOutputs.map((output) => output.coreNodeId))],
16512
+ workflowStatus: run.status
16513
+ });
16514
+ }
16276
16515
  async waitWorkflowRun(input, timeoutMs) {
16277
16516
  assertOnlyKeys3(input, ["workflowRunId"]);
16278
16517
  const id2 = requireString3(input.workflowRunId, "workflowRunId");
@@ -16479,6 +16718,21 @@ var CoreNodeCreativeLoop = class {
16479
16718
  this.definitions.set(id2, definition);
16480
16719
  return definition;
16481
16720
  }
16721
+ async resolveReferenceDataType(referenceViewNodeId) {
16722
+ const referenceViewNode = this.requireViewNode(referenceViewNodeId);
16723
+ if (referenceViewNode.type !== "resource") {
16724
+ throw new Error("Generation References require a resource View Node.");
16725
+ }
16726
+ let sourceDataType = referenceViewNode.contentType ?? "";
16727
+ const referenceCoreNodeId = this.resolveViewNodeCoreNodeId(referenceViewNode);
16728
+ if (sourceDataType !== "text" || asRecord3(referenceViewNode.data).mode === "content") {
16729
+ if (!referenceCoreNodeId)
16730
+ throw new Error("Referenced View Node has no current Core Node.");
16731
+ const coreNode = await this.requireCoreNode(referenceCoreNodeId);
16732
+ sourceDataType = readCoreNodeDataType2(coreNode);
16733
+ }
16734
+ return sourceDataType;
16735
+ }
16482
16736
  requireTarget(id2) {
16483
16737
  const viewNode = this.requireViewNode(id2);
16484
16738
  requireSupportedContentType(viewNode.contentType);
@@ -16524,8 +16778,6 @@ var CoreNodeCreativeLoop = class {
16524
16778
  data: {
16525
16779
  ...contentType === "text" ? { mode: "content" } : {},
16526
16780
  ...data,
16527
- creator_id: this.context.actor.id,
16528
- creator_name: this.context.actor.displayName,
16529
16781
  ...name ? { label: name } : {}
16530
16782
  },
16531
16783
  draft: null,
@@ -16563,6 +16815,14 @@ function createEstimatedCompletionTimes(estimate, submittedAt) {
16563
16815
  function attention(viewNodeId, result3) {
16564
16816
  return { attention: { kind: "view-nodes", viewNodeIds: [viewNodeId] }, result: result3 };
16565
16817
  }
16818
+ function reconciliationResult(viewNodeId, workflowRunId, reconciliationStatus, detail) {
16819
+ return attention(viewNodeId, {
16820
+ ...detail,
16821
+ reconciliationStatus,
16822
+ viewNodeId,
16823
+ workflowRunId
16824
+ });
16825
+ }
16566
16826
  function requireDraft(viewNode) {
16567
16827
  const draft = readGenerationDraft(viewNode.draft);
16568
16828
  if (!draft)
@@ -16588,6 +16848,38 @@ function readPrompt(draft) {
16588
16848
  }
16589
16849
  return null;
16590
16850
  }
16851
+ function inferReconciledMaterializedInputs(draft, run) {
16852
+ const materialized = {};
16853
+ for (const [slotName, bindings] of Object.entries(draft.inputs.slots)) {
16854
+ const references = bindings.filter((binding) => binding.kind !== "literal");
16855
+ if (references.length === 0)
16856
+ continue;
16857
+ const input = run.inputs[slotName];
16858
+ if (typeof input !== "object" || input === null || Array.isArray(input) || !("coreNodeIds" in input) || !Array.isArray(input.coreNodeIds)) {
16859
+ continue;
16860
+ }
16861
+ const coreNodeIds = input.coreNodeIds.filter((coreNodeId) => typeof coreNodeId === "string" && Boolean(coreNodeId));
16862
+ if (references.length === 1) {
16863
+ const reference = references[0];
16864
+ if (reference)
16865
+ materialized[slotName] = [{ coreNodeIds, inputRefId: reference.id }];
16866
+ continue;
16867
+ }
16868
+ if (references.length !== coreNodeIds.length)
16869
+ continue;
16870
+ materialized[slotName] = references.map((reference, index) => ({
16871
+ coreNodeIds: [coreNodeIds[index]],
16872
+ inputRefId: reference.id
16873
+ }));
16874
+ }
16875
+ return materialized;
16876
+ }
16877
+ function parseWorkflowTimestamp(value) {
16878
+ if (!value)
16879
+ return null;
16880
+ const timestamp = Date.parse(value);
16881
+ return Number.isFinite(timestamp) ? timestamp : null;
16882
+ }
16591
16883
  function parseConfig2(value) {
16592
16884
  const record2 = asRecord3(value);
16593
16885
  for (const item of Object.values(record2)) {
@@ -16616,6 +16908,14 @@ function asRecord3(value) {
16616
16908
  }
16617
16909
  return value;
16618
16910
  }
16911
+ function normalizeOptionalRecord(value, field) {
16912
+ if (value === void 0 || value === null)
16913
+ return {};
16914
+ if (typeof value !== "object" || Array.isArray(value)) {
16915
+ throw new Error(`${field} must be an object when present.`);
16916
+ }
16917
+ return structuredClone(value);
16918
+ }
16619
16919
  function requireString3(value, field) {
16620
16920
  if (typeof value !== "string" || !value.trim())
16621
16921
  throw new Error(`${field} must be non-empty.`);
@@ -16775,8 +17075,6 @@ var ExternalMediaImporter = class {
16775
17075
  data: {
16776
17076
  contentBindingError: null,
16777
17077
  contentBindingStatus: "pending",
16778
- creator_id: this.context.actor.id,
16779
- creator_name: this.context.actor.displayName,
16780
17078
  [IMPORT_INTENT_DATA_KEY]: structuredClone(intent),
16781
17079
  label: intent.name
16782
17080
  },
@@ -17201,8 +17499,6 @@ var MediaUploader = class {
17201
17499
  data: {
17202
17500
  contentBindingError: null,
17203
17501
  contentBindingStatus: "pending",
17204
- creator_id: this.context.actor.id,
17205
- creator_name: this.context.actor.displayName,
17206
17502
  label: intent.name,
17207
17503
  [UPLOAD_INTENT_DATA_KEY]: structuredClone(intent)
17208
17504
  },
@@ -17991,6 +18287,7 @@ var SemanticCanvasRuntime = class {
17991
18287
  unsubscribeRemote;
17992
18288
  commands;
17993
18289
  contentProjection;
18290
+ creationProvenanceSuffix;
17994
18291
  creativeLoop;
17995
18292
  externalMediaImporter;
17996
18293
  mediaUploader;
@@ -18000,12 +18297,12 @@ var SemanticCanvasRuntime = class {
18000
18297
  constructor(options) {
18001
18298
  this.options = options;
18002
18299
  this.now = options.now ?? Date.now;
18300
+ this.creationProvenanceSuffix = normalizeCreationProvenanceSuffix(options.clientName);
18003
18301
  this.commands = createProjectCanvasCommandExecutor(options.document, this.now);
18004
18302
  this.contentProjection = new ProjectContentProjection(options.projectContents);
18005
18303
  this.projectionRevision = options.initialRevision ?? 1;
18006
18304
  this.snapshot = options.document.getSnapshot();
18007
18305
  const operationContext = {
18008
- actor: options.actor,
18009
18306
  canWrite: options.role !== "viewer",
18010
18307
  clientInstanceId: options.clientInstanceId ?? "unknown",
18011
18308
  commit: async (input) => {
@@ -18342,15 +18639,18 @@ var SemanticCanvasRuntime = class {
18342
18639
  };
18343
18640
  }
18344
18641
  async commit(entry, timeoutMs) {
18345
- await this.applyHistoryState(entry.after, entry.viewNodeIds, entry.label, timeoutMs);
18346
- this.undoStack.push({ ...entry, kind: "reversible" });
18642
+ const after = this.stampCreatedViewNodes(entry.after, entry.before);
18643
+ await this.applyHistoryState(after, entry.viewNodeIds, entry.label, timeoutMs);
18644
+ this.undoStack.push({ ...entry, after, kind: "reversible" });
18347
18645
  this.redoStack.length = 0;
18348
18646
  }
18349
18647
  async applyOperationPlan(plan, timeoutMs) {
18350
18648
  if (plan.changes.length > 0) {
18649
+ const before = plan.changes.map((change) => change.before);
18650
+ const after = this.stampCreatedViewNodes(plan.changes.map((change) => change.after), before);
18351
18651
  const entry = {
18352
- after: plan.changes.map((change) => change.after),
18353
- before: plan.changes.map((change) => change.before),
18652
+ after,
18653
+ before,
18354
18654
  kind: "reversible",
18355
18655
  label: plan.label,
18356
18656
  viewNodeIds: plan.changes.map((change) => change.viewNodeId)
@@ -18387,16 +18687,23 @@ var SemanticCanvasRuntime = class {
18387
18687
  });
18388
18688
  }
18389
18689
  async applySemanticChanges(changes, label, timeoutMs, history, addPendingWorkflowInstanceIds, removePendingWorkflowInstanceIds) {
18690
+ const preparedChanges = changes.map((change) => ({
18691
+ ...change,
18692
+ after: change.before === null ? this.stampCreatedViewNode(change.after) : structuredClone(change.after)
18693
+ }));
18390
18694
  const previous = this.snapshot;
18391
18695
  this.snapshot = await this.commands.changeViewNodes({
18392
18696
  ...addPendingWorkflowInstanceIds ? { addPendingWorkflowInstanceIds } : {},
18393
- changes: changes.map((change) => ({ state: change.after, viewNodeId: change.viewNodeId })),
18697
+ changes: preparedChanges.map((change) => ({
18698
+ state: change.after,
18699
+ viewNodeId: change.viewNodeId
18700
+ })),
18394
18701
  operationName: label,
18395
18702
  ...removePendingWorkflowInstanceIds ? { removePendingWorkflowInstanceIds } : {},
18396
18703
  timeoutMs
18397
18704
  });
18398
18705
  this.projectionRevision += 1;
18399
- const viewNodeIds = changes.map((change) => change.viewNodeId);
18706
+ const viewNodeIds = preparedChanges.map((change) => change.viewNodeId);
18400
18707
  const viewNodeChanges = diffSemanticViewNodes(previous.viewNodes, this.snapshot.viewNodes, viewNodeIds);
18401
18708
  this.emit({
18402
18709
  changedViewNodeIds: viewNodeIds,
@@ -18406,8 +18713,8 @@ var SemanticCanvasRuntime = class {
18406
18713
  });
18407
18714
  if (history === "undoable") {
18408
18715
  this.undoStack.push({
18409
- after: changes.map((change) => change.after),
18410
- before: changes.map((change) => change.before),
18716
+ after: preparedChanges.map((change) => change.after),
18717
+ before: preparedChanges.map((change) => change.before),
18411
18718
  kind: "reversible",
18412
18719
  label,
18413
18720
  viewNodeIds
@@ -18418,6 +18725,22 @@ var SemanticCanvasRuntime = class {
18418
18725
  this.redoStack.length = 0;
18419
18726
  }
18420
18727
  }
18728
+ stampCreatedViewNodes(after, before) {
18729
+ return after.map((viewNode, index) => viewNode !== null && before[index] === null ? this.stampCreatedViewNode(viewNode) : structuredClone(viewNode));
18730
+ }
18731
+ stampCreatedViewNode(viewNode) {
18732
+ if (!this.creationProvenanceSuffix)
18733
+ return structuredClone(viewNode);
18734
+ const data = typeof viewNode.data === "object" && viewNode.data !== null && !Array.isArray(viewNode.data) ? structuredClone(viewNode.data) : {};
18735
+ delete data.creator_id;
18736
+ delete data.creator_name;
18737
+ data.createdByCli = this.creationProvenanceSuffix;
18738
+ if (viewNode.type === "note") {
18739
+ data.creator_id = this.options.actor.id;
18740
+ data.creator_name = `${this.options.actor.displayName} (${this.creationProvenanceSuffix})`;
18741
+ }
18742
+ return { ...structuredClone(viewNode), data };
18743
+ }
18421
18744
  nextNotePosition() {
18422
18745
  const count = this.snapshot.viewNodes.length;
18423
18746
  return { x: 160 + count % 4 * 348, y: 160 + Math.floor(count / 4) * 348 };
@@ -18472,7 +18795,7 @@ function duplicateInputContainsResource(snapshot, input) {
18472
18795
  return snapshot.viewNodes.some((viewNode) => ids.has(viewNode.id) && viewNode.type === "resource");
18473
18796
  }
18474
18797
  function isCreativeLoopOperation(name) {
18475
- return name === "getCoreNode" || name === "placeCoreNode" || name === "createGenerationTarget" || name === "createMediaTarget" || name === "planGeneration" || name === "editGenerationDraft" || name === "addVisualReference" || name === "removeVisualReference" || name === "startGeneration" || name === "getWorkflowRun" || name === "waitWorkflowRun";
18798
+ return name === "getCoreNode" || name === "placeCoreNode" || name === "createGenerationTarget" || name === "createMediaTarget" || name === "planGeneration" || name === "editGenerationDraft" || name === "addVisualReference" || name === "insertPromptReference" || name === "removeVisualReference" || name === "startGeneration" || name === "reconcileGenerationStart" || name === "getWorkflowRun" || name === "waitWorkflowRun";
18476
18799
  }
18477
18800
  function createViewNodeId() {
18478
18801
  return `view_node_${crypto.randomUUID().replaceAll("-", "")}`;
@@ -18510,6 +18833,17 @@ function requireString6(value, field) {
18510
18833
  throw new Error(`${field} must be a string.`);
18511
18834
  return value;
18512
18835
  }
18836
+ function normalizeCreationProvenanceSuffix(value) {
18837
+ if (value === void 0)
18838
+ return null;
18839
+ const normalized = value.trim();
18840
+ if (!normalized)
18841
+ throw new Error("clientName must be non-empty when provided.");
18842
+ if (normalized.includes("(") || normalized.includes(")")) {
18843
+ throw new Error("clientName must not contain parentheses.");
18844
+ }
18845
+ return normalized;
18846
+ }
18513
18847
 
18514
18848
  // src/integrations/backend.ts
18515
18849
  var BackendRequestError = class extends Error {
@@ -23716,6 +24050,7 @@ var AgentCollaborationWatch = class {
23716
24050
  now;
23717
24051
  pending = [];
23718
24052
  recent = [];
24053
+ workflowWatermarks = /* @__PURE__ */ new Map();
23719
24054
  activeWait = null;
23720
24055
  continuityLost = false;
23721
24056
  constructor(options = {}) {
@@ -23728,7 +24063,13 @@ var AgentCollaborationWatch = class {
23728
24063
  this.now = options.now ?? Date.now;
23729
24064
  }
23730
24065
  patchInterests(input) {
23731
- return this.interests.patch(input);
24066
+ const result3 = this.interests.patch(input);
24067
+ for (const key of result3.changedKeys) {
24068
+ for (const watermarkKey of this.workflowWatermarks.keys()) {
24069
+ if (watermarkKey.startsWith(`${key}\0`)) this.workflowWatermarks.delete(watermarkKey);
24070
+ }
24071
+ }
24072
+ return result3;
23732
24073
  }
23733
24074
  getInterests() {
23734
24075
  return this.interests.getAll();
@@ -23752,10 +24093,24 @@ var AgentCollaborationWatch = class {
23752
24093
  recordMany(facts) {
23753
24094
  if (this.continuityLost) return;
23754
24095
  for (const fact of facts) {
23755
- for (const interest of this.interests.matching(fact)) this.enqueue(interest.key, fact);
24096
+ for (const interest of this.interests.matching(fact)) {
24097
+ this.recordWorkflowWatermark(interest.key, fact);
24098
+ this.enqueue(interest.key, fact);
24099
+ }
23756
24100
  }
23757
24101
  if (this.activeWait && (this.pending.length > 0 || this.continuityLost)) this.deliverActive();
23758
24102
  }
24103
+ recordAuthoritativeWorkflow(fact) {
24104
+ if (fact.domain !== "workflow" || this.continuityLost) return;
24105
+ for (const interest of this.interests.matching(fact)) {
24106
+ const key = workflowWatermarkKey(interest.key, fact.ref);
24107
+ const fingerprint = workflowFingerprint(fact);
24108
+ if (this.workflowWatermarks.get(key) === fingerprint) continue;
24109
+ this.workflowWatermarks.set(key, fingerprint);
24110
+ this.enqueue(interest.key, fact);
24111
+ }
24112
+ if (this.activeWait && this.pending.length > 0) this.deliverActive();
24113
+ }
23759
24114
  wait(options) {
23760
24115
  const timeoutMs = positive(options.timeoutMs, "timeoutMs");
23761
24116
  if (this.activeWait)
@@ -23789,6 +24144,11 @@ var AgentCollaborationWatch = class {
23789
24144
  resynchronize() {
23790
24145
  this.continuityLost = false;
23791
24146
  this.pending.length = 0;
24147
+ this.workflowWatermarks.clear();
24148
+ }
24149
+ recordWorkflowWatermark(interest, fact) {
24150
+ if (fact.domain !== "workflow") return;
24151
+ this.workflowWatermarks.set(workflowWatermarkKey(interest, fact.ref), workflowFingerprint(fact));
23792
24152
  }
23793
24153
  enqueue(interest, fact) {
23794
24154
  const terminalPending = this.pending.find(
@@ -23832,6 +24192,7 @@ var AgentCollaborationWatch = class {
23832
24192
  merged: entry.merged,
23833
24193
  quietForMs: Math.max(0, now - entry.lastObservedAt),
23834
24194
  ref: entry.fact.ref,
24195
+ ...entry.fact.domain === "canvas" ? { source: entry.fact.source } : {},
23835
24196
  summary: structuredClone(entry.fact.summary)
23836
24197
  }));
23837
24198
  const result3 = {
@@ -23908,6 +24269,18 @@ function positive(value, field) {
23908
24269
  function watchError(code, message) {
23909
24270
  return Object.assign(new Error(message), { code });
23910
24271
  }
24272
+ function workflowWatermarkKey(interest, runId) {
24273
+ return `${interest}\0${runId}`;
24274
+ }
24275
+ function workflowFingerprint(fact) {
24276
+ return JSON.stringify({
24277
+ changeKind: fact.changeKind,
24278
+ kind: fact.kind,
24279
+ status: fact.status,
24280
+ summary: fact.summary,
24281
+ terminal: fact.terminal
24282
+ });
24283
+ }
23911
24284
 
23912
24285
  // src/canvas/session.ts
23913
24286
  var CanvasSession = class {
@@ -23934,6 +24307,7 @@ var CanvasSession = class {
23934
24307
  runtime = null;
23935
24308
  unsubscribeRuntime = null;
23936
24309
  observationListeners = /* @__PURE__ */ new Set();
24310
+ knownWorkflowRunIds = /* @__PURE__ */ new Set();
23937
24311
  projectionRevision = 0;
23938
24312
  actorId = null;
23939
24313
  collaborationContext = null;
@@ -23983,6 +24357,7 @@ var CanvasSession = class {
23983
24357
  const connectionId = this.health.connectionId;
23984
24358
  const runtime = new SemanticCanvasRuntime({
23985
24359
  actor: { displayName: actor.displayName, id: actor.accountId },
24360
+ clientName: normalizedClientName,
23986
24361
  clientInstanceId: this.clientInstanceId,
23987
24362
  document: document2,
23988
24363
  foundationData,
@@ -24001,6 +24376,9 @@ var CanvasSession = class {
24001
24376
  workflowRuntime
24002
24377
  });
24003
24378
  this.runtime = runtime;
24379
+ for (const workflowRunId of runtime.getSnapshot().pendingWorkflowInstanceIds) {
24380
+ this.knownWorkflowRunIds.add(workflowRunId);
24381
+ }
24004
24382
  this.projectionRevision = runtime.revision;
24005
24383
  this.unsubscribeRuntime = runtime.subscribe((observation) => {
24006
24384
  this.projectionRevision = observation.revision;
@@ -24024,11 +24402,58 @@ var CanvasSession = class {
24024
24402
  }
24025
24403
  async execute(name, input, timeoutMs) {
24026
24404
  const runtime = this.requireRuntime();
24405
+ if (typeof input.workflowRunId === "string" && input.workflowRunId) {
24406
+ this.knownWorkflowRunIds.add(input.workflowRunId);
24407
+ }
24027
24408
  const result3 = await runtime.execute(name, input, timeoutMs);
24409
+ if (typeof result3.result.workflowRunId === "string" && result3.result.workflowRunId) {
24410
+ this.knownWorkflowRunIds.add(result3.result.workflowRunId);
24411
+ }
24028
24412
  this.projectionRevision = result3.revision;
24029
24413
  if (result3.attention) this.publishAttention(result3.attention);
24030
24414
  return result3;
24031
24415
  }
24416
+ async catchUpWorkflowInterests(timeoutMs) {
24417
+ const runtime = this.requireRuntime();
24418
+ const deadline = Date.now() + timeoutMs;
24419
+ const knownWorkflowRunIds = [...this.knownWorkflowRunIds];
24420
+ const runIds = [
24421
+ ...new Set(
24422
+ this.watch.getInterests().filter((interest) => interest.kind === "workflow").flatMap((interest) => interest.filter.runIds ?? knownWorkflowRunIds)
24423
+ )
24424
+ ];
24425
+ for (const workflowRunId of runIds) {
24426
+ const remainingMs = deadline - Date.now();
24427
+ if (remainingMs < 1) break;
24428
+ try {
24429
+ const result3 = await runtime.execute("getWorkflowRun", { workflowRunId }, remainingMs);
24430
+ const workflowRun = result3.result.workflowRun;
24431
+ if (!isWorkflowRun(workflowRun)) continue;
24432
+ for (const fact of projectCanvasObservation(
24433
+ { kind: "workflow", revision: result3.revision, workflowRun },
24434
+ Date.now()
24435
+ )) {
24436
+ this.watch.recordAuthoritativeWorkflow(fact);
24437
+ }
24438
+ } catch {
24439
+ }
24440
+ }
24441
+ }
24442
+ acknowledgeWatchDelivery(result3) {
24443
+ if (result3.status !== "ready") return;
24444
+ for (const change of result3.changes) {
24445
+ if (change.source !== "remote" || !change.kind.startsWith("note.") && !change.kind.startsWith("view-node.")) {
24446
+ continue;
24447
+ }
24448
+ const bounds = this.requireRuntime().resolveAttentionBounds({
24449
+ kind: "view-nodes",
24450
+ viewNodeIds: [change.ref]
24451
+ });
24452
+ if (!bounds) continue;
24453
+ this.publishAttentionBounds(bounds);
24454
+ return;
24455
+ }
24456
+ }
24032
24457
  getCapabilities(detail) {
24033
24458
  return this.requireRuntime().capabilities.map(
24034
24459
  (descriptor2) => detail ? descriptor2 : {
@@ -24142,6 +24567,9 @@ function isIndeterminateWrite4(value) {
24142
24567
  function isWorkflowRecoveryExhausted(value) {
24143
24568
  return typeof value === "object" && value !== null && "workflowRecoveryExhausted" in value && value.workflowRecoveryExhausted === true;
24144
24569
  }
24570
+ function isWorkflowRun(value) {
24571
+ return typeof value === "object" && value !== null && "id" in value && typeof value.id === "string" && "status" in value && typeof value.status === "string" && "definitionId" in value && typeof value.definitionId === "string" && "outputs" in value && Array.isArray(value.outputs);
24572
+ }
24145
24573
 
24146
24574
  // src/canvas/client.ts
24147
24575
  var CANVAS_QUERY_TARGETS = [
@@ -24236,6 +24664,7 @@ var CanvasClient = class {
24236
24664
  });
24237
24665
  return { receipt };
24238
24666
  } catch (error51) {
24667
+ const operationResult2 = readCanvasOperationIndeterminateResult(error51);
24239
24668
  const operationUsage = readCanvasOperationUsage(error51);
24240
24669
  const indeterminate = isIndeterminateError(error51);
24241
24670
  const timedOut = indeterminate && (error51 instanceof IndeterminateBackendWriteError && error51.timedOut || readTimedOut(error51) || error51 instanceof Error && /timed out/i.test(error51.message));
@@ -24247,6 +24676,7 @@ var CanvasClient = class {
24247
24676
  message: safeCanvasMessage(error51),
24248
24677
  outcome: indeterminate ? "indeterminate" : "failed"
24249
24678
  },
24679
+ ...operationResult2 ? { result: redactCanvasRecord(operationResult2) } : {},
24250
24680
  status: timedOut ? "timed-out" : "failed",
24251
24681
  ...operationUsage ? { usage: operationUsage } : {}
24252
24682
  });
@@ -24856,7 +25286,16 @@ async function startAgentSessionDaemon(spec, dependencies = {}) {
24856
25286
  }
24857
25287
  if (request.kind === "delivery.ack") {
24858
25288
  const acknowledged = outstandingDelivery?.deliveryId === request.deliveryId;
24859
- if (acknowledged) outstandingDelivery = void 0;
25289
+ if (acknowledged) {
25290
+ const result3 = outstandingDelivery?.result;
25291
+ outstandingDelivery = void 0;
25292
+ if (result3) {
25293
+ try {
25294
+ client.session.acknowledgeWatchDelivery?.(result3);
25295
+ } catch {
25296
+ }
25297
+ }
25298
+ }
24860
25299
  return { acknowledged };
24861
25300
  }
24862
25301
  if (request.kind === "interests.get") return watch.getInterests();
@@ -24882,7 +25321,10 @@ async function startAgentSessionDaemon(spec, dependencies = {}) {
24882
25321
  }
24883
25322
  if (request.kind === "watch.wait") {
24884
25323
  if (outstandingDelivery) return outstandingDelivery;
24885
- const result3 = await watch.wait({ signal: context.signal, timeoutMs: request.timeoutMs });
25324
+ const startedAt = Date.now();
25325
+ await client.session.catchUpWorkflowInterests?.(Math.min(request.timeoutMs, 15e3));
25326
+ const remainingMs = Math.max(1, request.timeoutMs - (Date.now() - startedAt));
25327
+ const result3 = await watch.wait({ signal: context.signal, timeoutMs: remainingMs });
24886
25328
  if (result3.status !== "ready") return { result: result3 };
24887
25329
  outstandingDelivery = { deliveryId: crypto.randomUUID(), result: result3 };
24888
25330
  return outstandingDelivery;
@@ -24949,6 +25391,8 @@ async function createCanvasClient(spec, dependencies) {
24949
25391
  executeOperation: (input) => client.executeOperation(input),
24950
25392
  query: (input) => client.query(input),
24951
25393
  session: {
25394
+ acknowledgeWatchDelivery: (result3) => session.acknowledgeWatchDelivery(result3),
25395
+ catchUpWorkflowInterests: (timeoutMs) => session.catchUpWorkflowInterests(timeoutMs),
24952
25396
  getContext: () => session.getCollaborationContext(),
24953
25397
  getHealth: () => session.getHealth(),
24954
25398
  getIdentity: () => session.getIdentity(),
@@ -44620,7 +45064,7 @@ function registerCanvasCommands(program2, dependencies, setResult) {
44620
45064
  // package.json
44621
45065
  var package_default = {
44622
45066
  name: "@everfir/az8-cli",
44623
- version: "0.3.0-preview.1",
45067
+ version: "0.3.0-preview.2",
44624
45068
  description: "Semantic Project Canvas client for AZ8 Studio agents.",
44625
45069
  license: "UNLICENSED",
44626
45070
  type: "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@everfir/az8-cli",
3
- "version": "0.3.0-preview.1",
3
+ "version": "0.3.0-preview.2",
4
4
  "description": "Semantic Project Canvas client for AZ8 Studio agents.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -230,12 +230,20 @@ one-shot processes.
230
230
 
231
231
  1. Query `canvas.summary`; query selected details only as needed.
232
232
  2. Query `capabilities.detail` and validate the planned Operation input against its schema.
233
- 3. Pick explicit absolute Canvas coordinates. Public move positions remain absolute even for group
233
+ 3. When artifact type and placement are already clear, make the first meaningful Canvas state
234
+ visible before doing lengthy prompt refinement or generation planning:
235
+ - create the empty generation target first, then plan and edit its Draft;
236
+ - create an empty manual Text Resource with `text: ""`, then fill it with
237
+ `editTextContent`;
238
+ - create a Note with its useful content directly rather than creating an empty sticky.
239
+ Do not create a placeholder while its type or placement is still ambiguous. Watch and the
240
+ Session daemon never create placeholders automatically.
241
+ 4. Pick explicit absolute Canvas coordinates. Public move positions remain absolute even for group
234
242
  children.
235
- 4. Submit one Operation with a new request ID and wait for its terminal Receipt.
236
- 5. Confirm the Receipt outcome and affected IDs, then query the changed View Node when subsequent
243
+ 5. Submit one Operation with a new request ID and wait for its terminal Receipt.
244
+ 6. Confirm the Receipt outcome and affected IDs, then query the changed View Node when subsequent
237
245
  work depends on its exact state.
238
- 6. Only then plan the next interaction.
246
+ 7. Only then plan the next interaction.
239
247
 
240
248
  Common capabilities include notes, manual Text Resources, move/resize/rename, duplicate/remove,
241
249
  groups and stacking, Core Node placement, and generation targets. The runtime catalog is
@@ -270,6 +278,11 @@ Generation is an explicit sequence, never one transaction:
270
278
  plan.
271
279
  4. Execute `plan.operations` exactly in order, one Operation at a time. Each step revalidates
272
280
  current facts. Stop after the first non-success.
281
+ When a reference must also appear at a meaningful Prompt position, use
282
+ `insertPromptReference` with the target View Node, visible reference View Node, and
283
+ `placement: "start"` or `"end"`. The CLI creates and validates the binding and At token
284
+ atomically. Do not write `{{@...}}`, choose an input slot/index, or allocate a binding ID
285
+ yourself. `addVisualReference` remains the connection-only operation.
273
286
  5. `startGeneration` succeeds when the Workflow Run is accepted and immediate Canvas effects are
274
287
  acknowledged. This completes the start interaction; it does not mean generation finished.
275
288
  6. Retain the Workflow Run ID. After the successful start Receipt, continue any work that does not
@@ -283,6 +296,19 @@ Generation is an explicit sequence, never one transaction:
283
296
  8. On terminal success, query the target detail and resolve its current output Core Node through
284
297
  Project Content before downloading or placing it elsewhere.
285
298
 
299
+ If `startGeneration` returns an indeterminate Receipt after the Workflow was accepted, retain
300
+ `receipt.result.workflowRunId` and `receipt.result.viewNodeId`, reconnect the Session, and invoke
301
+ `reconcileGenerationStart` with those two identities. Never call `startGeneration` again for that
302
+ intent. `running-insufficient` means the Run is still authoritative but does not yet expose enough
303
+ target evidence: wait and reconcile later. `repaired` means the CLI restored the missing Canvas
304
+ launch facts through the semantic Command path. `conflict` or `insufficient` requires inspection;
305
+ neither authorizes a retry.
306
+
307
+ A Workflow Interest performs an authoritative status catch-up for Run IDs already known to the
308
+ Session; explicit `filter.runIds` narrows or restores that set when needed. This closes
309
+ missed-live-event races and delivers each unchanged terminal fact once. Keep explicit Run ID filters
310
+ current across handoffs; the daemon does not scan unrelated Workflow Runs.
311
+
286
312
  Workflow Definitions change over time. Query `workflowDefinitions.summary`, then
287
313
  `workflowDefinition.detail` only when planning detail is insufficient. Never guess a Definition,
288
314
  configuration option, modality, cost, or media compatibility from its display name.