@openacp/cli 2026.326.3 → 2026.327.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.
Files changed (72) hide show
  1. package/README.md +2 -2
  2. package/dist/{adapter-77ZCVABT.js → adapter-IZNL6AK2.js} +13 -13
  3. package/dist/{adapter-6ANPBSVU.js → adapter-Z435XYBQ.js} +2 -2
  4. package/dist/{api-server-CHVSUDBX.js → api-server-2I7B3MXR.js} +2 -2
  5. package/dist/{api-server-3PYLRBCN.js → api-server-5VEESFOT.js} +2 -2
  6. package/dist/{chunk-Y64XWMJ4.js → chunk-366FOUJG.js} +2 -2
  7. package/dist/{chunk-WVLDNYOJ.js → chunk-5RO42TWV.js} +2 -2
  8. package/dist/{chunk-UNJUWWQO.js → chunk-5YW56UJK.js} +1 -10
  9. package/dist/chunk-5YW56UJK.js.map +1 -0
  10. package/dist/{chunk-NBFIBGAT.js → chunk-7KGWYNWE.js} +1 -1
  11. package/dist/chunk-CDAUYTVP.js +41 -0
  12. package/dist/chunk-CDAUYTVP.js.map +1 -0
  13. package/dist/{chunk-Q6ZXJTZB.js → chunk-CFM4GJ74.js} +7 -11
  14. package/dist/chunk-CFM4GJ74.js.map +1 -0
  15. package/dist/{chunk-RKB2ZK6S.js → chunk-FDLQ5M6W.js} +17 -136
  16. package/dist/chunk-FDLQ5M6W.js.map +1 -0
  17. package/dist/{chunk-FQEBWOZR.js → chunk-QUXTZU36.js} +45 -126
  18. package/dist/chunk-QUXTZU36.js.map +1 -0
  19. package/dist/{chunk-QSDZDHNS.js → chunk-VO3A2NI4.js} +4 -4
  20. package/dist/{chunk-V5JT5TPD.js → chunk-ZPTM4NGK.js} +2 -2
  21. package/dist/cli.js +145 -46
  22. package/dist/cli.js.map +1 -1
  23. package/dist/{config-editor-HNEKXRLQ.js → config-editor-2GYL2SSZ.js} +2 -2
  24. package/dist/{core-plugins-VEUNFTMB.js → core-plugins-I6UPXQBL.js} +7 -10
  25. package/dist/{discord-NOJQ5PZO.js → discord-DXDTGVGS.js} +2 -2
  26. package/dist/index.d.ts +14 -62
  27. package/dist/index.js +15 -21
  28. package/dist/index.js.map +1 -1
  29. package/dist/{integrate-5C6KSU6D.js → integrate-APK4OEQF.js} +2 -2
  30. package/dist/integrate-APK4OEQF.js.map +1 -0
  31. package/dist/{main-T5WVCCFN.js → main-EJBK65NS.js} +33 -52
  32. package/dist/main-EJBK65NS.js.map +1 -0
  33. package/dist/{new-session-AVQCNXRG.js → new-session-HFO5GHSZ.js} +3 -3
  34. package/dist/plugin-create-LCXXNDK6.js +950 -0
  35. package/dist/plugin-create-LCXXNDK6.js.map +1 -0
  36. package/dist/plugin-search-HQ4WQKOF.js +40 -0
  37. package/dist/plugin-search-HQ4WQKOF.js.map +1 -0
  38. package/dist/{post-upgrade-XLHZ6ZB7.js → post-upgrade-2MG3VUDV.js} +2 -2
  39. package/dist/registry-client-AVGRE4CF.js +8 -0
  40. package/dist/{setup-BAI2F24H.js → setup-N7KT56O7.js} +7 -7
  41. package/dist/{telegram-ZDC3JQF2.js → telegram-QWMJU3A6.js} +2 -2
  42. package/package.json +2 -2
  43. package/dist/chunk-2CX4IEEC.js +0 -124
  44. package/dist/chunk-2CX4IEEC.js.map +0 -1
  45. package/dist/chunk-FQEBWOZR.js.map +0 -1
  46. package/dist/chunk-Q6ZXJTZB.js.map +0 -1
  47. package/dist/chunk-RKB2ZK6S.js.map +0 -1
  48. package/dist/chunk-UNJUWWQO.js.map +0 -1
  49. package/dist/chunk-WAAD23KY.js +0 -222
  50. package/dist/chunk-WAAD23KY.js.map +0 -1
  51. package/dist/integrate-5C6KSU6D.js.map +0 -1
  52. package/dist/main-T5WVCCFN.js.map +0 -1
  53. package/dist/plugin-create-LYF5PP5W.js +0 -327
  54. package/dist/plugin-create-LYF5PP5W.js.map +0 -1
  55. package/dist/usage-WYNK6ZC5.js +0 -10
  56. /package/dist/{adapter-77ZCVABT.js.map → adapter-IZNL6AK2.js.map} +0 -0
  57. /package/dist/{adapter-6ANPBSVU.js.map → adapter-Z435XYBQ.js.map} +0 -0
  58. /package/dist/{api-server-3PYLRBCN.js.map → api-server-2I7B3MXR.js.map} +0 -0
  59. /package/dist/{api-server-CHVSUDBX.js.map → api-server-5VEESFOT.js.map} +0 -0
  60. /package/dist/{chunk-Y64XWMJ4.js.map → chunk-366FOUJG.js.map} +0 -0
  61. /package/dist/{chunk-WVLDNYOJ.js.map → chunk-5RO42TWV.js.map} +0 -0
  62. /package/dist/{chunk-NBFIBGAT.js.map → chunk-7KGWYNWE.js.map} +0 -0
  63. /package/dist/{chunk-QSDZDHNS.js.map → chunk-VO3A2NI4.js.map} +0 -0
  64. /package/dist/{chunk-V5JT5TPD.js.map → chunk-ZPTM4NGK.js.map} +0 -0
  65. /package/dist/{config-editor-HNEKXRLQ.js.map → config-editor-2GYL2SSZ.js.map} +0 -0
  66. /package/dist/{core-plugins-VEUNFTMB.js.map → core-plugins-I6UPXQBL.js.map} +0 -0
  67. /package/dist/{discord-NOJQ5PZO.js.map → discord-DXDTGVGS.js.map} +0 -0
  68. /package/dist/{new-session-AVQCNXRG.js.map → new-session-HFO5GHSZ.js.map} +0 -0
  69. /package/dist/{post-upgrade-XLHZ6ZB7.js.map → post-upgrade-2MG3VUDV.js.map} +0 -0
  70. /package/dist/{telegram-ZDC3JQF2.js.map → registry-client-AVGRE4CF.js.map} +0 -0
  71. /package/dist/{setup-BAI2F24H.js.map → setup-N7KT56O7.js.map} +0 -0
  72. /package/dist/{usage-WYNK6ZC5.js.map → telegram-QWMJU3A6.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/plugins/api-server/api-server.ts","../../src/plugins/api-server/sse-manager.ts","../../src/plugins/api-server/static-server.ts","../../src/plugins/api-server/router.ts","../../src/plugins/api-server/routes/health.ts","../../src/plugins/api-server/routes/sessions.ts","../../src/plugins/api-server/routes/config.ts","../../src/plugins/api-server/routes/topics.ts","../../src/plugins/api-server/routes/tunnel.ts","../../src/plugins/api-server/routes/agents.ts","../../src/plugins/api-server/routes/notify.ts"],"sourcesContent":["import * as http from \"node:http\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport * as crypto from \"node:crypto\";\nimport { fileURLToPath } from \"node:url\";\nimport type { OpenACPCore } from \"../../core/core.js\";\nimport type { TopicManager } from \"../telegram/topic-manager.js\";\nimport { createChildLogger } from \"../../core/utils/log.js\";\nimport { SSEManager } from \"./sse-manager.js\";\nimport { StaticServer } from \"./static-server.js\";\nimport { Router } from \"./router.js\";\nimport { registerHealthRoutes } from \"./routes/health.js\";\nimport { registerSessionRoutes } from \"./routes/sessions.js\";\nimport { registerConfigRoutes } from \"./routes/config.js\";\nimport { registerTopicRoutes } from \"./routes/topics.js\";\nimport { registerTunnelRoutes } from \"./routes/tunnel.js\";\nimport { registerAgentRoutes } from \"./routes/agents.js\";\nimport { registerNotifyRoutes } from \"./routes/notify.js\";\n\nconst log = createChildLogger({ module: \"api-server\" });\n\nconst DEFAULT_PORT_FILE = path.join(os.homedir(), \".openacp\", \"api.port\");\n\nlet cachedVersion: string | undefined;\n\nfunction getVersion(): string {\n if (cachedVersion) return cachedVersion;\n try {\n const __filename = fileURLToPath(import.meta.url);\n const pkgPath = path.resolve(\n path.dirname(__filename),\n \"../../../package.json\",\n );\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n cachedVersion = pkg.version ?? \"0.0.0-dev\";\n } catch {\n cachedVersion = \"0.0.0-dev\";\n }\n return cachedVersion!;\n}\n\nexport interface ApiConfig {\n port: number;\n host: string;\n}\n\n/** Dependencies passed to route registration functions. */\nexport interface RouteDeps {\n core: OpenACPCore;\n topicManager?: TopicManager;\n startedAt: number;\n getVersion: () => string;\n sendJson: (res: http.ServerResponse, status: number, data: unknown) => void;\n readBody: (req: http.IncomingMessage) => Promise<string | null>;\n}\n\nexport class ApiServer {\n private server: http.Server | null = null;\n private actualPort: number = 0;\n private portFilePath: string;\n private startedAt = Date.now();\n private secret: string = \"\";\n private secretFilePath: string;\n private sseManager: SSEManager;\n private staticServer: StaticServer;\n private router: Router;\n\n constructor(\n private core: OpenACPCore,\n private config: ApiConfig,\n portFilePath?: string,\n private topicManager?: TopicManager,\n secretFilePath?: string,\n uiDir?: string,\n ) {\n this.portFilePath = portFilePath ?? DEFAULT_PORT_FILE;\n this.secretFilePath =\n secretFilePath ?? path.join(os.homedir(), \".openacp\", \"api-secret\");\n this.staticServer = new StaticServer(uiDir);\n this.sseManager = new SSEManager(\n core.eventBus,\n () => {\n const sessions = this.core.sessionManager.listSessions();\n return {\n active: sessions.filter(\n (s) => s.status === \"active\" || s.status === \"initializing\",\n ).length,\n total: sessions.length,\n };\n },\n this.startedAt,\n );\n\n this.router = new Router();\n const deps: RouteDeps = {\n core: this.core,\n topicManager: this.topicManager,\n startedAt: this.startedAt,\n getVersion,\n sendJson: this.sendJson.bind(this),\n readBody: this.readBody.bind(this),\n };\n\n registerHealthRoutes(this.router, deps);\n registerSessionRoutes(this.router, deps);\n registerConfigRoutes(this.router, deps);\n registerTopicRoutes(this.router, deps);\n registerTunnelRoutes(this.router, deps);\n registerAgentRoutes(this.router, deps);\n registerNotifyRoutes(this.router, deps);\n }\n\n async start(): Promise<void> {\n this.loadOrCreateSecret();\n this.server = http.createServer((req, res) => this.handleRequest(req, res));\n\n await new Promise<void>((resolve, reject) => {\n this.server!.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n log.warn(\n { port: this.config.port },\n \"API port in use, continuing without API server\",\n );\n this.server = null;\n // actualPort stays 0, port file not written\n resolve();\n } else {\n reject(err);\n }\n });\n\n this.server!.listen(this.config.port, this.config.host, () => {\n const addr = this.server!.address();\n if (addr && typeof addr === \"object\") {\n this.actualPort = addr.port;\n }\n this.writePortFile();\n log.info(\n { host: this.config.host, port: this.actualPort },\n \"API server listening\",\n );\n this.sseManager.setup();\n\n if (\n this.config.host !== \"127.0.0.1\" &&\n this.config.host !== \"localhost\"\n ) {\n log.warn(\n \"API server binding to non-localhost. Ensure api-secret file is secured.\",\n );\n }\n\n resolve();\n });\n });\n }\n\n async stop(): Promise<void> {\n this.sseManager.stop();\n this.removePortFile();\n if (this.server) {\n await new Promise<void>((resolve) => {\n this.server!.close(() => resolve());\n });\n this.server = null;\n }\n }\n\n getPort(): number {\n return this.actualPort;\n }\n\n getSecret(): string {\n return this.secret;\n }\n\n private writePortFile(): void {\n const dir = path.dirname(this.portFilePath);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(this.portFilePath, String(this.actualPort));\n }\n\n private removePortFile(): void {\n try {\n fs.unlinkSync(this.portFilePath);\n } catch {\n /* ignore */\n }\n }\n\n private loadOrCreateSecret(): void {\n const dir = path.dirname(this.secretFilePath);\n fs.mkdirSync(dir, { recursive: true });\n\n try {\n this.secret = fs.readFileSync(this.secretFilePath, \"utf-8\").trim();\n if (this.secret) {\n // Warn if file permissions are too open (like SSH does for private keys)\n try {\n const stat = fs.statSync(this.secretFilePath);\n const mode = stat.mode & 0o777;\n if (mode & 0o077) {\n log.warn(\n { path: this.secretFilePath, mode: \"0\" + mode.toString(8) },\n \"API secret file has insecure permissions (should be 0600). Run: chmod 600 %s\",\n this.secretFilePath,\n );\n }\n } catch {\n /* stat failed, skip check */\n }\n return;\n }\n } catch {\n // File doesn't exist, create it\n }\n\n this.secret = crypto.randomBytes(32).toString(\"hex\");\n fs.writeFileSync(this.secretFilePath, this.secret, { mode: 0o600 });\n }\n\n private authenticate(\n req: http.IncomingMessage,\n allowQueryParam = false,\n ): boolean {\n // Check Authorization header\n const authHeader = req.headers.authorization;\n if (authHeader?.startsWith(\"Bearer \")) {\n const token = authHeader.slice(7);\n if (\n token.length === this.secret.length &&\n crypto.timingSafeEqual(\n Buffer.from(token, \"utf-8\"),\n Buffer.from(this.secret, \"utf-8\"),\n )\n ) {\n return true;\n }\n }\n // Query param auth only for SSE (EventSource can't set headers)\n if (allowQueryParam) {\n const parsedUrl = new URL(req.url || \"\", \"http://localhost\");\n const qToken = parsedUrl.searchParams.get(\"token\");\n if (\n qToken &&\n qToken.length === this.secret.length &&\n crypto.timingSafeEqual(\n Buffer.from(qToken, \"utf-8\"),\n Buffer.from(this.secret, \"utf-8\"),\n )\n ) {\n return true;\n }\n }\n return false;\n }\n\n private async handleRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ): Promise<void> {\n const method = req.method?.toUpperCase();\n const url = req.url || \"\";\n\n // Auth check: exempt health/version, SSE (has own auth), and non-/api/ routes (static files)\n if (url.startsWith(\"/api/\")) {\n const isExempt =\n method === \"GET\" &&\n (url === \"/api/health\" ||\n url === \"/api/version\" ||\n url.startsWith(\"/api/events\"));\n if (!isExempt && !this.authenticate(req)) {\n this.sendJson(res, 401, { error: \"Unauthorized\" });\n return;\n }\n }\n\n try {\n // SSE endpoint — handled separately (streaming connection)\n if (method === \"GET\" && url.startsWith(\"/api/events\")) {\n if (!this.authenticate(req, true)) {\n this.sendJson(res, 401, { error: \"Unauthorized\" });\n return;\n }\n this.sseManager.handleRequest(req, res);\n return; // Don't end the response — SSE keeps it open\n }\n\n // Try router for API routes\n if (url.startsWith(\"/api/\")) {\n const match = this.router.match(method!, url);\n if (match) {\n await match.handler(req, res, match.params);\n } else {\n this.sendJson(res, 404, { error: \"Not found\" });\n }\n return;\n }\n\n // Try static file serving (UI dashboard) for non-API routes\n if (!this.staticServer.serve(req, res)) {\n this.sendJson(res, 404, { error: \"Not found\" });\n }\n } catch (err) {\n log.error({ err }, \"API request error\");\n this.sendJson(res, 500, { error: \"Internal server error\" });\n }\n }\n\n private sendJson(\n res: http.ServerResponse,\n status: number,\n data: unknown,\n ): void {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(data));\n }\n\n private readBody(req: http.IncomingMessage): Promise<string | null> {\n const MAX_BODY_SIZE = 1024 * 1024; // 1MB\n return new Promise((resolve) => {\n let data = \"\";\n let size = 0;\n let destroyed = false;\n req.on(\"data\", (chunk: Buffer) => {\n size += chunk.length;\n if (size > MAX_BODY_SIZE && !destroyed) {\n destroyed = true;\n req.destroy();\n resolve(null);\n return;\n }\n if (!destroyed) data += chunk;\n });\n req.on(\"end\", () => {\n if (!destroyed) resolve(data);\n });\n req.on(\"error\", () => {\n if (!destroyed) resolve(\"\");\n });\n });\n }\n}\n","import * as http from \"node:http\";\nimport type { EventBus, EventBusEvents } from \"../../core/event-bus.js\";\n\ninterface SSEResponse extends http.ServerResponse {\n sessionFilter?: string;\n}\n\ninterface SessionStats {\n active: number;\n total: number;\n}\n\nexport class SSEManager {\n private sseConnections = new Set<http.ServerResponse>();\n private sseCleanupHandlers = new Map<http.ServerResponse, () => void>();\n private healthInterval?: ReturnType<typeof setInterval>;\n private boundHandlers: Array<{\n event: keyof EventBusEvents;\n handler: (data: unknown) => void;\n }> = [];\n\n constructor(\n private eventBus: EventBus | undefined,\n private getSessionStats: () => SessionStats,\n private startedAt: number,\n ) {}\n\n setup(): void {\n if (!this.eventBus) return;\n\n const events = [\n \"session:created\",\n \"session:updated\",\n \"session:deleted\",\n \"agent:event\",\n \"permission:request\",\n ] as const;\n\n for (const eventName of events) {\n const handler = (data: unknown) => {\n this.broadcast(eventName, data);\n };\n this.eventBus.on(eventName, handler);\n this.boundHandlers.push({ event: eventName, handler });\n }\n\n // Health heartbeat every 30s\n this.healthInterval = setInterval(() => {\n const mem = process.memoryUsage();\n const stats = this.getSessionStats();\n this.broadcast(\"health\", {\n uptime: Date.now() - this.startedAt,\n memory: {\n rss: mem.rss,\n heapUsed: mem.heapUsed,\n heapTotal: mem.heapTotal,\n },\n sessions: stats,\n });\n }, 30_000);\n }\n\n handleRequest(req: http.IncomingMessage, res: http.ServerResponse): void {\n const parsedUrl = new URL(req.url || \"\", \"http://localhost\");\n const sessionFilter = parsedUrl.searchParams.get(\"sessionId\");\n\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n res.flushHeaders();\n\n // Store filter metadata on the response for broadcast\n (res as SSEResponse).sessionFilter = sessionFilter ?? undefined;\n\n this.sseConnections.add(res);\n\n const cleanup = () => {\n this.sseConnections.delete(res);\n this.sseCleanupHandlers.delete(res);\n };\n this.sseCleanupHandlers.set(res, cleanup);\n req.on(\"close\", cleanup);\n }\n\n broadcast(event: string, data: unknown): void {\n const payload = `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n // Events that carry sessionId and should be filtered\n const sessionEvents = [\n \"agent:event\",\n \"permission:request\",\n \"session:updated\",\n ];\n for (const res of this.sseConnections) {\n const filter = (res as SSEResponse).sessionFilter;\n if (filter && sessionEvents.includes(event)) {\n const eventData = data as { sessionId: string };\n if (eventData.sessionId !== filter) continue;\n }\n try {\n if (res.writable) res.write(payload);\n } catch {\n /* connection closed */\n }\n }\n }\n\n stop(): void {\n if (this.healthInterval) clearInterval(this.healthInterval);\n\n // Remove only our own event bus listeners\n if (this.eventBus) {\n for (const { event, handler } of this.boundHandlers) {\n this.eventBus.off(event, handler);\n }\n }\n this.boundHandlers = [];\n\n // Copy to avoid modifying Map while iterating\n const entries = [...this.sseCleanupHandlers];\n for (const [res, cleanup] of entries) {\n res.end();\n cleanup();\n }\n }\n}\n\nexport type { SessionStats };\n","import * as http from \"node:http\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"application/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".svg\": \"image/svg+xml\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n\nexport class StaticServer {\n private uiDir: string | undefined;\n\n constructor(uiDir?: string) {\n this.uiDir = uiDir;\n\n if (!this.uiDir) {\n const __filename = fileURLToPath(import.meta.url);\n const candidate = path.resolve(path.dirname(__filename), \"../../ui/dist\");\n if (fs.existsSync(path.join(candidate, \"index.html\"))) {\n this.uiDir = candidate;\n }\n // Also check dist-publish layout\n if (!this.uiDir) {\n const publishCandidate = path.resolve(\n path.dirname(__filename),\n \"../ui\",\n );\n if (fs.existsSync(path.join(publishCandidate, \"index.html\"))) {\n this.uiDir = publishCandidate;\n }\n }\n }\n }\n\n isAvailable(): boolean {\n return this.uiDir !== undefined;\n }\n\n serve(req: http.IncomingMessage, res: http.ServerResponse): boolean {\n if (!this.uiDir) return false;\n\n const urlPath = (req.url || \"/\").split(\"?\")[0];\n const safePath = path.normalize(urlPath);\n\n // Try exact file match\n const filePath = path.join(this.uiDir, safePath);\n if (!filePath.startsWith(this.uiDir + path.sep) && filePath !== this.uiDir)\n return false; // path traversal guard\n\n if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {\n const ext = path.extname(filePath);\n const contentType = MIME_TYPES[ext] ?? \"application/octet-stream\";\n // Vite-hashed assets get long cache, others get no-cache\n const isHashed = /\\.[a-zA-Z0-9]{8,}\\.(js|css)$/.test(filePath);\n const cacheControl = isHashed\n ? \"public, max-age=31536000, immutable\"\n : \"no-cache\";\n res.writeHead(200, {\n \"Content-Type\": contentType,\n \"Cache-Control\": cacheControl,\n });\n fs.createReadStream(filePath).pipe(res);\n return true;\n }\n\n // SPA fallback — serve index.html\n const indexPath = path.join(this.uiDir, \"index.html\");\n if (fs.existsSync(indexPath)) {\n res.writeHead(200, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-cache\",\n });\n fs.createReadStream(indexPath).pipe(res);\n return true;\n }\n\n return false;\n }\n}\n","import type * as http from \"node:http\";\n\nexport type Handler = (\n req: http.IncomingMessage,\n res: http.ServerResponse,\n params: Record<string, string>,\n) => Promise<void>;\n\ninterface Route {\n method: string;\n pattern: RegExp;\n keys: string[];\n handler: Handler;\n}\n\nexport class Router {\n private routes: Route[] = [];\n\n get(path: string, handler: Handler): void {\n this.add(\"GET\", path, handler);\n }\n post(path: string, handler: Handler): void {\n this.add(\"POST\", path, handler);\n }\n put(path: string, handler: Handler): void {\n this.add(\"PUT\", path, handler);\n }\n patch(path: string, handler: Handler): void {\n this.add(\"PATCH\", path, handler);\n }\n delete(path: string, handler: Handler): void {\n this.add(\"DELETE\", path, handler);\n }\n\n match(\n method: string,\n url: string,\n ): { handler: Handler; params: Record<string, string> } | null {\n const pathname = url.split(\"?\")[0];\n for (const route of this.routes) {\n if (route.method !== method) continue;\n const m = pathname.match(route.pattern);\n if (!m) continue;\n const params: Record<string, string> = {};\n for (let i = 0; i < route.keys.length; i++) {\n params[route.keys[i]] = m[i + 1];\n }\n return { handler: route.handler, params };\n }\n return null;\n }\n\n private add(method: string, path: string, handler: Handler): void {\n const keys: string[] = [];\n const pattern = path.replace(/:(\\w+)/g, (_, key) => {\n keys.push(key);\n return \"([^/]+)\";\n });\n this.routes.push({\n method,\n pattern: new RegExp(`^${pattern}$`),\n keys,\n handler,\n });\n }\n}\n","import type { Router } from \"../router.js\";\nimport type { RouteDeps } from \"../api-server.js\";\n\nexport function registerHealthRoutes(router: Router, deps: RouteDeps): void {\n router.get(\"/api/health\", async (_req, res) => {\n const activeSessions = deps.core.sessionManager.listSessions();\n const allRecords = deps.core.sessionManager.listRecords();\n const mem = process.memoryUsage();\n const tunnel = deps.core.tunnelService;\n\n deps.sendJson(res, 200, {\n status: \"ok\",\n uptime: Date.now() - deps.startedAt,\n version: deps.getVersion(),\n memory: {\n rss: mem.rss,\n heapUsed: mem.heapUsed,\n heapTotal: mem.heapTotal,\n },\n sessions: {\n active: activeSessions.filter(\n (s) => s.status === \"active\" || s.status === \"initializing\",\n ).length,\n total: allRecords.length,\n },\n adapters: Array.from(deps.core.adapters.keys()),\n tunnel: tunnel\n ? { enabled: true, url: tunnel.getPublicUrl() }\n : { enabled: false },\n });\n });\n\n router.get(\"/api/version\", async (_req, res) => {\n deps.sendJson(res, 200, { version: deps.getVersion() });\n });\n\n router.post(\"/api/restart\", async (_req, res) => {\n if (!deps.core.requestRestart) {\n deps.sendJson(res, 501, { error: \"Restart not available\" });\n return;\n }\n\n deps.sendJson(res, 200, { ok: true, message: \"Restarting...\" });\n setImmediate(() => deps.core.requestRestart!());\n });\n\n router.get(\"/api/adapters\", async (_req, res) => {\n const adapters = Array.from(deps.core.adapters.entries()).map(([name]) => ({\n name,\n type: \"built-in\" as const,\n }));\n deps.sendJson(res, 200, { adapters });\n });\n}\n","import type { Router } from \"../router.js\";\nimport type { RouteDeps } from \"../api-server.js\";\nimport { createChildLogger } from \"../../../core/utils/log.js\";\n\nconst log = createChildLogger({ module: \"api-server\" });\n\nexport function registerSessionRoutes(router: Router, deps: RouteDeps): void {\n router.post(\"/api/sessions/adopt\", async (req, res) => {\n const body = await deps.readBody(req);\n if (body === null) {\n return deps.sendJson(res, 413, { error: \"Request body too large\" });\n }\n if (!body) {\n return deps.sendJson(res, 400, {\n error: \"bad_request\",\n message: \"Empty request body\",\n });\n }\n\n let parsed: { agent?: string; agentSessionId?: string; cwd?: string; channel?: string };\n try {\n parsed = JSON.parse(body);\n } catch {\n return deps.sendJson(res, 400, {\n error: \"bad_request\",\n message: \"Invalid JSON\",\n });\n }\n\n const { agent, agentSessionId, cwd, channel } = parsed;\n\n if (!agent || !agentSessionId) {\n return deps.sendJson(res, 400, {\n error: \"bad_request\",\n message: \"Missing required fields: agent, agentSessionId\",\n });\n }\n\n const result = await deps.core.adoptSession(\n agent,\n agentSessionId,\n cwd ?? process.cwd(),\n channel,\n );\n\n if (result.ok) {\n return deps.sendJson(res, 200, result);\n } else {\n const status =\n result.error === \"session_limit\"\n ? 429\n : result.error === \"agent_not_supported\"\n ? 400\n : 500;\n return deps.sendJson(res, status, result);\n }\n });\n\n router.post(\"/api/sessions\", async (req, res) => {\n const body = await deps.readBody(req);\n let agent: string | undefined;\n let workspace: string | undefined;\n\n if (body) {\n try {\n const parsed = JSON.parse(body);\n agent = parsed.agent;\n workspace = parsed.workspace;\n } catch {\n deps.sendJson(res, 400, { error: \"Invalid JSON body\" });\n return;\n }\n }\n\n // Check max concurrent sessions\n const config = deps.core.configManager.get();\n const activeSessions = deps.core.sessionManager\n .listSessions()\n .filter((s) => s.status === \"active\" || s.status === \"initializing\");\n if (activeSessions.length >= config.security.maxConcurrentSessions) {\n deps.sendJson(res, 429, {\n error: `Max concurrent sessions (${config.security.maxConcurrentSessions}) reached. Cancel a session first.`,\n });\n return;\n }\n\n // Use the first registered adapter (e.g. Telegram) so API sessions appear in the channel\n const [adapterId, adapter] = deps.core.adapters.entries().next().value ?? [\n null,\n null,\n ];\n const channelId = adapterId ?? \"api\";\n\n const resolvedAgent = agent || config.defaultAgent;\n const resolvedWorkspace = deps.core.configManager.resolveWorkspace(\n workspace || config.agents[resolvedAgent]?.workingDirectory,\n );\n\n const session = await deps.core.createSession({\n channelId,\n agentName: resolvedAgent,\n workingDirectory: resolvedWorkspace,\n createThread: !!adapter,\n initialName: `🔄 ${resolvedAgent} — New Session`,\n });\n\n // If no adapter wired events (headless), auto-approve permissions\n if (!adapter) {\n session.agentInstance.onPermissionRequest = async (request) => {\n const allowOption = request.options.find((o) => o.isAllow);\n log.debug(\n {\n sessionId: session.id,\n permissionId: request.id,\n option: allowOption?.id,\n },\n \"Auto-approving permission for API session\",\n );\n return allowOption?.id ?? request.options[0]?.id ?? \"\";\n };\n }\n\n // Warmup in background so session moves from 'initializing' to 'active'\n session\n .warmup()\n .catch((err) =>\n log.warn({ err, sessionId: session.id }, \"API session warmup failed\"),\n );\n\n deps.sendJson(res, 200, {\n sessionId: session.id,\n agent: session.agentName,\n status: session.status,\n workspace: session.workingDirectory,\n });\n });\n\n router.post(\"/api/sessions/:sessionId/prompt\", async (req, res, params) => {\n const sessionId = decodeURIComponent(params.sessionId);\n const session = deps.core.sessionManager.getSession(sessionId);\n if (!session) {\n deps.sendJson(res, 404, { error: `Session \"${sessionId}\" not found` });\n return;\n }\n\n if (\n session.status === \"cancelled\" ||\n session.status === \"finished\" ||\n session.status === \"error\"\n ) {\n deps.sendJson(res, 400, { error: `Session is ${session.status}` });\n return;\n }\n\n const body = await deps.readBody(req);\n let prompt: string | undefined;\n if (body) {\n try {\n const parsed = JSON.parse(body);\n prompt = parsed.prompt;\n } catch {\n deps.sendJson(res, 400, { error: \"Invalid JSON body\" });\n return;\n }\n }\n\n if (!prompt) {\n deps.sendJson(res, 400, { error: \"Missing prompt\" });\n return;\n }\n\n session.enqueuePrompt(prompt).catch(() => {});\n deps.sendJson(res, 200, {\n ok: true,\n sessionId,\n queueDepth: session.queueDepth,\n });\n });\n\n router.post(\n \"/api/sessions/:sessionId/permission\",\n async (req, res, params) => {\n const sessionId = decodeURIComponent(params.sessionId);\n const session = deps.core.sessionManager.getSession(sessionId);\n if (!session) {\n deps.sendJson(res, 404, { error: `Session \"${sessionId}\" not found` });\n return;\n }\n\n const body = await deps.readBody(req);\n let permissionId: string | undefined;\n let optionId: string | undefined;\n if (body) {\n try {\n const parsed = JSON.parse(body);\n permissionId = parsed.permissionId;\n optionId = parsed.optionId;\n } catch {\n deps.sendJson(res, 400, { error: \"Invalid JSON body\" });\n return;\n }\n }\n\n if (!permissionId || !optionId) {\n deps.sendJson(res, 400, {\n error: \"Missing permissionId or optionId\",\n });\n return;\n }\n\n if (\n !session.permissionGate.isPending ||\n session.permissionGate.requestId !== permissionId\n ) {\n deps.sendJson(res, 400, {\n error: \"No matching pending permission request\",\n });\n return;\n }\n\n session.permissionGate.resolve(optionId);\n deps.sendJson(res, 200, { ok: true });\n },\n );\n\n router.patch(\n \"/api/sessions/:sessionId/dangerous\",\n async (req, res, params) => {\n const sessionId = decodeURIComponent(params.sessionId);\n const session = deps.core.sessionManager.getSession(sessionId);\n if (!session) {\n deps.sendJson(res, 404, { error: `Session \"${sessionId}\" not found` });\n return;\n }\n\n const body = await deps.readBody(req);\n let enabled: boolean | undefined;\n if (body) {\n try {\n const parsed = JSON.parse(body);\n enabled = parsed.enabled;\n } catch {\n deps.sendJson(res, 400, { error: \"Invalid JSON body\" });\n return;\n }\n }\n\n if (typeof enabled !== \"boolean\") {\n deps.sendJson(res, 400, { error: \"Missing enabled boolean\" });\n return;\n }\n\n session.dangerousMode = enabled;\n await deps.core.sessionManager.patchRecord(sessionId, {\n dangerousMode: enabled,\n });\n deps.sendJson(res, 200, { ok: true, dangerousMode: enabled });\n },\n );\n\n router.get(\"/api/sessions/:sessionId\", async (_req, res, params) => {\n const sessionId = decodeURIComponent(params.sessionId);\n const session = deps.core.sessionManager.getSession(sessionId);\n if (!session) {\n deps.sendJson(res, 404, { error: `Session \"${sessionId}\" not found` });\n return;\n }\n\n deps.sendJson(res, 200, {\n session: {\n id: session.id,\n agent: session.agentName,\n status: session.status,\n name: session.name ?? null,\n workspace: session.workingDirectory,\n createdAt: session.createdAt.toISOString(),\n dangerousMode: session.dangerousMode,\n queueDepth: session.queueDepth,\n promptRunning: session.promptRunning,\n threadId: session.threadId,\n channelId: session.channelId,\n agentSessionId: session.agentSessionId,\n },\n });\n });\n\n router.post(\"/api/sessions/:sessionId/summary\", async (_req, res, params) => {\n const sessionId = decodeURIComponent(params.sessionId);\n const result = await deps.core.summarizeSession(sessionId);\n if (result.ok) {\n deps.sendJson(res, 200, result);\n } else {\n deps.sendJson(res, 400, result);\n }\n });\n\n router.post(\"/api/sessions/:sessionId/archive\", async (_req, res, params) => {\n const sessionId = decodeURIComponent(params.sessionId);\n const result = await deps.core.archiveSession(sessionId);\n if (result.ok) {\n deps.sendJson(res, 200, result);\n } else {\n deps.sendJson(res, 400, result);\n }\n });\n\n router.delete(\"/api/sessions/:sessionId\", async (_req, res, params) => {\n const sessionId = decodeURIComponent(params.sessionId);\n const session = deps.core.sessionManager.getSession(sessionId);\n if (!session) {\n deps.sendJson(res, 404, { error: `Session \"${sessionId}\" not found` });\n return;\n }\n await deps.core.sessionManager.cancelSession(sessionId);\n deps.sendJson(res, 200, { ok: true });\n });\n\n router.get(\"/api/sessions\", async (_req, res) => {\n const sessions = deps.core.sessionManager.listSessions();\n deps.sendJson(res, 200, {\n sessions: sessions.map((s) => ({\n id: s.id,\n agent: s.agentName,\n status: s.status,\n name: s.name ?? null,\n workspace: s.workingDirectory,\n createdAt: s.createdAt.toISOString(),\n dangerousMode: s.dangerousMode,\n queueDepth: s.queueDepth,\n promptRunning: s.promptRunning,\n lastActiveAt:\n deps.core.sessionManager.getSessionRecord(s.id)?.lastActiveAt ??\n null,\n })),\n });\n });\n}\n","import type { Router } from \"../router.js\";\nimport type { RouteDeps } from \"../api-server.js\";\n\nconst SENSITIVE_KEYS = [\n \"botToken\",\n \"token\",\n \"apiKey\",\n \"secret\",\n \"password\",\n \"webhookSecret\",\n];\n\nfunction redactConfig(config: unknown): unknown {\n const redacted = structuredClone(config);\n redactDeep(redacted as Record<string, unknown>);\n return redacted;\n}\n\nfunction redactDeep(obj: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(obj)) {\n if (SENSITIVE_KEYS.includes(key) && typeof value === \"string\") {\n obj[key] = \"***\";\n } else if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === \"object\")\n redactDeep(item as Record<string, unknown>);\n }\n } else if (value && typeof value === \"object\") {\n redactDeep(value as Record<string, unknown>);\n }\n }\n}\n\nexport function registerConfigRoutes(router: Router, deps: RouteDeps): void {\n router.get(\"/api/config/editable\", async (_req, res) => {\n const { getSafeFields, resolveOptions, getConfigValue } =\n await import(\"../../../core/config/config-registry.js\");\n const config = deps.core.configManager.get();\n const safeFields = getSafeFields();\n\n const fields = safeFields.map((def) => ({\n path: def.path,\n displayName: def.displayName,\n group: def.group,\n type: def.type,\n options: resolveOptions(def, config),\n value: getConfigValue(config, def.path),\n hotReload: def.hotReload,\n }));\n\n deps.sendJson(res, 200, { fields });\n });\n\n router.get(\"/api/config\", async (_req, res) => {\n const config = deps.core.configManager.get();\n deps.sendJson(res, 200, { config: redactConfig(config) });\n });\n\n router.patch(\"/api/config\", async (req, res) => {\n const body = await deps.readBody(req);\n let configPath: string | undefined;\n let value: unknown;\n\n if (body) {\n try {\n const parsed = JSON.parse(body);\n configPath = parsed.path;\n value = parsed.value;\n } catch {\n deps.sendJson(res, 400, { error: \"Invalid JSON body\" });\n return;\n }\n }\n\n if (!configPath) {\n deps.sendJson(res, 400, { error: \"Missing path\" });\n return;\n }\n\n // Block prototype pollution\n const BLOCKED_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n const parts = configPath.split(\".\");\n if (parts.some((p) => BLOCKED_KEYS.has(p))) {\n deps.sendJson(res, 400, { error: \"Invalid config path\" });\n return;\n }\n\n // Enforce safe-fields scope — only fields marked 'safe' can be modified via API\n const { getFieldDef } = await import(\"../../../core/config/config-registry.js\");\n const fieldDef = getFieldDef(configPath);\n if (!fieldDef || fieldDef.scope !== \"safe\") {\n deps.sendJson(res, 403, {\n error: \"This config field cannot be modified via the API\",\n });\n return;\n }\n\n // Pre-validate by cloning config and applying the change\n const currentConfig = deps.core.configManager.get();\n const cloned = structuredClone(currentConfig) as Record<string, unknown>;\n let target: Record<string, unknown> = cloned;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (\n target[part] &&\n typeof target[part] === \"object\" &&\n !Array.isArray(target[part])\n ) {\n target = target[part] as Record<string, unknown>;\n } else if (target[part] === undefined || target[part] === null) {\n // Create intermediate objects for new paths (e.g. speech.stt.providers.groq.apiKey)\n target[part] = {};\n target = target[part] as Record<string, unknown>;\n } else {\n deps.sendJson(res, 400, { error: \"Invalid config path\" });\n return;\n }\n }\n\n const lastKey = parts[parts.length - 1];\n target[lastKey] = value;\n\n // Validate with Zod\n const { ConfigSchema } = await import(\"../../../core/config/config.js\");\n const result = ConfigSchema.safeParse(cloned);\n if (!result.success) {\n deps.sendJson(res, 400, {\n error: \"Validation failed\",\n details: result.error.issues.map((i) => ({\n path: i.path.join(\".\"),\n message: i.message,\n })),\n });\n return;\n }\n\n // Convert dot-path to nested object for save\n const updates: Record<string, unknown> = {};\n let updateTarget = updates;\n for (let i = 0; i < parts.length - 1; i++) {\n updateTarget[parts[i]] = {};\n updateTarget = updateTarget[parts[i]] as Record<string, unknown>;\n }\n updateTarget[lastKey] = value;\n\n await deps.core.configManager.save(updates, configPath);\n\n const { isHotReloadable } = await import(\"../../../core/config/config-registry.js\");\n const needsRestart = !isHotReloadable(configPath!);\n\n deps.sendJson(res, 200, {\n ok: true,\n needsRestart,\n config: redactConfig(deps.core.configManager.get()),\n });\n });\n}\n","import type { Router } from \"../router.js\";\nimport type { RouteDeps } from \"../api-server.js\";\n\nexport function registerTopicRoutes(router: Router, deps: RouteDeps): void {\n router.get(\"/api/topics\", async (req, res) => {\n if (!deps.topicManager) {\n deps.sendJson(res, 501, { error: \"Topic management not available\" });\n return;\n }\n const url = req.url || \"\";\n const params = new URL(url, \"http://localhost\").searchParams;\n const statusParam = params.get(\"status\");\n const filter = statusParam\n ? { statuses: statusParam.split(\",\") }\n : undefined;\n const topics = deps.topicManager.listTopics(filter);\n deps.sendJson(res, 200, { topics });\n });\n\n router.post(\"/api/topics/cleanup\", async (req, res) => {\n if (!deps.topicManager) {\n deps.sendJson(res, 501, { error: \"Topic management not available\" });\n return;\n }\n const body = await deps.readBody(req);\n let statuses: string[] | undefined;\n if (body) {\n try {\n statuses = JSON.parse(body).statuses;\n } catch {\n /* use defaults */\n }\n }\n const result = await deps.topicManager.cleanup(statuses);\n deps.sendJson(res, 200, result);\n });\n\n router.delete(\"/api/topics/:sessionId\", async (req, res, params) => {\n if (!deps.topicManager) {\n deps.sendJson(res, 501, { error: \"Topic management not available\" });\n return;\n }\n const sessionId = decodeURIComponent(params.sessionId);\n const url = req.url || \"\";\n const urlParams = new URL(url, \"http://localhost\").searchParams;\n const force = urlParams.get(\"force\") === \"true\";\n const result = await deps.topicManager.deleteTopic(\n sessionId,\n force ? { confirmed: true } : undefined,\n );\n if (result.ok) {\n deps.sendJson(res, 200, result);\n } else if (result.needsConfirmation) {\n deps.sendJson(res, 409, {\n error: \"Session is active\",\n needsConfirmation: true,\n session: result.session,\n });\n } else if (result.error === \"Cannot delete system topic\") {\n deps.sendJson(res, 403, { error: result.error });\n } else {\n deps.sendJson(res, 404, { error: result.error ?? \"Not found\" });\n }\n });\n}\n","import type { Router } from \"../router.js\";\nimport type { RouteDeps } from \"../api-server.js\";\n\nexport function registerTunnelRoutes(router: Router, deps: RouteDeps): void {\n router.get(\"/api/tunnel\", async (_req, res) => {\n const tunnel = deps.core.tunnelService;\n if (tunnel) {\n deps.sendJson(res, 200, {\n enabled: true,\n url: tunnel.getPublicUrl(),\n provider: deps.core.configManager.get().tunnel.provider,\n });\n } else {\n deps.sendJson(res, 200, { enabled: false });\n }\n });\n\n router.get(\"/api/tunnel/list\", async (_req, res) => {\n const tunnel = deps.core.tunnelService;\n if (!tunnel) {\n deps.sendJson(res, 200, []);\n return;\n }\n deps.sendJson(res, 200, tunnel.listTunnels());\n });\n\n router.post(\"/api/tunnel\", async (req, res) => {\n const tunnel = deps.core.tunnelService;\n if (!tunnel) {\n deps.sendJson(res, 400, { error: \"Tunnel service is not enabled\" });\n return;\n }\n const body = await deps.readBody(req);\n if (body === null) {\n deps.sendJson(res, 413, { error: \"Request body too large\" });\n return;\n }\n if (!body) {\n deps.sendJson(res, 400, { error: \"Missing request body\" });\n return;\n }\n try {\n const { port, label, sessionId } = JSON.parse(body);\n if (!port || typeof port !== \"number\") {\n deps.sendJson(res, 400, {\n error: \"port is required and must be a number\",\n });\n return;\n }\n const entry = await tunnel.addTunnel(port, { label, sessionId });\n deps.sendJson(res, 200, entry);\n } catch (err) {\n deps.sendJson(res, 400, { error: (err as Error).message });\n }\n });\n\n router.delete(\"/api/tunnel/:port\", async (_req, res, params) => {\n const tunnel = deps.core.tunnelService;\n if (!tunnel) {\n deps.sendJson(res, 400, { error: \"Tunnel service is not enabled\" });\n return;\n }\n const port = parseInt(params.port, 10);\n try {\n await tunnel.stopTunnel(port);\n deps.sendJson(res, 200, { ok: true });\n } catch (err) {\n deps.sendJson(res, 400, { error: (err as Error).message });\n }\n });\n\n router.delete(\"/api/tunnel\", async (_req, res) => {\n const tunnel = deps.core.tunnelService;\n if (!tunnel) {\n deps.sendJson(res, 400, { error: \"Tunnel service is not enabled\" });\n return;\n }\n const count = tunnel.listTunnels().length;\n await tunnel.stopAllUser();\n deps.sendJson(res, 200, { ok: true, stopped: count });\n });\n}\n","import type { Router } from \"../router.js\";\nimport type { RouteDeps } from \"../api-server.js\";\nimport { getAgentCapabilities } from \"../../../core/agents/agent-registry.js\";\n\nexport function registerAgentRoutes(router: Router, deps: RouteDeps): void {\n router.get(\"/api/agents\", async (_req, res) => {\n const agents = deps.core.agentManager.getAvailableAgents();\n const defaultAgent = deps.core.configManager.get().defaultAgent;\n const agentsWithCaps = agents.map((a) => ({\n ...a,\n capabilities: getAgentCapabilities(a.name),\n }));\n deps.sendJson(res, 200, { agents: agentsWithCaps, default: defaultAgent });\n });\n}\n","import type { Router } from \"../router.js\";\nimport type { RouteDeps } from \"../api-server.js\";\n\nexport function registerNotifyRoutes(router: Router, deps: RouteDeps): void {\n router.post(\"/api/notify\", async (req, res) => {\n const body = await deps.readBody(req);\n let message: string | undefined;\n if (body) {\n try {\n const parsed = JSON.parse(body);\n message = parsed.message;\n } catch {\n deps.sendJson(res, 400, { error: \"Invalid JSON body\" });\n return;\n }\n }\n\n if (!message) {\n deps.sendJson(res, 400, { error: \"Missing message\" });\n return;\n }\n\n await deps.core.notificationManager.notifyAll({\n sessionId: \"system\",\n type: \"completed\",\n summary: message,\n });\n deps.sendJson(res, 200, { ok: true });\n });\n}\n"],"mappings":"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","names":["fs","path","fileURLToPath","path","log","fileURLToPath","resolve"]}
