@graychennpm/codebridge 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/LICENSE +21 -0
  3. package/README.md +217 -2
  4. package/README.zh-CN.md +222 -0
  5. package/apps/web/public/brand/agent-logo-carbon.svg +1 -0
  6. package/apps/web/public/brand/agent-logo.svg +1 -0
  7. package/docs/zh-CN/npm-release.md +77 -0
  8. package/node_modules/@codebridge/agent-registry/dist/index.d.ts +32 -0
  9. package/node_modules/@codebridge/agent-registry/dist/index.js +177 -0
  10. package/node_modules/@codebridge/agent-registry/dist/setup.d.ts +9 -0
  11. package/node_modules/@codebridge/agent-registry/dist/setup.js +115 -0
  12. package/node_modules/@codebridge/agent-registry/package.json +17 -0
  13. package/node_modules/@codebridge/backends/dist/acp/acp-active-session.d.ts +12 -0
  14. package/node_modules/@codebridge/backends/dist/acp/acp-active-session.js +57 -0
  15. package/node_modules/@codebridge/backends/dist/acp/acp-claude-activity.d.ts +9 -0
  16. package/node_modules/@codebridge/backends/dist/acp/acp-claude-activity.js +49 -0
  17. package/node_modules/@codebridge/backends/dist/acp/acp-config-options.d.ts +46 -0
  18. package/node_modules/@codebridge/backends/dist/acp/acp-config-options.js +220 -0
  19. package/node_modules/@codebridge/backends/dist/acp/acp-doctor.d.ts +3 -0
  20. package/node_modules/@codebridge/backends/dist/acp/acp-doctor.js +18 -0
  21. package/node_modules/@codebridge/backends/dist/acp/acp-event-mapper.d.ts +5 -0
  22. package/node_modules/@codebridge/backends/dist/acp/acp-event-mapper.js +136 -0
  23. package/node_modules/@codebridge/backends/dist/acp/acp-kill.d.ts +10 -0
  24. package/node_modules/@codebridge/backends/dist/acp/acp-kill.js +24 -0
  25. package/node_modules/@codebridge/backends/dist/acp/acp-race.d.ts +6 -0
  26. package/node_modules/@codebridge/backends/dist/acp/acp-race.js +29 -0
  27. package/node_modules/@codebridge/backends/dist/acp/acp-session-list.d.ts +32 -0
  28. package/node_modules/@codebridge/backends/dist/acp/acp-session-list.js +218 -0
  29. package/node_modules/@codebridge/backends/dist/acp/acp-session-pool.d.ts +85 -0
  30. package/node_modules/@codebridge/backends/dist/acp/acp-session-pool.js +165 -0
  31. package/node_modules/@codebridge/backends/dist/acp/acp-session-runner.d.ts +78 -0
  32. package/node_modules/@codebridge/backends/dist/acp/acp-session-runner.js +550 -0
  33. package/node_modules/@codebridge/backends/dist/acp/acp-spawn-profiles.d.ts +9 -0
  34. package/node_modules/@codebridge/backends/dist/acp/acp-spawn-profiles.js +28 -0
  35. package/node_modules/@codebridge/backends/dist/acp/headless-client.d.ts +19 -0
  36. package/node_modules/@codebridge/backends/dist/acp/headless-client.js +47 -0
  37. package/node_modules/@codebridge/backends/dist/acp/index.d.ts +9 -0
  38. package/node_modules/@codebridge/backends/dist/acp/index.js +9 -0
  39. package/node_modules/@codebridge/backends/dist/agent-setup.d.ts +60 -0
  40. package/node_modules/@codebridge/backends/dist/agent-setup.js +504 -0
  41. package/node_modules/@codebridge/backends/dist/attachment-prompt.d.ts +8 -0
  42. package/node_modules/@codebridge/backends/dist/attachment-prompt.js +28 -0
  43. package/node_modules/@codebridge/backends/dist/auth-error-hints.d.ts +8 -0
  44. package/node_modules/@codebridge/backends/dist/auth-error-hints.js +33 -0
  45. package/node_modules/@codebridge/backends/dist/codex-skill-commands.d.ts +3 -0
  46. package/node_modules/@codebridge/backends/dist/codex-skill-commands.js +88 -0
  47. package/node_modules/@codebridge/backends/dist/index.d.ts +18 -0
  48. package/node_modules/@codebridge/backends/dist/index.js +34 -0
  49. package/node_modules/@codebridge/backends/dist/pi-providers.d.ts +45 -0
  50. package/node_modules/@codebridge/backends/dist/pi-providers.js +148 -0
  51. package/node_modules/@codebridge/backends/dist/pi-session-runner.d.ts +85 -0
  52. package/node_modules/@codebridge/backends/dist/pi-session-runner.js +460 -0
  53. package/node_modules/@codebridge/backends/dist/provider-connection.d.ts +17 -0
  54. package/node_modules/@codebridge/backends/dist/provider-connection.js +99 -0
  55. package/node_modules/@codebridge/backends/dist/session-discovery.d.ts +23 -0
  56. package/node_modules/@codebridge/backends/dist/session-discovery.js +340 -0
  57. package/node_modules/@codebridge/backends/dist/skill-control-plane.d.ts +147 -0
  58. package/node_modules/@codebridge/backends/dist/skill-control-plane.js +832 -0
  59. package/node_modules/@codebridge/backends/package.json +22 -0
  60. package/node_modules/@codebridge/bridge/dist/alert-notification-rules.d.ts +14 -0
  61. package/node_modules/@codebridge/bridge/dist/alert-notification-rules.js +37 -0
  62. package/node_modules/@codebridge/bridge/dist/channel-config.d.ts +4 -0
  63. package/node_modules/@codebridge/bridge/dist/channel-config.js +9 -0
  64. package/node_modules/@codebridge/bridge/dist/channel-ingress.d.ts +5 -0
  65. package/node_modules/@codebridge/bridge/dist/channel-ingress.js +403 -0
  66. package/node_modules/@codebridge/bridge/dist/cli.d.ts +3 -0
  67. package/node_modules/@codebridge/bridge/dist/cli.js +581 -0
  68. package/node_modules/@codebridge/bridge/dist/deployment.d.ts +46 -0
  69. package/node_modules/@codebridge/bridge/dist/deployment.js +174 -0
  70. package/node_modules/@codebridge/bridge/dist/event-loop-lag.d.ts +19 -0
  71. package/node_modules/@codebridge/bridge/dist/event-loop-lag.js +33 -0
  72. package/node_modules/@codebridge/bridge/dist/feishu-alert-monitor.d.ts +70 -0
  73. package/node_modules/@codebridge/bridge/dist/feishu-alert-monitor.js +591 -0
  74. package/node_modules/@codebridge/bridge/dist/init-wizard.d.ts +52 -0
  75. package/node_modules/@codebridge/bridge/dist/init-wizard.js +571 -0
  76. package/node_modules/@codebridge/bridge/dist/mcp-api.d.ts +4 -0
  77. package/node_modules/@codebridge/bridge/dist/mcp-api.js +100 -0
  78. package/node_modules/@codebridge/bridge/dist/outbound-api.d.ts +31 -0
  79. package/node_modules/@codebridge/bridge/dist/outbound-api.js +184 -0
  80. package/node_modules/@codebridge/bridge/dist/outbound-publishers.d.ts +54 -0
  81. package/node_modules/@codebridge/bridge/dist/outbound-publishers.js +213 -0
  82. package/node_modules/@codebridge/bridge/dist/project-api.d.ts +4 -0
  83. package/node_modules/@codebridge/bridge/dist/project-api.js +161 -0
  84. package/node_modules/@codebridge/bridge/dist/secrets-command.d.ts +13 -0
  85. package/node_modules/@codebridge/bridge/dist/secrets-command.js +34 -0
  86. package/node_modules/@codebridge/bridge/dist/session-api.d.ts +26 -0
  87. package/node_modules/@codebridge/bridge/dist/session-api.js +1378 -0
  88. package/node_modules/@codebridge/bridge/dist/session-history-import.d.ts +24 -0
  89. package/node_modules/@codebridge/bridge/dist/session-history-import.js +82 -0
  90. package/node_modules/@codebridge/bridge/dist/session-runtime-api.d.ts +19 -0
  91. package/node_modules/@codebridge/bridge/dist/session-runtime-api.js +453 -0
  92. package/node_modules/@codebridge/bridge/dist/session-runtime-migration.d.ts +21 -0
  93. package/node_modules/@codebridge/bridge/dist/session-runtime-migration.js +43 -0
  94. package/node_modules/@codebridge/bridge/dist/session-runtime-types.d.ts +85 -0
  95. package/node_modules/@codebridge/bridge/dist/session-runtime-types.js +98 -0
  96. package/node_modules/@codebridge/bridge/dist/skill-api.d.ts +28 -0
  97. package/node_modules/@codebridge/bridge/dist/skill-api.js +129 -0
  98. package/node_modules/@codebridge/bridge/dist/startup-surfaces.d.ts +15 -0
  99. package/node_modules/@codebridge/bridge/dist/startup-surfaces.js +13 -0
  100. package/node_modules/@codebridge/bridge/dist/web-frontend.d.ts +8 -0
  101. package/node_modules/@codebridge/bridge/dist/web-frontend.js +76 -0
  102. package/node_modules/@codebridge/bridge/dist/work-item-api.d.ts +6 -0
  103. package/node_modules/@codebridge/bridge/dist/work-item-api.js +414 -0
  104. package/node_modules/@codebridge/bridge/package.json +28 -0
  105. package/node_modules/@codebridge/channel-feishu/dist/alert-reactions.d.ts +6 -0
  106. package/node_modules/@codebridge/channel-feishu/dist/alert-reactions.js +58 -0
  107. package/node_modules/@codebridge/channel-feishu/dist/alert-types.d.ts +35 -0
  108. package/node_modules/@codebridge/channel-feishu/dist/alert-types.js +2 -0
  109. package/node_modules/@codebridge/channel-feishu/dist/bridge.d.ts +130 -0
  110. package/node_modules/@codebridge/channel-feishu/dist/bridge.js +1231 -0
  111. package/node_modules/@codebridge/channel-feishu/dist/cardkit-writer.d.ts +48 -0
  112. package/node_modules/@codebridge/channel-feishu/dist/cardkit-writer.js +153 -0
  113. package/node_modules/@codebridge/channel-feishu/dist/chain-topics.d.ts +20 -0
  114. package/node_modules/@codebridge/channel-feishu/dist/chain-topics.js +35 -0
  115. package/node_modules/@codebridge/channel-feishu/dist/coalescing-card-writer.d.ts +12 -0
  116. package/node_modules/@codebridge/channel-feishu/dist/coalescing-card-writer.js +53 -0
  117. package/node_modules/@codebridge/channel-feishu/dist/delivery-reconciler.d.ts +19 -0
  118. package/node_modules/@codebridge/channel-feishu/dist/delivery-reconciler.js +53 -0
  119. package/node_modules/@codebridge/channel-feishu/dist/durable-markdown-card.d.ts +19 -0
  120. package/node_modules/@codebridge/channel-feishu/dist/durable-markdown-card.js +77 -0
  121. package/node_modules/@codebridge/channel-feishu/dist/feishu-extra-events.d.ts +27 -0
  122. package/node_modules/@codebridge/channel-feishu/dist/feishu-extra-events.js +24 -0
  123. package/node_modules/@codebridge/channel-feishu/dist/feishu-http.d.ts +4 -0
  124. package/node_modules/@codebridge/channel-feishu/dist/feishu-http.js +25 -0
  125. package/node_modules/@codebridge/channel-feishu/dist/feishu-inbound-context.d.ts +13 -0
  126. package/node_modules/@codebridge/channel-feishu/dist/feishu-inbound-context.js +45 -0
  127. package/node_modules/@codebridge/channel-feishu/dist/feishu-inbound-media.d.ts +22 -0
  128. package/node_modules/@codebridge/channel-feishu/dist/feishu-inbound-media.js +273 -0
  129. package/node_modules/@codebridge/channel-feishu/dist/feishu-mention-gate.d.ts +13 -0
  130. package/node_modules/@codebridge/channel-feishu/dist/feishu-mention-gate.js +22 -0
  131. package/node_modules/@codebridge/channel-feishu/dist/feishu-outbound-file.d.ts +12 -0
  132. package/node_modules/@codebridge/channel-feishu/dist/feishu-outbound-file.js +38 -0
  133. package/node_modules/@codebridge/channel-feishu/dist/feishu-quoted-message.d.ts +30 -0
  134. package/node_modules/@codebridge/channel-feishu/dist/feishu-quoted-message.js +183 -0
  135. package/node_modules/@codebridge/channel-feishu/dist/index.d.ts +7 -0
  136. package/node_modules/@codebridge/channel-feishu/dist/index.js +3 -0
  137. package/node_modules/@codebridge/channel-feishu/dist/redacting-logger.d.ts +17 -0
  138. package/node_modules/@codebridge/channel-feishu/dist/redacting-logger.js +41 -0
  139. package/node_modules/@codebridge/channel-feishu/dist/run-status.d.ts +39 -0
  140. package/node_modules/@codebridge/channel-feishu/dist/run-status.js +166 -0
  141. package/node_modules/@codebridge/channel-feishu/dist/session-watcher.d.ts +98 -0
  142. package/node_modules/@codebridge/channel-feishu/dist/session-watcher.js +655 -0
  143. package/node_modules/@codebridge/channel-feishu/package.json +19 -0
  144. package/node_modules/@codebridge/channel-telegram/dist/coalescing-message-writer.d.ts +14 -0
  145. package/node_modules/@codebridge/channel-telegram/dist/coalescing-message-writer.js +56 -0
  146. package/node_modules/@codebridge/channel-telegram/dist/index.d.ts +3 -0
  147. package/node_modules/@codebridge/channel-telegram/dist/index.js +3 -0
  148. package/node_modules/@codebridge/channel-telegram/dist/telegram-api.d.ts +62 -0
  149. package/node_modules/@codebridge/channel-telegram/dist/telegram-api.js +72 -0
  150. package/node_modules/@codebridge/channel-telegram/dist/telegram-bridge.d.ts +64 -0
  151. package/node_modules/@codebridge/channel-telegram/dist/telegram-bridge.js +469 -0
  152. package/node_modules/@codebridge/channel-telegram/dist/telegram-session-watcher.d.ts +41 -0
  153. package/node_modules/@codebridge/channel-telegram/dist/telegram-session-watcher.js +184 -0
  154. package/node_modules/@codebridge/channel-telegram/package.json +18 -0
  155. package/node_modules/@codebridge/core/dist/config-schema.d.ts +1195 -0
  156. package/node_modules/@codebridge/core/dist/config-schema.js +293 -0
  157. package/node_modules/@codebridge/core/dist/config-store.d.ts +48 -0
  158. package/node_modules/@codebridge/core/dist/config-store.js +207 -0
  159. package/node_modules/@codebridge/core/dist/index.d.ts +11 -0
  160. package/node_modules/@codebridge/core/dist/index.js +10 -0
  161. package/node_modules/@codebridge/core/dist/json-file-store.d.ts +16 -0
  162. package/node_modules/@codebridge/core/dist/json-file-store.js +46 -0
  163. package/node_modules/@codebridge/core/dist/mcp-types.d.ts +7 -0
  164. package/node_modules/@codebridge/core/dist/mcp-types.js +2 -0
  165. package/node_modules/@codebridge/core/dist/mentions.d.ts +36 -0
  166. package/node_modules/@codebridge/core/dist/mentions.js +138 -0
  167. package/node_modules/@codebridge/core/dist/secret-migration.d.ts +14 -0
  168. package/node_modules/@codebridge/core/dist/secret-migration.js +55 -0
  169. package/node_modules/@codebridge/core/dist/secret-refs.d.ts +34 -0
  170. package/node_modules/@codebridge/core/dist/secret-refs.js +142 -0
  171. package/node_modules/@codebridge/core/dist/session-event-wire.d.ts +17 -0
  172. package/node_modules/@codebridge/core/dist/session-event-wire.js +28 -0
  173. package/node_modules/@codebridge/core/dist/types.d.ts +363 -0
  174. package/node_modules/@codebridge/core/dist/types.js +22 -0
  175. package/node_modules/@codebridge/core/dist/workspace-key.d.ts +11 -0
  176. package/node_modules/@codebridge/core/dist/workspace-key.js +25 -0
  177. package/node_modules/@codebridge/core/package.json +22 -0
  178. package/node_modules/@codebridge/mcp-runtime/dist/.tsbuildinfo +1 -0
  179. package/node_modules/@codebridge/mcp-runtime/dist/index.d.ts +92 -0
  180. package/node_modules/@codebridge/mcp-runtime/dist/index.js +377 -0
  181. package/node_modules/@codebridge/mcp-runtime/package.json +19 -0
  182. package/node_modules/@codebridge/policy/dist/capability-runtime.d.ts +123 -0
  183. package/node_modules/@codebridge/policy/dist/capability-runtime.js +195 -0
  184. package/node_modules/@codebridge/policy/dist/demo-capabilities.d.ts +4 -0
  185. package/node_modules/@codebridge/policy/dist/demo-capabilities.js +134 -0
  186. package/node_modules/@codebridge/policy/dist/equity-capabilities.d.ts +8 -0
  187. package/node_modules/@codebridge/policy/dist/equity-capabilities.js +35 -0
  188. package/node_modules/@codebridge/policy/dist/index.d.ts +107 -0
  189. package/node_modules/@codebridge/policy/dist/index.js +317 -0
  190. package/node_modules/@codebridge/policy/package.json +17 -0
  191. package/node_modules/@codebridge/project-catalog/dist/index.d.ts +145 -0
  192. package/node_modules/@codebridge/project-catalog/dist/index.js +699 -0
  193. package/node_modules/@codebridge/project-catalog/package.json +18 -0
  194. package/node_modules/@codebridge/router/dist/channel-stream-projector.d.ts +19 -0
  195. package/node_modules/@codebridge/router/dist/channel-stream-projector.js +68 -0
  196. package/node_modules/@codebridge/router/dist/command-help.d.ts +14 -0
  197. package/node_modules/@codebridge/router/dist/command-help.js +151 -0
  198. package/node_modules/@codebridge/router/dist/feishu-stream-presenter.d.ts +18 -0
  199. package/node_modules/@codebridge/router/dist/feishu-stream-presenter.js +193 -0
  200. package/node_modules/@codebridge/router/dist/index.d.ts +9 -0
  201. package/node_modules/@codebridge/router/dist/index.js +9 -0
  202. package/node_modules/@codebridge/router/dist/model-effort.d.ts +5 -0
  203. package/node_modules/@codebridge/router/dist/model-effort.js +33 -0
  204. package/node_modules/@codebridge/router/dist/orchestrator.d.ts +56 -0
  205. package/node_modules/@codebridge/router/dist/orchestrator.js +290 -0
  206. package/node_modules/@codebridge/router/dist/session-list-format.d.ts +19 -0
  207. package/node_modules/@codebridge/router/dist/session-list-format.js +97 -0
  208. package/node_modules/@codebridge/router/dist/session-rotation.d.ts +9 -0
  209. package/node_modules/@codebridge/router/dist/session-rotation.js +31 -0
  210. package/node_modules/@codebridge/router/dist/session-router.d.ts +59 -0
  211. package/node_modules/@codebridge/router/dist/session-router.js +182 -0
  212. package/node_modules/@codebridge/router/dist/slash-commands.d.ts +78 -0
  213. package/node_modules/@codebridge/router/dist/slash-commands.js +874 -0
  214. package/node_modules/@codebridge/router/package.json +18 -0
  215. package/node_modules/@codebridge/run-executor/dist/agent-event-aggregator.d.ts +18 -0
  216. package/node_modules/@codebridge/run-executor/dist/agent-event-aggregator.js +88 -0
  217. package/node_modules/@codebridge/run-executor/dist/index.d.ts +55 -0
  218. package/node_modules/@codebridge/run-executor/dist/index.js +754 -0
  219. package/node_modules/@codebridge/run-executor/dist/run-heartbeat.d.ts +14 -0
  220. package/node_modules/@codebridge/run-executor/dist/run-heartbeat.js +24 -0
  221. package/node_modules/@codebridge/run-executor/package.json +20 -0
  222. package/node_modules/@codebridge/runner-client/dist/index.d.ts +142 -0
  223. package/node_modules/@codebridge/runner-client/dist/index.js +439 -0
  224. package/node_modules/@codebridge/runner-client/package.json +18 -0
  225. package/node_modules/@codebridge/runner-host/dist/cli.d.ts +3 -0
  226. package/node_modules/@codebridge/runner-host/dist/cli.js +58 -0
  227. package/node_modules/@codebridge/runner-host/dist/codex-session-ownership.d.ts +13 -0
  228. package/node_modules/@codebridge/runner-host/dist/codex-session-ownership.js +79 -0
  229. package/node_modules/@codebridge/runner-host/dist/deployment-mcp-server.d.ts +10 -0
  230. package/node_modules/@codebridge/runner-host/dist/deployment-mcp-server.js +54 -0
  231. package/node_modules/@codebridge/runner-host/dist/fcb-script.d.ts +3 -0
  232. package/node_modules/@codebridge/runner-host/dist/fcb-script.js +99 -0
  233. package/node_modules/@codebridge/runner-host/dist/index.d.ts +3 -0
  234. package/node_modules/@codebridge/runner-host/dist/index.js +2 -0
  235. package/node_modules/@codebridge/runner-host/dist/materialize-attachments.d.ts +4 -0
  236. package/node_modules/@codebridge/runner-host/dist/materialize-attachments.js +62 -0
  237. package/node_modules/@codebridge/runner-host/dist/server.d.ts +150 -0
  238. package/node_modules/@codebridge/runner-host/dist/server.js +1295 -0
  239. package/node_modules/@codebridge/runner-host/dist/session-lease.d.ts +12 -0
  240. package/node_modules/@codebridge/runner-host/dist/session-lease.js +146 -0
  241. package/node_modules/@codebridge/runner-host/package.json +26 -0
  242. package/node_modules/@codebridge/session-catalog/dist/index.d.ts +124 -0
  243. package/node_modules/@codebridge/session-catalog/dist/index.js +411 -0
  244. package/node_modules/@codebridge/session-catalog/package.json +17 -0
  245. package/node_modules/@codebridge/session-coordinator/dist/coordinator.d.ts +111 -0
  246. package/node_modules/@codebridge/session-coordinator/dist/coordinator.js +364 -0
  247. package/node_modules/@codebridge/session-coordinator/dist/index.d.ts +5 -0
  248. package/node_modules/@codebridge/session-coordinator/dist/index.js +5 -0
  249. package/node_modules/@codebridge/session-coordinator/dist/lease.d.ts +14 -0
  250. package/node_modules/@codebridge/session-coordinator/dist/lease.js +26 -0
  251. package/node_modules/@codebridge/session-coordinator/dist/queued-claim.d.ts +20 -0
  252. package/node_modules/@codebridge/session-coordinator/dist/queued-claim.js +45 -0
  253. package/node_modules/@codebridge/session-coordinator/dist/recovery.d.ts +31 -0
  254. package/node_modules/@codebridge/session-coordinator/dist/recovery.js +114 -0
  255. package/node_modules/@codebridge/session-coordinator/package.json +17 -0
  256. package/node_modules/@codebridge/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  257. package/node_modules/@codebridge/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  258. package/node_modules/@codebridge/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  259. package/node_modules/@codebridge/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  260. package/node_modules/@codebridge/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  261. package/node_modules/@codebridge/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  262. package/node_modules/@codebridge/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  263. package/node_modules/@codebridge/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  264. package/node_modules/@codebridge/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  265. package/node_modules/@codebridge/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  266. package/node_modules/@codebridge/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  267. package/node_modules/@codebridge/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  268. package/node_modules/@codebridge/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  269. package/node_modules/@codebridge/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  270. package/node_modules/@codebridge/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  271. package/node_modules/@codebridge/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  272. package/node_modules/@codebridge/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  273. package/node_modules/@codebridge/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  274. package/node_modules/@codebridge/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  275. package/node_modules/@codebridge/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  276. package/node_modules/@codebridge/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  277. package/node_modules/@codebridge/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  278. package/node_modules/@codebridge/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  279. package/node_modules/@codebridge/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  280. package/node_modules/@codebridge/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  281. package/node_modules/@codebridge/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  282. package/node_modules/@codebridge/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  283. package/node_modules/@codebridge/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  284. package/node_modules/@codebridge/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  285. package/node_modules/@codebridge/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  286. package/node_modules/@codebridge/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  287. package/node_modules/@codebridge/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  288. package/node_modules/@codebridge/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  289. package/node_modules/@codebridge/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  290. package/node_modules/@codebridge/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  291. package/node_modules/@codebridge/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  292. package/node_modules/@codebridge/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  293. package/node_modules/@codebridge/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  294. package/node_modules/@codebridge/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  295. package/node_modules/@codebridge/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  296. package/node_modules/@codebridge/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  297. package/node_modules/@codebridge/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  298. package/node_modules/@codebridge/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  299. package/node_modules/@codebridge/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  300. package/node_modules/@codebridge/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  301. package/node_modules/@codebridge/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  302. package/node_modules/@codebridge/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  303. package/node_modules/@codebridge/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  304. package/node_modules/@codebridge/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  305. package/node_modules/@codebridge/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  306. package/node_modules/@codebridge/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  307. package/node_modules/@codebridge/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  308. package/node_modules/@codebridge/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  309. package/node_modules/@codebridge/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  310. package/node_modules/@codebridge/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  311. package/node_modules/@codebridge/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  312. package/node_modules/@codebridge/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  313. package/node_modules/@codebridge/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  314. package/node_modules/@codebridge/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  315. package/node_modules/@codebridge/web/dist/assets/abnfDiagram-N423BO3Z-C-JdFv0U.js +1 -0
  316. package/node_modules/@codebridge/web/dist/assets/arc-DsNROjzU.js +1 -0
  317. package/node_modules/@codebridge/web/dist/assets/architecture-TIHT7OUA-ZEBHG2JZ.js +1 -0
  318. package/node_modules/@codebridge/web/dist/assets/architectureDiagram-T3A2C74G-OsrxcwPM.js +36 -0
  319. package/node_modules/@codebridge/web/dist/assets/array-BifhSqXX.js +1 -0
  320. package/node_modules/@codebridge/web/dist/assets/blockDiagram-VBNYF7ZC-DRgfNeNW.js +132 -0
  321. package/node_modules/@codebridge/web/dist/assets/c4Diagram-5PPSVZJV-BtOGKTh8.js +10 -0
  322. package/node_modules/@codebridge/web/dist/assets/channel-MhXyjxUS.js +1 -0
  323. package/node_modules/@codebridge/web/dist/assets/chunk-2GRJ4B5K-Dy1gJ7sY.js +1 -0
  324. package/node_modules/@codebridge/web/dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  325. package/node_modules/@codebridge/web/dist/assets/chunk-4I5QYGJK-1pOLR_SG.js +1 -0
  326. package/node_modules/@codebridge/web/dist/assets/chunk-5RXB4S5H-CP43rgsO.js +231 -0
  327. package/node_modules/@codebridge/web/dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  328. package/node_modules/@codebridge/web/dist/assets/chunk-6Q2QTUOP-Bi3Xrp6W.js +88 -0
  329. package/node_modules/@codebridge/web/dist/assets/chunk-7BUUIJ7U-Bb538aSH.js +1 -0
  330. package/node_modules/@codebridge/web/dist/assets/chunk-7Z6QIM7H-CILAW2Nk.js +10 -0
  331. package/node_modules/@codebridge/web/dist/assets/chunk-GF5L2VYU-CAp09yhq.js +206 -0
  332. package/node_modules/@codebridge/web/dist/assets/chunk-I66GZJ75-B_rJXmNu.js +128 -0
  333. package/node_modules/@codebridge/web/dist/assets/chunk-JQJVKLGR-OVeOJFCx.js +156 -0
  334. package/node_modules/@codebridge/web/dist/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  335. package/node_modules/@codebridge/web/dist/assets/chunk-KBJHAD2P-uaupp0k5.js +1 -0
  336. package/node_modules/@codebridge/web/dist/assets/chunk-KEIR6QF5-BICK3FdT.js +161 -0
  337. package/node_modules/@codebridge/web/dist/assets/chunk-NSK5VX7P-fIHF5wwn.js +2 -0
  338. package/node_modules/@codebridge/web/dist/assets/chunk-QR6OTTB3-DxkJuF2b.js +62 -0
  339. package/node_modules/@codebridge/web/dist/assets/chunk-RYQCIY6F-CC5j3u-X.js +1 -0
  340. package/node_modules/@codebridge/web/dist/assets/chunk-UBXNYLIW-DB35O-6R.js +1 -0
  341. package/node_modules/@codebridge/web/dist/assets/chunk-W5SLKNZC-bkRBsbq-.js +1 -0
  342. package/node_modules/@codebridge/web/dist/assets/chunk-WRU74C26-DwvEoD-1.js +70 -0
  343. package/node_modules/@codebridge/web/dist/assets/chunk-XXDRQBXY-DRyYA-HY.js +1 -0
  344. package/node_modules/@codebridge/web/dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  345. package/node_modules/@codebridge/web/dist/assets/classDiagram-JCYQIIEL-B8r7z8ii.js +1 -0
  346. package/node_modules/@codebridge/web/dist/assets/classDiagram-v2-OCEON4UE-B8r7z8ii.js +1 -0
  347. package/node_modules/@codebridge/web/dist/assets/cose-bilkent-JH36ORCC-CLkwlrX7.js +1 -0
  348. package/node_modules/@codebridge/web/dist/assets/cynefin-VYW2F7L2-C3_Llw02.js +1 -0
  349. package/node_modules/@codebridge/web/dist/assets/cynefinDiagram-MW4NZA55-D5v7UnJy.js +62 -0
  350. package/node_modules/@codebridge/web/dist/assets/cytoscape.esm-B-NFISlW.js +321 -0
  351. package/node_modules/@codebridge/web/dist/assets/dagre-Buvkdvvj.js +1 -0
  352. package/node_modules/@codebridge/web/dist/assets/dagre-VZM6K2ZE-Cr0IibwW.js +4 -0
  353. package/node_modules/@codebridge/web/dist/assets/defaultLocale-BFoDCU3G.js +1 -0
  354. package/node_modules/@codebridge/web/dist/assets/diagram-7IWD3JNH-CpQXDIzA.js +30 -0
  355. package/node_modules/@codebridge/web/dist/assets/diagram-B4RE2ZJO-VaOkH0Ya.js +3 -0
  356. package/node_modules/@codebridge/web/dist/assets/diagram-LBJQPF4R-D0iXyNks.js +24 -0
  357. package/node_modules/@codebridge/web/dist/assets/diagram-Q27KOJAE-CtqYk01P.js +24 -0
  358. package/node_modules/@codebridge/web/dist/assets/diagram-UB23O5K3-CFnd3H1_.js +41 -0
  359. package/node_modules/@codebridge/web/dist/assets/dist-D2L7nRdk.js +1 -0
  360. package/node_modules/@codebridge/web/dist/assets/ebnfDiagram-BXEA7PRR-B0GIbJYt.js +1 -0
  361. package/node_modules/@codebridge/web/dist/assets/erDiagram-JOGREHBK-BApaLGVA.js +85 -0
  362. package/node_modules/@codebridge/web/dist/assets/eventmodeling-45OFAUF4-DqGGjcld.js +1 -0
  363. package/node_modules/@codebridge/web/dist/assets/flowDiagram-UKHOOZJN-I_qlizLH.js +1 -0
  364. package/node_modules/@codebridge/web/dist/assets/ganttDiagram-PKOTCBZU-B-QZ-J82.js +292 -0
  365. package/node_modules/@codebridge/web/dist/assets/gitGraph-TEB2WS4Q-DK2SJ2Ne.js +1 -0
  366. package/node_modules/@codebridge/web/dist/assets/gitGraphDiagram-DS77QQ5N-B6Z-pu0D.js +106 -0
  367. package/node_modules/@codebridge/web/dist/assets/graphlib-DS17s2tU.js +1 -0
  368. package/node_modules/@codebridge/web/dist/assets/index-8BzpyygS.js +559 -0
  369. package/node_modules/@codebridge/web/dist/assets/index-Bzaz89LE.css +1 -0
  370. package/node_modules/@codebridge/web/dist/assets/info-DKCQHKI2-CGWxt_Py.js +1 -0
  371. package/node_modules/@codebridge/web/dist/assets/infoDiagram-6WML65LV-77XjrPZs.js +2 -0
  372. package/node_modules/@codebridge/web/dist/assets/init-C-OQMol4.js +1 -0
  373. package/node_modules/@codebridge/web/dist/assets/ishikawaDiagram-WSZJBQD7-P1bZAz2x.js +70 -0
  374. package/node_modules/@codebridge/web/dist/assets/journeyDiagram-NVQOT4AX-C4rwMcBY.js +139 -0
  375. package/node_modules/@codebridge/web/dist/assets/kanban-definition-27J2QSJJ-mtw4a9bc.js +89 -0
  376. package/node_modules/@codebridge/web/dist/assets/line-DP4RkYqm.js +1 -0
  377. package/node_modules/@codebridge/web/dist/assets/linear-DMg3PPio.js +1 -0
  378. package/node_modules/@codebridge/web/dist/assets/map-BaFkSB1l.js +1 -0
  379. package/node_modules/@codebridge/web/dist/assets/mermaid-parser.core-HY84kHw1.js +7 -0
  380. package/node_modules/@codebridge/web/dist/assets/mermaid.core-DdgCdsnM.js +42 -0
  381. package/node_modules/@codebridge/web/dist/assets/mindmap-definition-FAOFIHXS-Cw1EnbhZ.js +96 -0
  382. package/node_modules/@codebridge/web/dist/assets/ordinal-BDEzSJ7C.js +1 -0
  383. package/node_modules/@codebridge/web/dist/assets/packet-7NZHBO7P-CEbrbJH3.js +1 -0
  384. package/node_modules/@codebridge/web/dist/assets/path-fybaL0A-.js +1 -0
  385. package/node_modules/@codebridge/web/dist/assets/pegDiagram-VL7TDLO6-CEc1Gedb.js +1 -0
  386. package/node_modules/@codebridge/web/dist/assets/pie-RZYD4A2V-DPXVs-IW.js +1 -0
  387. package/node_modules/@codebridge/web/dist/assets/pieDiagram-7S7Q4E2Y-hoQeGMFH.js +39 -0
  388. package/node_modules/@codebridge/web/dist/assets/quadrantDiagram-CIZ2JOQS-C-Nmxx0f.js +7 -0
  389. package/node_modules/@codebridge/web/dist/assets/radar-I7S5WNFK-BVd3X3Pd.js +1 -0
  390. package/node_modules/@codebridge/web/dist/assets/railroad-3IZDKUUU-CxLxzr_v.js +1 -0
  391. package/node_modules/@codebridge/web/dist/assets/railroad-abnf-AHOZXSZD-MA1zPI84.js +1 -0
  392. package/node_modules/@codebridge/web/dist/assets/railroad-ebnf-EBAXGLYW-Bqug_umD.js +1 -0
  393. package/node_modules/@codebridge/web/dist/assets/railroad-peg-LSFZ7HO6-DRcRFwpq.js +1 -0
  394. package/node_modules/@codebridge/web/dist/assets/railroadDiagram-AXF67PYL-B007ZkL9.js +1 -0
  395. package/node_modules/@codebridge/web/dist/assets/requirementDiagram-LRYGKXZP-LrTCcEi5.js +84 -0
  396. package/node_modules/@codebridge/web/dist/assets/rough.esm-Dy-Kn_BL.js +1 -0
  397. package/node_modules/@codebridge/web/dist/assets/sankeyDiagram-W5VNT64P-Ch4mzHck.js +40 -0
  398. package/node_modules/@codebridge/web/dist/assets/sequenceDiagram-SI44F4Z6-CHg4OzLX.js +162 -0
  399. package/node_modules/@codebridge/web/dist/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +1 -0
  400. package/node_modules/@codebridge/web/dist/assets/src-BrO6_odD.js +1 -0
  401. package/node_modules/@codebridge/web/dist/assets/stateDiagram-OKZ733FA-7cVkr5nR.js +1 -0
  402. package/node_modules/@codebridge/web/dist/assets/stateDiagram-v2-UEYNNEHI-CTy_mAXb.js +1 -0
  403. package/node_modules/@codebridge/web/dist/assets/swimlanes-SLNWSIFB-BwSVF5qy.js +2 -0
  404. package/node_modules/@codebridge/web/dist/assets/swimlanesDiagram-ULZ7WXOC-BBQnfZ1j.js +8 -0
  405. package/node_modules/@codebridge/web/dist/assets/timeline-definition-Z64GVDOM-BaHEkVDV.js +120 -0
  406. package/node_modules/@codebridge/web/dist/assets/treeView-QDETBFTQ-CF0kLN62.js +1 -0
  407. package/node_modules/@codebridge/web/dist/assets/treemap-6X3UGDF4-BB8A8uux.js +1 -0
  408. package/node_modules/@codebridge/web/dist/assets/vennDiagram-T6HMQDX7-BFK12Iro.js +34 -0
  409. package/node_modules/@codebridge/web/dist/assets/wardley-OPB4EBWU-C_3y61zk.js +1 -0
  410. package/node_modules/@codebridge/web/dist/assets/wardleyDiagram-T6FBY63Y-W2oGu4WK.js +78 -0
  411. package/node_modules/@codebridge/web/dist/assets/xychartDiagram-ELKLHX3M-BiVRnbvz.js +7 -0
  412. package/node_modules/@codebridge/web/dist/brand/agent-logo-carbon.svg +1 -0
  413. package/node_modules/@codebridge/web/dist/brand/agent-logo.svg +1 -0
  414. package/node_modules/@codebridge/web/dist/brand/agnet-logo-carbon.svg +1 -0
  415. package/node_modules/@codebridge/web/dist/brand/agnet-logo.svg +1 -0
  416. package/node_modules/@codebridge/web/dist/brand/agnet-mark-carbon.svg +1 -0
  417. package/node_modules/@codebridge/web/dist/brand/agnet-mark.svg +1 -0
  418. package/node_modules/@codebridge/web/dist/fonts/CommitMono-400-Regular.otf +0 -0
  419. package/node_modules/@codebridge/web/dist/fonts/CommitMono-700-Regular.otf +0 -0
  420. package/node_modules/@codebridge/web/dist/fonts/CommitMono-OFL.txt +21 -0
  421. package/node_modules/@codebridge/web/dist/fonts/DepartureMono-OFL.txt +21 -0
  422. package/node_modules/@codebridge/web/dist/fonts/DepartureMono-Regular.woff2 +0 -0
  423. package/node_modules/@codebridge/web/dist/index.html +25 -0
  424. package/node_modules/@codebridge/web/package.json +7 -0
  425. package/node_modules/@codebridge/work-items/dist/index.d.ts +371 -0
  426. package/node_modules/@codebridge/work-items/dist/index.js +1784 -0
  427. package/node_modules/@codebridge/work-items/dist/session-projector.d.ts +4 -0
  428. package/node_modules/@codebridge/work-items/dist/session-projector.js +506 -0
  429. package/node_modules/@codebridge/work-items/dist/session-runtime.d.ts +274 -0
  430. package/node_modules/@codebridge/work-items/dist/session-runtime.js +1103 -0
  431. package/node_modules/@codebridge/work-items/dist/session-schema.d.ts +9 -0
  432. package/node_modules/@codebridge/work-items/dist/session-schema.js +292 -0
  433. package/node_modules/@codebridge/work-items/package.json +20 -0
  434. package/package.json +75 -4
