@openacp/cli 2026.326.4 → 2026.327.2

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 (132) hide show
  1. package/README.md +2 -2
  2. package/dist/{adapter-6ANPBSVU.js → adapter-LC2QSDAS.js} +4 -5
  3. package/dist/{adapter-PQGHVG4K.js → adapter-Y55NXX6I.js} +2 -2
  4. package/dist/{api-server-3PYLRBCN.js → api-server-7G3ZUZRM.js} +2 -2
  5. package/dist/{api-server-CHVSUDBX.js → api-server-CAYNPUF2.js} +2 -2
  6. package/dist/{chunk-UNJUWWQO.js → chunk-2YCW3QDV.js} +21 -14
  7. package/dist/chunk-2YCW3QDV.js.map +1 -0
  8. package/dist/{chunk-Y64XWMJ4.js → chunk-36YQ44D7.js} +2 -2
  9. package/dist/{chunk-UB2QB6DE.js → chunk-3ASUU6WW.js} +2 -2
  10. package/dist/{chunk-V5JT5TPD.js → chunk-4GMLGCF2.js} +2 -2
  11. package/dist/chunk-CDAUYTVP.js +41 -0
  12. package/dist/chunk-CDAUYTVP.js.map +1 -0
  13. package/dist/{chunk-Q6ZXJTZB.js → chunk-HUWOFP2H.js} +9 -17
  14. package/dist/chunk-HUWOFP2H.js.map +1 -0
  15. package/dist/{chunk-P4SNGQNI.js → chunk-KMMEFXIE.js} +2 -2
  16. package/dist/{chunk-RKB2ZK6S.js → chunk-LP45RCA4.js} +579 -153
  17. package/dist/chunk-LP45RCA4.js.map +1 -0
  18. package/dist/{chunk-L7YNNBI5.js → chunk-QAQDGPB4.js} +1 -75
  19. package/dist/chunk-QAQDGPB4.js.map +1 -0
  20. package/dist/{chunk-V2M243KZ.js → chunk-TRXBJEZ5.js} +55 -53
  21. package/dist/chunk-TRXBJEZ5.js.map +1 -0
  22. package/dist/{chunk-NBFIBGAT.js → chunk-UMT7RU77.js} +45 -118
  23. package/dist/chunk-UMT7RU77.js.map +1 -0
  24. package/dist/{chunk-FQEBWOZR.js → chunk-XIBG7LSL.js} +181 -128
  25. package/dist/chunk-XIBG7LSL.js.map +1 -0
  26. package/dist/cli.js +155 -49
  27. package/dist/cli.js.map +1 -1
  28. package/dist/{config-editor-HNEKXRLQ.js → config-editor-3IKBPZA7.js} +2 -2
  29. package/dist/{core-plugins-VEUNFTMB.js → core-plugins-ROU4GPLT.js} +8 -12
  30. package/dist/{dev-loader-RDC5E2CW.js → dev-loader-DRU3R7ZM.js} +7 -18
  31. package/dist/dev-loader-DRU3R7ZM.js.map +1 -0
  32. package/dist/{doctor-H72BZOPA.js → doctor-QZQAP46W.js} +2 -2
  33. package/dist/index.d.ts +128 -66
  34. package/dist/index.js +41 -20
  35. package/dist/index.js.map +1 -1
  36. package/dist/{integrate-5C6KSU6D.js → integrate-G6CVXTGT.js} +3 -4
  37. package/dist/integrate-G6CVXTGT.js.map +1 -0
  38. package/dist/{main-T5WVCCFN.js → main-UVTZ46WP.js} +39 -185
  39. package/dist/main-UVTZ46WP.js.map +1 -0
  40. package/dist/plugin-create-5HQRF2ID.js +967 -0
  41. package/dist/plugin-create-5HQRF2ID.js.map +1 -0
  42. package/dist/plugin-installer-GQ2P3Q3E.js +23 -0
  43. package/dist/plugin-installer-GQ2P3Q3E.js.map +1 -0
  44. package/dist/plugin-search-HQ4WQKOF.js +40 -0
  45. package/dist/plugin-search-HQ4WQKOF.js.map +1 -0
  46. package/dist/{post-upgrade-XLHZ6ZB7.js → post-upgrade-3ADZRMYJ.js} +2 -2
  47. package/dist/registry-client-AVGRE4CF.js +8 -0
  48. package/dist/{setup-BAI2F24H.js → setup-EYAFK2WI.js} +77 -50
  49. package/dist/setup-EYAFK2WI.js.map +1 -0
  50. package/dist/{slack-KH7E3VBS.js → slack-37ZWBDUI.js} +2 -2
  51. package/dist/{telegram-ZDC3JQF2.js → telegram-2ZCCCZIY.js} +2 -2
  52. package/dist/{tunnel-M47I7H4B.js → tunnel-45HA72MB.js} +2 -2
  53. package/dist/{tunnel-service-WADYHREX.js → tunnel-service-QJPUYEKU.js} +11 -3
  54. package/dist/tunnel-service-QJPUYEKU.js.map +1 -0
  55. package/package.json +2 -3
  56. package/dist/action-detect-QPA775HB.js +0 -16
  57. package/dist/adapter-77ZCVABT.js +0 -2394
  58. package/dist/adapter-77ZCVABT.js.map +0 -1
  59. package/dist/admin-GBPZFFAU.js +0 -23
  60. package/dist/agents-BWU4MRRD.js +0 -15
  61. package/dist/chunk-2CX4IEEC.js +0 -124
  62. package/dist/chunk-2CX4IEEC.js.map +0 -1
  63. package/dist/chunk-4KGLKKQK.js +0 -298
  64. package/dist/chunk-4KGLKKQK.js.map +0 -1
  65. package/dist/chunk-5ZOFBTOR.js +0 -553
  66. package/dist/chunk-5ZOFBTOR.js.map +0 -1
  67. package/dist/chunk-6RXVEXF3.js +0 -23
  68. package/dist/chunk-6RXVEXF3.js.map +0 -1
  69. package/dist/chunk-FQEBWOZR.js.map +0 -1
  70. package/dist/chunk-GJOY37U7.js +0 -265
  71. package/dist/chunk-GJOY37U7.js.map +0 -1
  72. package/dist/chunk-HVBNCPAY.js +0 -71
  73. package/dist/chunk-HVBNCPAY.js.map +0 -1
  74. package/dist/chunk-I3CGU5W7.js +0 -134
  75. package/dist/chunk-I3CGU5W7.js.map +0 -1
  76. package/dist/chunk-L7YNNBI5.js.map +0 -1
  77. package/dist/chunk-MTSDOSXS.js +0 -219
  78. package/dist/chunk-MTSDOSXS.js.map +0 -1
  79. package/dist/chunk-NAM4ERUW.js +0 -203
  80. package/dist/chunk-NAM4ERUW.js.map +0 -1
  81. package/dist/chunk-NBFIBGAT.js.map +0 -1
  82. package/dist/chunk-O5RG4YZY.js +0 -122
  83. package/dist/chunk-O5RG4YZY.js.map +0 -1
  84. package/dist/chunk-Q6ZXJTZB.js.map +0 -1
  85. package/dist/chunk-QSDZDHNS.js +0 -145
  86. package/dist/chunk-QSDZDHNS.js.map +0 -1
  87. package/dist/chunk-RKB2ZK6S.js.map +0 -1
  88. package/dist/chunk-UNJUWWQO.js.map +0 -1
  89. package/dist/chunk-V2M243KZ.js.map +0 -1
  90. package/dist/chunk-WAAD23KY.js +0 -222
  91. package/dist/chunk-WAAD23KY.js.map +0 -1
  92. package/dist/chunk-WVLDNYOJ.js +0 -150
  93. package/dist/chunk-WVLDNYOJ.js.map +0 -1
  94. package/dist/dev-loader-RDC5E2CW.js.map +0 -1
  95. package/dist/discord-NOJQ5PZO.js +0 -8
  96. package/dist/doctor-RF6BHMCC.js +0 -15
  97. package/dist/doctor-RF6BHMCC.js.map +0 -1
  98. package/dist/integrate-5C6KSU6D.js.map +0 -1
  99. package/dist/main-T5WVCCFN.js.map +0 -1
  100. package/dist/new-session-AVQCNXRG.js +0 -17
  101. package/dist/new-session-AVQCNXRG.js.map +0 -1
  102. package/dist/plugin-create-AQ3B22BZ.js +0 -334
  103. package/dist/plugin-create-AQ3B22BZ.js.map +0 -1
  104. package/dist/session-KZFA6Z26.js +0 -20
  105. package/dist/session-KZFA6Z26.js.map +0 -1
  106. package/dist/settings-MFYM7CZO.js +0 -14
  107. package/dist/settings-MFYM7CZO.js.map +0 -1
  108. package/dist/setup-BAI2F24H.js.map +0 -1
  109. package/dist/slack-KH7E3VBS.js.map +0 -1
  110. package/dist/telegram-ZDC3JQF2.js.map +0 -1
  111. package/dist/tunnel-M47I7H4B.js.map +0 -1
  112. package/dist/tunnel-service-WADYHREX.js.map +0 -1
  113. package/dist/usage-WYNK6ZC5.js +0 -10
  114. package/dist/usage-WYNK6ZC5.js.map +0 -1
  115. package/dist/validators-6CLEZUBD.js +0 -8
  116. package/dist/validators-6CLEZUBD.js.map +0 -1
  117. /package/dist/{action-detect-QPA775HB.js.map → adapter-LC2QSDAS.js.map} +0 -0
  118. /package/dist/{adapter-PQGHVG4K.js.map → adapter-Y55NXX6I.js.map} +0 -0
  119. /package/dist/{adapter-6ANPBSVU.js.map → api-server-7G3ZUZRM.js.map} +0 -0
  120. /package/dist/{admin-GBPZFFAU.js.map → api-server-CAYNPUF2.js.map} +0 -0
  121. /package/dist/{chunk-Y64XWMJ4.js.map → chunk-36YQ44D7.js.map} +0 -0
  122. /package/dist/{chunk-UB2QB6DE.js.map → chunk-3ASUU6WW.js.map} +0 -0
  123. /package/dist/{chunk-V5JT5TPD.js.map → chunk-4GMLGCF2.js.map} +0 -0
  124. /package/dist/{chunk-P4SNGQNI.js.map → chunk-KMMEFXIE.js.map} +0 -0
  125. /package/dist/{agents-BWU4MRRD.js.map → config-editor-3IKBPZA7.js.map} +0 -0
  126. /package/dist/{api-server-3PYLRBCN.js.map → core-plugins-ROU4GPLT.js.map} +0 -0
  127. /package/dist/{api-server-CHVSUDBX.js.map → doctor-QZQAP46W.js.map} +0 -0
  128. /package/dist/{post-upgrade-XLHZ6ZB7.js.map → post-upgrade-3ADZRMYJ.js.map} +0 -0
  129. /package/dist/{config-editor-HNEKXRLQ.js.map → registry-client-AVGRE4CF.js.map} +0 -0
  130. /package/dist/{core-plugins-VEUNFTMB.js.map → slack-37ZWBDUI.js.map} +0 -0
  131. /package/dist/{discord-NOJQ5PZO.js.map → telegram-2ZCCCZIY.js.map} +0 -0
  132. /package/dist/{doctor-H72BZOPA.js.map → tunnel-45HA72MB.js.map} +0 -0