@@ -1,222 +0,0 @@
1
- import {
2
- createChildLogger
3
- } from "./chunk-XMMAGAT4.js";
4
-
5
- // src/plugins/usage/usage-store.ts
6
- import fs from "fs";
7
- import path from "path";
8
- var log = createChildLogger({ module: "usage-store" });
9
- var DEBOUNCE_MS = 2e3;
10
- var UsageStore = class {
11
- constructor(filePath, retentionDays) {
12
- this.filePath = filePath;
13
- this.retentionDays = retentionDays;
14
- this.load();
15
- this.cleanup();
16
- this.cleanupInterval = setInterval(
17
- () => this.cleanup(),
18
- 24 * 60 * 60 * 1e3
19
- );
20
- this.flushHandler = () => {
21
- try {
22
- this.flushSync();
23
- } catch {
24
- }
25
- };
26
- process.on("SIGTERM", this.flushHandler);
27
- process.on("SIGINT", this.flushHandler);
28
- process.on("exit", this.flushHandler);
29
- }
30
- records = [];
31
- debounceTimer = null;
32
- cleanupInterval = null;
33
- flushHandler = null;
34
- append(record) {
35
- this.records.push(record);
36
- this.scheduleDiskWrite();
37
- }
38
- query(period) {
39
- const cutoff = this.getCutoff(period);
40
- const filtered = cutoff ? this.records.filter((r) => new Date(r.timestamp).getTime() >= cutoff) : this.records;
41
- const totalTokens = filtered.reduce((sum, r) => sum + r.tokensUsed, 0);
42
- const totalCost = filtered.reduce(
43
- (sum, r) => sum + (r.cost?.amount ?? 0),
44
- 0
45
- );
46
- const sessionIds = new Set(filtered.map((r) => r.sessionId));
47
- const currency = filtered.find((r) => r.cost?.currency)?.cost?.currency ?? "USD";
48
- return {
49
- period,
50
- totalTokens,
51
- totalCost,
52
- currency,
53
- sessionCount: sessionIds.size,
54
- recordCount: filtered.length
55
- };
56
- }
57
- getMonthlyTotal() {
58
- const now = /* @__PURE__ */ new Date();
59
- const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
60
- const cutoff = startOfMonth.getTime();
61
- const filtered = this.records.filter(
62
- (r) => new Date(r.timestamp).getTime() >= cutoff
63
- );
64
- const totalCost = filtered.reduce(
65
- (sum, r) => sum + (r.cost?.amount ?? 0),
66
- 0
67
- );
68
- const currency = filtered.find((r) => r.cost?.currency)?.cost?.currency ?? "USD";
69
- return { totalCost, currency };
70
- }
71
- cleanup() {
72
- const cutoff = Date.now() - this.retentionDays * 24 * 60 * 60 * 1e3;
73
- const before = this.records.length;
74
- this.records = this.records.filter(
75
- (r) => new Date(r.timestamp).getTime() >= cutoff
76
- );
77
- const removed = before - this.records.length;
78
- if (removed > 0) {
79
- log.info({ removed }, "Cleaned up expired usage records");
80
- this.scheduleDiskWrite();
81
- }
82
- }
83
- flushSync() {
84
- if (this.debounceTimer) {
85
- clearTimeout(this.debounceTimer);
86
- this.debounceTimer = null;
87
- }
88
- const data = { version: 1, records: this.records };
89
- const dir = path.dirname(this.filePath);
90
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
91
- fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2));
92
- }
93
- destroy() {
94
- if (this.debounceTimer) this.flushSync();
95
- if (this.cleanupInterval) clearInterval(this.cleanupInterval);
96
- if (this.flushHandler) {
97
- process.removeListener("SIGTERM", this.flushHandler);
98
- process.removeListener("SIGINT", this.flushHandler);
99
- process.removeListener("exit", this.flushHandler);
100
- this.flushHandler = null;
101
- }
102
- }
103
- load() {
104
- if (!fs.existsSync(this.filePath)) return;
105
- try {
106
- const raw = JSON.parse(
107
- fs.readFileSync(this.filePath, "utf-8")
108
- );
109
- if (raw.version !== 1) {
110
- log.warn(
111
- { version: raw.version },
112
- "Unknown usage store version, skipping load"
113
- );
114
- return;
115
- }
116
- this.records = raw.records || [];
117
- log.debug({ count: this.records.length }, "Loaded usage records");
118
- } catch (err) {
119
- log.error({ err }, "Failed to load usage store, backing up corrupt file");
120
- try {
121
- fs.copyFileSync(this.filePath, this.filePath + ".bak");
122
- } catch {
123
- }
124
- this.records = [];
125
- }
126
- }
127
- getCutoff(period) {
128
- const now = /* @__PURE__ */ new Date();
129
- switch (period) {
130
- case "today": {
131
- const start = new Date(now);
132
- start.setHours(0, 0, 0, 0);
133
- return start.getTime();
134
- }
135
- case "week":
136
- return Date.now() - 7 * 24 * 60 * 60 * 1e3;
137
- case "month": {
138
- const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
139
- return startOfMonth.getTime();
140
- }
141
- case "all":
142
- return null;
143
- }
144
- }
145
- scheduleDiskWrite() {
146
- if (this.debounceTimer) clearTimeout(this.debounceTimer);
147
- this.debounceTimer = setTimeout(() => {
148
- this.flushSync();
149
- }, DEBOUNCE_MS);
150
- }
151
- };
152
-
153
- // src/plugins/usage/usage-budget.ts
154
- var UsageBudget = class {
155
- constructor(store, config, now = () => /* @__PURE__ */ new Date()) {
156
- this.store = store;
157
- this.config = config;
158
- this.now = now;
159
- this.lastNotifiedMonth = this.now().getMonth();
160
- }
161
- lastNotifiedStatus = "ok";
162
- lastNotifiedMonth;
163
- check() {
164
- if (!this.config.monthlyBudget) {
165
- return { status: "ok" };
166
- }
167
- const currentMonth = this.now().getMonth();
168
- if (currentMonth !== this.lastNotifiedMonth) {
169
- this.lastNotifiedStatus = "ok";
170
- this.lastNotifiedMonth = currentMonth;
171
- }
172
- const { totalCost } = this.store.getMonthlyTotal();
173
- const budget = this.config.monthlyBudget;
174
- const threshold = this.config.warningThreshold;
175
- let status;
176
- if (totalCost >= budget) {
177
- status = "exceeded";
178
- } else if (totalCost >= threshold * budget) {
179
- status = "warning";
180
- } else {
181
- status = "ok";
182
- }
183
- let message;
184
- if (status !== "ok" && status !== this.lastNotifiedStatus) {
185
- const pct = Math.round(totalCost / budget * 100);
186
- const filled = Math.round(Math.min(totalCost / budget, 1) * 10);
187
- const bar = "\u2593".repeat(filled) + "\u2591".repeat(10 - filled);
188
- if (status === "warning") {
189
- message = `\u26A0\uFE0F <b>Budget Warning</b>
190
- Monthly usage: $${totalCost.toFixed(2)} / $${budget.toFixed(2)} (${pct}%)
191
- ${bar} ${pct}%`;
192
- } else {
193
- message = `\u{1F6A8} <b>Budget Exceeded</b>
194
- Monthly usage: $${totalCost.toFixed(2)} / $${budget.toFixed(2)} (${pct}%)
195
- ${bar} ${pct}%
196
- Sessions are NOT blocked \u2014 this is a warning only.`;
197
- }
198
- }
199
- this.lastNotifiedStatus = status;
200
- return { status, message };
201
- }
202
- getStatus() {
203
- const { totalCost } = this.store.getMonthlyTotal();
204
- const budget = this.config.monthlyBudget ?? 0;
205
- let status = "ok";
206
- if (budget > 0) {
207
- if (totalCost >= budget) {
208
- status = "exceeded";
209
- } else if (totalCost >= this.config.warningThreshold * budget) {
210
- status = "warning";
211
- }
212
- }
213
- const percent = budget > 0 ? Math.round(totalCost / budget * 100) : 0;
214
- return { status, used: totalCost, budget, percent };
215
- }
216
- };
217
-
218
- export {
219
- UsageStore,
220
- UsageBudget
221
- };
222
- //# sourceMappingURL=chunk-WAAD23KY.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/plugins/usage/usage-store.ts","../../src/plugins/usage/usage-budget.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { UsageRecord, UsageSummary } from \"../../core/types.js\";\nimport { createChildLogger } from \"../../core/utils/log.js\";\n\nconst log = createChildLogger({ module: \"usage-store\" });\n\ninterface StoreFile {\n version: number;\n records: UsageRecord[];\n}\n\nconst DEBOUNCE_MS = 2000;\n\nexport class UsageStore {\n private records: UsageRecord[] = [];\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\n private flushHandler: (() => void) | null = null;\n\n constructor(\n private filePath: string,\n private retentionDays: number,\n ) {\n this.load();\n this.cleanup();\n\n this.cleanupInterval = setInterval(\n () => this.cleanup(),\n 24 * 60 * 60 * 1000,\n );\n\n this.flushHandler = () => {\n try {\n this.flushSync();\n } catch {\n // Best effort — don't block other exit handlers (e.g., session store flush)\n }\n };\n process.on(\"SIGTERM\", this.flushHandler);\n process.on(\"SIGINT\", this.flushHandler);\n process.on(\"exit\", this.flushHandler);\n }\n\n append(record: UsageRecord): void {\n this.records.push(record);\n this.scheduleDiskWrite();\n }\n\n query(period: \"today\" | \"week\" | \"month\" | \"all\"): UsageSummary {\n const cutoff = this.getCutoff(period);\n const filtered = cutoff\n ? this.records.filter((r) => new Date(r.timestamp).getTime() >= cutoff)\n : this.records;\n\n const totalTokens = filtered.reduce((sum, r) => sum + r.tokensUsed, 0);\n const totalCost = filtered.reduce(\n (sum, r) => sum + (r.cost?.amount ?? 0),\n 0,\n );\n const sessionIds = new Set(filtered.map((r) => r.sessionId));\n const currency =\n filtered.find((r) => r.cost?.currency)?.cost?.currency ?? \"USD\";\n\n return {\n period,\n totalTokens,\n totalCost,\n currency,\n sessionCount: sessionIds.size,\n recordCount: filtered.length,\n };\n }\n\n getMonthlyTotal(): { totalCost: number; currency: string } {\n const now = new Date();\n const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);\n const cutoff = startOfMonth.getTime();\n\n const filtered = this.records.filter(\n (r) => new Date(r.timestamp).getTime() >= cutoff,\n );\n const totalCost = filtered.reduce(\n (sum, r) => sum + (r.cost?.amount ?? 0),\n 0,\n );\n const currency =\n filtered.find((r) => r.cost?.currency)?.cost?.currency ?? \"USD\";\n\n return { totalCost, currency };\n }\n\n cleanup(): void {\n const cutoff =\n Date.now() - this.retentionDays * 24 * 60 * 60 * 1000;\n const before = this.records.length;\n this.records = this.records.filter(\n (r) => new Date(r.timestamp).getTime() >= cutoff,\n );\n const removed = before - this.records.length;\n if (removed > 0) {\n log.info({ removed }, \"Cleaned up expired usage records\");\n this.scheduleDiskWrite();\n }\n }\n\n flushSync(): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n const data: StoreFile = { version: 1, records: this.records };\n const dir = path.dirname(this.filePath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2));\n }\n\n destroy(): void {\n if (this.debounceTimer) this.flushSync();\n if (this.cleanupInterval) clearInterval(this.cleanupInterval);\n if (this.flushHandler) {\n process.removeListener(\"SIGTERM\", this.flushHandler);\n process.removeListener(\"SIGINT\", this.flushHandler);\n process.removeListener(\"exit\", this.flushHandler);\n this.flushHandler = null;\n }\n }\n\n private load(): void {\n if (!fs.existsSync(this.filePath)) return;\n try {\n const raw = JSON.parse(\n fs.readFileSync(this.filePath, \"utf-8\"),\n ) as StoreFile;\n if (raw.version !== 1) {\n log.warn(\n { version: raw.version },\n \"Unknown usage store version, skipping load\",\n );\n return;\n }\n this.records = raw.records || [];\n log.debug({ count: this.records.length }, \"Loaded usage records\");\n } catch (err) {\n log.error({ err }, \"Failed to load usage store, backing up corrupt file\");\n try {\n fs.copyFileSync(this.filePath, this.filePath + \".bak\");\n } catch {\n /* best effort */\n }\n this.records = [];\n }\n }\n\n private getCutoff(\n period: \"today\" | \"week\" | \"month\" | \"all\",\n ): number | null {\n const now = new Date();\n switch (period) {\n case \"today\": {\n const start = new Date(now);\n start.setHours(0, 0, 0, 0);\n return start.getTime();\n }\n case \"week\":\n return Date.now() - 7 * 24 * 60 * 60 * 1000;\n case \"month\": {\n // Use current calendar month (1st of month), consistent with getMonthlyTotal()\n const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);\n return startOfMonth.getTime();\n }\n case \"all\":\n return null;\n }\n }\n\n private scheduleDiskWrite(): void {\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n this.debounceTimer = setTimeout(() => {\n this.flushSync();\n }, DEBOUNCE_MS);\n }\n}\n","import type { UsageConfig } from \"../../core/config/config.js\";\nimport type { UsageStore } from \"./usage-store.js\";\n\nexport class UsageBudget {\n private lastNotifiedStatus: \"ok\" | \"warning\" | \"exceeded\" = \"ok\";\n private lastNotifiedMonth: number;\n\n constructor(\n private store: UsageStore,\n private config: UsageConfig,\n private now: () => Date = () => new Date(),\n ) {\n this.lastNotifiedMonth = this.now().getMonth();\n }\n\n check(): { status: \"ok\" | \"warning\" | \"exceeded\"; message?: string } {\n if (!this.config.monthlyBudget) {\n return { status: \"ok\" };\n }\n\n // Reset de-duplication at month boundary\n const currentMonth = this.now().getMonth();\n if (currentMonth !== this.lastNotifiedMonth) {\n this.lastNotifiedStatus = \"ok\";\n this.lastNotifiedMonth = currentMonth;\n }\n\n const { totalCost } = this.store.getMonthlyTotal();\n const budget = this.config.monthlyBudget;\n const threshold = this.config.warningThreshold;\n\n let status: \"ok\" | \"warning\" | \"exceeded\";\n if (totalCost >= budget) {\n status = \"exceeded\";\n } else if (totalCost >= threshold * budget) {\n status = \"warning\";\n } else {\n status = \"ok\";\n }\n\n // Only emit message on status change (prevents spam)\n let message: string | undefined;\n if (status !== \"ok\" && status !== this.lastNotifiedStatus) {\n const pct = Math.round((totalCost / budget) * 100);\n const filled = Math.round(Math.min(totalCost / budget, 1) * 10);\n const bar = \"▓\".repeat(filled) + \"░\".repeat(10 - filled);\n\n if (status === \"warning\") {\n message =\n `⚠️ <b>Budget Warning</b>\\n` +\n `Monthly usage: $${totalCost.toFixed(2)} / $${budget.toFixed(2)} (${pct}%)\\n` +\n `${bar} ${pct}%`;\n } else {\n message =\n `🚨 <b>Budget Exceeded</b>\\n` +\n `Monthly usage: $${totalCost.toFixed(2)} / $${budget.toFixed(2)} (${pct}%)\\n` +\n `${bar} ${pct}%\\n` +\n `Sessions are NOT blocked — this is a warning only.`;\n }\n }\n\n this.lastNotifiedStatus = status;\n return { status, message };\n }\n\n getStatus(): {\n status: \"ok\" | \"warning\" | \"exceeded\";\n used: number;\n budget: number;\n percent: number;\n } {\n const { totalCost } = this.store.getMonthlyTotal();\n const budget = this.config.monthlyBudget ?? 0;\n\n let status: \"ok\" | \"warning\" | \"exceeded\" = \"ok\";\n if (budget > 0) {\n if (totalCost >= budget) {\n status = \"exceeded\";\n } else if (totalCost >= this.config.warningThreshold * budget) {\n status = \"warning\";\n }\n }\n\n const percent = budget > 0 ? Math.round((totalCost / budget) * 100) : 0;\n return { status, used: totalCost, budget, percent };\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/cli/integrate.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, chmodSync, rmdirSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { getAgentCapabilities, commandExists, listAgentsWithIntegration } from \"../core/agents/agent-dependencies.js\";\nimport type { AgentIntegrationSpec } from \"../core/agents/agent-dependencies.js\";\n\nexport interface IntegrationResult {\n success: boolean;\n logs: string[];\n}\n\nexport interface IntegrationItem {\n id: string;\n name: string;\n description: string;\n isInstalled(): boolean;\n install(): Promise<IntegrationResult>;\n uninstall(): Promise<IntegrationResult>;\n}\n\nexport interface AgentIntegration {\n items: IntegrationItem[];\n}\n\nconst HOOK_MARKER = \"openacp-inject-session.sh\";\n\nfunction expandPath(p: string): string {\n return p.replace(/^~/, homedir());\n}\n\n// --- Script generators ---\n\nfunction generateInjectScript(_agentKey: string, spec: AgentIntegrationSpec): string {\n const sidVar = spec.sessionIdVar ?? \"SESSION_ID\";\n const cwdVar = spec.workingDirVar ?? \"WORKING_DIR\";\n\n // Resolve jq: check ~/.openacp/bin first, then PATH\n const jqResolver = `JQ=$(command -v jq 2>/dev/null || echo \"$HOME/.openacp/bin/jq\")`;\n\n if (spec.outputFormat === \"plaintext\") {\n return `#!/bin/bash\n${jqResolver}\nINPUT=$(cat)\nSESSION_ID=$(echo \"$INPUT\" | \"$JQ\" -r '${spec.sessionIdField}')\nCWD=$(echo \"$INPUT\" | \"$JQ\" -r '.cwd')\n\necho \"${sidVar}: $SESSION_ID\"\necho \"${cwdVar}: $CWD\"\n\nexit 0\n`;\n }\n\n // JSON output (Gemini, Cline, Cursor)\n return `#!/bin/bash\n${jqResolver}\nINPUT=$(cat)\nSESSION_ID=$(echo \"$INPUT\" | \"$JQ\" -r '${spec.sessionIdField}')\nCWD=$(echo \"$INPUT\" | \"$JQ\" -r '.cwd')\n\n\"$JQ\" -n --arg sid \"$SESSION_ID\" --arg cwd \"$CWD\" \\\\\n '{\"additionalContext\":\"${sidVar}: \\\\($sid)\\\\n${cwdVar}: \\\\($cwd)\"}'\n\nexit 0\n`;\n}\n\nfunction generateHandoffScript(agentKey: string): string {\n return `#!/bin/bash\nSESSION_ID=$1\nCWD=$2\nCHANNEL=$3\n\nif [ -z \"$SESSION_ID\" ]; then\n echo \"Usage: openacp-handoff.sh <session_id> [cwd] [channel]\"\n exit 1\nfi\n\nopenacp adopt ${agentKey} \"$SESSION_ID\" \\${CWD:+--cwd \"$CWD\"} \\${CHANNEL:+--channel \"$CHANNEL\"}\n`;\n}\n\nfunction generateTunnelCommand(): string {\n return `---\ndescription: Expose local ports to the internet. Use when user wants to share, preview, or access their local dev server remotely. Triggers on phrases like \"expose port\", \"map port\", \"share my app\", \"make it public\", \"open tunnel\", \"public URL\", \"share localhost\", \"preview on phone\", \"access from outside\", \"forward port\", \"ngrok\", \"cloudflare tunnel\", etc.\n---\n\nYou have access to OpenACP tunnel management via CLI. This creates a public URL for any local port (dev servers, APIs, static sites, etc.) using Cloudflare tunnel.\n\n## Commands\n\n\\`\\`\\`bash\n# Create a tunnel — exposes local port to the internet\nopenacp tunnel add <port> --label <name>\n\n# List all active tunnels with their public URLs\nopenacp tunnel list\n\n# Stop a specific tunnel\nopenacp tunnel stop <port>\n\n# Stop all tunnels\nopenacp tunnel stop-all\n\\`\\`\\`\n\n## When to use\n\nUser wants to:\n- **Share their local app** — \"share this on my phone\", \"let my friend see this\", \"preview on mobile\"\n- **Expose a port** — \"expose port 3000\", \"map port 5173\", \"make port 8080 public\"\n- **Get a public URL** — \"give me a public URL\", \"I need an external link\", \"make localhost accessible\"\n- **Open a tunnel** — \"open tunnel\", \"start tunnel\", \"tunnel this\", \"bật tunnel\"\n- **Forward/proxy a port** — \"forward port 3000\", \"proxy my server\"\n- **Deploy preview** — \"deploy preview\", \"share a preview link\"\n- **Access remotely** — \"access from my phone\", \"access from outside\"\n- **Manage tunnels** — \"show tunnels\", \"list tunnels\", \"stop tunnel\", \"close tunnel\", \"kill tunnel\"\n\n## How to respond\n\n1. Run the CLI command\n2. Share the public URL with the user\n3. Mention the URL works on any device (phone, tablet, other computer)\n4. If the user hasn't started a dev server yet, remind them to start one first\n\n## Example flow\n\nUser: \"I want to see this React app on my phone\"\n→ Check if dev server is running (e.g. port 5173 for Vite)\n→ Run: \\`openacp tunnel add 5173 --label react-app\\`\n→ Share the public URL\n`;\n}\n\nfunction generateHandoffCommand(_agentKey: string, spec: AgentIntegrationSpec): string {\n const sidVar = spec.sessionIdVar ?? \"SESSION_ID\";\n const cwdVar = spec.workingDirVar ?? \"WORKING_DIR\";\n const hooksDir = expandPath(spec.hooksDirPath);\n\n return `---\ndescription: Transfer current session to OpenACP (Telegram/Discord)\n---\n\nLook at the context injected at the start of this message to find\n${sidVar} and ${cwdVar}, then run:\n\nbash ${hooksDir}openacp-handoff.sh <${sidVar}> <${cwdVar}> <args if any>\n\nUsage: /openacp:handoff [channel]\n channel: telegram, discord, or omit for default adapter\n\nExamples:\n /openacp:handoff\n /openacp:handoff discord\n /openacp:handoff telegram\n`;\n}\n\n// --- Settings mergers ---\n\nfunction mergeSettingsJson(settingsPath: string, hookEvent: string, hookScriptPath: string): void {\n const fullPath = expandPath(settingsPath);\n let settings: Record<string, unknown> = {};\n\n if (existsSync(fullPath)) {\n const raw = readFileSync(fullPath, \"utf-8\");\n writeFileSync(`${fullPath}.bak`, raw);\n settings = JSON.parse(raw);\n }\n\n const hooks = (settings.hooks ?? {}) as Record<string, unknown[]>;\n settings.hooks = hooks;\n\n const eventHooks = (hooks[hookEvent] ?? []) as Array<{ hooks?: Array<{ type?: string; command?: string }> }>;\n hooks[hookEvent] = eventHooks;\n\n const alreadyInstalled = eventHooks.some((group) =>\n group.hooks?.some((h) => h.command?.includes(HOOK_MARKER)),\n );\n\n if (!alreadyInstalled) {\n eventHooks.push({\n hooks: [{ type: \"command\", command: hookScriptPath }],\n });\n }\n\n mkdirSync(dirname(fullPath), { recursive: true });\n writeFileSync(fullPath, JSON.stringify(settings, null, 2) + \"\\n\");\n}\n\nfunction mergeHooksJson(settingsPath: string, hookEvent: string, hookScriptPath: string): void {\n const fullPath = expandPath(settingsPath);\n let config: Record<string, unknown> = { version: 1 };\n\n if (existsSync(fullPath)) {\n const raw = readFileSync(fullPath, \"utf-8\");\n writeFileSync(`${fullPath}.bak`, raw);\n config = JSON.parse(raw);\n }\n\n const hooks = (config.hooks ?? {}) as Record<string, unknown[]>;\n config.hooks = hooks;\n\n const eventHooks = (hooks[hookEvent] ?? []) as Array<{ command?: string }>;\n hooks[hookEvent] = eventHooks;\n\n const alreadyInstalled = eventHooks.some((h) => h.command?.includes(HOOK_MARKER));\n\n if (!alreadyInstalled) {\n eventHooks.push({ command: hookScriptPath });\n }\n\n mkdirSync(dirname(fullPath), { recursive: true });\n writeFileSync(fullPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\nfunction removeFromSettingsJson(settingsPath: string, hookEvent: string): void {\n const fullPath = expandPath(settingsPath);\n if (!existsSync(fullPath)) return;\n\n const raw = readFileSync(fullPath, \"utf-8\");\n const settings = JSON.parse(raw);\n const hooks = settings.hooks as Record<string, unknown[]> | undefined;\n if (!hooks?.[hookEvent]) return;\n\n hooks[hookEvent] = (hooks[hookEvent] as Array<{ hooks?: Array<{ command?: string }> }>).filter(\n (group) => !group.hooks?.some((h) => h.command?.includes(\"openacp-\")),\n );\n\n if ((hooks[hookEvent] as unknown[]).length === 0) {\n delete hooks[hookEvent];\n }\n\n writeFileSync(fullPath, JSON.stringify(settings, null, 2) + \"\\n\");\n}\n\nfunction removeFromHooksJson(settingsPath: string, hookEvent: string): void {\n const fullPath = expandPath(settingsPath);\n if (!existsSync(fullPath)) return;\n\n const raw = readFileSync(fullPath, \"utf-8\");\n const config = JSON.parse(raw);\n const hooks = config.hooks as Record<string, unknown[]> | undefined;\n if (!hooks?.[hookEvent]) return;\n\n hooks[hookEvent] = (hooks[hookEvent] as Array<{ command?: string }>).filter(\n (h) => !h.command?.includes(\"openacp-\"),\n );\n\n if ((hooks[hookEvent] as unknown[]).length === 0) {\n delete hooks[hookEvent];\n }\n\n writeFileSync(fullPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\n// --- Core install/uninstall ---\n\nexport async function installIntegration(agentKey: string, spec: AgentIntegrationSpec): Promise<IntegrationResult> {\n const logs: string[] = [];\n try {\n // Check jq\n if (!commandExists(\"jq\")) {\n return {\n success: false,\n logs: [\"jq is required for handoff hooks. Install: brew install jq (macOS) or apt install jq (Linux)\"],\n };\n }\n\n const hooksDir = expandPath(spec.hooksDirPath);\n mkdirSync(hooksDir, { recursive: true });\n\n // Inject script\n const injectPath = join(hooksDir, \"openacp-inject-session.sh\");\n writeFileSync(injectPath, generateInjectScript(agentKey, spec));\n chmodSync(injectPath, 0o755);\n logs.push(`Created ${injectPath}`);\n\n // Handoff script\n const handoffPath = join(hooksDir, \"openacp-handoff.sh\");\n writeFileSync(handoffPath, generateHandoffScript(agentKey));\n chmodSync(handoffPath, 0o755);\n logs.push(`Created ${handoffPath}`);\n\n // Slash command / skill\n if (spec.commandsPath && spec.handoffCommandName) {\n if (spec.commandFormat === \"skill\") {\n const skillDir = expandPath(join(spec.commandsPath, spec.handoffCommandName));\n mkdirSync(skillDir, { recursive: true });\n const skillPath = join(skillDir, \"SKILL.md\");\n writeFileSync(skillPath, generateHandoffCommand(agentKey, spec));\n logs.push(`Created ${skillPath}`);\n } else {\n const cmdsDir = expandPath(spec.commandsPath);\n mkdirSync(cmdsDir, { recursive: true });\n const cmdPath = join(cmdsDir, `${spec.handoffCommandName}.md`);\n writeFileSync(cmdPath, generateHandoffCommand(agentKey, spec));\n logs.push(`Created ${cmdPath}`);\n }\n }\n\n // Merge settings\n const injectFullPath = join(hooksDir, \"openacp-inject-session.sh\");\n if (spec.settingsFormat === \"hooks_json\") {\n mergeHooksJson(spec.settingsPath, spec.hookEvent, injectFullPath);\n } else {\n mergeSettingsJson(spec.settingsPath, spec.hookEvent, injectFullPath);\n }\n logs.push(`Updated ${expandPath(spec.settingsPath)}`);\n\n return { success: true, logs };\n } catch (err) {\n logs.push(`Error: ${err instanceof Error ? err.message : String(err)}`);\n return { success: false, logs };\n }\n}\n\nexport async function uninstallIntegration(agentKey: string, spec: AgentIntegrationSpec): Promise<IntegrationResult> {\n const logs: string[] = [];\n try {\n const hooksDir = expandPath(spec.hooksDirPath);\n\n // Remove hook scripts\n for (const filename of [\"openacp-inject-session.sh\", \"openacp-handoff.sh\"]) {\n const filePath = join(hooksDir, filename);\n if (existsSync(filePath)) {\n unlinkSync(filePath);\n logs.push(`Removed ${filePath}`);\n }\n }\n\n // Remove slash command / skill\n if (spec.commandsPath && spec.handoffCommandName) {\n if (spec.commandFormat === \"skill\") {\n const skillDir = expandPath(join(spec.commandsPath, spec.handoffCommandName));\n const skillPath = join(skillDir, \"SKILL.md\");\n if (existsSync(skillPath)) {\n unlinkSync(skillPath);\n try { rmdirSync(skillDir); } catch { /* not empty */ }\n logs.push(`Removed ${skillPath}`);\n }\n } else {\n const cmdPath = expandPath(join(spec.commandsPath, `${spec.handoffCommandName}.md`));\n if (existsSync(cmdPath)) {\n unlinkSync(cmdPath);\n logs.push(`Removed ${cmdPath}`);\n }\n }\n }\n\n // Clean settings\n if (spec.settingsFormat === \"hooks_json\") {\n removeFromHooksJson(spec.settingsPath, spec.hookEvent);\n } else {\n removeFromSettingsJson(spec.settingsPath, spec.hookEvent);\n }\n logs.push(`Updated ${expandPath(spec.settingsPath)}`);\n\n return { success: true, logs };\n } catch (err) {\n logs.push(`Error: ${err instanceof Error ? err.message : String(err)}`);\n return { success: false, logs };\n }\n}\n\n// --- Public API (backward compat with existing cmdIntegrate / Telegram integrate) ---\n\nfunction buildHandoffItem(agentKey: string, spec: AgentIntegrationSpec): IntegrationItem {\n const hooksDir = expandPath(spec.hooksDirPath);\n return {\n id: \"handoff\",\n name: \"Handoff\",\n description: \"Transfer sessions between terminal and messaging platforms\",\n isInstalled(): boolean {\n return (\n existsSync(join(hooksDir, \"openacp-inject-session.sh\")) &&\n existsSync(join(hooksDir, \"openacp-handoff.sh\"))\n );\n },\n install: () => installIntegration(agentKey, spec),\n uninstall: () => uninstallIntegration(agentKey, spec),\n };\n}\n\nfunction getSkillBasePath(spec: AgentIntegrationSpec): string {\n // Skills go into the agent's skills directory (sibling to commands)\n // Claude: ~/.claude/skills/, Cursor: ~/.cursor/skills/\n const base = spec.commandsPath!;\n // If commandsPath is commands/, use skills/ instead\n const skillsBase = base.replace(/\\/commands\\/?$/, \"/skills/\");\n return expandPath(skillsBase);\n}\n\nfunction buildTunnelItem(spec: AgentIntegrationSpec): IntegrationItem | null {\n if (!spec.commandsPath) return null;\n\n function getTunnelPath(): string {\n return join(getSkillBasePath(spec), \"openacp-tunnel\", \"SKILL.md\");\n }\n\n return {\n id: \"tunnel\",\n name: \"Tunnel\",\n description: \"Expose local ports to the internet via OpenACP tunnel\",\n isInstalled(): boolean {\n return existsSync(getTunnelPath());\n },\n async install(): Promise<IntegrationResult> {\n const logs: string[] = [];\n try {\n const skillPath = getTunnelPath();\n mkdirSync(dirname(skillPath), { recursive: true });\n writeFileSync(skillPath, generateTunnelCommand());\n logs.push(`Created ${skillPath}`);\n return { success: true, logs };\n } catch (err) {\n logs.push(`Error: ${err instanceof Error ? err.message : String(err)}`);\n return { success: false, logs };\n }\n },\n async uninstall(): Promise<IntegrationResult> {\n const logs: string[] = [];\n try {\n const skillPath = getTunnelPath();\n if (existsSync(skillPath)) {\n unlinkSync(skillPath);\n try { rmdirSync(dirname(skillPath)); } catch { /* not empty */ }\n logs.push(`Removed ${skillPath}`);\n }\n return { success: true, logs };\n } catch (err) {\n logs.push(`Error: ${err instanceof Error ? err.message : String(err)}`);\n return { success: false, logs };\n }\n },\n };\n}\n\nexport function getIntegration(agentName: string): AgentIntegration | undefined {\n const caps = getAgentCapabilities(agentName);\n if (!caps.integration) return undefined;\n const items: IntegrationItem[] = [buildHandoffItem(agentName, caps.integration)];\n const tunnelItem = buildTunnelItem(caps.integration);\n if (tunnelItem) items.push(tunnelItem);\n return { items };\n}\n\nexport function listIntegrations(): string[] {\n return listAgentsWithIntegration();\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/core/command-registry.ts","../../src/core/commands/session.ts","../../src/core/commands/agents.ts","../../src/core/commands/admin.ts","../../src/core/commands/help.ts","../../src/core/commands/menu.ts","../../src/core/commands/index.ts","../../src/main.ts"],"sourcesContent":["import type { CommandDef, CommandArgs, CommandResponse } from './plugin/types.js'\n\ninterface RegisteredCommand extends CommandDef {\n /** Scope extracted from pluginName, e.g. '@openacp/speech' → 'speech' */\n scope?: string\n}\n\n/**\n * Central command registry with namespace resolution and adapter-specific overrides.\n *\n * Namespace rules:\n * - System commands always own the short name.\n * - Among plugins, the first to register wins the short name.\n * - Every plugin command also gets a qualified name: `scope:name`.\n * - Adapter plugins (@openacp/telegram, @openacp/discord, @openacp/slack)\n * registering a command that already exists → stored as an override\n * keyed by `channelId:commandName`, used when channelId matches.\n */\nexport class CommandRegistry {\n /** Main registry: short names + qualified names → RegisteredCommand */\n private commands = new Map<string, RegisteredCommand>()\n\n /** Adapter-specific overrides: `channelId:commandName` → RegisteredCommand */\n private overrides = new Map<string, RegisteredCommand>()\n\n private static ADAPTER_SCOPES = new Set(['telegram', 'discord', 'slack'])\n\n /**\n * Register a command definition.\n * @param def - Command definition\n * @param pluginName - Plugin that owns the command (set automatically by PluginContext)\n */\n register(def: CommandDef, pluginName?: string): void {\n const cmd: RegisteredCommand = {\n ...def,\n pluginName: pluginName ?? def.pluginName,\n }\n\n if (pluginName) {\n cmd.scope = CommandRegistry.extractScope(pluginName)\n }\n\n const qualifiedName = cmd.scope ? `${cmd.scope}:${cmd.name}` : undefined\n\n // Check if this is an adapter plugin overriding an existing command\n if (cmd.scope && CommandRegistry.ADAPTER_SCOPES.has(cmd.scope) && this.commands.has(cmd.name)) {\n // Store as adapter override\n this.overrides.set(`${cmd.scope}:${cmd.name}`, cmd)\n return\n }\n\n // Always register qualified name if available\n if (qualifiedName) {\n this.commands.set(qualifiedName, cmd)\n }\n\n // Short name logic\n if (this.commands.has(cmd.name)) {\n const existing = this.commands.get(cmd.name)!\n // System commands always win the short name\n if (existing.category === 'system') {\n // Plugin gets qualified name only (already registered above)\n return\n }\n // First plugin wins short name; later plugins get qualified only\n return\n }\n\n // No conflict — register short name\n this.commands.set(cmd.name, cmd)\n }\n\n /** Retrieve a command by name (short or qualified). */\n get(name: string): RegisteredCommand | undefined {\n return this.commands.get(name)\n }\n\n /** Remove a command by short name. Also removes its qualified name entry. */\n unregister(name: string): void {\n const cmd = this.commands.get(name)\n if (cmd) {\n this.commands.delete(name)\n // Also remove qualified name\n if (cmd.scope) {\n this.commands.delete(`${cmd.scope}:${name}`)\n }\n }\n // Also try removing as qualified name\n if (!cmd) {\n this.commands.delete(name)\n }\n }\n\n /** Remove all commands registered by a given plugin. */\n unregisterByPlugin(pluginName: string): void {\n const scope = CommandRegistry.extractScope(pluginName)\n const toDelete: string[] = []\n\n for (const [key, cmd] of this.commands) {\n if (cmd.pluginName === pluginName) {\n toDelete.push(key)\n }\n }\n\n for (const key of toDelete) {\n this.commands.delete(key)\n }\n\n // Also remove adapter overrides\n for (const [key, cmd] of this.overrides) {\n if (cmd.pluginName === pluginName) {\n this.overrides.delete(key)\n }\n }\n }\n\n /** Return all unique commands (deduplicated — each command appears once). */\n getAll(): RegisteredCommand[] {\n const seen = new Set<RegisteredCommand>()\n for (const cmd of this.commands.values()) {\n seen.add(cmd)\n }\n return [...seen]\n }\n\n /** Filter commands by category. */\n getByCategory(category: 'system' | 'plugin'): RegisteredCommand[] {\n return this.getAll().filter((cmd) => cmd.category === category)\n }\n\n /**\n * Parse and execute a command string.\n * @param commandString - Full command string, e.g. \"/greet hello world\"\n * @param baseArgs - Base arguments (channelId, userId, etc.)\n * @returns CommandResponse\n */\n async execute(commandString: string, baseArgs: CommandArgs): Promise<CommandResponse> {\n // Parse command name and raw args\n const trimmed = commandString.trim()\n const spaceIdx = trimmed.indexOf(' ')\n const cmdName = spaceIdx === -1 ? trimmed.slice(1) : trimmed.slice(1, spaceIdx)\n const rawArgs = spaceIdx === -1 ? '' : trimmed.slice(spaceIdx + 1)\n\n // Check for adapter-specific override first\n const overrideKey = `${baseArgs.channelId}:${cmdName}`\n const override = this.overrides.get(overrideKey)\n\n const cmd = override ?? this.commands.get(cmdName)\n\n if (!cmd) {\n return { type: 'error', message: `Unknown command: /${cmdName}` }\n }\n\n const args: CommandArgs = {\n ...baseArgs,\n raw: rawArgs,\n }\n\n try {\n const result = await cmd.handler(args)\n if (result === undefined || result === null) {\n return { type: 'silent' }\n }\n return result\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return { type: 'error', message: `Command /${cmdName} failed: ${message}` }\n }\n }\n\n /** Extract scope from plugin name: '@openacp/speech' → 'speech', 'my-plugin' → 'my-plugin' */\n static extractScope(pluginName: string): string {\n const slashIdx = pluginName.lastIndexOf('/')\n if (slashIdx !== -1) {\n return pluginName.slice(slashIdx + 1)\n }\n return pluginName\n }\n}\n","import type { CommandRegistry } from '../command-registry.js'\nimport type { CommandResponse } from '../plugin/types.js'\n\nexport function registerSessionCommands(registry: CommandRegistry, _core: unknown): void {\n registry.register({\n name: 'new',\n description: 'Start a new session',\n usage: '[agent-name]',\n category: 'system',\n handler: async (args) => {\n const agent = args.raw.trim()\n if (agent) {\n return { type: 'text', text: `Starting new session with agent: ${agent}` } satisfies CommandResponse\n }\n return { type: 'text', text: 'Starting new session...' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'cancel',\n description: 'Cancel the current agent turn',\n category: 'system',\n handler: async () => {\n return { type: 'silent' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'status',\n description: 'Show current session status',\n category: 'system',\n handler: async () => {\n return { type: 'text', text: 'No active session.' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'sessions',\n description: 'List all active sessions',\n category: 'system',\n handler: async () => {\n return { type: 'text', text: 'No active sessions.' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'clear',\n description: 'Clear session history',\n category: 'system',\n handler: async () => {\n return { type: 'silent' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'newchat',\n description: 'End current session and start a new one',\n category: 'system',\n handler: async () => {\n return { type: 'text', text: 'Ending session and starting a new one...' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'resume',\n description: 'Resume a previous session',\n usage: '<session-number>',\n category: 'system',\n handler: async (args) => {\n const id = args.raw.trim()\n if (!id) {\n return { type: 'error', message: 'Usage: /resume <session-number>' } satisfies CommandResponse\n }\n return { type: 'text', text: `Resuming session ${id}...` } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'summary',\n description: 'Show session summary',\n category: 'system',\n handler: async () => {\n return { type: 'text', text: 'No session summary available.' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'handoff',\n description: 'Hand off session to another agent',\n usage: '<agent-name>',\n category: 'system',\n handler: async (args) => {\n const agent = args.raw.trim()\n if (!agent) {\n return { type: 'error', message: 'Usage: /handoff <agent-name>' } satisfies CommandResponse\n }\n return { type: 'text', text: `Handing off to ${agent}...` } satisfies CommandResponse\n },\n })\n}\n","import type { CommandRegistry } from '../command-registry.js'\nimport type { CommandResponse } from '../plugin/types.js'\n\nexport function registerAgentCommands(registry: CommandRegistry, _core: unknown): void {\n registry.register({\n name: 'agents',\n description: 'List available agents',\n category: 'system',\n handler: async () => {\n return { type: 'text', text: 'No agents configured.' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'install',\n description: 'Install a plugin',\n usage: '<plugin-name>',\n category: 'system',\n handler: async (args) => {\n const plugin = args.raw.trim()\n if (!plugin) {\n return { type: 'error', message: 'Usage: /install <plugin-name>' } satisfies CommandResponse\n }\n return { type: 'text', text: `Installing plugin: ${plugin}...` } satisfies CommandResponse\n },\n })\n}\n","import type { CommandRegistry } from '../command-registry.js'\nimport type { CommandResponse } from '../plugin/types.js'\n\nexport function registerAdminCommands(registry: CommandRegistry, _core: unknown): void {\n registry.register({\n name: 'restart',\n description: 'Restart the server',\n category: 'system',\n handler: async () => {\n return { type: 'silent' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'update',\n description: 'Check for and apply updates',\n category: 'system',\n handler: async () => {\n return { type: 'text', text: 'Checking for updates...' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'doctor',\n description: 'Run system diagnostics',\n category: 'system',\n handler: async () => {\n return { type: 'text', text: 'Running diagnostics...' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'integrate',\n description: 'Set up a new channel integration',\n usage: '<channel>',\n category: 'system',\n handler: async (args) => {\n const channel = args.raw.trim()\n if (!channel) {\n return {\n type: 'menu',\n title: 'Available Integrations',\n options: [\n { label: 'Telegram', command: '/integrate telegram' },\n { label: 'Discord', command: '/integrate discord' },\n { label: 'Slack', command: '/integrate slack' },\n ],\n } satisfies CommandResponse\n }\n return { type: 'text', text: `Setting up ${channel} integration...` } satisfies CommandResponse\n },\n })\n}\n","import type { CommandRegistry } from '../command-registry.js'\nimport type { CommandResponse } from '../plugin/types.js'\n\nexport function registerHelpCommand(registry: CommandRegistry, _core: unknown): void {\n registry.register({\n name: 'help',\n description: 'Show available commands',\n usage: '[command]',\n category: 'system',\n handler: async (args) => {\n const query = args.raw.trim()\n\n if (query) {\n const cmd = registry.get(query)\n if (!cmd) {\n return { type: 'error', message: `Unknown command: /${query}` } satisfies CommandResponse\n }\n let text = `/${cmd.name}`\n if (cmd.usage) text += ` ${cmd.usage}`\n text += `\\n${cmd.description}`\n return { type: 'text', text } satisfies CommandResponse\n }\n\n // Auto-generate help from registry at invocation time\n const systemCmds = registry.getByCategory('system')\n const pluginCmds = registry.getByCategory('plugin')\n\n const lines: string[] = []\n\n if (systemCmds.length > 0) {\n lines.push('System Commands:')\n for (const cmd of systemCmds) {\n const usage = cmd.usage ? ` ${cmd.usage}` : ''\n lines.push(` /${cmd.name}${usage} — ${cmd.description}`)\n }\n }\n\n if (pluginCmds.length > 0) {\n if (lines.length > 0) lines.push('')\n lines.push('Plugin Commands:')\n for (const cmd of pluginCmds) {\n const usage = cmd.usage ? ` ${cmd.usage}` : ''\n lines.push(` /${cmd.name}${usage} — ${cmd.description}`)\n }\n }\n\n if (lines.length === 0) {\n return { type: 'text', text: 'No commands registered.' } satisfies CommandResponse\n }\n\n return { type: 'text', text: lines.join('\\n') } satisfies CommandResponse\n },\n })\n}\n","import type { CommandRegistry } from '../command-registry.js'\nimport type { CommandResponse } from '../plugin/types.js'\n\nexport function registerMenuCommand(registry: CommandRegistry, _core: unknown): void {\n registry.register({\n name: 'menu',\n description: 'Show the main menu',\n category: 'system',\n handler: async () => {\n return {\n type: 'menu',\n title: 'Main Menu',\n options: [\n { label: 'New Session', command: '/new' },\n { label: 'Active Sessions', command: '/sessions' },\n { label: 'Available Agents', command: '/agents' },\n { label: 'Usage', command: '/usage' },\n { label: 'Help', command: '/help' },\n ],\n } satisfies CommandResponse\n },\n })\n}\n","import type { CommandRegistry } from '../command-registry.js'\nimport { registerSessionCommands } from './session.js'\nimport { registerAgentCommands } from './agents.js'\nimport { registerAdminCommands } from './admin.js'\nimport { registerHelpCommand } from './help.js'\nimport { registerMenuCommand } from './menu.js'\n\nexport function registerSystemCommands(registry: CommandRegistry, core: unknown): void {\n registerSessionCommands(registry, core)\n registerAgentCommands(registry, core)\n registerAdminCommands(registry, core)\n registerHelpCommand(registry, core)\n registerMenuCommand(registry, core)\n}\n","#!/usr/bin/env node\n\nimport { ConfigManager } from './core/config/config.js'\nimport { OpenACPCore } from './core/core.js'\nimport { initLogger, shutdownLogger, cleanupOldSessionLogs, log, muteLogger, unmuteLogger } from './core/utils/log.js'\nimport { corePlugins } from './plugins/core-plugins.js'\nimport { SettingsManager } from './core/plugin/settings-manager.js'\nimport { PluginRegistry } from './core/plugin/plugin-registry.js'\nimport { CommandRegistry } from './core/command-registry.js'\nimport { registerSystemCommands } from './core/commands/index.js'\nimport type { IChannelAdapter } from './core/channel.js'\nimport type { TunnelService } from './plugins/tunnel/tunnel-service.js'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\n\nexport const RESTART_EXIT_CODE = 75\nlet shuttingDown = false\n\nconst OPENACP_DIR = path.join(os.homedir(), '.openacp')\nconst PLUGINS_DATA_DIR = path.join(OPENACP_DIR, 'plugins', 'data')\nconst REGISTRY_PATH = path.join(OPENACP_DIR, 'plugins.json')\n\nexport interface StartServerOptions {\n devPluginPath?: string\n noWatch?: boolean\n}\n\nexport async function startServer(opts?: StartServerOptions) {\n // 0. If running as daemon child, check state and write PID file\n if (process.argv.includes('--daemon-child')) {\n const { writePidFile, readPidFile, getPidPath, shouldAutoStart } = await import('./cli/daemon.js')\n\n // Only auto-start if the daemon was previously running (user started it)\n if (!shouldAutoStart()) {\n process.exit(0)\n }\n\n const pidPath = getPidPath()\n const existingPid = readPidFile(pidPath)\n if (existingPid !== null && existingPid !== process.pid) {\n try {\n process.kill(existingPid, 0)\n console.error(`Another OpenACP instance is already running (PID ${existingPid}). Exiting.`)\n process.exit(1)\n } catch {\n // Stale PID file — safe to overwrite\n }\n }\n writePidFile(pidPath, process.pid)\n }\n\n // Create SettingsManager and PluginRegistry early (needed by wizard + boot)\n const settingsManager = new SettingsManager(PLUGINS_DATA_DIR)\n const pluginRegistry = new PluginRegistry(REGISTRY_PATH)\n await pluginRegistry.load()\n\n // 1. Check config exists, run setup if not\n const configManager = new ConfigManager()\n const configExists = await configManager.exists()\n\n if (!configExists) {\n const { runSetup } = await import('./core/setup/index.js')\n const shouldStart = await runSetup(configManager, { settingsManager, pluginRegistry })\n if (!shouldStart) process.exit(0)\n }\n\n // 2. Load config (validates with Zod)\n await configManager.load()\n const config = configManager.get()\n initLogger(config.logging)\n log.debug({ configPath: configManager.getConfigPath() }, 'Config loaded')\n\n // First boot: auto-register built-in plugins if registry is empty\n if (pluginRegistry.list().size === 0) {\n await autoRegisterBuiltinPlugins(settingsManager, pluginRegistry, configManager)\n }\n\n // Show banner in foreground TTY mode (not daemon, not piped)\n const isForegroundTTY = !!(process.stdout.isTTY && !process.env.NO_COLOR && config.runMode !== 'daemon')\n if (isForegroundTTY) {\n const { printStartBanner } = await import('./core/setup/index.js')\n await printStartBanner()\n }\n\n // Mute pino during startup, show spinner instead\n let spinner: ReturnType<typeof import('ora').default> | undefined\n if (isForegroundTTY) {\n muteLogger()\n const ora = (await import('ora')).default\n spinner = ora({ text: 'Starting OpenACP...', spinner: 'dots' }).start()\n }\n\n // Post-upgrade dependency check (blocking — must complete before server start)\n try {\n const { runPostUpgradeChecks } = await import('./cli/post-upgrade.js')\n await runPostUpgradeChecks(config)\n } catch (err) {\n log.warn({ err }, 'Post-upgrade check failed')\n }\n\n // Async cleanup of old session logs (non-blocking)\n cleanupOldSessionLogs(config.logging.sessionLogRetentionDays).catch(err =>\n log.warn({ err }, 'Session log cleanup failed')\n )\n\n // 3. Create core\n const core = new OpenACPCore(configManager)\n\n // 3b. Create CommandRegistry and register as service\n const commandRegistry = new CommandRegistry()\n const serviceRegistry = core.lifecycleManager.serviceRegistry\n serviceRegistry.register('command-registry', commandRegistry, 'core')\n\n // 3c. Register system commands\n registerSystemCommands(commandRegistry, core)\n\n // 4. Boot all plugins (services, infrastructure, adapters)\n try {\n // Emit kernel:booted before plugin boot\n core.eventBus.emit('kernel:booted')\n\n // Pass settingsManager and pluginRegistry to LifecycleManager\n ;(core.lifecycleManager as any).settingsManager = settingsManager\n ;(core.lifecycleManager as any).pluginRegistry = pluginRegistry\n\n // Boot all built-in plugins in dependency order\n await core.lifecycleManager.boot(corePlugins)\n\n // Load dev plugin if running in dev mode\n if (opts?.devPluginPath) {\n const { DevPluginLoader } = await import('./core/plugin/dev-loader.js')\n const devLoader = new DevPluginLoader(opts.devPluginPath)\n\n try {\n const devPlugin = await devLoader.load()\n await core.lifecycleManager.boot([devPlugin])\n log.info({ plugin: devPlugin.name, version: devPlugin.version }, 'Dev plugin loaded')\n\n // Watch dist/ directory for changes and hot-reload\n if (!opts.noWatch) {\n const distPath = devLoader.getDistPath()\n let reloadTimer: ReturnType<typeof setTimeout> | null = null\n\n fs.watch(distPath, { recursive: true }, (_eventType, filename) => {\n if (!filename?.endsWith('.js')) return\n\n // Debounce: wait 500ms after last change\n if (reloadTimer) clearTimeout(reloadTimer)\n reloadTimer = setTimeout(async () => {\n try {\n log.info({ filename }, 'Dev plugin changed, reloading...')\n await core.lifecycleManager.unloadPlugin(devPlugin.name)\n const reloaded = await devLoader.load()\n await core.lifecycleManager.boot([reloaded])\n log.info({ plugin: reloaded.name, version: reloaded.version }, 'Dev plugin reloaded')\n } catch (err) {\n log.error({ err }, 'Dev plugin reload failed')\n }\n }, 500)\n })\n\n log.info({ distPath }, 'Watching dev plugin for changes')\n }\n } catch (err) {\n log.error({ err, pluginPath: opts.devPluginPath }, 'Failed to load dev plugin')\n }\n }\n\n // Wire adapters from service registry into core\n for (const adapterName of ['telegram', 'discord', 'slack']) {\n const adapter = serviceRegistry.get<IChannelAdapter>(`adapter:${adapterName}`)\n if (adapter) {\n core.registerAdapter(adapterName, adapter)\n log.info({ adapter: adapterName }, 'Adapter registered')\n }\n }\n\n // Wire tunnel service from service registry into core\n const tunnelSvc = serviceRegistry.get<TunnelService>('tunnel')\n if (tunnelSvc) {\n core.tunnelService = tunnelSvc\n }\n\n // Emit system:commands-ready with all registered commands\n core.eventBus.emit('system:commands-ready', { commands: commandRegistry.getAll() })\n\n core.eventBus.emit('system:ready')\n } catch (err) {\n log.error({ err }, 'Plugin boot failed')\n }\n\n if (core.adapters.size === 0) {\n log.error('No channels enabled. Enable at least one channel in config.')\n process.exit(1)\n }\n\n // 5. Setup shutdown handler\n const shutdown = async (signal: string, exitCode = 0) => {\n if (shuttingDown) return\n shuttingDown = true\n log.info({ signal, exitCode }, 'Signal received, shutting down')\n\n try {\n // Lifecycle teardown stops all plugins (adapters, api-server, tunnel, etc.)\n await core.lifecycleManager.shutdown()\n await core.stop()\n } catch (err) {\n log.error({ err }, 'Error during shutdown')\n }\n\n const isDaemon = process.argv.includes('--daemon-child')\n\n // Clean up PID file if running as daemon\n if (isDaemon) {\n const { removePidFile, getPidPath } = await import('./cli/daemon.js')\n removePidFile(getPidPath())\n }\n\n // Self-respawn on restart\n if (exitCode === RESTART_EXIT_CODE) {\n if (isDaemon) {\n // Daemon mode: spawn detached child writing to log file\n const { spawn: spawnChild } = await import('node:child_process')\n const { expandHome } = await import('./core/config/config.js')\n const fs = await import('node:fs')\n const pathMod = await import('node:path')\n\n const cliPath = pathMod.resolve(process.argv[1])\n const resolvedLogDir = expandHome(config.logging.logDir)\n fs.mkdirSync(resolvedLogDir, { recursive: true })\n const logFile = pathMod.join(resolvedLogDir, 'openacp.log')\n const out = fs.openSync(logFile, 'a')\n const err = fs.openSync(logFile, 'a')\n\n const child = spawnChild(process.execPath, [cliPath, '--daemon-child'], {\n detached: true,\n stdio: ['ignore', out, err],\n env: { ...process.env, OPENACP_SKIP_UPDATE_CHECK: '1' },\n })\n fs.closeSync(out)\n fs.closeSync(err)\n child.unref()\n log.info({ newPid: child.pid }, 'Respawned daemon for restart')\n } else if (!process.env.OPENACP_DEV_LOOP) {\n // Foreground production mode: spawn replacement process with inherited stdio\n const { spawn: spawnChild } = await import('node:child_process')\n const child = spawnChild(process.execPath, process.argv.slice(1), {\n stdio: 'inherit',\n env: { ...process.env, OPENACP_SKIP_UPDATE_CHECK: '1' },\n })\n await shutdownLogger()\n child.on('exit', (code) => process.exit(code ?? 0))\n return\n }\n }\n\n await shutdownLogger()\n process.exit(exitCode)\n }\n\n // Expose restart trigger for adapters (e.g. /restart command)\n core.requestRestart = () => shutdown('restart', RESTART_EXIT_CODE)\n\n process.on('SIGINT', () => shutdown('SIGINT'))\n process.on('SIGTERM', () => shutdown('SIGTERM'))\n\n process.on('uncaughtException', (err) => {\n log.error({ err }, 'Uncaught exception')\n })\n\n process.on('unhandledRejection', (err) => {\n log.error({ err }, 'Unhandled rejection')\n })\n\n await core.start()\n\n // 6. Log ready\n if (isForegroundTTY) {\n if (spinner) spinner.stop()\n const ok = (msg: string) => console.log(`\\x1b[32m✓\\x1b[0m ${msg}`)\n ok('Config loaded')\n ok('Dependencies checked')\n const tunnelSvc = core.lifecycleManager.serviceRegistry.get<TunnelService>('tunnel')\n if (tunnelSvc) ok(`Tunnel ready → ${tunnelSvc.getPublicUrl()}`)\n for (const [name] of core.adapters) ok(`${name.charAt(0).toUpperCase() + name.slice(1)} connected`)\n const apiPort = config.api?.port ?? 21420\n if (core.lifecycleManager.serviceRegistry.get('api-server')) ok(`API server on port ${apiPort}`)\n console.log(`\\nOpenACP is running. Press Ctrl+C to stop.\\n`)\n unmuteLogger()\n }\n log.debug({ agents: Object.keys(config.agents) }, 'OpenACP started')\n}\n\n/**\n * Auto-register all built-in plugins when the registry is empty (first boot with new plugin system,\n * or upgrade from legacy config). Also runs legacy config migration for each plugin.\n */\nasync function autoRegisterBuiltinPlugins(\n settingsManager: SettingsManager,\n pluginRegistry: PluginRegistry,\n configManager: ConfigManager,\n): Promise<void> {\n const allPlugins = [\n { name: '@openacp/security', version: '1.0.0', description: 'User access control and session limits' },\n { name: '@openacp/file-service', version: '1.0.0', description: 'File storage and management' },\n { name: '@openacp/context', version: '1.0.0', description: 'Conversation context management' },\n { name: '@openacp/usage', version: '1.0.0', description: 'Token usage tracking and budget enforcement' },\n { name: '@openacp/speech', version: '1.0.0', description: 'Text-to-speech and speech-to-text' },\n { name: '@openacp/notifications', version: '1.0.0', description: 'Cross-session notification routing' },\n { name: '@openacp/tunnel', version: '1.0.0', description: 'Expose local services via tunnel' },\n { name: '@openacp/api-server', version: '1.0.0', description: 'REST API + SSE streaming server' },\n { name: '@openacp/telegram', version: '1.0.0', description: 'Telegram adapter with forum topics' },\n { name: '@openacp/discord', version: '1.0.0', description: 'Discord adapter with forum threads' },\n { name: '@openacp/slack', version: '1.0.0', description: 'Slack adapter with channels and threads' },\n ]\n\n // Try to read legacy config for migration\n let legacyConfig: Record<string, unknown> | undefined\n try {\n const cfg = configManager.get()\n if (cfg && typeof cfg === 'object') {\n legacyConfig = cfg as unknown as Record<string, unknown>\n }\n } catch {\n // No config loaded yet — skip migration\n }\n\n // Run legacy migration for each plugin silently\n if (legacyConfig) {\n const pluginModules = await Promise.allSettled([\n import('./plugins/security/index.js'),\n import('./plugins/file-service/index.js'),\n import('./plugins/context/index.js'),\n import('./plugins/usage/index.js'),\n import('./plugins/speech/index.js'),\n import('./plugins/notifications/index.js'),\n import('./plugins/tunnel/index.js'),\n import('./plugins/api-server/index.js'),\n import('./plugins/telegram/index.js'),\n import('./plugins/discord/index.js'),\n import('./plugins/slack/index.js'),\n ])\n\n for (const result of pluginModules) {\n if (result.status !== 'fulfilled') continue\n const plugin = result.value.default\n if (plugin?.install) {\n try {\n // Check if settings already exist\n const existing = await settingsManager.loadSettings(plugin.name)\n if (Object.keys(existing).length > 0) continue\n\n // Create a silent install context for migration only\n const { createInstallContext } = await import('./core/plugin/install-context.js')\n const ctx = createInstallContext({\n pluginName: plugin.name,\n settingsManager,\n basePath: PLUGINS_DATA_DIR,\n legacyConfig,\n })\n // Override terminal to be silent\n ctx.terminal = createSilentTerminal()\n await plugin.install(ctx)\n } catch {\n // Silently skip — migration is best-effort\n }\n }\n }\n }\n\n for (const p of allPlugins) {\n pluginRegistry.register(p.name, {\n version: p.version,\n source: 'builtin',\n enabled: true,\n settingsPath: settingsManager.getSettingsPath(p.name),\n description: p.description,\n })\n }\n await pluginRegistry.save()\n log.info('Built-in plugins registered in plugin registry')\n}\n\n/**\n * Create a no-op terminal for silent migration (no user interaction).\n */\nfunction createSilentTerminal(): import('./core/plugin/types.js').TerminalIO {\n const noop = () => {}\n return {\n text: async () => '',\n select: async () => '' as any,\n confirm: async () => false,\n password: async () => '',\n multiselect: async () => [],\n log: { info: noop, success: noop, warning: noop, error: noop, step: noop },\n spinner: () => ({ start: noop, stop: noop, fail: noop }),\n note: noop,\n cancel: noop,\n }\n}\n\n// Direct execution for dev (node dist/main.js)\nconst isDirectExecution = process.argv[1]?.endsWith('main.js')\nif (isDirectExecution) {\n startServer().catch((err) => {\n log.error({ err }, 'Fatal error')\n process.exit(1)\n })\n}\n"],"mappings":"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","names":["fs"]}