@bd7pil/ocrc 0.9.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 (292) hide show
  1. package/LICENSE +34 -0
  2. package/README.md +330 -0
  3. package/dist/cli/host-backends.js +216 -0
  4. package/dist/cli/host-backends.js.map +1 -0
  5. package/dist/cli/host.js +185 -0
  6. package/dist/cli/host.js.map +1 -0
  7. package/dist/cli/index.js +67 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/cli/init.js +68 -0
  10. package/dist/cli/init.js.map +1 -0
  11. package/dist/cli/install.js +220 -0
  12. package/dist/cli/install.js.map +1 -0
  13. package/dist/cli/pair.js +11 -0
  14. package/dist/cli/pair.js.map +1 -0
  15. package/dist/cli/uninstall.js +75 -0
  16. package/dist/cli/uninstall.js.map +1 -0
  17. package/dist/connectivity/auth/cf-access.js +20 -0
  18. package/dist/connectivity/auth/cf-access.js.map +1 -0
  19. package/dist/connectivity/auth/index.js +2 -0
  20. package/dist/connectivity/auth/index.js.map +1 -0
  21. package/dist/connectivity/auth/select.js +19 -0
  22. package/dist/connectivity/auth/select.js.map +1 -0
  23. package/dist/connectivity/auth/token.js +157 -0
  24. package/dist/connectivity/auth/token.js.map +1 -0
  25. package/dist/connectivity/exposure/cloudflared.js +77 -0
  26. package/dist/connectivity/exposure/cloudflared.js.map +1 -0
  27. package/dist/connectivity/exposure/index.js +2 -0
  28. package/dist/connectivity/exposure/index.js.map +1 -0
  29. package/dist/connectivity/exposure/providers.js +49 -0
  30. package/dist/connectivity/exposure/providers.js.map +1 -0
  31. package/dist/connectivity/pairing.js +29 -0
  32. package/dist/connectivity/pairing.js.map +1 -0
  33. package/dist/core/agent/acp-backend.js +539 -0
  34. package/dist/core/agent/acp-backend.js.map +1 -0
  35. package/dist/core/agent/acp-connect.js +92 -0
  36. package/dist/core/agent/acp-connect.js.map +1 -0
  37. package/dist/core/agent/acp-normalizer.js +81 -0
  38. package/dist/core/agent/acp-normalizer.js.map +1 -0
  39. package/dist/core/agent/acp-replay.js +89 -0
  40. package/dist/core/agent/acp-replay.js.map +1 -0
  41. package/dist/core/agent/acp-store.js +129 -0
  42. package/dist/core/agent/acp-store.js.map +1 -0
  43. package/dist/core/agent/backend.js +2 -0
  44. package/dist/core/agent/backend.js.map +1 -0
  45. package/dist/core/agent/diff-util.js +70 -0
  46. package/dist/core/agent/diff-util.js.map +1 -0
  47. package/dist/core/agent/event.js +12 -0
  48. package/dist/core/agent/event.js.map +1 -0
  49. package/dist/core/agent/opencode-backend.js +598 -0
  50. package/dist/core/agent/opencode-backend.js.map +1 -0
  51. package/dist/core/agent/opencode-normalizer.js +69 -0
  52. package/dist/core/agent/opencode-normalizer.js.map +1 -0
  53. package/dist/core/agent/registry.js +55 -0
  54. package/dist/core/agent/registry.js.map +1 -0
  55. package/dist/core/agent/v2-backend.js +176 -0
  56. package/dist/core/agent/v2-backend.js.map +1 -0
  57. package/dist/core/card-bus.js +74 -0
  58. package/dist/core/card-bus.js.map +1 -0
  59. package/dist/core/channels.js +95 -0
  60. package/dist/core/channels.js.map +1 -0
  61. package/dist/core/history.js +91 -0
  62. package/dist/core/history.js.map +1 -0
  63. package/dist/core/list-files.js +50 -0
  64. package/dist/core/list-files.js.map +1 -0
  65. package/dist/core/opencode-events.js +29 -0
  66. package/dist/core/opencode-events.js.map +1 -0
  67. package/dist/core/primary-election.js +91 -0
  68. package/dist/core/primary-election.js.map +1 -0
  69. package/dist/core/push.js +152 -0
  70. package/dist/core/push.js.map +1 -0
  71. package/dist/core/relay.js +400 -0
  72. package/dist/core/relay.js.map +1 -0
  73. package/dist/core/scheduler.js +150 -0
  74. package/dist/core/scheduler.js.map +1 -0
  75. package/dist/core/state.js +222 -0
  76. package/dist/core/state.js.map +1 -0
  77. package/dist/core/stream-accumulator.js +76 -0
  78. package/dist/core/stream-accumulator.js.map +1 -0
  79. package/dist/core/structured-card.js +2 -0
  80. package/dist/core/structured-card.js.map +1 -0
  81. package/dist/core/types.js +2 -0
  82. package/dist/core/types.js.map +1 -0
  83. package/dist/index.js +3 -0
  84. package/dist/index.js.map +1 -0
  85. package/dist/opencode/global-events.js +57 -0
  86. package/dist/opencode/global-events.js.map +1 -0
  87. package/dist/opencode/list-sessions.js +122 -0
  88. package/dist/opencode/list-sessions.js.map +1 -0
  89. package/dist/opencode/submit.js +39 -0
  90. package/dist/opencode/submit.js.map +1 -0
  91. package/dist/opencode/workspaces.js +51 -0
  92. package/dist/opencode/workspaces.js.map +1 -0
  93. package/dist/plugin/config.js +128 -0
  94. package/dist/plugin/config.js.map +1 -0
  95. package/dist/plugin/control-plane.js +133 -0
  96. package/dist/plugin/control-plane.js.map +1 -0
  97. package/dist/plugin/entry.js +409 -0
  98. package/dist/plugin/entry.js.map +1 -0
  99. package/dist/plugin/v2/event-map.js +193 -0
  100. package/dist/plugin/v2/event-map.js.map +1 -0
  101. package/dist/plugin/v2/types.js +15 -0
  102. package/dist/plugin/v2/types.js.map +1 -0
  103. package/dist/transport/interface.js +2 -0
  104. package/dist/transport/interface.js.map +1 -0
  105. package/dist/transport/telegram/esc.js +9 -0
  106. package/dist/transport/telegram/esc.js.map +1 -0
  107. package/dist/transport/telegram/handlers/info-commands.js +101 -0
  108. package/dist/transport/telegram/handlers/info-commands.js.map +1 -0
  109. package/dist/transport/telegram/handlers.js +1348 -0
  110. package/dist/transport/telegram/handlers.js.map +1 -0
  111. package/dist/transport/telegram/i18n/en.js +538 -0
  112. package/dist/transport/telegram/i18n/en.js.map +1 -0
  113. package/dist/transport/telegram/i18n/index.js +83 -0
  114. package/dist/transport/telegram/i18n/index.js.map +1 -0
  115. package/dist/transport/telegram/i18n/zh.js +538 -0
  116. package/dist/transport/telegram/i18n/zh.js.map +1 -0
  117. package/dist/transport/telegram/index.js +792 -0
  118. package/dist/transport/telegram/index.js.map +1 -0
  119. package/dist/transport/telegram/main-keyboard.js +36 -0
  120. package/dist/transport/telegram/main-keyboard.js.map +1 -0
  121. package/dist/transport/telegram/managers/abort-suppression-manager.js +33 -0
  122. package/dist/transport/telegram/managers/abort-suppression-manager.js.map +1 -0
  123. package/dist/transport/telegram/managers/external-input-suppression-manager.js +51 -0
  124. package/dist/transport/telegram/managers/external-input-suppression-manager.js.map +1 -0
  125. package/dist/transport/telegram/managers/interaction-manager.js +254 -0
  126. package/dist/transport/telegram/managers/interaction-manager.js.map +1 -0
  127. package/dist/transport/telegram/managers/permission-manager.js +242 -0
  128. package/dist/transport/telegram/managers/permission-manager.js.map +1 -0
  129. package/dist/transport/telegram/managers/question-manager.js +191 -0
  130. package/dist/transport/telegram/managers/question-manager.js.map +1 -0
  131. package/dist/transport/telegram/managers/rename-manager.js +56 -0
  132. package/dist/transport/telegram/managers/rename-manager.js.map +1 -0
  133. package/dist/transport/telegram/menus.js +77 -0
  134. package/dist/transport/telegram/menus.js.map +1 -0
  135. package/dist/transport/telegram/permission-flow.js +156 -0
  136. package/dist/transport/telegram/permission-flow.js.map +1 -0
  137. package/dist/transport/telegram/question-flow.js +224 -0
  138. package/dist/transport/telegram/question-flow.js.map +1 -0
  139. package/dist/transport/telegram/render/block-parser.js +365 -0
  140. package/dist/transport/telegram/render/block-parser.js.map +1 -0
  141. package/dist/transport/telegram/render/block-plain-text.js +87 -0
  142. package/dist/transport/telegram/render/block-plain-text.js.map +1 -0
  143. package/dist/transport/telegram/render/block-splitter.js +152 -0
  144. package/dist/transport/telegram/render/block-splitter.js.map +1 -0
  145. package/dist/transport/telegram/render/chunker.js +71 -0
  146. package/dist/transport/telegram/render/chunker.js.map +1 -0
  147. package/dist/transport/telegram/render/limits.js +13 -0
  148. package/dist/transport/telegram/render/limits.js.map +1 -0
  149. package/dist/transport/telegram/render/markdown-normalizer.js +102 -0
  150. package/dist/transport/telegram/render/markdown-normalizer.js.map +1 -0
  151. package/dist/transport/telegram/render/markdown-to-telegram-v2.js +116 -0
  152. package/dist/transport/telegram/render/markdown-to-telegram-v2.js.map +1 -0
  153. package/dist/transport/telegram/render/part-signature.js +14 -0
  154. package/dist/transport/telegram/render/part-signature.js.map +1 -0
  155. package/dist/transport/telegram/render/pipeline.js +23 -0
  156. package/dist/transport/telegram/render/pipeline.js.map +1 -0
  157. package/dist/transport/telegram/render/rich-blocks.js +311 -0
  158. package/dist/transport/telegram/render/rich-blocks.js.map +1 -0
  159. package/dist/transport/telegram/render/text-splitter.js +64 -0
  160. package/dist/transport/telegram/render/text-splitter.js.map +1 -0
  161. package/dist/transport/telegram/render/types.js +2 -0
  162. package/dist/transport/telegram/render/types.js.map +1 -0
  163. package/dist/transport/telegram/renderer.js +305 -0
  164. package/dist/transport/telegram/renderer.js.map +1 -0
  165. package/dist/transport/telegram/streaming/duration-formatter.js +68 -0
  166. package/dist/transport/telegram/streaming/duration-formatter.js.map +1 -0
  167. package/dist/transport/telegram/streaming/finalize-assistant-response.js +37 -0
  168. package/dist/transport/telegram/streaming/finalize-assistant-response.js.map +1 -0
  169. package/dist/transport/telegram/streaming/response-streamer.js +400 -0
  170. package/dist/transport/telegram/streaming/response-streamer.js.map +1 -0
  171. package/dist/transport/telegram/streaming/running-tool-tracker.js +150 -0
  172. package/dist/transport/telegram/streaming/running-tool-tracker.js.map +1 -0
  173. package/dist/transport/telegram/streaming/stream-throttle.js +57 -0
  174. package/dist/transport/telegram/streaming/stream-throttle.js.map +1 -0
  175. package/dist/transport/telegram/streaming/tool-call-streamer.js +390 -0
  176. package/dist/transport/telegram/streaming/tool-call-streamer.js.map +1 -0
  177. package/dist/transport/telegram/streaming-render.js +182 -0
  178. package/dist/transport/telegram/streaming-render.js.map +1 -0
  179. package/dist/transport/telegram/types/interaction.js +2 -0
  180. package/dist/transport/telegram/types/interaction.js.map +1 -0
  181. package/dist/transport/telegram/types/model.js +25 -0
  182. package/dist/transport/telegram/types/model.js.map +1 -0
  183. package/dist/transport/telegram/types/permission.js +2 -0
  184. package/dist/transport/telegram/types/permission.js.map +1 -0
  185. package/dist/transport/telegram/types/question.js +2 -0
  186. package/dist/transport/telegram/types/question.js.map +1 -0
  187. package/dist/transport/telegram/types/rename.js +2 -0
  188. package/dist/transport/telegram/types/rename.js.map +1 -0
  189. package/dist/transport/telegram/types/scheduled-task.js +23 -0
  190. package/dist/transport/telegram/types/scheduled-task.js.map +1 -0
  191. package/dist/transport/telegram/types/session.js +2 -0
  192. package/dist/transport/telegram/types/session.js.map +1 -0
  193. package/dist/transport/telegram/ui.js +28 -0
  194. package/dist/transport/telegram/ui.js.map +1 -0
  195. package/dist/transport/web/index.js +148 -0
  196. package/dist/transport/web/index.js.map +1 -0
  197. package/dist/transport/web/middleware/cf-access.js +104 -0
  198. package/dist/transport/web/middleware/cf-access.js.map +1 -0
  199. package/dist/transport/web/opencode-config.js +15 -0
  200. package/dist/transport/web/opencode-config.js.map +1 -0
  201. package/dist/transport/web/routes/abort.js +12 -0
  202. package/dist/transport/web/routes/abort.js.map +1 -0
  203. package/dist/transport/web/routes/approval.js +16 -0
  204. package/dist/transport/web/routes/approval.js.map +1 -0
  205. package/dist/transport/web/routes/catalog.js +11 -0
  206. package/dist/transport/web/routes/catalog.js.map +1 -0
  207. package/dist/transport/web/routes/channels.js +53 -0
  208. package/dist/transport/web/routes/channels.js.map +1 -0
  209. package/dist/transport/web/routes/commands.js +15 -0
  210. package/dist/transport/web/routes/commands.js.map +1 -0
  211. package/dist/transport/web/routes/context.js +17 -0
  212. package/dist/transport/web/routes/context.js.map +1 -0
  213. package/dist/transport/web/routes/controls.js +34 -0
  214. package/dist/transport/web/routes/controls.js.map +1 -0
  215. package/dist/transport/web/routes/create-session.js +21 -0
  216. package/dist/transport/web/routes/create-session.js.map +1 -0
  217. package/dist/transport/web/routes/diff.js +7 -0
  218. package/dist/transport/web/routes/diff.js.map +1 -0
  219. package/dist/transport/web/routes/files.js +22 -0
  220. package/dist/transport/web/routes/files.js.map +1 -0
  221. package/dist/transport/web/routes/logs.js +9 -0
  222. package/dist/transport/web/routes/logs.js.map +1 -0
  223. package/dist/transport/web/routes/m8.js +69 -0
  224. package/dist/transport/web/routes/m8.js.map +1 -0
  225. package/dist/transport/web/routes/mcp.js +7 -0
  226. package/dist/transport/web/routes/mcp.js.map +1 -0
  227. package/dist/transport/web/routes/message.js +32 -0
  228. package/dist/transport/web/routes/message.js.map +1 -0
  229. package/dist/transport/web/routes/overrides.js +20 -0
  230. package/dist/transport/web/routes/overrides.js.map +1 -0
  231. package/dist/transport/web/routes/question.js +32 -0
  232. package/dist/transport/web/routes/question.js.map +1 -0
  233. package/dist/transport/web/routes/rename.js +12 -0
  234. package/dist/transport/web/routes/rename.js.map +1 -0
  235. package/dist/transport/web/routes/schedules.js +28 -0
  236. package/dist/transport/web/routes/schedules.js.map +1 -0
  237. package/dist/transport/web/routes/session.js +20 -0
  238. package/dist/transport/web/routes/session.js.map +1 -0
  239. package/dist/transport/web/routes/sessions.js +25 -0
  240. package/dist/transport/web/routes/sessions.js.map +1 -0
  241. package/dist/transport/web/routes/subagents.js +11 -0
  242. package/dist/transport/web/routes/subagents.js.map +1 -0
  243. package/dist/transport/web/routes/suggestions.js +7 -0
  244. package/dist/transport/web/routes/suggestions.js.map +1 -0
  245. package/dist/transport/web/routes/todo.js +7 -0
  246. package/dist/transport/web/routes/todo.js.map +1 -0
  247. package/dist/transport/web/routes/version.js +5 -0
  248. package/dist/transport/web/routes/version.js.map +1 -0
  249. package/dist/transport/web/routes/workspaces.js +7 -0
  250. package/dist/transport/web/routes/workspaces.js.map +1 -0
  251. package/dist/transport/web/server.js +111 -0
  252. package/dist/transport/web/server.js.map +1 -0
  253. package/dist/transport/web/session-summary.js +46 -0
  254. package/dist/transport/web/session-summary.js.map +1 -0
  255. package/dist/transport/web/ws-hub.js +83 -0
  256. package/dist/transport/web/ws-hub.js.map +1 -0
  257. package/dist/utils/logger.js +105 -0
  258. package/dist/utils/logger.js.map +1 -0
  259. package/dist/utils/markdown.js +129 -0
  260. package/dist/utils/markdown.js.map +1 -0
  261. package/dist/utils/paths.js +18 -0
  262. package/dist/utils/paths.js.map +1 -0
  263. package/dist/utils/version.js +44 -0
  264. package/dist/utils/version.js.map +1 -0
  265. package/package.json +91 -0
  266. package/web/dist/_app/env.js +1 -0
  267. package/web/dist/_app/immutable/assets/0.DxN3RsuG.css +1 -0
  268. package/web/dist/_app/immutable/assets/2.BNuGfmZP.css +1 -0
  269. package/web/dist/_app/immutable/assets/3.CTDprntu.css +1 -0
  270. package/web/dist/_app/immutable/chunks/BUpwHpMJ.js +1 -0
  271. package/web/dist/_app/immutable/chunks/BjY4dxcB.js +2 -0
  272. package/web/dist/_app/immutable/chunks/C2FuqD3s.js +1 -0
  273. package/web/dist/_app/immutable/chunks/CUHGq08X.js +2 -0
  274. package/web/dist/_app/immutable/chunks/CWj6FrbW.js +1 -0
  275. package/web/dist/_app/immutable/chunks/ClvoqtGj.js +1 -0
  276. package/web/dist/_app/immutable/chunks/DIEDQ_hk.js +1 -0
  277. package/web/dist/_app/immutable/entry/app.BoRpcVMj.js +2 -0
  278. package/web/dist/_app/immutable/entry/start.Cj-PQNTq.js +1 -0
  279. package/web/dist/_app/immutable/nodes/0.y9YEms5p.js +3 -0
  280. package/web/dist/_app/immutable/nodes/1.CPhhiRM2.js +1 -0
  281. package/web/dist/_app/immutable/nodes/2.B_c84Mc9.js +1 -0
  282. package/web/dist/_app/immutable/nodes/3.ClTd0J3D.js +64 -0
  283. package/web/dist/_app/version.json +1 -0
  284. package/web/dist/apple-touch-icon.png +0 -0
  285. package/web/dist/favicon.png +0 -0
  286. package/web/dist/favicon.svg +17 -0
  287. package/web/dist/icon-192.png +0 -0
  288. package/web/dist/icon-512-maskable.png +0 -0
  289. package/web/dist/icon-512.png +0 -0
  290. package/web/dist/index.html +73 -0
  291. package/web/dist/manifest.webmanifest +28 -0
  292. package/web/dist/service-worker.js +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"question.js","sourceRoot":"","sources":["../../../../src/transport/telegram/types/question.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=rename.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rename.js","sourceRoot":"","sources":["../../../../src/transport/telegram/types/rename.ts"],"names":[],"mappings":""}
