linkque-cli-v2 1.1.4 → 1.1.5

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/linkquejs.js CHANGED
@@ -25304,6 +25304,7 @@ function analyzeA2UIBindings(protocol) {
25304
25304
  const listRoots = inferListRoots(components, issues);
25305
25305
  for (const component of components) {
25306
25306
  const context = {
25307
+ surfaceId,
25307
25308
  component,
25308
25309
  listRoot: listRoots.get(component.id),
25309
25310
  occurrences,
@@ -25317,6 +25318,7 @@ function analyzeA2UIBindings(protocol) {
25317
25318
  issues.push(issue2(`card.surfaces.${surfaceId}.components.${component.id}.children.path`, "INVALID_BINDING_PATH", `Invalid list path ${children.path}`));
25318
25319
  } else {
25319
25320
  occurrences.push({
25321
+ surfaceId,
25320
25322
  componentId: component.id,
25321
25323
  componentName: component.component,
25322
25324
  propertyPath: "children.path",
@@ -25335,6 +25337,16 @@ function analyzeA2UIBindings(protocol) {
25335
25337
  issues
25336
25338
  };
25337
25339
  }
25340
+ function collectReferencedA2UICardBusinessFieldIds(protocol, fields) {
25341
+ const businessFields = fields.filter((field) => field.source === "business").slice().sort((left, right) => right.path.length - left.path.length);
25342
+ const result = /* @__PURE__ */ new Set();
25343
+ for (const occurrence of analyzeA2UIBindings(protocol).occurrences) {
25344
+ const field = businessFields.find((candidate) => occurrence.canonicalPath === candidate.path || occurrence.canonicalPath.startsWith(`${candidate.path}/*/`) || occurrence.canonicalPath.startsWith(`${candidate.path}/`));
25345
+ if (field)
25346
+ result.add(field.fieldId);
25347
+ }
25348
+ return result;
25349
+ }
25338
25350
  function visitValue(value, propertyPath, context) {
25339
25351
  if (propertyPath === "action.local.path" && typeof value === "string") {
25340
25352
  addOccurrence(value, propertyPath, "local", context);
@@ -25366,6 +25378,7 @@ function addOccurrence(rawPath, propertyPath, usage, context) {
25366
25378
  return;
25367
25379
  }
25368
25380
  context.occurrences.push({
25381
+ surfaceId: context.surfaceId,
25369
25382
  componentId: context.component.id,
25370
25383
  componentName: context.component.component,
25371
25384
  propertyPath,
@@ -26051,12 +26064,15 @@ function validateA2UICardBindings(input, options = {}) {
26051
26064
  readyCandidates.set(candidateKey(candidate.resourceId, candidate.tool.toolName), candidate.tool);
26052
26065
  }
26053
26066
  const bindingByField = new Map(bindings.map((binding) => [binding.fieldId, binding]));
26067
+ const requiredFields = collectReferencedA2UICardBusinessFieldIds(input.draft.card, input.draft.manifest.fields.filter((field) => field.required));
26054
26068
  for (const field of input.draft.manifest.fields) {
26055
26069
  if (field.source !== "business")
26056
26070
  continue;
26057
26071
  if (selectedFields && !selectedFields.has(field.fieldId))
26058
26072
  continue;
26059
26073
  const binding = bindingByField.get(field.fieldId);
26074
+ if (!selectedFields && !requiredFields.has(field.fieldId) && !binding)
26075
+ continue;
26060
26076
  if (!binding) {
26061
26077
  issues.push(issue2(`fields.${field.fieldId}`, "CARD_BINDING_INCOMPLETE", `business field ${field.fieldId} has not been bound`));
26062
26078
  continue;
@@ -26394,9 +26410,9 @@ function getA2UICardResourceConfigIssues(value) {
26394
26410
  validateLooseJsonSchema(value.presentationInputSchema, "config.presentationInputSchema", issues);
26395
26411
  const fields = validateFields(value.fields, "config.fields", issues);
26396
26412
  const resolver = validateResolver(value.resolver, "config.resolver", issues);
26397
- validateTemplate(value.a2uiTemplate, fields, issues);
26413
+ const card = validateTemplate(value.a2uiTemplate, fields, issues);
26398
26414
  if (fields && resolver)
26399
- validateResolverCoverage(fields, resolver, issues);
26415
+ validateResolverCoverage(fields, resolver, issues, card);
26400
26416
  return issues;
26401
26417
  }
26402
26418
  function getA2UICardResourceConfigV3Issues(value) {
@@ -26429,9 +26445,9 @@ function getA2UICardResourceConfigV3Issues(value) {
26429
26445
  }
26430
26446
  const dataSources = validateDataSources(value.dataSources, "config.dataSources", issues);
26431
26447
  const bindings = validateV3OutputBindings(value.bindings, "config.bindings", issues);
26432
- validateTemplate(value.a2uiTemplate, fields, issues);
26448
+ const card = validateTemplate(value.a2uiTemplate, fields, issues);
26433
26449
  if (fields && dataSources && bindings) {
26434
- validateV3Coverage(fields, dataSources, bindings, issues);
26450
+ validateV3Coverage(fields, dataSources, bindings, issues, { card });
26435
26451
  }
26436
26452
  return issues;
26437
26453
  }
@@ -26545,7 +26561,8 @@ function validateV3Coverage(fields, dataSources, bindings, issues, options = {})
26545
26561
  bound.add(binding.fieldId);
26546
26562
  });
26547
26563
  if (options.requireComplete !== false) {
26548
- for (const fieldId of businessFields) {
26564
+ const requiredFields = options.card ? collectReferencedA2UICardBusinessFieldIds(options.card, fields.filter((field) => field.required)) : new Set(fields.filter((field) => field.source === "business" && field.required).map((field) => field.fieldId));
26565
+ for (const fieldId of requiredFields) {
26549
26566
  if (bound.has(fieldId))
26550
26567
  continue;
26551
26568
  issues.push(issue2("config.bindings", "CARD_BINDING_INCOMPLETE", `business field ${fieldId} is not bound`));
@@ -26983,13 +27000,13 @@ function validateInstructionShape(instruction, path22, issues) {
26983
27000
  function validateTemplate(value, fields, issues) {
26984
27001
  if (!isPlainRecord(value)) {
26985
27002
  issues.push(issue2("config.a2uiTemplate", "INVALID_A2UI_TEMPLATE", "a2uiTemplate must be an object"));
26986
- return;
27003
+ return void 0;
26987
27004
  }
26988
27005
  exactKeys(value, ["argsSchema", "content"], "config.a2uiTemplate", issues);
26989
27006
  validateLooseJsonSchema(value.argsSchema, "config.a2uiTemplate.argsSchema", issues);
26990
27007
  if (typeof value.content !== "string") {
26991
27008
  issues.push(issue2("config.a2uiTemplate.content", "INVALID_A2UI_CONTENT", "a2uiTemplate.content must be serialized A2UI JSON"));
26992
- return;
27009
+ return void 0;
26993
27010
  }
26994
27011
  try {
26995
27012
  const card = validateProtocol(JSON.parse(value.content), "config.a2uiTemplate.content", issues);
@@ -26997,9 +27014,11 @@ function validateTemplate(value, fields, issues) {
26997
27014
  const analysis = analyzeA2UIBindings(card);
26998
27015
  issues.push(...analysis.issues);
26999
27016
  }
27017
+ return card;
27000
27018
  } catch {
27001
27019
  issues.push(issue2("config.a2uiTemplate.content", "INVALID_A2UI_CONTENT", "a2uiTemplate.content must contain valid JSON"));
27002
27020
  }
27021
+ return void 0;
27003
27022
  }
27004
27023
  function validateLooseJsonSchema(value, path22, issues) {
27005
27024
  const schemaIssues = getJsonSchemaIssues(value, path22, {
@@ -27008,7 +27027,7 @@ function validateLooseJsonSchema(value, path22, issues) {
27008
27027
  issues.push(...schemaIssues);
27009
27028
  return schemaIssues.length === 0;
27010
27029
  }
27011
- function validateResolverCoverage(fields, resolver, issues) {
27030
+ function validateResolverCoverage(fields, resolver, issues, card) {
27012
27031
  const businessFields = new Set(fields.filter((field) => field.source === "business").map((field) => field.fieldId));
27013
27032
  const bound = /* @__PURE__ */ new Set();
27014
27033
  resolver.outputBindings.forEach((binding, index) => {
@@ -27017,7 +27036,8 @@ function validateResolverCoverage(fields, resolver, issues) {
27017
27036
  }
27018
27037
  bound.add(binding.fieldId);
27019
27038
  });
27020
- for (const fieldId of businessFields) {
27039
+ const requiredFields = card ? collectReferencedA2UICardBusinessFieldIds(card, fields.filter((field) => field.required)) : new Set(fields.filter((field) => field.source === "business" && field.required).map((field) => field.fieldId));
27040
+ for (const fieldId of requiredFields) {
27021
27041
  if (!bound.has(fieldId)) {
27022
27042
  issues.push(issue2("config.resolver.outputBindings", "CARD_BINDING_INCOMPLETE", `business field ${fieldId} is not bound`));
27023
27043
  }
@@ -27065,6 +27085,7 @@ function compileA2UICardResource(input) {
27065
27085
  }
27066
27086
  const fieldById = new Map(draft.manifest.fields.map((field) => [field.fieldId, field]));
27067
27087
  const selectionByField = /* @__PURE__ */ new Map();
27088
+ const requiredFields = collectReferencedA2UICardBusinessFieldIds(draft.card, draft.manifest.fields.filter((field) => field.required));
27068
27089
  for (const selection of input.bindings) {
27069
27090
  const field = fieldById.get(selection.fieldId);
27070
27091
  if (!field || field.source !== "business") {
@@ -27078,9 +27099,9 @@ function compileA2UICardResource(input) {
27078
27099
  }
27079
27100
  selectionByField.set(selection.fieldId, cloneSelection(selection));
27080
27101
  }
27081
- for (const field of draft.manifest.fields) {
27082
- if (field.source === "business" && !selectionByField.has(field.fieldId)) {
27083
- throw new A2UICardCompileError("CARD_BINDING_INCOMPLETE", `Business field ${field.fieldId} has not been bound`);
27102
+ for (const fieldId of requiredFields) {
27103
+ if (!selectionByField.has(fieldId)) {
27104
+ throw new A2UICardCompileError("CARD_BINDING_INCOMPLETE", `Required referenced business field ${fieldId} has not been bound`);
27084
27105
  }
27085
27106
  }
27086
27107
  const resolver = compileResolver([...selectionByField.values()]);
@@ -27172,6 +27193,7 @@ function compileV3Resource(draft, revision, bindings, tools) {
27172
27193
  const sourceById = /* @__PURE__ */ new Map();
27173
27194
  const outputBindings = [];
27174
27195
  const boundFields = /* @__PURE__ */ new Set();
27196
+ const requiredFields = collectReferencedA2UICardBusinessFieldIds(draft.card, draft.manifest.fields.filter((field) => field.required));
27175
27197
  for (const binding of bindings) {
27176
27198
  const field = fieldById.get(binding.fieldId);
27177
27199
  if (!field || field.source !== "business" || boundFields.has(binding.fieldId)) {
@@ -27199,9 +27221,9 @@ function compileV3Resource(draft, revision, bindings, tools) {
27199
27221
  transform: binding.transform
27200
27222
  });
27201
27223
  }
27202
- for (const field of draft.manifest.fields) {
27203
- if (field.source === "business" && !boundFields.has(field.fieldId)) {
27204
- throw new A2UICardCompileError("CARD_BINDING_INCOMPLETE", `Business field ${field.fieldId} has not been bound`);
27224
+ for (const fieldId of requiredFields) {
27225
+ if (!boundFields.has(fieldId)) {
27226
+ throw new A2UICardCompileError("CARD_BINDING_INCOMPLETE", `Required referenced business field ${fieldId} has not been bound`);
27205
27227
  }
27206
27228
  }
27207
27229
  const resource = {
@@ -27404,9 +27426,6 @@ function createA2UICardDraftStructureChecksum(draft) {
27404
27426
  delete cloned.manifest.bindings;
27405
27427
  return sha256Hex(stableJsonStringify(cloned));
27406
27428
  }
27407
- function createA2UICardMcpConfigChecksum(resources) {
27408
- return sha256Hex(stableJsonStringify(resources));
27409
- }
27410
27429
  function createA2UICardRevision(draftChecksum2, bindings) {
27411
27430
  const digest = sha256Hex(`${draftChecksum2}
27412
27431
  ${stableJsonStringify(bindings)}`);
@@ -27485,6 +27504,393 @@ var SHA256_CONSTANTS = [
27485
27504
  3329325298
27486
27505
  ];
27487
27506
 
27507
+ // ../agent-a2ui-card-contract/dist/esm/authoring-model.js
27508
+ var INTERNAL_KEYS = /* @__PURE__ */ new Set([
27509
+ "__proto__",
27510
+ "constructor",
27511
+ "prototype",
27512
+ "id",
27513
+ "component",
27514
+ "surfaceId",
27515
+ "version",
27516
+ "child",
27517
+ "children"
27518
+ ]);
27519
+ var MERCHANT_CONTENT_KEYS = /* @__PURE__ */ new Set([
27520
+ "caption",
27521
+ "description",
27522
+ "label",
27523
+ "placeholder",
27524
+ "subtitle",
27525
+ "text",
27526
+ "title"
27527
+ ]);
27528
+ var DEFAULT_AUTHORING_PROJECTION = {
27529
+ directTargets: "content"
27530
+ };
27531
+ var COMPONENT_AUTHORING_PROJECTIONS = {
27532
+ Image: {
27533
+ directTargets: "image-source",
27534
+ fieldProperties: ["src"],
27535
+ groupLabel: "\u56FE\u7247"
27536
+ }
27537
+ };
27538
+ function extractA2UICardAuthoringModel(bundle, options = {}) {
27539
+ const analysis = analyzeA2UIBindings(bundle.card);
27540
+ const bindingByField = new Map((bundle.manifest.bindings ?? []).map((binding) => [
27541
+ binding.fieldId,
27542
+ binding
27543
+ ]));
27544
+ const fields = bundle.manifest.fields.filter((field) => field.source === "business");
27545
+ const registered = options.registeredComponents ? new Set(options.registeredComponents) : void 0;
27546
+ const occurrencesByComponent = groupBindingOccurrences(analysis.occurrences);
27547
+ const allFieldOccurrenceTargets = [];
27548
+ const groups = [];
27549
+ let order = 0;
27550
+ for (const { surfaceId, component } of orderedComponents(bundle)) {
27551
+ const occurrenceId = createA2UICardAuthoringOccurrenceId(surfaceId, component.id);
27552
+ const targets = [];
27553
+ if (!registered || registered.has(component.component)) {
27554
+ const projection = componentAuthoringProjection(component);
27555
+ const componentOccurrences = occurrencesByComponent.get(componentKey(surfaceId, component.id)) ?? [];
27556
+ discoverComponentTargets(component, occurrenceId, projection, targets);
27557
+ allFieldOccurrenceTargets.push(...fieldTargets(component, occurrenceId, fields, componentOccurrences, false));
27558
+ targets.push(...fieldTargets(component, occurrenceId, fields, componentOccurrences, true));
27559
+ targets.push(...actionTargets(component, occurrenceId));
27560
+ }
27561
+ if (targets.length === 0) {
27562
+ targets.push({
27563
+ kind: "agent-only",
27564
+ targetId: createA2UICardAuthoringTargetId(occurrenceId, "agent-only"),
27565
+ occurrenceId,
27566
+ label: "\u901A\u8FC7 Coding Agent \u4FEE\u6539",
27567
+ reason: registered && !registered.has(component.component) ? "\u7EC4\u4EF6\u672A\u5728\u5F53\u524D Catalog \u6CE8\u518C" : "\u6CA1\u6709\u53EF\u5B89\u5168\u76F4\u63A5\u7F16\u8F91\u7684\u4E1A\u52A1\u5B57\u6BB5"
27568
+ });
27569
+ }
27570
+ groups.push({
27571
+ occurrenceId,
27572
+ surfaceId,
27573
+ componentId: component.id,
27574
+ componentName: component.component,
27575
+ order: order++,
27576
+ label: componentAuthoringProjection(component).groupLabel ?? componentLabel(component),
27577
+ targets: deduplicateTargets(targets),
27578
+ agentOnly: targets.every((target) => target.kind === "agent-only")
27579
+ });
27580
+ }
27581
+ const fieldStates = fields.map((field) => {
27582
+ const occurrences = allFieldOccurrenceTargets.filter((target) => target.fieldId === field.fieldId);
27583
+ const binding = bindingByField.get(field.fieldId);
27584
+ return {
27585
+ field,
27586
+ ...binding ? { binding: cloneBinding(binding) } : {},
27587
+ occurrences,
27588
+ usageCount: new Set(occurrences.map((target) => `${target.occurrenceId}\0${target.propertyPath}`)).size,
27589
+ status: occurrences.length === 0 ? "unused" : binding ? "bound" : field.required ? "unbound-required" : "unbound-optional"
27590
+ };
27591
+ });
27592
+ const diagnostics = getA2UICardAuthoringDiagnostics(bundle, {
27593
+ groups,
27594
+ fields: fieldStates
27595
+ });
27596
+ return {
27597
+ draftId: bundle.manifest.draftId,
27598
+ resourceId: bundle.manifest.resourceId,
27599
+ groups,
27600
+ fields: fieldStates,
27601
+ diagnostics
27602
+ };
27603
+ }
27604
+ function componentAuthoringProjection(component) {
27605
+ return COMPONENT_AUTHORING_PROJECTIONS[component.component] ?? DEFAULT_AUTHORING_PROJECTION;
27606
+ }
27607
+ function discoverComponentTargets(component, occurrenceId, projection, targets) {
27608
+ if (projection.directTargets === "content") {
27609
+ discoverTargets(component, occurrenceId, "", targets);
27610
+ return;
27611
+ }
27612
+ if (typeof component.src !== "string")
27613
+ return;
27614
+ targets.push({
27615
+ kind: "image",
27616
+ targetId: createA2UICardAuthoringTargetId(occurrenceId, "src"),
27617
+ occurrenceId,
27618
+ propertyPath: "src",
27619
+ label: "\u56FE\u7247\u5730\u5740",
27620
+ value: component.src,
27621
+ role: "src"
27622
+ });
27623
+ }
27624
+ function getA2UICardAuthoringDiagnostics(bundle, partial) {
27625
+ const diagnostics = getA2UICardDraftBundleIssues(bundle).map((entry) => ({
27626
+ ...entry,
27627
+ severity: "hard-error"
27628
+ }));
27629
+ const model = partial ?? extractA2UICardAuthoringModel(bundle);
27630
+ for (const field of model.fields) {
27631
+ if (field.status === "unbound-required") {
27632
+ diagnostics.push({
27633
+ code: "REQUIRED_BINDING_MISSING",
27634
+ path: `manifest.fields.${field.field.fieldId}`,
27635
+ message: `\u5FC5\u586B\u5B57\u6BB5\u201C${field.field.label}\u201D\u5C1A\u672A\u7ED1\u5B9A`,
27636
+ severity: "hard-error",
27637
+ fieldId: field.field.fieldId
27638
+ });
27639
+ }
27640
+ }
27641
+ for (const group of model.groups) {
27642
+ const component = findComponent(bundle, group.surfaceId, group.componentId);
27643
+ const action = isPlainRecord(component?.action) ? component.action : void 0;
27644
+ const client = action && isPlainRecord(action.client) ? action.client : void 0;
27645
+ if (client?.name === "ui.page.open") {
27646
+ const context = isPlainRecord(client.context) ? client.context : void 0;
27647
+ if (typeof context?.url === "string" && !isSafePageUrl(context.url)) {
27648
+ diagnostics.push({
27649
+ code: "UNSAFE_PAGE_URL",
27650
+ path: `${group.occurrenceId}.action.client.context.url`,
27651
+ message: "\u9875\u9762\u5730\u5740\u5FC5\u987B\u662F\u5B89\u5168\u7684 http(s) \u5730\u5740\u6216\u7AD9\u5185\u7EDD\u5BF9\u8DEF\u5F84",
27652
+ severity: "hard-error",
27653
+ occurrenceId: group.occurrenceId
27654
+ });
27655
+ }
27656
+ } else if (client && typeof client.name === "string" && !["ui.overlay.close", "ui.surface.open"].includes(client.name)) {
27657
+ diagnostics.push({
27658
+ code: "UNREGISTERED_CLIENT_ACTION",
27659
+ path: `${group.occurrenceId}.action.client.name`,
27660
+ message: `\u672A\u6CE8\u518C\u7684 Client Action\uFF1A${client.name}`,
27661
+ severity: "hard-error",
27662
+ occurrenceId: group.occurrenceId
27663
+ });
27664
+ }
27665
+ }
27666
+ return deduplicateDiagnostics(diagnostics);
27667
+ }
27668
+ function validateA2UICardForPublish(bundle) {
27669
+ return getA2UICardAuthoringDiagnostics(bundle).filter((diagnostic) => diagnostic.severity === "hard-error");
27670
+ }
27671
+ function createA2UICardAuthoringOccurrenceId(surfaceId, componentId) {
27672
+ return `${encodeURIComponent(surfaceId)}:${encodeURIComponent(componentId)}`;
27673
+ }
27674
+ function createA2UICardAuthoringTargetId(occurrenceId, propertyPath) {
27675
+ return `${occurrenceId}:${encodeURIComponent(propertyPath)}`;
27676
+ }
27677
+ function isSafePageUrl(url) {
27678
+ const trimmed = url.trim();
27679
+ if (trimmed.length === 0 || trimmed.length > 2e3)
27680
+ return false;
27681
+ const token = /\{\{([^{}]+)\}\}/gu;
27682
+ let tokenCount = 0;
27683
+ for (const match of trimmed.matchAll(token)) {
27684
+ tokenCount++;
27685
+ if (tokenCount > 32)
27686
+ return false;
27687
+ const path22 = match[1]?.trim() ?? "";
27688
+ if (!(path22 === "/" || path22.startsWith("/") || path22.startsWith("./")) || path22.split("/").some((part) => ["..", "__proto__", "constructor", "prototype"].includes(part))) {
27689
+ return false;
27690
+ }
27691
+ }
27692
+ const candidate = trimmed.replace(token, "value");
27693
+ if (candidate.includes("{{") || candidate.includes("}}"))
27694
+ return false;
27695
+ try {
27696
+ return ["https:", "alipays:"].includes(new URL(candidate).protocol);
27697
+ } catch {
27698
+ return false;
27699
+ }
27700
+ }
27701
+ function orderedComponents(bundle) {
27702
+ const result = [];
27703
+ for (const message of bundle.card) {
27704
+ for (const instruction of message.datas) {
27705
+ if (!("updateComponents" in instruction))
27706
+ continue;
27707
+ for (const component of instruction.updateComponents.components) {
27708
+ result.push({
27709
+ surfaceId: instruction.updateComponents.surfaceId,
27710
+ component
27711
+ });
27712
+ }
27713
+ }
27714
+ }
27715
+ return result;
27716
+ }
27717
+ function discoverTargets(value, occurrenceId, propertyPath, targets) {
27718
+ if (Array.isArray(value)) {
27719
+ value.forEach((entry, index) => discoverTargets(entry, occurrenceId, appendPath(propertyPath, String(index)), targets));
27720
+ return;
27721
+ }
27722
+ if (!isPlainRecord(value))
27723
+ return;
27724
+ if (typeof value.path === "string")
27725
+ return;
27726
+ for (const [key, entry] of Object.entries(value)) {
27727
+ const nextPath = appendPath(propertyPath, key);
27728
+ if (INTERNAL_KEYS.has(key) || key === "action")
27729
+ continue;
27730
+ if (Array.isArray(entry) || isPlainRecord(entry)) {
27731
+ discoverTargets(entry, occurrenceId, nextPath, targets);
27732
+ continue;
27733
+ }
27734
+ if (!isJsonValue(entry))
27735
+ continue;
27736
+ if (typeof entry !== "string" || !MERCHANT_CONTENT_KEYS.has(key))
27737
+ continue;
27738
+ targets.push({
27739
+ kind: "literal",
27740
+ targetId: createA2UICardAuthoringTargetId(occurrenceId, nextPath),
27741
+ occurrenceId,
27742
+ propertyPath: nextPath,
27743
+ label: propertyLabel(nextPath),
27744
+ value: entry
27745
+ });
27746
+ }
27747
+ }
27748
+ function actionTargets(component, occurrenceId) {
27749
+ if (!isPlainRecord(component.action))
27750
+ return [];
27751
+ const action = component.action;
27752
+ const event = isPlainRecord(action.event) ? action.event : void 0;
27753
+ if (event) {
27754
+ const message = event["x2-user-message"];
27755
+ if (typeof message === "string" && typeof event.name === "string") {
27756
+ return [
27757
+ {
27758
+ kind: "agent-event",
27759
+ targetId: createA2UICardAuthoringTargetId(occurrenceId, "action"),
27760
+ occurrenceId,
27761
+ propertyPath: "action",
27762
+ label: "\u70B9\u51FB\u540E",
27763
+ message,
27764
+ eventName: event.name,
27765
+ hasContext: isPlainRecord(event.context)
27766
+ }
27767
+ ];
27768
+ }
27769
+ return [agentOnlyAction(occurrenceId, "\u52A8\u6001\u6216\u590D\u6742\u4E8B\u4EF6\u901A\u8FC7\u667A\u80FD\u4F53\u4FEE\u6539")];
27770
+ }
27771
+ const client = isPlainRecord(action.client) ? action.client : void 0;
27772
+ if (client?.name === "ui.page.open") {
27773
+ const context = isPlainRecord(client.context) ? client.context : void 0;
27774
+ const url = context?.url;
27775
+ return [
27776
+ {
27777
+ kind: "page-open",
27778
+ targetId: createA2UICardAuthoringTargetId(occurrenceId, "action"),
27779
+ occurrenceId,
27780
+ propertyPath: "action",
27781
+ label: "\u6253\u5F00\u9875\u9762",
27782
+ ...typeof url === "string" ? { url } : {},
27783
+ dynamic: isPlainRecord(url) && typeof url.path === "string"
27784
+ }
27785
+ ];
27786
+ }
27787
+ return [agentOnlyAction(occurrenceId, "\u8BE5\u884C\u4E3A\u53EA\u80FD\u901A\u8FC7 Coding Agent \u4FEE\u6539")];
27788
+ }
27789
+ function fieldTargets(component, occurrenceId, fields, occurrences, projectedOnly) {
27790
+ const projection = componentAuthoringProjection(component);
27791
+ const ordered = [...fields].sort((left, right) => right.path.length - left.path.length);
27792
+ return occurrences.flatMap((occurrence) => {
27793
+ if (projectedOnly && !isProjectedFieldOccurrence(occurrence.propertyPath, projection)) {
27794
+ return [];
27795
+ }
27796
+ const field = ordered.find((candidate) => occurrence.canonicalPath === candidate.path || occurrence.canonicalPath.startsWith(`${candidate.path}/*/`) || occurrence.canonicalPath.startsWith(`${candidate.path}/`));
27797
+ if (!field)
27798
+ return [];
27799
+ const suffix = occurrence.canonicalPath.slice(field.path.length).replace(/^\/\*/u, "");
27800
+ const targetPath = suffix ? suffix.startsWith("/") ? suffix : `/${suffix}` : void 0;
27801
+ return [
27802
+ {
27803
+ kind: "field-occurrence",
27804
+ targetId: createA2UICardAuthoringTargetId(occurrenceId, occurrence.propertyPath),
27805
+ occurrenceId,
27806
+ propertyPath: occurrence.propertyPath,
27807
+ label: fieldOccurrenceLabel(targetPath, occurrence.propertyPath),
27808
+ fieldId: field.fieldId,
27809
+ ...targetPath ? { targetPath } : {}
27810
+ }
27811
+ ];
27812
+ });
27813
+ }
27814
+ function isProjectedFieldOccurrence(propertyPath, projection) {
27815
+ if (propertyPath === "action" || propertyPath.startsWith("action.")) {
27816
+ return false;
27817
+ }
27818
+ return projection.fieldProperties === void 0 || projection.fieldProperties.includes(propertyPath);
27819
+ }
27820
+ function fieldOccurrenceLabel(targetPath, propertyPath) {
27821
+ if (!targetPath)
27822
+ return propertyLabel(propertyPath);
27823
+ const segment = targetPath.split("/").filter(Boolean).at(-1);
27824
+ return segment ? decodeJsonPointerSegment(segment) : propertyLabel(propertyPath);
27825
+ }
27826
+ function decodeJsonPointerSegment(segment) {
27827
+ return segment.replace(/~1/gu, "/").replace(/~0/gu, "~");
27828
+ }
27829
+ function groupBindingOccurrences(occurrences) {
27830
+ const result = /* @__PURE__ */ new Map();
27831
+ for (const occurrence of occurrences) {
27832
+ if (!occurrence.surfaceId)
27833
+ continue;
27834
+ const key = componentKey(occurrence.surfaceId, occurrence.componentId);
27835
+ const entries = result.get(key) ?? [];
27836
+ entries.push(occurrence);
27837
+ result.set(key, entries);
27838
+ }
27839
+ return result;
27840
+ }
27841
+ function findComponent(bundle, surfaceId, componentId) {
27842
+ return orderedComponents(bundle).find((entry) => entry.surfaceId === surfaceId && entry.component.id === componentId)?.component;
27843
+ }
27844
+ function agentOnlyAction(occurrenceId, reason) {
27845
+ return {
27846
+ kind: "agent-only",
27847
+ targetId: createA2UICardAuthoringTargetId(occurrenceId, "action"),
27848
+ occurrenceId,
27849
+ propertyPath: "action",
27850
+ label: "\u901A\u8FC7 Coding Agent \u4FEE\u6539\u884C\u4E3A",
27851
+ reason
27852
+ };
27853
+ }
27854
+ function componentLabel(component) {
27855
+ const candidate = component.label ?? component.title ?? component.text;
27856
+ return typeof candidate === "string" && candidate.trim() ? candidate : component.component;
27857
+ }
27858
+ function propertyLabel(propertyPath) {
27859
+ const key = propertyPath.split(".").at(-1) ?? propertyPath;
27860
+ const labels = {
27861
+ text: "\u6587\u6848",
27862
+ title: "\u6807\u9898",
27863
+ subtitle: "\u526F\u6807\u9898",
27864
+ label: "\u6807\u7B7E",
27865
+ description: "\u8BF4\u660E",
27866
+ value: "\u5185\u5BB9",
27867
+ alt: "\u56FE\u7247\u8BF4\u660E"
27868
+ };
27869
+ return labels[key] ?? key;
27870
+ }
27871
+ function appendPath(base, segment) {
27872
+ return base ? `${base}.${segment}` : segment;
27873
+ }
27874
+ function componentKey(surfaceId, componentId) {
27875
+ return `${surfaceId}\0${componentId}`;
27876
+ }
27877
+ function deduplicateTargets(targets) {
27878
+ return [
27879
+ ...new Map(targets.map((target) => [target.targetId, target])).values()
27880
+ ];
27881
+ }
27882
+ function deduplicateDiagnostics(diagnostics) {
27883
+ return [
27884
+ ...new Map(diagnostics.map((entry) => [
27885
+ `${entry.code}\0${entry.path}\0${entry.fieldId ?? ""}`,
27886
+ entry
27887
+ ])).values()
27888
+ ];
27889
+ }
27890
+ function cloneBinding(binding) {
27891
+ return JSON.parse(JSON.stringify(binding));
27892
+ }
27893
+
27488
27894
  // src/commands/card/index.ts
27489
27895
  var DRAFT_ROOT = ".card-drafts";
27490
27896
  var AGENT_CONFIG_PATH = "agent_config.json";
@@ -27614,36 +28020,20 @@ async function validateCardBindingsFromDisk(cwd, draftId, fieldId) {
27614
28020
  const directory = draftDirectory(cwd, draftId);
27615
28021
  const [bundle, contextValue, configValue] = await Promise.all([
27616
28022
  readBundle(directory, draftId),
27617
- readRequiredJson(import_path22.default.join(directory, "binding-context.json")),
28023
+ readOptionalJson(import_path22.default.join(directory, "binding-context.json")),
27618
28024
  readRequiredJson(import_path22.default.join(cwd, AGENT_CONFIG_PATH))
27619
28025
  ]);
27620
- const contextResult = parseA2UICardBindingContext(contextValue);
27621
- if (!contextResult.success) {
27622
- throw new LinkqueCliError(
27623
- "CARD_BINDING_CONTEXT_INVALID",
27624
- contextResult.issues.map((entry) => entry.message).join("; ")
27625
- );
27626
- }
27627
- const context = contextResult.data;
28026
+ const context = parseOptionalBindingContext(contextValue);
27628
28027
  const draftStructureChecksum = createA2UICardDraftStructureChecksum(bundle);
27629
28028
  const config2 = parseAgentConfig(configValue);
27630
28029
  const mcpResources = normalizedMcpResources(config2);
27631
- if (context.mcpConfigChecksum !== createA2UICardMcpConfigChecksum(mcpResources)) {
27632
- throw new LinkqueCliError(
27633
- "CARD_BINDING_CONTEXT_STALE",
27634
- "MCP \u914D\u7F6E\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u53D1\u8D77 AI \u8F85\u52A9\u7ED1\u5B9A"
27635
- );
27636
- }
27637
- const issues = validateA2UICardBindings(
27638
- {
27639
- draft: bundle,
27640
- context,
27641
- mountedMcpResourceIds: new Set(
27642
- mcpResources.map((resource) => String(resource.resourceId))
27643
- )
27644
- },
27645
- fieldId ? { fieldIds: /* @__PURE__ */ new Set([fieldId]) } : void 0
28030
+ const mountedMcpResourceIds = new Set(
28031
+ mcpResources.map((resource) => String(resource.resourceId))
27646
28032
  );
28033
+ const issues = context ? validateA2UICardBindings(
28034
+ { draft: bundle, context, mountedMcpResourceIds },
28035
+ fieldId ? { fieldIds: /* @__PURE__ */ new Set([fieldId]) } : void 0
28036
+ ) : validateBindingsWithoutContext(bundle, mountedMcpResourceIds, fieldId);
27647
28037
  if (issues.length > 0) {
27648
28038
  throw new LinkqueCliError(
27649
28039
  "CARD_BINDING_VALIDATION_FAILED",
@@ -27674,15 +28064,9 @@ async function finalizeCardWhileLocked(cwd, draftId, expectedDraftChecksum) {
27674
28064
  }
27675
28065
  const directory = draftDirectory(cwd, draftId);
27676
28066
  const bundle = await readBundle(directory, draftId);
27677
- const contextResult = parseA2UICardBindingContext(
27678
- await readRequiredJson(import_path22.default.join(directory, "binding-context.json"))
28067
+ const context = parseOptionalBindingContext(
28068
+ await readOptionalJson(import_path22.default.join(directory, "binding-context.json"))
27679
28069
  );
27680
- if (!contextResult.success) {
27681
- throw new LinkqueCliError(
27682
- "CARD_BINDING_CONTEXT_INVALID",
27683
- contextResult.issues.map((entry) => entry.message).join("; ")
27684
- );
27685
- }
27686
28070
  const configPath = import_path22.default.join(cwd, AGENT_CONFIG_PATH);
27687
28071
  const oldConfigBytes = await (0, import_promises16.readFile)(configPath);
27688
28072
  const config2 = parseAgentConfig(
@@ -27716,7 +28100,7 @@ async function finalizeCardWhileLocked(cwd, draftId, expectedDraftChecksum) {
27716
28100
  // V3,让 Agent 直接按真实 MCP inputSchema 决定参数;不再把 presentation input
27717
28101
  // 或 inputBindings 固化进 CARD。
27718
28102
  ...bindings.length > 0 ? { targetSchemaVersion: "3" } : {},
27719
- tools: contextResult.data.candidates.flatMap(
28103
+ tools: (context?.candidates ?? []).flatMap(
27720
28104
  (candidate) => candidate.status === "ready" ? [candidate.tool] : []
27721
28105
  )
27722
28106
  });
@@ -28043,6 +28427,47 @@ function normalizedMcpResources(config2) {
28043
28427
  (left, right) => stableJsonStringify(left).localeCompare(stableJsonStringify(right))
28044
28428
  );
28045
28429
  }
28430
+ function parseOptionalBindingContext(value) {
28431
+ if (value === void 0) return void 0;
28432
+ const result = parseA2UICardBindingContext(value);
28433
+ if (!result.success) {
28434
+ throw new LinkqueCliError(
28435
+ "CARD_BINDING_CONTEXT_INVALID",
28436
+ result.issues.map((entry) => entry.message).join("; ")
28437
+ );
28438
+ }
28439
+ return result.data;
28440
+ }
28441
+ function validateBindingsWithoutContext(bundle, mountedMcpResourceIds, fieldId) {
28442
+ const selectedFields = fieldId ? /* @__PURE__ */ new Set([fieldId]) : void 0;
28443
+ const bindings = (bundle.manifest.bindings ?? []).filter(
28444
+ (binding) => !selectedFields || selectedFields.has(binding.fieldId)
28445
+ );
28446
+ const issues = getA2UICardBindingSelectionIssues(
28447
+ bindings,
28448
+ "draft.manifest.bindings",
28449
+ bundle.manifest.fields
28450
+ );
28451
+ for (const binding of bindings) {
28452
+ if (!mountedMcpResourceIds.has(binding.mcpResourceId)) {
28453
+ issues.push({
28454
+ code: "MCP_TOOL_UNAVAILABLE",
28455
+ message: `MCP resource ${binding.mcpResourceId} is not mounted`,
28456
+ path: `draft.manifest.bindings.${binding.fieldId}`
28457
+ });
28458
+ }
28459
+ }
28460
+ if (!selectedFields) {
28461
+ issues.push(
28462
+ ...validateA2UICardForPublish(bundle).map((diagnostic) => ({
28463
+ code: diagnostic.code,
28464
+ message: diagnostic.message,
28465
+ path: diagnostic.path
28466
+ }))
28467
+ );
28468
+ }
28469
+ return issues;
28470
+ }
28046
28471
  function isJsonObject(value) {
28047
28472
  return value !== null && typeof value === "object" && !Array.isArray(value);
28048
28473
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linkque-cli-v2",
3
- "version": "1.1.4",
3
+ "version": "1.1.5",
4
4
  "description": "Public Linkque CLI bundle for sandbox debugging",
5
5
  "bin": {
6
6
  "linkquejs": "linkquejs.js"
@@ -17007,6 +17007,7 @@ function analyzeA2UIBindings(protocol) {
17007
17007
  const listRoots = inferListRoots(components, issues);
17008
17008
  for (const component of components) {
17009
17009
  const context = {
17010
+ surfaceId,
17010
17011
  component,
17011
17012
  listRoot: listRoots.get(component.id),
17012
17013
  occurrences,
@@ -17020,6 +17021,7 @@ function analyzeA2UIBindings(protocol) {
17020
17021
  issues.push(issue2(`card.surfaces.${surfaceId}.components.${component.id}.children.path`, "INVALID_BINDING_PATH", `Invalid list path ${children.path}`));
17021
17022
  } else {
17022
17023
  occurrences.push({
17024
+ surfaceId,
17023
17025
  componentId: component.id,
17024
17026
  componentName: component.component,
17025
17027
  propertyPath: "children.path",
@@ -17038,6 +17040,16 @@ function analyzeA2UIBindings(protocol) {
17038
17040
  issues
17039
17041
  };
17040
17042
  }
17043
+ function collectReferencedA2UICardBusinessFieldIds(protocol, fields) {
17044
+ const businessFields = fields.filter((field) => field.source === "business").slice().sort((left, right) => right.path.length - left.path.length);
17045
+ const result = /* @__PURE__ */ new Set();
17046
+ for (const occurrence of analyzeA2UIBindings(protocol).occurrences) {
17047
+ const field = businessFields.find((candidate) => occurrence.canonicalPath === candidate.path || occurrence.canonicalPath.startsWith(`${candidate.path}/*/`) || occurrence.canonicalPath.startsWith(`${candidate.path}/`));
17048
+ if (field)
17049
+ result.add(field.fieldId);
17050
+ }
17051
+ return result;
17052
+ }
17041
17053
  function visitValue(value, propertyPath, context) {
17042
17054
  if (propertyPath === "action.local.path" && typeof value === "string") {
17043
17055
  addOccurrence(value, propertyPath, "local", context);
@@ -17069,6 +17081,7 @@ function addOccurrence(rawPath, propertyPath, usage, context) {
17069
17081
  return;
17070
17082
  }
17071
17083
  context.occurrences.push({
17084
+ surfaceId: context.surfaceId,
17072
17085
  componentId: context.component.id,
17073
17086
  componentName: context.component.component,
17074
17087
  propertyPath,
@@ -17480,9 +17493,9 @@ function getA2UICardResourceConfigIssues(value) {
17480
17493
  validateLooseJsonSchema(value.presentationInputSchema, "config.presentationInputSchema", issues);
17481
17494
  const fields = validateFields(value.fields, "config.fields", issues);
17482
17495
  const resolver = validateResolver(value.resolver, "config.resolver", issues);
17483
- validateTemplate(value.a2uiTemplate, fields, issues);
17496
+ const card = validateTemplate(value.a2uiTemplate, fields, issues);
17484
17497
  if (fields && resolver)
17485
- validateResolverCoverage(fields, resolver, issues);
17498
+ validateResolverCoverage(fields, resolver, issues, card);
17486
17499
  return issues;
17487
17500
  }
17488
17501
  function getA2UICardResourceConfigV3Issues(value) {
@@ -17515,9 +17528,9 @@ function getA2UICardResourceConfigV3Issues(value) {
17515
17528
  }
17516
17529
  const dataSources = validateDataSources(value.dataSources, "config.dataSources", issues);
17517
17530
  const bindings = validateV3OutputBindings(value.bindings, "config.bindings", issues);
17518
- validateTemplate(value.a2uiTemplate, fields, issues);
17531
+ const card = validateTemplate(value.a2uiTemplate, fields, issues);
17519
17532
  if (fields && dataSources && bindings) {
17520
- validateV3Coverage(fields, dataSources, bindings, issues);
17533
+ validateV3Coverage(fields, dataSources, bindings, issues, { card });
17521
17534
  }
17522
17535
  return issues;
17523
17536
  }
@@ -17631,7 +17644,8 @@ function validateV3Coverage(fields, dataSources, bindings, issues, options = {})
17631
17644
  bound.add(binding.fieldId);
17632
17645
  });
17633
17646
  if (options.requireComplete !== false) {
17634
- for (const fieldId of businessFields) {
17647
+ const requiredFields = options.card ? collectReferencedA2UICardBusinessFieldIds(options.card, fields.filter((field) => field.required)) : new Set(fields.filter((field) => field.source === "business" && field.required).map((field) => field.fieldId));
17648
+ for (const fieldId of requiredFields) {
17635
17649
  if (bound.has(fieldId))
17636
17650
  continue;
17637
17651
  issues.push(issue2("config.bindings", "CARD_BINDING_INCOMPLETE", `business field ${fieldId} is not bound`));
@@ -17931,13 +17945,13 @@ function validateInstructionShape(instruction, path2, issues) {
17931
17945
  function validateTemplate(value, fields, issues) {
17932
17946
  if (!isPlainRecord(value)) {
17933
17947
  issues.push(issue2("config.a2uiTemplate", "INVALID_A2UI_TEMPLATE", "a2uiTemplate must be an object"));
17934
- return;
17948
+ return void 0;
17935
17949
  }
17936
17950
  exactKeys(value, ["argsSchema", "content"], "config.a2uiTemplate", issues);
17937
17951
  validateLooseJsonSchema(value.argsSchema, "config.a2uiTemplate.argsSchema", issues);
17938
17952
  if (typeof value.content !== "string") {
17939
17953
  issues.push(issue2("config.a2uiTemplate.content", "INVALID_A2UI_CONTENT", "a2uiTemplate.content must be serialized A2UI JSON"));
17940
- return;
17954
+ return void 0;
17941
17955
  }
17942
17956
  try {
17943
17957
  const card = validateProtocol(JSON.parse(value.content), "config.a2uiTemplate.content", issues);
@@ -17945,9 +17959,11 @@ function validateTemplate(value, fields, issues) {
17945
17959
  const analysis = analyzeA2UIBindings(card);
17946
17960
  issues.push(...analysis.issues);
17947
17961
  }
17962
+ return card;
17948
17963
  } catch {
17949
17964
  issues.push(issue2("config.a2uiTemplate.content", "INVALID_A2UI_CONTENT", "a2uiTemplate.content must contain valid JSON"));
17950
17965
  }
17966
+ return void 0;
17951
17967
  }
17952
17968
  function validateLooseJsonSchema(value, path2, issues) {
17953
17969
  const schemaIssues = getJsonSchemaIssues2(value, path2, {
@@ -17956,7 +17972,7 @@ function validateLooseJsonSchema(value, path2, issues) {
17956
17972
  issues.push(...schemaIssues);
17957
17973
  return schemaIssues.length === 0;
17958
17974
  }
17959
- function validateResolverCoverage(fields, resolver, issues) {
17975
+ function validateResolverCoverage(fields, resolver, issues, card) {
17960
17976
  const businessFields = new Set(fields.filter((field) => field.source === "business").map((field) => field.fieldId));
17961
17977
  const bound = /* @__PURE__ */ new Set();
17962
17978
  resolver.outputBindings.forEach((binding, index2) => {
@@ -17965,7 +17981,8 @@ function validateResolverCoverage(fields, resolver, issues) {
17965
17981
  }
17966
17982
  bound.add(binding.fieldId);
17967
17983
  });
17968
- for (const fieldId of businessFields) {
17984
+ const requiredFields = card ? collectReferencedA2UICardBusinessFieldIds(card, fields.filter((field) => field.required)) : new Set(fields.filter((field) => field.source === "business" && field.required).map((field) => field.fieldId));
17985
+ for (const fieldId of requiredFields) {
17969
17986
  if (!bound.has(fieldId)) {
17970
17987
  issues.push(issue2("config.resolver.outputBindings", "CARD_BINDING_INCOMPLETE", `business field ${fieldId} is not bound`));
17971
17988
  }
@@ -51,7 +51,7 @@ import {
51
51
  parseConversationRunRequest,
52
52
  parseSkillFile,
53
53
  streamToConversationEvents
54
- } from "../../chunk-YAKPGLYU.js";
54
+ } from "../../chunk-IMZDZMKV.js";
55
55
  import "../../chunk-XUFLSZM4.js";
56
56
  import "../../chunk-I64V3ICJ.js";
57
57
  import "../../chunk-6MHDOBWO.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getBakedProtocol,
3
3
  setBakedProtocol
4
- } from "../chunk-YAKPGLYU.js";
4
+ } from "../chunk-IMZDZMKV.js";
5
5
  import "../chunk-XUFLSZM4.js";
6
6
  import "../chunk-I64V3ICJ.js";
7
7
  import "../chunk-6MHDOBWO.js";
package/worker.js CHANGED
@@ -13822,6 +13822,7 @@ function analyzeA2UIBindings(protocol) {
13822
13822
  const listRoots = inferListRoots(components, issues);
13823
13823
  for (const component of components) {
13824
13824
  const context2 = {
13825
+ surfaceId,
13825
13826
  component,
13826
13827
  listRoot: listRoots.get(component.id),
13827
13828
  occurrences,
@@ -13835,6 +13836,7 @@ function analyzeA2UIBindings(protocol) {
13835
13836
  issues.push(issue2(`card.surfaces.${surfaceId}.components.${component.id}.children.path`, "INVALID_BINDING_PATH", `Invalid list path ${children.path}`));
13836
13837
  } else {
13837
13838
  occurrences.push({
13839
+ surfaceId,
13838
13840
  componentId: component.id,
13839
13841
  componentName: component.component,
13840
13842
  propertyPath: "children.path",
@@ -13853,6 +13855,16 @@ function analyzeA2UIBindings(protocol) {
13853
13855
  issues
13854
13856
  };
13855
13857
  }
13858
+ function collectReferencedA2UICardBusinessFieldIds(protocol, fields) {
13859
+ const businessFields = fields.filter((field) => field.source === "business").slice().sort((left, right) => right.path.length - left.path.length);
13860
+ const result = /* @__PURE__ */ new Set();
13861
+ for (const occurrence of analyzeA2UIBindings(protocol).occurrences) {
13862
+ const field = businessFields.find((candidate) => occurrence.canonicalPath === candidate.path || occurrence.canonicalPath.startsWith(`${candidate.path}/*/`) || occurrence.canonicalPath.startsWith(`${candidate.path}/`));
13863
+ if (field)
13864
+ result.add(field.fieldId);
13865
+ }
13866
+ return result;
13867
+ }
13856
13868
  function visitValue(value, propertyPath, context2) {
13857
13869
  if (propertyPath === "action.local.path" && typeof value === "string") {
13858
13870
  addOccurrence(value, propertyPath, "local", context2);
@@ -13884,6 +13896,7 @@ function addOccurrence(rawPath, propertyPath, usage, context2) {
13884
13896
  return;
13885
13897
  }
13886
13898
  context2.occurrences.push({
13899
+ surfaceId: context2.surfaceId,
13887
13900
  componentId: context2.component.id,
13888
13901
  componentName: context2.component.component,
13889
13902
  propertyPath,
@@ -14258,6 +14271,7 @@ var init_binding_context = __esm({
14258
14271
  init_json2();
14259
14272
  init_schema2();
14260
14273
  init_expression();
14274
+ init_binding_analyzer();
14261
14275
  }
14262
14276
  });
14263
14277
 
@@ -14309,9 +14323,9 @@ function getA2UICardResourceConfigIssues(value) {
14309
14323
  validateLooseJsonSchema(value.presentationInputSchema, "config.presentationInputSchema", issues);
14310
14324
  const fields = validateFields(value.fields, "config.fields", issues);
14311
14325
  const resolver = validateResolver(value.resolver, "config.resolver", issues);
14312
- validateTemplate(value.a2uiTemplate, fields, issues);
14326
+ const card = validateTemplate(value.a2uiTemplate, fields, issues);
14313
14327
  if (fields && resolver)
14314
- validateResolverCoverage(fields, resolver, issues);
14328
+ validateResolverCoverage(fields, resolver, issues, card);
14315
14329
  return issues;
14316
14330
  }
14317
14331
  function getA2UICardResourceConfigV3Issues(value) {
@@ -14344,9 +14358,9 @@ function getA2UICardResourceConfigV3Issues(value) {
14344
14358
  }
14345
14359
  const dataSources = validateDataSources(value.dataSources, "config.dataSources", issues);
14346
14360
  const bindings = validateV3OutputBindings(value.bindings, "config.bindings", issues);
14347
- validateTemplate(value.a2uiTemplate, fields, issues);
14361
+ const card = validateTemplate(value.a2uiTemplate, fields, issues);
14348
14362
  if (fields && dataSources && bindings) {
14349
- validateV3Coverage(fields, dataSources, bindings, issues);
14363
+ validateV3Coverage(fields, dataSources, bindings, issues, { card });
14350
14364
  }
14351
14365
  return issues;
14352
14366
  }
@@ -14460,7 +14474,8 @@ function validateV3Coverage(fields, dataSources, bindings, issues, options = {})
14460
14474
  bound.add(binding.fieldId);
14461
14475
  });
14462
14476
  if (options.requireComplete !== false) {
14463
- for (const fieldId of businessFields) {
14477
+ const requiredFields = options.card ? collectReferencedA2UICardBusinessFieldIds(options.card, fields.filter((field) => field.required)) : new Set(fields.filter((field) => field.source === "business" && field.required).map((field) => field.fieldId));
14478
+ for (const fieldId of requiredFields) {
14464
14479
  if (bound.has(fieldId))
14465
14480
  continue;
14466
14481
  issues.push(issue2("config.bindings", "CARD_BINDING_INCOMPLETE", `business field ${fieldId} is not bound`));
@@ -14760,13 +14775,13 @@ function validateInstructionShape(instruction, path6, issues) {
14760
14775
  function validateTemplate(value, fields, issues) {
14761
14776
  if (!isPlainRecord(value)) {
14762
14777
  issues.push(issue2("config.a2uiTemplate", "INVALID_A2UI_TEMPLATE", "a2uiTemplate must be an object"));
14763
- return;
14778
+ return void 0;
14764
14779
  }
14765
14780
  exactKeys(value, ["argsSchema", "content"], "config.a2uiTemplate", issues);
14766
14781
  validateLooseJsonSchema(value.argsSchema, "config.a2uiTemplate.argsSchema", issues);
14767
14782
  if (typeof value.content !== "string") {
14768
14783
  issues.push(issue2("config.a2uiTemplate.content", "INVALID_A2UI_CONTENT", "a2uiTemplate.content must be serialized A2UI JSON"));
14769
- return;
14784
+ return void 0;
14770
14785
  }
14771
14786
  try {
14772
14787
  const card = validateProtocol(JSON.parse(value.content), "config.a2uiTemplate.content", issues);
@@ -14774,9 +14789,11 @@ function validateTemplate(value, fields, issues) {
14774
14789
  const analysis = analyzeA2UIBindings(card);
14775
14790
  issues.push(...analysis.issues);
14776
14791
  }
14792
+ return card;
14777
14793
  } catch {
14778
14794
  issues.push(issue2("config.a2uiTemplate.content", "INVALID_A2UI_CONTENT", "a2uiTemplate.content must contain valid JSON"));
14779
14795
  }
14796
+ return void 0;
14780
14797
  }
14781
14798
  function validateLooseJsonSchema(value, path6, issues) {
14782
14799
  const schemaIssues = getJsonSchemaIssues2(value, path6, {
@@ -14785,7 +14802,7 @@ function validateLooseJsonSchema(value, path6, issues) {
14785
14802
  issues.push(...schemaIssues);
14786
14803
  return schemaIssues.length === 0;
14787
14804
  }
14788
- function validateResolverCoverage(fields, resolver, issues) {
14805
+ function validateResolverCoverage(fields, resolver, issues, card) {
14789
14806
  const businessFields = new Set(fields.filter((field) => field.source === "business").map((field) => field.fieldId));
14790
14807
  const bound = /* @__PURE__ */ new Set();
14791
14808
  resolver.outputBindings.forEach((binding, index2) => {
@@ -14794,7 +14811,8 @@ function validateResolverCoverage(fields, resolver, issues) {
14794
14811
  }
14795
14812
  bound.add(binding.fieldId);
14796
14813
  });
14797
- for (const fieldId of businessFields) {
14814
+ const requiredFields = card ? collectReferencedA2UICardBusinessFieldIds(card, fields.filter((field) => field.required)) : new Set(fields.filter((field) => field.source === "business" && field.required).map((field) => field.fieldId));
14815
+ for (const fieldId of requiredFields) {
14798
14816
  if (!bound.has(fieldId)) {
14799
14817
  issues.push(issue2("config.resolver.outputBindings", "CARD_BINDING_INCOMPLETE", `business field ${fieldId} is not bound`));
14800
14818
  }
@@ -14847,6 +14865,7 @@ var init_compiler = __esm({
14847
14865
  "../agent-a2ui-card-contract/dist/esm/compiler.js"() {
14848
14866
  "use strict";
14849
14867
  init_json2();
14868
+ init_binding_analyzer();
14850
14869
  init_validation();
14851
14870
  init_schema2();
14852
14871
  }
@@ -15070,6 +15089,25 @@ var init_template = __esm({
15070
15089
  }
15071
15090
  });
15072
15091
 
15092
+ // ../agent-a2ui-card-contract/dist/esm/authoring-model.js
15093
+ var init_authoring_model = __esm({
15094
+ "../agent-a2ui-card-contract/dist/esm/authoring-model.js"() {
15095
+ "use strict";
15096
+ init_binding_analyzer();
15097
+ init_json2();
15098
+ init_validation();
15099
+ }
15100
+ });
15101
+
15102
+ // ../agent-a2ui-card-contract/dist/esm/authoring-operation.js
15103
+ var init_authoring_operation = __esm({
15104
+ "../agent-a2ui-card-contract/dist/esm/authoring-operation.js"() {
15105
+ "use strict";
15106
+ init_authoring_model();
15107
+ init_json2();
15108
+ }
15109
+ });
15110
+
15073
15111
  // ../agent-a2ui-card-contract/dist/esm/index.js
15074
15112
  var init_esm4 = __esm({
15075
15113
  "../agent-a2ui-card-contract/dist/esm/index.js"() {
@@ -15087,6 +15125,8 @@ var init_esm4 = __esm({
15087
15125
  init_binding_context();
15088
15126
  init_preview_binding();
15089
15127
  init_template();
15128
+ init_authoring_model();
15129
+ init_authoring_operation();
15090
15130
  }
15091
15131
  });
15092
15132