agent-tower 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. package/dist/app.d.ts +2 -0
  2. package/dist/app.d.ts.map +1 -0
  3. package/dist/app.js +62 -0
  4. package/dist/app.js.map +1 -0
  5. package/dist/cli.d.ts +3 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +131 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/core/container.d.ts +11 -0
  10. package/dist/core/container.d.ts.map +1 -0
  11. package/dist/core/container.js +66 -0
  12. package/dist/core/container.js.map +1 -0
  13. package/dist/core/event-bus.d.ts +58 -0
  14. package/dist/core/event-bus.d.ts.map +1 -0
  15. package/dist/core/event-bus.js +29 -0
  16. package/dist/core/event-bus.js.map +1 -0
  17. package/dist/errors.d.ts +22 -0
  18. package/dist/errors.d.ts.map +1 -0
  19. package/dist/errors.js +36 -0
  20. package/dist/errors.js.map +1 -0
  21. package/dist/executors/base.executor.d.ts +160 -0
  22. package/dist/executors/base.executor.d.ts.map +1 -0
  23. package/dist/executors/base.executor.js +122 -0
  24. package/dist/executors/base.executor.js.map +1 -0
  25. package/dist/executors/claude-code.executor.d.ts +78 -0
  26. package/dist/executors/claude-code.executor.d.ts.map +1 -0
  27. package/dist/executors/claude-code.executor.js +160 -0
  28. package/dist/executors/claude-code.executor.js.map +1 -0
  29. package/dist/executors/command-builder.d.ts +64 -0
  30. package/dist/executors/command-builder.d.ts.map +1 -0
  31. package/dist/executors/command-builder.js +144 -0
  32. package/dist/executors/command-builder.js.map +1 -0
  33. package/dist/executors/cursor-agent.executor.d.ts +57 -0
  34. package/dist/executors/cursor-agent.executor.d.ts.map +1 -0
  35. package/dist/executors/cursor-agent.executor.js +109 -0
  36. package/dist/executors/cursor-agent.executor.js.map +1 -0
  37. package/dist/executors/default-profiles.json +29 -0
  38. package/dist/executors/execution-env.d.ts +64 -0
  39. package/dist/executors/execution-env.d.ts.map +1 -0
  40. package/dist/executors/execution-env.js +97 -0
  41. package/dist/executors/execution-env.js.map +1 -0
  42. package/dist/executors/gemini-cli.executor.d.ts +55 -0
  43. package/dist/executors/gemini-cli.executor.d.ts.map +1 -0
  44. package/dist/executors/gemini-cli.executor.js +117 -0
  45. package/dist/executors/gemini-cli.executor.js.map +1 -0
  46. package/dist/executors/index.d.ts +49 -0
  47. package/dist/executors/index.d.ts.map +1 -0
  48. package/dist/executors/index.js +95 -0
  49. package/dist/executors/index.js.map +1 -0
  50. package/dist/executors/profiles.d.ts +61 -0
  51. package/dist/executors/profiles.d.ts.map +1 -0
  52. package/dist/executors/profiles.js +192 -0
  53. package/dist/executors/profiles.js.map +1 -0
  54. package/dist/git/git-cli.d.ts +59 -0
  55. package/dist/git/git-cli.d.ts.map +1 -0
  56. package/dist/git/git-cli.js +156 -0
  57. package/dist/git/git-cli.js.map +1 -0
  58. package/dist/git/worktree.manager.d.ts +166 -0
  59. package/dist/git/worktree.manager.d.ts.map +1 -0
  60. package/dist/git/worktree.manager.js +481 -0
  61. package/dist/git/worktree.manager.js.map +1 -0
  62. package/dist/index.d.ts +2 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +37 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/mcp/context.d.ts +15 -0
  67. package/dist/mcp/context.d.ts.map +1 -0
  68. package/dist/mcp/context.js +19 -0
  69. package/dist/mcp/context.js.map +1 -0
  70. package/dist/mcp/http-client.d.ts +46 -0
  71. package/dist/mcp/http-client.d.ts.map +1 -0
  72. package/dist/mcp/http-client.js +100 -0
  73. package/dist/mcp/http-client.js.map +1 -0
  74. package/dist/mcp/index.d.ts +3 -0
  75. package/dist/mcp/index.d.ts.map +1 -0
  76. package/dist/mcp/index.js +36 -0
  77. package/dist/mcp/index.js.map +1 -0
  78. package/dist/mcp/server.d.ts +6 -0
  79. package/dist/mcp/server.d.ts.map +1 -0
  80. package/dist/mcp/server.js +32 -0
  81. package/dist/mcp/server.js.map +1 -0
  82. package/dist/mcp/tools/projects.d.ts +7 -0
  83. package/dist/mcp/tools/projects.d.ts.map +1 -0
  84. package/dist/mcp/tools/projects.js +12 -0
  85. package/dist/mcp/tools/projects.js.map +1 -0
  86. package/dist/mcp/tools/sessions.d.ts +7 -0
  87. package/dist/mcp/tools/sessions.d.ts.map +1 -0
  88. package/dist/mcp/tools/sessions.js +22 -0
  89. package/dist/mcp/tools/sessions.js.map +1 -0
  90. package/dist/mcp/tools/tasks.d.ts +7 -0
  91. package/dist/mcp/tools/tasks.d.ts.map +1 -0
  92. package/dist/mcp/tools/tasks.js +68 -0
  93. package/dist/mcp/tools/tasks.js.map +1 -0
  94. package/dist/mcp/tools/workspaces.d.ts +7 -0
  95. package/dist/mcp/tools/workspaces.d.ts.map +1 -0
  96. package/dist/mcp/tools/workspaces.js +45 -0
  97. package/dist/mcp/tools/workspaces.js.map +1 -0
  98. package/dist/mcp/types.d.ts +109 -0
  99. package/dist/mcp/types.d.ts.map +1 -0
  100. package/dist/mcp/types.js +55 -0
  101. package/dist/mcp/types.js.map +1 -0
  102. package/dist/middleware/tunnel-auth.d.ts +13 -0
  103. package/dist/middleware/tunnel-auth.d.ts.map +1 -0
  104. package/dist/middleware/tunnel-auth.js +39 -0
  105. package/dist/middleware/tunnel-auth.js.map +1 -0
  106. package/dist/output/__tests__/claude-code-parser-token.test.d.ts +2 -0
  107. package/dist/output/__tests__/claude-code-parser-token.test.d.ts.map +1 -0
  108. package/dist/output/__tests__/claude-code-parser-token.test.js +233 -0
  109. package/dist/output/__tests__/claude-code-parser-token.test.js.map +1 -0
  110. package/dist/output/__tests__/cursor-agent-parser-token.test.d.ts +2 -0
  111. package/dist/output/__tests__/cursor-agent-parser-token.test.d.ts.map +1 -0
  112. package/dist/output/__tests__/cursor-agent-parser-token.test.js +95 -0
  113. package/dist/output/__tests__/cursor-agent-parser-token.test.js.map +1 -0
  114. package/dist/output/__tests__/msg-store-token.test.d.ts +2 -0
  115. package/dist/output/__tests__/msg-store-token.test.d.ts.map +1 -0
  116. package/dist/output/__tests__/msg-store-token.test.js +38 -0
  117. package/dist/output/__tests__/msg-store-token.test.js.map +1 -0
  118. package/dist/output/claude-code-parser.d.ts +96 -0
  119. package/dist/output/claude-code-parser.d.ts.map +1 -0
  120. package/dist/output/claude-code-parser.js +498 -0
  121. package/dist/output/claude-code-parser.js.map +1 -0
  122. package/dist/output/cursor-agent-parser.d.ts +87 -0
  123. package/dist/output/cursor-agent-parser.d.ts.map +1 -0
  124. package/dist/output/cursor-agent-parser.js +476 -0
  125. package/dist/output/cursor-agent-parser.js.map +1 -0
  126. package/dist/output/index.d.ts +9 -0
  127. package/dist/output/index.d.ts.map +1 -0
  128. package/dist/output/index.js +13 -0
  129. package/dist/output/index.js.map +1 -0
  130. package/dist/output/msg-store.d.ts +110 -0
  131. package/dist/output/msg-store.d.ts.map +1 -0
  132. package/dist/output/msg-store.js +274 -0
  133. package/dist/output/msg-store.js.map +1 -0
  134. package/dist/output/types.d.ts +90 -0
  135. package/dist/output/types.d.ts.map +1 -0
  136. package/dist/output/types.js +93 -0
  137. package/dist/output/types.js.map +1 -0
  138. package/dist/output/utils/ansi.d.ts +8 -0
  139. package/dist/output/utils/ansi.d.ts.map +1 -0
  140. package/dist/output/utils/ansi.js +17 -0
  141. package/dist/output/utils/ansi.js.map +1 -0
  142. package/dist/output/utils/patch.d.ts +57 -0
  143. package/dist/output/utils/patch.d.ts.map +1 -0
  144. package/dist/output/utils/patch.js +113 -0
  145. package/dist/output/utils/patch.js.map +1 -0
  146. package/dist/pipeline/agent-pipeline.d.ts +28 -0
  147. package/dist/pipeline/agent-pipeline.d.ts.map +1 -0
  148. package/dist/pipeline/agent-pipeline.js +76 -0
  149. package/dist/pipeline/agent-pipeline.js.map +1 -0
  150. package/dist/routes/attachments.d.ts +3 -0
  151. package/dist/routes/attachments.d.ts.map +1 -0
  152. package/dist/routes/attachments.js +141 -0
  153. package/dist/routes/attachments.js.map +1 -0
  154. package/dist/routes/demo.d.ts +3 -0
  155. package/dist/routes/demo.d.ts.map +1 -0
  156. package/dist/routes/demo.js +152 -0
  157. package/dist/routes/demo.js.map +1 -0
  158. package/dist/routes/files.d.ts +3 -0
  159. package/dist/routes/files.d.ts.map +1 -0
  160. package/dist/routes/files.js +313 -0
  161. package/dist/routes/files.js.map +1 -0
  162. package/dist/routes/filesystem.d.ts +3 -0
  163. package/dist/routes/filesystem.d.ts.map +1 -0
  164. package/dist/routes/filesystem.js +126 -0
  165. package/dist/routes/filesystem.js.map +1 -0
  166. package/dist/routes/git.d.ts +3 -0
  167. package/dist/routes/git.d.ts.map +1 -0
  168. package/dist/routes/git.js +170 -0
  169. package/dist/routes/git.js.map +1 -0
  170. package/dist/routes/index.d.ts +3 -0
  171. package/dist/routes/index.d.ts.map +1 -0
  172. package/dist/routes/index.js +45 -0
  173. package/dist/routes/index.js.map +1 -0
  174. package/dist/routes/notifications.d.ts +10 -0
  175. package/dist/routes/notifications.d.ts.map +1 -0
  176. package/dist/routes/notifications.js +54 -0
  177. package/dist/routes/notifications.js.map +1 -0
  178. package/dist/routes/profiles.d.ts +12 -0
  179. package/dist/routes/profiles.d.ts.map +1 -0
  180. package/dist/routes/profiles.js +76 -0
  181. package/dist/routes/profiles.js.map +1 -0
  182. package/dist/routes/projects.d.ts +3 -0
  183. package/dist/routes/projects.d.ts.map +1 -0
  184. package/dist/routes/projects.js +94 -0
  185. package/dist/routes/projects.js.map +1 -0
  186. package/dist/routes/sessions.d.ts +12 -0
  187. package/dist/routes/sessions.d.ts.map +1 -0
  188. package/dist/routes/sessions.js +109 -0
  189. package/dist/routes/sessions.js.map +1 -0
  190. package/dist/routes/system.d.ts +3 -0
  191. package/dist/routes/system.d.ts.map +1 -0
  192. package/dist/routes/system.js +42 -0
  193. package/dist/routes/system.js.map +1 -0
  194. package/dist/routes/tasks.d.ts +3 -0
  195. package/dist/routes/tasks.d.ts.map +1 -0
  196. package/dist/routes/tasks.js +136 -0
  197. package/dist/routes/tasks.js.map +1 -0
  198. package/dist/routes/terminals.d.ts +3 -0
  199. package/dist/routes/terminals.d.ts.map +1 -0
  200. package/dist/routes/terminals.js +54 -0
  201. package/dist/routes/terminals.js.map +1 -0
  202. package/dist/routes/tunnel.d.ts +3 -0
  203. package/dist/routes/tunnel.d.ts.map +1 -0
  204. package/dist/routes/tunnel.js +36 -0
  205. package/dist/routes/tunnel.js.map +1 -0
  206. package/dist/routes/workspaces.d.ts +3 -0
  207. package/dist/routes/workspaces.d.ts.map +1 -0
  208. package/dist/routes/workspaces.js +171 -0
  209. package/dist/routes/workspaces.js.map +1 -0
  210. package/dist/services/commit-message.service.d.ts +32 -0
  211. package/dist/services/commit-message.service.d.ts.map +1 -0
  212. package/dist/services/commit-message.service.js +202 -0
  213. package/dist/services/commit-message.service.js.map +1 -0
  214. package/dist/services/notifications/feishu-channel.d.ts +9 -0
  215. package/dist/services/notifications/feishu-channel.d.ts.map +1 -0
  216. package/dist/services/notifications/feishu-channel.js +51 -0
  217. package/dist/services/notifications/feishu-channel.js.map +1 -0
  218. package/dist/services/notifications/index.d.ts +3 -0
  219. package/dist/services/notifications/index.d.ts.map +1 -0
  220. package/dist/services/notifications/index.js +2 -0
  221. package/dist/services/notifications/index.js.map +1 -0
  222. package/dist/services/notifications/notification.service.d.ts +10 -0
  223. package/dist/services/notifications/notification.service.d.ts.map +1 -0
  224. package/dist/services/notifications/notification.service.js +85 -0
  225. package/dist/services/notifications/notification.service.js.map +1 -0
  226. package/dist/services/notifications/os-channel.d.ts +8 -0
  227. package/dist/services/notifications/os-channel.d.ts.map +1 -0
  228. package/dist/services/notifications/os-channel.js +38 -0
  229. package/dist/services/notifications/os-channel.js.map +1 -0
  230. package/dist/services/notifications/types.d.ts +11 -0
  231. package/dist/services/notifications/types.d.ts.map +1 -0
  232. package/dist/services/notifications/types.js +2 -0
  233. package/dist/services/notifications/types.js.map +1 -0
  234. package/dist/services/project.service.d.ts +91 -0
  235. package/dist/services/project.service.d.ts.map +1 -0
  236. package/dist/services/project.service.js +138 -0
  237. package/dist/services/project.service.js.map +1 -0
  238. package/dist/services/session-manager.d.ts +164 -0
  239. package/dist/services/session-manager.d.ts.map +1 -0
  240. package/dist/services/session-manager.js +569 -0
  241. package/dist/services/session-manager.js.map +1 -0
  242. package/dist/services/task.service.d.ts +179 -0
  243. package/dist/services/task.service.d.ts.map +1 -0
  244. package/dist/services/task.service.js +281 -0
  245. package/dist/services/task.service.js.map +1 -0
  246. package/dist/services/terminal-manager.d.ts +64 -0
  247. package/dist/services/terminal-manager.d.ts.map +1 -0
  248. package/dist/services/terminal-manager.js +217 -0
  249. package/dist/services/terminal-manager.js.map +1 -0
  250. package/dist/services/tunnel.service.d.ts +16 -0
  251. package/dist/services/tunnel.service.d.ts.map +1 -0
  252. package/dist/services/tunnel.service.js +77 -0
  253. package/dist/services/tunnel.service.js.map +1 -0
  254. package/dist/services/workspace.service.d.ts +219 -0
  255. package/dist/services/workspace.service.d.ts.map +1 -0
  256. package/dist/services/workspace.service.js +351 -0
  257. package/dist/services/workspace.service.js.map +1 -0
  258. package/dist/socket/events.d.ts +2 -0
  259. package/dist/socket/events.d.ts.map +1 -0
  260. package/dist/socket/events.js +3 -0
  261. package/dist/socket/events.js.map +1 -0
  262. package/dist/socket/index.d.ts +20 -0
  263. package/dist/socket/index.d.ts.map +1 -0
  264. package/dist/socket/index.js +77 -0
  265. package/dist/socket/index.js.map +1 -0
  266. package/dist/socket/middleware/auth.d.ts +13 -0
  267. package/dist/socket/middleware/auth.d.ts.map +1 -0
  268. package/dist/socket/middleware/auth.js +29 -0
  269. package/dist/socket/middleware/auth.js.map +1 -0
  270. package/dist/socket/middleware/error-handler.d.ts +11 -0
  271. package/dist/socket/middleware/error-handler.d.ts.map +1 -0
  272. package/dist/socket/middleware/error-handler.js +39 -0
  273. package/dist/socket/middleware/error-handler.js.map +1 -0
  274. package/dist/socket/middleware/index.d.ts +3 -0
  275. package/dist/socket/middleware/index.d.ts.map +1 -0
  276. package/dist/socket/middleware/index.js +3 -0
  277. package/dist/socket/middleware/index.js.map +1 -0
  278. package/dist/socket/rooms.d.ts +30 -0
  279. package/dist/socket/rooms.d.ts.map +1 -0
  280. package/dist/socket/rooms.js +39 -0
  281. package/dist/socket/rooms.js.map +1 -0
  282. package/dist/socket/socket-gateway.d.ts +21 -0
  283. package/dist/socket/socket-gateway.d.ts.map +1 -0
  284. package/dist/socket/socket-gateway.js +173 -0
  285. package/dist/socket/socket-gateway.js.map +1 -0
  286. package/dist/types/index.d.ts +41 -0
  287. package/dist/types/index.d.ts.map +1 -0
  288. package/dist/types/index.js +41 -0
  289. package/dist/types/index.js.map +1 -0
  290. package/dist/utils/index.d.ts +12 -0
  291. package/dist/utils/index.d.ts.map +1 -0
  292. package/dist/utils/index.js +25 -0
  293. package/dist/utils/index.js.map +1 -0
  294. package/dist/web/assets/AgentDemoPage-WdWEQtyU.js +1 -0
  295. package/dist/web/assets/DemoPage-C4Z_ftHI.js +4 -0
  296. package/dist/web/assets/NotificationSettingsPage-FrLfgt9y.js +1 -0
  297. package/dist/web/assets/ProfileSettingsPage-Cs93rTRr.js +3 -0
  298. package/dist/web/assets/ProjectKanbanPage-BmlRVfzo.js +75 -0
  299. package/dist/web/assets/ProjectKanbanPage-G5OQeJvU.css +1 -0
  300. package/dist/web/assets/api-client-CEBkg5lt.js +1 -0
  301. package/dist/web/assets/circle-alert-BEozlsMd.js +1 -0
  302. package/dist/web/assets/code-block-OCS4YCEC-CGgYYS4A.js +2 -0
  303. package/dist/web/assets/folder-picker-BP3x3phB.js +1 -0
  304. package/dist/web/assets/index-BuAijQvi.js +13 -0
  305. package/dist/web/assets/index-CxV866Yg.css +1 -0
  306. package/dist/web/assets/loader-circle-yEIqsdJ1.js +1 -0
  307. package/dist/web/assets/mermaid-NOHMQCX5-CIqtI2jF.js +123 -0
  308. package/dist/web/assets/mermaid-NOHMQCX5-lI9o3AWT.css +1 -0
  309. package/dist/web/assets/modal-BoX2RXaV.js +1 -0
  310. package/dist/web/assets/query-keys-BD_s_Etj.js +1 -0
  311. package/dist/web/assets/use-profiles-Rh8rBsAt.js +1 -0
  312. package/dist/web/index.html +14 -0
  313. package/dist/web/vite.svg +1 -0
  314. package/node_modules/@agent-tower/shared/dist/dev-port.d.ts +12 -0
  315. package/node_modules/@agent-tower/shared/dist/dev-port.d.ts.map +1 -0
  316. package/node_modules/@agent-tower/shared/dist/dev-port.js +31 -0
  317. package/node_modules/@agent-tower/shared/dist/dev-port.js.map +1 -0
  318. package/node_modules/@agent-tower/shared/dist/index.d.ts +5 -0
  319. package/node_modules/@agent-tower/shared/dist/index.d.ts.map +1 -0
  320. package/node_modules/@agent-tower/shared/dist/index.js +5 -0
  321. package/node_modules/@agent-tower/shared/dist/index.js.map +1 -0
  322. package/node_modules/@agent-tower/shared/dist/log-adapter.d.ts +72 -0
  323. package/node_modules/@agent-tower/shared/dist/log-adapter.d.ts.map +1 -0
  324. package/node_modules/@agent-tower/shared/dist/log-adapter.js +144 -0
  325. package/node_modules/@agent-tower/shared/dist/log-adapter.js.map +1 -0
  326. package/node_modules/@agent-tower/shared/dist/socket/events.d.ts +133 -0
  327. package/node_modules/@agent-tower/shared/dist/socket/events.d.ts.map +1 -0
  328. package/node_modules/@agent-tower/shared/dist/socket/events.js +32 -0
  329. package/node_modules/@agent-tower/shared/dist/socket/events.js.map +1 -0
  330. package/node_modules/@agent-tower/shared/dist/socket/index.d.ts +2 -0
  331. package/node_modules/@agent-tower/shared/dist/socket/index.d.ts.map +1 -0
  332. package/node_modules/@agent-tower/shared/dist/socket/index.js +2 -0
  333. package/node_modules/@agent-tower/shared/dist/socket/index.js.map +1 -0
  334. package/node_modules/@agent-tower/shared/dist/types.d.ts +168 -0
  335. package/node_modules/@agent-tower/shared/dist/types.d.ts.map +1 -0
  336. package/node_modules/@agent-tower/shared/dist/types.js +53 -0
  337. package/node_modules/@agent-tower/shared/dist/types.js.map +1 -0
  338. package/node_modules/@agent-tower/shared/package.json +38 -0
  339. package/package.json +46 -0
  340. package/prisma/schema.prisma +130 -0
  341. package/scripts/postinstall.js +120 -0
