lib/mcp-settings-navigation.js
Rama main · réplica de lectura del repositorio original.
var crypto = require('crypto');
function createSettingsNavigation(ctx) {
var pending = new Map(), closed = false;
function open(owner, ws, screen, id, session, authorize, signal) {
authorize();
if (closed || pending.size >= 100) throw new Error('MCP settings navigation is unavailable.');
return new Promise(function (resolve, reject) {
var requestId = 'mcp-settings-' + crypto.randomUUID(), timer;
function finish(error, value) {
if (!pending.has(requestId)) return;
pending.delete(requestId); clearTimeout(timer); signal.removeEventListener('abort', stopped);
if (error) reject(error); else resolve(value);
}
function stopped() { finish(new Error('MCP settings request stopped. It may already have reached the interface; inspect before retrying.')); }
pending.set(requestId, { ws: ws, owner: owner, session: session, authorize: authorize, finish: finish });
timer = setTimeout(function () { finish(null, { status: 'delivered', acknowledged: false, message: 'Request sent to the owner interface; client acceptance and visible rendering are unconfirmed. Open MCP / Skills in the source project to continue.' }); }, 5000);
signal.addEventListener('abort', stopped, { once: true });
try {
authorize(); if (signal.aborted) return stopped();
ctx.sendTo(ws, { type: 'mcp_settings_request', requestId: requestId, slug: ctx.slug, sessionId: session.localId, screen: screen, connectionId: id || null });
} catch (error) { finish(error); }
});
}
function handle(ws, msg) {
if (msg.type !== 'mcp_settings_result') return false;
var entry = pending.get(msg.requestId);
if (!entry || entry.ws !== ws || msg.slug !== ctx.slug || msg.sessionId !== entry.session.localId) return true;
try { entry.authorize(); entry.finish(null, { status: msg.accepted === true ? 'client_accepted' : 'client_refused', acknowledged: true, rendered: 'unconfirmed', message: msg.accepted === true ? 'Client accepted the settings request. Secret entry and saving remain human actions.' : 'The interface context changed or the connection is not loaded. Open MCP / Skills in the source conversation.' }); }
catch (error) { entry.finish(error); }
return true;
}
return { open: open, handle: handle, destroy: function () { closed = true; pending.forEach(function (entry) { entry.finish(new Error('MCP settings navigation closed.')); }); pending.clear(); } };
}
module.exports = { createSettingsNavigation: createSettingsNavigation };