@jingyi0605/codingns 0.3.6 → 0.5.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 (369) hide show
  1. package/README.md +3 -0
  2. package/bin/codingns.mjs +913 -1
  3. package/dist/public/assets/AdaptiveButlerPage-B153lk5H.css +1 -0
  4. package/dist/public/assets/AdaptiveButlerPage-R-XZw7pd.js +3 -0
  5. package/dist/public/assets/App-DUAg5urj.css +1 -0
  6. package/dist/public/assets/App-DkvE5EyM.js +30 -0
  7. package/dist/public/assets/BootstrapPage-Vu5oEJ8z.js +1 -0
  8. package/dist/public/assets/ConversationPage-Cjpg6g0J.js +2 -0
  9. package/dist/public/assets/DesktopDetachPreviewPage-BgeEqbc5.js +1 -0
  10. package/dist/public/assets/DesktopWindowPage-1WelvxdH.js +2 -0
  11. package/dist/public/assets/FileContextPanel-D_ghXJuW.js +1 -0
  12. package/dist/public/assets/GitSidebar-D9f9Jxwr.js +6 -0
  13. package/dist/public/assets/MobileCreateSessionSheet-DLq5qPkx.js +1 -0
  14. package/dist/public/assets/MobileSheet-DLg-gX1t.js +1 -0
  15. package/dist/public/assets/MobileTopHeaderFrame-DArgZI7L.js +1 -0
  16. package/dist/public/assets/MobileWorkspaceSwitcherHeader-0ywJKfBQ.js +1 -0
  17. package/dist/public/assets/ServerSettingsModal-izoYMx9U.js +1 -0
  18. package/dist/public/assets/SessionIndexPage-C5aG8FIv.js +1 -0
  19. package/dist/public/assets/SettingsPage-HJIC-P-4.js +1 -0
  20. package/dist/public/assets/TerminalManagerPanel-DpyUTo9k.js +1 -0
  21. package/dist/public/assets/{TerminalPage-D00S4KM6.js → TerminalPage-CtKXIU0h.js} +19 -19
  22. package/dist/public/assets/TerminalRuntimeFallbackModal-CRhOQOsT.js +1 -0
  23. package/dist/public/assets/ToolFilesPage-DcYPsS-e.js +1 -0
  24. package/dist/public/assets/ToolGitPage-CsPl89ty.js +1 -0
  25. package/dist/public/assets/ToolProcessesPage-D0dvR8xK.js +1 -0
  26. package/dist/public/assets/ToolsHomePage-4fP-KRiv.js +1 -0
  27. package/dist/public/assets/WorkbenchLandingPage-kvlfyxRo.js +1 -0
  28. package/dist/public/assets/WorkbenchLayout-ByFw4eeu.js +3 -0
  29. package/dist/public/assets/WorkbenchModal-Ctob14VR.js +1 -0
  30. package/dist/public/assets/WorkbenchShellRoute-BUITtdAg.css +1 -0
  31. package/dist/public/assets/WorkbenchShellRoute-Kw7JEZI3.js +1 -0
  32. package/dist/public/assets/WorkspaceDebugDetailPage-Com5kEXJ.js +1 -0
  33. package/dist/public/assets/WorkspaceDetailPage-D0Lrx4Uz.js +1 -0
  34. package/dist/public/assets/WorkspaceHomePage-wR8d3aP9.js +1 -0
  35. package/dist/public/assets/butler-records-events-DgWCG364.js +1 -0
  36. package/dist/public/assets/default-session-permission-mode-CcGwR4Kk.js +1 -0
  37. package/dist/public/assets/event-DvH9tcej.js +1 -0
  38. package/dist/public/assets/file-tree-icon-UFVoVzhM.js +31 -0
  39. package/dist/public/assets/index-Byp9hJ0c.js +42 -0
  40. package/dist/public/assets/index-_52jxu4a.css +1 -0
  41. package/dist/public/assets/preferences-service-KIYeE2gk.js +1 -0
  42. package/dist/public/assets/session-runtime-machine-0KNSSPp5.js +17 -0
  43. package/dist/public/assets/styles-BWPBZvze.css +1 -0
  44. package/dist/public/assets/styles-CSUx5LGe.js +1 -0
  45. package/dist/public/assets/terminal-runtime-meta-AWXJpN4r.js +1 -0
  46. package/dist/public/assets/useRegisteredDebugTemplates-DBDRdptr.js +1 -0
  47. package/dist/public/assets/window-BWqRixxq.js +1 -0
  48. package/dist/public/index.html +2 -2
  49. package/dist/server/middlewares/auth-guard.d.ts +4 -0
  50. package/dist/server/middlewares/auth-guard.js +42 -4
  51. package/dist/server/middlewares/auth-guard.js.map +1 -1
  52. package/dist/server/modules/assistant-capability/assistant-capability-controller.d.ts +234 -0
  53. package/dist/server/modules/assistant-capability/assistant-capability-controller.js +365 -0
  54. package/dist/server/modules/assistant-capability/assistant-capability-controller.js.map +1 -1
  55. package/dist/server/modules/assistant-capability/assistant-capability-service.d.ts +262 -2
  56. package/dist/server/modules/assistant-capability/assistant-capability-service.js +737 -3
  57. package/dist/server/modules/assistant-capability/assistant-capability-service.js.map +1 -1
  58. package/dist/server/modules/auth/auth-controller.d.ts +11 -1
  59. package/dist/server/modules/auth/auth-controller.js +61 -2
  60. package/dist/server/modules/auth/auth-controller.js.map +1 -1
  61. package/dist/server/modules/auth/auth-device-display-name.d.ts +10 -0
  62. package/dist/server/modules/auth/auth-device-display-name.js +190 -0
  63. package/dist/server/modules/auth/auth-device-display-name.js.map +1 -0
  64. package/dist/server/modules/auth/auth-service.d.ts +80 -5
  65. package/dist/server/modules/auth/auth-service.js +333 -23
  66. package/dist/server/modules/auth/auth-service.js.map +1 -1
  67. package/dist/server/modules/butler/assistant-automation-service.d.ts +112 -0
  68. package/dist/server/modules/butler/assistant-automation-service.js +832 -0
  69. package/dist/server/modules/butler/assistant-automation-service.js.map +1 -0
  70. package/dist/server/modules/butler/assistant-automation-trigger.d.ts +94 -0
  71. package/dist/server/modules/butler/assistant-automation-trigger.js +400 -0
  72. package/dist/server/modules/butler/assistant-automation-trigger.js.map +1 -0
  73. package/dist/server/modules/butler/assistant-sandbox-cleanup-scheduler.d.ts +32 -0
  74. package/dist/server/modules/butler/assistant-sandbox-cleanup-scheduler.js +93 -0
  75. package/dist/server/modules/butler/assistant-sandbox-cleanup-scheduler.js.map +1 -0
  76. package/dist/server/modules/butler/assistant-sandbox-service.d.ts +69 -0
  77. package/dist/server/modules/butler/assistant-sandbox-service.js +399 -0
  78. package/dist/server/modules/butler/assistant-sandbox-service.js.map +1 -0
  79. package/dist/server/modules/butler/butler-action-context-service.d.ts +4 -1
  80. package/dist/server/modules/butler/butler-action-context-service.js +8 -2
  81. package/dist/server/modules/butler/butler-action-context-service.js.map +1 -1
  82. package/dist/server/modules/butler/butler-auth-service.js +7 -2
  83. package/dist/server/modules/butler/butler-auth-service.js.map +1 -1
  84. package/dist/server/modules/butler/butler-control-session-service.d.ts +11 -1
  85. package/dist/server/modules/butler/butler-control-session-service.js +173 -40
  86. package/dist/server/modules/butler/butler-control-session-service.js.map +1 -1
  87. package/dist/server/modules/butler/butler-control-timer-scheduler.d.ts +32 -0
  88. package/dist/server/modules/butler/butler-control-timer-scheduler.js +93 -0
  89. package/dist/server/modules/butler/butler-control-timer-scheduler.js.map +1 -0
  90. package/dist/server/modules/butler/butler-control-timer-service.d.ts +42 -0
  91. package/dist/server/modules/butler/butler-control-timer-service.js +132 -0
  92. package/dist/server/modules/butler/butler-control-timer-service.js.map +1 -0
  93. package/dist/server/modules/butler/butler-controller.d.ts +42 -2
  94. package/dist/server/modules/butler/butler-controller.js +79 -12
  95. package/dist/server/modules/butler/butler-controller.js.map +1 -1
  96. package/dist/server/modules/butler/butler-follow-up-evaluation-instruction-adapter.d.ts +2 -1
  97. package/dist/server/modules/butler/butler-follow-up-evaluation-instruction-adapter.js +27 -25
  98. package/dist/server/modules/butler/butler-follow-up-evaluation-instruction-adapter.js.map +1 -1
  99. package/dist/server/modules/butler/butler-follow-up-service.d.ts +41 -5
  100. package/dist/server/modules/butler/butler-follow-up-service.js +568 -371
  101. package/dist/server/modules/butler/butler-follow-up-service.js.map +1 -1
  102. package/dist/server/modules/butler/butler-inbox-analysis-service.d.ts +4 -1
  103. package/dist/server/modules/butler/butler-inbox-analysis-service.js +18 -4
  104. package/dist/server/modules/butler/butler-inbox-analysis-service.js.map +1 -1
  105. package/dist/server/modules/butler/butler-inbox-service.js +1 -0
  106. package/dist/server/modules/butler/butler-inbox-service.js.map +1 -1
  107. package/dist/server/modules/butler/butler-profile-service.js +2 -5
  108. package/dist/server/modules/butler/butler-profile-service.js.map +1 -1
  109. package/dist/server/modules/butler/butler-project-service.d.ts +3 -1
  110. package/dist/server/modules/butler/butler-project-service.js +7 -1
  111. package/dist/server/modules/butler/butler-project-service.js.map +1 -1
  112. package/dist/server/modules/butler/butler-session-service.d.ts +5 -1
  113. package/dist/server/modules/butler/butler-session-service.js +26 -1
  114. package/dist/server/modules/butler/butler-session-service.js.map +1 -1
  115. package/dist/server/modules/butler/butler-session-summary-service.js +2 -1
  116. package/dist/server/modules/butler/butler-session-summary-service.js.map +1 -1
  117. package/dist/server/modules/butler/butler-workspace-context.d.ts +4 -1
  118. package/dist/server/modules/butler/butler-workspace-context.js +204 -58
  119. package/dist/server/modules/butler/butler-workspace-context.js.map +1 -1
  120. package/dist/server/modules/butler/patrol-execution-service.js +2 -1
  121. package/dist/server/modules/butler/patrol-execution-service.js.map +1 -1
  122. package/dist/server/modules/butler/provider-adapter-registry.d.ts +3 -0
  123. package/dist/server/modules/butler/provider-adapter-registry.js +18 -1
  124. package/dist/server/modules/butler/provider-adapter-registry.js.map +1 -1
  125. package/dist/server/modules/butler/verification-run-service.d.ts +9 -2
  126. package/dist/server/modules/butler/verification-run-service.js +188 -34
  127. package/dist/server/modules/butler/verification-run-service.js.map +1 -1
  128. package/dist/server/modules/debug-target/debug-target-controller.js +1 -1
  129. package/dist/server/modules/debug-target/debug-target-controller.js.map +1 -1
  130. package/dist/server/modules/debug-target/debug-target-service.d.ts +7 -2
  131. package/dist/server/modules/debug-target/debug-target-service.js +563 -100
  132. package/dist/server/modules/debug-target/debug-target-service.js.map +1 -1
  133. package/dist/server/modules/git/git-command-helper-client.d.ts +1 -0
  134. package/dist/server/modules/git/git-command-helper-client.js +19 -26
  135. package/dist/server/modules/git/git-command-helper-client.js.map +1 -1
  136. package/dist/server/modules/git/git-command-runner.js +19 -1
  137. package/dist/server/modules/git/git-command-runner.js.map +1 -1
  138. package/dist/server/modules/preferences/profile-service.d.ts +3 -1
  139. package/dist/server/modules/preferences/profile-service.js +74 -3
  140. package/dist/server/modules/preferences/profile-service.js.map +1 -1
  141. package/dist/server/modules/provider/provider-controller.d.ts +1 -1
  142. package/dist/server/modules/provider/provider-controller.js.map +1 -1
  143. package/dist/server/modules/provider/provider-discovery-helper-client.d.ts +5 -3
  144. package/dist/server/modules/provider/provider-discovery-helper-client.js +129 -43
  145. package/dist/server/modules/provider/provider-discovery-helper-client.js.map +1 -1
  146. package/dist/server/modules/provider/provider-discovery-helper-process.js +44 -0
  147. package/dist/server/modules/provider/provider-discovery-helper-process.js.map +1 -1
  148. package/dist/server/modules/provider/provider-discovery-runtime.js +83 -3
  149. package/dist/server/modules/provider/provider-discovery-runtime.js.map +1 -1
  150. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-identity-service.d.ts +10 -0
  151. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-identity-service.js +48 -0
  152. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-identity-service.js.map +1 -0
  153. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-packets.d.ts +48 -0
  154. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-packets.js +11 -0
  155. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-packets.js.map +1 -0
  156. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-protocol.d.ts +74 -0
  157. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-protocol.js +302 -0
  158. package/dist/server/modules/relay-tunnel/crypto/relay-tunnel-protocol.js.map +1 -0
  159. package/dist/server/modules/relay-tunnel/relay-tunnel-controller.d.ts +33 -0
  160. package/dist/server/modules/relay-tunnel/relay-tunnel-controller.js +57 -0
  161. package/dist/server/modules/relay-tunnel/relay-tunnel-controller.js.map +1 -0
  162. package/dist/server/modules/relay-tunnel/relay-tunnel-edge-proof.d.ts +9 -0
  163. package/dist/server/modules/relay-tunnel/relay-tunnel-edge-proof.js +25 -0
  164. package/dist/server/modules/relay-tunnel/relay-tunnel-edge-proof.js.map +1 -0
  165. package/dist/server/modules/relay-tunnel/relay-tunnel-gateway-service.d.ts +18 -0
  166. package/dist/server/modules/relay-tunnel/relay-tunnel-gateway-service.js +230 -0
  167. package/dist/server/modules/relay-tunnel/relay-tunnel-gateway-service.js.map +1 -0
  168. package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.d.ts +41 -0
  169. package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.js +443 -0
  170. package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.js.map +1 -0
  171. package/dist/server/modules/relay-tunnel/relay-tunnel-service.d.ts +111 -0
  172. package/dist/server/modules/relay-tunnel/relay-tunnel-service.js +771 -0
  173. package/dist/server/modules/relay-tunnel/relay-tunnel-service.js.map +1 -0
  174. package/dist/server/modules/sessions/claude-runtime-helper-client.js +23 -1
  175. package/dist/server/modules/sessions/claude-runtime-helper-client.js.map +1 -1
  176. package/dist/server/modules/sessions/codex-app-server-helper-client.d.ts +2 -1
  177. package/dist/server/modules/sessions/codex-app-server-helper-client.js +78 -0
  178. package/dist/server/modules/sessions/codex-app-server-helper-client.js.map +1 -1
  179. package/dist/server/modules/sessions/codex-app-server-helper-process.js +84 -2
  180. package/dist/server/modules/sessions/codex-app-server-helper-process.js.map +1 -1
  181. package/dist/server/modules/sessions/provider-session-delete-cli.d.ts +15 -0
  182. package/dist/server/modules/sessions/provider-session-delete-cli.js +148 -0
  183. package/dist/server/modules/sessions/provider-session-delete-cli.js.map +1 -0
  184. package/dist/server/modules/sessions/session-controller.d.ts +4 -1
  185. package/dist/server/modules/sessions/session-controller.js +4 -0
  186. package/dist/server/modules/sessions/session-controller.js.map +1 -1
  187. package/dist/server/modules/sessions/session-history-service.d.ts +24 -1
  188. package/dist/server/modules/sessions/session-history-service.js +401 -42
  189. package/dist/server/modules/sessions/session-history-service.js.map +1 -1
  190. package/dist/server/modules/sessions/session-live-runtime-router-service.d.ts +25 -0
  191. package/dist/server/modules/sessions/session-live-runtime-router-service.js +42 -0
  192. package/dist/server/modules/sessions/session-live-runtime-router-service.js.map +1 -0
  193. package/dist/server/modules/sessions/session-live-runtime-service.d.ts +6 -0
  194. package/dist/server/modules/sessions/session-live-runtime-service.js +130 -28
  195. package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
  196. package/dist/server/modules/sessions/session-message-attachment-service.d.ts +1 -0
  197. package/dist/server/modules/sessions/session-message-attachment-service.js +22 -0
  198. package/dist/server/modules/sessions/session-message-attachment-service.js.map +1 -1
  199. package/dist/server/modules/sessions/session-message-origin-utils.d.ts +12 -0
  200. package/dist/server/modules/sessions/session-message-origin-utils.js +45 -0
  201. package/dist/server/modules/sessions/session-message-origin-utils.js.map +1 -0
  202. package/dist/server/modules/sessions/session-permission-request-service.d.ts +1 -0
  203. package/dist/server/modules/sessions/session-permission-request-service.js +367 -5
  204. package/dist/server/modules/sessions/session-permission-request-service.js.map +1 -1
  205. package/dist/server/modules/sessions/session-provider-error-mapper.js +32 -0
  206. package/dist/server/modules/sessions/session-provider-error-mapper.js.map +1 -1
  207. package/dist/server/modules/sessions/session-provider-usage-guard-service.d.ts +37 -0
  208. package/dist/server/modules/sessions/session-provider-usage-guard-service.js +179 -0
  209. package/dist/server/modules/sessions/session-provider-usage-guard-service.js.map +1 -0
  210. package/dist/server/modules/sessions/session-provider-usage-limit.d.ts +17 -0
  211. package/dist/server/modules/sessions/session-provider-usage-limit.js +465 -0
  212. package/dist/server/modules/sessions/session-provider-usage-limit.js.map +1 -0
  213. package/dist/server/modules/skills/assistant-runtime-skill-catalog.d.ts +8 -0
  214. package/dist/server/modules/skills/assistant-runtime-skill-catalog.js +26 -0
  215. package/dist/server/modules/skills/assistant-runtime-skill-catalog.js.map +1 -0
  216. package/dist/server/modules/skills/assistant-runtime-skill-cleanup.d.ts +9 -0
  217. package/dist/server/modules/skills/assistant-runtime-skill-cleanup.js +55 -0
  218. package/dist/server/modules/skills/assistant-runtime-skill-cleanup.js.map +1 -0
  219. package/dist/server/modules/skills/builtin-skill-service.js +1 -6
  220. package/dist/server/modules/skills/builtin-skill-service.js.map +1 -1
  221. package/dist/server/modules/skills/builtin-skills/codingns-assistant/SKILL.md +19 -12
  222. package/dist/server/modules/skills/builtin-skills/codingns-assistant/references/cli-workflow.md +9 -3
  223. package/dist/server/modules/skills/skill-controller.d.ts +2 -2
  224. package/dist/server/modules/skills/skill-controller.js +9 -1
  225. package/dist/server/modules/skills/skill-controller.js.map +1 -1
  226. package/dist/server/modules/skills/skill-manager-service.d.ts +26 -1
  227. package/dist/server/modules/skills/skill-manager-service.js +346 -90
  228. package/dist/server/modules/skills/skill-manager-service.js.map +1 -1
  229. package/dist/server/modules/skills/skill-name-policy.d.ts +2 -0
  230. package/dist/server/modules/skills/skill-name-policy.js +10 -0
  231. package/dist/server/modules/skills/skill-name-policy.js.map +1 -0
  232. package/dist/server/modules/tailscale/tailscale-service.d.ts +2 -0
  233. package/dist/server/modules/tailscale/tailscale-service.js +21 -8
  234. package/dist/server/modules/tailscale/tailscale-service.js.map +1 -1
  235. package/dist/server/modules/tasks/task-helper-client.d.ts +5 -2
  236. package/dist/server/modules/tasks/task-helper-client.js +118 -38
  237. package/dist/server/modules/tasks/task-helper-client.js.map +1 -1
  238. package/dist/server/modules/tasks/task-helper-process.js +94 -3
  239. package/dist/server/modules/tasks/task-helper-process.js.map +1 -1
  240. package/dist/server/modules/tasks/task-types.d.ts +6 -0
  241. package/dist/server/modules/tasks/task-types.js +7 -1
  242. package/dist/server/modules/tasks/task-types.js.map +1 -1
  243. package/dist/server/modules/terminal/command-template-service.d.ts +9 -0
  244. package/dist/server/modules/terminal/command-template-service.js +87 -5
  245. package/dist/server/modules/terminal/command-template-service.js.map +1 -1
  246. package/dist/server/modules/terminal/template-reverse-proxy-service.js +71 -3
  247. package/dist/server/modules/terminal/template-reverse-proxy-service.js.map +1 -1
  248. package/dist/server/modules/terminal/terminal-controller.d.ts +3 -0
  249. package/dist/server/modules/terminal/terminal-controller.js +41 -0
  250. package/dist/server/modules/terminal/terminal-controller.js.map +1 -1
  251. package/dist/server/modules/workbench/workbench-service.d.ts +3 -0
  252. package/dist/server/modules/workbench/workbench-service.js +4 -3
  253. package/dist/server/modules/workbench/workbench-service.js.map +1 -1
  254. package/dist/server/modules/workbench/workspace-file-watcher.d.ts +14 -6
  255. package/dist/server/modules/workbench/workspace-file-watcher.js +267 -57
  256. package/dist/server/modules/workbench/workspace-file-watcher.js.map +1 -1
  257. package/dist/server/modules/workbench/workspace-panel-snapshot-service.d.ts +2 -0
  258. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js +32 -3
  259. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js.map +1 -1
  260. package/dist/server/modules/worktree/worktree-manager.d.ts +9 -1
  261. package/dist/server/modules/worktree/worktree-manager.js +9 -1
  262. package/dist/server/modules/worktree/worktree-manager.js.map +1 -1
  263. package/dist/server/routes/assistant.js +49 -0
  264. package/dist/server/routes/assistant.js.map +1 -1
  265. package/dist/server/routes/auth.js +4 -0
  266. package/dist/server/routes/auth.js.map +1 -1
  267. package/dist/server/routes/butler.js +5 -0
  268. package/dist/server/routes/butler.js.map +1 -1
  269. package/dist/server/routes/sessions.js +1 -0
  270. package/dist/server/routes/sessions.js.map +1 -1
  271. package/dist/server/routes/system.d.ts +2 -1
  272. package/dist/server/routes/system.js +13 -1
  273. package/dist/server/routes/system.js.map +1 -1
  274. package/dist/server/server/create-server.d.ts +18 -0
  275. package/dist/server/server/create-server.js +113 -20
  276. package/dist/server/server/create-server.js.map +1 -1
  277. package/dist/server/shared/utils/tokens.d.ts +3 -1
  278. package/dist/server/shared/utils/tokens.js +9 -2
  279. package/dist/server/shared/utils/tokens.js.map +1 -1
  280. package/dist/server/storage/repositories/assistant-automation-run-repository.d.ts +12 -0
  281. package/dist/server/storage/repositories/assistant-automation-run-repository.js +139 -0
  282. package/dist/server/storage/repositories/assistant-automation-run-repository.js.map +1 -0
  283. package/dist/server/storage/repositories/assistant-automation-task-repository.d.ts +17 -0
  284. package/dist/server/storage/repositories/assistant-automation-task-repository.js +179 -0
  285. package/dist/server/storage/repositories/assistant-automation-task-repository.js.map +1 -0
  286. package/dist/server/storage/repositories/assistant-sandbox-workspace-repository.d.ts +18 -0
  287. package/dist/server/storage/repositories/assistant-sandbox-workspace-repository.js +191 -0
  288. package/dist/server/storage/repositories/assistant-sandbox-workspace-repository.js.map +1 -0
  289. package/dist/server/storage/repositories/auth-device-repository.d.ts +22 -0
  290. package/dist/server/storage/repositories/auth-device-repository.js +97 -0
  291. package/dist/server/storage/repositories/auth-device-repository.js.map +1 -0
  292. package/dist/server/storage/repositories/auth-device-session-repository.d.ts +17 -0
  293. package/dist/server/storage/repositories/auth-device-session-repository.js +82 -0
  294. package/dist/server/storage/repositories/auth-device-session-repository.js.map +1 -0
  295. package/dist/server/storage/repositories/auth-login-event-repository.d.ts +9 -0
  296. package/dist/server/storage/repositories/auth-login-event-repository.js +53 -0
  297. package/dist/server/storage/repositories/auth-login-event-repository.js.map +1 -0
  298. package/dist/server/storage/repositories/auth-token-repository.d.ts +4 -0
  299. package/dist/server/storage/repositories/auth-token-repository.js +58 -5
  300. package/dist/server/storage/repositories/auth-token-repository.js.map +1 -1
  301. package/dist/server/storage/repositories/butler-control-session-repository.js +27 -3
  302. package/dist/server/storage/repositories/butler-control-session-repository.js.map +1 -1
  303. package/dist/server/storage/repositories/butler-control-timer-repository.d.ts +15 -0
  304. package/dist/server/storage/repositories/butler-control-timer-repository.js +157 -0
  305. package/dist/server/storage/repositories/butler-control-timer-repository.js.map +1 -0
  306. package/dist/server/storage/repositories/butler-follow-up-task-repository.js +21 -3
  307. package/dist/server/storage/repositories/butler-follow-up-task-repository.js.map +1 -1
  308. package/dist/server/storage/repositories/instance-relay-tunnel-identity-repository.d.ts +8 -0
  309. package/dist/server/storage/repositories/instance-relay-tunnel-identity-repository.js +52 -0
  310. package/dist/server/storage/repositories/instance-relay-tunnel-identity-repository.js.map +1 -0
  311. package/dist/server/storage/repositories/instance-relay-tunnel-repository.d.ts +10 -0
  312. package/dist/server/storage/repositories/instance-relay-tunnel-repository.js +153 -0
  313. package/dist/server/storage/repositories/instance-relay-tunnel-repository.js.map +1 -0
  314. package/dist/server/storage/repositories/instance-tailscale-repository.js +6 -3
  315. package/dist/server/storage/repositories/instance-tailscale-repository.js.map +1 -1
  316. package/dist/server/storage/repositories/managed-skill-repository.d.ts +2 -1
  317. package/dist/server/storage/repositories/managed-skill-repository.js +14 -4
  318. package/dist/server/storage/repositories/managed-skill-repository.js.map +1 -1
  319. package/dist/server/storage/repositories/session-message-attachment-repository.d.ts +2 -0
  320. package/dist/server/storage/repositories/session-message-attachment-repository.js +24 -0
  321. package/dist/server/storage/repositories/session-message-attachment-repository.js.map +1 -1
  322. package/dist/server/storage/repositories/user-preference-profile-repository.js +6 -3
  323. package/dist/server/storage/repositories/user-preference-profile-repository.js.map +1 -1
  324. package/dist/server/storage/sqlite/client.js +534 -2
  325. package/dist/server/storage/sqlite/client.js.map +1 -1
  326. package/dist/server/storage/sqlite/schema.sql +228 -4
  327. package/dist/server/types/domain.d.ts +170 -2
  328. package/dist/server/ws/workbench-ws-hub.d.ts +14 -8
  329. package/dist/server/ws/workbench-ws-hub.js +369 -209
  330. package/dist/server/ws/workbench-ws-hub.js.map +1 -1
  331. package/dist/server/ws/ws-auth-guard.js +1 -4
  332. package/dist/server/ws/ws-auth-guard.js.map +1 -1
  333. package/dist/server/ws/ws-server.d.ts +1 -1
  334. package/dist/server/ws/ws-server.js.map +1 -1
  335. package/node_modules/@codingns/session-sync-core/dist/codex-resume-history.d.ts +1 -0
  336. package/node_modules/@codingns/session-sync-core/dist/codex-resume-history.js +80 -0
  337. package/node_modules/@codingns/session-sync-core/dist/codex-resume-history.js.map +1 -0
  338. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.d.ts +5 -1
  339. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js +122 -4
  340. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js.map +1 -1
  341. package/node_modules/@codingns/session-sync-core/dist/providers/codex.d.ts +17 -1
  342. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +437 -51
  343. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
  344. package/node_modules/@codingns/session-sync-core/dist/providers/gemini.d.ts +7 -1
  345. package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js +240 -27
  346. package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js.map +1 -1
  347. package/node_modules/@codingns/session-sync-core/dist/providers/kimi.d.ts +5 -1
  348. package/node_modules/@codingns/session-sync-core/dist/providers/kimi.js +108 -2
  349. package/node_modules/@codingns/session-sync-core/dist/providers/kimi.js.map +1 -1
  350. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.d.ts +3 -0
  351. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js +101 -8
  352. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js.map +1 -1
  353. package/node_modules/@codingns/session-sync-core/dist/providers/utils.d.ts +1 -0
  354. package/node_modules/@codingns/session-sync-core/dist/providers/utils.js +4 -1
  355. package/node_modules/@codingns/session-sync-core/dist/providers/utils.js.map +1 -1
  356. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js +44 -0
  357. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js.map +1 -1
  358. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.d.ts +5 -1
  359. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +153 -60
  360. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
  361. package/node_modules/@codingns/session-sync-core/dist/runtime/types.d.ts +1 -0
  362. package/node_modules/@codingns/session-sync-core/dist/services.d.ts +1 -0
  363. package/node_modules/@codingns/session-sync-core/dist/services.js +24 -8
  364. package/node_modules/@codingns/session-sync-core/dist/services.js.map +1 -1
  365. package/node_modules/@codingns/session-sync-core/dist/types.d.ts +6 -0
  366. package/package.json +1 -1
  367. package/scripts/postinstall.mjs +0 -33
  368. package/dist/public/assets/index-BlOinYqR.js +0 -122
  369. package/dist/public/assets/index-Dg_7g6lA.css +0 -1
