comfyui-mcp 0.50.30 → 0.50.32

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.
@@ -0,0 +1,59 @@
1
+ // WHY the fence-adoption validator refused, in words the caller can act on.
2
+ //
3
+ // Extracted from the validator callback in index.ts so it is reachable by tests:
4
+ // while it lived inline, the only way to assert the wording was to build a fake
5
+ // bridge and check that it returned what the fake was told to return — a
6
+ // tautology that would have passed with the logic deleted.
7
+ //
8
+ // #1077 — the validator has three gates and all of them used to return a bare
9
+ // `false`, so a permanently-wedged session was told only "the adoption was
10
+ // REFUSED". Naming the gate is the fix; naming it WRONGLY is worse than not
11
+ // naming it, which is what the first version of this did.
12
+ //
13
+ // `canReach()` and `tabServerOrigin()` both swallow whatever `resolveTarget`
14
+ // throws, so a turn issued from SEVERAL workflows at once (routing ambiguity,
15
+ // #1001) is indistinguishable at those call sites from a dead tab and from a
16
+ // connection carrying no Origin. It therefore inherited the structural
17
+ // no-Origin story: "refreshing will not help, stop using the relay backend".
18
+ // For an ambiguous turn that is wrong on every count — the tabs are connected,
19
+ // the Origin exists, nothing is structural, and it clears on the next
20
+ // single-origin message. The cause is typed and was simply being discarded.
21
+ /** The turn's target is ambiguous — say so, and say it is self-clearing. */
22
+ function ambiguousTurn(tabId, what) {
23
+ return (`this turn was issued from SEVERAL workflows at once, so ${what} for "${tabId}" — the tabs ` +
24
+ `are connected and fine. This clears itself: target a workflow explicitly ` +
25
+ `(panel_set_workflow_target with a path, or panel_open_workflow), or let the next ` +
26
+ `single-origin message settle it. Do NOT reconnect or refresh.`);
27
+ }
28
+ /** Gate 1: the routed tab did not resolve at all. */
29
+ export function unreachableReason(tabId, failure) {
30
+ if (failure === "ambiguous")
31
+ return ambiguousTurn(tabId, "there is no single target to fence");
32
+ return `the routed tab (${tabId}) is no longer reachable, so there is nothing to fence`;
33
+ }
34
+ /** Gate 2: it resolved, but not to a live panel tab. */
35
+ export function noPanelTabReason(tabId) {
36
+ return `${tabId} does not resolve to a live panel tab (a scope address whose tab has gone away)`;
37
+ }
38
+ /**
39
+ * Gate 3: the workflow identity did not validate.
40
+ *
41
+ * ORDER MATTERS. An ambiguous turn also yields no origin, so it must be checked
42
+ * BEFORE the structural no-Origin case, or it borrows a remedy that cannot help
43
+ * it and is told its problem is permanent.
44
+ */
45
+ export function identityReason(tabId, origin, workflowUuid, failure) {
46
+ if (!origin && failure === "ambiguous") {
47
+ return ambiguousTurn(tabId, "no single tab's identity could be read");
48
+ }
49
+ if (!origin) {
50
+ return (`this tab's connection carries no server-observed Origin, and the workflow identity is ` +
51
+ `bound to one — so the fence can never be adopted for it. This is structural, not ` +
52
+ `transient: refreshing the tab will not change it. Relay-backend connections ` +
53
+ `(COMFYUI_MCP_TUNNEL_BACKEND=relay) are the known case, because the relay protocol does ` +
54
+ `not forward the browser's handshake Origin.`);
55
+ }
56
+ return (`the workflow identity did not validate (uuid ${String(workflowUuid)} against origin ` +
57
+ `${origin}) — a malformed uuid, or one bound to a different origin.`);
58
+ }
59
+ //# sourceMappingURL=fence-refusal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fence-refusal.js","sourceRoot":"","sources":["../../src/orchestrator/fence-refusal.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAChF,yEAAyE;AACzE,2DAA2D;AAC3D,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,4EAA4E;AAC5E,0DAA0D;AAC1D,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,6EAA6E;AAC7E,uEAAuE;AACvE,6EAA6E;AAC7E,+EAA+E;AAC/E,sEAAsE;AACtE,4EAA4E;AAM5E,4EAA4E;AAC5E,SAAS,aAAa,CAAC,KAAa,EAAE,IAAY;IAChD,OAAO,CACL,2DAA2D,IAAI,SAAS,KAAK,eAAe;QAC5F,2EAA2E;QAC3E,mFAAmF;QACnF,+DAA+D,CAChE,CAAC;AACJ,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,OAAuB;IACtE,IAAI,OAAO,KAAK,WAAW;QAAE,OAAO,aAAa,CAAC,KAAK,EAAE,oCAAoC,CAAC,CAAC;IAC/F,OAAO,mBAAmB,KAAK,wDAAwD,CAAC;AAC1F,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,GAAG,KAAK,iFAAiF,CAAC;AACnG,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAa,EACb,MAA0B,EAC1B,YAAqB,EACrB,OAAuB;IAEvB,IAAI,CAAC,MAAM,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;QACvC,OAAO,aAAa,CAAC,KAAK,EAAE,wCAAwC,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CACL,wFAAwF;YACxF,mFAAmF;YACnF,8EAA8E;YAC9E,yFAAyF;YACzF,6CAA6C,CAC9C,CAAC;IACJ,CAAC;IACD,OAAO,CACL,gDAAgD,MAAM,CAAC,YAAY,CAAC,kBAAkB;QACtF,GAAG,MAAM,2DAA2D,CACrE,CAAC;AACJ,CAAC"}
@@ -27,6 +27,7 @@ import { isPanelAutoInstallDisabled } from "../services/panel-installer.js";
27
27
  import { SelfRestarter, canSelfRestart } from "../services/self-restart.js";
