comfyui-mcp 0.52.43 → 0.52.44
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/index.js +90 -35
- package/dist/orchestrator/index.js.map +1 -1
- package/dist/orchestrator/pair-durability.js +7 -7
- package/dist/orchestrator/pair-durability.js.map +1 -1
- package/dist/orchestrator/pair-update-prefs.js +63 -0
- package/dist/orchestrator/pair-update-prefs.js.map +1 -0
- package/dist/orchestrator/panel-tools.js +265 -12
- package/dist/orchestrator/panel-tools.js.map +1 -1
- package/dist/orchestrator/promoted-widget.js +52 -0
- package/dist/orchestrator/promoted-widget.js.map +1 -1
- package/dist/services/auto-update-gate.js +67 -0
- package/dist/services/auto-update-gate.js.map +1 -0
- package/dist/services/panel-auto-update.js +137 -0
- package/dist/services/panel-auto-update.js.map +1 -0
- package/dist/services/self-restart.js +63 -3
- package/dist/services/self-restart.js.map +1 -1
- package/dist/services/ui-bridge.js +15 -4
- package/dist/services/ui-bridge.js.map +1 -1
- package/package.json +2 -2
|
@@ -30,8 +30,11 @@ import { panelRecoveryContext } from "../services/panel-recovery.js";
|
|
|
30
30
|
import { isPanelAutoInstallDisabled } from "../services/panel-installer.js";
|
|
31
31
|
import { releaseOwnedPanelLock } from "../services/panel-pin-guard.js";
|
|
32
32
|
import { SelfRestarter, canSelfRestart } from "../services/self-restart.js";
|
|
33
|
+
import { tickPanelAutoUpdate } from "../services/panel-auto-update.js";
|
|
33
34
|
import { pairUrlDurability } from "./pair-durability.js";
|
|
34
35
|
import { loadOrCreatePairToken } from "./pair-token-store.js";
|
|
36
|
+
import { autoUpdateApplyAllowed, pairAutoUpdateDisclosure, pairingActiveOf, pairingTransportOf, } from "../services/auto-update-gate.js";
|
|
37
|
+
import { loadPairUpdatePrefs, savePairUpdatePrefs } from "./pair-update-prefs.js";
|
|
35
38
|
import { SessionStore, workflowIdentityParts, carryWorkflowCommandStamp } from "./session-store.js";
|
|
36
39
|
import { unreachableReason, noPanelTabReason, identityReason } from "./fence-refusal.js";
|
|
37
40
|
import { SHARED_SESSION_SCOPE, isScopeAddress, conversationTabs, shouldRetireSharedAgent, messageOrigin, normalizeHelloBackend, workflowOriginNote, } from "../services/session-scope.js";
|
|
@@ -81,7 +84,7 @@ import { PanelAgentManager, fetchSupportedModels, fetchSupportedCommands, isEffo
|
|
|
81
84
|
import { promptText } from "./error-text.js";
|
|
82
85
|
import { callToolAdmission } from "./call-tool-admission.js";
|
|
83
86
|
import { DEFERRED_PANEL_TOOLS_STEERING, withDeferredPanelToolsNote, } from "../deferred-panel-tools.js";
|
|
84
|
-
import { createPanelMcpServer, makePanelToolCtx, resolvePinTarget, secretSavedReply, setApplyMcpReload, RETRY_TOKEN_CMDS, } from "./panel-tools.js";
|
|
87
|
+
import { createPanelMcpServer, makePanelToolCtx, resolvePinTarget, secretSavedReply, setApplyMcpReload, forgetAbandonedConfirmCards, RETRY_TOKEN_CMDS, } from "./panel-tools.js";
|
|
85
88
|
import { optionsAckFrame, optionsErrorAckFrame, optionsRequestMeta, } from "./options-ack.js";
|
|
86
89
|
import { readUserMcpServers } from "../services/user-mcp-config.js";
|
|
87
90
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -1054,20 +1057,25 @@ export async function runPanelOrchestrator() {
|
|
|
1054
1057
|
let pairToken = envPairToken;
|
|
1055
1058
|
let pairListenerStarted = false;
|
|
1056
1059
|
let pairTunnel = null;
|
|
1060
|
+
// Forward declaration — assigned after teardownCore exists. Declared here so
|
|
1061
|
+
// pair / apply_updates_now handlers can refresh the restarter without hitting
|
|
1062
|
+
// the TDZ if a frame arrives before that assignment.
|
|
1063
|
+
let selfRestarter = null;
|
|
1057
1064
|
/**
|
|
1058
|
-
* #
|
|
1065
|
+
* #1963 — APPLY gate for auto-update. Checking still runs.
|
|
1059
1066
|
*
|
|
1060
|
-
*
|
|
1061
|
-
*
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1064
|
-
*
|
|
1067
|
+
* pairingActive is STICKY on `pairTunnel` (the handle exists from mint until
|
|
1068
|
+
* process exit). A live-socket test is the hole a locked-screen phone falls
|
|
1069
|
+
* through: the OS has closed the socket, the gate opened, the hostname
|
|
1070
|
+
* rotated. The pair-time toggle (default ON) is how a desk session applies
|
|
1071
|
+
* anyway; apply_updates_now is the one-shot override.
|
|
1065
1072
|
*/
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1073
|
+
const autoUpdateGateInput = () => ({
|
|
1074
|
+
activeTransport: pairingTransportOf(pairTunnel),
|
|
1075
|
+
pairingActive: pairingActiveOf(pairTunnel),
|
|
1076
|
+
deferWhilePaired: loadPairUpdatePrefs().deferWhilePaired,
|
|
1077
|
+
});
|
|
1078
|
+
const applyAutoUpdateAllowed = () => autoUpdateApplyAllowed(autoUpdateGateInput());
|
|
1071
1079
|
// #875 — the token is PERSISTED, not per-session. It used to be minted fresh on
|
|
1072
1080
|
// every run, so a self-restart (on by default, hourly npm check) invalidated the
|
|
1073
1081
|
// URL the phone had saved. The reporter experienced that as "updating the npm
|
|
@@ -2608,7 +2616,14 @@ export async function runPanelOrchestrator() {
|
|
|
2608
2616
|
// newcomer never asked the previous occupant's questions, so its answers must
|
|
2609
2617
|
// stop being recoverable and stop being pushed. closeAsks downgrades and
|
|
2610
2618
|
// unsends; it never deletes, so those answers are still reported.
|
|
2611
|
-
|
|
2619
|
+
// panel#1554 — same boundary, same reason: a confirmation card the previous
|
|
2620
|
+
// occupant abandoned must not be claimable by the newcomer. Both retirements ride
|
|
2621
|
+
// THIS one listener because the bridge takes a single takeover listener, so a
|
|
2622
|
+
// second setTabTakenOverListener call would silently replace the first.
|
|
2623
|
+
bridge.setTabTakenOverListener((tabId) => {
|
|
2624
|
+
AskAnswers.closeAsks(tabId);
|
|
2625
|
+
forgetAbandonedConfirmCards(tabId);
|
|
2626
|
+
});
|
|
2612
2627
|
bridge.setTabGoneListener((tabId, incarnation) => AskAnswers.retireDebt(tabId, incarnation));
|
|
2613
2628
|
// #694 — the bridge retains a late mutation only for commands that can come
|
|
2614
2629
|
// back as a retry token, which is the retry-token layer's own set. Installed
|
|
@@ -4554,6 +4569,18 @@ export async function runPanelOrchestrator() {
|
|
|
4554
4569
|
if (event.type === "pair" && event.tab_id) {
|
|
4555
4570
|
const mode = event.mode === "tunnel" ? "tunnel" : "lan";
|
|
4556
4571
|
const tabId = event.tab_id;
|
|
4572
|
+
// Pair-time toggle, default ON. An explicit boolean is the only thing we
|
|
4573
|
+
// persist — a missing field leaves the last saved (or default) value.
|
|
4574
|
+
const rawDefer = event.defer_while_paired;
|
|
4575
|
+
if (typeof rawDefer === "boolean") {
|
|
4576
|
+
try {
|
|
4577
|
+
savePairUpdatePrefs({ deferWhilePaired: rawDefer });
|
|
4578
|
+
}
|
|
4579
|
+
catch (err) {
|
|
4580
|
+
logger.warn(`[panel-orchestrator] could not persist pair-update prefs: ${err instanceof Error ? err.message : String(err)}`);
|
|
4581
|
+
}
|
|
4582
|
+
selfRestarter?.requestApplyPolicyRefresh();
|
|
4583
|
+
}
|
|
4557
4584
|
void (async () => {
|
|
4558
4585
|
const token = await ensurePairListener();
|
|
4559
4586
|
let url;
|
|
@@ -4598,12 +4625,55 @@ export async function runPanelOrchestrator() {
|
|
|
4598
4625
|
(durability.survivesRestart
|
|
4599
4626
|
? "survives restart"
|
|
4600
4627
|
: `rotates on restart: ${durability.rotates.join(", ")}`));
|
|
4601
|
-
|
|
4628
|
+
const auto_update = pairAutoUpdateDisclosure(autoUpdateGateInput());
|
|
4629
|
+
bridge.push({ type: "pair_url", mode, url, durability, auto_update }, tabId);
|
|
4602
4630
|
})().catch((err) => {
|
|
4603
4631
|
bridge.push({ type: "pair_error", mode, error: err instanceof Error ? err.message : String(err) }, tabId);
|
|
4604
4632
|
});
|
|
4605
4633
|
return;
|
|
4606
4634
|
}
|
|
4635
|
+
// #1963 — flip the pair-time "Don't update while my phone is paired" toggle
|
|
4636
|
+
// after the URL is already minted (the checkbox on the QR modal).
|
|
4637
|
+
if (event.type === "set_pair_update_pref" && event.tab_id) {
|
|
4638
|
+
const tabId = event.tab_id;
|
|
4639
|
+
const rawDefer = event.defer_while_paired;
|
|
4640
|
+
if (typeof rawDefer !== "boolean") {
|
|
4641
|
+
bridge.push({ type: "pair_update_pref", ok: false, error: "defer_while_paired must be a boolean" }, tabId);
|
|
4642
|
+
return;
|
|
4643
|
+
}
|
|
4644
|
+
try {
|
|
4645
|
+
const prefs = savePairUpdatePrefs({ deferWhilePaired: rawDefer });
|
|
4646
|
+
bridge.push({
|
|
4647
|
+
type: "pair_update_pref",
|
|
4648
|
+
ok: true,
|
|
4649
|
+
defer_while_paired: prefs.deferWhilePaired,
|
|
4650
|
+
apply: autoUpdateApplyAllowed({
|
|
4651
|
+
...autoUpdateGateInput(),
|
|
4652
|
+
deferWhilePaired: prefs.deferWhilePaired,
|
|
4653
|
+
}),
|
|
4654
|
+
}, tabId);
|
|
4655
|
+
selfRestarter?.requestApplyPolicyRefresh();
|
|
4656
|
+
}
|
|
4657
|
+
catch (err) {
|
|
4658
|
+
bridge.push({
|
|
4659
|
+
type: "pair_update_pref",
|
|
4660
|
+
ok: false,
|
|
4661
|
+
error: err instanceof Error ? err.message : String(err),
|
|
4662
|
+
}, tabId);
|
|
4663
|
+
}
|
|
4664
|
+
return;
|
|
4665
|
+
}
|
|
4666
|
+
// #1963 — "Update now" from the desk (or from the deferred-update notice).
|
|
4667
|
+
// One-shot: ignores the tunnel gate for this tick only.
|
|
4668
|
+
if (event.type === "apply_updates_now") {
|
|
4669
|
+
const tabId = event.tab_id;
|
|
4670
|
+
logger.info("[panel-orchestrator] apply_updates_now — checking and applying updates (bypass tunnel gate)");
|
|
4671
|
+
void selfRestarter?.updateTick({ forceApply: true });
|
|
4672
|
+
if (tabId) {
|
|
4673
|
+
bridge.push({ type: "ack", ok: true, kind: "apply_updates_now" }, tabId);
|
|
4674
|
+
}
|
|
4675
|
+
return;
|
|
4676
|
+
}
|
|
4607
4677
|
// Direct tool channel: the mobile app invokes a WHITELISTED read/download tool
|
|
4608
4678
|
// (structured data for nav lists + rig downloads) without an agent turn. Replies
|
|
4609
4679
|
// with a `tool_result` frame the client correlates by rid.
|
|
@@ -6223,9 +6293,6 @@ export async function runPanelOrchestrator() {
|
|
|
6223
6293
|
: " — remote target: installs/downloads run ON the ComfyUI host via its Manager (a local path would be the wrong filesystem; only local-FS tools like node_pack (action:'verify') are unavailable)";
|
|
6224
6294
|
logger.info(`[panel-orchestrator] ready — bridge on ws://127.0.0.1:${bridgePort}, console on ${consoleUrl}; an agent spawns per ComfyUI tab on its first message (model=${model}, comfyui=${comfyuiUrl}${pathNote})`);
|
|
6225
6295
|
let shuttingDown = false;
|
|
6226
|
-
// Forward declaration — assigned right after teardownCore exists; teardownCore
|
|
6227
|
-
// stops its timers so no update-check tick can fire mid-teardown.
|
|
6228
|
-
let selfRestarter = null;
|
|
6229
6296
|
/** Everything shutdown does EXCEPT exiting — shared with the self-restarter,
|
|
6230
6297
|
* which spawns its replacement first and exits itself after this settles. */
|
|
6231
6298
|
const teardownCore = async () => {
|
|
@@ -6352,24 +6419,12 @@ export async function runPanelOrchestrator() {
|
|
|
6352
6419
|
// …and the same for an ask answer the user actually gave that has not
|
|
6353
6420
|
// reached the agent yet (#486). Restarting would destroy it silently.
|
|
6354
6421
|
!AskAnswers.hasOutstanding() &&
|
|
6355
|
-
!QueueMonitor.isBusy()
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
// an update nobody asked for at that moment — which is what the reporter
|
|
6362
|
-
// experienced and (reasonably) blamed on the npm version.
|
|
6363
|
-
//
|
|
6364
|
-
// Deferral, not cancellation: the update check still runs and the restart
|
|
6365
|
-
// stays armed, so it fires as soon as the tunnel goes away. The cost is
|
|
6366
|
-
// that a tunnel left up indefinitely postpones updates indefinitely, so it
|
|
6367
|
-
// is DISCLOSED — in pair-durability's tunnel note, which the panel shows at
|
|
6368
|
-
// pair time. Deliberately not announced from here: this is a predicate the
|
|
6369
|
-
// restarter polls, and emitting from it would either fire repeatedly or
|
|
6370
|
-
// need its own state to suppress itself. Pair time is also where the user
|
|
6371
|
-
// is actually looking (#1077: an orchestrator log may be unreachable).
|
|
6372
|
-
!tunnelPairingLive(),
|
|
6422
|
+
!QueueMonitor.isBusy(),
|
|
6423
|
+
// #1963 — transport gate is applyAllowed, not allIdle. Idle is in-flight
|
|
6424
|
+
// work; this is "would a restart rotate the phone's tunnel hostname?"
|
|
6425
|
+
// Checking still runs; APPLY (disk + restart, and the panel pack) does not.
|
|
6426
|
+
applyAllowed: applyAutoUpdateAllowed,
|
|
6427
|
+
panelTick: async ({ apply }) => tickPanelAutoUpdate({ apply }),
|
|
6373
6428
|
announce: (text) => void bridge.push({ type: "say", text }),
|
|
6374
6429
|
teardown: teardownCore,
|
|
6375
6430
|
});
|