@@ -0,0 +1,771 @@
1
+ import { AppError } from "../../shared/errors/app-error.js";
2
+ import { decryptSecret, encryptSecret } from "../../shared/utils/secret-box.js";
3
+ import { nowIso } from "../../shared/utils/time.js";
4
+ import { RelayTunnelIdentityService } from "./crypto/relay-tunnel-identity-service.js";
5
+ import { createTaskManager } from "../tasks/task-manager.js";
6
+ import { HOST_TASK_TYPES } from "../tasks/task-types.js";
7
+ export class RelayTunnelService {
8
+ db;
9
+ bootstrapStateRepository;
10
+ repository;
11
+ defaultLocalTargetBaseUrl;
12
+ legacyLocalTargetBaseUrl;
13
+ controlSessionSecret;
14
+ fetchFn;
15
+ taskManager;
16
+ runtimeAdapter;
17
+ identityService;
18
+ constructor(db, bootstrapStateRepository, identityRepository, repository, options, taskManager = createTaskManager(), runtimeAdapter = new NoopRelayTunnelRuntimeAdapter()) {
19
+ this.db = db;
20
+ this.bootstrapStateRepository = bootstrapStateRepository;
21
+ this.repository = repository;
22
+ this.taskManager = taskManager;
23
+ this.runtimeAdapter = runtimeAdapter;
24
+ this.identityService = new RelayTunnelIdentityService(identityRepository);
25
+ this.controlSessionSecret = normalizeRequiredText(options.controlSessionSecret, "controlSessionSecret");
26
+ this.fetchFn = options.fetchFn ?? fetch;
27
+ this.defaultLocalTargetBaseUrl = normalizeHttpBaseUrl(options.defaultLocalTargetBaseUrl, "defaultLocalTargetBaseUrl");
28
+ this.legacyLocalTargetBaseUrl = options.legacyLocalTargetBaseUrl
29
+ ? normalizeHttpBaseUrl(options.legacyLocalTargetBaseUrl, "legacyLocalTargetBaseUrl")
30
+ : null;
31
+ this.registerBackgroundTasks();
32
+ }
33
+ async restoreOnStartup() {
34
+ const snapshot = this.readStateSnapshot();
35
+ if (!snapshot.hasPersistedConfig
36
+ || !snapshot.config.activated
37
+ || !snapshot.config.enabled
38
+ || !isBound(snapshot.config)) {
39
+ return;
40
+ }
41
+ const effectiveConfig = this.syncIdentityIntoConfig(snapshot.config);
42
+ if (!this.isBootstrapInitialized()) {
43
+ this.repository.upsertStatus(buildSkeletonStatus("blocked_uninitialized", effectiveConfig, {
44
+ observedAt: nowIso()
45
+ }));
46
+ return;
47
+ }
48
+ this.requestReconnect("relay_tunnel.startup_restore");
49
+ }
50
+ async getStatus() {
51
+ const snapshot = this.readStateSnapshot();
52
+ const effectiveConfig = this.resolveConfigWithIdentity(snapshot.config);
53
+ return this.buildStatusDto(snapshot, effectiveConfig, this.resolveEffectiveStatus(effectiveConfig));
54
+ }
55
+ async ensureIdentity() {
56
+ const snapshot = this.readStateSnapshot();
57
+ const nextConfig = this.syncIdentityIntoConfig(snapshot.config);
58
+ return this.buildStatusDto({
59
+ config: nextConfig,
60
+ hasPersistedConfig: snapshot.hasPersistedConfig || nextConfig !== snapshot.config
61
+ }, nextConfig, this.resolveEffectiveStatus(nextConfig));
62
+ }
63
+ async updateConfig(input) {
64
+ const snapshot = this.readStateSnapshot();
65
+ const nextConfig = {
66
+ ...snapshot.config,
67
+ activated: input.activated !== undefined
68
+ ? input.activated
69
+ : snapshot.config.activated,
70
+ relayBaseUrl: input.relayBaseUrl !== undefined
71
+ ? normalizeWebsocketBaseUrl(input.relayBaseUrl, "relayBaseUrl")
72
+ : snapshot.config.relayBaseUrl,
73
+ controlBaseUrl: input.controlBaseUrl !== undefined
74
+ ? normalizeHttpBaseUrl(input.controlBaseUrl, "controlBaseUrl")
75
+ : snapshot.config.controlBaseUrl,
76
+ localTargetBaseUrl: input.localTargetBaseUrl !== undefined
77
+ ? normalizeHttpBaseUrl(input.localTargetBaseUrl, "localTargetBaseUrl")
78
+ : snapshot.config.localTargetBaseUrl,
79
+ localTargetBaseUrlSource: input.localTargetBaseUrl !== undefined
80
+ ? "custom"
81
+ : (snapshot.config.localTargetBaseUrlSource ?? "default"),
82
+ enabled: input.activated === false
83
+ ? false
84
+ : snapshot.config.enabled,
85
+ updatedAt: nowIso()
86
+ };
87
+ this.repository.upsertConfig(nextConfig);
88
+ const effectiveConfig = this.resolveConfigWithIdentity(nextConfig);
89
+ if (!effectiveConfig.activated) {
90
+ const nextStatus = buildSkeletonStatus("disabled", effectiveConfig, {
91
+ observedAt: nowIso()
92
+ });
93
+ this.repository.upsertStatus(nextStatus);
94
+ this.taskManager.cancel(HOST_TASK_TYPES.relayTunnelConnect, "default", "relay_tunnel_deactivated");
95
+ await this.runtimeAdapter.disconnect?.("relay_tunnel_deactivated");
96
+ return this.buildStatusDto({
97
+ config: effectiveConfig,
98
+ hasPersistedConfig: true
99
+ }, effectiveConfig, nextStatus);
100
+ }
101
+ if (effectiveConfig.enabled && isBound(effectiveConfig) && this.isBootstrapInitialized()) {
102
+ this.requestReconnect("relay_tunnel.config_update");
103
+ }
104
+ return this.buildStatusDto({
105
+ config: effectiveConfig,
106
+ hasPersistedConfig: true
107
+ }, effectiveConfig, this.resolveEffectiveStatus(effectiveConfig));
108
+ }
109
+ async loginControl(input) {
110
+ const snapshot = this.readStateSnapshot();
111
+ const controlBaseUrl = requireConfiguredControlBaseUrl(snapshot.config);
112
+ const email = normalizeRequiredText(input.email, "email");
113
+ const password = normalizeRequiredText(input.password, "password");
114
+ const response = await this.requestControlApi({
115
+ controlBaseUrl,
116
+ path: "/api/public/auth/login",
117
+ method: "POST",
118
+ headers: {
119
+ "Content-Type": "application/json"
120
+ },
121
+ body: JSON.stringify({
122
+ email,
123
+ password
124
+ }),
125
+ failurePrefix: "控制站登录失败"
126
+ });
127
+ const timestamp = nowIso();
128
+ const nextConfig = {
129
+ ...snapshot.config,
130
+ accountId: response.account.accountId,
131
+ controlAccessTokenCiphertext: encryptSecret(this.controlSessionSecret, response.accessToken),
132
+ controlAccountEmail: response.account.email.trim(),
133
+ controlSessionExpiresAt: normalizeOptionalText(response.expiresAt),
134
+ updatedAt: timestamp
135
+ };
136
+ this.repository.upsertConfig(nextConfig);
137
+ return this.buildStatusDto({
138
+ config: nextConfig,
139
+ hasPersistedConfig: true
140
+ }, this.resolveConfigWithIdentity(nextConfig), this.resolveEffectiveStatus(nextConfig));
141
+ }
142
+ async logoutControl() {
143
+ const snapshot = this.readStateSnapshot();
144
+ const nextConfig = clearRelayTunnelControlSession(snapshot.config, {
145
+ clearAccountId: !snapshot.config.bindingId,
146
+ updatedAt: nowIso()
147
+ });
148
+ this.repository.upsertConfig(nextConfig);
149
+ return this.buildStatusDto({
150
+ config: nextConfig,
151
+ hasPersistedConfig: true
152
+ }, this.resolveConfigWithIdentity(nextConfig), this.resolveEffectiveStatus(nextConfig));
153
+ }
154
+ async checkHostLabelAvailability(hostLabel) {
155
+ const snapshot = this.readStateSnapshot();
156
+ const normalizedHostLabel = normalizeRequiredText(hostLabel, "hostLabel");
157
+ const { controlBaseUrl, accessToken } = this.requireControlSession(snapshot.config);
158
+ const path = `/api/v1/hosts/availability?hostLabel=${encodeURIComponent(normalizedHostLabel)}`;
159
+ return await this.requestControlApi({
160
+ controlBaseUrl,
161
+ path,
162
+ method: "GET",
163
+ headers: {
164
+ Authorization: `Bearer ${accessToken}`
165
+ },
166
+ failurePrefix: "检查 Host 名称失败"
167
+ });
168
+ }
169
+ async bindControlHost(hostLabel) {
170
+ const snapshot = this.readStateSnapshot();
171
+ if (snapshot.config.bindingId && snapshot.config.tunnelDomain) {
172
+ const effectiveConfig = this.resolveConfigWithIdentity(snapshot.config);
173
+ return this.buildStatusDto(snapshot, effectiveConfig, this.resolveEffectiveStatus(effectiveConfig));
174
+ }
175
+ const normalizedHostLabel = normalizeRequiredText(hostLabel, "hostLabel");
176
+ const { controlBaseUrl, accessToken, accountId } = this.requireControlSession(snapshot.config);
177
+ const identity = this.identityService.ensureIdentity();
178
+ const bindResponse = await this.requestControlApi({
179
+ controlBaseUrl,
180
+ path: "/api/v1/hosts/bind",
181
+ method: "POST",
182
+ headers: {
183
+ "Content-Type": "application/json",
184
+ Authorization: `Bearer ${accessToken}`
185
+ },
186
+ body: JSON.stringify({
187
+ hostLabel: normalizedHostLabel,
188
+ hostPublicKey: identity.publicKeyPem,
189
+ hostFingerprint: identity.keyFingerprint
190
+ }),
191
+ failurePrefix: "绑定 Host 失败"
192
+ });
193
+ return await this.bind({
194
+ accountId,
195
+ bindingId: bindResponse.binding.bindingId,
196
+ tunnelDomain: bindResponse.binding.tunnelDomain,
197
+ relayBaseUrl: bindResponse.binding.relayBaseUrl,
198
+ controlBaseUrl
199
+ });
200
+ }
201
+ async getTrafficWallet() {
202
+ const snapshot = this.readStateSnapshot();
203
+ const { controlBaseUrl, accessToken } = this.requireControlSession(snapshot.config);
204
+ const response = await this.requestControlApi({
205
+ controlBaseUrl,
206
+ path: "/api/v1/traffic-wallet/me",
207
+ method: "GET",
208
+ headers: {
209
+ Authorization: `Bearer ${accessToken}`
210
+ },
211
+ failurePrefix: "读取控制站流量信息失败"
212
+ });
213
+ return response.wallet;
214
+ }
215
+ async bind(input) {
216
+ const snapshot = this.readStateSnapshot();
217
+ const accountId = normalizeRequiredText(input.accountId, "accountId");
218
+ const bindingId = normalizeRequiredText(input.bindingId, "bindingId");
219
+ const tunnelDomain = normalizeTunnelDomain(input.tunnelDomain, "tunnelDomain");
220
+ const identity = this.identityService.ensureIdentity();
221
+ const relayBaseUrl = input.relayBaseUrl !== undefined
222
+ ? normalizeWebsocketBaseUrl(input.relayBaseUrl, "relayBaseUrl")
223
+ : snapshot.config.relayBaseUrl;
224
+ const controlBaseUrl = input.controlBaseUrl !== undefined
225
+ ? normalizeHttpBaseUrl(input.controlBaseUrl, "controlBaseUrl")
226
+ : snapshot.config.controlBaseUrl;
227
+ if (!relayBaseUrl || !controlBaseUrl) {
228
+ throw new AppError({
229
+ statusCode: 400,
230
+ errorCode: "INVALID_INPUT",
231
+ detail: "绑定前必须提供 relayBaseUrl 和 controlBaseUrl"
232
+ });
233
+ }
234
+ const timestamp = nowIso();
235
+ const nextConfig = {
236
+ ...snapshot.config,
237
+ relayBaseUrl,
238
+ controlBaseUrl,
239
+ accountId,
240
+ tunnelDomain,
241
+ bindingId,
242
+ hostPublicKey: identity.publicKeyPem,
243
+ hostKeyFingerprint: identity.keyFingerprint,
244
+ updatedAt: timestamp
245
+ };
246
+ const nextStatus = buildSkeletonStatus(nextConfig.enabled
247
+ ? (this.isBootstrapInitialized() ? "connecting" : "blocked_uninitialized")
248
+ : "disabled", nextConfig, {
249
+ observedAt: timestamp
250
+ });
251
+ this.db.transaction(() => {
252
+ this.repository.upsertConfig(nextConfig);
253
+ this.repository.upsertStatus(nextStatus);
254
+ })();
255
+ if (nextConfig.enabled && this.isBootstrapInitialized()) {
256
+ this.requestReconnect("relay_tunnel.bind");
257
+ }
258
+ return this.buildStatusDto({
259
+ config: nextConfig,
260
+ hasPersistedConfig: true
261
+ }, nextConfig, this.resolveEffectiveStatus(nextConfig));
262
+ }
263
+ async unbind() {
264
+ const snapshot = this.readStateSnapshot();
265
+ const timestamp = nowIso();
266
+ const nextConfig = clearRelayTunnelControlSession({
267
+ ...snapshot.config,
268
+ enabled: false,
269
+ bindingId: null,
270
+ tunnelDomain: null,
271
+ updatedAt: timestamp
272
+ }, {
273
+ clearAccountId: true,
274
+ updatedAt: timestamp
275
+ });
276
+ const nextStatus = buildSkeletonStatus("disabled", nextConfig, {
277
+ observedAt: timestamp
278
+ });
279
+ this.taskManager.cancel(HOST_TASK_TYPES.relayTunnelConnect, "default", "relay_tunnel_unbound");
280
+ await this.runtimeAdapter.disconnect?.("relay_tunnel_unbound");
281
+ this.db.transaction(() => {
282
+ this.repository.upsertConfig(nextConfig);
283
+ this.repository.upsertStatus(nextStatus);
284
+ })();
285
+ return this.buildStatusDto({
286
+ config: nextConfig,
287
+ hasPersistedConfig: true
288
+ }, nextConfig, nextStatus);
289
+ }
290
+ async enable() {
291
+ const snapshot = this.readStateSnapshot();
292
+ if (!isBound(snapshot.config)) {
293
+ throw new AppError({
294
+ statusCode: 409,
295
+ errorCode: "RELAY_TUNNEL_NOT_BOUND",
296
+ detail: "当前实例还没有绑定公共隧道"
297
+ });
298
+ }
299
+ const timestamp = nowIso();
300
+ const nextConfig = {
301
+ ...snapshot.config,
302
+ activated: true,
303
+ enabled: true,
304
+ updatedAt: timestamp
305
+ };
306
+ const configWithIdentity = this.syncIdentityIntoConfig(nextConfig);
307
+ const nextStatus = buildSkeletonStatus(this.isBootstrapInitialized() ? "connecting" : "blocked_uninitialized", configWithIdentity, {
308
+ observedAt: timestamp
309
+ });
310
+ this.db.transaction(() => {
311
+ this.repository.upsertConfig(configWithIdentity);
312
+ this.repository.upsertStatus(nextStatus);
313
+ })();
314
+ if (this.isBootstrapInitialized()) {
315
+ this.requestReconnect("relay_tunnel.enable");
316
+ }
317
+ return this.buildStatusDto({
318
+ config: configWithIdentity,
319
+ hasPersistedConfig: true
320
+ }, configWithIdentity, nextStatus);
321
+ }
322
+ async disable() {
323
+ const snapshot = this.readStateSnapshot();
324
+ const timestamp = nowIso();
325
+ const nextConfig = {
326
+ ...snapshot.config,
327
+ enabled: false,
328
+ updatedAt: timestamp
329
+ };
330
+ const nextStatus = buildSkeletonStatus("disabled", nextConfig, {
331
+ observedAt: timestamp
332
+ });
333
+ this.db.transaction(() => {
334
+ this.repository.upsertConfig(nextConfig);
335
+ this.repository.upsertStatus(nextStatus);
336
+ })();
337
+ this.taskManager.cancel(HOST_TASK_TYPES.relayTunnelConnect, "default", "relay_tunnel_disabled");
338
+ await this.runtimeAdapter.disconnect?.("relay_tunnel_disabled");
339
+ return this.buildStatusDto({
340
+ config: nextConfig,
341
+ hasPersistedConfig: true
342
+ }, nextConfig, nextStatus);
343
+ }
344
+ requestReconnect(source = "relay_tunnel.reconnect") {
345
+ return this.taskManager.enqueue(HOST_TASK_TYPES.relayTunnelConnect, {
346
+ key: "default",
347
+ source,
348
+ input: {
349
+ source
350
+ }
351
+ });
352
+ }
353
+ readStateSnapshot() {
354
+ const persistedConfig = this.reconcileLegacyLocalTargetBaseUrl(this.repository.findConfig());
355
+ return {
356
+ config: persistedConfig
357
+ ?? {
358
+ activated: false,
359
+ enabled: false,
360
+ provider: "codingns_relay",
361
+ relayBaseUrl: null,
362
+ controlBaseUrl: null,
363
+ controlAccessTokenCiphertext: null,
364
+ controlAccountEmail: null,
365
+ controlSessionExpiresAt: null,
366
+ accountId: null,
367
+ tunnelDomain: null,
368
+ bindingId: null,
369
+ hostPublicKey: null,
370
+ hostKeyFingerprint: null,
371
+ localTargetBaseUrl: this.defaultLocalTargetBaseUrl,
372
+ localTargetBaseUrlSource: "default",
373
+ updatedAt: nowIso()
374
+ },
375
+ hasPersistedConfig: persistedConfig !== null
376
+ };
377
+ }
378
+ reconcileLegacyLocalTargetBaseUrl(config) {
379
+ if (!config) {
380
+ return config;
381
+ }
382
+ if ((config.localTargetBaseUrlSource ?? "default") !== "default") {
383
+ return config;
384
+ }
385
+ if (config.localTargetBaseUrl === this.defaultLocalTargetBaseUrl) {
386
+ return config;
387
+ }
388
+ // `default` 源的目标地址由当前运行模式决定,不应该把历史默认值永久粘在库里。
389
+ // 只要默认入口变化了,就在启动时自动收敛到新的默认值;用户显式写入的 custom 配置不动。
390
+ const migratedConfig = {
391
+ ...config,
392
+ localTargetBaseUrl: this.defaultLocalTargetBaseUrl,
393
+ localTargetBaseUrlSource: "default",
394
+ updatedAt: nowIso()
395
+ };
396
+ this.repository.upsertConfig(migratedConfig);
397
+ return migratedConfig;
398
+ }
399
+ resolveEffectiveStatus(config) {
400
+ const persisted = this.repository.findStatus();
401
+ if (!config.activated || !config.enabled) {
402
+ return buildSkeletonStatus("disabled", config, {
403
+ observedAt: persisted?.observedAt ?? null
404
+ });
405
+ }
406
+ if (!isBound(config)) {
407
+ return buildSkeletonStatus("unbound", config, {
408
+ observedAt: persisted?.observedAt ?? null
409
+ });
410
+ }
411
+ if (!this.isBootstrapInitialized()) {
412
+ return buildSkeletonStatus("blocked_uninitialized", config, {
413
+ observedAt: persisted?.observedAt ?? null
414
+ });
415
+ }
416
+ if (!persisted
417
+ || persisted.phase === "disabled"
418
+ || persisted.phase === "unbound"
419
+ || persisted.phase === "blocked_uninitialized") {
420
+ return buildSkeletonStatus("connecting", config, {
421
+ observedAt: persisted?.observedAt ?? null
422
+ });
423
+ }
424
+ return {
425
+ ...persisted,
426
+ bindingId: config.bindingId,
427
+ tunnelDomain: config.tunnelDomain,
428
+ hostFingerprint: config.hostKeyFingerprint
429
+ };
430
+ }
431
+ registerBackgroundTasks() {
432
+ if (this.taskManager.has(HOST_TASK_TYPES.relayTunnelConnect)) {
433
+ return;
434
+ }
435
+ this.taskManager.register({
436
+ taskType: HOST_TASK_TYPES.relayTunnelConnect,
437
+ executionLane: "host_background",
438
+ timeoutMs: 15_000,
439
+ run: async (_input, context) => await this.runConnectTask(context.signal)
440
+ });
441
+ }
442
+ async runConnectTask(signal) {
443
+ const snapshot = this.readStateSnapshot();
444
+ if (!snapshot.config.enabled || !isBound(snapshot.config)) {
445
+ const effectiveConfig = this.resolveConfigWithIdentity(snapshot.config);
446
+ return this.buildStatusDto(snapshot, effectiveConfig, this.resolveEffectiveStatus(effectiveConfig));
447
+ }
448
+ const effectiveConfig = this.syncIdentityIntoConfig(snapshot.config);
449
+ if (!this.isBootstrapInitialized()) {
450
+ const blockedStatus = buildSkeletonStatus("blocked_uninitialized", effectiveConfig, {
451
+ observedAt: nowIso()
452
+ });
453
+ this.repository.upsertStatus(blockedStatus);
454
+ return this.buildStatusDto(snapshot, effectiveConfig, blockedStatus);
455
+ }
456
+ try {
457
+ const nextStatus = await this.runtimeAdapter.connect(effectiveConfig, signal);
458
+ if (signal.aborted) {
459
+ const latestSnapshot = this.readStateSnapshot();
460
+ const effectiveConfig = this.resolveConfigWithIdentity(latestSnapshot.config);
461
+ return this.buildStatusDto(latestSnapshot, effectiveConfig, this.resolveEffectiveStatus(effectiveConfig));
462
+ }
463
+ this.repository.upsertStatus(nextStatus);
464
+ return this.buildStatusDto(snapshot, effectiveConfig, nextStatus);
465
+ }
466
+ catch (error) {
467
+ if (signal.aborted) {
468
+ const latestSnapshot = this.readStateSnapshot();
469
+ const effectiveConfig = this.resolveConfigWithIdentity(latestSnapshot.config);
470
+ return this.buildStatusDto(latestSnapshot, effectiveConfig, this.resolveEffectiveStatus(effectiveConfig));
471
+ }
472
+ const failedStatus = {
473
+ ...buildSkeletonStatus("error", snapshot.config, {
474
+ observedAt: nowIso()
475
+ }),
476
+ lastError: error instanceof Error ? error.message : String(error)
477
+ };
478
+ this.repository.upsertStatus(failedStatus);
479
+ return this.buildStatusDto(snapshot, effectiveConfig, failedStatus);
480
+ }
481
+ }
482
+ buildStatusDto(snapshot, effectiveConfig, effectiveStatus) {
483
+ return {
484
+ activated: effectiveConfig.activated,
485
+ enabled: effectiveConfig.enabled,
486
+ provider: effectiveConfig.provider,
487
+ relayBaseUrl: effectiveConfig.relayBaseUrl,
488
+ controlBaseUrl: effectiveConfig.controlBaseUrl,
489
+ controlAccountEmail: effectiveConfig.controlAccountEmail,
490
+ controlSessionExpiresAt: effectiveConfig.controlSessionExpiresAt,
491
+ accountId: effectiveConfig.accountId,
492
+ tunnelDomain: effectiveConfig.tunnelDomain,
493
+ bindingId: effectiveConfig.bindingId,
494
+ hostPublicKey: effectiveConfig.hostPublicKey,
495
+ hostKeyFingerprint: effectiveConfig.hostKeyFingerprint,
496
+ localTargetBaseUrl: effectiveConfig.localTargetBaseUrl,
497
+ phase: effectiveStatus.phase,
498
+ connected: effectiveStatus.connected,
499
+ hostFingerprint: effectiveStatus.hostFingerprint,
500
+ trafficUsedBytes: effectiveStatus.trafficUsedBytes,
501
+ trafficRemainingBytes: effectiveStatus.trafficRemainingBytes,
502
+ quotaResetAt: effectiveStatus.quotaResetAt,
503
+ lastError: effectiveStatus.lastError,
504
+ observedAt: effectiveStatus.observedAt,
505
+ updatedAt: snapshot.hasPersistedConfig ? snapshot.config.updatedAt : null
506
+ };
507
+ }
508
+ resolveConfigWithIdentity(config) {
509
+ const identity = this.identityService.getIdentity();
510
+ if (!identity) {
511
+ return config;
512
+ }
513
+ return {
514
+ ...config,
515
+ hostPublicKey: identity.publicKeyPem,
516
+ hostKeyFingerprint: identity.keyFingerprint
517
+ };
518
+ }
519
+ syncIdentityIntoConfig(config) {
520
+ const identity = this.identityService.ensureIdentity();
521
+ if (config.hostPublicKey === identity.publicKeyPem
522
+ && config.hostKeyFingerprint === identity.keyFingerprint) {
523
+ return config;
524
+ }
525
+ const nextConfig = {
526
+ ...config,
527
+ hostPublicKey: identity.publicKeyPem,
528
+ hostKeyFingerprint: identity.keyFingerprint
529
+ };
530
+ this.repository.upsertConfig(nextConfig);
531
+ return nextConfig;
532
+ }
533
+ isBootstrapInitialized() {
534
+ return this.bootstrapStateRepository.getState().initialized;
535
+ }
536
+ requireControlSession(config) {
537
+ const controlBaseUrl = requireConfiguredControlBaseUrl(config);
538
+ const encryptedAccessToken = normalizeOptionalText(config.controlAccessTokenCiphertext);
539
+ const accountId = normalizeOptionalText(config.accountId);
540
+ if (!encryptedAccessToken || !accountId) {
541
+ throw new AppError({
542
+ statusCode: 409,
543
+ errorCode: "RELAY_TUNNEL_CONTROL_SESSION_REQUIRED",
544
+ detail: "当前还没有登录控制站账号"
545
+ });
546
+ }
547
+ try {
548
+ return {
549
+ controlBaseUrl,
550
+ accessToken: decryptSecret(this.controlSessionSecret, encryptedAccessToken),
551
+ accountId
552
+ };
553
+ }
554
+ catch {
555
+ const nextConfig = clearRelayTunnelControlSession(config, {
556
+ clearAccountId: !config.bindingId,
557
+ updatedAt: nowIso()
558
+ });
559
+ this.repository.upsertConfig(nextConfig);
560
+ throw new AppError({
561
+ statusCode: 409,
562
+ errorCode: "RELAY_TUNNEL_CONTROL_SESSION_REQUIRED",
563
+ detail: "控制站登录态已失效,请重新登录"
564
+ });
565
+ }
566
+ }
567
+ async requestControlApi(input) {
568
+ const response = await this.fetchFn(new URL(input.path, ensureTrailingSlash(input.controlBaseUrl)), {
569
+ method: input.method,
570
+ headers: input.headers,
571
+ body: input.body
572
+ });
573
+ if (!response.ok) {
574
+ throw await buildControlApiError(response, input.failurePrefix);
575
+ }
576
+ return await response.json();
577
+ }
578
+ }
579
+ class NoopRelayTunnelRuntimeAdapter {
580
+ async connect(config, _signal) {
581
+ return buildSkeletonStatus("connecting", config, {
582
+ observedAt: nowIso()
583
+ });
584
+ }
585
+ }
586
+ function buildSkeletonStatus(phase, config, overrides) {
587
+ return {
588
+ phase,
589
+ connected: false,
590
+ bindingId: config.bindingId,
591
+ tunnelDomain: config.tunnelDomain,
592
+ hostFingerprint: config.hostKeyFingerprint,
593
+ trafficUsedBytes: null,
594
+ trafficRemainingBytes: null,
595
+ quotaResetAt: null,
596
+ lastError: null,
597
+ observedAt: overrides?.observedAt ?? null
598
+ };
599
+ }
600
+ function isBound(config) {
601
+ return Boolean(config.bindingId && config.tunnelDomain);
602
+ }
603
+ function normalizeRequiredText(value, field) {
604
+ const normalized = value?.trim();
605
+ if (!normalized) {
606
+ throw new AppError({
607
+ statusCode: 400,
608
+ errorCode: "INVALID_INPUT",
609
+ detail: `${field} 不能为空`,
610
+ field
611
+ });
612
+ }
613
+ return normalized;
614
+ }
615
+ function normalizeOptionalText(value) {
616
+ const normalized = value?.trim();
617
+ return normalized ? normalized : null;
618
+ }
619
+ function normalizeTunnelDomain(value, field) {
620
+ const normalized = normalizeRequiredText(value, field).toLowerCase();
621
+ if (!/^[a-z0-9-]+(\.[a-z0-9-]+)+$/.test(normalized)) {
622
+ throw new AppError({
623
+ statusCode: 400,
624
+ errorCode: "INVALID_INPUT",
625
+ detail: "tunnelDomain 必须是合法域名",
626
+ field
627
+ });
628
+ }
629
+ return normalized;
630
+ }
631
+ function normalizeHttpBaseUrl(value, field) {
632
+ if (value === null || value === undefined) {
633
+ return value ?? null;
634
+ }
635
+ const normalized = value.trim();
636
+ if (normalized.length === 0) {
637
+ return null;
638
+ }
639
+ let parsed;
640
+ try {
641
+ parsed = new URL(normalized);
642
+ }
643
+ catch {
644
+ throw new AppError({
645
+ statusCode: 400,
646
+ errorCode: "INVALID_INPUT",
647
+ detail: `${field} 必须是合法的 http 或 https 地址`,
648
+ field
649
+ });
650
+ }
651
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
652
+ throw new AppError({
653
+ statusCode: 400,
654
+ errorCode: "INVALID_INPUT",
655
+ detail: `${field} 只允许使用 http 或 https 协议`,
656
+ field
657
+ });
658
+ }
659
+ if (parsed.username || parsed.password || parsed.search || parsed.hash) {
660
+ throw new AppError({
661
+ statusCode: 400,
662
+ errorCode: "INVALID_INPUT",
663
+ detail: `${field} 不能包含账号、查询参数或 hash`,
664
+ field
665
+ });
666
+ }
667
+ const pathname = parsed.pathname === "/" ? "" : parsed.pathname.replace(/\/+$/, "");
668
+ return `${parsed.protocol}//${parsed.host}${pathname}`;
669
+ }
670
+ function normalizeWebsocketBaseUrl(value, field) {
671
+ if (value === null || value === undefined) {
672
+ return value ?? null;
673
+ }
674
+ const normalized = value.trim();
675
+ if (normalized.length === 0) {
676
+ return null;
677
+ }
678
+ let parsed;
679
+ try {
680
+ parsed = new URL(normalized);
681
+ }
682
+ catch {
683
+ throw new AppError({
684
+ statusCode: 400,
685
+ errorCode: "INVALID_INPUT",
686
+ detail: `${field} 必须是合法的 ws、wss、http 或 https 地址`,
687
+ field
688
+ });
689
+ }
690
+ if (parsed.protocol !== "ws:"
691
+ && parsed.protocol !== "wss:"
692
+ && parsed.protocol !== "http:"
693
+ && parsed.protocol !== "https:") {
694
+ throw new AppError({
695
+ statusCode: 400,
696
+ errorCode: "INVALID_INPUT",
697
+ detail: `${field} 只允许使用 ws、wss、http 或 https 协议`,
698
+ field
699
+ });
700
+ }
701
+ if (parsed.username || parsed.password || parsed.search || parsed.hash) {
702
+ throw new AppError({
703
+ statusCode: 400,
704
+ errorCode: "INVALID_INPUT",
705
+ detail: `${field} 不能包含账号、查询参数或 hash`,
706
+ field
707
+ });
708
+ }
709
+ const pathname = parsed.pathname === "/" ? "" : parsed.pathname.replace(/\/+$/, "");
710
+ const normalizedProtocol = parsed.protocol === "https:"
711
+ ? "wss:"
712
+ : parsed.protocol === "http:"
713
+ ? "ws:"
714
+ : parsed.protocol;
715
+ return `${normalizedProtocol}//${parsed.host}${pathname}`;
716
+ }
717
+ function requireConfiguredControlBaseUrl(config) {
718
+ const controlBaseUrl = normalizeOptionalText(config.controlBaseUrl);
719
+ if (!controlBaseUrl) {
720
+ throw new AppError({
721
+ statusCode: 409,
722
+ errorCode: "RELAY_TUNNEL_CONTROL_BASE_URL_REQUIRED",
723
+ detail: "当前还没有配置控制站点地址"
724
+ });
725
+ }
726
+ return controlBaseUrl;
727
+ }
728
+ function ensureTrailingSlash(value) {
729
+ return value.endsWith("/") ? value : `${value}/`;
730
+ }
731
+ function clearRelayTunnelControlSession(config, options) {
732
+ return {
733
+ ...config,
734
+ controlAccessTokenCiphertext: null,
735
+ controlAccountEmail: null,
736
+ controlSessionExpiresAt: null,
737
+ accountId: options.clearAccountId ? null : config.accountId,
738
+ updatedAt: options.updatedAt
739
+ };
740
+ }
741
+ async function buildControlApiError(response, failurePrefix) {
742
+ const detail = await readControlApiErrorDetail(response);
743
+ return new AppError({
744
+ statusCode: response.status,
745
+ errorCode: "RELAY_TUNNEL_CONTROL_API_ERROR",
746
+ detail: `${failurePrefix}:${detail}`
747
+ });
748
+ }
749
+ async function readControlApiErrorDetail(response) {
750
+ const contentType = response.headers.get("content-type") ?? "";
751
+ if (contentType.includes("application/json")) {
752
+ try {
753
+ const payload = await response.json();
754
+ const detail = readJsonErrorText(payload.detail)
755
+ ?? readJsonErrorText(payload.message)
756
+ ?? readJsonErrorText(payload.error);
757
+ if (detail) {
758
+ return detail;
759
+ }
760
+ }
761
+ catch {
762
+ // 忽略 JSON 解析失败,回退到纯文本。
763
+ }
764
+ }
765
+ const text = normalizeOptionalText(await response.text());
766
+ return text ?? `HTTP ${response.status}`;
767
+ }
768
+ function readJsonErrorText(value) {
769
+ return typeof value === "string" ? normalizeOptionalText(value) : null;
770
+ }
771
+ //# sourceMappingURL=relay-tunnel-service.js.map