28
28
  import { pairUrlDurability } from "./pair-durability.js";
29
29
  import { SessionStore, workflowIdentityParts } from "./session-store.js";
30
+ import { unreachableReason, noPanelTabReason, identityReason } from "./fence-refusal.js";
30
31
  import { SHARED_SESSION_SCOPE, isScopeAddress, conversationTabs, shouldRetireSharedAgent, messageOrigin, normalizeHelloBackend, workflowOriginNote, } from "../services/session-scope.js";
31
32
  import { TurnOriginTracker, makeScopeRepinHandler, makeScopeTargetResolver, } from "./turn-origins.js";
32
33
  import { listSessions, loadTranscript } from "./history.js";
@@ -2541,11 +2542,12 @@ export async function runPanelOrchestrator() {
2541
2542
  // log to fall back on. One of these is structurally unsatisfiable for a
2542
2543
  // relay-backend session, and that is invisible without this.
2543
2544
  try {
2545
+ // #1077 — an AMBIGUOUS turn is not a dead tab. Both fail canReach, and
2546
+ // calling the first the second sent the caller to reconnect a panel that
2547
+ // was never disconnected. The wording lives in fence-refusal.ts so it is
2548
+ // testable without standing up the orchestrator.
2544
2549
  if (!bridge.canReach(tabId))
2545
- return {
2546
- ok: false,
2547
- reason: `the routed tab (${tabId}) is no longer reachable, so there is nothing to fence`,
2548
- };
2550
+ return { ok: false, reason: unreachableReason(tabId, bridge.resolveFailure?.(tabId)) };
2549
2551
  }
2550
2552
  catch (err) {
2551
2553
  return {
@@ -2555,25 +2557,13 @@ export async function runPanelOrchestrator() {
2555
2557
  }
2556
2558
  const panelTab = scopeToRealTab(tabId);
2557
2559
  if (!panelTab)
2558
- return {
2559
- ok: false,
2560
- reason: `${tabId} does not resolve to a live panel tab (a scope address whose tab has gone away)`,
2561
- };
2560
+ return { ok: false, reason: noPanelTabReason(tabId) };
2562
2561
  const origin = bridge.tabServerOrigin(tabId);
2563
2562
  const identity = workflowIdentityParts({ workflowUuid, origin });
2564
2563
  if (!identity)
2565
2564
  return {
2566
2565
  ok: false,
2567
- reason: !origin
2568
- ? // The relay case, and the one worth naming precisely: this is not
2569
- // transient and no amount of refreshing fixes it.
2570
- `this tab's connection carries no server-observed Origin, and the workflow ` +
2571
- `identity is bound to one — so the fence can never be adopted for it. This is ` +
2572
- `structural, not transient: refreshing the tab will not change it. Relay-backend ` +
2573
- `connections (COMFYUI_MCP_TUNNEL_BACKEND=relay) are the known case, because the ` +
2574
- `relay protocol does not forward the browser's handshake Origin`
2575
- : `the workflow identity did not validate (uuid ${String(workflowUuid)} against ` +
2576
- `origin ${origin}) — a malformed uuid, or one bound to a different origin`,
2566
+ reason: identityReason(tabId, origin, workflowUuid, bridge.resolveFailure?.(tabId)),
2577
2567
  };
2578
2568
  tabCommandWorkflowUuid.set(panelTab, identity.uuid);
2579
2569
  // #716/#884 — an explicit, VALIDATED open/re-pin from the shared agent is