linkque-cli-v2 1.1.4-beta.1 → 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 +439 -36
- package/package.json +1 -1
package/linkquejs.js
CHANGED
|
@@ -27426,9 +27426,6 @@ function createA2UICardDraftStructureChecksum(draft) {
|
|
|
27426
27426
|
delete cloned.manifest.bindings;
|
|
27427
27427
|
return sha256Hex(stableJsonStringify(cloned));
|
|
27428
27428
|
}
|
|
27429
|
-
function createA2UICardMcpConfigChecksum(resources) {
|
|
27430
|
-
return sha256Hex(stableJsonStringify(resources));
|
|
27431
|
-
}
|
|
27432
27429
|
function createA2UICardRevision(draftChecksum2, bindings) {
|
|
27433
27430
|
const digest = sha256Hex(`${draftChecksum2}
|
|
27434
27431
|
${stableJsonStringify(bindings)}`);
|
|
@@ -27507,6 +27504,393 @@ var SHA256_CONSTANTS = [
|
|
|
27507
27504
|
3329325298
|
|
27508
27505
|
];
|
|
27509
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
|
+
|
|
27510
27894
|
// src/commands/card/index.ts
|
|
27511
27895
|
var DRAFT_ROOT = ".card-drafts";
|
|
27512
27896
|
var AGENT_CONFIG_PATH = "agent_config.json";
|
|
@@ -27636,36 +28020,20 @@ async function validateCardBindingsFromDisk(cwd, draftId, fieldId) {
|
|
|
27636
28020
|
const directory = draftDirectory(cwd, draftId);
|
|
27637
28021
|
const [bundle, contextValue, configValue] = await Promise.all([
|
|
27638
28022
|
readBundle(directory, draftId),
|
|
27639
|
-
|
|
28023
|
+
readOptionalJson(import_path22.default.join(directory, "binding-context.json")),
|
|
27640
28024
|
readRequiredJson(import_path22.default.join(cwd, AGENT_CONFIG_PATH))
|
|
27641
28025
|
]);
|
|
27642
|
-
const
|
|
27643
|
-
if (!contextResult.success) {
|
|
27644
|
-
throw new LinkqueCliError(
|
|
27645
|
-
"CARD_BINDING_CONTEXT_INVALID",
|
|
27646
|
-
contextResult.issues.map((entry) => entry.message).join("; ")
|
|
27647
|
-
);
|
|
27648
|
-
}
|
|
27649
|
-
const context = contextResult.data;
|
|
28026
|
+
const context = parseOptionalBindingContext(contextValue);
|
|
27650
28027
|
const draftStructureChecksum = createA2UICardDraftStructureChecksum(bundle);
|
|
27651
28028
|
const config2 = parseAgentConfig(configValue);
|
|
27652
28029
|
const mcpResources = normalizedMcpResources(config2);
|
|
27653
|
-
|
|
27654
|
-
|
|
27655
|
-
"CARD_BINDING_CONTEXT_STALE",
|
|
27656
|
-
"MCP \u914D\u7F6E\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u53D1\u8D77 AI \u8F85\u52A9\u7ED1\u5B9A"
|
|
27657
|
-
);
|
|
27658
|
-
}
|
|
27659
|
-
const issues = validateA2UICardBindings(
|
|
27660
|
-
{
|
|
27661
|
-
draft: bundle,
|
|
27662
|
-
context,
|
|
27663
|
-
mountedMcpResourceIds: new Set(
|
|
27664
|
-
mcpResources.map((resource) => String(resource.resourceId))
|
|
27665
|
-
)
|
|
27666
|
-
},
|
|
27667
|
-
fieldId ? { fieldIds: /* @__PURE__ */ new Set([fieldId]) } : void 0
|
|
28030
|
+
const mountedMcpResourceIds = new Set(
|
|
28031
|
+
mcpResources.map((resource) => String(resource.resourceId))
|
|
27668
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);
|
|
27669
28037
|
if (issues.length > 0) {
|
|
27670
28038
|
throw new LinkqueCliError(
|
|
27671
28039
|
"CARD_BINDING_VALIDATION_FAILED",
|
|
@@ -27696,15 +28064,9 @@ async function finalizeCardWhileLocked(cwd, draftId, expectedDraftChecksum) {
|
|
|
27696
28064
|
}
|
|
27697
28065
|
const directory = draftDirectory(cwd, draftId);
|
|
27698
28066
|
const bundle = await readBundle(directory, draftId);
|
|
27699
|
-
const
|
|
27700
|
-
await
|
|
28067
|
+
const context = parseOptionalBindingContext(
|
|
28068
|
+
await readOptionalJson(import_path22.default.join(directory, "binding-context.json"))
|
|
27701
28069
|
);
|
|
27702
|
-
if (!contextResult.success) {
|
|
27703
|
-
throw new LinkqueCliError(
|
|
27704
|
-
"CARD_BINDING_CONTEXT_INVALID",
|
|
27705
|
-
contextResult.issues.map((entry) => entry.message).join("; ")
|
|
27706
|
-
);
|
|
27707
|
-
}
|
|
27708
28070
|
const configPath = import_path22.default.join(cwd, AGENT_CONFIG_PATH);
|
|
27709
28071
|
const oldConfigBytes = await (0, import_promises16.readFile)(configPath);
|
|
27710
28072
|
const config2 = parseAgentConfig(
|
|
@@ -27738,7 +28100,7 @@ async function finalizeCardWhileLocked(cwd, draftId, expectedDraftChecksum) {
|
|
|
27738
28100
|
// V3,让 Agent 直接按真实 MCP inputSchema 决定参数;不再把 presentation input
|
|
27739
28101
|
// 或 inputBindings 固化进 CARD。
|
|
27740
28102
|
...bindings.length > 0 ? { targetSchemaVersion: "3" } : {},
|
|
27741
|
-
tools:
|
|
28103
|
+
tools: (context?.candidates ?? []).flatMap(
|
|
27742
28104
|
(candidate) => candidate.status === "ready" ? [candidate.tool] : []
|
|
27743
28105
|
)
|
|
27744
28106
|
});
|
|
@@ -28065,6 +28427,47 @@ function normalizedMcpResources(config2) {
|
|
|
28065
28427
|
(left, right) => stableJsonStringify(left).localeCompare(stableJsonStringify(right))
|
|
28066
28428
|
);
|
|
28067
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
|
+
}
|
|
28068
28471
|
function isJsonObject(value) {
|
|
28069
28472
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
28070
28473
|
}
|