@openacp/cli 0.1.0
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/README.md +286 -0
- package/dist/chunk-624B5RFL.js +672 -0
- package/dist/chunk-624B5RFL.js.map +1 -0
- package/dist/chunk-FLAM2AON.js +209 -0
- package/dist/chunk-FLAM2AON.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +88 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +326 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/main-2DVA2NVU.js +84 -0
- package/dist/main-2DVA2NVU.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../packages/core/src/streams.ts","../../packages/core/src/stderr-capture.ts","../../packages/core/src/agent-instance.ts","../../packages/core/src/agent-manager.ts","../../packages/core/src/session.ts","../../packages/core/src/session-manager.ts","../../packages/core/src/notification.ts","../../packages/core/src/core.ts"],"sourcesContent":["import type { Writable, Readable } from 'node:stream'\n\nexport function nodeToWebWritable(nodeStream: Writable): WritableStream<Uint8Array> {\n return new WritableStream<Uint8Array>({\n write(chunk) {\n return new Promise<void>((resolve, reject) => {\n nodeStream.write(Buffer.from(chunk), (err) => {\n if (err) reject(err)\n else resolve()\n })\n })\n },\n })\n}\n\nexport function nodeToWebReadable(nodeStream: Readable): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n nodeStream.on('data', (chunk: Buffer) => {\n controller.enqueue(new Uint8Array(chunk))\n })\n nodeStream.on('end', () => controller.close())\n nodeStream.on('error', (err) => controller.error(err))\n },\n })\n}\n","export class StderrCapture {\n private lines: string[] = []\n\n constructor(private maxLines: number = 50) {}\n\n append(chunk: string): void {\n this.lines.push(...chunk.split('\\n').filter(Boolean))\n if (this.lines.length > this.maxLines) {\n this.lines = this.lines.slice(-this.maxLines)\n }\n }\n\n getLastLines(): string {\n return this.lines.join('\\n')\n }\n}\n","import { spawn, execSync, type ChildProcess } from 'node:child_process'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { randomUUID } from 'node:crypto'\nimport { ClientSideConnection, ndJsonStream } from '@agentclientprotocol/sdk'\nimport type { Agent, Client, PromptResponse, PermissionOption as SdkPermissionOption } from '@agentclientprotocol/sdk'\nimport { nodeToWebWritable, nodeToWebReadable } from './streams.js'\nimport { StderrCapture } from './stderr-capture.js'\nimport type { AgentDefinition, AgentEvent, PermissionRequest } from './types.js'\nimport { log } from './log.js'\n\n/** Resolve an agent command to a directly executable form (avoids shell wrappers) */\nfunction resolveAgentCommand(cmd: string): { command: string; args: string[] } {\n // 1. Check local node_modules for the package's actual JS entry point\n const packageDirs = [\n path.resolve(process.cwd(), 'node_modules', '@zed-industries', cmd, 'dist', 'index.js'),\n path.resolve(process.cwd(), 'node_modules', cmd, 'dist', 'index.js'),\n ]\n for (const jsPath of packageDirs) {\n if (fs.existsSync(jsPath)) {\n return { command: process.execPath, args: [jsPath] }\n }\n }\n\n // 2. Check local .bin — if it's a JS file with shebang, run with node directly\n const localBin = path.resolve(process.cwd(), 'node_modules', '.bin', cmd)\n if (fs.existsSync(localBin)) {\n const content = fs.readFileSync(localBin, 'utf-8')\n if (content.startsWith('#!/usr/bin/env node')) {\n return { command: process.execPath, args: [localBin] }\n }\n // Shell wrapper — try to find the target JS file\n const match = content.match(/\"([^\"]+\\.js)\"/)\n if (match) {\n const target = path.resolve(path.dirname(localBin), match[1])\n if (fs.existsSync(target)) {\n return { command: process.execPath, args: [target] }\n }\n }\n }\n\n // 3. Try resolving from PATH using which\n try {\n const fullPath = execSync(`which ${cmd}`, { encoding: 'utf-8' }).trim()\n if (fullPath) {\n const content = fs.readFileSync(fullPath, 'utf-8')\n if (content.startsWith('#!/usr/bin/env node')) {\n return { command: process.execPath, args: [fullPath] }\n }\n }\n } catch {\n // which failed\n }\n\n // 4. Fallback: use command as-is\n return { command: cmd, args: [] }\n}\n\ninterface TerminalState {\n process: ChildProcess\n output: string\n exitStatus: { exitCode: number | null; signal: string | null } | null\n}\n\nexport class AgentInstance {\n private connection!: ClientSideConnection\n private child!: ChildProcess\n private stderrCapture!: StderrCapture\n private terminals: Map<string, TerminalState> = new Map()\n\n sessionId!: string\n agentName: string\n\n // Callbacks — set by core when wiring events\n onSessionUpdate: (event: AgentEvent) => void = () => {}\n onPermissionRequest: (request: PermissionRequest) => Promise<string> = async () => ''\n\n private constructor(agentName: string) {\n this.agentName = agentName\n }\n\n static async spawn(agentDef: AgentDefinition, workingDirectory: string): Promise<AgentInstance> {\n const instance = new AgentInstance(agentDef.name)\n\n // 1. Resolve command: find the actual JS entry point to avoid shell wrappers\n const resolved = resolveAgentCommand(agentDef.command)\n log.debug(`Spawning agent \"${agentDef.name}\" → ${resolved.command} ${resolved.args.join(' ')}`)\n\n // Spawn subprocess\n instance.child = spawn(resolved.command, [...resolved.args, ...agentDef.args], {\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd: workingDirectory,\n env: { ...process.env, ...agentDef.env },\n })\n\n // 2. Handle spawn errors (e.g., command not found)\n await new Promise<void>((resolve, reject) => {\n instance.child.on('error', (err) => {\n reject(new Error(`Failed to spawn agent \"${agentDef.name}\": ${err.message}. Is \"${agentDef.command}\" installed?`))\n })\n instance.child.on('spawn', () => resolve())\n })\n\n // 3. Capture stderr\n instance.stderrCapture = new StderrCapture(50)\n instance.child.stderr!.on('data', (chunk: Buffer) => {\n instance.stderrCapture.append(chunk.toString())\n })\n\n // 3. Create ACP stream\n const toAgent = nodeToWebWritable(instance.child.stdin!)\n const fromAgent = nodeToWebReadable(instance.child.stdout!)\n const stream = ndJsonStream(toAgent, fromAgent)\n\n // 4. Create ClientSideConnection\n instance.connection = new ClientSideConnection(\n (_agent: Agent): Client => instance.createClient(_agent),\n stream,\n )\n\n // 5. ACP handshake\n await instance.connection.initialize({\n protocolVersion: 1,\n clientCapabilities: {\n fs: { readTextFile: true, writeTextFile: true },\n terminal: true,\n },\n })\n\n // 6. Create session\n const response = await instance.connection.newSession({\n cwd: workingDirectory,\n mcpServers: [],\n })\n instance.sessionId = response.sessionId\n\n // 7. Crash detection\n instance.child.on('exit', (code, signal) => {\n if (code !== 0 && code !== null) {\n const stderr = instance.stderrCapture.getLastLines()\n instance.onSessionUpdate({\n type: 'error',\n message: `Agent crashed (exit code ${code})\\n${stderr}`,\n })\n }\n })\n\n instance.connection.closed.then(() => {\n // Connection closed — may be normal shutdown or crash\n log.debug('ACP connection closed for', instance.agentName)\n })\n\n log.info(`Agent \"${agentDef.name}\" spawned with session ${response.sessionId}`)\n return instance\n }\n\n // createClient — implemented in Task 6b\n private createClient(_agent: Agent): Client {\n const self = this\n const MAX_OUTPUT_BYTES = 1024 * 1024 // 1MB cap\n\n return {\n // ── Session updates ──────────────────────────────────────────────────\n async sessionUpdate(params) {\n const update = params.update\n let event: AgentEvent | null = null\n\n switch (update.sessionUpdate) {\n case 'agent_message_chunk':\n if (update.content.type === 'text') {\n event = { type: 'text', content: update.content.text }\n }\n break\n case 'agent_thought_chunk':\n if (update.content.type === 'text') {\n event = { type: 'thought', content: update.content.text }\n }\n break\n case 'tool_call':\n event = {\n type: 'tool_call',\n id: update.toolCallId,\n name: update.title,\n kind: update.kind ?? undefined,\n status: update.status ?? 'pending',\n }\n break\n case 'tool_call_update':\n event = {\n type: 'tool_update',\n id: update.toolCallId,\n status: update.status ?? 'pending',\n }\n break\n case 'plan':\n event = { type: 'plan', entries: update.entries }\n break\n case 'usage_update':\n event = {\n type: 'usage',\n tokensUsed: update.used,\n contextSize: update.size,\n cost: update.cost ?? undefined,\n }\n break\n case 'available_commands_update':\n event = { type: 'commands_update', commands: update.availableCommands }\n break\n default:\n // Unknown update type — ignore\n return\n }\n\n if (event !== null) {\n self.onSessionUpdate(event)\n }\n },\n\n // ── Permission requests ──────────────────────────────────────────────\n async requestPermission(params) {\n const permissionRequest: PermissionRequest = {\n id: params.toolCall.toolCallId,\n description: params.toolCall.title ?? params.toolCall.toolCallId,\n options: params.options.map((opt: SdkPermissionOption) => ({\n id: opt.optionId,\n label: opt.name,\n isAllow: opt.kind === 'allow_once' || opt.kind === 'allow_always',\n })),\n }\n\n const selectedOptionId = await self.onPermissionRequest(permissionRequest)\n return {\n outcome: { outcome: 'selected' as const, optionId: selectedOptionId },\n }\n },\n\n // ── File operations ──────────────────────────────────────────────────\n async readTextFile(params) {\n const content = await fs.promises.readFile(params.path, 'utf-8')\n return { content }\n },\n\n async writeTextFile(params) {\n await fs.promises.mkdir(path.dirname(params.path), { recursive: true })\n await fs.promises.writeFile(params.path, params.content, 'utf-8')\n return {}\n },\n\n // ── Terminal operations ──────────────────────────────────────────────\n async createTerminal(params) {\n const terminalId = randomUUID()\n const args = params.args ?? []\n const env: Record<string, string> = {}\n for (const ev of params.env ?? []) {\n env[ev.name] = ev.value\n }\n\n const childProcess = spawn(params.command, args, {\n cwd: params.cwd ?? undefined,\n env: { ...process.env, ...env },\n shell: false,\n })\n\n const state: TerminalState = {\n process: childProcess,\n output: '',\n exitStatus: null,\n }\n self.terminals.set(terminalId, state)\n\n const outputByteLimit = params.outputByteLimit ?? MAX_OUTPUT_BYTES\n\n const appendOutput = (chunk: string) => {\n state.output += chunk\n // Truncate from the beginning if over limit\n const bytes = Buffer.byteLength(state.output, 'utf-8')\n if (bytes > outputByteLimit) {\n // Find truncation point at character boundary\n const excess = bytes - outputByteLimit\n state.output = state.output.slice(excess)\n }\n }\n\n childProcess.stdout?.on('data', (chunk: Buffer) => appendOutput(chunk.toString()))\n childProcess.stderr?.on('data', (chunk: Buffer) => appendOutput(chunk.toString()))\n\n childProcess.on('exit', (code, signal) => {\n state.exitStatus = { exitCode: code, signal }\n })\n\n return { terminalId }\n },\n\n async terminalOutput(params) {\n const state = self.terminals.get(params.terminalId)\n if (!state) {\n throw new Error(`Terminal not found: ${params.terminalId}`)\n }\n return {\n output: state.output,\n truncated: false,\n exitStatus: state.exitStatus\n ? { exitCode: state.exitStatus.exitCode, signal: state.exitStatus.signal }\n : undefined,\n }\n },\n\n async waitForTerminalExit(params) {\n const state = self.terminals.get(params.terminalId)\n if (!state) {\n throw new Error(`Terminal not found: ${params.terminalId}`)\n }\n if (state.exitStatus !== null) {\n return { exitCode: state.exitStatus.exitCode, signal: state.exitStatus.signal }\n }\n return new Promise((resolve) => {\n state.process.on('exit', (code, signal) => {\n resolve({ exitCode: code, signal })\n })\n })\n },\n\n async killTerminal(params) {\n const state = self.terminals.get(params.terminalId)\n if (!state) {\n throw new Error(`Terminal not found: ${params.terminalId}`)\n }\n state.process.kill('SIGTERM')\n return {}\n },\n\n async releaseTerminal(params) {\n const state = self.terminals.get(params.terminalId)\n if (!state) {\n return\n }\n state.process.kill('SIGKILL')\n self.terminals.delete(params.terminalId)\n },\n }\n }\n\n async prompt(text: string): Promise<PromptResponse> {\n return this.connection.prompt({\n sessionId: this.sessionId,\n prompt: [{ type: 'text', text }],\n })\n }\n\n async cancel(): Promise<void> {\n await this.connection.cancel({ sessionId: this.sessionId })\n }\n\n async destroy(): Promise<void> {\n // Cleanup terminals\n for (const [, t] of this.terminals) {\n t.process.kill('SIGKILL')\n }\n this.terminals.clear()\n\n // Kill agent subprocess\n this.child.kill('SIGTERM')\n setTimeout(() => {\n if (!this.child.killed) this.child.kill('SIGKILL')\n }, 10_000)\n }\n}\n","import type { Config } from './config.js'\nimport type { AgentDefinition } from './types.js'\nimport { AgentInstance } from './agent-instance.js'\n\nexport class AgentManager {\n constructor(private config: Config) {}\n\n getAvailableAgents(): AgentDefinition[] {\n return Object.entries(this.config.agents).map(([name, cfg]) => ({\n name,\n command: cfg.command,\n args: cfg.args,\n workingDirectory: cfg.workingDirectory,\n env: cfg.env,\n }))\n }\n\n getAgent(name: string): AgentDefinition | undefined {\n const cfg = this.config.agents[name]\n if (!cfg) return undefined\n return { name, ...cfg }\n }\n\n async spawn(agentName: string, workingDirectory: string): Promise<AgentInstance> {\n const agentDef = this.getAgent(agentName)\n if (!agentDef) throw new Error(`Agent \"${agentName}\" not found in config`)\n return AgentInstance.spawn(agentDef, workingDirectory)\n }\n}\n","import { nanoid } from 'nanoid'\nimport type { AgentInstance } from './agent-instance.js'\nimport type { ChannelAdapter } from './channel.js'\nimport type { SessionStatus } from './types.js'\nimport { log } from './log.js'\n\nexport class Session {\n id: string\n channelId: string\n threadId: string = ''\n agentName: string\n workingDirectory: string\n agentInstance: AgentInstance\n status: SessionStatus = 'initializing'\n name?: string\n promptQueue: string[] = []\n promptRunning: boolean = false\n createdAt: Date = new Date()\n adapter?: ChannelAdapter // Set by wireSessionEvents for renaming\n pendingPermission?: { requestId: string; resolve: (optionId: string) => void }\n\n constructor(opts: {\n id?: string\n channelId: string\n agentName: string\n workingDirectory: string\n agentInstance: AgentInstance\n }) {\n this.id = opts.id || nanoid(12)\n this.channelId = opts.channelId\n this.agentName = opts.agentName\n this.workingDirectory = opts.workingDirectory\n this.agentInstance = opts.agentInstance\n }\n\n async enqueuePrompt(text: string): Promise<void> {\n if (this.promptRunning) {\n this.promptQueue.push(text)\n log.debug(`Prompt queued for session ${this.id} (${this.promptQueue.length} in queue)`)\n return\n }\n await this.runPrompt(text)\n }\n\n private async runPrompt(text: string): Promise<void> {\n this.promptRunning = true\n this.status = 'active'\n\n try {\n await this.agentInstance.prompt(text)\n\n // Auto-name after first user prompt\n if (!this.name) {\n await this.autoName()\n }\n } catch (err) {\n this.status = 'error'\n log.error(`Prompt failed for session ${this.id}:`, err)\n } finally {\n this.promptRunning = false\n\n // Process next queued prompt\n if (this.promptQueue.length > 0) {\n const next = this.promptQueue.shift()!\n await this.runPrompt(next)\n }\n }\n }\n\n // NOTE: This injects a summary prompt into the agent's conversation history.\n // Known Phase 1 limitation — the agent sees this prompt in its context.\n private async autoName(): Promise<void> {\n let title = ''\n const prevHandler = this.agentInstance.onSessionUpdate\n this.agentInstance.onSessionUpdate = (event) => {\n if (event.type === 'text') title += event.content\n }\n\n try {\n await this.agentInstance.prompt(\n 'Summarize this conversation in max 5 words for a topic title. Reply ONLY with the title, nothing else.'\n )\n this.name = title.trim().slice(0, 50)\n\n // Rename the topic on the channel\n if (this.adapter && this.name) {\n await this.adapter.renameSessionThread(this.id, this.name)\n }\n } catch {\n this.name = `Session ${this.id.slice(0, 6)}`\n } finally {\n this.agentInstance.onSessionUpdate = prevHandler\n }\n }\n\n async cancel(): Promise<void> {\n this.status = 'cancelled'\n await this.agentInstance.cancel()\n }\n\n async destroy(): Promise<void> {\n await this.agentInstance.destroy()\n }\n}\n","import type { AgentManager } from './agent-manager.js'\nimport { Session } from './session.js'\n\nexport class SessionManager {\n private sessions: Map<string, Session> = new Map()\n\n async createSession(\n channelId: string,\n agentName: string,\n workingDirectory: string,\n agentManager: AgentManager,\n ): Promise<Session> {\n const agentInstance = await agentManager.spawn(agentName, workingDirectory)\n const session = new Session({ channelId, agentName, workingDirectory, agentInstance })\n this.sessions.set(session.id, session)\n return session\n }\n\n getSession(sessionId: string): Session | undefined {\n return this.sessions.get(sessionId)\n }\n\n getSessionByThread(channelId: string, threadId: string): Session | undefined {\n for (const session of this.sessions.values()) {\n if (session.channelId === channelId && session.threadId === threadId) {\n return session\n }\n }\n return undefined\n }\n\n async cancelSession(sessionId: string): Promise<void> {\n const session = this.sessions.get(sessionId)\n if (session) await session.cancel()\n }\n\n listSessions(channelId?: string): Session[] {\n const all = Array.from(this.sessions.values())\n if (channelId) return all.filter(s => s.channelId === channelId)\n return all\n }\n\n async destroyAll(): Promise<void> {\n for (const session of this.sessions.values()) {\n await session.destroy()\n }\n this.sessions.clear()\n }\n}\n","import type { ChannelAdapter } from './channel.js'\nimport type { NotificationMessage } from './types.js'\n\nexport class NotificationManager {\n constructor(private adapters: Map<string, ChannelAdapter>) {}\n\n async notify(channelId: string, notification: NotificationMessage): Promise<void> {\n const adapter = this.adapters.get(channelId)\n if (adapter) {\n await adapter.sendNotification(notification)\n }\n }\n\n async notifyAll(notification: NotificationMessage): Promise<void> {\n for (const adapter of this.adapters.values()) {\n await adapter.sendNotification(notification)\n }\n }\n}\n","import { ConfigManager } from './config.js'\nimport { AgentManager } from './agent-manager.js'\nimport { SessionManager } from './session-manager.js'\nimport { NotificationManager } from './notification.js'\nimport { ChannelAdapter } from './channel.js'\nimport { Session } from './session.js'\nimport type { IncomingMessage, AgentEvent, OutgoingMessage, PermissionRequest } from './types.js'\nimport { log } from './log.js'\n\nexport class OpenACPCore {\n configManager: ConfigManager\n agentManager: AgentManager\n sessionManager: SessionManager\n notificationManager: NotificationManager\n adapters: Map<string, ChannelAdapter> = new Map()\n\n constructor(configManager: ConfigManager) {\n this.configManager = configManager\n const config = configManager.get()\n this.agentManager = new AgentManager(config)\n this.sessionManager = new SessionManager()\n this.notificationManager = new NotificationManager(this.adapters)\n }\n\n registerAdapter(name: string, adapter: ChannelAdapter): void {\n this.adapters.set(name, adapter)\n }\n\n async start(): Promise<void> {\n for (const adapter of this.adapters.values()) {\n await adapter.start()\n }\n }\n\n async stop(): Promise<void> {\n // 1. Notify users\n try {\n await this.notificationManager.notifyAll({\n sessionId: 'system',\n type: 'error',\n summary: 'OpenACP is shutting down',\n })\n } catch { /* best effort */ }\n\n // 2. Destroy all sessions\n await this.sessionManager.destroyAll()\n\n // 3. Stop adapters\n for (const adapter of this.adapters.values()) {\n await adapter.stop()\n }\n }\n\n // --- Message Routing ---\n\n async handleMessage(message: IncomingMessage): Promise<void> {\n const config = this.configManager.get()\n\n // Security: check allowed user IDs\n if (config.security.allowedUserIds.length > 0) {\n if (!config.security.allowedUserIds.includes(message.userId)) return\n }\n\n // Check concurrent session limit\n const activeSessions = this.sessionManager.listSessions()\n .filter(s => s.status === 'active' || s.status === 'initializing')\n if (activeSessions.length >= config.security.maxConcurrentSessions) {\n const adapter = this.adapters.get(message.channelId)\n if (adapter) {\n await adapter.sendMessage('system', {\n type: 'error',\n text: `Max concurrent sessions (${config.security.maxConcurrentSessions}) reached. Cancel a session first.`,\n })\n }\n return\n }\n\n // Find session by thread\n const session = this.sessionManager.getSessionByThread(message.channelId, message.threadId)\n if (!session) return\n\n // Forward to session\n await session.enqueuePrompt(message.text)\n }\n\n async handleNewSession(\n channelId: string,\n agentName?: string,\n workspacePath?: string,\n ): Promise<Session> {\n const config = this.configManager.get()\n const resolvedAgent = agentName || config.defaultAgent\n const resolvedWorkspace = this.configManager.resolveWorkspace(\n workspacePath || config.agents[resolvedAgent]?.workingDirectory\n )\n\n const session = await this.sessionManager.createSession(\n channelId, resolvedAgent, resolvedWorkspace, this.agentManager\n )\n\n // Wire events\n const adapter = this.adapters.get(channelId)\n if (adapter) {\n this.wireSessionEvents(session, adapter)\n }\n\n return session\n }\n\n async handleNewChat(\n channelId: string,\n currentThreadId: string,\n ): Promise<Session | null> {\n const currentSession = this.sessionManager.getSessionByThread(channelId, currentThreadId)\n if (!currentSession) return null\n\n return this.handleNewSession(\n channelId,\n currentSession.agentName,\n currentSession.workingDirectory,\n )\n }\n\n // --- Event Wiring ---\n\n private toOutgoingMessage(event: AgentEvent): OutgoingMessage {\n switch (event.type) {\n case 'text':\n return { type: 'text', text: event.content }\n case 'thought':\n return { type: 'thought', text: event.content }\n case 'tool_call':\n return { type: 'tool_call', text: event.name, metadata: { id: event.id, kind: event.kind, status: event.status, content: event.content, locations: event.locations } }\n case 'tool_update':\n return { type: 'tool_update', text: '', metadata: { id: event.id, status: event.status, content: event.content } }\n case 'plan':\n return { type: 'plan', text: '', metadata: { entries: event.entries } }\n case 'usage':\n return { type: 'usage', text: '', metadata: { tokensUsed: event.tokensUsed, contextSize: event.contextSize, cost: event.cost } }\n case 'commands_update':\n // Log but don't surface to user (Phase 3 feature)\n log.debug('Commands update:', event.commands)\n return { type: 'text', text: '' } // no-op for now\n default:\n return { type: 'text', text: '' }\n }\n }\n\n // Public — adapters call this for assistant session wiring\n wireSessionEvents(session: Session, adapter: ChannelAdapter): void {\n // Set adapter reference for autoName → renameSessionThread\n session.adapter = adapter\n\n session.agentInstance.onSessionUpdate = (event: AgentEvent) => {\n switch (event.type) {\n case 'text':\n case 'thought':\n case 'tool_call':\n case 'tool_update':\n case 'plan':\n case 'usage':\n adapter.sendMessage(session.id, this.toOutgoingMessage(event))\n break\n\n case 'session_end':\n session.status = 'finished'\n adapter.sendMessage(session.id, { type: 'session_end', text: `Done (${event.reason})` })\n this.notificationManager.notify(session.channelId, {\n sessionId: session.id,\n sessionName: session.name,\n type: 'completed',\n summary: `Session \"${session.name || session.id}\" completed`,\n })\n break\n\n case 'error':\n adapter.sendMessage(session.id, { type: 'error', text: event.message })\n this.notificationManager.notify(session.channelId, {\n sessionId: session.id,\n sessionName: session.name,\n type: 'error',\n summary: event.message,\n })\n break\n\n case 'commands_update':\n log.debug('Commands available:', event.commands)\n break\n }\n }\n\n session.agentInstance.onPermissionRequest = async (request: PermissionRequest) => {\n // Send permission UI to session topic\n await adapter.sendPermissionRequest(session.id, request)\n\n // Send notification with deep link\n await this.notificationManager.notify(session.channelId, {\n sessionId: session.id,\n sessionName: session.name,\n type: 'permission',\n summary: request.description,\n })\n\n // Wait for user response — adapter resolves this promise\n return new Promise<string>((resolve) => {\n session.pendingPermission = { requestId: request.id, resolve }\n })\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// packages/core/src/log.ts
|
|
2
|
+
var log = {
|
|
3
|
+
info: (...args) => console.log((/* @__PURE__ */ new Date()).toISOString(), "[INFO]", ...args),
|
|
4
|
+
warn: (...args) => console.warn((/* @__PURE__ */ new Date()).toISOString(), "[WARN]", ...args),
|
|
5
|
+
error: (...args) => console.error((/* @__PURE__ */ new Date()).toISOString(), "[ERROR]", ...args),
|
|
6
|
+
debug: (...args) => {
|
|
7
|
+
if (process.env.OPENACP_DEBUG) console.log((/* @__PURE__ */ new Date()).toISOString(), "[DEBUG]", ...args);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// packages/core/src/config.ts
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import * as fs from "fs";
|
|
14
|
+
import * as path from "path";
|
|
15
|
+
import * as os from "os";
|
|
16
|
+
var BaseChannelSchema = z.object({
|
|
17
|
+
enabled: z.boolean().default(false),
|
|
18
|
+
adapter: z.string().optional()
|
|
19
|
+
// package name for plugin adapters
|
|
20
|
+
}).passthrough();
|
|
21
|
+
var PLUGINS_DIR = path.join(os.homedir(), ".openacp", "plugins");
|
|
22
|
+
var AgentSchema = z.object({
|
|
23
|
+
command: z.string(),
|
|
24
|
+
args: z.array(z.string()).default([]),
|
|
25
|
+
workingDirectory: z.string().optional(),
|
|
26
|
+
env: z.record(z.string(), z.string()).default({})
|
|
27
|
+
});
|
|
28
|
+
var ConfigSchema = z.object({
|
|
29
|
+
channels: z.record(z.string(), BaseChannelSchema),
|
|
30
|
+
agents: z.record(z.string(), AgentSchema),
|
|
31
|
+
defaultAgent: z.string(),
|
|
32
|
+
workspace: z.object({
|
|
33
|
+
baseDir: z.string().default("~/openacp-workspace")
|
|
34
|
+
}).default({}),
|
|
35
|
+
security: z.object({
|
|
36
|
+
allowedUserIds: z.array(z.string()).default([]),
|
|
37
|
+
maxConcurrentSessions: z.number().default(5),
|
|
38
|
+
sessionTimeoutMinutes: z.number().default(60)
|
|
39
|
+
}).default({})
|
|
40
|
+
});
|
|
41
|
+
function expandHome(p) {
|
|
42
|
+
if (p.startsWith("~")) {
|
|
43
|
+
return path.join(os.homedir(), p.slice(1));
|
|
44
|
+
}
|
|
45
|
+
return p;
|
|
46
|
+
}
|
|
47
|
+
var DEFAULT_CONFIG = {
|
|
48
|
+
channels: {
|
|
49
|
+
telegram: {
|
|
50
|
+
enabled: false,
|
|
51
|
+
botToken: "YOUR_BOT_TOKEN_HERE",
|
|
52
|
+
chatId: 0,
|
|
53
|
+
notificationTopicId: null,
|
|
54
|
+
assistantTopicId: null
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
agents: {
|
|
58
|
+
claude: { command: "claude-agent-acp", args: [], env: {} },
|
|
59
|
+
codex: { command: "codex", args: ["--acp"], env: {} }
|
|
60
|
+
},
|
|
61
|
+
defaultAgent: "claude",
|
|
62
|
+
workspace: { baseDir: "~/openacp-workspace" },
|
|
63
|
+
security: { allowedUserIds: [], maxConcurrentSessions: 5, sessionTimeoutMinutes: 60 }
|
|
64
|
+
};
|
|
65
|
+
var ConfigManager = class {
|
|
66
|
+
config;
|
|
67
|
+
configPath;
|
|
68
|
+
constructor() {
|
|
69
|
+
this.configPath = process.env.OPENACP_CONFIG_PATH || expandHome("~/.openacp/config.json");
|
|
70
|
+
}
|
|
71
|
+
async load() {
|
|
72
|
+
const dir = path.dirname(this.configPath);
|
|
73
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
74
|
+
if (!fs.existsSync(this.configPath)) {
|
|
75
|
+
fs.writeFileSync(this.configPath, JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
76
|
+
log.info(`Config created at ${this.configPath}`);
|
|
77
|
+
log.info("Please edit it with your Telegram bot token and chat ID, then restart.");
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
const raw = JSON.parse(fs.readFileSync(this.configPath, "utf-8"));
|
|
81
|
+
this.applyEnvOverrides(raw);
|
|
82
|
+
const result = ConfigSchema.safeParse(raw);
|
|
83
|
+
if (!result.success) {
|
|
84
|
+
log.error("Config validation failed:");
|
|
85
|
+
for (const issue of result.error.issues) {
|
|
86
|
+
log.error(` ${issue.path.join(".")}: ${issue.message}`);
|
|
87
|
+
}
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
this.config = result.data;
|
|
91
|
+
}
|
|
92
|
+
get() {
|
|
93
|
+
return this.config;
|
|
94
|
+
}
|
|
95
|
+
async save(updates) {
|
|
96
|
+
const raw = JSON.parse(fs.readFileSync(this.configPath, "utf-8"));
|
|
97
|
+
this.deepMerge(raw, updates);
|
|
98
|
+
fs.writeFileSync(this.configPath, JSON.stringify(raw, null, 2));
|
|
99
|
+
const result = ConfigSchema.safeParse(raw);
|
|
100
|
+
if (result.success) {
|
|
101
|
+
this.config = result.data;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
resolveWorkspace(input) {
|
|
105
|
+
if (!input) {
|
|
106
|
+
const resolved2 = expandHome(this.config.workspace.baseDir);
|
|
107
|
+
fs.mkdirSync(resolved2, { recursive: true });
|
|
108
|
+
return resolved2;
|
|
109
|
+
}
|
|
110
|
+
if (input.startsWith("/") || input.startsWith("~")) {
|
|
111
|
+
const resolved2 = expandHome(input);
|
|
112
|
+
fs.mkdirSync(resolved2, { recursive: true });
|
|
113
|
+
return resolved2;
|
|
114
|
+
}
|
|
115
|
+
const name = input.toLowerCase();
|
|
116
|
+
const resolved = path.join(expandHome(this.config.workspace.baseDir), name);
|
|
117
|
+
fs.mkdirSync(resolved, { recursive: true });
|
|
118
|
+
return resolved;
|
|
119
|
+
}
|
|
120
|
+
applyEnvOverrides(raw) {
|
|
121
|
+
const overrides = [
|
|
122
|
+
["OPENACP_TELEGRAM_BOT_TOKEN", ["channels", "telegram", "botToken"]],
|
|
123
|
+
["OPENACP_TELEGRAM_CHAT_ID", ["channels", "telegram", "chatId"]],
|
|
124
|
+
["OPENACP_DEFAULT_AGENT", ["defaultAgent"]]
|
|
125
|
+
];
|
|
126
|
+
for (const [envVar, configPath] of overrides) {
|
|
127
|
+
const value = process.env[envVar];
|
|
128
|
+
if (value !== void 0) {
|
|
129
|
+
let target = raw;
|
|
130
|
+
for (let i = 0; i < configPath.length - 1; i++) {
|
|
131
|
+
if (!target[configPath[i]]) target[configPath[i]] = {};
|
|
132
|
+
target = target[configPath[i]];
|
|
133
|
+
}
|
|
134
|
+
const key = configPath[configPath.length - 1];
|
|
135
|
+
target[key] = key === "chatId" ? Number(value) : value;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
deepMerge(target, source) {
|
|
140
|
+
for (const key of Object.keys(source)) {
|
|
141
|
+
if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
|
|
142
|
+
if (!target[key]) target[key] = {};
|
|
143
|
+
this.deepMerge(target[key], source[key]);
|
|
144
|
+
} else {
|
|
145
|
+
target[key] = source[key];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// packages/core/src/plugin-manager.ts
|
|
152
|
+
import { execSync } from "child_process";
|
|
153
|
+
import * as fs2 from "fs";
|
|
154
|
+
import * as path2 from "path";
|
|
155
|
+
import { createRequire } from "module";
|
|
156
|
+
function ensurePluginsDir() {
|
|
157
|
+
fs2.mkdirSync(PLUGINS_DIR, { recursive: true });
|
|
158
|
+
const pkgPath = path2.join(PLUGINS_DIR, "package.json");
|
|
159
|
+
if (!fs2.existsSync(pkgPath)) {
|
|
160
|
+
fs2.writeFileSync(pkgPath, JSON.stringify({ name: "openacp-plugins", private: true, dependencies: {} }, null, 2));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function installPlugin(packageName) {
|
|
164
|
+
ensurePluginsDir();
|
|
165
|
+
log.info(`Installing ${packageName}...`);
|
|
166
|
+
execSync(`npm install ${packageName} --prefix "${PLUGINS_DIR}"`, { stdio: "inherit" });
|
|
167
|
+
log.info(`${packageName} installed successfully.`);
|
|
168
|
+
}
|
|
169
|
+
function uninstallPlugin(packageName) {
|
|
170
|
+
ensurePluginsDir();
|
|
171
|
+
log.info(`Uninstalling ${packageName}...`);
|
|
172
|
+
execSync(`npm uninstall ${packageName} --prefix "${PLUGINS_DIR}"`, { stdio: "inherit" });
|
|
173
|
+
log.info(`${packageName} uninstalled.`);
|
|
174
|
+
}
|
|
175
|
+
function listPlugins() {
|
|
176
|
+
const pkgPath = path2.join(PLUGINS_DIR, "package.json");
|
|
177
|
+
if (!fs2.existsSync(pkgPath)) return {};
|
|
178
|
+
const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
|
|
179
|
+
return pkg.dependencies || {};
|
|
180
|
+
}
|
|
181
|
+
async function loadAdapterFactory(packageName) {
|
|
182
|
+
try {
|
|
183
|
+
const require2 = createRequire(path2.join(PLUGINS_DIR, "package.json"));
|
|
184
|
+
const resolved = require2.resolve(packageName);
|
|
185
|
+
const mod = await import(resolved);
|
|
186
|
+
const factory = mod.adapterFactory || mod.default;
|
|
187
|
+
if (!factory || typeof factory.createAdapter !== "function") {
|
|
188
|
+
log.error(`Plugin ${packageName} does not export a valid AdapterFactory (needs .createAdapter())`);
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
return factory;
|
|
192
|
+
} catch (err) {
|
|
193
|
+
log.error(`Failed to load plugin ${packageName}:`, err);
|
|
194
|
+
log.error(`Run: npx openacp install ${packageName}`);
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export {
|
|
200
|
+
log,
|
|
201
|
+
PLUGINS_DIR,
|
|
202
|
+
expandHome,
|
|
203
|
+
ConfigManager,
|
|
204
|
+
installPlugin,
|
|
205
|
+
uninstallPlugin,
|
|
206
|
+
listPlugins,
|
|
207
|
+
loadAdapterFactory
|
|
208
|
+
};
|
|
209
|
+
//# sourceMappingURL=chunk-FLAM2AON.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../packages/core/src/log.ts","../../packages/core/src/config.ts","../../packages/core/src/plugin-manager.ts"],"sourcesContent":["export const log = {\n info: (...args: unknown[]) => console.log(new Date().toISOString(), '[INFO]', ...args),\n warn: (...args: unknown[]) => console.warn(new Date().toISOString(), '[WARN]', ...args),\n error: (...args: unknown[]) => console.error(new Date().toISOString(), '[ERROR]', ...args),\n debug: (...args: unknown[]) => {\n if (process.env.OPENACP_DEBUG) console.log(new Date().toISOString(), '[DEBUG]', ...args)\n },\n}\n","import { z } from 'zod'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport * as os from 'node:os'\nimport { log } from './log.js'\n\nconst BaseChannelSchema = z.object({\n enabled: z.boolean().default(false),\n adapter: z.string().optional(), // package name for plugin adapters\n}).passthrough()\n\nexport const PLUGINS_DIR = path.join(os.homedir(), '.openacp', 'plugins')\n\nconst AgentSchema = z.object({\n command: z.string(),\n args: z.array(z.string()).default([]),\n workingDirectory: z.string().optional(),\n env: z.record(z.string(), z.string()).default({}),\n})\n\nexport const ConfigSchema = z.object({\n channels: z.record(z.string(), BaseChannelSchema),\n agents: z.record(z.string(), AgentSchema),\n defaultAgent: z.string(),\n workspace: z.object({\n baseDir: z.string().default('~/openacp-workspace'),\n }).default({}),\n security: z.object({\n allowedUserIds: z.array(z.string()).default([]),\n maxConcurrentSessions: z.number().default(5),\n sessionTimeoutMinutes: z.number().default(60),\n }).default({}),\n})\n\nexport type Config = z.infer<typeof ConfigSchema>\n\nexport function expandHome(p: string): string {\n if (p.startsWith('~')) {\n return path.join(os.homedir(), p.slice(1))\n }\n return p\n}\n\nconst DEFAULT_CONFIG = {\n channels: {\n telegram: {\n enabled: false,\n botToken: \"YOUR_BOT_TOKEN_HERE\",\n chatId: 0,\n notificationTopicId: null,\n assistantTopicId: null\n }\n },\n agents: {\n claude: { command: \"claude-agent-acp\", args: [], env: {} },\n codex: { command: \"codex\", args: [\"--acp\"], env: {} }\n },\n defaultAgent: \"claude\",\n workspace: { baseDir: \"~/openacp-workspace\" },\n security: { allowedUserIds: [], maxConcurrentSessions: 5, sessionTimeoutMinutes: 60 }\n}\n\nexport class ConfigManager {\n private config!: Config\n private configPath: string\n\n constructor() {\n this.configPath = process.env.OPENACP_CONFIG_PATH || expandHome('~/.openacp/config.json')\n }\n\n async load(): Promise<void> {\n // 1. Ensure directory exists\n const dir = path.dirname(this.configPath)\n fs.mkdirSync(dir, { recursive: true })\n\n // 2. If config file doesn't exist, create default\n if (!fs.existsSync(this.configPath)) {\n fs.writeFileSync(this.configPath, JSON.stringify(DEFAULT_CONFIG, null, 2))\n log.info(`Config created at ${this.configPath}`)\n log.info('Please edit it with your Telegram bot token and chat ID, then restart.')\n process.exit(1)\n }\n\n // 3. Read and parse\n const raw = JSON.parse(fs.readFileSync(this.configPath, 'utf-8'))\n\n // 4. Apply env var overrides\n this.applyEnvOverrides(raw)\n\n // 5. Validate with Zod\n const result = ConfigSchema.safeParse(raw)\n if (!result.success) {\n log.error('Config validation failed:')\n for (const issue of result.error.issues) {\n log.error(` ${issue.path.join('.')}: ${issue.message}`)\n }\n process.exit(1)\n }\n this.config = result.data\n }\n\n get(): Config {\n return this.config\n }\n\n async save(updates: Record<string, unknown>): Promise<void> {\n // Read current file, merge updates, write back\n const raw = JSON.parse(fs.readFileSync(this.configPath, 'utf-8'))\n this.deepMerge(raw, updates)\n fs.writeFileSync(this.configPath, JSON.stringify(raw, null, 2))\n // Re-validate and update in-memory config\n const result = ConfigSchema.safeParse(raw)\n if (result.success) {\n this.config = result.data\n }\n }\n\n resolveWorkspace(input?: string): string {\n if (!input) {\n const resolved = expandHome(this.config.workspace.baseDir)\n fs.mkdirSync(resolved, { recursive: true })\n return resolved\n }\n if (input.startsWith('/') || input.startsWith('~')) {\n const resolved = expandHome(input)\n fs.mkdirSync(resolved, { recursive: true })\n return resolved\n }\n // Named workspace → lowercase, under baseDir\n const name = input.toLowerCase()\n const resolved = path.join(expandHome(this.config.workspace.baseDir), name)\n fs.mkdirSync(resolved, { recursive: true })\n return resolved\n }\n\n private applyEnvOverrides(raw: Record<string, unknown>): void {\n const overrides: [string, string[]][] = [\n ['OPENACP_TELEGRAM_BOT_TOKEN', ['channels', 'telegram', 'botToken']],\n ['OPENACP_TELEGRAM_CHAT_ID', ['channels', 'telegram', 'chatId']],\n ['OPENACP_DEFAULT_AGENT', ['defaultAgent']],\n ]\n for (const [envVar, configPath] of overrides) {\n const value = process.env[envVar]\n if (value !== undefined) {\n let target = raw as Record<string, any>\n for (let i = 0; i < configPath.length - 1; i++) {\n if (!target[configPath[i]]) target[configPath[i]] = {}\n target = target[configPath[i]]\n }\n const key = configPath[configPath.length - 1]\n // Convert chatId to number\n target[key] = key === 'chatId' ? Number(value) : value\n }\n }\n }\n\n private deepMerge(target: Record<string, any>, source: Record<string, any>): void {\n for (const key of Object.keys(source)) {\n if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {\n if (!target[key]) target[key] = {}\n this.deepMerge(target[key], source[key])\n } else {\n target[key] = source[key]\n }\n }\n }\n}\n","import { execSync } from 'node:child_process'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { createRequire } from 'node:module'\nimport { PLUGINS_DIR } from './config.js'\nimport { log } from './log.js'\nimport type { ChannelAdapter } from './channel.js'\n\nexport interface AdapterFactory {\n name: string\n createAdapter(core: any, config: any): ChannelAdapter\n}\n\nfunction ensurePluginsDir(): void {\n fs.mkdirSync(PLUGINS_DIR, { recursive: true })\n const pkgPath = path.join(PLUGINS_DIR, 'package.json')\n if (!fs.existsSync(pkgPath)) {\n fs.writeFileSync(pkgPath, JSON.stringify({ name: 'openacp-plugins', private: true, dependencies: {} }, null, 2))\n }\n}\n\nexport function installPlugin(packageName: string): void {\n ensurePluginsDir()\n log.info(`Installing ${packageName}...`)\n execSync(`npm install ${packageName} --prefix \"${PLUGINS_DIR}\"`, { stdio: 'inherit' })\n log.info(`${packageName} installed successfully.`)\n}\n\nexport function uninstallPlugin(packageName: string): void {\n ensurePluginsDir()\n log.info(`Uninstalling ${packageName}...`)\n execSync(`npm uninstall ${packageName} --prefix \"${PLUGINS_DIR}\"`, { stdio: 'inherit' })\n log.info(`${packageName} uninstalled.`)\n}\n\nexport function listPlugins(): Record<string, string> {\n const pkgPath = path.join(PLUGINS_DIR, 'package.json')\n if (!fs.existsSync(pkgPath)) return {}\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n return pkg.dependencies || {}\n}\n\nexport async function loadAdapterFactory(packageName: string): Promise<AdapterFactory | null> {\n try {\n const require = createRequire(path.join(PLUGINS_DIR, 'package.json'))\n const resolved = require.resolve(packageName)\n const mod = await import(resolved)\n\n // Plugin must export `adapterFactory` or default export conforming to AdapterFactory\n const factory: AdapterFactory | undefined = mod.adapterFactory || mod.default\n if (!factory || typeof factory.createAdapter !== 'function') {\n log.error(`Plugin ${packageName} does not export a valid AdapterFactory (needs .createAdapter())`)\n return null\n }\n return factory\n } catch (err) {\n log.error(`Failed to load plugin ${packageName}:`, err)\n log.error(`Run: npx openacp install ${packageName}`)\n return null\n }\n}\n"],"mappings":";AAAO,IAAM,MAAM;AAAA,EACjB,MAAM,IAAI,SAAoB,QAAQ,KAAI,oBAAI,KAAK,GAAE,YAAY,GAAG,UAAU,GAAG,IAAI;AAAA,EACrF,MAAM,IAAI,SAAoB,QAAQ,MAAK,oBAAI,KAAK,GAAE,YAAY,GAAG,UAAU,GAAG,IAAI;AAAA,EACtF,OAAO,IAAI,SAAoB,QAAQ,OAAM,oBAAI,KAAK,GAAE,YAAY,GAAG,WAAW,GAAG,IAAI;AAAA,EACzF,OAAO,IAAI,SAAoB;AAC7B,QAAI,QAAQ,IAAI,cAAe,SAAQ,KAAI,oBAAI,KAAK,GAAE,YAAY,GAAG,WAAW,GAAG,IAAI;AAAA,EACzF;AACF;;;ACPA,SAAS,SAAS;AAClB,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,YAAY,QAAQ;AAGpB,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACjC,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAClC,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA;AAC/B,CAAC,EAAE,YAAY;AAER,IAAM,cAAmB,UAAQ,WAAQ,GAAG,YAAY,SAAS;AAExE,IAAM,cAAc,EAAE,OAAO;AAAA,EAC3B,SAAS,EAAE,OAAO;AAAA,EAClB,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACpC,kBAAkB,EAAE,OAAO,EAAE,SAAS;AAAA,EACtC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC;AAEM,IAAM,eAAe,EAAE,OAAO;AAAA,EACnC,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,iBAAiB;AAAA,EAChD,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,WAAW;AAAA,EACxC,cAAc,EAAE,OAAO;AAAA,EACvB,WAAW,EAAE,OAAO;AAAA,IAClB,SAAS,EAAE,OAAO,EAAE,QAAQ,qBAAqB;AAAA,EACnD,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACb,UAAU,EAAE,OAAO;AAAA,IACjB,gBAAgB,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,IAC9C,uBAAuB,EAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,IAC3C,uBAAuB,EAAE,OAAO,EAAE,QAAQ,EAAE;AAAA,EAC9C,CAAC,EAAE,QAAQ,CAAC,CAAC;AACf,CAAC;AAIM,SAAS,WAAW,GAAmB;AAC5C,MAAI,EAAE,WAAW,GAAG,GAAG;AACrB,WAAY,UAAQ,WAAQ,GAAG,EAAE,MAAM,CAAC,CAAC;AAAA,EAC3C;AACA,SAAO;AACT;AAEA,IAAM,iBAAiB;AAAA,EACrB,UAAU;AAAA,IACR,UAAU;AAAA,MACR,SAAS;AAAA,MACT,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,qBAAqB;AAAA,MACrB,kBAAkB;AAAA,IACpB;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN,QAAQ,EAAE,SAAS,oBAAoB,MAAM,CAAC,GAAG,KAAK,CAAC,EAAE;AAAA,IACzD,OAAO,EAAE,SAAS,SAAS,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC,EAAE;AAAA,EACtD;AAAA,EACA,cAAc;AAAA,EACd,WAAW,EAAE,SAAS,sBAAsB;AAAA,EAC5C,UAAU,EAAE,gBAAgB,CAAC,GAAG,uBAAuB,GAAG,uBAAuB,GAAG;AACtF;AAEO,IAAM,gBAAN,MAAoB;AAAA,EACjB;AAAA,EACA;AAAA,EAER,cAAc;AACZ,SAAK,aAAa,QAAQ,IAAI,uBAAuB,WAAW,wBAAwB;AAAA,EAC1F;AAAA,EAEA,MAAM,OAAsB;AAE1B,UAAM,MAAW,aAAQ,KAAK,UAAU;AACxC,IAAG,aAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAGrC,QAAI,CAAI,cAAW,KAAK,UAAU,GAAG;AACnC,MAAG,iBAAc,KAAK,YAAY,KAAK,UAAU,gBAAgB,MAAM,CAAC,CAAC;AACzE,UAAI,KAAK,qBAAqB,KAAK,UAAU,EAAE;AAC/C,UAAI,KAAK,wEAAwE;AACjF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAGA,UAAM,MAAM,KAAK,MAAS,gBAAa,KAAK,YAAY,OAAO,CAAC;AAGhE,SAAK,kBAAkB,GAAG;AAG1B,UAAM,SAAS,aAAa,UAAU,GAAG;AACzC,QAAI,CAAC,OAAO,SAAS;AACnB,UAAI,MAAM,2BAA2B;AACrC,iBAAW,SAAS,OAAO,MAAM,QAAQ;AACvC,YAAI,MAAM,KAAK,MAAM,KAAK,KAAK,GAAG,CAAC,KAAK,MAAM,OAAO,EAAE;AAAA,MACzD;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,SAAK,SAAS,OAAO;AAAA,EACvB;AAAA,EAEA,MAAc;AACZ,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,KAAK,SAAiD;AAE1D,UAAM,MAAM,KAAK,MAAS,gBAAa,KAAK,YAAY,OAAO,CAAC;AAChE,SAAK,UAAU,KAAK,OAAO;AAC3B,IAAG,iBAAc,KAAK,YAAY,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAE9D,UAAM,SAAS,aAAa,UAAU,GAAG;AACzC,QAAI,OAAO,SAAS;AAClB,WAAK,SAAS,OAAO;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,iBAAiB,OAAwB;AACvC,QAAI,CAAC,OAAO;AACV,YAAMA,YAAW,WAAW,KAAK,OAAO,UAAU,OAAO;AACzD,MAAG,aAAUA,WAAU,EAAE,WAAW,KAAK,CAAC;AAC1C,aAAOA;AAAA,IACT;AACA,QAAI,MAAM,WAAW,GAAG,KAAK,MAAM,WAAW,GAAG,GAAG;AAClD,YAAMA,YAAW,WAAW,KAAK;AACjC,MAAG,aAAUA,WAAU,EAAE,WAAW,KAAK,CAAC;AAC1C,aAAOA;AAAA,IACT;AAEA,UAAM,OAAO,MAAM,YAAY;AAC/B,UAAM,WAAgB,UAAK,WAAW,KAAK,OAAO,UAAU,OAAO,GAAG,IAAI;AAC1E,IAAG,aAAU,UAAU,EAAE,WAAW,KAAK,CAAC;AAC1C,WAAO;AAAA,EACT;AAAA,EAEQ,kBAAkB,KAAoC;AAC5D,UAAM,YAAkC;AAAA,MACtC,CAAC,8BAA8B,CAAC,YAAY,YAAY,UAAU,CAAC;AAAA,MACnE,CAAC,4BAA4B,CAAC,YAAY,YAAY,QAAQ,CAAC;AAAA,MAC/D,CAAC,yBAAyB,CAAC,cAAc,CAAC;AAAA,IAC5C;AACA,eAAW,CAAC,QAAQ,UAAU,KAAK,WAAW;AAC5C,YAAM,QAAQ,QAAQ,IAAI,MAAM;AAChC,UAAI,UAAU,QAAW;AACvB,YAAI,SAAS;AACb,iBAAS,IAAI,GAAG,IAAI,WAAW,SAAS,GAAG,KAAK;AAC9C,cAAI,CAAC,OAAO,WAAW,CAAC,CAAC,EAAG,QAAO,WAAW,CAAC,CAAC,IAAI,CAAC;AACrD,mBAAS,OAAO,WAAW,CAAC,CAAC;AAAA,QAC/B;AACA,cAAM,MAAM,WAAW,WAAW,SAAS,CAAC;AAE5C,eAAO,GAAG,IAAI,QAAQ,WAAW,OAAO,KAAK,IAAI;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,UAAU,QAA6B,QAAmC;AAChF,eAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,UAAI,OAAO,GAAG,KAAK,OAAO,OAAO,GAAG,MAAM,YAAY,CAAC,MAAM,QAAQ,OAAO,GAAG,CAAC,GAAG;AACjF,YAAI,CAAC,OAAO,GAAG,EAAG,QAAO,GAAG,IAAI,CAAC;AACjC,aAAK,UAAU,OAAO,GAAG,GAAG,OAAO,GAAG,CAAC;AAAA,MACzC,OAAO;AACL,eAAO,GAAG,IAAI,OAAO,GAAG;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AACF;;;ACtKA,SAAS,gBAAgB;AACzB,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB,SAAS,qBAAqB;AAU9B,SAAS,mBAAyB;AAChC,EAAG,cAAU,aAAa,EAAE,WAAW,KAAK,CAAC;AAC7C,QAAM,UAAe,WAAK,aAAa,cAAc;AACrD,MAAI,CAAI,eAAW,OAAO,GAAG;AAC3B,IAAG,kBAAc,SAAS,KAAK,UAAU,EAAE,MAAM,mBAAmB,SAAS,MAAM,cAAc,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC;AAAA,EACjH;AACF;AAEO,SAAS,cAAc,aAA2B;AACvD,mBAAiB;AACjB,MAAI,KAAK,cAAc,WAAW,KAAK;AACvC,WAAS,eAAe,WAAW,cAAc,WAAW,KAAK,EAAE,OAAO,UAAU,CAAC;AACrF,MAAI,KAAK,GAAG,WAAW,0BAA0B;AACnD;AAEO,SAAS,gBAAgB,aAA2B;AACzD,mBAAiB;AACjB,MAAI,KAAK,gBAAgB,WAAW,KAAK;AACzC,WAAS,iBAAiB,WAAW,cAAc,WAAW,KAAK,EAAE,OAAO,UAAU,CAAC;AACvF,MAAI,KAAK,GAAG,WAAW,eAAe;AACxC;AAEO,SAAS,cAAsC;AACpD,QAAM,UAAe,WAAK,aAAa,cAAc;AACrD,MAAI,CAAI,eAAW,OAAO,EAAG,QAAO,CAAC;AACrC,QAAM,MAAM,KAAK,MAAS,iBAAa,SAAS,OAAO,CAAC;AACxD,SAAO,IAAI,gBAAgB,CAAC;AAC9B;AAEA,eAAsB,mBAAmB,aAAqD;AAC5F,MAAI;AACF,UAAMC,WAAU,cAAmB,WAAK,aAAa,cAAc,CAAC;AACpE,UAAM,WAAWA,SAAQ,QAAQ,WAAW;AAC5C,UAAM,MAAM,MAAM,OAAO;AAGzB,UAAM,UAAsC,IAAI,kBAAkB,IAAI;AACtE,QAAI,CAAC,WAAW,OAAO,QAAQ,kBAAkB,YAAY;AAC3D,UAAI,MAAM,UAAU,WAAW,kEAAkE;AACjG,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,QAAI,MAAM,yBAAyB,WAAW,KAAK,GAAG;AACtD,QAAI,MAAM,4BAA4B,WAAW,EAAE;AACnD,WAAO;AAAA,EACT;AACF;","names":["resolved","fs","path","require"]}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
installPlugin,
|
|
4
|
+
listPlugins,
|
|
5
|
+
uninstallPlugin
|
|
6
|
+
} from "./chunk-FLAM2AON.js";
|
|
7
|
+
|
|
8
|
+
// packages/core/src/cli.ts
|
|
9
|
+
var args = process.argv.slice(2);
|
|
10
|
+
var command = args[0];
|
|
11
|
+
function printHelp() {
|
|
12
|
+
console.log(`
|
|
13
|
+
OpenACP - Self-hosted bridge for AI coding agents
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
openacp Start the server
|
|
17
|
+
openacp install <package> Install a plugin adapter
|
|
18
|
+
openacp uninstall <package> Uninstall a plugin adapter
|
|
19
|
+
openacp plugins List installed plugins
|
|
20
|
+
openacp --version Show version
|
|
21
|
+
openacp --help Show this help
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
npx openacp
|
|
25
|
+
npx openacp install @openacp/adapter-discord
|
|
26
|
+
npx openacp uninstall @openacp/adapter-discord
|
|
27
|
+
`);
|
|
28
|
+
}
|
|
29
|
+
async function main() {
|
|
30
|
+
if (command === "--help" || command === "-h") {
|
|
31
|
+
printHelp();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (command === "--version" || command === "-v") {
|
|
35
|
+
try {
|
|
36
|
+
const { createRequire } = await import("module");
|
|
37
|
+
const require2 = createRequire(import.meta.url);
|
|
38
|
+
const pkg = require2("../package.json");
|
|
39
|
+
console.log(`openacp v${pkg.version}`);
|
|
40
|
+
} catch {
|
|
41
|
+
console.log("openacp v0.0.0-dev");
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (command === "install") {
|
|
46
|
+
const pkg = args[1];
|
|
47
|
+
if (!pkg) {
|
|
48
|
+
console.error("Usage: openacp install <package>");
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
installPlugin(pkg);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (command === "uninstall") {
|
|
55
|
+
const pkg = args[1];
|
|
56
|
+
if (!pkg) {
|
|
57
|
+
console.error("Usage: openacp uninstall <package>");
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
uninstallPlugin(pkg);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (command === "plugins") {
|
|
64
|
+
const plugins = listPlugins();
|
|
65
|
+
const entries = Object.entries(plugins);
|
|
66
|
+
if (entries.length === 0) {
|
|
67
|
+
console.log("No plugins installed.");
|
|
68
|
+
} else {
|
|
69
|
+
console.log("Installed plugins:");
|
|
70
|
+
for (const [name, version] of entries) {
|
|
71
|
+
console.log(` ${name}@${version}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (command && !command.startsWith("-")) {
|
|
77
|
+
console.error(`Unknown command: ${command}`);
|
|
78
|
+
printHelp();
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
const { startServer } = await import("./main-2DVA2NVU.js");
|
|
82
|
+
await startServer();
|
|
83
|
+
}
|
|
84
|
+
main().catch((err) => {
|
|
85
|
+
console.error("Fatal:", err);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
});
|
|
88
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../packages/core/src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { installPlugin, uninstallPlugin, listPlugins } from './plugin-manager.js'\n\nconst args = process.argv.slice(2)\nconst command = args[0]\n\nfunction printHelp(): void {\n console.log(`\nOpenACP - Self-hosted bridge for AI coding agents\n\nUsage:\n openacp Start the server\n openacp install <package> Install a plugin adapter\n openacp uninstall <package> Uninstall a plugin adapter\n openacp plugins List installed plugins\n openacp --version Show version\n openacp --help Show this help\n\nExamples:\n npx openacp\n npx openacp install @openacp/adapter-discord\n npx openacp uninstall @openacp/adapter-discord\n`)\n}\n\nasync function main() {\n if (command === '--help' || command === '-h') {\n printHelp()\n return\n }\n\n if (command === '--version' || command === '-v') {\n // In published build: read version from own package.json via createRequire\n // In dev: fallback to 'dev'\n try {\n const { createRequire } = await import('node:module')\n const require = createRequire(import.meta.url)\n const pkg = require('../package.json')\n console.log(`openacp v${pkg.version}`)\n } catch {\n console.log('openacp v0.0.0-dev')\n }\n return\n }\n\n if (command === 'install') {\n const pkg = args[1]\n if (!pkg) {\n console.error('Usage: openacp install <package>')\n process.exit(1)\n }\n installPlugin(pkg)\n return\n }\n\n if (command === 'uninstall') {\n const pkg = args[1]\n if (!pkg) {\n console.error('Usage: openacp uninstall <package>')\n process.exit(1)\n }\n uninstallPlugin(pkg)\n return\n }\n\n if (command === 'plugins') {\n const plugins = listPlugins()\n const entries = Object.entries(plugins)\n if (entries.length === 0) {\n console.log('No plugins installed.')\n } else {\n console.log('Installed plugins:')\n for (const [name, version] of entries) {\n console.log(` ${name}@${version}`)\n }\n }\n return\n }\n\n // Default: start server\n if (command && !command.startsWith('-')) {\n console.error(`Unknown command: ${command}`)\n printHelp()\n process.exit(1)\n }\n\n // Import and run server start\n const { startServer } = await import('./main.js')\n await startServer()\n}\n\nmain().catch((err) => {\n console.error('Fatal:', err)\n process.exit(1)\n})\n"],"mappings":";;;;;;;;AAIA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,UAAU,KAAK,CAAC;AAEtB,SAAS,YAAkB;AACzB,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAeb;AACD;AAEA,eAAe,OAAO;AACpB,MAAI,YAAY,YAAY,YAAY,MAAM;AAC5C,cAAU;AACV;AAAA,EACF;AAEA,MAAI,YAAY,eAAe,YAAY,MAAM;AAG/C,QAAI;AACF,YAAM,EAAE,cAAc,IAAI,MAAM,OAAO,QAAa;AACpD,YAAMA,WAAU,cAAc,YAAY,GAAG;AAC7C,YAAM,MAAMA,SAAQ,iBAAiB;AACrC,cAAQ,IAAI,YAAY,IAAI,OAAO,EAAE;AAAA,IACvC,QAAQ;AACN,cAAQ,IAAI,oBAAoB;AAAA,IAClC;AACA;AAAA,EACF;AAEA,MAAI,YAAY,WAAW;AACzB,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,CAAC,KAAK;AACR,cAAQ,MAAM,kCAAkC;AAChD,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,kBAAc,GAAG;AACjB;AAAA,EACF;AAEA,MAAI,YAAY,aAAa;AAC3B,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,CAAC,KAAK;AACR,cAAQ,MAAM,oCAAoC;AAClD,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,oBAAgB,GAAG;AACnB;AAAA,EACF;AAEA,MAAI,YAAY,WAAW;AACzB,UAAM,UAAU,YAAY;AAC5B,UAAM,UAAU,OAAO,QAAQ,OAAO;AACtC,QAAI,QAAQ,WAAW,GAAG;AACxB,cAAQ,IAAI,uBAAuB;AAAA,IACrC,OAAO;AACL,cAAQ,IAAI,oBAAoB;AAChC,iBAAW,CAAC,MAAM,OAAO,KAAK,SAAS;AACrC,gBAAQ,IAAI,KAAK,IAAI,IAAI,OAAO,EAAE;AAAA,MACpC;AAAA,IACF;AACA;AAAA,EACF;AAGA,MAAI,WAAW,CAAC,QAAQ,WAAW,GAAG,GAAG;AACvC,YAAQ,MAAM,oBAAoB,OAAO,EAAE;AAC3C,cAAU;AACV,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,EAAE,YAAY,IAAI,MAAM,OAAO,qBAAW;AAChD,QAAM,YAAY;AACpB;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM,UAAU,GAAG;AAC3B,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["require"]}
|