dominus-cli 2.4.0 → 2.4.1

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config/config.ts","../src/transport/protocol.ts","../src/transport/auth.ts","../src/transport/ws-client.ts","../src/transport/daemon-launcher.ts","../src/install-plugin.ts"],"names":["path","os","fs","fileURLToPath"],"mappings":"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","file":"install-plugin.js","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport type { ConfigAccess } from '../tools/types.js';\n\nconst DOMINUS_DIR = path.join(os.homedir(), '.dominus');\nconst CONFIG_PATH = path.join(DOMINUS_DIR, 'config.json');\nconst DB_PATH = path.join(DOMINUS_DIR, 'dominus.db');\nconst RULES_PATH = path.join(DOMINUS_DIR, 'rules.json');\n\nexport type AIProviderType =\n | 'openai'\n | 'anthropic'\n | 'gemini'\n | 'xai'\n | 'openrouter'\n | 'custom';\n\nexport interface ProviderConfig {\n name: string;\n baseUrl: string;\n envVar: string;\n defaultModel: string;\n}\n\nexport const PROVIDERS: Record<AIProviderType, ProviderConfig> = {\n openai: {\n name: 'OpenAI',\n baseUrl: 'https://api.openai.com/v1',\n envVar: 'OPENAI_API_KEY',\n defaultModel: 'gpt-5.3-codex',\n },\n anthropic: {\n name: 'Anthropic',\n baseUrl: 'https://api.anthropic.com/v1/',\n envVar: 'ANTHROPIC_API_KEY',\n defaultModel: 'claude-sonnet-4-6',\n },\n gemini: {\n name: 'Google Gemini',\n baseUrl: 'https://generativelanguage.googleapis.com/v1beta/openai',\n envVar: 'GEMINI_API_KEY',\n defaultModel: 'gemini-3.1-pro',\n },\n xai: {\n name: 'xAI (Grok)',\n baseUrl: 'https://api.x.ai/v1',\n envVar: 'XAI_API_KEY',\n defaultModel: 'grok-4.2',\n },\n openrouter: {\n name: 'OpenRouter',\n baseUrl: 'https://openrouter.ai/api/v1',\n envVar: 'OPENROUTER_API_KEY',\n defaultModel: 'anthropic/claude-sonnet-4-6',\n },\n custom: {\n name: 'Custom',\n baseUrl: '',\n envVar: '',\n defaultModel: '',\n },\n};\n\nexport interface DominusConfig {\n provider: AIProviderType;\n apiKey?: string;\n apiBaseUrl: string;\n model: string;\n port: number;\n maxToolIterations: number;\n maxVerifyRetries: number;\n tokenBudget: number;\n autoIndex: boolean;\n autoLearn: boolean;\n userName: string;\n openCloudApiKey?: string;\n}\n\nconst DEFAULTS: DominusConfig = {\n provider: 'openai',\n apiBaseUrl: '',\n model: '',\n port: 18088,\n maxToolIterations: 25,\n maxVerifyRetries: 3,\n tokenBudget: 128000,\n autoIndex: true,\n autoLearn: true,\n userName: 'Developer',\n};\n\n/**\n * Auto-detect provider from environment variables.\n * Returns the first provider whose env var is set, or null.\n */\nexport function detectProviderFromEnv(): { provider: AIProviderType; apiKey: string } | null {\n const priority: AIProviderType[] = ['openai', 'anthropic', 'gemini', 'xai', 'openrouter'];\n for (const p of priority) {\n const key = process.env[PROVIDERS[p].envVar];\n if (key) return { provider: p, apiKey: key };\n }\n return null;\n}\n\n/**\n * Resolve the effective base URL and model for a provider config.\n */\nexport function resolveProviderSettings(config: DominusConfig): {\n baseUrl: string;\n model: string;\n} {\n const providerInfo = PROVIDERS[config.provider];\n return {\n baseUrl: config.apiBaseUrl || providerInfo?.baseUrl || PROVIDERS.openrouter.baseUrl,\n model: config.model || providerInfo?.defaultModel || 'gpt-4o',\n };\n}\n\nexport interface DominusRules {\n do: string[];\n dont: string[];\n conventions: string[];\n context: string;\n}\n\nconst DEFAULT_RULES: DominusRules = {\n do: [],\n dont: [],\n conventions: [],\n context: '',\n};\n\nfunction ensureDir(): void {\n if (!fs.existsSync(DOMINUS_DIR)) {\n fs.mkdirSync(DOMINUS_DIR, { recursive: true });\n }\n}\n\nfunction readJson<T>(filePath: string, defaults: T): T {\n try {\n if (fs.existsSync(filePath)) {\n const raw = fs.readFileSync(filePath, 'utf-8');\n return { ...defaults, ...JSON.parse(raw) };\n }\n } catch {\n // Corrupted file; reset to defaults\n }\n return { ...defaults };\n}\n\nfunction writeJson(filePath: string, data: unknown): void {\n ensureDir();\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\nexport function loadConfig(): DominusConfig {\n ensureDir();\n return readJson(CONFIG_PATH, DEFAULTS);\n}\n\nexport function saveConfig(config: DominusConfig): void {\n writeJson(CONFIG_PATH, config);\n}\n\nexport function getConfigValue<K extends keyof DominusConfig>(key: K): DominusConfig[K] {\n const config = loadConfig();\n return config[key];\n}\n\nexport function setConfigValue<K extends keyof DominusConfig>(\n key: K,\n value: DominusConfig[K],\n): void {\n const config = loadConfig();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (config as any)[key] = value;\n saveConfig(config);\n}\n\nexport function loadRules(): DominusRules {\n ensureDir();\n return readJson(RULES_PATH, DEFAULT_RULES);\n}\n\nexport function saveRules(rules: DominusRules): void {\n writeJson(RULES_PATH, rules);\n}\n\nexport function getDominusDir(): string {\n ensureDir();\n return DOMINUS_DIR;\n}\n\nexport function getDbPath(): string {\n ensureDir();\n return DB_PATH;\n}\n\nexport function createConfigAccess(): ConfigAccess {\n return {\n get<T>(key: string): T | undefined {\n const config = loadConfig() as unknown as Record<string, unknown>;\n return config[key] as T | undefined;\n },\n set(key: string, value: unknown): void {\n const config = loadConfig() as unknown as Record<string, unknown>;\n config[key] = value;\n saveConfig(config as unknown as DominusConfig);\n },\n getAll(): Record<string, unknown> {\n return loadConfig() as unknown as Record<string, unknown>;\n },\n };\n}\n","import { nanoid } from 'nanoid';\nimport { z } from 'zod';\n\nexport const DOMINUS_PROTOCOL_VERSION = 2;\nexport const MAX_MESSAGE_BYTES = 1024 * 1024;\n\nexport interface WsMessage<T = unknown> {\n id: string;\n type: string;\n payload: T;\n ts: number;\n}\n\nexport const StudioMsg = {\n HELLO: 'studio:hello',\n CONNECTED: 'studio:connected',\n DISCONNECTED: 'studio:disconnected',\n EXPLORER: 'studio:explorer',\n OUTPUT: 'studio:output',\n ERROR: 'studio:error',\n SELECTION: 'studio:selection',\n SCRIPT_CONTENT: 'studio:script:content',\n SCRIPT_CHANGED: 'studio:script:changed',\n RESPONSE: 'studio:response',\n REFLECTION: 'studio:reflection',\n TEST_RESULTS: 'studio:test:results',\n AUTHENTICATED: 'server:authenticated',\n AUTH_REJECTED: 'server:auth_rejected',\n} as const;\n\nexport const ControllerMsg = {\n HELLO: 'controller:hello',\n WELCOME: 'controller:welcome',\n RELAY: 'controller:relay',\n TARGET_STATE: 'controller:target_state',\n SET_ACTIVE_CONNECTION: 'controller:set_active_connection',\n} as const;\n\nexport const CliMsg = {\n GET_EXPLORER: 'cli:get:explorer',\n GET_SCRIPT: 'cli:get:script',\n SET_SCRIPT: 'cli:set:script',\n RUN_CODE: 'cli:run',\n GET_PROPERTIES: 'cli:get:properties',\n GET_DESCENDANTS_PROPERTIES: 'cli:get:descendants:properties',\n SET_PROPERTIES: 'cli:set:properties',\n INSERT_INSTANCE: 'cli:insert',\n DELETE_INSTANCE: 'cli:delete',\n GET_SELECTION: 'cli:get:selection',\n SELECT: 'cli:select',\n SEARCH_SCRIPTS: 'cli:search:scripts',\n GET_OUTPUT: 'cli:get:output',\n RUN_TESTS: 'cli:run:tests',\n EXECUTE_RUN_TEST: 'cli:test:run',\n EXECUTE_PLAY_TEST: 'cli:test:play',\n END_TEST: 'cli:test:end',\n BUILD_UI: 'cli:build:ui',\n GET_REFLECTION: 'cli:get:reflection',\n UPLOAD_ASSET: 'cli:upload:asset',\n SERIALIZE_UI: 'cli:serialize:ui',\n MOVE_INSTANCE: 'cli:move:instance',\n UNDO: 'cli:undo',\n REDO: 'cli:redo',\n BULK_SET_PROPERTIES: 'cli:bulk:set:properties',\n FIND_REPLACE_SCRIPTS: 'cli:find:replace:scripts',\n V2_GET_TREE: 'studio:v2:get_tree',\n V2_INSPECT: 'studio:v2:inspect',\n V2_GET_SELECTION: 'studio:v2:get_selection',\n V2_READ_SCRIPT: 'studio:v2:read_script',\n V2_UPDATE_SCRIPT: 'studio:v2:update_script',\n V2_APPLY: 'studio:v2:apply',\n V2_CREATE_PARTS: 'studio:v2:create_parts',\n V2_CLONE_INSTANCES: 'studio:v2:clone_instances',\n V2_GROUP_INSTANCES: 'studio:v2:group_instances',\n V2_UNGROUP_INSTANCES: 'studio:v2:ungroup_instances',\n V2_TRANSFORM_INSTANCES: 'studio:v2:transform_instances',\n V2_CREATE_WELDS: 'studio:v2:create_welds',\n V2_QUERY_PARTS: 'studio:v2:query_parts',\n V2_SET_SELECTION: 'studio:v2:set_selection',\n V2_GET_METADATA: 'studio:v2:get_metadata',\n V2_SET_ATTRIBUTES: 'studio:v2:set_attributes',\n V2_UPDATE_TAGS: 'studio:v2:update_tags',\n V2_LIST_CALLABLE_METHODS: 'studio:v2:list_callable_methods',\n V2_INVOKE_METHODS: 'studio:v2:invoke_methods',\n V2_DELETE: 'studio:v2:delete',\n V2_BUILD_UI: 'studio:v2:build_ui',\n V2_SNAPSHOT_UI: 'studio:v2:snapshot_ui',\n V2_RUN_TEST: 'studio:v2:run_test',\n V2_GET_OUTPUT: 'studio:v2:get_output',\n V2_GET_REFLECTION: 'studio:v2:get_reflection',\n} as const;\n\nexport type StudioMsgType = (typeof StudioMsg)[keyof typeof StudioMsg];\nexport type CliMsgType = (typeof CliMsg)[keyof typeof CliMsg];\n\nexport interface ExplorerNode {\n name: string;\n className: string;\n path: string;\n ref?: InstanceRef;\n children?: ExplorerNode[];\n}\n\nexport interface InstanceRef {\n instanceId?: string;\n pathSegments?: string[];\n}\n\nexport interface StudioConnectedPayload {\n studioVersion: string;\n protocolVersion?: number;\n clientId?: string;\n token?: string;\n connectionId?: string;\n placeId?: number;\n placeName?: string;\n engineVersion?: string;\n}\n\nexport interface ScriptContentPayload {\n path: string;\n className: 'Script' | 'LocalScript' | 'ModuleScript';\n source: string;\n lineCount: number;\n}\n\nexport interface ScriptChangedPayload {\n path: string;\n source: string;\n}\n\nexport interface OutputPayload {\n message: string;\n level: 'info' | 'warn' | 'error';\n timestamp: number;\n source?: string;\n}\n\nexport interface SelectionPayload {\n paths: string[];\n classNames: string[];\n}\n\nexport interface PropertyEntry {\n name: string;\n value: string;\n type: string;\n category?: string;\n}\n\nexport interface TestResultPayload {\n name: string;\n passed: boolean;\n duration: number;\n error?: string;\n}\n\nexport interface StudioTestPayload {\n args?: unknown;\n}\n\nexport interface StudioTestResultPayload {\n success: boolean;\n result?: unknown;\n error?: string;\n duration?: number;\n}\n\nexport interface ReflectionPayload {\n className: string;\n properties: { name: string; type: string; category: string }[];\n methods: { name: string; parameters: string[] }[];\n events: { name: string; parameters: string[] }[];\n}\n\nexport interface RunCodePayload {\n code: string;\n}\n\nexport interface RunCodeResponsePayload {\n output: string;\n error?: string;\n duration: number;\n}\n\nexport interface SearchScriptsPayload {\n query: string;\n maxResults?: number;\n}\n\nexport interface SearchResultPayload {\n results: {\n path: string;\n className: string;\n matches: { line: number; text: string }[];\n }[];\n}\n\nexport interface InsertInstancePayload {\n className: string;\n parentPath: string;\n name: string;\n properties?: Record<string, unknown>;\n}\n\nexport interface SetPropertiesPayload {\n path: string;\n properties: Record<string, unknown>;\n}\n\nexport function createMessage<T>(type: string, payload: T): WsMessage<T> {\n return { id: nanoid(), type, payload, ts: Date.now() };\n}\n\nexport function createRequest<T>(type: string, payload: T): WsMessage<T> {\n return createMessage(type, payload);\n}\n\nexport function parseMessage(raw: string): WsMessage {\n if (Buffer.byteLength(raw, 'utf8') > MAX_MESSAGE_BYTES) {\n throw new Error(`WebSocket message exceeds ${MAX_MESSAGE_BYTES} bytes`);\n }\n try {\n const parsed = JSON.parse(raw) as unknown;\n return wsMessageSchema.parse(parsed) as WsMessage;\n } catch {\n throw new Error(`Failed to parse WebSocket message: ${raw.slice(0, 100)}`);\n }\n}\n\nexport function serializeMessage(msg: WsMessage): string {\n const serialized = JSON.stringify(msg);\n if (Buffer.byteLength(serialized, 'utf8') > MAX_MESSAGE_BYTES) {\n throw new Error(`WebSocket message exceeds ${MAX_MESSAGE_BYTES} bytes`);\n }\n return serialized;\n}\n\nconst wsMessageSchema = z\n .object({\n id: z.string().min(1).max(128),\n type: z.string().min(1).max(128),\n payload: z.unknown(),\n ts: z.number().finite(),\n })\n .strict();\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport * as crypto from 'node:crypto';\nimport { getDominusDir } from '../config/config.js';\n\nconst TOKEN_FILE = 'bridge-token';\n\nexport function loadOrCreateBridgeToken(): string {\n const tokenPath = path.join(getDominusDir(), TOKEN_FILE);\n try {\n const existing = fs.readFileSync(tokenPath, 'utf8').trim();\n if (existing.length >= 32) return existing;\n } catch {\n // First run or an unreadable token is repaired below.\n }\n\n const token = crypto.randomBytes(32).toString('base64url');\n fs.writeFileSync(tokenPath, `${token}\\n`, { encoding: 'utf8', mode: 0o600 });\n try {\n fs.chmodSync(tokenPath, 0o600);\n } catch {\n // Windows ACLs do not map directly to POSIX modes.\n }\n return token;\n}\n\nexport function tokensEqual(actual: unknown, expected: string): boolean {\n if (typeof actual !== 'string') return false;\n const actualBuffer = Buffer.from(actual);\n const expectedBuffer = Buffer.from(expected);\n return (\n actualBuffer.length === expectedBuffer.length &&\n crypto.timingSafeEqual(actualBuffer, expectedBuffer)\n );\n}\n","import { EventEmitter } from 'node:events';\nimport { WebSocket } from 'ws';\nimport {\n ControllerMsg,\n DOMINUS_PROTOCOL_VERSION,\n StudioMsg,\n createMessage,\n parseMessage,\n serializeMessage,\n type WsMessage,\n} from './protocol.js';\nimport { loadOrCreateBridgeToken } from './auth.js';\nimport type { PlaceInfo, StudioBridge, StudioConnection } from './ws-server.js';\n\ninterface ClientOptions {\n token?: string;\n connectTimeoutMs?: number;\n}\n\ninterface ControlResult {\n success?: boolean;\n error?: string;\n [key: string]: unknown;\n}\n\nexport class DominusClient extends EventEmitter implements StudioBridge {\n private ws: WebSocket | null = null;\n private readonly port: number;\n private readonly token: string;\n private readonly connectTimeoutMs: number;\n private readonly connections = new Map<string, Omit<StudioConnection, 'ws'>>();\n private activeConnectionId: string | null = null;\n private readonly pendingRequests = new Map<\n string,\n {\n resolve: (msg: WsMessage) => void;\n reject: (err: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n }\n >();\n\n constructor(port = 18088, options: ClientOptions = {}) {\n super();\n this.port = port;\n this.token = options.token ?? loadOrCreateBridgeToken();\n this.connectTimeoutMs = options.connectTimeoutMs ?? 8_000;\n }\n\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(`ws://127.0.0.1:${this.port}`, {\n perMessageDeflate: false,\n maxPayload: 1024 * 1024,\n });\n let settled = false;\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true;\n ws.close(1008, 'Dominus controller handshake timed out');\n reject(new Error('Timed out authenticating with the Dominus bridge'));\n }\n }, this.connectTimeoutMs);\n\n ws.on('open', () => {\n this.ws = ws;\n ws.send(\n serializeMessage(\n createMessage(ControllerMsg.HELLO, {\n protocolVersion: DOMINUS_PROTOCOL_VERSION,\n token: this.token,\n }),\n ),\n );\n });\n\n ws.on('message', (raw) => {\n try {\n const msg = parseMessage(raw.toString());\n if (msg.type === ControllerMsg.WELCOME && !settled) {\n settled = true;\n clearTimeout(timer);\n this.applyWelcome(msg.payload);\n this.emit('server:started', { port: this.port, relay: true });\n resolve();\n return;\n }\n if (msg.type === StudioMsg.AUTH_REJECTED && !settled) {\n settled = true;\n clearTimeout(timer);\n const payload = msg.payload as { error?: string };\n reject(new Error(payload.error ?? 'Dominus controller authentication failed'));\n ws.close(1008, 'Controller authentication failed');\n return;\n }\n this.handleMessage(msg);\n } catch (err) {\n this.emit('server:error', err);\n }\n });\n\n ws.on('close', () => {\n clearTimeout(timer);\n this.ws = null;\n this.connections.clear();\n this.activeConnectionId = null;\n if (!settled) {\n settled = true;\n reject(new Error('Dominus bridge closed before authentication completed'));\n }\n this.rejectPending(new Error('Dominus relay connection lost'));\n this.emit('studio:disconnected');\n });\n\n ws.on('error', (err) => {\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n reject(err);\n }\n this.emit('server:error', err);\n });\n });\n }\n\n private applyWelcome(payload: unknown): void {\n const welcome = payload as {\n connections?: PlaceInfo[];\n activeConnectionId?: string | null;\n };\n this.replaceConnections(welcome.connections ?? []);\n this.activeConnectionId = welcome.activeConnectionId ?? null;\n if (!this.resolveTargetInfo() && this.connections.size === 1) {\n this.activeConnectionId = this.connections.keys().next().value ?? null;\n }\n }\n\n private handleMessage(msg: WsMessage): void {\n if (msg.type === ControllerMsg.TARGET_STATE) {\n const payload = msg.payload as {\n connections?: PlaceInfo[];\n defaultActiveConnectionId?: string | null;\n };\n this.replaceConnections(payload.connections ?? []);\n if (this.activeConnectionId && !this.connections.has(this.activeConnectionId)) {\n this.activeConnectionId = null;\n }\n if (!this.activeConnectionId && this.connections.size === 1) {\n this.activeConnectionId = this.connections.keys().next().value ?? null;\n }\n this.emit('controller:target_state', payload);\n return;\n }\n\n if (msg.type === StudioMsg.CONNECTED) {\n const connection = msg.payload as PlaceInfo;\n this.connections.set(connection.connectionId, toConnectionInfo(connection));\n if (!this.activeConnectionId && this.connections.size === 1) {\n this.activeConnectionId = connection.connectionId;\n }\n this.emit('studio:connected', connection);\n return;\n }\n\n if (msg.type === StudioMsg.DISCONNECTED) {\n const payload = msg.payload as { connectionId?: string };\n if (payload.connectionId) this.connections.delete(payload.connectionId);\n if (this.activeConnectionId === payload.connectionId) this.activeConnectionId = null;\n if (!this.activeConnectionId && this.connections.size === 1) {\n this.activeConnectionId = this.connections.keys().next().value ?? null;\n }\n this.emit('studio:disconnected', payload);\n return;\n }\n\n if (msg.type === StudioMsg.RESPONSE) {\n const pending = this.pendingRequests.get(msg.id);\n if (pending) {\n clearTimeout(pending.timer);\n this.pendingRequests.delete(msg.id);\n pending.resolve(msg);\n }\n return;\n }\n\n this.emit(msg.type, msg.payload);\n this.emit('message', msg);\n }\n\n private replaceConnections(connections: PlaceInfo[]): void {\n this.connections.clear();\n for (const connection of connections) {\n this.connections.set(connection.connectionId, toConnectionInfo(connection));\n }\n }\n\n private sendMessage(message: WsMessage): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n throw new Error('Not connected to the Dominus bridge');\n }\n this.ws.send(serializeMessage(message));\n }\n\n private waitForResponse<T = unknown>(\n message: WsMessage,\n timeoutMs: number,\n ): Promise<WsMessage<T>> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pendingRequests.delete(message.id);\n reject(new Error(`Dominus request timed out: ${message.type}`));\n }, timeoutMs);\n this.pendingRequests.set(message.id, {\n resolve: resolve as (msg: WsMessage) => void,\n reject,\n timer,\n });\n try {\n this.sendMessage(message);\n } catch (err) {\n clearTimeout(timer);\n this.pendingRequests.delete(message.id);\n reject(err);\n }\n });\n }\n\n private async sendControlRequest<T extends ControlResult>(\n type: string,\n payload: unknown,\n timeoutMs = 10_000,\n ): Promise<T> {\n const response = await this.waitForResponse<T>(createMessage(type, payload), timeoutMs);\n const result = response.payload;\n if (result.error || result.success === false) throw new Error(result.error ?? `${type} failed`);\n return result;\n }\n\n sendRequest<T = unknown>(\n type: string,\n payload: unknown,\n timeoutMs = 15_000,\n ): Promise<WsMessage<T>> {\n const target = this.resolveTargetInfo();\n if (!target || !this.activeConnectionId) {\n return Promise.reject(\n new Error(\n this.connections.size > 1\n ? 'Multiple Studio sessions are connected. Call dominus_select_studio first.'\n : 'No authenticated Roblox Studio connection',\n ),\n );\n }\n const request = createMessage(type, payload);\n const relay = createMessage(ControllerMsg.RELAY, {\n connectionId: this.activeConnectionId,\n request,\n });\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pendingRequests.delete(request.id);\n reject(new Error(`Studio request timed out: ${type}`));\n }, timeoutMs);\n this.pendingRequests.set(request.id, {\n resolve: resolve as (msg: WsMessage) => void,\n reject,\n timer,\n });\n try {\n this.sendMessage(relay);\n } catch (err) {\n clearTimeout(timer);\n this.pendingRequests.delete(request.id);\n reject(err);\n }\n });\n }\n\n sendNotification(type: string, payload: unknown): void {\n if (!this.activeConnectionId) return;\n const request = createMessage(type, payload);\n this.sendMessage(\n createMessage(ControllerMsg.RELAY, {\n connectionId: this.activeConnectionId,\n request,\n }),\n );\n }\n\n isConnected(): boolean {\n return this.resolveTargetInfo() !== null;\n }\n\n getConnectionInfo(): StudioConnection | null {\n const target = this.resolveTargetInfo();\n if (!target || !this.ws) return null;\n return { ...target, ws: this.ws };\n }\n\n listConnections(): PlaceInfo[] {\n return [...this.connections.values()].map((connection) => ({\n placeId: connection.placeId ?? 0,\n connectionId: connection.connectionId,\n clientId: connection.clientId,\n placeName: connection.placeName,\n studioVersion: connection.studioVersion,\n connectedAt: connection.connectedAt,\n active: connection.connectionId === this.activeConnectionId,\n }));\n }\n\n getActiveConnectionId(): string | null {\n return this.activeConnectionId;\n }\n\n async setActiveConnectionId(connectionId: string | null): Promise<void> {\n if (connectionId && !this.connections.has(connectionId)) {\n throw new Error(`Studio connection ${connectionId} is not connected`);\n }\n await this.sendControlRequest(ControllerMsg.SET_ACTIVE_CONNECTION, { connectionId });\n this.activeConnectionId = connectionId;\n }\n\n getActivePlaceId(): number {\n return this.resolveTargetInfo()?.placeId ?? 0;\n }\n\n setActivePlaceId(placeId: number): void {\n if (placeId === 0) {\n void this.setActiveConnectionId(null);\n return;\n }\n const matches = [...this.connections.values()].filter(\n (connection) => connection.placeId === placeId,\n );\n if (matches.length !== 1) {\n throw new Error(\n matches.length === 0\n ? `Place ${placeId} is not connected`\n : `Place ${placeId} has multiple Studio sessions; select a connectionId instead`,\n );\n }\n void this.setActiveConnectionId(matches[0].connectionId);\n }\n\n private resolveTargetInfo(): Omit<StudioConnection, 'ws'> | null {\n if (this.activeConnectionId) return this.connections.get(this.activeConnectionId) ?? null;\n if (this.connections.size === 1) return this.connections.values().next().value ?? null;\n return null;\n }\n\n getPort(): number {\n return this.port;\n }\n\n stop(): Promise<void> {\n this.rejectPending(new Error('Dominus client is shutting down'));\n return new Promise((resolve) => {\n if (!this.ws) {\n resolve();\n return;\n }\n const ws = this.ws;\n this.ws = null;\n ws.once('close', resolve);\n ws.close(1000, 'Dominus client shutdown');\n });\n }\n\n private rejectPending(error: Error): void {\n for (const pending of this.pendingRequests.values()) {\n clearTimeout(pending.timer);\n pending.reject(error);\n }\n this.pendingRequests.clear();\n }\n}\n\nfunction toConnectionInfo(connection: PlaceInfo): Omit<StudioConnection, 'ws'> {\n return {\n connectedAt: connection.connectedAt,\n connectionId: connection.connectionId,\n clientId: connection.clientId,\n studioVersion: connection.studioVersion,\n placeId: connection.placeId,\n placeName: connection.placeName,\n };\n}\n\nexport async function isPortInUse(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const ws = new WebSocket(`ws://127.0.0.1:${port}`);\n const timer = setTimeout(() => {\n ws.close();\n resolve(false);\n }, 750);\n ws.on('open', () => {\n clearTimeout(timer);\n ws.close();\n resolve(true);\n });\n ws.on('error', () => {\n clearTimeout(timer);\n resolve(false);\n });\n });\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { spawn } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport { DominusClient, isPortInUse } from './ws-client.js';\n\nexport interface BridgeLaunchOptions {\n attempts?: number;\n connectTimeoutMs?: number;\n daemonPath?: string;\n launch?: (port: number) => void;\n retryDelayMs?: number;\n token?: string;\n}\n\nfunction resolveDaemonPath(): string {\n const besideEntry = fileURLToPath(new URL('./bridge-daemon.js', import.meta.url));\n if (fs.existsSync(besideEntry)) return besideEntry;\n\n const projectBuild = path.resolve(\n path.dirname(fileURLToPath(import.meta.url)),\n '../../dist/bridge-daemon.js',\n );\n if (fs.existsSync(projectBuild)) return projectBuild;\n\n throw new Error('Dominus bridge daemon is missing. Reinstall or rebuild dominus-cli.');\n}\n\nexport function launchBridgeDaemon(port: number, daemonPath = resolveDaemonPath()): void {\n const child = spawn(process.execPath, [daemonPath], {\n detached: true,\n env: { ...process.env, DOMINUS_BRIDGE_PORT: String(port) },\n stdio: 'ignore',\n windowsHide: true,\n });\n child.unref();\n}\n\nasync function connectController(\n port: number,\n timeoutMs: number,\n token?: string,\n): Promise<DominusClient> {\n const client = new DominusClient(port, { connectTimeoutMs: timeoutMs, token });\n try {\n await client.connect();\n return client;\n } catch (error) {\n await client.stop().catch(() => undefined);\n throw error;\n }\n}\n\nexport async function ensureBridgeDaemon(\n port: number,\n options: BridgeLaunchOptions = {},\n): Promise<DominusClient> {\n const attempts = options.attempts ?? 30;\n const connectTimeoutMs = options.connectTimeoutMs ?? 750;\n const retryDelayMs = options.retryDelayMs ?? 100;\n\n try {\n return await connectController(port, connectTimeoutMs, options.token);\n } catch (initialError) {\n if (await isPortInUse(port)) {\n throw new Error(\n `Port ${port} is occupied by a process that is not this Dominus bridge: ${formatError(initialError)}`,\n );\n }\n }\n\n const launch =\n options.launch ?? ((targetPort) => launchBridgeDaemon(targetPort, options.daemonPath));\n launch(port);\n\n let lastError: unknown;\n for (let attempt = 0; attempt < attempts; attempt += 1) {\n await new Promise((resolve) => setTimeout(resolve, retryDelayMs));\n try {\n return await connectController(port, connectTimeoutMs, options.token);\n } catch (error) {\n lastError = error;\n }\n }\n\n throw new Error(\n `Dominus could not start its local Studio bridge on port ${port}: ${formatError(lastError)}`,\n );\n}\n\nfunction formatError(error: unknown): string {\n return error instanceof Error ? error.message : String(error ?? 'unknown error');\n}\n","import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { loadConfig } from './config/config.js';\nimport { ensureBridgeDaemon } from './transport/daemon-launcher.js';\nimport { loadOrCreateBridgeToken } from './transport/auth.js';\n\nconst TOKEN_PLACEHOLDER = '__DOMINUS_BRIDGE_TOKEN__';\n\nfunction getPluginDirectory(): string {\n if (process.platform === 'win32') {\n const localAppData = process.env.LOCALAPPDATA;\n if (!localAppData) throw new Error('LOCALAPPDATA is not set');\n return path.join(localAppData, 'Roblox', 'Plugins');\n }\n if (process.platform === 'darwin') {\n return path.join(os.homedir(), 'Documents', 'Roblox', 'Plugins');\n }\n return path.join(os.homedir(), '.local', 'share', 'Roblox', 'Plugins');\n}\n\nconst distDirectory = path.dirname(fileURLToPath(import.meta.url));\nconst source = path.resolve(distDirectory, '..', 'plugin', 'Dominus.rbxmx');\nconst destinationDirectory = getPluginDirectory();\nconst destination = path.join(destinationDirectory, 'Dominus2.rbxmx');\n\nif (!fs.existsSync(source)) {\n throw new Error(`Packaged plugin not found at ${source}. Run pnpm build:plugin first.`);\n}\n\nconst template = fs.readFileSync(source, 'utf8');\nif (!template.includes(TOKEN_PLACEHOLDER)) {\n throw new Error('Packaged plugin template is missing its bridge token placeholder');\n}\nconst personalizedPlugin = template.replaceAll(TOKEN_PLACEHOLDER, loadOrCreateBridgeToken());\n\nfs.mkdirSync(destinationDirectory, { recursive: true });\nfs.writeFileSync(destination, personalizedPlugin, 'utf8');\nfor (const obsoleteName of ['Dominus2.rbxm', 'Dominus.rbxm', 'Dominus.rbxmx']) {\n const obsoletePath = path.join(destinationDirectory, obsoleteName);\n if (obsoletePath !== destination) fs.rmSync(obsoletePath, { force: true });\n}\nconsole.log(`Installed Dominus 2 Studio plugin to ${destination}`);\nconsole.log(\n 'Dominus 2 authenticates automatically. Restart Studio only if the toolbar does not reconnect.',\n);\n\nconst bridge = await ensureBridgeDaemon(loadConfig().port);\nawait bridge.stop();\nconsole.log('Dominus Studio bridge is running in the background.');\n"]}
1
+ {"version":3,"sources":["../src/config/config.ts","../src/transport/protocol.ts","../src/transport/auth.ts","../src/transport/ws-client.ts","../src/transport/daemon-launcher.ts","../src/install-plugin.ts"],"names":["path","os","fs","fileURLToPath"],"mappings":"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","file":"install-plugin.js","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport type { ConfigAccess } from '../tools/types.js';\n\nconst DOMINUS_DIR = path.join(os.homedir(), '.dominus');\nconst CONFIG_PATH = path.join(DOMINUS_DIR, 'config.json');\nconst DB_PATH = path.join(DOMINUS_DIR, 'dominus.db');\nconst RULES_PATH = path.join(DOMINUS_DIR, 'rules.json');\n\nexport type AIProviderType =\n | 'openai'\n | 'anthropic'\n | 'gemini'\n | 'xai'\n | 'openrouter'\n | 'custom';\n\nexport interface ProviderConfig {\n name: string;\n baseUrl: string;\n envVar: string;\n defaultModel: string;\n}\n\nexport const PROVIDERS: Record<AIProviderType, ProviderConfig> = {\n openai: {\n name: 'OpenAI',\n baseUrl: 'https://api.openai.com/v1',\n envVar: 'OPENAI_API_KEY',\n defaultModel: 'gpt-5.3-codex',\n },\n anthropic: {\n name: 'Anthropic',\n baseUrl: 'https://api.anthropic.com/v1/',\n envVar: 'ANTHROPIC_API_KEY',\n defaultModel: 'claude-sonnet-4-6',\n },\n gemini: {\n name: 'Google Gemini',\n baseUrl: 'https://generativelanguage.googleapis.com/v1beta/openai',\n envVar: 'GEMINI_API_KEY',\n defaultModel: 'gemini-3.1-pro',\n },\n xai: {\n name: 'xAI (Grok)',\n baseUrl: 'https://api.x.ai/v1',\n envVar: 'XAI_API_KEY',\n defaultModel: 'grok-4.2',\n },\n openrouter: {\n name: 'OpenRouter',\n baseUrl: 'https://openrouter.ai/api/v1',\n envVar: 'OPENROUTER_API_KEY',\n defaultModel: 'anthropic/claude-sonnet-4-6',\n },\n custom: {\n name: 'Custom',\n baseUrl: '',\n envVar: '',\n defaultModel: '',\n },\n};\n\nexport interface DominusConfig {\n provider: AIProviderType;\n apiKey?: string;\n apiBaseUrl: string;\n model: string;\n port: number;\n maxToolIterations: number;\n maxVerifyRetries: number;\n tokenBudget: number;\n autoIndex: boolean;\n autoLearn: boolean;\n userName: string;\n openCloudApiKey?: string;\n}\n\nconst DEFAULTS: DominusConfig = {\n provider: 'openai',\n apiBaseUrl: '',\n model: '',\n port: 18088,\n maxToolIterations: 25,\n maxVerifyRetries: 3,\n tokenBudget: 128000,\n autoIndex: true,\n autoLearn: true,\n userName: 'Developer',\n};\n\n/**\n * Auto-detect provider from environment variables.\n * Returns the first provider whose env var is set, or null.\n */\nexport function detectProviderFromEnv(): { provider: AIProviderType; apiKey: string } | null {\n const priority: AIProviderType[] = ['openai', 'anthropic', 'gemini', 'xai', 'openrouter'];\n for (const p of priority) {\n const key = process.env[PROVIDERS[p].envVar];\n if (key) return { provider: p, apiKey: key };\n }\n return null;\n}\n\n/**\n * Resolve the effective base URL and model for a provider config.\n */\nexport function resolveProviderSettings(config: DominusConfig): {\n baseUrl: string;\n model: string;\n} {\n const providerInfo = PROVIDERS[config.provider];\n return {\n baseUrl: config.apiBaseUrl || providerInfo?.baseUrl || PROVIDERS.openrouter.baseUrl,\n model: config.model || providerInfo?.defaultModel || 'gpt-4o',\n };\n}\n\nexport interface DominusRules {\n do: string[];\n dont: string[];\n conventions: string[];\n context: string;\n}\n\nconst DEFAULT_RULES: DominusRules = {\n do: [],\n dont: [],\n conventions: [],\n context: '',\n};\n\nfunction ensureDir(): void {\n if (!fs.existsSync(DOMINUS_DIR)) {\n fs.mkdirSync(DOMINUS_DIR, { recursive: true });\n }\n}\n\nfunction readJson<T>(filePath: string, defaults: T): T {\n try {\n if (fs.existsSync(filePath)) {\n const raw = fs.readFileSync(filePath, 'utf-8');\n return { ...defaults, ...JSON.parse(raw) };\n }\n } catch {\n // Corrupted file; reset to defaults\n }\n return { ...defaults };\n}\n\nfunction writeJson(filePath: string, data: unknown): void {\n ensureDir();\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\nexport function loadConfig(): DominusConfig {\n ensureDir();\n return readJson(CONFIG_PATH, DEFAULTS);\n}\n\nexport function saveConfig(config: DominusConfig): void {\n writeJson(CONFIG_PATH, config);\n}\n\nexport function getConfigValue<K extends keyof DominusConfig>(key: K): DominusConfig[K] {\n const config = loadConfig();\n return config[key];\n}\n\nexport function setConfigValue<K extends keyof DominusConfig>(\n key: K,\n value: DominusConfig[K],\n): void {\n const config = loadConfig();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (config as any)[key] = value;\n saveConfig(config);\n}\n\nexport function loadRules(): DominusRules {\n ensureDir();\n return readJson(RULES_PATH, DEFAULT_RULES);\n}\n\nexport function saveRules(rules: DominusRules): void {\n writeJson(RULES_PATH, rules);\n}\n\nexport function getDominusDir(): string {\n ensureDir();\n return DOMINUS_DIR;\n}\n\nexport function getDbPath(): string {\n ensureDir();\n return DB_PATH;\n}\n\nexport function createConfigAccess(): ConfigAccess {\n return {\n get<T>(key: string): T | undefined {\n const config = loadConfig() as unknown as Record<string, unknown>;\n return config[key] as T | undefined;\n },\n set(key: string, value: unknown): void {\n const config = loadConfig() as unknown as Record<string, unknown>;\n config[key] = value;\n saveConfig(config as unknown as DominusConfig);\n },\n getAll(): Record<string, unknown> {\n return loadConfig() as unknown as Record<string, unknown>;\n },\n };\n}\n","import { nanoid } from 'nanoid';\nimport { z } from 'zod';\n\nexport const DOMINUS_PROTOCOL_VERSION = 2;\nexport const MAX_MESSAGE_BYTES = 1024 * 1024;\n\nexport interface WsMessage<T = unknown> {\n id: string;\n type: string;\n payload: T;\n ts: number;\n}\n\nexport const StudioMsg = {\n HELLO: 'studio:hello',\n CONNECTED: 'studio:connected',\n DISCONNECTED: 'studio:disconnected',\n EXPLORER: 'studio:explorer',\n OUTPUT: 'studio:output',\n ERROR: 'studio:error',\n SELECTION: 'studio:selection',\n SCRIPT_CONTENT: 'studio:script:content',\n SCRIPT_CHANGED: 'studio:script:changed',\n RESPONSE: 'studio:response',\n REFLECTION: 'studio:reflection',\n TEST_RESULTS: 'studio:test:results',\n AUTHENTICATED: 'server:authenticated',\n AUTH_REJECTED: 'server:auth_rejected',\n} as const;\n\nexport const ControllerMsg = {\n HELLO: 'controller:hello',\n WELCOME: 'controller:welcome',\n RELAY: 'controller:relay',\n TARGET_STATE: 'controller:target_state',\n GET_TARGET_STATE: 'controller:get_target_state',\n SET_ACTIVE_CONNECTION: 'controller:set_active_connection',\n} as const;\n\nexport const CliMsg = {\n GET_EXPLORER: 'cli:get:explorer',\n GET_SCRIPT: 'cli:get:script',\n SET_SCRIPT: 'cli:set:script',\n RUN_CODE: 'cli:run',\n GET_PROPERTIES: 'cli:get:properties',\n GET_DESCENDANTS_PROPERTIES: 'cli:get:descendants:properties',\n SET_PROPERTIES: 'cli:set:properties',\n INSERT_INSTANCE: 'cli:insert',\n DELETE_INSTANCE: 'cli:delete',\n GET_SELECTION: 'cli:get:selection',\n SELECT: 'cli:select',\n SEARCH_SCRIPTS: 'cli:search:scripts',\n GET_OUTPUT: 'cli:get:output',\n RUN_TESTS: 'cli:run:tests',\n EXECUTE_RUN_TEST: 'cli:test:run',\n EXECUTE_PLAY_TEST: 'cli:test:play',\n END_TEST: 'cli:test:end',\n BUILD_UI: 'cli:build:ui',\n GET_REFLECTION: 'cli:get:reflection',\n UPLOAD_ASSET: 'cli:upload:asset',\n SERIALIZE_UI: 'cli:serialize:ui',\n MOVE_INSTANCE: 'cli:move:instance',\n UNDO: 'cli:undo',\n REDO: 'cli:redo',\n BULK_SET_PROPERTIES: 'cli:bulk:set:properties',\n FIND_REPLACE_SCRIPTS: 'cli:find:replace:scripts',\n V2_GET_TREE: 'studio:v2:get_tree',\n V2_INSPECT: 'studio:v2:inspect',\n V2_GET_SELECTION: 'studio:v2:get_selection',\n V2_READ_SCRIPT: 'studio:v2:read_script',\n V2_UPDATE_SCRIPT: 'studio:v2:update_script',\n V2_APPLY: 'studio:v2:apply',\n V2_CREATE_PARTS: 'studio:v2:create_parts',\n V2_CLONE_INSTANCES: 'studio:v2:clone_instances',\n V2_GROUP_INSTANCES: 'studio:v2:group_instances',\n V2_UNGROUP_INSTANCES: 'studio:v2:ungroup_instances',\n V2_TRANSFORM_INSTANCES: 'studio:v2:transform_instances',\n V2_CREATE_WELDS: 'studio:v2:create_welds',\n V2_QUERY_PARTS: 'studio:v2:query_parts',\n V2_SET_SELECTION: 'studio:v2:set_selection',\n V2_GET_METADATA: 'studio:v2:get_metadata',\n V2_SET_ATTRIBUTES: 'studio:v2:set_attributes',\n V2_UPDATE_TAGS: 'studio:v2:update_tags',\n V2_LIST_CALLABLE_METHODS: 'studio:v2:list_callable_methods',\n V2_INVOKE_METHODS: 'studio:v2:invoke_methods',\n V2_DELETE: 'studio:v2:delete',\n V2_BUILD_UI: 'studio:v2:build_ui',\n V2_SNAPSHOT_UI: 'studio:v2:snapshot_ui',\n V2_RUN_TEST: 'studio:v2:run_test',\n V2_GET_OUTPUT: 'studio:v2:get_output',\n V2_GET_REFLECTION: 'studio:v2:get_reflection',\n} as const;\n\nexport type StudioMsgType = (typeof StudioMsg)[keyof typeof StudioMsg];\nexport type CliMsgType = (typeof CliMsg)[keyof typeof CliMsg];\n\nexport interface ExplorerNode {\n name: string;\n className: string;\n path: string;\n ref?: InstanceRef;\n children?: ExplorerNode[];\n}\n\nexport interface InstanceRef {\n instanceId?: string;\n pathSegments?: string[];\n}\n\nexport interface StudioConnectedPayload {\n studioVersion: string;\n protocolVersion?: number;\n clientId?: string;\n token?: string;\n connectionId?: string;\n placeId?: number;\n placeName?: string;\n engineVersion?: string;\n}\n\nexport interface ScriptContentPayload {\n path: string;\n className: 'Script' | 'LocalScript' | 'ModuleScript';\n source: string;\n lineCount: number;\n}\n\nexport interface ScriptChangedPayload {\n path: string;\n source: string;\n}\n\nexport interface OutputPayload {\n message: string;\n level: 'info' | 'warn' | 'error';\n timestamp: number;\n source?: string;\n}\n\nexport interface SelectionPayload {\n paths: string[];\n classNames: string[];\n}\n\nexport interface PropertyEntry {\n name: string;\n value: string;\n type: string;\n category?: string;\n}\n\nexport interface TestResultPayload {\n name: string;\n passed: boolean;\n duration: number;\n error?: string;\n}\n\nexport interface StudioTestPayload {\n args?: unknown;\n}\n\nexport interface StudioTestResultPayload {\n success: boolean;\n result?: unknown;\n error?: string;\n duration?: number;\n}\n\nexport interface ReflectionPayload {\n className: string;\n properties: { name: string; type: string; category: string }[];\n methods: { name: string; parameters: string[] }[];\n events: { name: string; parameters: string[] }[];\n}\n\nexport interface RunCodePayload {\n code: string;\n}\n\nexport interface RunCodeResponsePayload {\n output: string;\n error?: string;\n duration: number;\n}\n\nexport interface SearchScriptsPayload {\n query: string;\n maxResults?: number;\n}\n\nexport interface SearchResultPayload {\n results: {\n path: string;\n className: string;\n matches: { line: number; text: string }[];\n }[];\n}\n\nexport interface InsertInstancePayload {\n className: string;\n parentPath: string;\n name: string;\n properties?: Record<string, unknown>;\n}\n\nexport interface SetPropertiesPayload {\n path: string;\n properties: Record<string, unknown>;\n}\n\nexport function createMessage<T>(type: string, payload: T): WsMessage<T> {\n return { id: nanoid(), type, payload, ts: Date.now() };\n}\n\nexport function createRequest<T>(type: string, payload: T): WsMessage<T> {\n return createMessage(type, payload);\n}\n\nexport function parseMessage(raw: string): WsMessage {\n if (Buffer.byteLength(raw, 'utf8') > MAX_MESSAGE_BYTES) {\n throw new Error(`WebSocket message exceeds ${MAX_MESSAGE_BYTES} bytes`);\n }\n try {\n const parsed = JSON.parse(raw) as unknown;\n return wsMessageSchema.parse(parsed) as WsMessage;\n } catch {\n throw new Error(`Failed to parse WebSocket message: ${raw.slice(0, 100)}`);\n }\n}\n\nexport function serializeMessage(msg: WsMessage): string {\n const serialized = JSON.stringify(msg);\n if (Buffer.byteLength(serialized, 'utf8') > MAX_MESSAGE_BYTES) {\n throw new Error(`WebSocket message exceeds ${MAX_MESSAGE_BYTES} bytes`);\n }\n return serialized;\n}\n\nconst wsMessageSchema = z\n .object({\n id: z.string().min(1).max(128),\n type: z.string().min(1).max(128),\n payload: z.unknown(),\n ts: z.number().finite(),\n })\n .strict();\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport * as crypto from 'node:crypto';\nimport { getDominusDir } from '../config/config.js';\n\nconst TOKEN_FILE = 'bridge-token';\n\nexport function loadOrCreateBridgeToken(): string {\n const tokenPath = path.join(getDominusDir(), TOKEN_FILE);\n try {\n const existing = fs.readFileSync(tokenPath, 'utf8').trim();\n if (existing.length >= 32) return existing;\n } catch {\n // First run or an unreadable token is repaired below.\n }\n\n const token = crypto.randomBytes(32).toString('base64url');\n fs.writeFileSync(tokenPath, `${token}\\n`, { encoding: 'utf8', mode: 0o600 });\n try {\n fs.chmodSync(tokenPath, 0o600);\n } catch {\n // Windows ACLs do not map directly to POSIX modes.\n }\n return token;\n}\n\nexport function tokensEqual(actual: unknown, expected: string): boolean {\n if (typeof actual !== 'string') return false;\n const actualBuffer = Buffer.from(actual);\n const expectedBuffer = Buffer.from(expected);\n return (\n actualBuffer.length === expectedBuffer.length &&\n crypto.timingSafeEqual(actualBuffer, expectedBuffer)\n );\n}\n","import { EventEmitter } from 'node:events';\nimport { WebSocket } from 'ws';\nimport {\n ControllerMsg,\n DOMINUS_PROTOCOL_VERSION,\n StudioMsg,\n createMessage,\n parseMessage,\n serializeMessage,\n type WsMessage,\n} from './protocol.js';\nimport { loadOrCreateBridgeToken } from './auth.js';\nimport type { PlaceInfo, StudioBridge, StudioConnection } from './ws-server.js';\n\ninterface ClientOptions {\n token?: string;\n connectTimeoutMs?: number;\n autoReconnect?: boolean;\n reconnectDelayMs?: number;\n maxReconnectDelayMs?: number;\n}\n\ninterface ControlResult {\n success?: boolean;\n error?: string;\n [key: string]: unknown;\n}\n\nexport class DominusClient extends EventEmitter implements StudioBridge {\n private ws: WebSocket | null = null;\n private readonly port: number;\n private readonly token: string;\n private readonly connectTimeoutMs: number;\n private readonly autoReconnect: boolean;\n private readonly reconnectDelayMs: number;\n private readonly maxReconnectDelayMs: number;\n private readonly connections = new Map<string, Omit<StudioConnection, 'ws'>>();\n private activeConnectionId: string | null = null;\n private connectPromise: Promise<void> | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private nextReconnectDelayMs: number;\n private hasAuthenticated = false;\n private stopping = false;\n private readonly pendingRequests = new Map<\n string,\n {\n resolve: (msg: WsMessage) => void;\n reject: (err: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n }\n >();\n\n constructor(port = 18088, options: ClientOptions = {}) {\n super();\n this.port = port;\n this.token = options.token ?? loadOrCreateBridgeToken();\n this.connectTimeoutMs = options.connectTimeoutMs ?? 8_000;\n this.autoReconnect = options.autoReconnect ?? true;\n this.reconnectDelayMs = options.reconnectDelayMs ?? 250;\n this.maxReconnectDelayMs = options.maxReconnectDelayMs ?? 5_000;\n this.nextReconnectDelayMs = this.reconnectDelayMs;\n }\n\n connect(): Promise<void> {\n if (this.ws?.readyState === WebSocket.OPEN) return Promise.resolve();\n if (this.connectPromise) return this.connectPromise;\n\n this.stopping = false;\n this.clearReconnectTimer();\n const attempt = this.openConnection();\n this.connectPromise = attempt;\n void attempt.then(\n () => {\n if (this.connectPromise === attempt) this.connectPromise = null;\n },\n () => {\n if (this.connectPromise === attempt) this.connectPromise = null;\n },\n );\n return attempt;\n }\n\n private openConnection(): Promise<void> {\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(`ws://127.0.0.1:${this.port}`, {\n perMessageDeflate: false,\n maxPayload: 1024 * 1024,\n });\n let settled = false;\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true;\n ws.close(1008, 'Dominus controller handshake timed out');\n reject(new Error('Timed out authenticating with the Dominus bridge'));\n }\n }, this.connectTimeoutMs);\n\n ws.on('open', () => {\n this.ws = ws;\n ws.send(\n serializeMessage(\n createMessage(ControllerMsg.HELLO, {\n protocolVersion: DOMINUS_PROTOCOL_VERSION,\n token: this.token,\n }),\n ),\n );\n });\n\n ws.on('message', (raw) => {\n try {\n const msg = parseMessage(raw.toString());\n if (msg.type === ControllerMsg.WELCOME && !settled) {\n settled = true;\n clearTimeout(timer);\n this.applyWelcome(msg.payload);\n this.hasAuthenticated = true;\n this.nextReconnectDelayMs = this.reconnectDelayMs;\n this.emit('server:started', { port: this.port, relay: true });\n resolve();\n return;\n }\n if (msg.type === StudioMsg.AUTH_REJECTED && !settled) {\n settled = true;\n clearTimeout(timer);\n const payload = msg.payload as { error?: string };\n reject(new Error(payload.error ?? 'Dominus controller authentication failed'));\n ws.close(1008, 'Controller authentication failed');\n return;\n }\n this.handleMessage(msg);\n } catch (err) {\n this.emit('server:error', err);\n }\n });\n\n ws.on('close', () => {\n clearTimeout(timer);\n const wasCurrentSocket = this.ws === ws;\n if (wasCurrentSocket) {\n this.ws = null;\n this.connections.clear();\n this.activeConnectionId = null;\n }\n if (!settled) {\n settled = true;\n reject(new Error('Dominus bridge closed before authentication completed'));\n }\n if (wasCurrentSocket) {\n this.rejectPending(new Error('Dominus relay connection lost'));\n this.emit('studio:disconnected');\n this.scheduleReconnect();\n }\n });\n\n ws.on('error', (err) => {\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n reject(err);\n }\n this.emit('server:error', err);\n });\n });\n }\n\n private scheduleReconnect(): void {\n if (\n !this.autoReconnect ||\n !this.hasAuthenticated ||\n this.stopping ||\n this.reconnectTimer ||\n this.ws?.readyState === WebSocket.OPEN\n ) {\n return;\n }\n\n const delayMs = this.nextReconnectDelayMs;\n this.nextReconnectDelayMs = Math.min(delayMs * 2, this.maxReconnectDelayMs);\n const timer = setTimeout(() => {\n if (this.reconnectTimer !== timer) return;\n this.reconnectTimer = null;\n if (this.stopping) return;\n void this.connect().catch(() => this.scheduleReconnect());\n }, delayMs);\n timer.unref?.();\n this.reconnectTimer = timer;\n }\n\n private clearReconnectTimer(): void {\n if (!this.reconnectTimer) return;\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n private applyWelcome(payload: unknown): void {\n const welcome = payload as {\n connections?: PlaceInfo[];\n activeConnectionId?: string | null;\n };\n this.replaceConnections(welcome.connections ?? []);\n this.activeConnectionId = welcome.activeConnectionId ?? null;\n if (!this.resolveTargetInfo() && this.connections.size === 1) {\n this.activeConnectionId = this.connections.keys().next().value ?? null;\n }\n }\n\n private handleMessage(msg: WsMessage): void {\n if (msg.type === ControllerMsg.TARGET_STATE) {\n const payload = msg.payload as {\n connections?: PlaceInfo[];\n defaultActiveConnectionId?: string | null;\n };\n this.replaceConnections(payload.connections ?? []);\n if (this.activeConnectionId && !this.connections.has(this.activeConnectionId)) {\n this.activeConnectionId = null;\n }\n if (!this.activeConnectionId && this.connections.size === 1) {\n this.activeConnectionId = this.connections.keys().next().value ?? null;\n }\n this.emit('controller:target_state', payload);\n return;\n }\n\n if (msg.type === StudioMsg.CONNECTED) {\n const connection = msg.payload as PlaceInfo;\n this.connections.set(connection.connectionId, toConnectionInfo(connection));\n if (!this.activeConnectionId && this.connections.size === 1) {\n this.activeConnectionId = connection.connectionId;\n }\n this.emit('studio:connected', connection);\n return;\n }\n\n if (msg.type === StudioMsg.DISCONNECTED) {\n const payload = msg.payload as { connectionId?: string };\n if (payload.connectionId) this.connections.delete(payload.connectionId);\n if (this.activeConnectionId === payload.connectionId) this.activeConnectionId = null;\n if (!this.activeConnectionId && this.connections.size === 1) {\n this.activeConnectionId = this.connections.keys().next().value ?? null;\n }\n this.emit('studio:disconnected', payload);\n return;\n }\n\n if (msg.type === StudioMsg.RESPONSE) {\n const pending = this.pendingRequests.get(msg.id);\n if (pending) {\n clearTimeout(pending.timer);\n this.pendingRequests.delete(msg.id);\n pending.resolve(msg);\n }\n return;\n }\n\n this.emit(msg.type, msg.payload);\n this.emit('message', msg);\n }\n\n private replaceConnections(connections: PlaceInfo[]): void {\n this.connections.clear();\n for (const connection of connections) {\n this.connections.set(connection.connectionId, toConnectionInfo(connection));\n }\n }\n\n private sendMessage(message: WsMessage): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n throw new Error('Not connected to the Dominus bridge');\n }\n this.ws.send(serializeMessage(message));\n }\n\n private waitForResponse<T = unknown>(\n message: WsMessage,\n timeoutMs: number,\n ): Promise<WsMessage<T>> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pendingRequests.delete(message.id);\n reject(new Error(`Dominus request timed out: ${message.type}`));\n }, timeoutMs);\n this.pendingRequests.set(message.id, {\n resolve: resolve as (msg: WsMessage) => void,\n reject,\n timer,\n });\n try {\n this.sendMessage(message);\n } catch (err) {\n clearTimeout(timer);\n this.pendingRequests.delete(message.id);\n reject(err);\n }\n });\n }\n\n private async sendControlRequest<T extends ControlResult>(\n type: string,\n payload: unknown,\n timeoutMs = 10_000,\n ): Promise<T> {\n const response = await this.waitForResponse<T>(createMessage(type, payload), timeoutMs);\n const result = response.payload;\n if (result.error || result.success === false) throw new Error(result.error ?? `${type} failed`);\n return result;\n }\n\n sendRequest<T = unknown>(\n type: string,\n payload: unknown,\n timeoutMs = 15_000,\n ): Promise<WsMessage<T>> {\n const target = this.resolveTargetInfo();\n if (!target || !this.activeConnectionId) {\n return Promise.reject(\n new Error(\n this.connections.size > 1\n ? 'Multiple Studio sessions are connected. Call dominus_select_studio first.'\n : 'No authenticated Roblox Studio connection',\n ),\n );\n }\n const request = createMessage(type, payload);\n const relay = createMessage(ControllerMsg.RELAY, {\n connectionId: this.activeConnectionId,\n request,\n });\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pendingRequests.delete(request.id);\n reject(new Error(`Studio request timed out: ${type}`));\n }, timeoutMs);\n this.pendingRequests.set(request.id, {\n resolve: resolve as (msg: WsMessage) => void,\n reject,\n timer,\n });\n try {\n this.sendMessage(relay);\n } catch (err) {\n clearTimeout(timer);\n this.pendingRequests.delete(request.id);\n reject(err);\n }\n });\n }\n\n sendNotification(type: string, payload: unknown): void {\n if (!this.activeConnectionId) return;\n const request = createMessage(type, payload);\n this.sendMessage(\n createMessage(ControllerMsg.RELAY, {\n connectionId: this.activeConnectionId,\n request,\n }),\n );\n }\n\n isConnected(): boolean {\n return this.resolveTargetInfo() !== null;\n }\n\n getConnectionInfo(): StudioConnection | null {\n const target = this.resolveTargetInfo();\n if (!target || !this.ws) return null;\n return { ...target, ws: this.ws };\n }\n\n listConnections(): PlaceInfo[] {\n return [...this.connections.values()].map((connection) => ({\n placeId: connection.placeId ?? 0,\n connectionId: connection.connectionId,\n clientId: connection.clientId,\n placeName: connection.placeName,\n studioVersion: connection.studioVersion,\n connectedAt: connection.connectedAt,\n active: connection.connectionId === this.activeConnectionId,\n }));\n }\n\n async refreshConnections(): Promise<PlaceInfo[]> {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) await this.connect();\n const result = await this.sendControlRequest<\n ControlResult & {\n connections?: PlaceInfo[];\n defaultActiveConnectionId?: string | null;\n }\n >(ControllerMsg.GET_TARGET_STATE, {});\n\n this.replaceConnections(result.connections ?? []);\n if (this.activeConnectionId && !this.connections.has(this.activeConnectionId)) {\n this.activeConnectionId = null;\n }\n if (\n !this.activeConnectionId &&\n result.defaultActiveConnectionId &&\n this.connections.has(result.defaultActiveConnectionId)\n ) {\n this.activeConnectionId = result.defaultActiveConnectionId;\n }\n if (!this.activeConnectionId && this.connections.size === 1) {\n this.activeConnectionId = this.connections.keys().next().value ?? null;\n }\n return this.listConnections();\n }\n\n getActiveConnectionId(): string | null {\n return this.activeConnectionId;\n }\n\n async setActiveConnectionId(connectionId: string | null): Promise<void> {\n if (connectionId && !this.connections.has(connectionId)) {\n await this.refreshConnections();\n }\n if (connectionId && !this.connections.has(connectionId)) {\n throw new Error(`Studio connection ${connectionId} is not connected`);\n }\n await this.sendControlRequest(ControllerMsg.SET_ACTIVE_CONNECTION, { connectionId });\n this.activeConnectionId = connectionId;\n }\n\n getActivePlaceId(): number {\n return this.resolveTargetInfo()?.placeId ?? 0;\n }\n\n setActivePlaceId(placeId: number): void {\n if (placeId === 0) {\n void this.setActiveConnectionId(null);\n return;\n }\n const matches = [...this.connections.values()].filter(\n (connection) => connection.placeId === placeId,\n );\n if (matches.length !== 1) {\n throw new Error(\n matches.length === 0\n ? `Place ${placeId} is not connected`\n : `Place ${placeId} has multiple Studio sessions; select a connectionId instead`,\n );\n }\n void this.setActiveConnectionId(matches[0].connectionId);\n }\n\n private resolveTargetInfo(): Omit<StudioConnection, 'ws'> | null {\n if (this.activeConnectionId) return this.connections.get(this.activeConnectionId) ?? null;\n if (this.connections.size === 1) return this.connections.values().next().value ?? null;\n return null;\n }\n\n getPort(): number {\n return this.port;\n }\n\n stop(): Promise<void> {\n this.stopping = true;\n this.hasAuthenticated = false;\n this.clearReconnectTimer();\n this.rejectPending(new Error('Dominus client is shutting down'));\n return new Promise((resolve) => {\n if (!this.ws) {\n resolve();\n return;\n }\n const ws = this.ws;\n this.ws = null;\n ws.once('close', resolve);\n ws.close(1000, 'Dominus client shutdown');\n });\n }\n\n private rejectPending(error: Error): void {\n for (const pending of this.pendingRequests.values()) {\n clearTimeout(pending.timer);\n pending.reject(error);\n }\n this.pendingRequests.clear();\n }\n}\n\nfunction toConnectionInfo(connection: PlaceInfo): Omit<StudioConnection, 'ws'> {\n return {\n connectedAt: connection.connectedAt,\n connectionId: connection.connectionId,\n clientId: connection.clientId,\n studioVersion: connection.studioVersion,\n placeId: connection.placeId,\n placeName: connection.placeName,\n };\n}\n\nexport async function isPortInUse(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const ws = new WebSocket(`ws://127.0.0.1:${port}`);\n const timer = setTimeout(() => {\n ws.close();\n resolve(false);\n }, 750);\n ws.on('open', () => {\n clearTimeout(timer);\n ws.close();\n resolve(true);\n });\n ws.on('error', () => {\n clearTimeout(timer);\n resolve(false);\n });\n });\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { spawn } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport { DominusClient, isPortInUse } from './ws-client.js';\n\nexport interface BridgeLaunchOptions {\n attempts?: number;\n connectTimeoutMs?: number;\n daemonPath?: string;\n launch?: (port: number) => void;\n retryDelayMs?: number;\n token?: string;\n}\n\nfunction resolveDaemonPath(): string {\n const besideEntry = fileURLToPath(new URL('./bridge-daemon.js', import.meta.url));\n if (fs.existsSync(besideEntry)) return besideEntry;\n\n const projectBuild = path.resolve(\n path.dirname(fileURLToPath(import.meta.url)),\n '../../dist/bridge-daemon.js',\n );\n if (fs.existsSync(projectBuild)) return projectBuild;\n\n throw new Error('Dominus bridge daemon is missing. Reinstall or rebuild dominus-cli.');\n}\n\nexport function launchBridgeDaemon(port: number, daemonPath = resolveDaemonPath()): void {\n const child = spawn(process.execPath, [daemonPath], {\n detached: true,\n env: { ...process.env, DOMINUS_BRIDGE_PORT: String(port) },\n stdio: 'ignore',\n windowsHide: true,\n });\n child.unref();\n}\n\nasync function connectController(\n port: number,\n timeoutMs: number,\n token?: string,\n): Promise<DominusClient> {\n const client = new DominusClient(port, { connectTimeoutMs: timeoutMs, token });\n try {\n await client.connect();\n return client;\n } catch (error) {\n await client.stop().catch(() => undefined);\n throw error;\n }\n}\n\nexport async function ensureBridgeDaemon(\n port: number,\n options: BridgeLaunchOptions = {},\n): Promise<DominusClient> {\n const attempts = options.attempts ?? 30;\n const connectTimeoutMs = options.connectTimeoutMs ?? 750;\n const retryDelayMs = options.retryDelayMs ?? 100;\n\n try {\n return await connectController(port, connectTimeoutMs, options.token);\n } catch (initialError) {\n if (await isPortInUse(port)) {\n throw new Error(\n `Port ${port} is occupied by a process that is not this Dominus bridge: ${formatError(initialError)}`,\n );\n }\n }\n\n const launch =\n options.launch ?? ((targetPort) => launchBridgeDaemon(targetPort, options.daemonPath));\n launch(port);\n\n let lastError: unknown;\n for (let attempt = 0; attempt < attempts; attempt += 1) {\n await new Promise((resolve) => setTimeout(resolve, retryDelayMs));\n try {\n return await connectController(port, connectTimeoutMs, options.token);\n } catch (error) {\n lastError = error;\n }\n }\n\n throw new Error(\n `Dominus could not start its local Studio bridge on port ${port}: ${formatError(lastError)}`,\n );\n}\n\nfunction formatError(error: unknown): string {\n return error instanceof Error ? error.message : String(error ?? 'unknown error');\n}\n","import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { loadConfig } from './config/config.js';\nimport { ensureBridgeDaemon } from './transport/daemon-launcher.js';\nimport { loadOrCreateBridgeToken } from './transport/auth.js';\n\nconst TOKEN_PLACEHOLDER = '__DOMINUS_BRIDGE_TOKEN__';\n\nfunction getPluginDirectory(): string {\n if (process.platform === 'win32') {\n const localAppData = process.env.LOCALAPPDATA;\n if (!localAppData) throw new Error('LOCALAPPDATA is not set');\n return path.join(localAppData, 'Roblox', 'Plugins');\n }\n if (process.platform === 'darwin') {\n return path.join(os.homedir(), 'Documents', 'Roblox', 'Plugins');\n }\n return path.join(os.homedir(), '.local', 'share', 'Roblox', 'Plugins');\n}\n\nconst distDirectory = path.dirname(fileURLToPath(import.meta.url));\nconst source = path.resolve(distDirectory, '..', 'plugin', 'Dominus.rbxmx');\nconst destinationDirectory = getPluginDirectory();\nconst destination = path.join(destinationDirectory, 'Dominus2.rbxmx');\n\nif (!fs.existsSync(source)) {\n throw new Error(`Packaged plugin not found at ${source}. Run pnpm build:plugin first.`);\n}\n\nconst template = fs.readFileSync(source, 'utf8');\nif (!template.includes(TOKEN_PLACEHOLDER)) {\n throw new Error('Packaged plugin template is missing its bridge token placeholder');\n}\nconst personalizedPlugin = template.replaceAll(TOKEN_PLACEHOLDER, loadOrCreateBridgeToken());\n\nfs.mkdirSync(destinationDirectory, { recursive: true });\nfs.writeFileSync(destination, personalizedPlugin, 'utf8');\nfor (const obsoleteName of ['Dominus2.rbxm', 'Dominus.rbxm', 'Dominus.rbxmx']) {\n const obsoletePath = path.join(destinationDirectory, obsoleteName);\n if (obsoletePath !== destination) fs.rmSync(obsoletePath, { force: true });\n}\nconsole.log(`Installed Dominus 2 Studio plugin to ${destination}`);\nconsole.log(\n 'Dominus 2 authenticates automatically. Restart Studio only if the toolbar does not reconnect.',\n);\n\nconst bridge = await ensureBridgeDaemon(loadConfig().port);\nawait bridge.stop();\nconsole.log('Dominus Studio bridge is running in the background.');\n"]}
package/dist/mcp.js CHANGED
@@ -74,6 +74,7 @@ var ControllerMsg = {
74
74
  WELCOME: "controller:welcome",
75
75
  RELAY: "controller:relay",
76
76
  TARGET_STATE: "controller:target_state",
77
+ GET_TARGET_STATE: "controller:get_target_state",
77
78
  SET_ACTIVE_CONNECTION: "controller:set_active_connection"
78
79
  };
79
80
  var CliMsg = {
@@ -180,16 +181,45 @@ var DominusClient = class extends EventEmitter {
180
181
  port;
181
182
  token;
182
183
  connectTimeoutMs;
184
+ autoReconnect;
185
+ reconnectDelayMs;
186
+ maxReconnectDelayMs;
183
187
  connections = /* @__PURE__ */ new Map();
184
188
  activeConnectionId = null;
189
+ connectPromise = null;
190
+ reconnectTimer = null;
191
+ nextReconnectDelayMs;
192
+ hasAuthenticated = false;
193
+ stopping = false;
185
194
  pendingRequests = /* @__PURE__ */ new Map();
186
195
  constructor(port = 18088, options = {}) {
187
196
  super();
188
197
  this.port = port;
189
198
  this.token = options.token ?? loadOrCreateBridgeToken();
190
199
  this.connectTimeoutMs = options.connectTimeoutMs ?? 8e3;
200
+ this.autoReconnect = options.autoReconnect ?? true;
201
+ this.reconnectDelayMs = options.reconnectDelayMs ?? 250;
202
+ this.maxReconnectDelayMs = options.maxReconnectDelayMs ?? 5e3;
203
+ this.nextReconnectDelayMs = this.reconnectDelayMs;
191
204
  }
192
205
  connect() {
206
+ if (this.ws?.readyState === WebSocket.OPEN) return Promise.resolve();
207
+ if (this.connectPromise) return this.connectPromise;
208
+ this.stopping = false;
209
+ this.clearReconnectTimer();
210
+ const attempt = this.openConnection();
211
+ this.connectPromise = attempt;
212
+ void attempt.then(
213
+ () => {
214
+ if (this.connectPromise === attempt) this.connectPromise = null;
215
+ },
216
+ () => {
217
+ if (this.connectPromise === attempt) this.connectPromise = null;
218
+ }
219
+ );
220
+ return attempt;
221
+ }
222
+ openConnection() {
193
223
  return new Promise((resolve, reject) => {
194
224
  const ws = new WebSocket(`ws://127.0.0.1:${this.port}`, {
195
225
  perMessageDeflate: false,
@@ -221,6 +251,8 @@ var DominusClient = class extends EventEmitter {
221
251
  settled = true;
222
252
  clearTimeout(timer);
223
253
  this.applyWelcome(msg.payload);
254
+ this.hasAuthenticated = true;
255
+ this.nextReconnectDelayMs = this.reconnectDelayMs;
224
256
  this.emit("server:started", { port: this.port, relay: true });
225
257
  resolve();
226
258
  return;
@@ -240,15 +272,21 @@ var DominusClient = class extends EventEmitter {
240
272
  });
241
273
  ws.on("close", () => {
242
274
  clearTimeout(timer);
243
- this.ws = null;
244
- this.connections.clear();
245
- this.activeConnectionId = null;
275
+ const wasCurrentSocket = this.ws === ws;
276
+ if (wasCurrentSocket) {
277
+ this.ws = null;
278
+ this.connections.clear();
279
+ this.activeConnectionId = null;
280
+ }
246
281
  if (!settled) {
247
282
  settled = true;
248
283
  reject(new Error("Dominus bridge closed before authentication completed"));
249
284
  }
250
- this.rejectPending(new Error("Dominus relay connection lost"));
251
- this.emit("studio:disconnected");
285
+ if (wasCurrentSocket) {
286
+ this.rejectPending(new Error("Dominus relay connection lost"));
287
+ this.emit("studio:disconnected");
288
+ this.scheduleReconnect();
289
+ }
252
290
  });
253
291
  ws.on("error", (err) => {
254
292
  if (!settled) {
@@ -260,6 +298,26 @@ var DominusClient = class extends EventEmitter {
260
298
  });
261
299
  });
262
300
  }
301
+ scheduleReconnect() {
302
+ if (!this.autoReconnect || !this.hasAuthenticated || this.stopping || this.reconnectTimer || this.ws?.readyState === WebSocket.OPEN) {
303
+ return;
304
+ }
305
+ const delayMs = this.nextReconnectDelayMs;
306
+ this.nextReconnectDelayMs = Math.min(delayMs * 2, this.maxReconnectDelayMs);
307
+ const timer = setTimeout(() => {
308
+ if (this.reconnectTimer !== timer) return;
309
+ this.reconnectTimer = null;
310
+ if (this.stopping) return;
311
+ void this.connect().catch(() => this.scheduleReconnect());
312
+ }, delayMs);
313
+ timer.unref?.();
314
+ this.reconnectTimer = timer;
315
+ }
316
+ clearReconnectTimer() {
317
+ if (!this.reconnectTimer) return;
318
+ clearTimeout(this.reconnectTimer);
319
+ this.reconnectTimer = null;
320
+ }
263
321
  applyWelcome(payload) {
264
322
  const welcome = payload;
265
323
  this.replaceConnections(welcome.connections ?? []);
@@ -412,10 +470,28 @@ var DominusClient = class extends EventEmitter {
412
470
  active: connection.connectionId === this.activeConnectionId
413
471
  }));
414
472
  }
473
+ async refreshConnections() {
474
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) await this.connect();
475
+ const result = await this.sendControlRequest(ControllerMsg.GET_TARGET_STATE, {});
476
+ this.replaceConnections(result.connections ?? []);
477
+ if (this.activeConnectionId && !this.connections.has(this.activeConnectionId)) {
478
+ this.activeConnectionId = null;
479
+ }
480
+ if (!this.activeConnectionId && result.defaultActiveConnectionId && this.connections.has(result.defaultActiveConnectionId)) {
481
+ this.activeConnectionId = result.defaultActiveConnectionId;
482
+ }
483
+ if (!this.activeConnectionId && this.connections.size === 1) {
484
+ this.activeConnectionId = this.connections.keys().next().value ?? null;
485
+ }
486
+ return this.listConnections();
487
+ }
415
488
  getActiveConnectionId() {
416
489
  return this.activeConnectionId;
417
490
  }
418
491
  async setActiveConnectionId(connectionId) {
492
+ if (connectionId && !this.connections.has(connectionId)) {
493
+ await this.refreshConnections();
494
+ }
419
495
  if (connectionId && !this.connections.has(connectionId)) {
420
496
  throw new Error(`Studio connection ${connectionId} is not connected`);
421
497
  }
@@ -449,6 +525,9 @@ var DominusClient = class extends EventEmitter {
449
525
  return this.port;
450
526
  }
451
527
  stop() {
528
+ this.stopping = true;
529
+ this.hasAuthenticated = false;
530
+ this.clearReconnectTimer();
452
531
  this.rejectPending(new Error("Dominus client is shutting down"));
453
532
  return new Promise((resolve) => {
454
533
  if (!this.ws) {
@@ -601,23 +680,26 @@ function registerDominusResources(server, bridge) {
601
680
  description: "Current authenticated Roblox Studio sessions and selected target.",
602
681
  mimeType: "application/json"
603
682
  },
604
- async (uri) => ({
605
- contents: [
606
- {
607
- uri: uri.href,
608
- mimeType: "application/json",
609
- text: JSON.stringify(
610
- {
611
- protocolVersion: 2,
612
- activeConnectionId: bridge.getActiveConnectionId(),
613
- connections: bridge.listConnections()
614
- },
615
- null,
616
- 2
617
- )
618
- }
619
- ]
620
- })
683
+ async (uri) => {
684
+ const connections = bridge.refreshConnections ? await bridge.refreshConnections() : bridge.listConnections();
685
+ return {
686
+ contents: [
687
+ {
688
+ uri: uri.href,
689
+ mimeType: "application/json",
690
+ text: JSON.stringify(
691
+ {
692
+ protocolVersion: 2,
693
+ activeConnectionId: bridge.getActiveConnectionId(),
694
+ connections
695
+ },
696
+ null,
697
+ 2
698
+ )
699
+ }
700
+ ]
701
+ };
702
+ }
621
703
  );
622
704
  server.registerPrompt(
623
705
  "dominus-workflow",
@@ -944,11 +1026,12 @@ function registerConnectionTools(server, bridge) {
944
1026
  },
945
1027
  async () => {
946
1028
  try {
1029
+ const connections = bridge.refreshConnections ? await bridge.refreshConnections() : bridge.listConnections();
947
1030
  return success({
948
1031
  protocolVersion: 2,
949
1032
  port: bridge.getPort(),
950
1033
  activeConnectionId: bridge.getActiveConnectionId(),
951
- connections: bridge.listConnections()
1034
+ connections
952
1035
  });
953
1036
  } catch (err) {
954
1037
  return failure(err);