package/README.md CHANGED
@@ -10,7 +10,7 @@ Send a message. The agent writes code. You see everything — in real time.
10
10
  [![Node.js >= 20](https://img.shields.io/badge/Node.js-%3E%3D%2020-green.svg)](https://nodejs.org/)
11
11
  [![ACP Protocol](https://img.shields.io/badge/Protocol-ACP-purple.svg)](https://agentclientprotocol.org/)
12
12
  [![npm](https://img.shields.io/npm/v/@openacp/cli.svg)](https://www.npmjs.com/package/@openacp/cli)
13
- [![Twitter Follow](https://img.shields.io/twitter/follow/Open_ACP?style=social)](https://x.com/Open_ACP)
13
+ [![Twitter Follow](https://img.shields.io/twitter/follow/openacp_ai?style=social)](https://x.com/openacp_ai)
14
14
 
15
15
  [Documentation](docs/gitbook/) · [Quick Start](#quick-start) · [Features](#features) · [Agents](#supported-agents) · [Contributing](docs/gitbook/extending/contributing.md)
16
16
 
@@ -182,7 +182,7 @@ We welcome contributions! See the [contributing guide](docs/gitbook/extending/co
182
182
 
183
183
  ## Follow Us
184
184
 
185
- [![Twitter Follow](https://img.shields.io/twitter/follow/Open_ACP?style=social)](https://x.com/Open_ACP)
185
+ [![Twitter Follow](https://img.shields.io/twitter/follow/openacp_ai?style=social)](https://x.com/openacp_ai)
186
186
 
187
187
  ## License
188
188
 
@@ -1,10 +1,9 @@
1
1
  import {
2
2
  TelegramAdapter
3
- } from "./chunk-RKB2ZK6S.js";
4
- import "./chunk-5ZOFBTOR.js";
5
- import "./chunk-V2M243KZ.js";
3
+ } from "./chunk-LP45RCA4.js";
6
4
  import "./chunk-AFKX424Q.js";
7
- import "./chunk-L7YNNBI5.js";
5
+ import "./chunk-QAQDGPB4.js";
6
+ import "./chunk-TRXBJEZ5.js";
8
7
  import "./chunk-APS6UEFU.js";
9
8
  import "./chunk-ODUM3D6X.js";
10
9
  import "./chunk-QVMEF6FB.js";
@@ -13,4 +12,4 @@ import "./chunk-VUNV25KB.js";
13
12
  export {
14
13
  TelegramAdapter
15
14
  };
16
- //# sourceMappingURL=adapter-6ANPBSVU.js.map
15
+ //# sourceMappingURL=adapter-LC2QSDAS.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  BaseRenderer,
3
3
  MessagingAdapter
4
- } from "./chunk-V2M243KZ.js";
4
+ } from "./chunk-TRXBJEZ5.js";
5
5
  import {
6
6
  createChildLogger
7
7
  } from "./chunk-XMMAGAT4.js";
@@ -1003,4 +1003,4 @@ ${notification.summary}`;
1003
1003
  export {
1004
1004
  SlackAdapter
1005
1005
  };
1006
- //# sourceMappingURL=adapter-PQGHVG4K.js.map
1006
+ //# sourceMappingURL=adapter-Y55NXX6I.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  api_server_default
3
- } from "./chunk-V5JT5TPD.js";
3
+ } from "./chunk-4GMLGCF2.js";
4
4
  import "./chunk-VUNV25KB.js";
5
5
  export {
6
6
  api_server_default as default
7
7
  };
8
- //# sourceMappingURL=api-server-3PYLRBCN.js.map
8
+ //# sourceMappingURL=api-server-7G3ZUZRM.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ApiServer
3
- } from "./chunk-UNJUWWQO.js";
3
+ } from "./chunk-2YCW3QDV.js";
4
4
  import "./chunk-FNRSWA2K.js";
5
5
  import "./chunk-ZSLHHQPQ.js";
6
6
  import "./chunk-XMMAGAT4.js";
@@ -8,4 +8,4 @@ import "./chunk-VUNV25KB.js";
8
8
  export {
9
9
  ApiServer
10
10
  };
11
- //# sourceMappingURL=api-server-CHVSUDBX.js.map
11
+ //# sourceMappingURL=api-server-CAYNPUF2.js.map
@@ -322,11 +322,13 @@ function registerSessionRoutes(router, deps) {
322
322
  const body = await deps.readBody(req);
323
323
  let agent;
324
324
  let workspace;
325
+ let channel;
325
326
  if (body) {
326
327
  try {
327
328
  const parsed = JSON.parse(body);
328
329
  agent = parsed.agent;
329
330
  workspace = parsed.workspace;
331
+ channel = parsed.channel;
330
332
  } catch {
331
333
  deps.sendJson(res, 400, { error: "Invalid JSON body" });
332
334
  return;
@@ -340,10 +342,24 @@ function registerSessionRoutes(router, deps) {
340
342
  });
341
343
  return;
342
344
  }
343
- const [adapterId, adapter] = deps.core.adapters.entries().next().value ?? [
344
- null,
345
- null
346
- ];
345
+ let adapterId = null;
346
+ let adapter = null;
347
+ if (channel) {
348
+ if (!deps.core.adapters.has(channel)) {
349
+ const available = Array.from(deps.core.adapters.keys()).join(", ") || "none";
350
+ deps.sendJson(res, 400, {
351
+ error: `Adapter '${channel}' is not connected. Available: ${available}`
352
+ });
353
+ return;
354
+ }
355
+ adapterId = channel;
356
+ adapter = deps.core.adapters.get(channel) ?? null;
357
+ } else {
358
+ const firstEntry = deps.core.adapters.entries().next().value;
359
+ if (firstEntry) {
360
+ [adapterId, adapter] = firstEntry;
361
+ }
362
+ }
347
363
  const channelId = adapterId ?? "api";
348
364
  const resolvedAgent = agent || config.defaultAgent;
349
365
  const resolvedWorkspace = deps.core.configManager.resolveWorkspace(
@@ -507,15 +523,6 @@ function registerSessionRoutes(router, deps) {
507
523
  }
508
524
  });
509
525
  });
510
- router.post("/api/sessions/:sessionId/summary", async (_req, res, params) => {
511
- const sessionId = decodeURIComponent(params.sessionId);
512
- const result = await deps.core.summarizeSession(sessionId);
513
- if (result.ok) {
514
- deps.sendJson(res, 200, result);
515
- } else {
516
- deps.sendJson(res, 400, result);
517
- }
518
- });
519
526
  router.post("/api/sessions/:sessionId/archive", async (_req, res, params) => {
520
527
  const sessionId = decodeURIComponent(params.sessionId);
521
528
  const result = await deps.core.archiveSession(sessionId);
@@ -1105,4 +1112,4 @@ export {
1105
1112
  StaticServer,
1106
1113
  ApiServer
1107
1114
  };
1108
- //# sourceMappingURL=chunk-UNJUWWQO.js.map
1115
+ //# sourceMappingURL=chunk-2YCW3QDV.js.map
@@ -0,0 +1 @@
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 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 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/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"]}
@@ -146,7 +146,7 @@ function createTelegramPlugin() {
146
146
  ctx.log.info("Telegram disabled (missing botToken or chatId)");
147
147
  return;
148
148
  }
149
- const { TelegramAdapter } = await import("./adapter-6ANPBSVU.js");
149
+ const { TelegramAdapter } = await import("./adapter-LC2QSDAS.js");
150
150
  adapter = new TelegramAdapter(ctx.core, {
151
151
  ...config,
152
152
  enabled: true,
@@ -209,4 +209,4 @@ var telegram_default = createTelegramPlugin();
209
209
  export {
210
210
  telegram_default
211
211
  };
212
- //# sourceMappingURL=chunk-Y64XWMJ4.js.map
212
+ //# sourceMappingURL=chunk-36YQ44D7.js.map
@@ -100,7 +100,7 @@ function createSlackPlugin() {
100
100
  ctx.log.info("Slack disabled (missing botToken or appToken)");
101
101
  return;
102
102
  }
103
- const { SlackAdapter } = await import("./adapter-PQGHVG4K.js");
103
+ const { SlackAdapter } = await import("./adapter-Y55NXX6I.js");
104
104
  adapter = new SlackAdapter(ctx.core, {
105
105
  ...config,
106
106
  enabled: true,
@@ -121,4 +121,4 @@ var slack_default = createSlackPlugin();
121
121
  export {
122
122
  slack_default
123
123
  };
124
- //# sourceMappingURL=chunk-UB2QB6DE.js.map
124
+ //# sourceMappingURL=chunk-3ASUU6WW.js.map
@@ -66,7 +66,7 @@ function createApiServerPlugin() {
66
66
  },
67
67
  async setup(ctx) {
68
68
  const config = ctx.pluginConfig;
69
- const { ApiServer } = await import("./api-server-CHVSUDBX.js");
69
+ const { ApiServer } = await import("./api-server-CAYNPUF2.js");
70
70
  const apiConfig = {
71
71
  port: config.port ?? 0,
72
72
  host: config.host ?? "127.0.0.1"
@@ -94,4 +94,4 @@ var api_server_default = createApiServerPlugin();
94
94
  export {
95
95
  api_server_default
96
96
  };
97
- //# sourceMappingURL=chunk-V5JT5TPD.js.map
97
+ //# sourceMappingURL=chunk-4GMLGCF2.js.map
@@ -0,0 +1,41 @@
1
+ // src/core/plugin/registry-client.ts
2
+ var REGISTRY_URL = "https://raw.githubusercontent.com/Open-ACP/plugin-registry/main/registry.json";
3
+ var CACHE_TTL = 60 * 1e3;
4
+ var RegistryClient = class {
5
+ cache = null;
6
+ registryUrl;
7
+ constructor(registryUrl) {
8
+ this.registryUrl = registryUrl ?? REGISTRY_URL;
9
+ }
10
+ async getRegistry() {
11
+ if (this.cache && Date.now() - this.cache.fetchedAt < CACHE_TTL) {
12
+ return this.cache.data;
13
+ }
14
+ const res = await fetch(this.registryUrl);
15
+ if (!res.ok) throw new Error(`Failed to fetch registry: ${res.status}`);
16
+ const data = await res.json();
17
+ this.cache = { data, fetchedAt: Date.now() };
18
+ return data;
19
+ }
20
+ async search(query) {
21
+ const registry = await this.getRegistry();
22
+ const q = query.toLowerCase();
23
+ return registry.plugins.filter((p) => {
24
+ const text = `${p.name} ${p.displayName ?? ""} ${p.description} ${p.tags?.join(" ") ?? ""}`.toLowerCase();
25
+ return text.includes(q);
26
+ });
27
+ }
28
+ async resolve(name) {
29
+ const registry = await this.getRegistry();
30
+ const plugin = registry.plugins.find((p) => p.name === name);
31
+ return plugin?.npm ?? null;
32
+ }
33
+ clearCache() {
34
+ this.cache = null;
35
+ }
36
+ };
37
+
38
+ export {
39
+ RegistryClient
40
+ };
41
+ //# sourceMappingURL=chunk-CDAUYTVP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/plugin/registry-client.ts"],"sourcesContent":["const REGISTRY_URL = 'https://raw.githubusercontent.com/Open-ACP/plugin-registry/main/registry.json'\nconst CACHE_TTL = 60 * 1000 // 1 minute\n\nexport interface RegistryPlugin {\n name: string\n displayName?: string\n description: string\n npm: string\n version: string\n minCliVersion: string\n category: string\n tags: string[]\n icon: string\n author: string\n repository: string\n license: string\n verified: boolean\n featured: boolean\n}\n\nexport interface Registry {\n version: number\n generatedAt: string\n pluginCount: number\n plugins: RegistryPlugin[]\n categories: Array<{ id: string; name: string; icon: string }>\n}\n\nexport class RegistryClient {\n private cache: { data: Registry; fetchedAt: number } | null = null\n private registryUrl: string\n\n constructor(registryUrl?: string) {\n this.registryUrl = registryUrl ?? REGISTRY_URL\n }\n\n async getRegistry(): Promise<Registry> {\n if (this.cache && Date.now() - this.cache.fetchedAt < CACHE_TTL) {\n return this.cache.data\n }\n const res = await fetch(this.registryUrl)\n if (!res.ok) throw new Error(`Failed to fetch registry: ${res.status}`)\n const data = await res.json() as Registry\n this.cache = { data, fetchedAt: Date.now() }\n return data\n }\n\n async search(query: string): Promise<RegistryPlugin[]> {\n const registry = await this.getRegistry()\n const q = query.toLowerCase()\n return registry.plugins.filter(p => {\n const text = `${p.name} ${p.displayName ?? ''} ${p.description} ${p.tags?.join(' ') ?? ''}`.toLowerCase()\n return text.includes(q)\n })\n }\n\n async resolve(name: string): Promise<string | null> {\n const registry = await this.getRegistry()\n const plugin = registry.plugins.find(p => p.name === name)\n return plugin?.npm ?? null\n }\n\n clearCache(): void {\n this.cache = null\n }\n}\n"],"mappings":";AAAA,IAAM,eAAe;AACrB,IAAM,YAAY,KAAK;AA2BhB,IAAM,iBAAN,MAAqB;AAAA,EAClB,QAAsD;AAAA,EACtD;AAAA,EAER,YAAY,aAAsB;AAChC,SAAK,cAAc,eAAe;AAAA,EACpC;AAAA,EAEA,MAAM,cAAiC;AACrC,QAAI,KAAK,SAAS,KAAK,IAAI,IAAI,KAAK,MAAM,YAAY,WAAW;AAC/D,aAAO,KAAK,MAAM;AAAA,IACpB;AACA,UAAM,MAAM,MAAM,MAAM,KAAK,WAAW;AACxC,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,6BAA6B,IAAI,MAAM,EAAE;AACtE,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAK,QAAQ,EAAE,MAAM,WAAW,KAAK,IAAI,EAAE;AAC3C,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,OAA0C;AACrD,UAAM,WAAW,MAAM,KAAK,YAAY;AACxC,UAAM,IAAI,MAAM,YAAY;AAC5B,WAAO,SAAS,QAAQ,OAAO,OAAK;AAClC,YAAM,OAAO,GAAG,EAAE,IAAI,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,WAAW,IAAI,EAAE,MAAM,KAAK,GAAG,KAAK,EAAE,GAAG,YAAY;AACxG,aAAO,KAAK,SAAS,CAAC;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAQ,MAAsC;AAClD,UAAM,WAAW,MAAM,KAAK,YAAY;AACxC,UAAM,SAAS,SAAS,QAAQ,KAAK,OAAK,EAAE,SAAS,IAAI;AACzD,WAAO,QAAQ,OAAO;AAAA,EACxB;AAAA,EAEA,aAAmB;AACjB,SAAK,QAAQ;AAAA,EACf;AACF;","names":[]}
@@ -1,18 +1,18 @@
1
1
  import {
2
- slack_default
3
- } from "./chunk-UB2QB6DE.js";
2
+ telegram_default
3
+ } from "./chunk-36YQ44D7.js";
4
4
  import {
5
- discord_default
6
- } from "./chunk-WVLDNYOJ.js";
5
+ slack_default
6
+ } from "./chunk-3ASUU6WW.js";
7
7
  import {
8
- telegram_default
9
- } from "./chunk-Y64XWMJ4.js";
8
+ notifications_default
9
+ } from "./chunk-SNPYTMPR.js";
10
10
  import {
11
11
  tunnel_default
12
- } from "./chunk-P4SNGQNI.js";
12
+ } from "./chunk-KMMEFXIE.js";
13
13
  import {
14
14
  api_server_default
15
- } from "./chunk-V5JT5TPD.js";
15
+ } from "./chunk-4GMLGCF2.js";
16
16
  import {
17
17
  security_default
18
18
  } from "./chunk-5OCGO27U.js";
@@ -22,15 +22,9 @@ import {
22
22
  import {
23
23
  context_default
24
24
  } from "./chunk-ZHGPZBS4.js";
25
- import {
26
- usage_default
27
- } from "./chunk-2CX4IEEC.js";
28
25
  import {
29
26
  speech_default
30
27
  } from "./chunk-AD3X6DGK.js";
31
- import {
32
- notifications_default
33
- } from "./chunk-SNPYTMPR.js";
34
28
 
35
29
  // src/plugins/core-plugins.ts
36
30
  var corePlugins = [
@@ -38,7 +32,6 @@ var corePlugins = [
38
32
  security_default,
39
33
  file_service_default,
40
34
  context_default,
41
- usage_default,
42
35
  speech_default,
43
36
  notifications_default,
44
37
  // Infrastructure plugins
@@ -46,11 +39,10 @@ var corePlugins = [
46
39
  api_server_default,
47
40
  // Adapter plugins (depend on security, notifications, etc.)
48
41
  telegram_default,
49
- discord_default,
50
42
  slack_default
51
43
  ];
52
44
 
53
45
  export {
54
46
  corePlugins
55
47
  };
56
- //# sourceMappingURL=chunk-Q6ZXJTZB.js.map
48
+ //# sourceMappingURL=chunk-HUWOFP2H.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugins/core-plugins.ts"],"sourcesContent":["/**\n * All built-in plugins: services, infrastructure, and adapters.\n * Booted by LifecycleManager in dependency order.\n * Adapter plugins depend on service plugins, so they boot last.\n */\nimport securityPlugin from './security/index.js'\nimport fileServicePlugin from './file-service/index.js'\nimport contextPlugin from './context/index.js'\nimport speechPlugin from './speech/index.js'\nimport notificationsPlugin from './notifications/index.js'\nimport tunnelPlugin from './tunnel/index.js'\nimport apiServerPlugin from './api-server/index.js'\nimport telegramPlugin from './telegram/index.js'\nimport slackPlugin from './slack/index.js'\n\nexport const corePlugins = [\n // Service plugins (no adapter dependencies)\n securityPlugin,\n fileServicePlugin,\n contextPlugin,\n speechPlugin,\n notificationsPlugin,\n // Infrastructure plugins\n tunnelPlugin,\n apiServerPlugin,\n // Adapter plugins (depend on security, notifications, etc.)\n telegramPlugin,\n slackPlugin,\n]\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeO,IAAM,cAAc;AAAA;AAAA,EAEzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AACF;","names":[]}
@@ -116,7 +116,7 @@ function createTunnelPlugin() {
116
116
  ctx.log.info("Tunnel disabled (no provider configured)");
117
117
  return;
118
118
  }
119
- const { TunnelService } = await import("./tunnel-service-WADYHREX.js");
119
+ const { TunnelService } = await import("./tunnel-service-QJPUYEKU.js");
120
120
  const tunnelSvc = new TunnelService(config);
121
121
  const publicUrl = await tunnelSvc.start();
122
122
  service = tunnelSvc;
@@ -155,4 +155,4 @@ var tunnel_default = createTunnelPlugin();
155
155
  export {
156
156
  tunnel_default
157
157
  };
158
- //# sourceMappingURL=chunk-P4SNGQNI.js.map
158
+ //# sourceMappingURL=chunk-KMMEFXIE.js.map