@@ -0,0 +1,1295 @@
1
+ import { supportedAgentSetupManifests } from "@codebridge/agent-registry";
2
+ import { AcpSessionPool, AgentSetupService, BackendRegistry, closePiSession, deleteAcpSession, deletePiSession, forkPiSession, listAcpConfigOptions, listAcpSessions, listCodexSkillCommands, listPiCommands, listPiConfigOptions, listPiSessions, loadAcpSessionHistory, loadClaudeSessionHistory, loadCodexSessionHistory, loadPiSessionHistory, PI_PROVIDER_PRESETS, readPiProviders, runAcpSession, runPiSession, SKILL_AGENT_IDS, SkillControlPlane, testProviderConnection, validateProviders, writePiProviders, } from "@codebridge/backends";
3
+ import { DEFAULT_DATA_DIR, VERSION } from "@codebridge/core";
4
+ import { Hono } from "hono";
5
+ import { execFile } from "node:child_process";
6
+ import crypto from "node:crypto";
7
+ import fs from "node:fs";
8
+ import os from "node:os";
9
+ import path from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ import { promisify } from "node:util";
12
+ import { inspectForeignCodexSessionOwners } from "./codex-session-ownership.js";
13
+ import { createDeploymentMcpServerConfig } from "./deployment-mcp-server.js";
14
+ import { writeFcbScript } from "./fcb-script.js";
15
+ import { cleanupAttachments, materializeAttachments } from "./materialize-attachments.js";
16
+ import { SessionLeaseStore } from "./session-lease.js";
17
+ /** doctor 的认证探测:BackendProfile.type → AgentSetupService 的 agentId 命名空间 */
18
+ const AGENT_ID_BY_BACKEND_TYPE = {
19
+ "claude-code": "claude",
20
+ codex: "codex",
21
+ "cursor-cli": "cursor",
22
+ "generic-spawn": "opencode",
23
+ };
24
+ /** prompt_feishu:权限请求等待用户回复的超时(到点自动拒绝)。需小于 noOutput 超时。 */
25
+ const PERMISSION_PROMPT_TIMEOUT_MS = 8 * 60 * 1000;
26
+ const execFileAsync = promisify(execFile);
27
+ const CODEX_BUILTIN_COMMANDS = [
28
+ { name: "plan", description: "Turn plan mode on." },
29
+ { name: "mcp", description: "List configured Model Context Protocol (MCP) tools." },
30
+ { name: "skills", description: "List available skills." },
31
+ { name: "status", description: "Display session configuration and token usage." },
32
+ { name: "review", description: "Review uncommitted changes, or review with custom instructions.", input: { hint: "optional review instructions" } },
33
+ { name: "review-branch", description: "Review changes relative to a base branch.", input: { hint: "branch name" } },
34
+ { name: "review-commit", description: "Review a specific commit.", input: { hint: "commit sha" } },
35
+ { name: "compact", description: "Summarize conversation to avoid hitting the context limit." },
36
+ { name: "goal", description: "Set a goal to keep pursuing.", input: { hint: "[<objective>|clear|pause|resume]" } },
37
+ { name: "logout", description: "Sign out of Codex. This option is available when you are logged in via ChatGPT." },
38
+ ];
39
+ async function pickNativeDirectory() {
40
+ if (process.platform !== "darwin") {
41
+ throw new Error("当前系统不支持原生目录选择器");
42
+ }
43
+ try {
44
+ const { stdout } = await execFileAsync("/usr/bin/osascript", [
45
+ "-e",
46
+ 'POSIX path of (choose folder with prompt "选择要加入当前 Session 的目录")',
47
+ ]);
48
+ return stdout.trim() || null;
49
+ }
50
+ catch (error) {
51
+ const message = error instanceof Error ? error.message : String(error);
52
+ if (message.includes("User canceled") || message.includes("-128"))
53
+ return null;
54
+ throw error;
55
+ }
56
+ }
57
+ function resolveDoctorCwd(config) {
58
+ const home = os.homedir();
59
+ const raw = config.workspaces?.default ??
60
+ config.workspaces?.root ??
61
+ path.join(home, "Projects");
62
+ return raw.startsWith("~") ? path.join(home, raw.slice(1)) : raw;
63
+ }
64
+ function resolveRunCwd(raw) {
65
+ if (!path.isAbsolute(raw)) {
66
+ return { error: `工作目录必须使用绝对路径: ${raw}` };
67
+ }
68
+ try {
69
+ const cwd = fs.realpathSync(raw);
70
+ if (!fs.statSync(cwd).isDirectory()) {
71
+ return { error: `工作目录不是目录: ${raw}` };
72
+ }
73
+ return { cwd };
74
+ }
75
+ catch {
76
+ return { error: `工作目录不存在或无法访问: ${raw}` };
77
+ }
78
+ }
79
+ function resolveAdditionalDirectories(raw, cwd) {
80
+ if (!raw?.length)
81
+ return {};
82
+ const directories = [];
83
+ for (const value of raw) {
84
+ if (!path.isAbsolute(value)) {
85
+ return { error: `附加目录必须使用绝对路径: ${value}` };
86
+ }
87
+ const resolved = resolveRunCwd(value);
88
+ if ("error" in resolved) {
89
+ return { error: `附加目录 ${value} 无效:${resolved.error}` };
90
+ }
91
+ if (resolved.cwd !== cwd && !directories.includes(resolved.cwd)) {
92
+ directories.push(resolved.cwd);
93
+ }
94
+ }
95
+ return directories.length ? { directories } : {};
96
+ }
97
+ export class RunnerHost {
98
+ options;
99
+ registry = new BackendRegistry();
100
+ active = new Map();
101
+ runLifecycles = new Map();
102
+ maxConcurrent;
103
+ dataDir;
104
+ acpPermissionPolicy;
105
+ acpRunOptions;
106
+ fcbBinDir;
107
+ sessionLeases;
108
+ inspectSessionOwners;
109
+ /** 长驻 ACP 会话池:同会话消息复用适配器进程(kill switch: runnerHost.acpSessionPool) */
110
+ sessionPool;
111
+ agentSetup;
112
+ skillControlPlane;
113
+ /**
114
+ * prompt_feishu:每个 run 的挂起权限请求队列(FIFO)。claude 通常一次只挂一个,
115
+ * 但并行工具可能并发请求——用队列而非单槽,避免互相覆盖、/approve 只回给最早的那个。
116
+ */
117
+ pendingPermissions = new Map();
118
+ deploymentMcpServerPath;
119
+ constructor(options) {
120
+ this.options = options;
121
+ this.maxConcurrent = options.maxConcurrentRuns ?? 4;
122
+ this.dataDir = options.dataDir ?? DEFAULT_DATA_DIR;
123
+ this.deploymentMcpServerPath = options.deploymentMcpServerPath
124
+ ?? fileURLToPath(new URL("./deployment-mcp-server.js", import.meta.url));
125
+ this.skillControlPlane = options.skillControlPlane ?? new SkillControlPlane({
126
+ dataDir: this.dataDir,
127
+ });
128
+ this.acpPermissionPolicy =
129
+ options.config.runnerHost?.acpPermissionPolicy ?? "auto_allow";
130
+ const rh = options.config.runnerHost;
131
+ this.acpRunOptions = {
132
+ promptTimeoutMs: rh?.acpPromptTimeoutMs,
133
+ noOutputTimeoutMs: rh?.acpNoOutputTimeoutMs,
134
+ stallTimeoutMs: rh?.acpStallTimeoutMs,
135
+ drainBackgroundWork: rh?.acpDrainBackgroundWork,
136
+ postStopProbeMs: rh?.acpPostStopProbeMs,
137
+ postStopQuietMs: rh?.acpPostStopQuietMs,
138
+ postStopMaxMs: rh?.acpPostStopMaxMs,
139
+ };
140
+ this.sessionPool = new AcpSessionPool({
141
+ enabled: rh?.acpSessionPool ?? true,
142
+ idleMs: rh?.acpSessionIdleMs ?? 10 * 60_000,
143
+ maxPooled: rh?.acpSessionPoolMax ?? 4,
144
+ });
145
+ this.agentSetup = options.agentSetupService ?? new AgentSetupService({
146
+ manifests: supportedAgentSetupManifests,
147
+ });
148
+ this.sessionLeases = new SessionLeaseStore(this.dataDir);
149
+ this.inspectSessionOwners =
150
+ options.inspectSessionOwners ?? inspectForeignCodexSessionOwners;
151
+ for (const [id, profile] of Object.entries(options.config.backends)) {
152
+ this.registry.register(id, profile);
153
+ }
154
+ // fcb 写失败不阻塞 Runner 启动,只是 Agent 内没有 fcb 可用
155
+ this.fcbBinDir = writeFcbScript(this.dataDir).catch(() => undefined);
156
+ }
157
+ /** Agent 子进程环境:fcb 出站 API 凭据 + 把 fcb 挂到 PATH */
158
+ async buildAgentEnv(request) {
159
+ const env = {
160
+ FCB_CHAT_ID: request.sessionKey.chatId,
161
+ FCB_API: `http://127.0.0.1:${this.options.config.bridge?.apiPort ?? 19790}`,
162
+ FCB_RUN_ID: request.runId,
163
+ FCB_TOKEN: this.options.token,
164
+ };
165
+ if (request.sessionKey.topicId) {
166
+ env.FCB_TOPIC_ID = request.sessionKey.topicId;
167
+ }
168
+ const binDir = await this.fcbBinDir;
169
+ if (binDir) {
170
+ env.PATH = `${binDir}:${process.env.PATH ?? ""}`;
171
+ }
172
+ return env;
173
+ }
174
+ get registryIds() {
175
+ return this.registry.ids();
176
+ }
177
+ async doctor() {
178
+ const backend = await this.registry.doctor(resolveDoctorCwd(this.options.config));
179
+ const authProbes = await this.probeConfiguredBackendAuth();
180
+ return {
181
+ version: VERSION,
182
+ backends: this.registry.ids(),
183
+ authProbes,
184
+ ...backend,
185
+ };
186
+ }
187
+ /**
188
+ * 每个已配置的 ACP 后端各探一次登录状态,纯展示用:探测失败/未知也照样返回,绝不让
189
+ * doctor 整体失败,调用方也绝不能拿这个当拦截运行的硬门槛(见 AgentAuthProbe 注释)。
190
+ */
191
+ async probeConfiguredBackendAuth() {
192
+ const results = {};
193
+ for (const [backendId, profile] of Object.entries(this.options.config.backends)) {
194
+ const agentId = AGENT_ID_BY_BACKEND_TYPE[profile.type];
195
+ if (!agentId)
196
+ continue;
197
+ try {
198
+ results[backendId] = await this.agentSetup.probeAuth(agentId);
199
+ }
200
+ catch (err) {
201
+ results[backendId] = {
202
+ ok: false,
203
+ advisory: true,
204
+ message: err instanceof Error ? err.message : String(err),
205
+ };
206
+ }
207
+ }
208
+ return results;
209
+ }
210
+ async listAgentSetup() {
211
+ return this.agentSetup.list();
212
+ }
213
+ async detectAgent(agentId) {
214
+ const setup = await this.agentSetup.detect(agentId);
215
+ return { agentId, ...setup };
216
+ }
217
+ async installAgent(agentId, strategyId) {
218
+ return this.agentSetup.install(agentId, strategyId);
219
+ }
220
+ cancel(runId) {
221
+ const run = this.active.get(runId);
222
+ if (!run)
223
+ return false;
224
+ const lifecycle = this.runLifecycles.get(runId);
225
+ if (lifecycle)
226
+ lifecycle.cancelRequested = true;
227
+ run.aborted = true;
228
+ run.cancel();
229
+ return true;
230
+ }
231
+ async cancelAndWait(runId) {
232
+ const lifecycle = this.runLifecycles.get(runId) ?? this.createRunLifecycle(runId);
233
+ if (lifecycle.completed)
234
+ return true;
235
+ lifecycle.cancelRequested = true;
236
+ this.cancel(runId);
237
+ if (!lifecycle.started) {
238
+ lifecycle.expiry = setTimeout(() => {
239
+ if (this.runLifecycles.get(runId) === lifecycle && !lifecycle.started) {
240
+ this.runLifecycles.delete(runId);
241
+ }
242
+ }, 60_000);
243
+ lifecycle.expiry.unref();
244
+ return true;
245
+ }
246
+ await lifecycle.finished;
247
+ return true;
248
+ }
249
+ createRunLifecycle(runId) {
250
+ let finish;
251
+ const finished = new Promise((resolve) => {
252
+ finish = resolve;
253
+ });
254
+ const lifecycle = {
255
+ started: false,
256
+ completed: false,
257
+ cancelRequested: false,
258
+ finished,
259
+ finish,
260
+ };
261
+ this.runLifecycles.set(runId, lifecycle);
262
+ return lifecycle;
263
+ }
264
+ async steer(runId, prompt) {
265
+ const run = this.active.get(runId);
266
+ if (!run)
267
+ return { ok: false, error: "当前没有正在运行的任务" };
268
+ if (!run.steer)
269
+ return { ok: false, error: "当前 ACP Agent 未声明 steering 支持" };
270
+ try {
271
+ const response = await run.steer(prompt);
272
+ const outcome = response &&
273
+ typeof response === "object" &&
274
+ "outcome" in response &&
275
+ typeof response.outcome === "string"
276
+ ? response.outcome
277
+ : "accepted";
278
+ return { ok: true, outcome };
279
+ }
280
+ catch (err) {
281
+ return {
282
+ ok: false,
283
+ error: err instanceof Error ? err.message : String(err),
284
+ };
285
+ }
286
+ }
287
+ async listSessions(backendId, cwd, options) {
288
+ const profile = this.options.config.backends[backendId];
289
+ if (!profile) {
290
+ return { sessions: [], error: `Unknown backend: ${backendId}` };
291
+ }
292
+ const resolvedCwd = resolveRunCwd(cwd);
293
+ if ("error" in resolvedCwd) {
294
+ return { sessions: [], error: resolvedCwd.error };
295
+ }
296
+ cwd = resolvedCwd.cwd;
297
+ try {
298
+ const sessions = profile.type === "pi-sdk"
299
+ ? await listPiSessions(backendId, cwd, {
300
+ limit: options?.limit ?? 20,
301
+ })
302
+ : await listAcpSessions(backendId, profile, cwd, {
303
+ limit: options?.limit ?? 20,
304
+ all: options?.all ?? false,
305
+ });
306
+ return { sessions };
307
+ }
308
+ catch (err) {
309
+ const message = err instanceof Error ? err.message : String(err);
310
+ return {
311
+ sessions: [],
312
+ error: `${profile.type === "pi-sdk" ? "Pi session/list" : "ACP session/list"} failed for ${backendId}: ${message}`,
313
+ };
314
+ }
315
+ }
316
+ async loadSessionHistory(backendId, rawCwd, sessionId, additionalDirectories) {
317
+ const profile = this.options.config.backends[backendId];
318
+ if (!profile)
319
+ throw new Error(`Unknown backend: ${backendId}`);
320
+ const resolvedCwd = resolveRunCwd(rawCwd);
321
+ if ("error" in resolvedCwd)
322
+ throw new Error(resolvedCwd.error);
323
+ const resolvedDirectories = resolveAdditionalDirectories(additionalDirectories, resolvedCwd.cwd);
324
+ if ("error" in resolvedDirectories)
325
+ throw new Error(resolvedDirectories.error);
326
+ if (profile.type === "pi-sdk") {
327
+ return loadPiSessionHistory(resolvedCwd.cwd, sessionId);
328
+ }
329
+ if (profile.type === "codex") {
330
+ return loadCodexSessionHistory(sessionId);
331
+ }
332
+ try {
333
+ const history = await loadAcpSessionHistory(backendId, profile, resolvedCwd.cwd, sessionId, {
334
+ additionalDirectories: resolvedDirectories.directories,
335
+ });
336
+ if (history.length || profile.type !== "claude-code")
337
+ return history;
338
+ }
339
+ catch (error) {
340
+ if (profile.type !== "claude-code")
341
+ throw error;
342
+ }
343
+ return loadClaudeSessionHistory(resolvedCwd.cwd, sessionId);
344
+ }
345
+ async authorizeDirectory(rawPath) {
346
+ if (!path.isAbsolute(rawPath)) {
347
+ return { ok: false, error: `工作目录必须使用绝对路径: ${rawPath}` };
348
+ }
349
+ const candidate = path.resolve(rawPath);
350
+ try {
351
+ const handle = await fs.promises.opendir(candidate);
352
+ await handle.close();
353
+ return { ok: true, path: await fs.promises.realpath(candidate) };
354
+ }
355
+ catch (err) {
356
+ const code = err.code;
357
+ if (code === "EACCES" || code === "EPERM") {
358
+ return {
359
+ ok: false,
360
+ path: candidate,
361
+ error: `Runner 尚未获得目录访问权限:${candidate}`,
362
+ };
363
+ }
364
+ return {
365
+ ok: false,
366
+ error: `Runner 无法访问目录 ${candidate}:${err instanceof Error ? err.message : String(err)}`,
367
+ };
368
+ }
369
+ }
370
+ async listDirectory(rawRoot, relativePath = "") {
371
+ const resolvedRoot = resolveRunCwd(rawRoot);
372
+ if ("error" in resolvedRoot)
373
+ return { ok: false, error: resolvedRoot.error };
374
+ const target = path.resolve(resolvedRoot.cwd, relativePath || ".");
375
+ const relativeTarget = path.relative(resolvedRoot.cwd, target);
376
+ if (relativeTarget === ".." || relativeTarget.startsWith(`..${path.sep}`) || path.isAbsolute(relativeTarget)) {
377
+ return { ok: false, error: "目录必须位于当前 Workspace 内" };
378
+ }
379
+ try {
380
+ const canonicalTarget = await fs.promises.realpath(target);
381
+ const canonicalRelative = path.relative(resolvedRoot.cwd, canonicalTarget);
382
+ if (canonicalRelative === ".." || canonicalRelative.startsWith(`..${path.sep}`) || path.isAbsolute(canonicalRelative)) {
383
+ return { ok: false, error: "目录必须位于当前 Workspace 内" };
384
+ }
385
+ const entries = (await fs.promises.readdir(canonicalTarget, { withFileTypes: true }))
386
+ .filter((entry) => entry.name !== ".git" && !entry.isSymbolicLink())
387
+ .map((entry) => {
388
+ const absolutePath = path.join(canonicalTarget, entry.name);
389
+ return {
390
+ name: entry.name,
391
+ path: path.relative(resolvedRoot.cwd, absolutePath),
392
+ absolutePath,
393
+ kind: entry.isDirectory() ? "directory" : "file",
394
+ };
395
+ })
396
+ .sort((left, right) => left.kind === right.kind
397
+ ? left.name.localeCompare(right.name)
398
+ : left.kind === "directory" ? -1 : 1)
399
+ .slice(0, 200);
400
+ return {
401
+ ok: true,
402
+ root: resolvedRoot.cwd,
403
+ path: canonicalTarget,
404
+ relativePath: canonicalRelative,
405
+ entries,
406
+ };
407
+ }
408
+ catch (error) {
409
+ return {
410
+ ok: false,
411
+ error: `Runner 无法读取目录:${error instanceof Error ? error.message : String(error)}`,
412
+ };
413
+ }
414
+ }
415
+ async pickDirectory() {
416
+ try {
417
+ const selected = await (this.options.directoryPicker ?? pickNativeDirectory)();
418
+ if (!selected)
419
+ return { ok: true, cancelled: true };
420
+ return this.authorizeDirectory(selected);
421
+ }
422
+ catch (error) {
423
+ return {
424
+ ok: false,
425
+ error: error instanceof Error ? error.message : String(error),
426
+ };
427
+ }
428
+ }
429
+ async closeSession(backendId, cwd, sessionId) {
430
+ return this.manageSession("close", backendId, cwd, sessionId);
431
+ }
432
+ async deleteSession(backendId, cwd, sessionId) {
433
+ return this.manageSession("delete", backendId, cwd, sessionId);
434
+ }
435
+ async forkSession(backendId, cwd, sessionId, targetCwd) {
436
+ if ([...this.active.values()].some((run) => run.sessionId === sessionId)) {
437
+ return { ok: false, error: `Session ${sessionId} 正在运行,请先停止后重试` };
438
+ }
439
+ const profile = this.options.config.backends[backendId];
440
+ if (!profile)
441
+ return { ok: false, error: `Unknown backend: ${backendId}` };
442
+ const source = resolveRunCwd(cwd);
443
+ if ("error" in source)
444
+ return { ok: false, error: source.error };
445
+ const target = resolveRunCwd(targetCwd);
446
+ if ("error" in target)
447
+ return { ok: false, error: target.error };
448
+ if (profile.type !== "pi-sdk") {
449
+ return { ok: false, error: `${backendId} 未声明 Session fork 能力` };
450
+ }
451
+ try {
452
+ return await (this.options.piSessionForker ?? forkPiSession)(source.cwd, sessionId, target.cwd);
453
+ }
454
+ catch (error) {
455
+ return {
456
+ ok: false,
457
+ error: `Pi session/fork failed for ${backendId}: ${error instanceof Error ? error.message : String(error)}`,
458
+ };
459
+ }
460
+ }
461
+ async manageSession(action, backendId, cwd, sessionId) {
462
+ if ([...this.active.values()].some((run) => run.sessionId === sessionId)) {
463
+ return {
464
+ ok: false,
465
+ error: `ACP session ${sessionId} 正在运行,请先 /stop 后重试`,
466
+ };
467
+ }
468
+ const profile = this.options.config.backends[backendId];
469
+ if (!profile)
470
+ return { ok: false, error: `Unknown backend: ${backendId}` };
471
+ const resolvedCwd = resolveRunCwd(cwd);
472
+ if ("error" in resolvedCwd)
473
+ return { ok: false, error: resolvedCwd.error };
474
+ try {
475
+ if (action === "close") {
476
+ if (profile.type === "pi-sdk") {
477
+ return closePiSession(resolvedCwd.cwd, sessionId);
478
+ }
479
+ const result = await this.sessionPool.close(sessionId);
480
+ if (result.error === "not_owned") {
481
+ return {
482
+ ok: false,
483
+ error: "Runner 当前未持有该 ACP session;历史 session 请使用 /session delete",
484
+ };
485
+ }
486
+ if (!result.ok) {
487
+ return {
488
+ ok: false,
489
+ error: `ACP session/close failed for ${backendId}: ${result.error ?? "未知错误"}`,
490
+ };
491
+ }
492
+ return result;
493
+ }
494
+ if (profile.type === "pi-sdk") {
495
+ return deletePiSession(resolvedCwd.cwd, sessionId);
496
+ }
497
+ await deleteAcpSession(profile, resolvedCwd.cwd, sessionId);
498
+ this.sessionPool.remove(sessionId);
499
+ return { ok: true };
500
+ }
501
+ catch (err) {
502
+ const message = err instanceof Error ? err.message : String(err);
503
+ return {
504
+ ok: false,
505
+ error: `${profile.type === "pi-sdk" ? "Pi session" : "ACP session"}/${action} failed for ${backendId}: ${message}`,
506
+ };
507
+ }
508
+ }
509
+ /** /model 动态列表:拉取 ACP 适配器 advertise 的会话配置项 */
510
+ async listConfigOptions(backendId, cwd, model) {
511
+ const profile = this.options.config.backends[backendId];
512
+ if (!profile) {
513
+ return { options: [], error: `Unknown backend: ${backendId}` };
514
+ }
515
+ const resolvedCwd = resolveRunCwd(cwd);
516
+ if ("error" in resolvedCwd) {
517
+ return { options: [], error: resolvedCwd.error };
518
+ }
519
+ cwd = resolvedCwd.cwd;
520
+ try {
521
+ if (profile.type === "pi-sdk") {
522
+ return { options: await listPiConfigOptions(undefined, model) };
523
+ }
524
+ return { options: await listAcpConfigOptions(profile, cwd) };
525
+ }
526
+ catch (err) {
527
+ const message = err instanceof Error ? err.message : String(err);
528
+ return {
529
+ options: [],
530
+ error: `ACP config options failed for ${backendId}: ${message}`,
531
+ };
532
+ }
533
+ }
534
+ async listCommands(backendId, cwd) {
535
+ const profile = this.options.config.backends[backendId];
536
+ if (!profile)
537
+ return { commands: [], error: `Unknown backend: ${backendId}` };
538
+ const resolvedCwd = resolveRunCwd(cwd);
539
+ if ("error" in resolvedCwd)
540
+ return { commands: [], error: resolvedCwd.error };
541
+ if (profile.type === "codex") {
542
+ try {
543
+ const skills = await (this.options.codexSkillLister ?? listCodexSkillCommands)(resolvedCwd.cwd);
544
+ const commands = new Map(CODEX_BUILTIN_COMMANDS.map((command) => [command.name, command]));
545
+ for (const command of skills)
546
+ commands.set(command.name, command);
547
+ return { commands: [...commands.values()] };
548
+ }
549
+ catch (error) {
550
+ return {
551
+ commands: CODEX_BUILTIN_COMMANDS,
552
+ error: `Codex skills failed for ${backendId}: ${error instanceof Error ? error.message : String(error)}`,
553
+ };
554
+ }
555
+ }
556
+ if (profile.type !== "pi-sdk")
557
+ return { commands: [] };
558
+ try {
559
+ return { commands: await listPiCommands(resolvedCwd.cwd) };
560
+ }
561
+ catch (error) {
562
+ return {
563
+ commands: [],
564
+ error: `Pi commands failed for ${backendId}: ${error instanceof Error ? error.message : String(error)}`,
565
+ };
566
+ }
567
+ }
568
+ scanSkills() {
569
+ return this.skillControlPlane.scan();
570
+ }
571
+ addSkillSource(sourcePath) {
572
+ return this.skillControlPlane.addSource(sourcePath);
573
+ }
574
+ previewSkillAdopt(skillId, actorId) {
575
+ return this.skillControlPlane.previewAdopt({ skill_id: skillId, actor_id: actorId });
576
+ }
577
+ previewSkillAssignment(input) {
578
+ return this.skillControlPlane.previewAssignment(input);
579
+ }
580
+ previewSkillGlobalState(skillId, enabled, actorId) {
581
+ return this.skillControlPlane.previewGlobalState({
582
+ skill_id: skillId,
583
+ enabled,
584
+ actor_id: actorId,
585
+ });
586
+ }
587
+ previewSkillUnmanage(skillId, actorId) {
588
+ return this.skillControlPlane.previewUnmanage({ skill_id: skillId, actor_id: actorId });
589
+ }
590
+ applySkillPlan(planId, actorId) {
591
+ return this.skillControlPlane.applyPlan({ plan_id: planId, actor_id: actorId });
592
+ }
593
+ async *executeRun(request) {
594
+ const previous = this.runLifecycles.get(request.runId);
595
+ if (previous?.expiry)
596
+ clearTimeout(previous.expiry);
597
+ const lifecycle = previous && !previous.completed ? previous : this.createRunLifecycle(request.runId);
598
+ lifecycle.started = true;
599
+ if (lifecycle.expiry)
600
+ clearTimeout(lifecycle.expiry);
601
+ try {
602
+ if (lifecycle.cancelRequested)
603
+ return;
604
+ yield* this.executeRunInner(request, lifecycle);
605
+ }
606
+ finally {
607
+ lifecycle.completed = true;
608
+ lifecycle.finish();
609
+ // A consumer may reject a fatal event after this attempt already ended.
610
+ // Remember that completion so its late cancel cannot create a pre-start
611
+ // cancellation tombstone that suppresses a retry with the same Run ID.
612
+ lifecycle.expiry = setTimeout(() => {
613
+ if (this.runLifecycles.get(request.runId) === lifecycle) {
614
+ this.runLifecycles.delete(request.runId);
615
+ }
616
+ }, 60_000);
617
+ lifecycle.expiry.unref();
618
+ }
619
+ }
620
+ async *executeRunInner(request, lifecycle) {
621
+ while (this.active.size >= this.maxConcurrent) {
622
+ if (lifecycle.cancelRequested)
623
+ return;
624
+ await new Promise((r) => setTimeout(r, 100));
625
+ }
626
+ if (lifecycle.cancelRequested)
627
+ return;
628
+ const backendId = request.sessionKey.backendId;
629
+ const profile = this.options.config.backends[backendId];
630
+ if (!profile) {
631
+ yield {
632
+ type: "error",
633
+ message: `Unknown backend: ${backendId}`,
634
+ fatal: true,
635
+ };
636
+ yield { type: "done", exitCode: 1 };
637
+ return;
638
+ }
639
+ const resolvedCwd = resolveRunCwd(request.sessionKey.cwd);
640
+ if ("error" in resolvedCwd) {
641
+ yield { type: "error", message: resolvedCwd.error, fatal: true };
642
+ yield { type: "done", exitCode: 1 };
643
+ return;
644
+ }
645
+ const resolvedAdditional = resolveAdditionalDirectories(request.additionalDirectories, resolvedCwd.cwd);
646
+ if ("error" in resolvedAdditional) {
647
+ yield { type: "error", message: resolvedAdditional.error, fatal: true };
648
+ yield { type: "done", exitCode: 1 };
649
+ return;
650
+ }
651
+ let sessionLease = null;
652
+ if (request.resumeSessionId) {
653
+ const sessionId = request.resumeSessionId;
654
+ if ([...this.active.values()].some((run) => run.sessionId === sessionId)) {
655
+ yield {
656
+ type: "error",
657
+ message: `ACP session ${sessionId} 正在运行;请等待当前任务结束或先 /stop`,
658
+ fatal: true,
659
+ };
660
+ yield { type: "done", exitCode: 1 };
661
+ return;
662
+ }
663
+ sessionLease = await this.sessionLeases.acquire(sessionId, request.runId);
664
+ if (!sessionLease) {
665
+ yield {
666
+ type: "error",
667
+ message: `ACP session ${sessionId} 已被另一个 Runner 任务占用`,
668
+ fatal: true,
669
+ };
670
+ yield { type: "done", exitCode: 1 };
671
+ return;
672
+ }
673
+ }
674
+ let localAttachments = [];
675
+ try {
676
+ if (lifecycle.cancelRequested)
677
+ return;
678
+ if (backendId === "codex" && request.resumeSessionId) {
679
+ const ownerGroup = this.sessionPool.ownerProcessGroupId(request.resumeSessionId);
680
+ const owners = await this.inspectSessionOwners(request.resumeSessionId, new Set(ownerGroup === undefined ? [] : [ownerGroup]));
681
+ if (owners.length > 0) {
682
+ yield {
683
+ type: "error",
684
+ message: `Codex session ${request.resumeSessionId} 正被桌面端/TUI 占用(PID: ${owners.join(", ")});请先在原客户端停止该任务`,
685
+ fatal: true,
686
+ };
687
+ yield { type: "done", exitCode: 1 };
688
+ return;
689
+ }
690
+ }
691
+ if (lifecycle.cancelRequested)
692
+ return;
693
+ localAttachments = await materializeAttachments(this.dataDir, request.runId, request.attachments);
694
+ if (lifecycle.cancelRequested)
695
+ return;
696
+ const ctx = {
697
+ runId: request.runId,
698
+ cwd: resolvedCwd.cwd,
699
+ prompt: request.prompt,
700
+ additionalDirectories: resolvedAdditional.directories,
701
+ attachments: localAttachments.length ? localAttachments : undefined,
702
+ resumeSessionId: request.resumeSessionId,
703
+ backendConfig: profile,
704
+ model: request.model,
705
+ effort: request.effort,
706
+ mode: request.mode,
707
+ claudePermissionMode: request.claudePermissionMode,
708
+ acpConfig: request.acpConfig,
709
+ mcpServers: [createDeploymentMcpServerConfig(this.deploymentMcpServerPath, {
710
+ api: `http://127.0.0.1:${this.options.config.bridge?.apiPort ?? 19790}`,
711
+ token: this.options.token,
712
+ runId: request.runId,
713
+ })],
714
+ extraEnv: await this.buildAgentEnv(request),
715
+ };
716
+ if (lifecycle.cancelRequested)
717
+ return;
718
+ if (profile.type === "pi-sdk") {
719
+ yield* this.executePiRun(request.runId, ctx);
720
+ }
721
+ else {
722
+ yield* this.executeAcpRun(request.runId, ctx, sessionLease?.lost);
723
+ }
724
+ }
725
+ finally {
726
+ if (localAttachments.length > 0) {
727
+ await cleanupAttachments(this.dataDir, request.runId);
728
+ }
729
+ await sessionLease?.release();
730
+ }
731
+ }
732
+ async *executeAcpRun(runId, ctx, sessionLockLost) {
733
+ const handleRef = {};
734
+ const activeRun = {
735
+ runId,
736
+ sessionId: ctx.resumeSessionId,
737
+ aborted: false,
738
+ // handleRef 在 runAcpSession 生成器体起始处赋值(首次 next() 即可用)
739
+ cancel: () => handleRef.current?.cancel(),
740
+ steer: async (prompt) => {
741
+ const steer = handleRef.current?.steer;
742
+ if (!steer)
743
+ throw new Error("当前 ACP Agent 未声明 steering 支持或仍在初始化");
744
+ return steer(prompt);
745
+ },
746
+ };
747
+ this.active.set(runId, activeRun);
748
+ let lockLostError;
749
+ let runFinished = false;
750
+ void sessionLockLost?.then((error) => {
751
+ if (runFinished)
752
+ return;
753
+ lockLostError = error;
754
+ activeRun.aborted = true;
755
+ activeRun.cancel();
756
+ });
757
+ // prompt_feishu 权限模式:权限请求经带外队列进 SSE,等 /approve /deny 或超时拒绝
758
+ const oobEvents = [];
759
+ const removePending = (requestId) => {
760
+ const queue = this.pendingPermissions.get(runId);
761
+ if (!queue)
762
+ return;
763
+ const idx = queue.findIndex((p) => p.requestId === requestId);
764
+ if (idx >= 0)
765
+ queue.splice(idx, 1);
766
+ if (queue.length === 0)
767
+ this.pendingPermissions.delete(runId);
768
+ };
769
+ const requestDecision = this.acpPermissionPolicy === "prompt_feishu"
770
+ ? (info) => new Promise((resolve) => {
771
+ const requestId = crypto.randomUUID();
772
+ const timer = setTimeout(() => {
773
+ removePending(requestId); // 只摘自己,不动同 run 的其它挂起请求
774
+ oobEvents.push({
775
+ type: "error",
776
+ message: `权限请求「${info.title}」超过 ${Math.round(PERMISSION_PROMPT_TIMEOUT_MS / 60000)} 分钟未回复,已自动拒绝。`,
777
+ fatal: false,
778
+ });
779
+ resolve(false);
780
+ }, PERMISSION_PROMPT_TIMEOUT_MS);
781
+ timer.unref();
782
+ const queue = this.pendingPermissions.get(runId) ?? [];
783
+ queue.push({
784
+ requestId,
785
+ resolve: (approve) => {
786
+ clearTimeout(timer);
787
+ removePending(requestId);
788
+ resolve(approve);
789
+ },
790
+ });
791
+ this.pendingPermissions.set(runId, queue);
792
+ oobEvents.push({
793
+ type: "permission_request",
794
+ requestId,
795
+ title: info.title,
796
+ });
797
+ })
798
+ : undefined;
799
+ let exitCode = 0;
800
+ try {
801
+ for await (const event of runAcpSession(ctx, {
802
+ permissionPolicy: this.acpPermissionPolicy,
803
+ isAborted: () => activeRun.aborted,
804
+ ...this.acpRunOptions,
805
+ sessionPool: this.sessionPool,
806
+ requestDecision,
807
+ pollOutOfBandEvents: () => oobEvents.splice(0),
808
+ }, handleRef)) {
809
+ if (event.type === "session")
810
+ activeRun.sessionId = event.sessionId;
811
+ if (event.type === "error" && event.fatal)
812
+ exitCode = 1;
813
+ yield event;
814
+ }
815
+ }
816
+ catch (err) {
817
+ yield {
818
+ type: "error",
819
+ message: err instanceof Error ? err.message : String(err),
820
+ fatal: true,
821
+ };
822
+ exitCode = 1;
823
+ }
824
+ finally {
825
+ runFinished = true;
826
+ // run 结束仍挂着的权限请求:全部解除阻塞(按拒绝处理),避免 handler 悬挂
827
+ for (const pending of [...(this.pendingPermissions.get(runId) ?? [])]) {
828
+ pending.resolve(false);
829
+ }
830
+ this.pendingPermissions.delete(runId);
831
+ this.active.delete(runId);
832
+ if (lockLostError) {
833
+ yield {
834
+ type: "error",
835
+ message: `ACP session 锁异常丢失,任务已立即停止:${lockLostError.message}`,
836
+ fatal: true,
837
+ };
838
+ exitCode = 1;
839
+ }
840
+ yield { type: "done", exitCode };
841
+ }
842
+ }
843
+ async *executePiRun(runId, ctx) {
844
+ const handleRef = {};
845
+ const activeRun = {
846
+ runId,
847
+ sessionId: ctx.resumeSessionId,
848
+ aborted: false,
849
+ cancel: () => {
850
+ void handleRef.current?.cancel();
851
+ },
852
+ steer: async (prompt) => {
853
+ const steer = handleRef.current?.steer;
854
+ if (!steer)
855
+ throw new Error("当前 Pi Agent 尚未初始化或不支持 steering");
856
+ return steer(prompt);
857
+ },
858
+ };
859
+ this.active.set(runId, activeRun);
860
+ let exitCode = 0;
861
+ try {
862
+ for await (const event of runPiSession(ctx, {
863
+ isAborted: () => activeRun.aborted,
864
+ handleRef,
865
+ ...(this.options.piSessionFactory
866
+ ? { createSession: this.options.piSessionFactory }
867
+ : {}),
868
+ })) {
869
+ if (event.type === "session")
870
+ activeRun.sessionId = event.sessionId;
871
+ if (event.type === "error" && event.fatal)
872
+ exitCode = 1;
873
+ yield event;
874
+ }
875
+ }
876
+ catch (err) {
877
+ yield {
878
+ type: "error",
879
+ message: err instanceof Error ? err.message : String(err),
880
+ fatal: true,
881
+ };
882
+ exitCode = 1;
883
+ }
884
+ finally {
885
+ this.active.delete(runId);
886
+ yield { type: "done", exitCode };
887
+ }
888
+ }
889
+ /** runner 退出前清场:杀池内空闲进程 + 取消在飞 run(子进程 detached,不清就孤儿) */
890
+ shutdown() {
891
+ this.sessionPool.shutdown();
892
+ for (const run of [...this.active.values()]) {
893
+ run.aborted = true;
894
+ try {
895
+ run.cancel();
896
+ }
897
+ catch {
898
+ // 尽力而为
899
+ }
900
+ }
901
+ this.active.clear();
902
+ for (const lifecycle of this.runLifecycles.values()) {
903
+ if (lifecycle.expiry)
904
+ clearTimeout(lifecycle.expiry);
905
+ }
906
+ this.runLifecycles.clear();
907
+ }
908
+ /** /approve /deny:回应当前 run 最早挂起的权限请求(FIFO) */
909
+ resolvePermission(runId, approve) {
910
+ const pending = this.pendingPermissions.get(runId)?.[0];
911
+ if (!pending)
912
+ return false;
913
+ pending.resolve(approve);
914
+ return true;
915
+ }
916
+ }
917
+ export function createRunnerApp(host, token) {
918
+ const app = new Hono();
919
+ app.use("*", async (c, next) => {
920
+ const auth = c.req.header("authorization");
921
+ if (auth !== `Bearer ${token}`) {
922
+ return c.json({ error: "unauthorized" }, 401);
923
+ }
924
+ await next();
925
+ });
926
+ app.get("/health", (c) => c.json({ ok: true, version: VERSION, backends: host.registryIds }));
927
+ app.get("/doctor", async (c) => c.json(await host.doctor()));
928
+ app.get("/agents/setup", async (c) => {
929
+ return c.json({ agents: await host.listAgentSetup() });
930
+ });
931
+ app.post("/agents/detect", async (c) => {
932
+ const agents = await host.listAgentSetup();
933
+ const results = await Promise.all(agents.map(async (agent) => {
934
+ try {
935
+ return await host.detectAgent(agent.agentId);
936
+ }
937
+ catch (error) {
938
+ return {
939
+ ...agent,
940
+ runtime: "unavailable",
941
+ diagnostic: {
942
+ stage: "detect",
943
+ code: "detect_failed",
944
+ message: error instanceof Error ? error.message : String(error),
945
+ },
946
+ };
947
+ }
948
+ }));
949
+ return c.json({ agents: results });
950
+ });
951
+ app.post("/agents/:agentId/detect", async (c) => {
952
+ try {
953
+ return c.json(await host.detectAgent(c.req.param("agentId")));
954
+ }
955
+ catch (error) {
956
+ return agentSetupErrorResponse(c, error, 404);
957
+ }
958
+ });
959
+ app.post("/agents/:agentId/install", async (c) => {
960
+ const body = await c.req.json().catch(() => null);
961
+ if (!body || typeof body.strategy_id !== "string" || !body.strategy_id.trim()) {
962
+ return c.json({ error: "install_strategy_not_found" }, 400);
963
+ }
964
+ try {
965
+ return c.json(await host.installAgent(c.req.param("agentId"), body.strategy_id.trim()));
966
+ }
967
+ catch (error) {
968
+ return agentSetupErrorResponse(c, error, 404, 400);
969
+ }
970
+ });
971
+ app.get("/skills", (c) => {
972
+ try {
973
+ return c.json(host.scanSkills());
974
+ }
975
+ catch (error) {
976
+ return skillControlPlaneErrorResponse(c, error);
977
+ }
978
+ });
979
+ app.post("/skills/sources", async (c) => {
980
+ const body = await c.req.json().catch(() => null);
981
+ if (!body || typeof body.path !== "string" || !body.path.trim()) {
982
+ return c.json({ error: "invalid_skill_source", message: "path is required" }, 400);
983
+ }
984
+ try {
985
+ return c.json(host.addSkillSource(body.path.trim()));
986
+ }
987
+ catch (error) {
988
+ return skillControlPlaneErrorResponse(c, error);
989
+ }
990
+ });
991
+ app.post("/skills/:skillId/adopt/preview", async (c) => {
992
+ const actorId = await readSkillActor(c);
993
+ if (!actorId)
994
+ return c.json({ error: "invalid_skill_actor" }, 400);
995
+ try {
996
+ return c.json(host.previewSkillAdopt(c.req.param("skillId"), actorId));
997
+ }
998
+ catch (error) {
999
+ return skillControlPlaneErrorResponse(c, error);
1000
+ }
1001
+ });
1002
+ app.post("/skills/:skillId/global-state/preview", async (c) => {
1003
+ const body = await c.req.json().catch(() => null);
1004
+ if (!body || typeof body.actor_id !== "string" || !body.actor_id.trim() || typeof body.enabled !== "boolean") {
1005
+ return c.json({ error: "invalid_skill_global_state" }, 400);
1006
+ }
1007
+ try {
1008
+ return c.json(host.previewSkillGlobalState(c.req.param("skillId"), body.enabled, body.actor_id.trim()));
1009
+ }
1010
+ catch (error) {
1011
+ return skillControlPlaneErrorResponse(c, error);
1012
+ }
1013
+ });
1014
+ app.post("/skills/assignments/preview", async (c) => {
1015
+ const input = await readSkillAssignment(c);
1016
+ if (!input) {
1017
+ return c.json({ error: "invalid_skill_assignment" }, 400);
1018
+ }
1019
+ try {
1020
+ return c.json(host.previewSkillAssignment(input));
1021
+ }
1022
+ catch (error) {
1023
+ return skillControlPlaneErrorResponse(c, error);
1024
+ }
1025
+ });
1026
+ app.post("/skills/:skillId/unmanage/preview", async (c) => {
1027
+ const actorId = await readSkillActor(c);
1028
+ if (!actorId)
1029
+ return c.json({ error: "invalid_skill_actor" }, 400);
1030
+ try {
1031
+ return c.json(host.previewSkillUnmanage(c.req.param("skillId"), actorId));
1032
+ }
1033
+ catch (error) {
1034
+ return skillControlPlaneErrorResponse(c, error);
1035
+ }
1036
+ });
1037
+ for (const kind of ["adopt", "global-state", "assignment", "unmanage"]) {
1038
+ app.post(`/skills/${kind}-plans/:planId/apply`, async (c) => {
1039
+ const actorId = await readSkillActor(c);
1040
+ if (!actorId)
1041
+ return c.json({ error: "invalid_skill_actor" }, 400);
1042
+ try {
1043
+ return c.json(host.applySkillPlan(c.req.param("planId"), actorId));
1044
+ }
1045
+ catch (error) {
1046
+ return skillControlPlaneErrorResponse(c, error);
1047
+ }
1048
+ });
1049
+ }
1050
+ // Pi provider management (docs/orchestration/agent-providers.md).
1051
+ // models.json lives on this host; bridge proxies and never persists it.
1052
+ app.get("/pi/providers/presets", (c) => c.json({ presets: PI_PROVIDER_PRESETS }));
1053
+ app.get("/pi/providers", (c) => {
1054
+ try {
1055
+ return c.json(readPiProviders());
1056
+ }
1057
+ catch (error) {
1058
+ return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
1059
+ }
1060
+ });
1061
+ app.put("/pi/providers", async (c) => {
1062
+ const body = (await c.req.json().catch(() => null));
1063
+ if (!body)
1064
+ return c.json({ error: "invalid_json" }, 400);
1065
+ const issues = validateProviders(body);
1066
+ if (issues.length)
1067
+ return c.json({ error: "invalid_providers", issues }, 400);
1068
+ try {
1069
+ writePiProviders(body);
1070
+ return c.json({ ok: true });
1071
+ }
1072
+ catch (error) {
1073
+ return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
1074
+ }
1075
+ });
1076
+ app.post("/pi/providers/test", async (c) => {
1077
+ const body = (await c.req.json().catch(() => null));
1078
+ if (!body || typeof body.baseUrl !== "string" || !/^https?:\/\//.test(body.baseUrl)) {
1079
+ return c.json({ error: "baseUrl (http/https) is required" }, 400);
1080
+ }
1081
+ return c.json(await testProviderConnection({
1082
+ baseUrl: body.baseUrl,
1083
+ apiKey: body.apiKey,
1084
+ authHeader: body.authHeader,
1085
+ api: typeof body.api === "string" ? body.api : undefined,
1086
+ model: typeof body.model === "string" ? body.model : undefined,
1087
+ }));
1088
+ });
1089
+ app.post("/runs/:id/permission", async (c) => {
1090
+ const body = (await c.req.json().catch(() => ({})));
1091
+ if (typeof body.approve !== "boolean") {
1092
+ return c.json({ error: "approve (boolean) is required" }, 400);
1093
+ }
1094
+ const resolved = host.resolvePermission(c.req.param("id"), body.approve);
1095
+ return c.json({ resolved });
1096
+ });
1097
+ app.post("/runs/:id/cancel", async (c) => {
1098
+ const ok = await host.cancelAndWait(c.req.param("id"));
1099
+ return c.json({ ok });
1100
+ });
1101
+ app.post("/runs/:id/steer", async (c) => {
1102
+ const body = (await c.req.json().catch(() => ({})));
1103
+ if (!body.prompt?.trim()) {
1104
+ return c.json({ error: "prompt is required" }, 400);
1105
+ }
1106
+ const result = await host.steer(c.req.param("id"), body.prompt.trim());
1107
+ return c.json(result, result.ok ? 200 : 409);
1108
+ });
1109
+ app.post("/runs", async (c) => {
1110
+ const body = (await c.req.json());
1111
+ const encoder = new TextEncoder();
1112
+ const stream = new ReadableStream({
1113
+ async start(controller) {
1114
+ const keepalive = encoder.encode(": keepalive\n\n");
1115
+ controller.enqueue(keepalive);
1116
+ const timer = setInterval(() => {
1117
+ try {
1118
+ controller.enqueue(keepalive);
1119
+ }
1120
+ catch {
1121
+ clearInterval(timer);
1122
+ }
1123
+ }, 15_000);
1124
+ const send = (event) => {
1125
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\n\n`));
1126
+ };
1127
+ try {
1128
+ for await (const event of host.executeRun(body)) {
1129
+ send(event);
1130
+ }
1131
+ }
1132
+ catch (err) {
1133
+ send({
1134
+ type: "error",
1135
+ message: err instanceof Error ? err.message : String(err),
1136
+ fatal: true,
1137
+ });
1138
+ send({ type: "done", exitCode: 1 });
1139
+ }
1140
+ finally {
1141
+ clearInterval(timer);
1142
+ controller.close();
1143
+ }
1144
+ },
1145
+ });
1146
+ return new Response(stream, {
1147
+ headers: {
1148
+ "Content-Type": "text/event-stream",
1149
+ "Cache-Control": "no-cache",
1150
+ Connection: "keep-alive",
1151
+ },
1152
+ });
1153
+ });
1154
+ app.get("/sessions", async (c) => {
1155
+ const backend = c.req.query("backend");
1156
+ const cwd = c.req.query("cwd");
1157
+ const all = c.req.query("all") === "true";
1158
+ const limit = Number(c.req.query("limit") ?? "20");
1159
+ if (!backend || !cwd) {
1160
+ return c.json({ error: "backend and cwd are required" }, 400);
1161
+ }
1162
+ const result = await host.listSessions(backend, cwd, {
1163
+ all,
1164
+ limit: Number.isFinite(limit) ? limit : 20,
1165
+ });
1166
+ return c.json(result);
1167
+ });
1168
+ app.get("/sessions/:id/history", async (c) => {
1169
+ const backend = c.req.query("backend");
1170
+ const cwd = c.req.query("cwd");
1171
+ if (!backend || !cwd) {
1172
+ return c.json({ error: "backend and cwd are required" }, 400);
1173
+ }
1174
+ try {
1175
+ const encodedDirectories = c.req.query("additional_directories");
1176
+ const additionalDirectories = encodedDirectories
1177
+ ? JSON.parse(encodedDirectories)
1178
+ : undefined;
1179
+ if (additionalDirectories !== undefined && (!Array.isArray(additionalDirectories) ||
1180
+ !additionalDirectories.every((directory) => typeof directory === "string"))) {
1181
+ return c.json({ error: "additional_directories must be a string array" }, 400);
1182
+ }
1183
+ const events = await host.loadSessionHistory(backend, cwd, c.req.param("id"), additionalDirectories);
1184
+ return c.json({ events });
1185
+ }
1186
+ catch (error) {
1187
+ return c.json({ error: error instanceof Error ? error.message : String(error) }, 409);
1188
+ }
1189
+ });
1190
+ app.post("/directories/authorize", async (c) => {
1191
+ const body = (await c.req.json().catch(() => null));
1192
+ if (!body?.path)
1193
+ return c.json({ ok: false, error: "path 必填" }, 400);
1194
+ const result = await host.authorizeDirectory(body.path);
1195
+ return c.json(result, result.ok ? 200 : 403);
1196
+ });
1197
+ app.get("/directories/list", async (c) => {
1198
+ const root = c.req.query("root");
1199
+ if (!root)
1200
+ return c.json({ ok: false, error: "root is required" }, 400);
1201
+ const result = await host.listDirectory(root, c.req.query("path") ?? "");
1202
+ return c.json(result, result.ok ? 200 : 400);
1203
+ });
1204
+ app.post("/directories/pick", async (c) => {
1205
+ const result = await host.pickDirectory();
1206
+ return c.json(result, result.ok ? 200 : 503);
1207
+ });
1208
+ app.post("/sessions/:id/close", async (c) => {
1209
+ const body = (await c.req.json().catch(() => ({})));
1210
+ if (!body.backend || !body.cwd) {
1211
+ return c.json({ error: "backend and cwd are required" }, 400);
1212
+ }
1213
+ const result = await host.closeSession(body.backend, body.cwd, c.req.param("id"));
1214
+ return c.json(result, result.ok ? 200 : 409);
1215
+ });
1216
+ app.post("/sessions/:id/fork", async (c) => {
1217
+ const body = (await c.req.json().catch(() => ({})));
1218
+ if (!body.backend || !body.cwd || !body.targetCwd) {
1219
+ return c.json({ error: "backend, cwd and targetCwd are required" }, 400);
1220
+ }
1221
+ const result = await host.forkSession(body.backend, body.cwd, c.req.param("id"), body.targetCwd);
1222
+ return c.json(result, result.ok ? 201 : 409);
1223
+ });
1224
+ app.delete("/sessions/:id", async (c) => {
1225
+ const body = (await c.req.json().catch(() => ({})));
1226
+ if (!body.backend || !body.cwd) {
1227
+ return c.json({ error: "backend and cwd are required" }, 400);
1228
+ }
1229
+ const result = await host.deleteSession(body.backend, body.cwd, c.req.param("id"));
1230
+ return c.json(result, result.ok ? 200 : 409);
1231
+ });
1232
+ app.get("/config-options", async (c) => {
1233
+ const backend = c.req.query("backend");
1234
+ const cwd = c.req.query("cwd");
1235
+ if (!backend || !cwd) {
1236
+ return c.json({ error: "backend and cwd are required" }, 400);
1237
+ }
1238
+ const result = await host.listConfigOptions(backend, cwd, c.req.query("model") || null);
1239
+ return c.json(result);
1240
+ });
1241
+ app.get("/commands", async (c) => {
1242
+ const backend = c.req.query("backend");
1243
+ const cwd = c.req.query("cwd");
1244
+ if (!backend || !cwd) {
1245
+ return c.json({ error: "backend and cwd are required" }, 400);
1246
+ }
1247
+ return c.json(await host.listCommands(backend, cwd));
1248
+ });
1249
+ return app;
1250
+ }
1251
+ function agentSetupErrorResponse(c, error, agentStatus = 404, strategyStatus = 400) {
1252
+ const message = error instanceof Error ? error.message : String(error);
1253
+ if (message.startsWith("Unknown agent:")) {
1254
+ return c.json({ error: "agent_not_found" }, agentStatus);
1255
+ }
1256
+ if (message.startsWith("Unknown install strategy:")) {
1257
+ return c.json({ error: "install_strategy_not_found" }, strategyStatus);
1258
+ }
1259
+ return c.json({ error: "agent_setup_failed", message }, 500);
1260
+ }
1261
+ async function readSkillAssignment(c) {
1262
+ const body = await c.req.json().catch(() => null);
1263
+ if (!body
1264
+ || typeof body.skill_id !== "string"
1265
+ || !body.skill_id.trim()
1266
+ || typeof body.agent_id !== "string"
1267
+ || !SKILL_AGENT_IDS.includes(body.agent_id)
1268
+ || typeof body.enabled !== "boolean"
1269
+ || typeof body.actor_id !== "string"
1270
+ || !body.actor_id.trim()) {
1271
+ return null;
1272
+ }
1273
+ return {
1274
+ skill_id: body.skill_id.trim(),
1275
+ agent_id: body.agent_id,
1276
+ enabled: body.enabled,
1277
+ actor_id: body.actor_id.trim(),
1278
+ };
1279
+ }
1280
+ async function readSkillActor(c) {
1281
+ const body = await c.req.json().catch(() => null);
1282
+ return body && typeof body.actor_id === "string" && body.actor_id.trim()
1283
+ ? body.actor_id.trim()
1284
+ : null;
1285
+ }
1286
+ function skillControlPlaneErrorResponse(c, error) {
1287
+ const value = error;
1288
+ const code = typeof value?.code === "string" ? value.code : "skill_control_plane_failed";
1289
+ const status = value?.status === 400 || value?.status === 404 || value?.status === 409 || value?.status === 422
1290
+ ? value.status
1291
+ : 500;
1292
+ const message = typeof value?.message === "string" ? value.message : String(error);
1293
+ return c.json({ error: code, message }, status);
1294
+ }
1295
+ //# sourceMappingURL=server.js.map