// FED R6 (#1800): the Console's bus-backed options for startServer, built over one transport // `call`. cli.mjs builds them once over the human transport. A granted user's session gets the same // set over its own user transport (bus.mjs userCaller), so no route a user reaches holds a // human-transport object, and the broker decides every verb the user sends (design 3.1 D4). import { createChat } from './chat.mjs'; import { views } from '../../bus/src/views.mjs'; // Row 194 (#1692, D7): the Agents section's verbs. The caller refuses any other, so the server's // agentWrite reaches only these. export const AGENT_VERBS = ['instance.launch', 'instance.regenerate', 'instance.end', 'veto.set', 'instance.request']; // P4 owner transport only; the HTTP boundary and broker both refuse users/testers. export const PROXY_VERBS = Object.freeze(['proxy.accounts', 'proxy.login.start', 'proxy.login.submit', 'proxy.login.status', 'proxy.login.cancel', 'proxy.apikey.add', 'proxy.priority.set', 'proxy.group.models.set', 'proxy.keys', 'plugins', 'plugins.set', // #1873: proxy setup from the page. The broker gates both to the human owner. 'proxy.init', 'proxy.fence.clear']); export const TESTER_AGENT_VERBS = ['instance.launch', 'instance.end', 'instance.request']; // U4b (#1873): the task board's writes, the person's built-in store verbs (broker tasks.*). The // caller refuses any other, so the board's taskWrite never reaches unarchive or delete. export const TASK_WRITE_VERBS = Object.freeze(['tasks.create', 'tasks.edit', 'tasks.archive']); export const agentCaller = (call, verbs) => async (verb, args) => { if (!verbs.includes(verb)) throw new Error(`the Console does not call ${verb}`); return call(verb, args); }; // `send` is the --send flag: without it every write is null. `owner` is the owner's transport for // a granted user's options; it goes to createChat, which sends it only the `plugins` read. // Request workspace reads use the owner console transport, never this shared user transport. export function consoleBus(call, { send: sendOn = false, owner = null } = {}) { // Project remote operations are deliberately absent: this object is also used by granted users. const o = { proxyCall: agentCaller(call, PROXY_VERBS), processing: { read: () => call('processing.status'), halt: args => call('processing.halt', args), resume: args => call('processing.resume', args) }, chat: createChat({ call, owner }), // Row 155 (#1649): `names` is a webui read only, so it sits beside the shared views. Row 165 // (#1662): so is `instances`, and its write `instances.set` is only under --send. Row 65 // (mos-0840): so is `routes`, and its write `routes.set`. // Row 278: this owner/reader read belongs to the Console, not the shared // role views or the tester adapter. The bus decides caller eligibility. bus: { ...views({ call }), names: () => call('names'), instances: () => call('instances'), routes: () => call('routes'), 'thread.claims': () => call('thread.claims') }, // Row 148: the spec and docs editor reads like the other reads and saves only under --send. projectFiles: args => call('project.files', args), projectFile: args => call('project.file', args), libraryFile: args => call('library.file', args), libraryStatus: args => call('library.status', args), send: null, librarySync: null, libraryRevert: null, librarySave: null, settingsWrite: null, projectSave: null, nameWrite: null, assistantStop: null, instancesWrite: null, routesWrite: null, agentWrite: null, taskWrite: null, }; if (sendOn) { o.send = args => call('message.send', args); o.librarySync = args => call('library.sync', args); o.libraryRevert = args => call('library.revert', args); o.settingsWrite = args => call('limits.set', args); o.librarySave = args => call('library.file.save', args); o.projectSave = args => call('project.file.save', args); o.nameWrite = args => call('name.set', args); o.assistantStop = args => call('assistant.stop', args); o.instancesWrite = args => call('instances.set', args); o.routesWrite = args => call('routes.set', args); o.agentWrite = agentCaller(call, AGENT_VERBS); o.taskWrite = agentCaller(call, TASK_WRITE_VERBS); } return o; } // A granted user's options per session: consoleBus over `transport(session.user)`, that user's own // transport, with the owner's transport `owner` passed as it is. Nothing from the session or the // request reaches `owner` (mos-1394, sage-3157): createChat sends it only `plugins` with {}. export function userOptionsFor({ owner, transport, send = false }) { if (typeof owner !== 'function' || typeof transport !== 'function') throw new TypeError('userOptionsFor needs owner and transport functions'); return session => consoleBus(transport(session.user), { send, owner }); }