comfyui-mcp 0.52.199 → 0.52.200
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/dist/orchestrator/panel-tools.js +103 -53
- package/dist/orchestrator/panel-tools.js.map +1 -1
- package/dist/services/missing-models.js +1 -1
- package/dist/services/missing-models.js.map +1 -1
- package/dist/services/model-resolver.js +176 -22
- package/dist/services/model-resolver.js.map +1 -1
- package/package.json +1 -1
|
@@ -6035,13 +6035,21 @@ function forgetStaleSubgraphIdentity(ctx) {
|
|
|
6035
6035
|
ctx.bridge?.clearPromotedSubgraphIdentity?.(ctx.tabId);
|
|
6036
6036
|
}
|
|
6037
6037
|
/** Tabs whose promoted-container mapping is unverified after a queue-busy
|
|
6038
|
-
* mutation refusal. `graph_get_subgraph` can stay
|
|
6039
|
-
*
|
|
6038
|
+
* mutation refusal or a canvas-replacing load. `graph_get_subgraph` can stay
|
|
6039
|
+
* indeterminate for ordinary root nodes and live subgraphs until something
|
|
6040
|
+
* walks the live graph (#2730, #2886). */
|
|
6040
6041
|
const staleSubgraphMappingTabs = new Set();
|
|
6041
6042
|
function noteStaleSubgraphMapping(tabId) {
|
|
6042
6043
|
if (tabId)
|
|
6043
6044
|
staleSubgraphMappingTabs.add(tabId);
|
|
6044
6045
|
}
|
|
6046
|
+
/** A successful `graph_load` replaced the canvas. Drop leftover subgraph
|
|
6047
|
+
* identity and force one mapping refresh before the next promoted write so
|
|
6048
|
+
* `panel_set_widget` does not stay refused until a manual current-target rebind. */
|
|
6049
|
+
function noteCanvasReplacedForPromotedWrites(ctx) {
|
|
6050
|
+
forgetStaleSubgraphIdentity(ctx);
|
|
6051
|
+
noteStaleSubgraphMapping(ctx.tabId);
|
|
6052
|
+
}
|
|
6045
6053
|
export function __resetStaleSubgraphMappingForTest() {
|
|
6046
6054
|
staleSubgraphMappingTabs.clear();
|
|
6047
6055
|
}
|
|
@@ -6586,6 +6594,9 @@ function classifyPromotedSubgraphReadError(res) {
|
|
|
6586
6594
|
}
|
|
6587
6595
|
return "permanent";
|
|
6588
6596
|
}
|
|
6597
|
+
function isStaleSubgraphMappingRead(res) {
|
|
6598
|
+
return /subgraph mapping is not loaded/i.test(textOfToolResult(res));
|
|
6599
|
+
}
|
|
6589
6600
|
/**
|
|
6590
6601
|
* panel#1869 — the panel's `[canvas-root-divergence]` refusal is a DIAGNOSIS,
|
|
6591
6602
|
* and must not be replaced by the promoted-container wording.
|
|
@@ -7442,7 +7453,12 @@ async function preparePromotedWidgetWrite(ctx, nodeId, widget) {
|
|
|
7442
7453
|
// ordinary root node. Refresh the mapping once and re-probe. Still
|
|
7443
7454
|
// unverifiable → refuse. Do not spend the transient subgraph re-read on
|
|
7444
7455
|
// a permanent application error.
|
|
7445
|
-
|
|
7456
|
+
// #2886 — a live subgraph container has the same stale-registry miss
|
|
7457
|
+
// after graph_load. Re-probing only the ordinary fast path left those
|
|
7458
|
+
// writes refused; retry graph_get_subgraph once the mapping walk ran.
|
|
7459
|
+
// Do not replay other permanent application errors.
|
|
7460
|
+
const mappingUnknown = isStaleSubgraphMappingRead(sub);
|
|
7461
|
+
if (!mappingRefreshed && (rootGraphIdentity !== null || mappingUnknown)) {
|
|
7446
7462
|
const refreshError = await refreshSubgraphMapping();
|
|
7447
7463
|
if (refreshError)
|
|
7448
7464
|
return refreshError;
|
|
@@ -7455,61 +7471,89 @@ async function preparePromotedWidgetWrite(ctx, nodeId, widget) {
|
|
|
7455
7471
|
return ordinaryBindingRefusal(widget, driftAfterMapping);
|
|
7456
7472
|
return ordinaryWritePlanFromScope(widget, targetScope, tabBefore, identityBefore);
|
|
7457
7473
|
}
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
}
|
|
7461
|
-
// A binding/subgraph registration transition can make the first read
|
|
7462
|
-
// indeterminate even though the same live container is readable immediately
|
|
7463
|
-
// afterward. Refresh once, then keep the existing fail-closed classification
|
|
7464
|
-
// and identity checks for the fresh reply.
|
|
7465
|
-
const refreshedSub = await ctx.call({ cmd: "graph_get_subgraph", node_id: nodeId }, undefined, undefined, undefined, PROMOTED_PREFLIGHT_READ_OPTIONS);
|
|
7466
|
-
if (refreshedSub.isError) {
|
|
7467
|
-
const refreshedReadKind = classifyPromotedSubgraphReadError(refreshedSub);
|
|
7468
|
-
if (refreshedReadKind === "definitive-ordinary") {
|
|
7469
|
-
const driftAfterRefresh = panelBindingDriftReason(ctx, "after the subgraph refresh", hasIdentityApi, identityBefore, tabBefore);
|
|
7470
|
-
if (driftAfterRefresh)
|
|
7471
|
-
return promotedWriteRefusal(widget, driftAfterRefresh);
|
|
7472
|
-
const expectedNodeType = definitiveNonPromotedNodeType(refreshedSub);
|
|
7473
|
-
if (!expectedNodeType) {
|
|
7474
|
-
return promotedWriteRefusal(widget, "the definitive ordinary refresh did not publish a node type fence");
|
|
7475
|
-
}
|
|
7476
|
-
const expectedNodeIdentity = targetScope?.nodeIdentity;
|
|
7477
|
-
if (!expectedNodeIdentity) {
|
|
7478
|
-
return promotedWriteRefusal(widget, "the preflight ordinary-node read did not publish a trustworthy node identity fence");
|
|
7474
|
+
if (mappingUnknown) {
|
|
7475
|
+
sub = await ctx.call({ cmd: "graph_get_subgraph", node_id: nodeId }, undefined, undefined, undefined, PROMOTED_PREFLIGHT_READ_OPTIONS);
|
|
7479
7476
|
}
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
7477
|
+
}
|
|
7478
|
+
if (sub.isError) {
|
|
7479
|
+
if (classifyPromotedSubgraphReadError(sub) === "definitive-ordinary") {
|
|
7480
|
+
const driftAfterMappingRead = panelBindingDriftReason(ctx, "after the subgraph mapping refresh", hasIdentityApi, identityBefore, tabBefore);
|
|
7481
|
+
if (driftAfterMappingRead)
|
|
7482
|
+
return promotedWriteRefusal(widget, driftAfterMappingRead);
|
|
7483
|
+
if (targetScope?.activeView === "subgraph" && targetScope.node === "ordinary") {
|
|
7484
|
+
if (!targetScope.nodeIdentity)
|
|
7485
|
+
return null;
|
|
7486
|
+
const expectedNodeType = definitiveNonPromotedNodeType(sub);
|
|
7487
|
+
if (!sameDefinitiveOrdinaryNodeType(expectedNodeType, targetScope.nodeType)) {
|
|
7488
|
+
return promotedWriteRefusal(widget, "the ordinary node type changed between the scope and subgraph reads");
|
|
7489
|
+
}
|
|
7490
|
+
if (ctx.tabExpectedNodeTypeFenceCapability?.() !== true) {
|
|
7491
|
+
return promotedPanelBuildRefusal(ctx, nodeId, widget, "does not advertise the atomic ordinary-node write fence", "enforces_expected_node_type_at_write");
|
|
7492
|
+
}
|
|
7493
|
+
if (ctx.tabExpectedNodeIdentityFenceCapability?.() !== true) {
|
|
7494
|
+
return promotedPanelBuildRefusal(ctx, nodeId, widget, "does not advertise the atomic ordinary-node identity write fence", "enforces_expected_node_identity_at_write");
|
|
7495
|
+
}
|
|
7496
|
+
return ordinaryWritePlanFromScope(widget, targetScope, tabBefore, identityBefore);
|
|
7497
|
+
}
|
|
7498
|
+
return null;
|
|
7489
7499
|
}
|
|
7490
|
-
return
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7500
|
+
return promotedSubgraphReadRefusal(widget, sub, "graph_get_subgraph could not determine whether the addressed node is a promoted container");
|
|
7501
|
+
}
|
|
7502
|
+
}
|
|
7503
|
+
else {
|
|
7504
|
+
// A binding/subgraph registration transition can make the first read
|
|
7505
|
+
// indeterminate even though the same live container is readable immediately
|
|
7506
|
+
// afterward. Refresh once, then keep the existing fail-closed classification
|
|
7507
|
+
// and identity checks for the fresh reply.
|
|
7508
|
+
const refreshedSub = await ctx.call({ cmd: "graph_get_subgraph", node_id: nodeId }, undefined, undefined, undefined, PROMOTED_PREFLIGHT_READ_OPTIONS);
|
|
7509
|
+
if (refreshedSub.isError) {
|
|
7510
|
+
const refreshedReadKind = classifyPromotedSubgraphReadError(refreshedSub);
|
|
7511
|
+
if (refreshedReadKind === "definitive-ordinary") {
|
|
7512
|
+
const driftAfterRefresh = panelBindingDriftReason(ctx, "after the subgraph refresh", hasIdentityApi, identityBefore, tabBefore);
|
|
7513
|
+
if (driftAfterRefresh)
|
|
7514
|
+
return promotedWriteRefusal(widget, driftAfterRefresh);
|
|
7515
|
+
const expectedNodeType = definitiveNonPromotedNodeType(refreshedSub);
|
|
7516
|
+
if (!expectedNodeType) {
|
|
7517
|
+
return promotedWriteRefusal(widget, "the definitive ordinary refresh did not publish a node type fence");
|
|
7518
|
+
}
|
|
7519
|
+
const expectedNodeIdentity = targetScope?.nodeIdentity;
|
|
7520
|
+
if (!expectedNodeIdentity) {
|
|
7521
|
+
return promotedWriteRefusal(widget, "the preflight ordinary-node read did not publish a trustworthy node identity fence");
|
|
7522
|
+
}
|
|
7523
|
+
if (ctx.tabExpectedNodeTypeFenceCapability?.() !== true) {
|
|
7524
|
+
return promotedPanelBuildRefusal(ctx, nodeId, widget, "does not advertise the atomic ordinary-node write fence", "enforces_expected_node_type_at_write");
|
|
7525
|
+
}
|
|
7526
|
+
if (ctx.tabExpectedNodeIdentityFenceCapability?.() !== true) {
|
|
7527
|
+
return promotedPanelBuildRefusal(ctx, nodeId, widget, "does not advertise the atomic ordinary-node identity write fence", "enforces_expected_node_identity_at_write");
|
|
7528
|
+
}
|
|
7529
|
+
const ordinaryScope = targetScope;
|
|
7530
|
+
if (!ordinaryScope?.graphIdentity) {
|
|
7531
|
+
return ordinaryBindingRefusal(widget, "did not publish the current graph identity needed to fence this ordinary write");
|
|
7532
|
+
}
|
|
7533
|
+
return {
|
|
7534
|
+
kind: "ordinary-write",
|
|
7535
|
+
activeView: ordinaryScope.activeView,
|
|
7536
|
+
...(ordinaryScope.scopeOwnerNodeId !== undefined
|
|
7537
|
+
? { scopeOwnerNodeId: ordinaryScope.scopeOwnerNodeId }
|
|
7506
7538
|
: {}),
|
|
7507
|
-
|
|
7508
|
-
|
|
7539
|
+
graphIdentity: ordinaryScope.graphIdentity,
|
|
7540
|
+
...(ordinaryScope.workflowUuid !== undefined
|
|
7541
|
+
? { workflowUuid: ordinaryScope.workflowUuid }
|
|
7542
|
+
: {}),
|
|
7543
|
+
expectedNodeType,
|
|
7544
|
+
expectedNodeIdentity,
|
|
7545
|
+
binding: {
|
|
7546
|
+
tabId: tabBefore,
|
|
7547
|
+
...(isUsablePanelConnectionIdentity(identityBefore)
|
|
7548
|
+
? { identity: identityBefore }
|
|
7549
|
+
: {}),
|
|
7550
|
+
},
|
|
7551
|
+
};
|
|
7552
|
+
}
|
|
7553
|
+
return promotedSubgraphReadRefusal(widget, refreshedSub, "graph_get_subgraph could not determine whether the addressed node is a promoted container");
|
|
7509
7554
|
}
|
|
7510
|
-
|
|
7555
|
+
sub = refreshedSub;
|
|
7511
7556
|
}
|
|
7512
|
-
sub = refreshedSub;
|
|
7513
7557
|
}
|
|
7514
7558
|
let payload = parseToolResultJson(sub);
|
|
7515
7559
|
if (!payload || !promotedEnvelopeCarriesEvidence(payload)) {
|
|
@@ -17918,6 +17962,12 @@ export function buildPanelToolDefs() {
|
|
|
17918
17962
|
// `format:"api"`. That field is present only on this branch, which makes it the
|
|
17919
17963
|
// signal rather than an inference.
|
|
17920
17964
|
const reply = parseToolResultJson(loaded);
|
|
17965
|
+
// #2886 — a successful load replaces the canvas. UI-format keeps the
|
|
17966
|
+
// instance uuid, so the fence is still valid, but leftover subgraph
|
|
17967
|
+
// identity and the subgraph registry still describe the PREVIOUS graph.
|
|
17968
|
+
// Mark mapping stale here; do not re-derive from whatever is active now.
|
|
17969
|
+
if (reply?.loaded === true)
|
|
17970
|
+
noteCanvasReplacedForPromotedWrites(ctx);
|
|
17921
17971
|
const remintedInstance = reply?.loaded === true && reply?.format === "api";
|
|
17922
17972
|
if (!remintedInstance)
|
|
17923
17973
|
return loaded;
|