comfyui-mcp
Version:
Local-first, agent-native control plane for ComfyUI — MCP server + autonomous sidebar agent that drives your live graph in natural language on ANY LLM: Claude/ChatGPT/Gemini on your subscription (no API key), free local models via Ollama (fully offline),
112 lines • 7.13 kB
JavaScript
// WHY the fence-adoption validator refused, in words the caller can act on.
//
// Extracted from the validator callback in index.ts so it is reachable by tests:
// while it lived inline, the only way to assert the wording was to build a fake
// bridge and check that it returned what the fake was told to return — a
// tautology that would have passed with the logic deleted.
//
// #1077 — the validator has three gates and all of them used to return a bare
// `false`, so a permanently-wedged session was told only "the adoption was
// REFUSED". Naming the gate is the fix; naming it WRONGLY is worse than not
// naming it, which is what the first version of this did.
//
// `canReach()` and `tabServerOrigin()` both swallow whatever `resolveTarget`
// throws, so a turn issued from SEVERAL workflows at once (routing ambiguity,
// #1001) is indistinguishable at those call sites from a dead tab and from a
// connection carrying no Origin. It therefore inherited the structural
// no-Origin story: "refreshing will not help, stop using the relay backend".
// For an ambiguous turn that is wrong on every count — the tabs are connected,
// the Origin exists, nothing is structural, and it clears on the next
// single-origin message. The cause is typed and was simply being discarded.
/** The turn's target is ambiguous — say so, and say it is self-clearing. */
function ambiguousTurn(tabId, what) {
return (`this turn was issued from SEVERAL workflows at once, so ${what} for "${tabId}" — the tabs ` +
`are connected and fine. This clears itself: target a workflow explicitly ` +
`(panel_set_workflow_target with a path, or panel_open_workflow), or let the next ` +
`single-origin message settle it. Do NOT reconnect or refresh.`);
}
/** Gate 1: the routed tab did not resolve at all. */
export function unreachableReason(tabId, failure) {
if (failure === "ambiguous")
return ambiguousTurn(tabId, "there is no single target to fence");
return `the routed tab (${tabId}) is no longer reachable, so there is nothing to fence`;
}
/** Gate 2: it resolved, but not to a live panel tab. */
export function noPanelTabReason(tabId) {
return `${tabId} does not resolve to a live panel tab (a scope address whose tab has gone away)`;
}
/**
* Gate 3: the workflow identity did not validate.
*
* ORDER MATTERS. An ambiguous turn also yields no origin, so it must be checked
* BEFORE the structural no-Origin case, or it borrows a remedy that cannot help
* it and is told its problem is permanent.
*/
/**
* The remedy for "this connection has no server-observed Origin" (panel#1065).
*
* Shared, because it was NOT shared and the two copies drifted. #1077/#1240 gave
* the relay path the origin it already knows from COMFYUI_URL, and updated the
* refusal below to say so. The OTHER surface rendering this same refusal — the
* `rejected` branch of describeFenceRebind in panel-tools.ts — kept the pre-fix
* text, which told the user to abandon the relay backend and to "report it: the
* relay protocol has to forward the browser's handshake Origin for this path to
* work at all".
*
* A user on 0.50.114 — a version that HAS the fix — followed that instruction and
* filed panel#1065 quoting it back. The stale sentence manufactured its own bug
* report, and told someone to downgrade a working setup on the way.
*/
export const NO_ORIGIN_REMEDY =
// The gate's OWN semantics come first, because they dissolve the fear the old
// wording created and the reporter's stated obstacle at once. Measured, not
// assumed: workflowIdentityParts requires an origin to EXIST, both call sites
// take only `.uuid`, and `identity.origin` is never read again — so the value
// is a scope, not a claim to be checked against the browser.
`What this gate checks is PRESENCE, not agreement: the identity needs SOME origin to be ` +
`scoped to, and nothing ever compares it against the browser's — so the value does not have ` +
`to match where the panel is served from. ` +
// Two causes, named separately (codex review, P1). The predicate that selects this
// remedy is generic, and a blanket "set COMFYUI_URL" sends a direct/LAN/pairing or
// non-browser caller to a change that CANNOT add a handshake origin, leaving them
// fenced with nothing left to try.
`On a RELAY connection the origin is derived from COMFYUI_URL, so an unset or unparseable ` +
`COMFYUI_URL is the usual cause and setting it to any valid URL supplies one; you do not have ` +
`to leave the relay backend, which has supplied its own origin since 0.50.67. ` +
`On any other path the connection never presented an Origin header at all — a non-browser ` +
`client, or a proxy that strips it — and what fixes that is reaching the orchestrator from the ` +
`browser panel itself. ` +
`Refreshing the tab will not change either case. Reads and non-graph tools keep working ` +
`meanwhile — they do not need the fence.`;
export function identityReason(tabId, origin, workflowUuid, failure) {
if (!origin && failure === "ambiguous") {
return ambiguousTurn(tabId, "no single tab's identity could be read");
}
if (!origin) {
// The relay case USED to land here and was told, correctly at the time, that
// its problem was permanent. It no longer is: the relay path now supplies the
// origin it already knows from COMFYUI_URL, so a relay session adopts fences
// like any other. Naming a fixed cause as the "known case" would send a
// reader to change a backend that is no longer the reason (#1077).
return (`this tab's connection carries no server-observed Origin, and the workflow identity is ` +
`bound to one — so the fence cannot be adopted for it. This means the connection reached ` +
`the orchestrator by a path that neither observed nor was told the panel's origin. ` +
NO_ORIGIN_REMEDY);
}
// #1255 — this used to end "a malformed uuid, or one bound to a different
// origin", which describes a comparison the code does not perform.
// workflowIdentityParts uses the origin as a PRESENCE gate: it requires one to
// exist, and never compares it against a previously bound value (nothing in
// the repo has ever read `identity.origin` -- both call sites take `.uuid`).
// Reaching here with an origin present therefore means the UUID failed its
// shape check, full stop.
//
// The old wording sent a reader hunting for an origin mismatch that cannot
// happen -- it cost a whole investigation and a closed-unmerged PR before the
// mechanism was checked rather than believed. A refusal must describe the
// check it actually ran.
return (`the workflow identity did not validate: the uuid ${String(workflowUuid)} is not a ` +
`well-formed workflow uuid. (The origin ${origin} was present and accepted -- this gate ` +
`requires an origin to exist, it does not compare it against a previously bound one.)`);
}
//# sourceMappingURL=fence-refusal.js.map