@@ -0,0 +1,23 @@
1
+ export const DEFAULT_TASK_AGENT = "build";
2
+ export function createScheduledTaskModel(model) {
3
+ return {
4
+ providerID: model.providerID,
5
+ modelID: model.modelID,
6
+ variant: model.variant ?? null,
7
+ };
8
+ }
9
+ export function cloneParsedTaskSchedule(schedule) {
10
+ return { ...schedule };
11
+ }
12
+ export function cloneScheduledTaskModel(model) {
13
+ return { ...model };
14
+ }
15
+ export function cloneScheduledTask(task) {
16
+ return {
17
+ ...task,
18
+ // Backfill for tasks persisted before the agent field existed (they ran with "build").
19
+ agent: task.agent ?? DEFAULT_TASK_AGENT,
20
+ model: cloneScheduledTaskModel(task.model),
21
+ };
22
+ }
23
+ //# sourceMappingURL=scheduled-task.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduled-task.js","sourceRoot":"","sources":["../../../../src/transport/telegram/types/scheduled-task.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAuE1C,MAAM,UAAU,wBAAwB,CAAC,KAAgB;IACvD,OAAO;QACL,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,IAAI;KAC/B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,QAA4B;IAClE,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAyB;IAC/D,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAmB;IACpD,OAAO;QACL,GAAG,IAAI;QACP,uFAAuF;QACvF,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,kBAAkB;QACvC,KAAK,EAAE,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC;KAC3C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../../../src/transport/telegram/types/session.ts"],"names":[],"mappings":""}
@@ -0,0 +1,28 @@
1
+ // Minimal Telegram-UI and error helpers shared by the grammY transport.
2
+ // These preserve the old Markup call-shapes (spread-friendly {reply_markup})
3
+ // so call sites stay a mechanical find/replace, and read both grammY's
4
+ // top-level error fields and the legacy response-envelope shape.
5
+ import { InlineKeyboard } from 'grammy';
6
+ export const btn = (text, callback_data) => ({ text, callback_data });
7
+ /** Build an InlineKeyboard from row arrays; returns {reply_markup} for spreading into reply opts. */
8
+ export function inlineKeyboard(rows) {
9
+ let kb = new InlineKeyboard();
10
+ rows.forEach((row, i) => {
11
+ for (const b of row)
12
+ kb = kb.text(b.text, b.callback_data);
13
+ if (i < rows.length - 1)
14
+ kb = kb.row();
15
+ });
16
+ return { reply_markup: kb };
17
+ }
18
+ /** Telegram API error code — grammY raises GrammyError with a top-level code. */
19
+ export function errorCodeOf(e) {
20
+ const anyE = e;
21
+ return anyE?.error_code ?? anyE?.response?.error_code;
22
+ }
23
+ /** retry_after from a 429 — grammY exposes it on the error's parameters. */
24
+ export function retryAfterOf(e) {
25
+ const anyE = e;
26
+ return anyE?.parameters?.retry_after ?? anyE?.response?.parameters?.retry_after;
27
+ }
28
+ //# sourceMappingURL=ui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/transport/telegram/ui.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,6EAA6E;AAC7E,uEAAuE;AACvE,iEAAiE;AAEjE,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAOvC,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,aAAqB,EAAS,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAA;AAE5F,qGAAqG;AACrG,MAAM,UAAU,cAAc,CAAC,IAAe;IAC5C,IAAI,EAAE,GAAG,IAAI,cAAc,EAAE,CAAA;IAC7B,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QACtB,KAAK,MAAM,CAAC,IAAI,GAAG;YAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAA;QAC1D,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,CAAA;IACxC,CAAC,CAAC,CAAA;IACF,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,CAAA;AAC7B,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,WAAW,CAAC,CAAU;IACpC,MAAM,IAAI,GAAG,CAAQ,CAAA;IACrB,OAAO,IAAI,EAAE,UAAU,IAAI,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAA;AACvD,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,YAAY,CAAC,CAAU;IACrC,MAAM,IAAI,GAAG,CAAQ,CAAA;IACrB,OAAO,IAAI,EAAE,UAAU,EAAE,WAAW,IAAI,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAA;AACjF,CAAC"}
@@ -0,0 +1,148 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { serve } from '@hono/node-server';
4
+ import { WebSocketServer } from 'ws';
5
+ import { serveStatic } from '@hono/node-server/serve-static';
6
+ import { buildServer } from './server.js';
7
+ import { createWsHub } from './ws-hub.js';
8
+ import { createLogger } from '../../utils/logger.js';
9
+ const log = createLogger('web');
10
+ const CAPS = {
11
+ edit: true, maxMessageLength: Number.POSITIVE_INFINITY,
12
+ buttons: true, richText: true, streaming: true,
13
+ };
14
+ export function createWebTransport(cfg) {
15
+ let messageHandler;
16
+ let server;
17
+ let wss;
18
+ return {
19
+ name: 'web',
20
+ capabilities: CAPS,
21
+ async start(deps) {
22
+ if (!existsSync(cfg.staticRoot)) {
23
+ throw new Error(`Web static root not found: ${cfg.staticRoot}. Run 'cd web && npm run build' first.`);
24
+ }
25
+ const wsHub = createWsHub({ cardBus: deps.cardBus, registry: cfg.registry, state: deps.state });
26
+ const app = buildServer({
27
+ auth: cfg.auth,
28
+ registry: cfg.registry,
29
+ state: deps.state,
30
+ cardBus: deps.cardBus,
31
+ onMessage: (msg) => messageHandler ? messageHandler(msg) : Promise.resolve(),
32
+ scheduler: cfg.scheduler,
33
+ channels: cfg.channels,
34
+ telegramStatus: cfg.telegramStatus,
35
+ });
36
+ // Immutable hashed assets cache forever; everything else (above all
37
+ // index.html, which references those hashes) must revalidate on every
38
+ // load — a cached stale index points at deleted hashes and the app
39
+ // half-loads after any redeploy ("every refresh looks different").
40
+ app.use('/_app/immutable/*', async (c, next) => {
41
+ await next();
42
+ c.header('Cache-Control', 'public, max-age=31536000, immutable');
43
+ });
44
+ // index.html — served BOTH as the static file ('/') and by the SPA
45
+ // fallback below — must always revalidate.
46
+ app.use(async (c, next) => {
47
+ await next();
48
+ if (c.req.path === '/' || c.req.path === '/index.html') {
49
+ c.header('Cache-Control', 'no-cache');
50
+ }
51
+ });
52
+ app.use('/*', serveStatic({ root: cfg.staticRoot }));
53
+ // SPA fallback — SvelteKit static adapter only prerenders index.html;
54
+ // dynamic routes like /[sessionId]/ resolve client-side, so any non-API
55
+ // path that doesn't match a real file must serve index.html.
56
+ // Critical: ONLY fall back navigation-style paths. If a missing asset
57
+ // (e.g. stale /_app/old-hash.js a cached browser still asks for) gets
58
+ // index.html, the browser sees text/html where it expects JS and the
59
+ // whole module graph silently stalls.
60
+ const indexHtmlPath = join(cfg.staticRoot, 'index.html');
61
+ // Read once at startup — the previous per-request readFileSync put a
62
+ // synchronous disk hit on every unmatched GET.
63
+ const indexHtml = readFileSync(indexHtmlPath, 'utf-8');
64
+ app.get('*', (c) => {
65
+ const path = c.req.path;
66
+ if (path.startsWith('/api/') || path === '/ws')
67
+ return c.notFound();
68
+ return c.html(indexHtml);
69
+ });
70
+ // serve() returns immediately and bind errors (EADDRINUSE, EACCES) only
71
+ // surface as an async 'error' event. Await the listening callback so a
72
+ // failed bind REJECTS start() — the entrypoint's transport retry loop
73
+ // (1s→30s backoff) then actually recovers, e.g. when the port is held by
74
+ // a still-shutting-down predecessor. Without this, the error used to end
75
+ // up an uncaughtException that installProcessGuards() swallows, leaving
76
+ // the transport "started" but silently unbound.
77
+ server = await new Promise((resolveBind, rejectBind) => {
78
+ const s = serve({ fetch: app.fetch, hostname: cfg.host, port: cfg.port }, (info) => {
79
+ log.info(`web transport listening on http://${info.address}:${info.port}`);
80
+ resolveBind(s);
81
+ });
82
+ s.once('error', rejectBind);
83
+ });
84
+ server.on('error', (err) => {
85
+ log.error(`web transport error after bind: ${err.message}`);
86
+ setImmediate(() => { throw err; });
87
+ });
88
+ // Clients only ever send ping/subscribe — cap frames well below the 100MiB
89
+ // default so a rogue client can't exhaust memory.
90
+ wss = new WebSocketServer({ noServer: true, maxPayload: 64 * 1024 });
91
+ server.on('upgrade', async (req, socket, head) => {
92
+ const hasCookie = !!req.headers?.cookie;
93
+ const hasAccessHdr = !!req.headers?.['cf-access-jwt-assertion'];
94
+ const reqUrl = new URL(req.url, 'http://localhost');
95
+ log.info(`ws upgrade attempt path=${reqUrl.pathname} cookie=${hasCookie} cf-access-hdr=${hasAccessHdr}`);
96
+ if (reqUrl.pathname !== '/ws') {
97
+ log.info(`ws upgrade rejected: wrong path=${reqUrl.pathname}`);
98
+ socket.destroy();
99
+ return;
100
+ }
101
+ // Auth: delegate to the configured strategy (token or CF Access). A throw
102
+ // here would otherwise hang the TCP socket and raise unhandledRejection.
103
+ let user;
104
+ try {
105
+ user = await cfg.auth.verifyUpgrade({ headers: req.headers, url: req.url, socket: req.socket });
106
+ }
107
+ catch (e) {
108
+ log.warn(`ws upgrade rejected: verifyUpgrade threw: ${e.message}`);
109
+ socket.destroy();
110
+ return;
111
+ }
112
+ if (!user) {
113
+ log.warn(`ws upgrade rejected: JWT verify failed (cookie=${hasCookie} cf-access-hdr=${hasAccessHdr})`);
114
+ socket.destroy();
115
+ return;
116
+ }
117
+ const wsUser = { email: user.email ?? user.sub ?? 'user' };
118
+ log.info(`ws upgrade accepted: ${wsUser.email}`);
119
+ wss.handleUpgrade(req, socket, head, (ws) => {
120
+ log.info(`ws handleUpgrade callback fired, attaching`);
121
+ wsHub.attach(ws, wsUser);
122
+ ws.on('message', (data) => {
123
+ try {
124
+ wsHub.handleClientMessage(ws, JSON.parse(data.toString()));
125
+ }
126
+ catch { }
127
+ });
128
+ ws.on('close', (code, reason) => {
129
+ log.info(`ws closed code=${code} reason="${reason.toString()}"`);
130
+ wsHub.detach(ws);
131
+ });
132
+ ws.on('error', (err) => log.warn(`ws error: ${err.message}`));
133
+ });
134
+ });
135
+ },
136
+ async stop() {
137
+ wss?.close();
138
+ server?.close();
139
+ },
140
+ async send(_chatId, _card) {
141
+ throw new Error('Transport.send not implemented for Web in v0.5.0 (use cardBus.publish)');
142
+ },
143
+ onMessage(h) { messageHandler = h; },
144
+ onCommand() { },
145
+ onButtonClick() { },
146
+ };
147
+ }
148
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transport/web/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,KAAK,EAAmB,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAA;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA;AAK5D,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAIpD,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;AAe/B,MAAM,IAAI,GAAwB;IAChC,IAAI,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,CAAC,iBAAiB;IACtD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI;CAC/C,CAAA;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAuB;IACxD,IAAI,cAAqE,CAAA;IACzE,IAAI,MAA8B,CAAA;IAClC,IAAI,GAAgC,CAAA;IAEpC,OAAO;QACL,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,IAAI;QAClB,KAAK,CAAC,KAAK,CAAC,IAAwB;YAClC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CAAC,8BAA8B,GAAG,CAAC,UAAU,wCAAwC,CAAC,CAAA;YACvG,CAAC;YACD,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAA;YAC/F,MAAM,GAAG,GAAG,WAAW,CAAC;gBACtB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE;gBAC5E,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,cAAc,EAAE,GAAG,CAAC,cAAc;aACnC,CAAC,CAAA;YAEF,oEAAoE;YACpE,sEAAsE;YACtE,mEAAmE;YACnE,mEAAmE;YACnE,GAAG,CAAC,GAAG,CAAC,mBAAmB,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;gBAC7C,MAAM,IAAI,EAAE,CAAA;gBACZ,CAAC,CAAC,MAAM,CAAC,eAAe,EAAE,qCAAqC,CAAC,CAAA;YAClE,CAAC,CAAC,CAAA;YACF,mEAAmE;YACnE,2CAA2C;YAC3C,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;gBACxB,MAAM,IAAI,EAAE,CAAA;gBACZ,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;oBACvD,CAAC,CAAC,MAAM,CAAC,eAAe,EAAE,UAAU,CAAC,CAAA;gBACvC,CAAC;YACH,CAAC,CAAC,CAAA;YACF,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;YAEpD,sEAAsE;YACtE,wEAAwE;YACxE,6DAA6D;YAC7D,sEAAsE;YACtE,sEAAsE;YACtE,qEAAqE;YACrE,sCAAsC;YACtC,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC,CAAA;YACxD,qEAAqE;YACrE,+CAA+C;YAC/C,MAAM,SAAS,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAA;YACtD,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE;gBACjB,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAA;gBACvB,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,IAAI,KAAK,KAAK;oBAAE,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAA;gBACnE,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAC1B,CAAC,CAAC,CAAA;YAEF,wEAAwE;YACxE,uEAAuE;YACvE,sEAAsE;YACtE,yEAAyE;YACzE,yEAAyE;YACzE,wEAAwE;YACxE,gDAAgD;YAChD,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE;gBACrD,MAAM,CAAC,GAAG,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;oBACjF,GAAG,CAAC,IAAI,CAAC,qCAAqC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;oBAC1E,WAAW,CAAC,CAAC,CAAC,CAAA;gBAChB,CAAC,CAAC,CAAA;gBACF,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;YAC7B,CAAC,CAAC,CAGD;YAAC,MAAc,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;gBAC1C,GAAG,CAAC,KAAK,CAAC,mCAAmC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;gBAC3D,YAAY,CAAC,GAAG,EAAE,GAAG,MAAM,GAAG,CAAA,CAAC,CAAC,CAAC,CAAA;YACnC,CAAC,CAAC,CAAA;YAEF,2EAA2E;YAC3E,kDAAkD;YAClD,GAAG,GAAG,IAAI,eAAe,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CACnE;YAAC,MAAc,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,GAAQ,EAAE,MAAW,EAAE,IAAS,EAAE,EAAE;gBACxE,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAA;gBACvC,MAAM,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,yBAAyB,CAAC,CAAA;gBAC/D,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAA;gBACnD,GAAG,CAAC,IAAI,CAAC,2BAA2B,MAAM,CAAC,QAAQ,WAAW,SAAS,kBAAkB,YAAY,EAAE,CAAC,CAAA;gBACxG,IAAI,MAAM,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;oBAC9B,GAAG,CAAC,IAAI,CAAC,mCAAmC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;oBAC9D,MAAM,CAAC,OAAO,EAAE,CAAA;oBAChB,OAAM;gBACR,CAAC;gBACD,0EAA0E;gBAC1E,yEAAyE;gBACzE,IAAI,IAAI,CAAA;gBACR,IAAI,CAAC;oBACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,aAAa,CACjC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAC3D,CAAA;gBACH,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,GAAG,CAAC,IAAI,CAAC,6CAA8C,CAAW,CAAC,OAAO,EAAE,CAAC,CAAA;oBAC7E,MAAM,CAAC,OAAO,EAAE,CAAA;oBAChB,OAAM;gBACR,CAAC;gBACD,IAAI,CAAC,IAAI,EAAE,CAAC;oBACV,GAAG,CAAC,IAAI,CAAC,kDAAkD,SAAS,kBAAkB,YAAY,GAAG,CAAC,CAAA;oBACtG,MAAM,CAAC,OAAO,EAAE,CAAA;oBAChB,OAAM;gBACR,CAAC;gBACD,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,IAAI,MAAM,EAAE,CAAA;gBAC1D,GAAG,CAAC,IAAI,CAAC,wBAAwB,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;gBAChD,GAAI,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE;oBAC3C,GAAG,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAA;oBACtD,KAAK,CAAC,MAAM,CAAC,EAAS,EAAE,MAAM,CAAC,CAAA;oBAC/B,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;wBACxB,IAAI,CAAC;4BAAC,KAAK,CAAC,mBAAmB,CAAC,EAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;wBAAC,CAAC;wBAAC,MAAM,CAAC,CAAA,CAAC;oBACpF,CAAC,CAAC,CAAA;oBACF,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;wBAC9B,GAAG,CAAC,IAAI,CAAC,kBAAkB,IAAI,YAAY,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;wBAChE,KAAK,CAAC,MAAM,CAAC,EAAS,CAAC,CAAA;oBACzB,CAAC,CAAC,CAAA;oBACF,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;gBAC/D,CAAC,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;QACJ,CAAC;QACD,KAAK,CAAC,IAAI;YACR,GAAG,EAAE,KAAK,EAAE,CAAA;YACZ,MAAM,EAAE,KAAK,EAAE,CAAA;QACjB,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,KAAqB;YACvC,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAA;QAC3F,CAAC;QACD,SAAS,CAAC,CAAC,IAAI,cAAc,GAAG,CAAC,CAAA,CAAC,CAAC;QACnC,SAAS,KAAK,CAAC;QACf,aAAa,KAAK,CAAC;KACpB,CAAA;AACH,CAAC"}
@@ -0,0 +1,104 @@
1
+ import { createRemoteJWKSet, jwtVerify } from 'jose';
2
+ function isLoopbackAddr(addr) {
3
+ if (!addr)
4
+ return false;
5
+ // Strip IPv6 prefix
6
+ const clean = addr.replace(/^::ffff:/, '').split('%')[0];
7
+ return clean === '127.0.0.1' || clean === '::1';
8
+ }
9
+ /**
10
+ * Whether dev bypass should grant access for this request.
11
+ *
12
+ * When the real peer address is known, ONLY a loopback peer qualifies — a
13
+ * remote peer must never be bypassed just because the server binds to loopback,
14
+ * otherwise host-header spoofing behind a tunnel (peer is 127.0.0.1 but the
15
+ * real client is remote) would defeat CF Access. Only when the peer address is
16
+ * unavailable (Bun/Nitropack, where raw socket info isn't exposed) do we fall
17
+ * back to opts.host.
18
+ *
19
+ * WARNING: with devBypass on, a same-host cloudflared/quick-tunnel makes ALL
20
+ * remote traffic arrive from 127.0.0.1 — every request looks loopback and auth
21
+ * is silently wide open. Never combine devBypass with a tunnel; a startup
22
+ * warning is logged when devBypass is enabled (see createCfAccessAuth).
23
+ */
24
+ function devBypassAllowed(peer, opts) {
25
+ if (!opts.devBypass)
26
+ return false;
27
+ const peerKnown = peer !== undefined && peer !== '';
28
+ return peerKnown ? isLoopbackAddr(peer) : isLoopbackAddr(opts.host);
29
+ }
30
+ function remoteAddr(c) {
31
+ try {
32
+ // Hono on Node.js / Bun: use raw request socket
33
+ const raw = c.env?.incoming ?? c.req?.raw;
34
+ return raw?.socket?.remoteAddress;
35
+ }
36
+ catch {
37
+ return undefined;
38
+ }
39
+ }
40
+ function extractJwt(headers, query) {
41
+ const header = headers['cf-access-jwt-assertion'];
42
+ if (typeof header === 'string')
43
+ return header;
44
+ if (query) {
45
+ const q = new URLSearchParams(query);
46
+ const j = q.get('cf_access_jwt');
47
+ if (j)
48
+ return j;
49
+ }
50
+ const cookie = headers['cookie'];
51
+ if (typeof cookie === 'string') {
52
+ const m = cookie.match(/CF_Authorization=([^;]+)/);
53
+ if (m)
54
+ return m[1];
55
+ }
56
+ }
57
+ export async function verifyUpgradeJwt(req, opts, jwks) {
58
+ if (devBypassAllowed(req.socket?.remoteAddress, opts)) {
59
+ return { email: opts.devEmail ?? 'dev@localhost', sub: 'dev' };
60
+ }
61
+ const query = req.url?.startsWith('/ws') ? req.url.split('?')[1] : undefined;
62
+ const jwt = extractJwt(req.headers, query);
63
+ if (!jwt)
64
+ return null;
65
+ try {
66
+ const keys = jwks ?? createRemoteJWKSet(new URL(`https://${opts.team}.cloudflareaccess.com/cdn-cgi/access/certs`));
67
+ const { payload } = await jwtVerify(jwt, keys, {
68
+ issuer: `https://${opts.team}.cloudflareaccess.com`,
69
+ audience: opts.aud,
70
+ });
71
+ return { email: payload.email, sub: payload.sub };
72
+ }
73
+ catch {
74
+ return null;
75
+ }
76
+ }
77
+ export function cfAccessMiddleware(opts) {
78
+ const jwksUri = `https://${opts.team}.cloudflareaccess.com/cdn-cgi/access/certs`;
79
+ const issuer = `https://${opts.team}.cloudflareaccess.com`;
80
+ const jwks = createRemoteJWKSet(new URL(jwksUri));
81
+ return async (c, next) => {
82
+ if (devBypassAllowed(remoteAddr(c), opts)) {
83
+ c.set('user', { email: opts.devEmail ?? 'dev@localhost', sub: 'dev' });
84
+ return next();
85
+ }
86
+ // No query-string JWT here: ?cf_access_jwt= on a normal HTTP URL would leak
87
+ // into browser history/referer. It is accepted only on the WS upgrade path
88
+ // (/ws) — see verifyUpgradeJwt — because browsers can't set WS headers.
89
+ const jwt = c.req.header('cf-access-jwt-assertion') ||
90
+ c.req.header('cookie')?.match(/CF_Authorization=([^;]+)/)?.[1];
91
+ if (!jwt) {
92
+ return c.json({ error: 'Unauthorized' }, 401);
93
+ }
94
+ try {
95
+ const { payload } = await jwtVerify(jwt, jwks, { issuer, audience: opts.aud });
96
+ c.set('user', { email: payload.email, sub: payload.sub });
97
+ return next();
98
+ }
99
+ catch {
100
+ return c.json({ error: 'Unauthorized' }, 401);
101
+ }
102
+ };
103
+ }
104
+ //# sourceMappingURL=cf-access.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cf-access.js","sourceRoot":"","sources":["../../../../src/transport/web/middleware/cf-access.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /** Best-effort GET of an opencode raw-config endpoint. Returns {} on any failure. */
2
+ export async function fetchOpencodeConfig(baseUrl, path) {
3
+ if (!baseUrl)
4
+ return {};
5
+ try {
6
+ const res = await fetch(`${baseUrl.replace(/\/+$/, '')}${path}`, { signal: AbortSignal.timeout(5000) });
7
+ if (!res.ok)
8
+ return {};
9
+ return await res.json();
10
+ }
11
+ catch {
12
+ return {};
13
+ }
14
+ }
15
+ //# sourceMappingURL=opencode-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-config.js","sourceRoot":"","sources":["../../../src/transport/web/opencode-config.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAe,EAAE,IAAY;IACrE,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAA;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACvG,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,EAAE,CAAA;QACtB,OAAO,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ export function registerAbort(app, reg, state) {
2
+ app.post('/api/abort', async (c) => {
3
+ const body = await c.req.json().catch(() => ({}));
4
+ if (typeof body.sessionId !== 'string' || !body.sessionId)
5
+ return c.json({ error: 'sessionId required' }, 400);
6
+ const id = state.normalizeSessionId(body.sessionId);
7
+ state.getActiveAbort(id)?.abort();
8
+ await reg.forSession(id).abort(id);
9
+ return c.json({ ok: true });
10
+ });
11
+ }
12
+ //# sourceMappingURL=abort.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abort.js","sourceRoot":"","sources":["../../../../src/transport/web/routes/abort.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,aAAa,CAAC,GAAS,EAAE,GAAoB,EAAE,KAAmB;IAChF,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACjC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAA2B,CAAA;QAC3E,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC9G,MAAM,EAAE,GAAG,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACnD,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAA;QACjC,MAAM,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAClC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ const DECISIONS = ['once', 'always', 'reject'];
2
+ export function registerApproval(app, reg, state) {
3
+ app.post('/api/approval', async (c) => {
4
+ const body = await c.req.json().catch(() => ({}));
5
+ if (typeof body.sessionId !== 'string' || !body.sessionId)
6
+ return c.json({ error: 'sessionId required' }, 400);
7
+ if (typeof body.requestId !== 'string' || !body.requestId)
8
+ return c.json({ error: 'requestId required' }, 400);
9
+ if (!DECISIONS.includes(body.decision))
10
+ return c.json({ error: 'decision must be once|always|reject' }, 400);
11
+ const id = state.normalizeSessionId(body.sessionId);
12
+ await reg.forSession(id).resolvePermission(id, body.requestId, body.decision);
13
+ return c.json({ ok: true });
14
+ });
15
+ }
16
+ //# sourceMappingURL=approval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval.js","sourceRoot":"","sources":["../../../../src/transport/web/routes/approval.ts"],"names":[],"mappings":"AAKA,MAAM,SAAS,GAAyB,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;AAEpE,MAAM,UAAU,gBAAgB,CAAC,GAAS,EAAE,GAAoB,EAAE,KAAmB;IACnF,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACpC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAA8E,CAAA;QAC9H,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC9G,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC9G,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,QAA8B,CAAC;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,qCAAqC,EAAE,EAAE,GAAG,CAAC,CAAA;QAClI,MAAM,EAAE,GAAG,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACnD,MAAM,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,QAA8B,CAAC,CAAA;QACnG,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ export function registerCatalog(app, reg) {
2
+ app.get('/api/agents', async (c) => {
3
+ const b = reg.get(c.req.query('backend') ?? '') ?? reg.active();
4
+ return c.json(await b.getAgents());
5
+ });
6
+ app.get('/api/models', async (c) => {
7
+ const b = reg.get(c.req.query('backend') ?? '') ?? reg.active();
8
+ return c.json(await b.getModels());
9
+ });
10
+ }
11
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../../src/transport/web/routes/catalog.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,eAAe,CAAC,GAAS,EAAE,GAAoB;IAC7D,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACjC,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAA;QAC/D,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,CAAC,CAAA;IACpC,CAAC,CAAC,CAAA;IACF,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACjC,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAA;QAC/D,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,CAAC,CAAA;IACpC,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * M9: bot-channel settings — list + update. `tgStatus` (injected by entry)
3
+ * reports the live Telegram polling state so the web panel can show
4
+ * connected/未绑定 like the ZCode reference.
5
+ */
6
+ export function registerChannels(app, channels, tgStatus) {
7
+ if (!channels)
8
+ return;
9
+ app.get('/api/channels', (c) => {
10
+ const status = tgStatus?.() ?? null;
11
+ return c.json({
12
+ channels: channels.list().map((b) => ({
13
+ ...b,
14
+ live: b.channel === 'telegram' && status ? { connected: status.connected, username: status.username } : null,
15
+ })),
16
+ });
17
+ });
18
+ app.patch('/api/channels/:id', async (c) => {
19
+ const body = (await c.req.json().catch(() => ({})));
20
+ if (body.replyGranularity && body.replyGranularity !== 'standard' && body.replyGranularity !== 'detailed') {
21
+ return c.json({ error: 'replyGranularity must be standard|detailed' }, 400);
22
+ }
23
+ if (body.workspaces && body.workspaces.mode !== 'all' && body.workspaces.mode !== 'custom') {
24
+ return c.json({ error: 'invalid workspaces' }, 400);
25
+ }
26
+ const updated = channels.update(c.req.param('id'), body);
27
+ if (!updated)
28
+ return c.json({ error: 'not found' }, 404);
29
+ return c.json({ channel: updated });
30
+ });
31
+ app.post('/api/channels/:id/reset', (c) => {
32
+ const updated = channels.reset(c.req.param('id'));
33
+ if (!updated)
34
+ return c.json({ error: 'not found' }, 404);
35
+ return c.json({ channel: updated });
36
+ });
37
+ // Pairing QR — the pair URL carries the token in its fragment, so this is
38
+ // only ever rendered inside an already-paired session (same trust model as
39
+ // TG's /pair command).
40
+ app.get('/api/pair/qr', async (c) => {
41
+ try {
42
+ const { buildPairContext } = await import('../../../connectivity/pairing.js');
43
+ const QRCode = (await import('qrcode')).default;
44
+ const { token, url } = await buildPairContext();
45
+ const svg = await QRCode.toString(url, { type: 'svg', margin: 1 });
46
+ return c.json({ url, svg });
47
+ }
48
+ catch (err) {
49
+ return c.json({ error: err.message }, 500);
50
+ }
51
+ });
52
+ }
53
+ //# sourceMappingURL=channels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channels.js","sourceRoot":"","sources":["../../../../src/transport/web/routes/channels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export function registerCommands(app, reg, state) {
2
+ app.get('/api/commands', async (c) => {
3
+ const b = reg.get(c.req.query('backend') ?? '') ?? reg.active();
4
+ return c.json(await b.listCommands());
5
+ });
6
+ app.post('/api/command', async (c) => {
7
+ const body = await c.req.json().catch(() => ({}));
8
+ if (!body.sessionId || !body.command)
9
+ return c.json({ error: 'sessionId and command required' }, 400);
10
+ const id = state.normalizeSessionId(body.sessionId);
11
+ await reg.forSession(id).runCommand(id, body.command, body.arguments);
12
+ return c.json({ ok: true });
13
+ });
14
+ }
15
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../../../src/transport/web/routes/commands.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,gBAAgB,CAAC,GAAS,EAAE,GAAoB,EAAE,KAAmB;IACnF,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACnC,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAA;QAC/D,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,YAAY,EAAE,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IACF,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACnC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAiE,CAAA;QACjH,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gCAAgC,EAAE,EAAE,GAAG,CAAC,CAAA;QACrG,MAAM,EAAE,GAAG,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACnD,MAAM,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;QACrE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ export function registerContext(app, reg, state) {
2
+ app.get('/api/session/:id/context', async (c) => {
3
+ const id = state.normalizeSessionId(c.req.param('id'));
4
+ const ctx = await reg.forSession(id).getContext(id);
5
+ return c.json({
6
+ sessionId: id,
7
+ agent: ctx.agent,
8
+ model: ctx.model,
9
+ tokens: ctx.tokens,
10
+ cost: ctx.cost ?? state.getSessionCost(id),
11
+ directory: ctx.directory,
12
+ nextAgent: state.getNextAgent(),
13
+ nextModel: state.getNextModel(),
14
+ });
15
+ });
16
+ }
17
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../../src/transport/web/routes/context.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,eAAe,CAAC,GAAS,EAAE,GAAoB,EAAE,KAAmB;IAClF,GAAG,CAAC,GAAG,CAAC,0BAA0B,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC9C,MAAM,EAAE,GAAG,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;QACtD,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QACnD,OAAO,CAAC,CAAC,IAAI,CAAC;YACZ,SAAS,EAAE,EAAE;YACb,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;YAC1C,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,SAAS,EAAE,KAAK,CAAC,YAAY,EAAE;YAC/B,SAAS,EAAE,KAAK,CAAC,YAAY,EAAE;SAChC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Session controls — read the switchable mode + model for a session, and switch
3
+ * them. Backed by the optional getControls/setMode/setModel (present only when the
4
+ * backend's `sessionControls` capability is true; ACP/kimi). Missing → 404/empty.
5
+ */
6
+ export function registerControls(app, reg, state) {
7
+ app.get('/api/session/:id/controls', async (c) => {
8
+ const id = state.normalizeSessionId(c.req.param('id'));
9
+ return c.json((await reg.forSession(id).getControls?.(id)) ?? {});
10
+ });
11
+ app.post('/api/session/:id/mode', async (c) => {
12
+ const id = state.normalizeSessionId(c.req.param('id'));
13
+ const { modeId } = await c.req.json().catch(() => ({ modeId: undefined }));
14
+ if (!modeId)
15
+ return c.json({ error: 'modeId required' }, 400);
16
+ const b = reg.forSession(id);
17
+ if (!b.setMode)
18
+ return c.json({ error: 'mode switching not supported' }, 404);
19
+ await b.setMode(id, modeId);
20
+ return c.json({ ok: true });
21
+ });
22
+ app.post('/api/session/:id/model', async (c) => {
23
+ const id = state.normalizeSessionId(c.req.param('id'));
24
+ const { modelId } = await c.req.json().catch(() => ({ modelId: undefined }));
25
+ if (!modelId)
26
+ return c.json({ error: 'modelId required' }, 400);
27
+ const b = reg.forSession(id);
28
+ if (!b.setModel)
29
+ return c.json({ error: 'model switching not supported' }, 404);
30
+ await b.setModel(id, modelId);
31
+ return c.json({ ok: true });
32
+ });
33
+ }
34
+ //# sourceMappingURL=controls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controls.js","sourceRoot":"","sources":["../../../../src/transport/web/routes/controls.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAS,EAAE,GAAoB,EAAE,KAAmB;IACnF,GAAG,CAAC,GAAG,CAAC,2BAA2B,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC/C,MAAM,EAAE,GAAG,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;QACtD,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;IACnE,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC5C,MAAM,EAAE,GAAG,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;QACtD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAuB,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,CAAA;QAC/F,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC7D,MAAM,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QAC5B,IAAI,CAAC,CAAC,CAAC,OAAO;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,EAAE,GAAG,CAAC,CAAA;QAC7E,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;QAC3B,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,IAAI,CAAC,wBAAwB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC7C,MAAM,EAAE,GAAG,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;QACtD,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAwB,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,CAAA;QAClG,IAAI,CAAC,OAAO;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC/D,MAAM,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QAC5B,IAAI,CAAC,CAAC,CAAC,QAAQ;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,+BAA+B,EAAE,EAAE,GAAG,CAAC,CAAA;QAC/E,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;QAC7B,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ export function registerCreateSession(app, reg) {
2
+ app.post('/api/session', async (c) => {
3
+ const body = (await c.req.json().catch(() => ({})));
4
+ const backend = (body.backendId && reg.get(body.backendId)) || reg.active();
5
+ const directory = typeof body.directory === 'string' ? body.directory.trim() : '';
6
+ // Backends that don't enumerate workspaces (e.g. ACP) create in their own
7
+ // default working directory — the directory is optional there.
8
+ if (!directory && backend.capabilities.workspaces) {
9
+ return c.json({ error: 'directory required' }, 400);
10
+ }
11
+ try {
12
+ const { id } = await backend.createSession({ directory, title: body.title });
13
+ reg.tag(id, backend.id);
14
+ return c.json({ id, backendId: backend.id });
15
+ }
16
+ catch {
17
+ return c.json({ error: 'create failed' }, 500);
18
+ }
19
+ });
20
+ }
21
+ //# sourceMappingURL=create-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-session.js","sourceRoot":"","sources":["../../../../src/transport/web/routes/create-session.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,qBAAqB,CAAC,GAAS,EAAE,GAAoB;IACnE,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACnC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAA+D,CAAA;QACjH,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAA;QAC3E,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QACjF,0EAA0E;QAC1E,+DAA+D;QAC/D,IAAI,CAAC,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;YAClD,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAA;QACrD,CAAC;QACD,IAAI,CAAC;YACH,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAA;YAC5E,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;YACvB,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAA;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE,GAAG,CAAC,CAAA;QAChD,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ export function registerDiff(app, reg, state) {
2
+ app.get('/api/session/:id/diff', async (c) => {
3
+ const id = state.normalizeSessionId(c.req.param('id'));
4
+ return c.json(await reg.forSession(id).getDiff(id));
5
+ });
6
+ }
7
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../../src/transport/web/routes/diff.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,YAAY,CAAC,GAAS,EAAE,GAAoB,EAAE,KAAmB;IAC/E,GAAG,CAAC,GAAG,CAAC,uBAAuB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC3C,MAAM,EAAE,GAAG,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;QACtD,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;AACJ,CAAC"}