@openacp/cli 2026.331.1 → 2026.331.3

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 (182) hide show
  1. package/README.md +2 -1
  2. package/dist/cli.js +24987 -270
  3. package/dist/cli.js.map +1 -1
  4. package/dist/data/registry-snapshot.json +1 -1
  5. package/dist/index.d.ts +10 -0
  6. package/dist/index.js +17669 -406
  7. package/dist/index.js.map +1 -1
  8. package/package.json +2 -2
  9. package/dist/adapter-ELG3VRZ3.js +0 -14
  10. package/dist/adapter-ELG3VRZ3.js.map +0 -1
  11. package/dist/agent-catalog-UYD26QDK.js +0 -10
  12. package/dist/agent-catalog-UYD26QDK.js.map +0 -1
  13. package/dist/agent-dependencies-ED2ZTUHG.js +0 -23
  14. package/dist/agent-dependencies-ED2ZTUHG.js.map +0 -1
  15. package/dist/agent-registry-YOGP656W.js +0 -8
  16. package/dist/agent-registry-YOGP656W.js.map +0 -1
  17. package/dist/agent-store-5UHZH2XI.js +0 -8
  18. package/dist/agent-store-5UHZH2XI.js.map +0 -1
  19. package/dist/api-client-PEMHYL5U.js +0 -13
  20. package/dist/api-client-PEMHYL5U.js.map +0 -1
  21. package/dist/api-server-DATG2KBR.js +0 -10
  22. package/dist/api-server-DATG2KBR.js.map +0 -1
  23. package/dist/api-server-L5Z7XACW.js +0 -7
  24. package/dist/api-server-L5Z7XACW.js.map +0 -1
  25. package/dist/autostart-CUPZMKKC.js +0 -22
  26. package/dist/autostart-CUPZMKKC.js.map +0 -1
  27. package/dist/chunk-23SRIVG4.js +0 -50
  28. package/dist/chunk-23SRIVG4.js.map +0 -1
  29. package/dist/chunk-2KT6TROD.js +0 -129
  30. package/dist/chunk-2KT6TROD.js.map +0 -1
  31. package/dist/chunk-2R5XM3ES.js +0 -154
  32. package/dist/chunk-2R5XM3ES.js.map +0 -1
  33. package/dist/chunk-3EWTPOF7.js +0 -51
  34. package/dist/chunk-3EWTPOF7.js.map +0 -1
  35. package/dist/chunk-566W6INH.js +0 -83
  36. package/dist/chunk-566W6INH.js.map +0 -1
  37. package/dist/chunk-5WGVYX3C.js +0 -55
  38. package/dist/chunk-5WGVYX3C.js.map +0 -1
  39. package/dist/chunk-7GXEMMEV.js +0 -44
  40. package/dist/chunk-7GXEMMEV.js.map +0 -1
  41. package/dist/chunk-7U6IZIJP.js +0 -186
  42. package/dist/chunk-7U6IZIJP.js.map +0 -1
  43. package/dist/chunk-7YIKTRSM.js +0 -105
  44. package/dist/chunk-7YIKTRSM.js.map +0 -1
  45. package/dist/chunk-7ZCQF6QM.js +0 -27
  46. package/dist/chunk-7ZCQF6QM.js.map +0 -1
  47. package/dist/chunk-AFKX424Q.js +0 -92
  48. package/dist/chunk-AFKX424Q.js.map +0 -1
  49. package/dist/chunk-BYCJQPMN.js +0 -543
  50. package/dist/chunk-BYCJQPMN.js.map +0 -1
  51. package/dist/chunk-CDAUYTVP.js +0 -41
  52. package/dist/chunk-CDAUYTVP.js.map +0 -1
  53. package/dist/chunk-EWVXSTQK.js +0 -6544
  54. package/dist/chunk-EWVXSTQK.js.map +0 -1
  55. package/dist/chunk-FNRSWA2K.js +0 -1
  56. package/dist/chunk-FNRSWA2K.js.map +0 -1
  57. package/dist/chunk-FPKQYCQS.js +0 -776
  58. package/dist/chunk-FPKQYCQS.js.map +0 -1
  59. package/dist/chunk-IZ5UEZF7.js +0 -138
  60. package/dist/chunk-IZ5UEZF7.js.map +0 -1
  61. package/dist/chunk-K6UY5M75.js +0 -653
  62. package/dist/chunk-K6UY5M75.js.map +0 -1
  63. package/dist/chunk-KGAQW6F4.js +0 -106
  64. package/dist/chunk-KGAQW6F4.js.map +0 -1
  65. package/dist/chunk-LGFWH3AE.js +0 -26
  66. package/dist/chunk-LGFWH3AE.js.map +0 -1
  67. package/dist/chunk-LRV56K2M.js +0 -4106
  68. package/dist/chunk-LRV56K2M.js.map +0 -1
  69. package/dist/chunk-MDJHCCFS.js +0 -485
  70. package/dist/chunk-MDJHCCFS.js.map +0 -1
  71. package/dist/chunk-MLF4W5R6.js +0 -101
  72. package/dist/chunk-MLF4W5R6.js.map +0 -1
  73. package/dist/chunk-NHD5XDD2.js +0 -686
  74. package/dist/chunk-NHD5XDD2.js.map +0 -1
  75. package/dist/chunk-NJX75BLK.js +0 -259
  76. package/dist/chunk-NJX75BLK.js.map +0 -1
  77. package/dist/chunk-NOEAJNTK.js +0 -156
  78. package/dist/chunk-NOEAJNTK.js.map +0 -1
  79. package/dist/chunk-ON7HB5O7.js +0 -58
  80. package/dist/chunk-ON7HB5O7.js.map +0 -1
  81. package/dist/chunk-OSBZXY2W.js +0 -126
  82. package/dist/chunk-OSBZXY2W.js.map +0 -1
  83. package/dist/chunk-OYSAN7UX.js +0 -15
  84. package/dist/chunk-OYSAN7UX.js.map +0 -1
  85. package/dist/chunk-P3HHJANC.js +0 -209
  86. package/dist/chunk-P3HHJANC.js.map +0 -1
  87. package/dist/chunk-R2YLDQLI.js +0 -1115
  88. package/dist/chunk-R2YLDQLI.js.map +0 -1
  89. package/dist/chunk-R6KZYF7D.js +0 -231
  90. package/dist/chunk-R6KZYF7D.js.map +0 -1
  91. package/dist/chunk-S64CB6J3.js +0 -98
  92. package/dist/chunk-S64CB6J3.js.map +0 -1
  93. package/dist/chunk-SSLVNCEA.js +0 -236
  94. package/dist/chunk-SSLVNCEA.js.map +0 -1
  95. package/dist/chunk-TGP34LQN.js +0 -681
  96. package/dist/chunk-TGP34LQN.js.map +0 -1
  97. package/dist/chunk-VUSCVRJL.js +0 -229
  98. package/dist/chunk-VUSCVRJL.js.map +0 -1
  99. package/dist/chunk-W26AUH5B.js +0 -61
  100. package/dist/chunk-W26AUH5B.js.map +0 -1
  101. package/dist/chunk-WQCJTU2C.js +0 -84
  102. package/dist/chunk-WQCJTU2C.js.map +0 -1
  103. package/dist/chunk-XRJUS6FE.js +0 -53
  104. package/dist/chunk-XRJUS6FE.js.map +0 -1
  105. package/dist/chunk-YZCKSNRN.js +0 -453
  106. package/dist/chunk-YZCKSNRN.js.map +0 -1
  107. package/dist/chunk-ZIRH6QWW.js +0 -69
  108. package/dist/chunk-ZIRH6QWW.js.map +0 -1
  109. package/dist/chunk-ZSLHHQPQ.js +0 -282
  110. package/dist/chunk-ZSLHHQPQ.js.map +0 -1
  111. package/dist/config-X4UP7H6R.js +0 -13
  112. package/dist/config-X4UP7H6R.js.map +0 -1
  113. package/dist/config-editor-7BENRVG5.js +0 -11
  114. package/dist/config-editor-7BENRVG5.js.map +0 -1
  115. package/dist/config-registry-M3FFWEVM.js +0 -18
  116. package/dist/config-registry-M3FFWEVM.js.map +0 -1
  117. package/dist/context-FVGCU5TI.js +0 -9
  118. package/dist/context-FVGCU5TI.js.map +0 -1
  119. package/dist/core-plugins-JSY2I44L.js +0 -25
  120. package/dist/core-plugins-JSY2I44L.js.map +0 -1
  121. package/dist/daemon-UOSRDEXW.js +0 -34
  122. package/dist/daemon-UOSRDEXW.js.map +0 -1
  123. package/dist/dev-loader-7P3HZCIA.js +0 -37
  124. package/dist/dev-loader-7P3HZCIA.js.map +0 -1
  125. package/dist/doctor-6DLACBR4.js +0 -10
  126. package/dist/doctor-6DLACBR4.js.map +0 -1
  127. package/dist/file-service-FQQYME7M.js +0 -8
  128. package/dist/file-service-FQQYME7M.js.map +0 -1
  129. package/dist/install-cloudflared-LNS5L5FR.js +0 -33
  130. package/dist/install-cloudflared-LNS5L5FR.js.map +0 -1
  131. package/dist/install-context-KZO5FR4D.js +0 -78
  132. package/dist/install-context-KZO5FR4D.js.map +0 -1
  133. package/dist/install-jq-SN4IA5K4.js +0 -31
  134. package/dist/install-jq-SN4IA5K4.js.map +0 -1
  135. package/dist/instance-context-FLCE7VZ4.js +0 -13
  136. package/dist/instance-context-FLCE7VZ4.js.map +0 -1
  137. package/dist/instance-registry-SW5FWKHO.js +0 -7
  138. package/dist/instance-registry-SW5FWKHO.js.map +0 -1
  139. package/dist/integrate-JIEZYDOR.js +0 -371
  140. package/dist/integrate-JIEZYDOR.js.map +0 -1
  141. package/dist/log-YZ243M5G.js +0 -25
  142. package/dist/log-YZ243M5G.js.map +0 -1
  143. package/dist/main-D7M2AKRM.js +0 -697
  144. package/dist/main-D7M2AKRM.js.map +0 -1
  145. package/dist/menu-ALFN37IR.js +0 -15
  146. package/dist/menu-ALFN37IR.js.map +0 -1
  147. package/dist/notifications-MO23S7S3.js +0 -8
  148. package/dist/notifications-MO23S7S3.js.map +0 -1
  149. package/dist/plugin-create-HFKS23JY.js +0 -968
  150. package/dist/plugin-create-HFKS23JY.js.map +0 -1
  151. package/dist/plugin-installer-VSTYZSXC.js +0 -9
  152. package/dist/plugin-installer-VSTYZSXC.js.map +0 -1
  153. package/dist/plugin-registry-6J3YSFHF.js +0 -7
  154. package/dist/plugin-registry-6J3YSFHF.js.map +0 -1
  155. package/dist/plugin-search-MGKAL5JM.js +0 -39
  156. package/dist/plugin-search-MGKAL5JM.js.map +0 -1
  157. package/dist/post-upgrade-F4YPMTUT.js +0 -79
  158. package/dist/post-upgrade-F4YPMTUT.js.map +0 -1
  159. package/dist/read-text-file-DJBTITIB.js +0 -7
  160. package/dist/read-text-file-DJBTITIB.js.map +0 -1
  161. package/dist/registry-client-GTBWLXYU.js +0 -7
  162. package/dist/registry-client-GTBWLXYU.js.map +0 -1
  163. package/dist/security-O4XGN2CM.js +0 -8
  164. package/dist/security-O4XGN2CM.js.map +0 -1
  165. package/dist/settings-manager-B4UN2LAC.js +0 -7
  166. package/dist/settings-manager-B4UN2LAC.js.map +0 -1
  167. package/dist/setup-44WLBIOT.js +0 -989
  168. package/dist/setup-44WLBIOT.js.map +0 -1
  169. package/dist/speech-GHTSWDAN.js +0 -9
  170. package/dist/speech-GHTSWDAN.js.map +0 -1
  171. package/dist/suggest-RST5VOHB.js +0 -36
  172. package/dist/suggest-RST5VOHB.js.map +0 -1
  173. package/dist/telegram-D7ASLVEB.js +0 -7
  174. package/dist/telegram-D7ASLVEB.js.map +0 -1
  175. package/dist/tunnel-ALJDPFDQ.js +0 -10
  176. package/dist/tunnel-ALJDPFDQ.js.map +0 -1
  177. package/dist/tunnel-service-TBAHDXMF.js +0 -755
  178. package/dist/tunnel-service-TBAHDXMF.js.map +0 -1
  179. package/dist/validators-GITLOFXC.js +0 -11
  180. package/dist/validators-GITLOFXC.js.map +0 -1
  181. package/dist/version-AXXV6IV2.js +0 -15
  182. package/dist/version-AXXV6IV2.js.map +0 -1