@@ -0,0 +1,351 @@
1
+ import { prisma } from '../utils/index.js';
2
+ import { WorkspaceStatus, TaskStatus, SessionStatus, SessionPurpose } from '../types/index.js';
3
+ import { WorktreeManager } from '../git/worktree.manager.js';
4
+ import { execGit } from '../git/git-cli.js';
5
+ import { NotFoundError, ServiceError } from '../errors.js';
6
+ import { getSessionManager, getEventBus } from '../core/container.js';
7
+ /** 过滤条件:只返回用户可见的 CHAT session */
8
+ const visibleSessionsFilter = { where: { purpose: { not: SessionPurpose.COMMIT_MSG } } };
9
+ export class WorkspaceService {
10
+ sessionService = getSessionManager();
11
+ eventBus = getEventBus();
12
+ // ── Queries ──────────────────────────────────────────────────────────────────
13
+ async findById(id) {
14
+ return prisma.workspace.findUnique({
15
+ where: { id },
16
+ include: { sessions: visibleSessionsFilter, task: { include: { project: true } } },
17
+ });
18
+ }
19
+ /**
20
+ * 获取 Task 下所有 Workspace
21
+ */
22
+ async findByTaskId(taskId) {
23
+ const task = await prisma.task.findUnique({ where: { id: taskId } });
24
+ if (!task) {
25
+ throw new NotFoundError('Task', taskId);
26
+ }
27
+ return prisma.workspace.findMany({
28
+ where: { taskId },
29
+ include: { sessions: visibleSessionsFilter },
30
+ orderBy: { createdAt: 'desc' },
31
+ });
32
+ }
33
+ // ── Create ───────────────────────────────────────────────────────────────────
34
+ /**
35
+ * 创建 Workspace
36
+ *
37
+ * - 默认分支名: at/{workspace-short-id}(ID 前 8 位)
38
+ * - 支持用户自定义分支名
39
+ * - 创建前校验分支名合法性 & 是否已存在
40
+ * - 创建后自动将关联 Task 状态改为 IN_PROGRESS
41
+ * - 失败时回滚已创建的数据库记录
42
+ */
43
+ async create(taskId, branchName) {
44
+ const task = await prisma.task.findUnique({
45
+ where: { id: taskId },
46
+ include: { project: true },
47
+ });
48
+ if (!task) {
49
+ throw new NotFoundError('Task', taskId);
50
+ }
51
+ const worktreeManager = new WorktreeManager(task.project.repoPath);
52
+ // 查找可复用的 MERGED workspace(branch 已通过 update-ref 保留)
53
+ if (!branchName) {
54
+ const mergedWorkspace = await prisma.workspace.findFirst({
55
+ where: { taskId, status: WorkspaceStatus.MERGED },
56
+ orderBy: { updatedAt: 'desc' },
57
+ });
58
+ if (mergedWorkspace) {
59
+ const worktreePath = await worktreeManager.ensureWorktreeExists(mergedWorkspace.branchName);
60
+ const updated = await prisma.workspace.update({
61
+ where: { id: mergedWorkspace.id },
62
+ data: {
63
+ status: WorkspaceStatus.ACTIVE,
64
+ worktreePath,
65
+ },
66
+ include: { sessions: true, task: { include: { project: true } } },
67
+ });
68
+ // Task 状态回退到 IN_PROGRESS
69
+ if (task.status !== TaskStatus.IN_PROGRESS && task.status !== TaskStatus.TODO) {
70
+ await prisma.task.update({
71
+ where: { id: taskId },
72
+ data: { status: TaskStatus.IN_PROGRESS },
73
+ });
74
+ this.eventBus.emit('task:updated', {
75
+ taskId,
76
+ projectId: task.projectId,
77
+ status: TaskStatus.IN_PROGRESS,
78
+ });
79
+ }
80
+ return updated;
81
+ }
82
+ }
83
+ // 先在数据库创建记录以获取 ID(用于生成默认分支名)
84
+ const workspace = await prisma.workspace.create({
85
+ data: {
86
+ taskId,
87
+ branchName: '', // 占位,稍后更新
88
+ worktreePath: '', // 占位,稍后更新
89
+ status: WorkspaceStatus.ACTIVE,
90
+ },
91
+ });
92
+ try {
93
+ // 生成分支名:用户指定 or 自动生成 at/{shortId}
94
+ const branch = branchName || `at/${workspace.id.slice(0, 8)}`;
95
+ // WorktreeManager.create 内部已做分支名合法性校验和重复检查
96
+ const worktreePath = await worktreeManager.create(branch);
97
+ // 更新数据库记录:填入真正的 branchName 和 worktreePath
98
+ const updated = await prisma.workspace.update({
99
+ where: { id: workspace.id },
100
+ data: { branchName: branch, worktreePath },
101
+ include: { sessions: true, task: { include: { project: true } } },
102
+ });
103
+ // 将关联 Task 状态改为 IN_PROGRESS(仅当当前为 TODO 时)
104
+ if (task.status === TaskStatus.TODO) {
105
+ await prisma.task.update({
106
+ where: { id: taskId },
107
+ data: { status: TaskStatus.IN_PROGRESS },
108
+ });
109
+ this.eventBus.emit('task:updated', {
110
+ taskId,
111
+ projectId: task.projectId,
112
+ status: TaskStatus.IN_PROGRESS,
113
+ });
114
+ }
115
+ return updated;
116
+ }
117
+ catch (err) {
118
+ // 回滚:删除已创建的数据库记录
119
+ await prisma.workspace.delete({ where: { id: workspace.id } }).catch(() => {
120
+ // 忽略回滚失败
121
+ });
122
+ throw err;
123
+ }
124
+ }
125
+ // ── Delete ───────────────────────────────────────────────────────────────────
126
+ /**
127
+ * 删除 Workspace
128
+ *
129
+ * - 删除前检查是否有 RUNNING 状态的 Session,有则拒绝删除
130
+ * - 删除时先停止所有关联 Session 的进程
131
+ * - 删除时调用 WorktreeManager.remove 清理 worktree
132
+ * - worktree 清理失败时仍然删除数据库记录(记录警告日志)
133
+ */
134
+ async delete(id) {
135
+ const workspace = await prisma.workspace.findUnique({
136
+ where: { id },
137
+ include: {
138
+ sessions: true,
139
+ task: { include: { project: true } },
140
+ },
141
+ });
142
+ if (!workspace) {
143
+ throw new NotFoundError('Workspace', id);
144
+ }
145
+ // 停止所有活跃的 Session(RUNNING 和 PENDING 状态)
146
+ const activeSessions = workspace.sessions.filter((s) => s.status === SessionStatus.PENDING || s.status === SessionStatus.RUNNING);
147
+ for (const session of activeSessions) {
148
+ try {
149
+ await this.sessionService.stop(session.id);
150
+ }
151
+ catch {
152
+ // 忽略停止失败
153
+ }
154
+ }
155
+ // 清理 worktree
156
+ try {
157
+ const worktreeManager = new WorktreeManager(workspace.task.project.repoPath);
158
+ await worktreeManager.remove(workspace.worktreePath);
159
+ }
160
+ catch (err) {
161
+ // worktree 清理失败时记录警告但不阻断删除
162
+ console.warn(`[WorkspaceService] Failed to remove worktree for workspace ${id}: ${err instanceof Error ? err.message : err}`);
163
+ }
164
+ // 删除数据库记录(级联删除 sessions)
165
+ await prisma.workspace.delete({ where: { id } });
166
+ return true;
167
+ }
168
+ // ── Diff ─────────────────────────────────────────────────────────────────────
169
+ async getDiff(id) {
170
+ const workspace = await prisma.workspace.findUnique({
171
+ where: { id },
172
+ include: { task: { include: { project: true } } },
173
+ });
174
+ if (!workspace) {
175
+ throw new NotFoundError('Workspace', id);
176
+ }
177
+ const worktreeManager = new WorktreeManager(workspace.task.project.repoPath);
178
+ return worktreeManager.getDiff(workspace.worktreePath, workspace.task.project.mainBranch);
179
+ }
180
+ // ── Merge ────────────────────────────────────────────────────────────────────
181
+ // ── Git Operations ──────────────────────────────────────────────────────────
182
+ /**
183
+ * Rebase 工作空间分支到最新的基础分支
184
+ */
185
+ async rebase(id) {
186
+ const workspace = await prisma.workspace.findUnique({
187
+ where: { id },
188
+ include: { task: { include: { project: true } } },
189
+ });
190
+ if (!workspace) {
191
+ throw new NotFoundError('Workspace', id);
192
+ }
193
+ const worktreeManager = new WorktreeManager(workspace.task.project.repoPath);
194
+ await worktreeManager.rebase(workspace.worktreePath, workspace.task.project.mainBranch);
195
+ }
196
+ /**
197
+ * 获取工作空间的 Git 操作状态
198
+ */
199
+ async getGitStatus(id) {
200
+ const workspace = await prisma.workspace.findUnique({
201
+ where: { id },
202
+ include: { task: { include: { project: true } } },
203
+ });
204
+ if (!workspace) {
205
+ throw new NotFoundError('Workspace', id);
206
+ }
207
+ const worktreeManager = new WorktreeManager(workspace.task.project.repoPath);
208
+ return worktreeManager.getGitOperationStatus(workspace.worktreePath, workspace.task.project.mainBranch);
209
+ }
210
+ /**
211
+ * 中止工作空间当前进行中的 Git 操作
212
+ */
213
+ async abortOperation(id) {
214
+ const workspace = await prisma.workspace.findUnique({
215
+ where: { id },
216
+ include: { task: { include: { project: true } } },
217
+ });
218
+ if (!workspace) {
219
+ throw new NotFoundError('Workspace', id);
220
+ }
221
+ const worktreeManager = new WorktreeManager(workspace.task.project.repoPath);
222
+ await worktreeManager.abortOperation(workspace.worktreePath);
223
+ }
224
+ // ── Merge (squash) ──────────────────────────────────────────────────────────
225
+ /**
226
+ * 合并 Workspace 到主分支(squash merge)
227
+ *
228
+ * @param commitMessage - 可选的自定义 commit message
229
+ * @returns squash commit 的 SHA
230
+ */
231
+ async merge(id, commitMessage) {
232
+ const workspace = await prisma.workspace.findUnique({
233
+ where: { id },
234
+ include: { task: { include: { project: true } } },
235
+ });
236
+ if (!workspace) {
237
+ throw new NotFoundError('Workspace', id);
238
+ }
239
+ // 优先使用传入的 commitMessage,其次使用 AI 生成的缓存
240
+ const message = commitMessage || workspace.commitMessage || undefined;
241
+ const worktreeManager = new WorktreeManager(workspace.task.project.repoPath);
242
+ const { sha } = await worktreeManager.merge(workspace.worktreePath, workspace.task.project.mainBranch, message ? { commitMessage: message } : undefined);
243
+ // 更新 workspace:标记 MERGED,清空 worktreePath(物理目录已删除)
244
+ await prisma.workspace.update({
245
+ where: { id },
246
+ data: { status: WorkspaceStatus.MERGED, worktreePath: '' },
247
+ });
248
+ // Task 推进到 DONE
249
+ const advanceableStatuses = [TaskStatus.IN_PROGRESS, TaskStatus.IN_REVIEW];
250
+ if (advanceableStatuses.includes(workspace.task.status)) {
251
+ await prisma.task.update({
252
+ where: { id: workspace.task.id },
253
+ data: { status: TaskStatus.DONE },
254
+ });
255
+ this.eventBus.emit('task:updated', {
256
+ taskId: workspace.task.id,
257
+ projectId: workspace.task.projectId,
258
+ status: TaskStatus.DONE,
259
+ });
260
+ }
261
+ return sha;
262
+ }
263
+ // ── Archive ──────────────────────────────────────────────────────────────────
264
+ /**
265
+ * 归档 Workspace(标记状态为 ABANDONED)
266
+ */
267
+ async archive(id) {
268
+ const workspace = await prisma.workspace.findUnique({
269
+ where: { id },
270
+ include: { sessions: true },
271
+ });
272
+ if (!workspace) {
273
+ throw new NotFoundError('Workspace', id);
274
+ }
275
+ if (workspace.status !== WorkspaceStatus.ACTIVE) {
276
+ throw new ServiceError(`Cannot archive workspace in ${workspace.status} status`, 'INVALID_WORKSPACE_STATE', 400);
277
+ }
278
+ // 停止所有活跃的 Session
279
+ const activeSessions = workspace.sessions.filter((s) => s.status === SessionStatus.PENDING || s.status === SessionStatus.RUNNING);
280
+ for (const session of activeSessions) {
281
+ try {
282
+ await this.sessionService.stop(session.id);
283
+ }
284
+ catch {
285
+ // 忽略停止失败
286
+ }
287
+ }
288
+ return prisma.workspace.update({
289
+ where: { id },
290
+ data: { status: WorkspaceStatus.ABANDONED },
291
+ include: { sessions: true, task: { include: { project: true } } },
292
+ });
293
+ }
294
+ // ── Cleanup ──────────────────────────────────────────────────────────────────
295
+ /**
296
+ * 清理所有 ABANDONED/MERGED 状态且关联 Task 为 DONE 的 Workspace
297
+ *
298
+ * @returns 被清理的 Workspace 数量
299
+ */
300
+ async cleanup() {
301
+ const workspaces = await prisma.workspace.findMany({
302
+ where: {
303
+ status: { in: [WorkspaceStatus.ABANDONED, WorkspaceStatus.MERGED] },
304
+ task: { status: TaskStatus.DONE },
305
+ },
306
+ include: { task: { include: { project: true } } },
307
+ });
308
+ let cleaned = 0;
309
+ for (const workspace of workspaces) {
310
+ try {
311
+ const worktreeManager = new WorktreeManager(workspace.task.project.repoPath);
312
+ // 清理残留 worktree(如果还存在)
313
+ if (workspace.worktreePath) {
314
+ await worktreeManager.remove(workspace.worktreePath);
315
+ }
316
+ // Task 已 DONE,branch 不再需要,删除
317
+ if (workspace.branchName) {
318
+ try {
319
+ await execGit(workspace.task.project.repoPath, ['branch', '-D', workspace.branchName]);
320
+ }
321
+ catch {
322
+ // branch 可能已不存在,忽略
323
+ }
324
+ }
325
+ }
326
+ catch (err) {
327
+ console.warn(`[WorkspaceService] cleanup: failed for workspace ${workspace.id}: ${err instanceof Error ? err.message : err}`);
328
+ }
329
+ await prisma.workspace.delete({ where: { id: workspace.id } });
330
+ cleaned++;
331
+ }
332
+ return cleaned;
333
+ }
334
+ // ── Startup Prune ────────────────────────────────────────────────────────────
335
+ /**
336
+ * 服务启动时调用:对所有项目执行 git worktree prune
337
+ */
338
+ static async pruneAllWorktrees() {
339
+ const projects = await prisma.project.findMany();
340
+ for (const project of projects) {
341
+ try {
342
+ const worktreeManager = new WorktreeManager(project.repoPath);
343
+ await worktreeManager.prune();
344
+ }
345
+ catch (err) {
346
+ console.warn(`[WorkspaceService] prune failed for project ${project.id}: ${err instanceof Error ? err.message : err}`);
347
+ }
348
+ }
349
+ }
350
+ }
351
+ //# sourceMappingURL=workspace.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.service.js","sourceRoot":"","sources":["../../src/services/workspace.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC/F,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAItE,iCAAiC;AACjC,MAAM,qBAAqB,GAAG,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,cAAc,CAAC,UAAU,EAAE,EAAE,EAAE,CAAC;AAEzF,MAAM,OAAO,gBAAgB;IACnB,cAAc,GAAG,iBAAiB,EAAE,CAAC;IACrC,QAAQ,GAAa,WAAW,EAAE,CAAC;IAE3C,gFAAgF;IAEhF,KAAK,CAAC,QAAQ,CAAC,EAAU;QACvB,OAAO,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC;YACjC,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,OAAO,EAAE,EAAE,QAAQ,EAAE,qBAAqB,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;SACnF,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,MAAc;QAC/B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC1C,CAAC;QAED,OAAO,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC;YAC/B,KAAK,EAAE,EAAE,MAAM,EAAE;YACjB,OAAO,EAAE,EAAE,QAAQ,EAAE,qBAAqB,EAAE;YAC5C,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,gFAAgF;IAEhF;;;;;;;;OAQG;IACH,KAAK,CAAC,MAAM,CAAC,MAAc,EAAE,UAAmB;QAC9C,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;YACxC,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE;YACrB,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;SAC3B,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC1C,CAAC;QAED,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAEnE,oDAAoD;QACpD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC;gBACvD,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC,MAAM,EAAE;gBACjD,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE;aAC/B,CAAC,CAAC;YAEH,IAAI,eAAe,EAAE,CAAC;gBACpB,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC,oBAAoB,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;gBAE5F,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;oBAC5C,KAAK,EAAE,EAAE,EAAE,EAAE,eAAe,CAAC,EAAE,EAAE;oBACjC,IAAI,EAAE;wBACJ,MAAM,EAAE,eAAe,CAAC,MAAM;wBAC9B,YAAY;qBACb;oBACD,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;iBAClE,CAAC,CAAC;gBAEH,yBAAyB;gBACzB,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,WAAW,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,IAAI,EAAE,CAAC;oBAC9E,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;wBACvB,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE;wBACrB,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,WAAW,EAAE;qBACzC,CAAC,CAAC;oBACH,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE;wBACjC,MAAM;wBACN,SAAS,EAAE,IAAI,CAAC,SAAS;wBACzB,MAAM,EAAE,UAAU,CAAC,WAAW;qBAC/B,CAAC,CAAC;gBACL,CAAC;gBAED,OAAO,OAAO,CAAC;YACjB,CAAC;QACH,CAAC;QAED,6BAA6B;QAC7B,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;YAC9C,IAAI,EAAE;gBACJ,MAAM;gBACN,UAAU,EAAE,EAAE,EAAE,UAAU;gBAC1B,YAAY,EAAE,EAAE,EAAE,UAAU;gBAC5B,MAAM,EAAE,eAAe,CAAC,MAAM;aAC/B;SACF,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,kCAAkC;YAClC,MAAM,MAAM,GAAG,UAAU,IAAI,MAAM,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YAE9D,2CAA2C;YAC3C,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAE1D,0CAA0C;YAC1C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;gBAC5C,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE;gBAC3B,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE;gBAC1C,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;aAClE,CAAC,CAAC;YAEH,0CAA0C;YAC1C,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,IAAI,EAAE,CAAC;gBACpC,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;oBACvB,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE;oBACrB,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,WAAW,EAAE;iBACzC,CAAC,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE;oBACjC,MAAM;oBACN,SAAS,EAAE,IAAI,CAAC,SAAS;oBACzB,MAAM,EAAE,UAAU,CAAC,WAAW;iBAC/B,CAAC,CAAC;YACL,CAAC;YAED,OAAO,OAAO,CAAC;QACjB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,iBAAiB;YACjB,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;gBACxE,SAAS;YACX,CAAC,CAAC,CAAC;YACH,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,gFAAgF;IAEhF;;;;;;;OAOG;IACH,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC;YAClD,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,OAAO,EAAE;gBACP,QAAQ,EAAE,IAAI;gBACd,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;aACrC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC3C,CAAC;QAED,wCAAwC;QACxC,MAAM,cAAc,GAAG,SAAS,CAAC,QAAQ,CAAC,MAAM,CAC9C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,OAAO,CAChF,CAAC;QACF,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;YACrC,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QAED,cAAc;QACd,IAAI,CAAC;YACH,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC7E,MAAM,eAAe,CAAC,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,2BAA2B;YAC3B,OAAO,CAAC,IAAI,CACV,8DAA8D,EAAE,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAChH,CAAC;QACJ,CAAC;QAED,yBAAyB;QACzB,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,gFAAgF;IAEhF,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC;YAClD,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;SAClD,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC3C,CAAC;QAED,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC7E,OAAO,eAAe,CAAC,OAAO,CAC5B,SAAS,CAAC,YAAY,EACtB,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAClC,CAAC;IACJ,CAAC;IAED,gFAAgF;IAEhF,+EAA+E;IAE/E;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC;YAClD,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;SAClD,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC3C,CAAC;QAED,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC7E,MAAM,eAAe,CAAC,MAAM,CAC1B,SAAS,CAAC,YAAY,EACtB,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAClC,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,EAAU;QAC3B,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC;YAClD,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;SAClD,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC3C,CAAC;QAED,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC7E,OAAO,eAAe,CAAC,qBAAqB,CAC1C,SAAS,CAAC,YAAY,EACtB,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAClC,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,EAAU;QAC7B,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC;YAClD,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;SAClD,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC3C,CAAC;QAED,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC7E,MAAM,eAAe,CAAC,cAAc,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAC/D,CAAC;IAED,+EAA+E;IAE/E;;;;;OAKG;IACH,KAAK,CAAC,KAAK,CAAC,EAAU,EAAE,aAAsB;QAC5C,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC;YAClD,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;SAClD,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC3C,CAAC;QAED,sCAAsC;QACtC,MAAM,OAAO,GAAG,aAAa,IAAI,SAAS,CAAC,aAAa,IAAI,SAAS,CAAC;QAEtE,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC7E,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,eAAe,CAAC,KAAK,CACzC,SAAS,CAAC,YAAY,EACtB,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EACjC,OAAO,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CACjD,CAAC;QAEF,kDAAkD;QAClD,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;YAC5B,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,IAAI,EAAE,EAAE,MAAM,EAAE,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE;SAC3D,CAAC,CAAC;QAEH,gBAAgB;QAChB,MAAM,mBAAmB,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;QAC3E,IAAI,mBAAmB,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,MAAoB,CAAC,EAAE,CAAC;YACtE,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;gBACvB,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE;gBAChC,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE;aAClC,CAAC,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE;gBACjC,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE;gBACzB,SAAS,EAAE,SAAS,CAAC,IAAI,CAAC,SAAS;gBACnC,MAAM,EAAE,UAAU,CAAC,IAAI;aACxB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,GAAG,CAAC;IACb,CAAC;IAED,gFAAgF;IAEhF;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC;YAClD,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;SAC5B,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC3C,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,KAAK,eAAe,CAAC,MAAM,EAAE,CAAC;YAChD,MAAM,IAAI,YAAY,CACpB,+BAA+B,SAAS,CAAC,MAAM,SAAS,EACxD,yBAAyB,EACzB,GAAG,CACJ,CAAC;QACJ,CAAC;QAED,kBAAkB;QAClB,MAAM,cAAc,GAAG,SAAS,CAAC,QAAQ,CAAC,MAAM,CAC9C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,OAAO,CAChF,CAAC;QACF,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;YACrC,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;YAC7B,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,IAAI,EAAE,EAAE,MAAM,EAAE,eAAe,CAAC,SAAS,EAAE;YAC3C,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;SAClE,CAAC,CAAC;IACL,CAAC;IAED,gFAAgF;IAEhF;;;;OAIG;IACH,KAAK,CAAC,OAAO;QACX,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC;YACjD,KAAK,EAAE;gBACL,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,eAAe,CAAC,SAAS,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE;gBACnE,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE;aAClC;YACD,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;SAClD,CAAC,CAAC;QAEH,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,IAAI,CAAC;gBACH,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAE7E,uBAAuB;gBACvB,IAAI,SAAS,CAAC,YAAY,EAAE,CAAC;oBAC3B,MAAM,eAAe,CAAC,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;gBACvD,CAAC;gBAED,6BAA6B;gBAC7B,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;oBACzB,IAAI,CAAC;wBACH,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;oBACzF,CAAC;oBAAC,MAAM,CAAC;wBACP,mBAAmB;oBACrB,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CACV,oDAAoD,SAAS,CAAC,EAAE,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAChH,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAC/D,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,gFAAgF;IAEhF;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,iBAAiB;QAC5B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QAEjD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAC9D,MAAM,eAAe,CAAC,KAAK,EAAE,CAAC;YAChC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CACV,+CAA+C,OAAO,CAAC,EAAE,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CACzG,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export { NAMESPACE, ClientEvents, ServerEvents, type SubscribePayload, type UnsubscribePayload, type SessionInputPayload, type SessionResizePayload, type SessionStdoutPayload, type SessionPatchPayload, type SessionExitPayload, type SessionErrorPayload, type SessionIdPayload, type SessionSubscribedPayload, type SessionUnsubscribedPayload, type TaskUpdatedPayload, type TaskDeletedPayload, type TerminalInputPayload, type TerminalResizePayload, type TerminalStdoutPayload, type TerminalExitPayload, type TerminalSubscribedPayload, type TerminalUnsubscribedPayload, type AgentStatus, type AgentStatusPayload, type AckResponse, type ClientEventType, type ServerEventType, } from '@agent-tower/shared/socket';
2
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/socket/events.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EAChC,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,4BAA4B,CAAA"}
@@ -0,0 +1,3 @@
1
+ // 从 shared 包重新导出事件类型
2
+ export { NAMESPACE, ClientEvents, ServerEvents, } from '@agent-tower/shared/socket';
3
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/socket/events.ts"],"names":[],"mappings":"AAAA,qBAAqB;AACrB,OAAO,EACL,SAAS,EACT,YAAY,EACZ,YAAY,GAyBb,MAAM,4BAA4B,CAAA"}
@@ -0,0 +1,20 @@
1
+ import { Server } from 'socket.io';
2
+ import type { FastifyInstance } from 'fastify';
3
+ import { type AgentStatusPayload } from './events.js';
4
+ /**
5
+ * 获取 Socket.IO 实例
6
+ */
7
+ export declare function getIO(): Server;
8
+ /**
9
+ * 初始化 Socket.IO 服务
10
+ */
11
+ export declare function initializeSocket(fastify: FastifyInstance): Promise<Server>;
12
+ /**
13
+ * 关闭 Socket.IO 服务
14
+ */
15
+ export declare function closeSocket(): Promise<void>;
16
+ export * from './events.js';
17
+ export * from './rooms.js';
18
+ export { type AuthenticatedSocket } from './middleware/index.js';
19
+ export declare function broadcastAgentStatus(payload: AgentStatusPayload): void;
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/socket/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAClC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAG9C,OAAO,EAAa,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAMhE;;GAEG;AACH,wBAAgB,KAAK,IAAI,MAAM,CAK9B;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CA6BhF;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAqBjD;AAGD,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAEhE,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAEtE"}
@@ -0,0 +1,77 @@
1
+ import { Server } from 'socket.io';
2
+ import { authMiddleware } from './middleware/index.js';
3
+ import { SocketGateway } from './socket-gateway.js';
4
+ import { NAMESPACE } from './events.js';
5
+ import { getEventBus, getSessionManager, getTerminalManager, getNotificationService } from '../core/container.js';
6
+ let io = null;
7
+ let socketGateway = null;
8
+ /**
9
+ * 获取 Socket.IO 实例
10
+ */
11
+ export function getIO() {
12
+ if (!io) {
13
+ throw new Error('Socket.IO not initialized');
14
+ }
15
+ return io;
16
+ }
17
+ /**
18
+ * 初始化 Socket.IO 服务
19
+ */
20
+ export async function initializeSocket(fastify) {
21
+ // Clean up previous instance to prevent listener accumulation during dev hot-reload
22
+ socketGateway?.destroy();
23
+ socketGateway = null;
24
+ io = new Server(fastify.server, {
25
+ cors: {
26
+ origin: process.env.CORS_ORIGIN || '*',
27
+ methods: ['GET', 'POST'],
28
+ credentials: true,
29
+ },
30
+ pingTimeout: 60000,
31
+ pingInterval: 25000,
32
+ });
33
+ const nsp = io.of(NAMESPACE);
34
+ nsp.use(authMiddleware);
35
+ const tm = await getTerminalManager();
36
+ getNotificationService();
37
+ socketGateway = new SocketGateway(nsp, getEventBus(), getSessionManager(), tm);
38
+ nsp.on('connection', (socket) => {
39
+ console.log(`[Socket] Connected: ${socket.id}`);
40
+ socketGateway?.register(socket);
41
+ });
42
+ console.log('[Socket.IO] Initialized namespace:', NAMESPACE);
43
+ return io;
44
+ }
45
+ /**
46
+ * 关闭 Socket.IO 服务
47
+ */
48
+ export async function closeSocket() {
49
+ if (io) {
50
+ socketGateway?.destroy();
51
+ // Kill all active agent session pipelines on shutdown
52
+ getSessionManager().destroyAll();
53
+ // Kill all standalone terminals on shutdown
54
+ try {
55
+ const tm = await getTerminalManager();
56
+ tm.destroyAll();
57
+ }
58
+ catch {
59
+ // TerminalManager may not have been initialized; safe to ignore
60
+ }
61
+ await new Promise((resolve) => {
62
+ io.close(() => {
63
+ console.log('[Socket.IO] Closed');
64
+ resolve();
65
+ });
66
+ });
67
+ socketGateway = null;
68
+ io = null;
69
+ }
70
+ }
71
+ // 导出类型和工具
72
+ export * from './events.js';
73
+ export * from './rooms.js';
74
+ export function broadcastAgentStatus(payload) {
75
+ socketGateway?.broadcastAgentStatus(payload);
76
+ }
77
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/socket/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Socket } from 'socket.io';
2
+ type NextFunction = (err?: Error) => void;
3
+ export interface AuthenticatedSocket extends Socket {
4
+ userId?: string;
5
+ username?: string;
6
+ }
7
+ /**
8
+ * Socket 认证中间件
9
+ * 隧道请求(带 CF 头)必须携带有效 token,本地请求放行
10
+ */
11
+ export declare function authMiddleware(socket: AuthenticatedSocket, next: NextFunction): void;
12
+ export {};
13
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/socket/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAGvC,KAAK,YAAY,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,KAAK,IAAI,CAAA;AAEzC,MAAM,WAAW,mBAAoB,SAAQ,MAAM;IACjD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,mBAAmB,EAC3B,IAAI,EAAE,YAAY,QA2BnB"}
@@ -0,0 +1,29 @@
1
+ import { TunnelService } from '../../services/tunnel.service.js';
2
+ /**
3
+ * Socket 认证中间件
4
+ * 隧道请求(带 CF 头)必须携带有效 token,本地请求放行
5
+ */
6
+ export function authMiddleware(socket, next) {
7
+ // 检查是否为隧道请求
8
+ const headers = socket.request.headers;
9
+ const isTunnel = !!(headers['cf-connecting-ip'] || headers['cf-ray']);
10
+ if (isTunnel && TunnelService.isRunning()) {
11
+ const token = socket.handshake.auth?.token ??
12
+ socket.handshake.query?.token;
13
+ if (!token || !TunnelService.validateToken(token)) {
14
+ return next(new Error('Unauthorized: valid tunnel token required'));
15
+ }
16
+ }
17
+ // 设置用户标识
18
+ const authToken = socket.handshake.auth?.token;
19
+ if (authToken) {
20
+ socket.userId = authToken;
21
+ socket.username = `User-${authToken.slice(0, 6)}`;
22
+ }
23
+ else {
24
+ socket.userId = `anonymous-${socket.id.slice(0, 8)}`;
25
+ socket.username = 'Anonymous';
26
+ }
27
+ next();
28
+ }
29
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/socket/middleware/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAA;AAShE;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC5B,MAA2B,EAC3B,IAAkB;IAElB,YAAY;IACZ,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAA;IACtC,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAA;IAErE,IAAI,QAAQ,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,CAAC;QAC1C,MAAM,KAAK,GACT,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK;YAC3B,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,KAA4B,CAAA;QAEvD,IAAI,CAAC,KAAK,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YAClD,OAAO,IAAI,CAAC,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC,CAAA;QACrE,CAAC;IACH,CAAC;IAED,SAAS;IACT,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAA;IAC9C,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,CAAC,MAAM,GAAG,SAAS,CAAA;QACzB,MAAM,CAAC,QAAQ,GAAG,QAAQ,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;IACnD,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,MAAM,GAAG,aAAa,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;QACpD,MAAM,CAAC,QAAQ,GAAG,WAAW,CAAA;IAC/B,CAAC;IAED,IAAI,EAAE,CAAA;AACR,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Socket } from 'socket.io';
2
+ import type { AckResponse } from '../events.js';
3
+ /**
4
+ * 包装 handler 函数,统一处理错误
5
+ */
6
+ export declare function withErrorHandler<T, R>(handler: (socket: Socket, payload: T) => Promise<R>): (socket: Socket, payload: T, callback?: (response: AckResponse<R>) => void) => Promise<void>;
7
+ /**
8
+ * 创建带验证的 handler
9
+ */
10
+ export declare function createHandler<T, R>(validator: (payload: unknown) => T, handler: (socket: Socket, payload: T) => Promise<R>): (socket: Socket, payload: unknown, callback?: ((response: AckResponse<R>) => void) | undefined) => Promise<void>;
11
+ //# sourceMappingURL=error-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../../src/socket/middleware/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAK/C;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,EACnC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,IAGjD,QAAQ,MAAM,EACd,SAAS,CAAC,EACV,WAAW,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI,mBAwBhD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,CAAC,EAChC,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,CAAC,EAClC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,YAjCzC,MAAM,8DAE2B,IAAI,gCAqChD"}
@@ -0,0 +1,39 @@
1
+ // 通用错误事件名
2
+ const ERROR_EVENT = 'error';
3
+ /**
4
+ * 包装 handler 函数,统一处理错误
5
+ */
6
+ export function withErrorHandler(handler) {
7
+ return async (socket, payload, callback) => {
8
+ try {
9
+ const result = await handler(socket, payload);
10
+ callback?.({ success: true, data: result });
11
+ }
12
+ catch (error) {
13
+ const message = error instanceof Error ? error.message : 'Unknown error';
14
+ console.error(`[Socket Error] ${message}`, error);
15
+ callback?.({
16
+ success: false,
17
+ error: {
18
+ code: 'INTERNAL_ERROR',
19
+ message,
20
+ },
21
+ });
22
+ // 也发送错误事件给客户端
23
+ socket.emit(ERROR_EVENT, {
24
+ code: 'INTERNAL_ERROR',
25
+ message,
26
+ });
27
+ }
28
+ };
29
+ }
30
+ /**
31
+ * 创建带验证的 handler
32
+ */
33
+ export function createHandler(validator, handler) {
34
+ return withErrorHandler(async (socket, payload) => {
35
+ const validated = validator(payload);
36
+ return handler(socket, validated);
37
+ });
38
+ }
39
+ //# sourceMappingURL=error-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../../src/socket/middleware/error-handler.ts"],"names":[],"mappings":"AAGA,UAAU;AACV,MAAM,WAAW,GAAG,OAAO,CAAA;AAE3B;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAmD;IAEnD,OAAO,KAAK,EACV,MAAc,EACd,OAAU,EACV,QAA6C,EAC7C,EAAE;QACF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;YAC7C,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;QAC7C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAA;YACxE,OAAO,CAAC,KAAK,CAAC,kBAAkB,OAAO,EAAE,EAAE,KAAK,CAAC,CAAA;YAEjD,QAAQ,EAAE,CAAC;gBACT,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE;oBACL,IAAI,EAAE,gBAAgB;oBACtB,OAAO;iBACR;aACF,CAAC,CAAA;YAEF,cAAc;YACd,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE;gBACvB,IAAI,EAAE,gBAAgB;gBACtB,OAAO;aACR,CAAC,CAAA;QACJ,CAAC;IACH,CAAC,CAAA;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,SAAkC,EAClC,OAAmD;IAEnD,OAAO,gBAAgB,CAAC,KAAK,EAAE,MAAc,EAAE,OAAgB,EAAE,EAAE;QACjE,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,CAAA;QACpC,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { authMiddleware, type AuthenticatedSocket } from './auth.js';
2
+ export { withErrorHandler, createHandler } from './error-handler.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/socket/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAA;AACpE,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { authMiddleware } from './auth.js';
2
+ export { withErrorHandler, createHandler } from './error-handler.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/socket/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAA4B,MAAM,WAAW,CAAA;AACpE,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA"}