@@ -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\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 ?? path.join(os.homedir(), \".openacp\", \"api.port\");\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 let channel: string | undefined;\n\n if (body) {\n try {\n const parsed = JSON.parse(body);\n agent = parsed.agent;\n workspace = parsed.workspace;\n channel = parsed.channel;\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 // Resolve adapter: use explicit channel if provided, otherwise fall back to first registered adapter\n let adapterId: string | null = null;\n let adapter: InstanceType<any> | null = null;\n\n if (channel) {\n if (!deps.core.adapters.has(channel)) {\n const available = Array.from(deps.core.adapters.keys()).join(\", \") || \"none\";\n deps.sendJson(res, 400, {\n error: `Adapter '${channel}' is not connected. Available: ${available}`,\n });\n return;\n }\n adapterId = channel;\n adapter = deps.core.adapters.get(channel) ?? null;\n } else {\n const firstEntry = deps.core.adapters.entries().next().value;\n if (firstEntry) {\n [adapterId, adapter] = firstEntry;\n }\n }\n\n const channelId = adapterId ?? \"api\";\n\n const resolvedAgent = agent || config.defaultAgent;\n const agentDef = deps.core.agentCatalog.resolve(resolvedAgent);\n const resolvedWorkspace = deps.core.configManager.resolveWorkspace(\n workspace || agentDef?.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/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,231 +0,0 @@
1
- // src/core/utils/log.ts
2
- import pino from "pino";
3
- import fs from "fs";
4
- import path from "path";
5
- import os from "os";
6
- var rootLogger = pino({
7
- level: "debug",
8
- transport: { target: "pino-pretty", options: { colorize: true, translateTime: "SYS:standard" } }
9
- });
10
- var initialized = false;
11
- var logDir;
12
- var currentTransport;
13
- function expandHome(p) {
14
- return p.startsWith("~") ? path.join(os.homedir(), p.slice(1)) : p;
15
- }
16
- function wrapVariadic(logger) {
17
- return {
18
- info: (...args) => {
19
- if (args.length === 0) return;
20
- if (typeof args[0] === "object" && args[0] !== null && !(args[0] instanceof Error)) {
21
- logger.info(args[0], args.slice(1).join(" "));
22
- } else {
23
- logger.info(args.map(String).join(" "));
24
- }
25
- },
26
- warn: (...args) => {
27
- if (args.length === 0) return;
28
- if (typeof args[0] === "object" && args[0] !== null && !(args[0] instanceof Error)) {
29
- logger.warn(args[0], args.slice(1).join(" "));
30
- } else {
31
- logger.warn(args.map(String).join(" "));
32
- }
33
- },
34
- error: (...args) => {
35
- if (args.length === 0) return;
36
- if (typeof args[0] === "object" && args[0] !== null && !(args[0] instanceof Error)) {
37
- logger.error(args[0], args.slice(1).join(" "));
38
- } else {
39
- logger.error(args.map(String).join(" "));
40
- }
41
- },
42
- debug: (...args) => {
43
- if (args.length === 0) return;
44
- if (typeof args[0] === "object" && args[0] !== null && !(args[0] instanceof Error)) {
45
- logger.debug(args[0], args.slice(1).join(" "));
46
- } else {
47
- logger.debug(args.map(String).join(" "));
48
- }
49
- },
50
- fatal: (...args) => {
51
- if (args.length === 0) return;
52
- if (typeof args[0] === "object" && args[0] !== null && !(args[0] instanceof Error)) {
53
- logger.fatal(args[0], args.slice(1).join(" "));
54
- } else {
55
- logger.fatal(args.map(String).join(" "));
56
- }
57
- },
58
- child: (bindings) => logger.child(bindings)
59
- };
60
- }
61
- var log = wrapVariadic(rootLogger);
62
- var muteCount = 0;
63
- var savedLevel = "info";
64
- function muteLogger() {
65
- if (muteCount === 0) {
66
- savedLevel = rootLogger.level;
67
- rootLogger.level = "silent";
68
- }
69
- muteCount++;
70
- }
71
- function unmuteLogger() {
72
- muteCount--;
73
- if (muteCount <= 0) {
74
- muteCount = 0;
75
- rootLogger.level = savedLevel;
76
- }
77
- }
78
- function initLogger(config) {
79
- if (initialized) return rootLogger;
80
- const resolvedLogDir = expandHome(config.logDir);
81
- logDir = resolvedLogDir;
82
- try {
83
- fs.mkdirSync(resolvedLogDir, { recursive: true });
84
- fs.mkdirSync(path.join(resolvedLogDir, "sessions"), { recursive: true });
85
- } catch (err) {
86
- console.error(`[WARN] Failed to create log directory ${resolvedLogDir}, falling back to console-only:`, err);
87
- return rootLogger;
88
- }
89
- const transports = pino.transport({
90
- targets: [
91
- {
92
- target: "pino-pretty",
93
- options: {
94
- colorize: true,
95
- translateTime: "HH:mm:ss",
96
- ignore: "pid,hostname",
97
- singleLine: true
98
- },
99
- level: config.level
100
- },
101
- {
102
- target: "pino-roll",
103
- options: {
104
- file: path.join(resolvedLogDir, "openacp.log"),
105
- size: config.maxFileSize,
106
- limit: { count: config.maxFiles }
107
- },
108
- level: config.level
109
- }
110
- ]
111
- });
112
- currentTransport = transports;
113
- rootLogger = pino({ level: config.level }, transports);
114
- initialized = true;
115
- Object.assign(log, wrapVariadic(rootLogger));
116
- return rootLogger;
117
- }
118
- function setLogLevel(level) {
119
- rootLogger.level = level;
120
- }
121
- function createChildLogger(context) {
122
- return new Proxy({}, {
123
- get(_target, prop, receiver) {
124
- const child = rootLogger.child(context);
125
- const value = Reflect.get(child, prop, receiver);
126
- return typeof value === "function" ? value.bind(child) : value;
127
- }
128
- });
129
- }
130
- function createSessionLogger(sessionId, parentLogger) {
131
- const sessionLogDir = logDir ? path.join(logDir, "sessions") : void 0;
132
- if (!sessionLogDir) {
133
- return parentLogger.child({ sessionId });
134
- }
135
- try {
136
- const sessionLogPath = path.join(sessionLogDir, `${sessionId}.log`);
137
- const dest = pino.destination(sessionLogPath);
138
- const sessionFileLogger = pino({ level: parentLogger.level }, dest).child({ sessionId });
139
- const combinedChild = parentLogger.child({ sessionId });
140
- const originalInfo = combinedChild.info.bind(combinedChild);
141
- const originalWarn = combinedChild.warn.bind(combinedChild);
142
- const originalError = combinedChild.error.bind(combinedChild);
143
- const originalDebug = combinedChild.debug.bind(combinedChild);
144
- const originalFatal = combinedChild.fatal.bind(combinedChild);
145
- combinedChild.info = ((objOrMsg, ...rest) => {
146
- sessionFileLogger.info(objOrMsg, ...rest);
147
- return originalInfo(objOrMsg, ...rest);
148
- });
149
- combinedChild.warn = ((objOrMsg, ...rest) => {
150
- sessionFileLogger.warn(objOrMsg, ...rest);
151
- return originalWarn(objOrMsg, ...rest);
152
- });
153
- combinedChild.error = ((objOrMsg, ...rest) => {
154
- sessionFileLogger.error(objOrMsg, ...rest);
155
- return originalError(objOrMsg, ...rest);
156
- });
157
- combinedChild.debug = ((objOrMsg, ...rest) => {
158
- sessionFileLogger.debug(objOrMsg, ...rest);
159
- return originalDebug(objOrMsg, ...rest);
160
- });
161
- combinedChild.fatal = ((objOrMsg, ...rest) => {
162
- sessionFileLogger.fatal(objOrMsg, ...rest);
163
- return originalFatal(objOrMsg, ...rest);
164
- });
165
- combinedChild.__sessionDest = dest;
166
- return combinedChild;
167
- } catch (err) {
168
- parentLogger.warn({ sessionId, err }, "Failed to create session log file, using combined log only");
169
- return parentLogger.child({ sessionId });
170
- }
171
- }
172
- function closeSessionLogger(logger) {
173
- const dest = logger.__sessionDest;
174
- if (dest && typeof dest.destroy === "function") {
175
- dest.destroy();
176
- }
177
- }
178
- async function shutdownLogger() {
179
- if (!initialized) return;
180
- const transport = currentTransport;
181
- rootLogger = pino({ level: "debug" });
182
- Object.assign(log, wrapVariadic(rootLogger));
183
- currentTransport = void 0;
184
- logDir = void 0;
185
- initialized = false;
186
- if (transport) {
187
- await new Promise((resolve) => {
188
- const timeout = setTimeout(resolve, 3e3);
189
- transport.on("close", () => {
190
- clearTimeout(timeout);
191
- resolve();
192
- });
193
- transport.end();
194
- });
195
- }
196
- }
197
- async function cleanupOldSessionLogs(retentionDays) {
198
- if (!logDir) return;
199
- const sessionsDir = path.join(logDir, "sessions");
200
- try {
201
- const files = await fs.promises.readdir(sessionsDir);
202
- const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
203
- for (const file of files) {
204
- try {
205
- const filePath = path.join(sessionsDir, file);
206
- const stat = await fs.promises.stat(filePath);
207
- if (stat.mtimeMs < cutoff) {
208
- await fs.promises.unlink(filePath);
209
- rootLogger.debug({ file }, "Deleted old session log");
210
- }
211
- } catch (err) {
212
- rootLogger.warn({ file, err }, "Failed to delete old session log");
213
- }
214
- }
215
- } catch {
216
- }
217
- }
218
-
219
- export {
220
- log,
221
- muteLogger,
222
- unmuteLogger,
223
- initLogger,
224
- setLogLevel,
225
- createChildLogger,
226
- createSessionLogger,
227
- closeSessionLogger,
228
- shutdownLogger,
229
- cleanupOldSessionLogs
230
- };
231
- //# sourceMappingURL=chunk-R6KZYF7D.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/core/utils/log.ts"],"sourcesContent":["import pino from 'pino'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport type { LoggingConfig } from '../config/config.js'\n\nexport type Logger = pino.Logger\n\n// --- Default console-only logger (pre-init) ---\nlet rootLogger: pino.Logger = pino({\n level: 'debug',\n transport: { target: 'pino-pretty', options: { colorize: true, translateTime: 'SYS:standard' } },\n})\nlet initialized = false\nlet logDir: string | undefined\nlet currentTransport: ReturnType<typeof pino.transport> | undefined\n\nfunction expandHome(p: string): string {\n return p.startsWith('~') ? path.join(os.homedir(), p.slice(1)) : p\n}\n\n// --- Variadic wrapper for backward compatibility ---\nfunction wrapVariadic(logger: pino.Logger) {\n return {\n info: (...args: unknown[]) => {\n if (args.length === 0) return\n if (typeof args[0] === 'object' && args[0] !== null && !(args[0] instanceof Error)) {\n logger.info(args[0] as object, args.slice(1).join(' '))\n } else {\n logger.info(args.map(String).join(' '))\n }\n },\n warn: (...args: unknown[]) => {\n if (args.length === 0) return\n if (typeof args[0] === 'object' && args[0] !== null && !(args[0] instanceof Error)) {\n logger.warn(args[0] as object, args.slice(1).join(' '))\n } else {\n logger.warn(args.map(String).join(' '))\n }\n },\n error: (...args: unknown[]) => {\n if (args.length === 0) return\n if (typeof args[0] === 'object' && args[0] !== null && !(args[0] instanceof Error)) {\n logger.error(args[0] as object, args.slice(1).join(' '))\n } else {\n logger.error(args.map(String).join(' '))\n }\n },\n debug: (...args: unknown[]) => {\n if (args.length === 0) return\n if (typeof args[0] === 'object' && args[0] !== null && !(args[0] instanceof Error)) {\n logger.debug(args[0] as object, args.slice(1).join(' '))\n } else {\n logger.debug(args.map(String).join(' '))\n }\n },\n fatal: (...args: unknown[]) => {\n if (args.length === 0) return\n if (typeof args[0] === 'object' && args[0] !== null && !(args[0] instanceof Error)) {\n logger.fatal(args[0] as object, args.slice(1).join(' '))\n } else {\n logger.fatal(args.map(String).join(' '))\n }\n },\n child: (bindings: pino.Bindings) => logger.child(bindings),\n }\n}\n\nexport const log = wrapVariadic(rootLogger)\n\n// --- Mute/unmute (suppress pino output during interactive prompts) ---\n\nlet muteCount = 0\nlet savedLevel = 'info'\n\nexport function muteLogger(): void {\n if (muteCount === 0) {\n savedLevel = rootLogger.level\n rootLogger.level = 'silent'\n }\n muteCount++\n}\n\nexport function unmuteLogger(): void {\n muteCount--\n if (muteCount <= 0) {\n muteCount = 0\n rootLogger.level = savedLevel\n }\n}\n\n// --- Public API ---\n\nexport function initLogger(config: LoggingConfig): Logger {\n if (initialized) return rootLogger\n\n const resolvedLogDir = expandHome(config.logDir)\n logDir = resolvedLogDir\n\n try {\n fs.mkdirSync(resolvedLogDir, { recursive: true })\n fs.mkdirSync(path.join(resolvedLogDir, 'sessions'), { recursive: true })\n } catch (err) {\n console.error(`[WARN] Failed to create log directory ${resolvedLogDir}, falling back to console-only:`, err)\n return rootLogger\n }\n\n const transports = pino.transport({\n targets: [\n {\n target: 'pino-pretty',\n options: {\n colorize: true,\n translateTime: 'HH:mm:ss',\n ignore: 'pid,hostname',\n singleLine: true,\n },\n level: config.level,\n },\n {\n target: 'pino-roll',\n options: {\n file: path.join(resolvedLogDir, 'openacp.log'),\n size: config.maxFileSize,\n limit: { count: config.maxFiles },\n },\n level: config.level,\n },\n ],\n })\n\n currentTransport = transports\n rootLogger = pino({ level: config.level }, transports)\n initialized = true\n\n // Update the default log wrapper to use the new root logger\n Object.assign(log, wrapVariadic(rootLogger))\n\n return rootLogger\n}\n\n/** Change log level at runtime. Pino transport targets respect parent level changes automatically. */\nexport function setLogLevel(level: string): void {\n rootLogger.level = level\n}\n\nexport function createChildLogger(context: { module: string; [key: string]: unknown }): Logger {\n // Return a proxy that always delegates to the current rootLogger.\n // This ensures child loggers created at module-level (before initLogger)\n // pick up the initialized logger with pino-pretty transport.\n return new Proxy({} as Logger, {\n get(_target, prop, receiver) {\n const child = rootLogger.child(context)\n const value = Reflect.get(child, prop, receiver)\n return typeof value === 'function' ? value.bind(child) : value\n },\n })\n}\n\nexport function createSessionLogger(sessionId: string, parentLogger: Logger): Logger {\n const sessionLogDir = logDir ? path.join(logDir, 'sessions') : undefined\n if (!sessionLogDir) {\n return parentLogger.child({ sessionId })\n }\n\n try {\n const sessionLogPath = path.join(sessionLogDir, `${sessionId}.log`)\n const dest = pino.destination(sessionLogPath)\n const sessionFileLogger = pino({ level: parentLogger.level }, dest).child({ sessionId })\n\n // Create a logger that writes to both parent (combined) and session file\n const combinedChild = parentLogger.child({ sessionId })\n const originalInfo = combinedChild.info.bind(combinedChild)\n const originalWarn = combinedChild.warn.bind(combinedChild)\n const originalError = combinedChild.error.bind(combinedChild)\n const originalDebug = combinedChild.debug.bind(combinedChild)\n const originalFatal = combinedChild.fatal.bind(combinedChild)\n\n // Proxy log methods to write to both destinations\n combinedChild.info = ((objOrMsg: any, ...rest: any[]) => {\n sessionFileLogger.info(objOrMsg, ...rest)\n return originalInfo(objOrMsg, ...rest)\n }) as any\n combinedChild.warn = ((objOrMsg: any, ...rest: any[]) => {\n sessionFileLogger.warn(objOrMsg, ...rest)\n return originalWarn(objOrMsg, ...rest)\n }) as any\n combinedChild.error = ((objOrMsg: any, ...rest: any[]) => {\n sessionFileLogger.error(objOrMsg, ...rest)\n return originalError(objOrMsg, ...rest)\n }) as any\n combinedChild.debug = ((objOrMsg: any, ...rest: any[]) => {\n sessionFileLogger.debug(objOrMsg, ...rest)\n return originalDebug(objOrMsg, ...rest)\n }) as any\n combinedChild.fatal = ((objOrMsg: any, ...rest: any[]) => {\n sessionFileLogger.fatal(objOrMsg, ...rest)\n return originalFatal(objOrMsg, ...rest)\n }) as any\n\n // Store dest for cleanup\n ;(combinedChild as any).__sessionDest = dest\n\n return combinedChild\n } catch (err) {\n // Graceful degradation: session file failed, just use combined log\n parentLogger.warn({ sessionId, err }, 'Failed to create session log file, using combined log only')\n return parentLogger.child({ sessionId })\n }\n}\n\nexport function closeSessionLogger(logger: Logger): void {\n const dest = (logger as any).__sessionDest\n if (dest && typeof dest.destroy === 'function') {\n dest.destroy()\n }\n}\n\nexport async function shutdownLogger(): Promise<void> {\n if (!initialized) return\n\n const transport = currentTransport\n\n // Reset state immediately so re-init is possible\n rootLogger = pino({ level: 'debug' })\n Object.assign(log, wrapVariadic(rootLogger))\n currentTransport = undefined\n logDir = undefined\n initialized = false\n\n if (transport) {\n await new Promise<void>((resolve) => {\n const timeout = setTimeout(resolve, 3000)\n transport.on('close', () => {\n clearTimeout(timeout)\n resolve()\n })\n transport.end()\n })\n }\n}\n\nexport async function cleanupOldSessionLogs(retentionDays: number): Promise<void> {\n if (!logDir) return\n\n const sessionsDir = path.join(logDir, 'sessions')\n try {\n const files = await fs.promises.readdir(sessionsDir)\n const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1000\n\n for (const file of files) {\n try {\n const filePath = path.join(sessionsDir, file)\n const stat = await fs.promises.stat(filePath)\n if (stat.mtimeMs < cutoff) {\n await fs.promises.unlink(filePath)\n rootLogger.debug({ file }, 'Deleted old session log')\n }\n } catch (err) {\n rootLogger.warn({ file, err }, 'Failed to delete old session log')\n }\n }\n } catch {\n // Sessions directory doesn't exist — no-op\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,98 +0,0 @@
1
- // src/cli/version.ts
2
- import { fileURLToPath } from "url";
3
- import { dirname, join, resolve } from "path";
4
- import { existsSync, readFileSync } from "fs";
5
- var NPM_PACKAGE = "@openacp/cli";
6
- function findPackageJson() {
7
- let dir = dirname(fileURLToPath(import.meta.url));
8
- for (let i = 0; i < 5; i++) {
9
- const candidate = join(dir, "package.json");
10
- if (existsSync(candidate)) return candidate;
11
- const parent = resolve(dir, "..");
12
- if (parent === dir) break;
13
- dir = parent;
14
- }
15
- return null;
16
- }
17
- function getCurrentVersion() {
18
- try {
19
- const pkgPath = findPackageJson();
20
- if (!pkgPath) return "0.0.0-dev";
21
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
22
- return pkg.version;
23
- } catch {
24
- return "0.0.0-dev";
25
- }
26
- }
27
- async function getLatestVersion() {
28
- try {
29
- const res = await fetch(`https://registry.npmjs.org/${NPM_PACKAGE}/latest`, {
30
- signal: AbortSignal.timeout(5e3)
31
- });
32
- if (!res.ok) return null;
33
- const data = await res.json();
34
- return data.version ?? null;
35
- } catch {
36
- return null;
37
- }
38
- }
39
- function compareVersions(current, latest) {
40
- const a = current.split(".").map(Number);
41
- const b = latest.split(".").map(Number);
42
- for (let i = 0; i < 3; i++) {
43
- if ((a[i] ?? 0) < (b[i] ?? 0)) return -1;
44
- if ((a[i] ?? 0) > (b[i] ?? 0)) return 1;
45
- }
46
- return 0;
47
- }
48
- async function runUpdate() {
49
- const { spawn } = await import("child_process");
50
- return new Promise((resolve2) => {
51
- const child = spawn("npm", ["install", "-g", `${NPM_PACKAGE}@latest`], {
52
- stdio: "inherit",
53
- shell: true
54
- });
55
- const onSignal = () => {
56
- child.kill("SIGTERM");
57
- resolve2(false);
58
- };
59
- process.on("SIGINT", onSignal);
60
- process.on("SIGTERM", onSignal);
61
- child.on("close", (code) => {
62
- process.off("SIGINT", onSignal);
63
- process.off("SIGTERM", onSignal);
64
- resolve2(code === 0);
65
- });
66
- });
67
- }
68
- async function checkAndPromptUpdate() {
69
- if (process.env.OPENACP_DEV_LOOP || process.env.OPENACP_SKIP_UPDATE_CHECK) return;
70
- const current = getCurrentVersion();
71
- if (current === "0.0.0-dev") return;
72
- const latest = await getLatestVersion();
73
- if (!latest || compareVersions(current, latest) >= 0) return;
74
- console.log(`\x1B[33mUpdate available: v${current} \u2192 v${latest}\x1B[0m`);
75
- const clack = await import("@clack/prompts");
76
- const yes = await clack.confirm({
77
- message: "Update now before starting?"
78
- });
79
- if (clack.isCancel(yes) || !yes) {
80
- return;
81
- }
82
- const ok = await runUpdate();
83
- if (ok) {
84
- console.log(`\x1B[32m\u2713 Updated to v${latest}. Please re-run your command.\x1B[0m`);
85
- process.exit(0);
86
- } else {
87
- console.error("\x1B[31mUpdate failed. Continuing with current version.\x1B[0m");
88
- }
89
- }
90
-
91
- export {
92
- getCurrentVersion,
93
- getLatestVersion,
94
- compareVersions,
95
- runUpdate,
96
- checkAndPromptUpdate
97
- };
98
- //# sourceMappingURL=chunk-S64CB6J3.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/cli/version.ts"],"sourcesContent":["import { fileURLToPath } from 'node:url'\nimport { dirname, join, resolve } from 'node:path'\nimport { existsSync, readFileSync } from 'node:fs'\n\nconst NPM_PACKAGE = '@openacp/cli'\n\nfunction findPackageJson(): string | null {\n let dir = dirname(fileURLToPath(import.meta.url))\n for (let i = 0; i < 5; i++) {\n const candidate = join(dir, 'package.json')\n if (existsSync(candidate)) return candidate\n const parent = resolve(dir, '..')\n if (parent === dir) break\n dir = parent\n }\n return null\n}\n\nexport function getCurrentVersion(): string {\n try {\n const pkgPath = findPackageJson()\n if (!pkgPath) return '0.0.0-dev'\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))\n return pkg.version as string\n } catch {\n return '0.0.0-dev'\n }\n}\n\nexport async function getLatestVersion(): Promise<string | null> {\n try {\n const res = await fetch(`https://registry.npmjs.org/${NPM_PACKAGE}/latest`, {\n signal: AbortSignal.timeout(5000),\n })\n if (!res.ok) return null\n const data = (await res.json()) as { version?: string }\n return data.version ?? null\n } catch {\n return null\n }\n}\n\nexport function compareVersions(current: string, latest: string): -1 | 0 | 1 {\n const a = current.split('.').map(Number)\n const b = latest.split('.').map(Number)\n for (let i = 0; i < 3; i++) {\n if ((a[i] ?? 0) < (b[i] ?? 0)) return -1\n if ((a[i] ?? 0) > (b[i] ?? 0)) return 1\n }\n return 0\n}\n\nexport async function runUpdate(): Promise<boolean> {\n const { spawn } = await import('node:child_process')\n return new Promise((resolve) => {\n const child = spawn('npm', ['install', '-g', `${NPM_PACKAGE}@latest`], {\n stdio: 'inherit',\n shell: true,\n })\n const onSignal = () => {\n child.kill('SIGTERM')\n resolve(false)\n }\n process.on('SIGINT', onSignal)\n process.on('SIGTERM', onSignal)\n child.on('close', (code) => {\n process.off('SIGINT', onSignal)\n process.off('SIGTERM', onSignal)\n resolve(code === 0)\n })\n })\n}\n\nexport async function checkAndPromptUpdate(): Promise<void> {\n if (process.env.OPENACP_DEV_LOOP || process.env.OPENACP_SKIP_UPDATE_CHECK) return\n\n const current = getCurrentVersion()\n if (current === '0.0.0-dev') return\n\n const latest = await getLatestVersion()\n if (!latest || compareVersions(current, latest) >= 0) return\n\n console.log(`\\x1b[33mUpdate available: v${current} → v${latest}\\x1b[0m`)\n const clack = await import('@clack/prompts')\n const yes = await clack.confirm({\n message: 'Update now before starting?',\n })\n if (clack.isCancel(yes) || !yes) {\n return\n }\n const ok = await runUpdate()\n if (ok) {\n console.log(`\\x1b[32m✓ Updated to v${latest}. Please re-run your command.\\x1b[0m`)\n process.exit(0)\n } else {\n console.error('\\x1b[31mUpdate failed. Continuing with current version.\\x1b[0m')\n }\n}\n"],"mappings":"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","names":["resolve"]}