@dyyz1993/create-agent 2.1.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (349) hide show
  1. package/package.json +5 -4
  2. package/src/__tests__/cli.test.ts +2 -0
  3. package/src/__tests__/copy.test.ts +110 -122
  4. package/src/__tests__/create-args.test.ts +113 -0
  5. package/src/__tests__/templates.test.ts +29 -3
  6. package/src/__tests__/update.test.ts +129 -0
  7. package/src/cli.ts +30 -32
  8. package/src/commands/create.ts +83 -24
  9. package/src/commands/update.ts +174 -0
  10. package/src/commands/workspace.ts +26 -6
  11. package/src/lib/copy.ts +233 -93
  12. package/src/lib/templates.ts +12 -0
  13. package/templates/agent/.husky/commit-msg +4 -0
  14. package/templates/agent/.husky/pre-commit +11 -0
  15. package/templates/agent/.husky/pre-push +6 -0
  16. package/templates/agent/.prettierignore +6 -0
  17. package/templates/agent/.prettierrc +9 -0
  18. package/templates/agent/CHANGELOG.md +15 -0
  19. package/templates/agent/commitlint.config.js +8 -0
  20. package/templates/agent/package.json +19 -4
  21. package/templates/agent/src/gateway/__tests__/ws-handler-token.test.ts +53 -39
  22. package/templates/agent/src/mainview/App.tsx +14 -12
  23. package/templates/agent/src/mainview/__tests__/hooks/use-rpc-init.test.ts +194 -190
  24. package/templates/agent/src/mainview/components/bash/BashPanel.tsx +210 -189
  25. package/templates/agent/src/mainview/components/chat/ChatPanel.tsx +45 -20
  26. package/templates/agent/src/mainview/components/common/ThemeToggle.tsx +41 -21
  27. package/templates/agent/src/mainview/components/debug/DebugPanel.tsx +181 -114
  28. package/templates/agent/src/mainview/components/debug/__tests__/DebugPanel.test.tsx +80 -80
  29. package/templates/agent/src/mainview/components/diff/__tests__/DiffViewerPanel.test.tsx +61 -58
  30. package/templates/agent/src/mainview/components/feed/FeedPanel.tsx +43 -41
  31. package/templates/agent/src/mainview/components/file-preview/FilePreviewOverlay.tsx +69 -50
  32. package/templates/agent/src/mainview/components/file-preview/VirtualizedCodeView.tsx +31 -18
  33. package/templates/agent/src/mainview/components/git/GitPanel.tsx +731 -490
  34. package/templates/agent/src/mainview/components/git/__tests__/GitPanel.test.tsx +157 -139
  35. package/templates/agent/src/mainview/components/layout/AppLayout.tsx +210 -161
  36. package/templates/agent/src/mainview/components/layout/__tests__/AppLayout.test.tsx +130 -122
  37. package/templates/agent/src/mainview/components/rules/RulesPanel.tsx +119 -109
  38. package/templates/agent/src/mainview/components/search/SearchPanel.tsx +123 -117
  39. package/templates/agent/src/mainview/components/search/__tests__/SearchPanel.test.tsx +64 -44
  40. package/templates/agent/src/mainview/components/sidebar/__tests__/PinButton.test.tsx +38 -38
  41. package/templates/agent/src/mainview/components/todo/TodoPanel.tsx +40 -38
  42. package/templates/agent/src/mainview/components/todo/__tests__/TodoPanel.test.tsx +72 -72
  43. package/templates/agent/src/mainview/lib/i18n/locales/en.json +175 -155
  44. package/templates/agent/src/mainview/lib/i18n/locales/zh.json +173 -155
  45. package/templates/agent/src/mainview/stores/use-app-store.ts +96 -86
  46. package/templates/agent/src/mainview/stores/use-explorer-store.ts +292 -275
  47. package/templates/agent/src/mainview/types/index.ts +23 -22
  48. package/templates/agent/src/mainview/utils/file-icon.tsx +17 -21
  49. package/templates/agent/src/shared/handlers/chat.ts +53 -53
  50. package/templates/agent/src/shared/handlers/debug.ts +13 -3
  51. package/templates/browser-agent/.env.example +19 -0
  52. package/templates/browser-agent/.husky/commit-msg +4 -0
  53. package/templates/browser-agent/.husky/pre-commit +11 -0
  54. package/templates/browser-agent/.husky/pre-push +6 -0
  55. package/templates/browser-agent/.prettierignore +6 -0
  56. package/templates/browser-agent/.prettierrc +9 -0
  57. package/templates/browser-agent/AGENTS.md +396 -0
  58. package/templates/browser-agent/CHANGELOG.md +15 -0
  59. package/templates/browser-agent/LICENSE +21 -0
  60. package/templates/browser-agent/README.md +103 -0
  61. package/templates/browser-agent/commitlint.config.js +8 -0
  62. package/templates/browser-agent/electrobun.config.ts +27 -0
  63. package/templates/browser-agent/electron/main.js +46 -0
  64. package/templates/browser-agent/electron/preload.js +5 -0
  65. package/templates/browser-agent/electron-builder.json +40 -0
  66. package/templates/browser-agent/eslint.config.mjs +79 -0
  67. package/templates/browser-agent/llms.txt +24 -0
  68. package/templates/browser-agent/package.json +140 -0
  69. package/templates/browser-agent/postcss.config.js +6 -0
  70. package/templates/browser-agent/scripts/dev.ts +138 -0
  71. package/templates/browser-agent/src/__tests__/hybrid-mode.test.ts +126 -0
  72. package/templates/browser-agent/src/__tests__/server-config-security.test.ts +55 -0
  73. package/templates/browser-agent/src/__tests__/server-config.test.ts +59 -0
  74. package/templates/browser-agent/src/bun/index.ts +130 -0
  75. package/templates/browser-agent/src/bun/three.d.ts +1 -0
  76. package/templates/browser-agent/src/gateway/http-routes.ts +1 -0
  77. package/templates/browser-agent/src/gateway/ipc-transport.ts +68 -0
  78. package/templates/browser-agent/src/gateway/sse-transport.ts +221 -0
  79. package/templates/browser-agent/src/mainview/App.tsx +45 -0
  80. package/templates/browser-agent/src/mainview/__tests__/hooks/use-rpc-init.test.ts +202 -0
  81. package/templates/browser-agent/src/mainview/__tests__/hooks/use-sidebar-resize.test.ts +127 -0
  82. package/templates/browser-agent/src/mainview/__tests__/i18n/i18n.test.ts +49 -0
  83. package/templates/browser-agent/src/mainview/__tests__/setup.ts +40 -0
  84. package/templates/browser-agent/src/mainview/__tests__/stores/use-chat-store.test.ts +73 -0
  85. package/templates/browser-agent/src/mainview/__tests__/stores/use-sidebar-store.test.ts +61 -0
  86. package/templates/browser-agent/src/mainview/__tests__/theme-variables.test.ts +36 -0
  87. package/templates/browser-agent/src/mainview/components/assets/AssetsPanel.tsx +139 -0
  88. package/templates/browser-agent/src/mainview/components/chat/ChatPanel.tsx +219 -0
  89. package/templates/browser-agent/src/mainview/components/chat/CommandBar.tsx +184 -0
  90. package/templates/browser-agent/src/mainview/components/chat/MessageBubble.tsx +249 -0
  91. package/templates/browser-agent/src/mainview/components/chat/ToolPicker.tsx +115 -0
  92. package/templates/browser-agent/src/mainview/components/common/ErrorBoundary.tsx +1 -0
  93. package/templates/browser-agent/src/mainview/components/common/LanguageSwitcher.tsx +15 -0
  94. package/templates/browser-agent/src/mainview/components/common/ThemeToggle.tsx +45 -0
  95. package/templates/browser-agent/src/mainview/components/common/__tests__/ErrorBoundary.test.tsx +74 -0
  96. package/templates/browser-agent/src/mainview/components/common/__tests__/LanguageSwitcher.test.tsx +44 -0
  97. package/templates/browser-agent/src/mainview/components/common/__tests__/ThemeToggle.test.tsx +41 -0
  98. package/templates/browser-agent/src/mainview/components/dev/NetworkPanel.tsx +155 -0
  99. package/templates/browser-agent/src/mainview/components/layout/AppLayout.tsx +311 -0
  100. package/templates/browser-agent/src/mainview/components/onboarding/SetupWizard.tsx +310 -0
  101. package/templates/browser-agent/src/mainview/components/process/ProcessPanel.tsx +329 -0
  102. package/templates/browser-agent/src/mainview/components/sidebar/SessionSidebar.tsx +122 -0
  103. package/templates/browser-agent/src/mainview/components/sidebar/SkillSidebar.tsx +115 -0
  104. package/templates/browser-agent/src/mainview/components/topbar/TopBar.tsx +350 -0
  105. package/templates/browser-agent/src/mainview/global.d.ts +13 -0
  106. package/templates/browser-agent/src/mainview/hooks/__tests__/use-breakpoint.test.ts +151 -0
  107. package/templates/browser-agent/src/mainview/hooks/use-agent-chat.ts +157 -0
  108. package/templates/browser-agent/src/mainview/hooks/use-breakpoint.ts +68 -0
  109. package/templates/browser-agent/src/mainview/hooks/use-rpc-init.ts +71 -0
  110. package/templates/browser-agent/src/mainview/hooks/use-sidebar-resize.ts +40 -0
  111. package/templates/browser-agent/src/mainview/index.css +71 -0
  112. package/templates/browser-agent/src/mainview/index.html +12 -0
  113. package/templates/browser-agent/src/mainview/lib/api-client.ts +397 -0
  114. package/templates/browser-agent/src/mainview/lib/i18n/index.ts +30 -0
  115. package/templates/browser-agent/src/mainview/lib/i18n/locales/en.json +130 -0
  116. package/templates/browser-agent/src/mainview/lib/i18n/locales/zh.json +128 -0
  117. package/templates/browser-agent/src/mainview/lib/network-bus.ts +92 -0
  118. package/templates/browser-agent/src/mainview/lib/rpc-cache.ts +94 -0
  119. package/templates/browser-agent/src/mainview/main.tsx +18 -0
  120. package/templates/browser-agent/src/mainview/stores/__tests__/use-connection-store.test.ts +26 -0
  121. package/templates/browser-agent/src/mainview/stores/__tests__/use-locale-store.test.ts +32 -0
  122. package/templates/browser-agent/src/mainview/stores/__tests__/use-log-store.test.ts +28 -0
  123. package/templates/browser-agent/src/mainview/stores/__tests__/use-theme-store.test.ts +59 -0
  124. package/templates/browser-agent/src/mainview/stores/message-batcher.ts +25 -0
  125. package/templates/browser-agent/src/mainview/stores/use-asset-store.ts +65 -0
  126. package/templates/browser-agent/src/mainview/stores/use-chat-store.ts +200 -0
  127. package/templates/browser-agent/src/mainview/stores/use-connection-store.ts +173 -0
  128. package/templates/browser-agent/src/mainview/stores/use-locale-store.ts +27 -0
  129. package/templates/browser-agent/src/mainview/stores/use-log-store.ts +16 -0
  130. package/templates/browser-agent/src/mainview/stores/use-network-panel-store.ts +18 -0
  131. package/templates/browser-agent/src/mainview/stores/use-record-store.ts +147 -0
  132. package/templates/browser-agent/src/mainview/stores/use-session-store.ts +151 -0
  133. package/templates/browser-agent/src/mainview/stores/use-sidebar-store.ts +161 -0
  134. package/templates/browser-agent/src/mainview/stores/use-theme-store.ts +46 -0
  135. package/templates/browser-agent/src/mainview/stores/use-view-store.ts +20 -0
  136. package/templates/browser-agent/src/mainview/types/index.ts +6 -0
  137. package/templates/browser-agent/src/server-config.ts +45 -0
  138. package/templates/browser-agent/src/server.ts +78 -0
  139. package/templates/browser-agent/src/shared/handlers/__tests__/chat-concurrency.test.ts +127 -0
  140. package/templates/browser-agent/src/shared/handlers/__tests__/chat-handler.test.ts +77 -0
  141. package/templates/browser-agent/src/shared/handlers/__tests__/file-handler.test.ts +100 -0
  142. package/templates/browser-agent/src/shared/handlers/__tests__/system-handler.test.ts +55 -0
  143. package/templates/browser-agent/src/shared/handlers/__tests__/timer-handler.test.ts +77 -0
  144. package/templates/browser-agent/src/shared/handlers/browser.ts +596 -0
  145. package/templates/browser-agent/src/shared/handlers/chat.ts +213 -0
  146. package/templates/browser-agent/src/shared/handlers/file.ts +99 -0
  147. package/templates/browser-agent/src/shared/handlers/index.ts +7 -0
  148. package/templates/browser-agent/src/shared/handlers/session.ts +167 -0
  149. package/templates/browser-agent/src/shared/handlers/system.ts +27 -0
  150. package/templates/browser-agent/src/shared/handlers/timer.ts +34 -0
  151. package/templates/browser-agent/src/shared/http-routes.ts +437 -0
  152. package/templates/browser-agent/src/shared/lib/__tests__/logger.test.ts +92 -0
  153. package/templates/browser-agent/src/shared/lib/__tests__/path-security.test.ts +77 -0
  154. package/templates/browser-agent/src/shared/lib/__tests__/web-server.test.ts +203 -0
  155. package/templates/browser-agent/src/shared/lib/agent.ts +384 -0
  156. package/templates/browser-agent/src/shared/lib/cdp.ts +448 -0
  157. package/templates/browser-agent/src/shared/lib/generate.ts +111 -0
  158. package/templates/browser-agent/src/shared/lib/logger.ts +152 -0
  159. package/templates/browser-agent/src/shared/lib/mock-stream.ts +147 -0
  160. package/templates/browser-agent/src/shared/lib/path-security.ts +38 -0
  161. package/templates/browser-agent/src/shared/lib/port-registry.ts +103 -0
  162. package/templates/browser-agent/src/shared/lib/web-server.ts +127 -0
  163. package/templates/browser-agent/src/shared/lib/xhs-extract.ts +71 -0
  164. package/templates/browser-agent/src/shared/modules/browser.ts +86 -0
  165. package/templates/browser-agent/src/shared/modules/chat.ts +20 -0
  166. package/templates/browser-agent/src/shared/modules/file.ts +40 -0
  167. package/templates/browser-agent/src/shared/modules/session.ts +55 -0
  168. package/templates/browser-agent/src/shared/modules/system.ts +8 -0
  169. package/templates/browser-agent/src/shared/modules/timer.ts +11 -0
  170. package/templates/browser-agent/src/shared/register-all-handlers.ts +36 -0
  171. package/templates/browser-agent/src/shared/rpc-schema.ts +34 -0
  172. package/templates/browser-agent/tailwind.config.js +15 -0
  173. package/templates/browser-agent/tsconfig.ipc.json +14 -0
  174. package/templates/browser-agent/tsconfig.json +36 -0
  175. package/templates/browser-agent/vite.config.ts +3 -0
  176. package/templates/browser-agent/vitest.config.ts +3 -0
  177. package/templates/chat/.husky/commit-msg +4 -0
  178. package/templates/chat/.husky/pre-commit +11 -0
  179. package/templates/chat/.husky/pre-push +6 -0
  180. package/templates/chat/CHANGELOG.md +15 -0
  181. package/templates/chat/commitlint.config.js +8 -0
  182. package/templates/chat/package.json +19 -4
  183. package/templates/chat/src/mainview/__tests__/hooks/use-input-history.test.ts +125 -0
  184. package/templates/chat/src/mainview/__tests__/setup.ts +32 -29
  185. package/templates/chat/src/mainview/components/chat/ChatPanel.tsx +80 -55
  186. package/templates/chat/src/mainview/components/common/ThemeToggle.tsx +40 -20
  187. package/templates/chat/src/mainview/lib/i18n/locales/en.json +175 -155
  188. package/templates/chat/src/mainview/lib/i18n/locales/zh.json +173 -155
  189. package/templates/chat/src/shared/handlers/chat.ts +17 -19
  190. package/templates/chat/src/shared/handlers/debug.ts +12 -2
  191. package/templates/cowork/.env.example +8 -0
  192. package/templates/cowork/.prettierignore +6 -0
  193. package/templates/cowork/.prettierrc +9 -0
  194. package/templates/cowork/AGENTS.md +236 -0
  195. package/templates/cowork/CHANGELOG.md +15 -0
  196. package/templates/cowork/LICENSE +21 -0
  197. package/templates/cowork/README.md +103 -0
  198. package/templates/cowork/commitlint.config.js +8 -0
  199. package/templates/cowork/docs/CODE-VIEW-PLAN.md +637 -0
  200. package/templates/cowork/docs/CODE-VIEW-V2.md +196 -0
  201. package/templates/cowork/docs/CODE-VIEW-V4.md +150 -0
  202. package/templates/cowork/electrobun.config.ts +27 -0
  203. package/templates/cowork/eslint.config.mjs +79 -0
  204. package/templates/cowork/llms.txt +24 -0
  205. package/templates/cowork/package.json +87 -0
  206. package/templates/cowork/postcss.config.js +6 -0
  207. package/templates/cowork/scripts/dev.ts +138 -0
  208. package/templates/cowork/src/__tests__/hybrid-mode.test.ts +126 -0
  209. package/templates/cowork/src/__tests__/server-config-security.test.ts +55 -0
  210. package/templates/cowork/src/__tests__/server-config.test.ts +59 -0
  211. package/templates/cowork/src/bun/index.ts +130 -0
  212. package/templates/cowork/src/bun/three.d.ts +1 -0
  213. package/templates/cowork/src/gateway/http-routes.ts +1 -0
  214. package/templates/cowork/src/gateway/ipc-transport.ts +68 -0
  215. package/templates/cowork/src/gateway/sse-transport.ts +231 -0
  216. package/templates/cowork/src/mainview/App.tsx +45 -0
  217. package/templates/cowork/src/mainview/__tests__/hooks/use-rpc-init.test.ts +202 -0
  218. package/templates/cowork/src/mainview/__tests__/hooks/use-sidebar-resize.test.ts +127 -0
  219. package/templates/cowork/src/mainview/__tests__/i18n/i18n.test.ts +49 -0
  220. package/templates/cowork/src/mainview/__tests__/setup.ts +40 -0
  221. package/templates/cowork/src/mainview/__tests__/stores/use-chat-store.test.ts +73 -0
  222. package/templates/cowork/src/mainview/__tests__/stores/use-sidebar-store.test.ts +61 -0
  223. package/templates/cowork/src/mainview/__tests__/theme-variables.test.ts +36 -0
  224. package/templates/cowork/src/mainview/components/chat/TaskChat.tsx +311 -0
  225. package/templates/cowork/src/mainview/components/chat/__tests__/localhost-links.test.ts +76 -0
  226. package/templates/cowork/src/mainview/components/common/ErrorBoundary.tsx +1 -0
  227. package/templates/cowork/src/mainview/components/common/LanguageSwitcher.tsx +15 -0
  228. package/templates/cowork/src/mainview/components/common/ThemeToggle.tsx +45 -0
  229. package/templates/cowork/src/mainview/components/common/__tests__/ErrorBoundary.test.tsx +74 -0
  230. package/templates/cowork/src/mainview/components/common/__tests__/LanguageSwitcher.test.tsx +44 -0
  231. package/templates/cowork/src/mainview/components/common/__tests__/ThemeToggle.test.tsx +41 -0
  232. package/templates/cowork/src/mainview/components/dev/NetworkPanel.tsx +155 -0
  233. package/templates/cowork/src/mainview/components/layout/AppLayout.tsx +216 -0
  234. package/templates/cowork/src/mainview/components/right/ArtifactsPanel.tsx +54 -0
  235. package/templates/cowork/src/mainview/components/right/ContextPanel.tsx +133 -0
  236. package/templates/cowork/src/mainview/components/right/ElementPicker.tsx +206 -0
  237. package/templates/cowork/src/mainview/components/right/PreviewBlock.tsx +155 -0
  238. package/templates/cowork/src/mainview/components/right/ProgressPanel.tsx +85 -0
  239. package/templates/cowork/src/mainview/components/sidebar/TaskSidebar.tsx +211 -0
  240. package/templates/cowork/src/mainview/components/topbar/TopBar.tsx +86 -0
  241. package/templates/cowork/src/mainview/global.d.ts +13 -0
  242. package/templates/cowork/src/mainview/hooks/__tests__/use-breakpoint.test.ts +123 -0
  243. package/templates/cowork/src/mainview/hooks/use-breakpoint.ts +53 -0
  244. package/templates/cowork/src/mainview/hooks/use-rpc-init.ts +26 -0
  245. package/templates/cowork/src/mainview/hooks/use-sidebar-resize.ts +40 -0
  246. package/templates/cowork/src/mainview/index.css +89 -0
  247. package/templates/cowork/src/mainview/index.html +12 -0
  248. package/templates/cowork/src/mainview/lib/api-client.ts +404 -0
  249. package/templates/cowork/src/mainview/lib/i18n/index.ts +30 -0
  250. package/templates/cowork/src/mainview/lib/i18n/locales/en.json +130 -0
  251. package/templates/cowork/src/mainview/lib/i18n/locales/zh.json +128 -0
  252. package/templates/cowork/src/mainview/lib/network-bus.ts +92 -0
  253. package/templates/cowork/src/mainview/lib/rpc-cache.ts +94 -0
  254. package/templates/cowork/src/mainview/main.tsx +18 -0
  255. package/templates/cowork/src/mainview/stores/__tests__/use-connection-store.test.ts +26 -0
  256. package/templates/cowork/src/mainview/stores/__tests__/use-locale-store.test.ts +32 -0
  257. package/templates/cowork/src/mainview/stores/__tests__/use-log-store.test.ts +28 -0
  258. package/templates/cowork/src/mainview/stores/__tests__/use-preview-store.test.ts +193 -0
  259. package/templates/cowork/src/mainview/stores/__tests__/use-sidebar-store.test.ts +81 -0
  260. package/templates/cowork/src/mainview/stores/__tests__/use-theme-store.test.ts +59 -0
  261. package/templates/cowork/src/mainview/stores/message-batcher.ts +25 -0
  262. package/templates/cowork/src/mainview/stores/use-chat-store.ts +198 -0
  263. package/templates/cowork/src/mainview/stores/use-connection-store.ts +168 -0
  264. package/templates/cowork/src/mainview/stores/use-context-store.ts +68 -0
  265. package/templates/cowork/src/mainview/stores/use-locale-store.ts +27 -0
  266. package/templates/cowork/src/mainview/stores/use-log-store.ts +16 -0
  267. package/templates/cowork/src/mainview/stores/use-network-panel-store.ts +18 -0
  268. package/templates/cowork/src/mainview/stores/use-output-store.ts +47 -0
  269. package/templates/cowork/src/mainview/stores/use-preview-store.ts +97 -0
  270. package/templates/cowork/src/mainview/stores/use-sidebar-store.ts +272 -0
  271. package/templates/cowork/src/mainview/stores/use-task-store.ts +86 -0
  272. package/templates/cowork/src/mainview/stores/use-theme-store.ts +46 -0
  273. package/templates/cowork/src/mainview/stores/use-view-store.ts +29 -0
  274. package/templates/cowork/src/mainview/types/index.ts +6 -0
  275. package/templates/cowork/src/server-config.ts +44 -0
  276. package/templates/cowork/src/server.ts +78 -0
  277. package/templates/cowork/src/shared/handlers/__tests__/chat-concurrency.test.ts +127 -0
  278. package/templates/cowork/src/shared/handlers/__tests__/chat-handler.test.ts +77 -0
  279. package/templates/cowork/src/shared/handlers/__tests__/file-handler.test.ts +100 -0
  280. package/templates/cowork/src/shared/handlers/__tests__/preview-handler.test.ts +172 -0
  281. package/templates/cowork/src/shared/handlers/__tests__/system-handler.test.ts +55 -0
  282. package/templates/cowork/src/shared/handlers/__tests__/timer-handler.test.ts +77 -0
  283. package/templates/cowork/src/shared/handlers/chat.ts +213 -0
  284. package/templates/cowork/src/shared/handlers/context.ts +72 -0
  285. package/templates/cowork/src/shared/handlers/file.ts +99 -0
  286. package/templates/cowork/src/shared/handlers/index.ts +9 -0
  287. package/templates/cowork/src/shared/handlers/output.ts +59 -0
  288. package/templates/cowork/src/shared/handlers/preview.ts +81 -0
  289. package/templates/cowork/src/shared/handlers/system.ts +27 -0
  290. package/templates/cowork/src/shared/handlers/task.ts +101 -0
  291. package/templates/cowork/src/shared/handlers/timer.ts +34 -0
  292. package/templates/cowork/src/shared/http-routes.ts +444 -0
  293. package/templates/cowork/src/shared/lib/__tests__/logger.test.ts +92 -0
  294. package/templates/cowork/src/shared/lib/__tests__/path-security.test.ts +77 -0
  295. package/templates/cowork/src/shared/lib/__tests__/web-server.test.ts +203 -0
  296. package/templates/cowork/src/shared/lib/logger.ts +152 -0
  297. package/templates/cowork/src/shared/lib/path-security.ts +38 -0
  298. package/templates/cowork/src/shared/lib/port-registry.ts +103 -0
  299. package/templates/cowork/src/shared/lib/web-server.ts +127 -0
  300. package/templates/cowork/src/shared/modules/chat.ts +20 -0
  301. package/templates/cowork/src/shared/modules/context.ts +32 -0
  302. package/templates/cowork/src/shared/modules/file.ts +40 -0
  303. package/templates/cowork/src/shared/modules/output.ts +20 -0
  304. package/templates/cowork/src/shared/modules/preview.ts +44 -0
  305. package/templates/cowork/src/shared/modules/system.ts +8 -0
  306. package/templates/cowork/src/shared/modules/task.ts +31 -0
  307. package/templates/cowork/src/shared/modules/timer.ts +11 -0
  308. package/templates/cowork/src/shared/register-all-handlers.ts +36 -0
  309. package/templates/cowork/src/shared/rpc-schema.ts +38 -0
  310. package/templates/cowork/tailwind.config.js +15 -0
  311. package/templates/cowork/test-upload.txt +0 -0
  312. package/templates/cowork/tsconfig.ipc.json +14 -0
  313. package/templates/cowork/tsconfig.json +36 -0
  314. package/templates/cowork/vite.config.ts +3 -0
  315. package/templates/cowork/vitest.config.ts +3 -0
  316. package/templates/general/.husky/commit-msg +4 -0
  317. package/templates/general/.husky/pre-commit +11 -0
  318. package/templates/general/.husky/pre-push +6 -0
  319. package/templates/general/CHANGELOG.md +15 -0
  320. package/templates/general/commitlint.config.js +8 -0
  321. package/templates/general/package.json +19 -4
  322. package/templates/general/src/mainview/__tests__/hooks/use-input-history.test.ts +125 -0
  323. package/templates/general/src/mainview/__tests__/setup.ts +32 -29
  324. package/templates/general/src/mainview/components/chat/ChatPanel.tsx +80 -55
  325. package/templates/general/src/mainview/components/common/ThemeToggle.tsx +40 -20
  326. package/templates/general/src/mainview/components/debug/DebugPanel.tsx +170 -156
  327. package/templates/general/src/mainview/components/debug/__tests__/DebugPanel.test.tsx +169 -0
  328. package/templates/general/src/mainview/components/explorer/ConfirmDialog.tsx +42 -42
  329. package/templates/general/src/mainview/components/explorer/ContextMenu.tsx +72 -67
  330. package/templates/general/src/mainview/components/feed/FeedPanel.tsx +7 -5
  331. package/templates/general/src/mainview/components/file-preview/FilePreviewOverlay.tsx +64 -45
  332. package/templates/general/src/mainview/components/file-preview/VirtualizedCodeView.tsx +24 -7
  333. package/templates/general/src/mainview/components/git/GitPanel.tsx +700 -473
  334. package/templates/general/src/mainview/components/layout/AppLayout.tsx +123 -114
  335. package/templates/general/src/mainview/components/search/SearchPanel.tsx +15 -19
  336. package/templates/general/src/mainview/lib/i18n/locales/en.json +175 -155
  337. package/templates/general/src/mainview/lib/i18n/locales/zh.json +173 -155
  338. package/templates/general/src/mainview/stores/__tests__/use-explorer-store.test.ts +259 -0
  339. package/templates/general/src/mainview/stores/__tests__/use-feed-store.test.ts +160 -0
  340. package/templates/general/src/mainview/stores/__tests__/use-git-store.test.ts +313 -0
  341. package/templates/general/src/mainview/stores/__tests__/use-notification-store.test.ts +115 -0
  342. package/templates/general/src/mainview/stores/__tests__/use-sidebar-store.test.ts +120 -0
  343. package/templates/general/src/mainview/stores/use-explorer-store.ts +277 -260
  344. package/templates/general/src/mainview/types/index.ts +21 -20
  345. package/templates/general/src/shared/handlers/chat.ts +1 -1
  346. package/templates/general/src/shared/handlers/debug.ts +12 -2
  347. package/templates/shared/components/ErrorBoundary.tsx +0 -1
  348. package/templates/shared/vite-base.config.ts +8 -7
  349. /package/templates/{shared → browser-agent}/test-upload.txt +0 -0
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Asset Store — 资源管理
3
+ *
4
+ * 对应 PRD §4.6 资源管理 + §8 数据模型
5
+ */
6
+
7
+ import { create } from "zustand";
8
+
9
+ interface Asset {
10
+ id: string;
11
+ kind: string;
12
+ name: string;
13
+ size?: number;
14
+ mime: string;
15
+ path?: string;
16
+ url?: string;
17
+ dataUrl?: string;
18
+ source: { sessionId: string; taskId: string; createdAt: number };
19
+ }
20
+
21
+ interface AssetState {
22
+ // 当前展示的资源列表
23
+ assets: Asset[];
24
+
25
+ // Actions
26
+ setAssets: (assets: Asset[]) => void;
27
+ addAsset: (asset: Asset) => void;
28
+ addAssets: (assets: Asset[]) => void;
29
+ clearAssets: () => void;
30
+ /** 下载资源 */
31
+ downloadAsset: (assetId: string) => void;
32
+ /** 获取资源下载 URL */
33
+ getDownloadUrl: (asset: Asset) => string;
34
+ }
35
+
36
+ export const useAssetStore = create<AssetState>((set, get) => ({
37
+ assets: [],
38
+
39
+ setAssets: (assets) => set({ assets }),
40
+
41
+ addAsset: (asset) =>
42
+ set((s) => ({ assets: [...s.assets, asset] })),
43
+
44
+ addAssets: (assets) =>
45
+ set((s) => ({ assets: [...s.assets, ...assets] })),
46
+
47
+ clearAssets: () => set({ assets: [] }),
48
+
49
+ downloadAsset: (assetId: string) => {
50
+ const asset = get().assets.find((a) => a.id === assetId);
51
+ if (!asset) return;
52
+ const url = get().getDownloadUrl(asset);
53
+ const a = document.createElement("a");
54
+ a.href = url;
55
+ a.download = asset.name;
56
+ a.click();
57
+ },
58
+
59
+ getDownloadUrl: (asset: Asset) => {
60
+ if (asset.dataUrl) return asset.dataUrl;
61
+ if (asset.path) return `/api/assets/${asset.id}/download`;
62
+ if (asset.url) return asset.url;
63
+ return "";
64
+ },
65
+ }));
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Chat Store — Agent 流式聊天
3
+ *
4
+ * 对应 PRD §4.2-4.3:SSE 流式渲染、轮次展示、工具调用卡片
5
+ */
6
+
7
+ import { create } from "zustand";
8
+
9
+ export interface ToolCall {
10
+ id: string;
11
+ tool: string;
12
+ input: string;
13
+ output: string;
14
+ status: "running" | "done";
15
+ }
16
+
17
+ export interface Turn {
18
+ turn: number;
19
+ toolCalls: ToolCall[];
20
+ text: string;
21
+ done: boolean;
22
+ }
23
+
24
+ export interface AgentMessage {
25
+ id: string;
26
+ role: "agent";
27
+ text: string;
28
+ turns: Turn[];
29
+ thinking: string;
30
+ steps?: { label: string; status: string; detail?: string }[];
31
+ summary?: any;
32
+ error?: string;
33
+ at: number;
34
+ }
35
+
36
+ interface ChatState {
37
+ messages: (AgentMessage | { id: string; role: "user"; text: string; at: number })[];
38
+
39
+ // 流式回调,由 ChatPanel 绑定
40
+ _onEventCallback: ((event: any) => void) | null;
41
+ setOnEventCallback: (cb: ((event: any) => void) | null) => void;
42
+
43
+ addUserMessage: (text: string) => void;
44
+ addAgentPlaceholder: (id: string) => void;
45
+ patchLastAgent: (patch: Partial<AgentMessage>) => void;
46
+ pushToolCall: (tc: ToolCall) => void;
47
+ updateToolCall: (tcId: string, output: string) => void;
48
+ appendThinking: (delta: string) => void;
49
+ appendText: (delta: string) => void;
50
+ markTurnDone: (turnNum: number) => void;
51
+ setMessages: (msgs: any[]) => void;
52
+ }
53
+
54
+ export const useChatStore = create<ChatState>((set, get) => ({
55
+ messages: [],
56
+ _onEventCallback: null,
57
+
58
+ setOnEventCallback: (cb) => set({ _onEventCallback: cb }),
59
+
60
+ addUserMessage: (text) =>
61
+ set((s) => ({
62
+ messages: [
63
+ ...s.messages,
64
+ { id: `msg_${Date.now()}`, role: "user" as const, text, at: Date.now() },
65
+ ],
66
+ })),
67
+
68
+ addAgentPlaceholder: (id) =>
69
+ set((s) => ({
70
+ messages: [
71
+ ...s.messages,
72
+ {
73
+ id,
74
+ role: "agent" as const,
75
+ text: "",
76
+ turns: [],
77
+ thinking: "",
78
+ at: Date.now(),
79
+ },
80
+ ],
81
+ })),
82
+
83
+ patchLastAgent: (patch) => {
84
+ const msgs = [...get().messages];
85
+ for (let i = msgs.length - 1; i >= 0; i--) {
86
+ const entry = msgs[i];
87
+ if (!entry || entry.role !== "agent") continue;
88
+ msgs[i] = { ...(entry as AgentMessage), ...patch };
89
+ break;
90
+ }
91
+ set({ messages: msgs });
92
+ },
93
+
94
+ pushToolCall: (tc) => {
95
+ const msgs = [...get().messages];
96
+ for (let i = msgs.length - 1; i >= 0; i--) {
97
+ const entry = msgs[i];
98
+ if (!entry || entry.role !== "agent") continue;
99
+ const m = entry as AgentMessage;
100
+ const turns = [...(m.turns || [])];
101
+ const lastTurn = turns[turns.length - 1];
102
+ if (turns.length === 0 || !lastTurn || lastTurn.done) {
103
+ turns.push({
104
+ turn: turns.length + 1,
105
+ toolCalls: [],
106
+ text: "",
107
+ done: false,
108
+ });
109
+ }
110
+ const currentTurn = turns[turns.length - 1];
111
+ if (currentTurn) {
112
+ currentTurn.toolCalls = [...currentTurn.toolCalls, tc];
113
+ }
114
+ msgs[i] = { ...m, turns };
115
+ break;
116
+ }
117
+ set({ messages: msgs });
118
+ },
119
+
120
+ updateToolCall: (tcId, output) => {
121
+ const msgs = [...get().messages];
122
+ for (let i = msgs.length - 1; i >= 0; i--) {
123
+ const entry = msgs[i];
124
+ if (!entry || entry.role !== "agent") continue;
125
+ const m = entry as AgentMessage;
126
+ const turns = [...(m.turns || [])];
127
+ const cur = turns[turns.length - 1];
128
+ if (cur) {
129
+ const calls = [...cur.toolCalls];
130
+ const idx = calls.findIndex((c) => c.id === tcId);
131
+ if (idx >= 0) {
132
+ const c = calls[idx];
133
+ if (c) calls[idx] = { ...c, output, status: "done" as const };
134
+ } else {
135
+ const ri =
136
+ calls.length -
137
+ 1 -
138
+ [...calls].reverse().findIndex((c) => c.status === "running");
139
+ const c = calls[ri];
140
+ if (c) calls[ri] = { ...c, output, status: "done" as const };
141
+ }
142
+ cur.toolCalls = calls;
143
+ }
144
+ msgs[i] = { ...m, turns };
145
+ break;
146
+ }
147
+ set({ messages: msgs });
148
+ },
149
+
150
+ appendThinking: (delta) => {
151
+ const msgs = [...get().messages];
152
+ for (let i = msgs.length - 1; i >= 0; i--) {
153
+ const entry = msgs[i];
154
+ if (!entry || entry.role !== "agent") continue;
155
+ const m = entry as AgentMessage;
156
+ msgs[i] = { ...m, thinking: (m.thinking || "") + delta };
157
+ break;
158
+ }
159
+ set({ messages: msgs });
160
+ },
161
+
162
+ appendText: (delta) => {
163
+ const msgs = [...get().messages];
164
+ for (let i = msgs.length - 1; i >= 0; i--) {
165
+ const entry = msgs[i];
166
+ if (!entry || entry.role !== "agent") continue;
167
+ const m = entry as AgentMessage;
168
+ const turns = [...(m.turns || [])];
169
+ const openTurn = turns.find((t) => !t.done);
170
+ if (openTurn) {
171
+ openTurn.text = (openTurn.text || "") + delta;
172
+ }
173
+ msgs[i] = { ...m, turns, text: (m.text || "") + delta };
174
+ break;
175
+ }
176
+ set({ messages: msgs });
177
+ },
178
+
179
+ markTurnDone: (_turnNum) => {
180
+ const msgs = [...get().messages];
181
+ for (let i = msgs.length - 1; i >= 0; i--) {
182
+ const entry = msgs[i];
183
+ if (!entry || entry.role !== "agent") continue;
184
+ const m = entry as AgentMessage;
185
+ const turns = [...(m.turns || [])];
186
+ const lastTurn = turns[turns.length - 1];
187
+ if (turns.length > 0 && lastTurn && !lastTurn.done) {
188
+ turns[turns.length - 1] = {
189
+ ...lastTurn,
190
+ done: true,
191
+ };
192
+ }
193
+ msgs[i] = { ...m, turns };
194
+ break;
195
+ }
196
+ set({ messages: msgs });
197
+ },
198
+
199
+ setMessages: (msgs) => set({ messages: msgs }),
200
+ }));
@@ -0,0 +1,173 @@
1
+ import { create } from "zustand";
2
+ import { apiClient } from "../lib/api-client";
3
+ import { useLogStore } from "./use-log-store";
4
+ import { networkBus } from "../lib/network-bus";
5
+
6
+ export interface BrowserTab {
7
+ index: number;
8
+ url: string;
9
+ title: string;
10
+ active: boolean;
11
+ }
12
+
13
+ // 轮询定时器(模块级,避免重复创建)
14
+ let _pollTimer: ReturnType<typeof setInterval> | null = null;
15
+
16
+ interface ConnectionState {
17
+ mode: "web" | "desktop";
18
+ ready: boolean;
19
+ // 浏览器连接状态
20
+ browserStatus: "offline" | "online";
21
+ browsers: { pluginId: string; name: string; tabs: number }[];
22
+ tabs: BrowserTab[];
23
+ activeTabIndex: number;
24
+ selectedTabIndex: number | null; // null = 用活跃 tab
25
+ // 插件
26
+ plugins: { name: string; description: string }[];
27
+ activePlugins: string[];
28
+ // 系统信息
29
+ systemInfo: any;
30
+
31
+ setReady: (ready: boolean) => void;
32
+ setMode: (mode: "web" | "desktop") => void;
33
+ setBrowserStatus: (status: "offline" | "online", browsers?: any[]) => void;
34
+ setTabs: (tabs: BrowserTab[], activeIndex: number) => void;
35
+ selectTab: (index: number | null) => void;
36
+ setPlugins: (plugins: any[]) => void;
37
+ setActivePlugins: (plugins: string[]) => void;
38
+ toggleActivePlugin: (name: string) => void;
39
+ initializeConnection: () => void;
40
+ checkBrowser: () => Promise<void>;
41
+ loadTabs: () => Promise<void>;
42
+ startConnectionPolling: () => void;
43
+ stopConnectionPolling: () => void;
44
+ }
45
+
46
+ export const useConnectionStore = create<ConnectionState>((set, get) => ({
47
+ mode: "web",
48
+ ready: false,
49
+ browserStatus: "offline",
50
+ browsers: [],
51
+ tabs: [],
52
+ activeTabIndex: 0,
53
+ selectedTabIndex: null,
54
+ plugins: [],
55
+ activePlugins: [],
56
+ systemInfo: null,
57
+
58
+ setReady: (ready) => set({ ready }),
59
+ setMode: (mode) => set({ mode }),
60
+
61
+ setBrowserStatus: (status, browsers) =>
62
+ set({ browserStatus: status, browsers: browsers || [] }),
63
+
64
+ setTabs: (tabs, activeIndex) => set({ tabs, activeTabIndex: activeIndex }),
65
+
66
+ selectTab: (index) => set({ selectedTabIndex: index }),
67
+
68
+ setPlugins: (plugins) => set({ plugins }),
69
+
70
+ setActivePlugins: (plugins) => set({ activePlugins: plugins }),
71
+
72
+ toggleActivePlugin: (name) => {
73
+ const current = get().activePlugins;
74
+ if (current.includes(name)) {
75
+ set({ activePlugins: current.filter((p) => p !== name) });
76
+ } else {
77
+ set({ activePlugins: [...current, name] });
78
+ }
79
+ },
80
+
81
+ initializeConnection: () => {
82
+ const MAX_RETRIES = 5;
83
+ let retries = 0;
84
+ const init = async () => {
85
+ try {
86
+ await apiClient.initialize();
87
+ const transport = apiClient.getTransport();
88
+ set({
89
+ mode: transport === "ipc" ? "desktop" : "web",
90
+ ready: true,
91
+ });
92
+ useLogStore
93
+ .getState()
94
+ .addLog(
95
+ `${transport === "ipc" ? "Desktop" : "Web"} mode - ${transport.toUpperCase()}`,
96
+ );
97
+
98
+ // 初始检测浏览器连接 + 加载标签页
99
+ await get().checkBrowser();
100
+ if (get().browserStatus === "online") {
101
+ await get().loadTabs();
102
+ } else {
103
+ // 未连接 → 启动轮询,用户装好扩展后自动发现
104
+ get().startConnectionPolling();
105
+ }
106
+ } catch {
107
+ retries++;
108
+ if (retries < MAX_RETRIES) {
109
+ setTimeout(init, 1000);
110
+ } else {
111
+ useLogStore
112
+ .getState()
113
+ .addLog(`Failed to connect after ${MAX_RETRIES} retries`);
114
+ }
115
+ }
116
+ };
117
+ init();
118
+ },
119
+
120
+ checkBrowser: async () => {
121
+ try {
122
+ const result = await apiClient.call("browser.checkConnection", {});
123
+ const wasOffline = get().browserStatus === "offline";
124
+ set({
125
+ browserStatus: result.connected ? "online" : "offline",
126
+ browsers: result.browsers,
127
+ });
128
+ // 刚连上时,立即加载标签页
129
+ if (wasOffline && result.connected) {
130
+ await get().loadTabs();
131
+ }
132
+ } catch {
133
+ set({ browserStatus: "offline", browsers: [] });
134
+ }
135
+ },
136
+
137
+ loadTabs: async () => {
138
+ try {
139
+ const result = await apiClient.call("browser.listTabs", {});
140
+ set({ tabs: result.tabs, activeTabIndex: result.activeIndex });
141
+ } catch (err) {
142
+ networkBus.emitStatus(`加载标签页失败: ${err instanceof Error ? err.message : String(err)}`);
143
+ }
144
+ },
145
+
146
+ /**
147
+ * 启动连接轮询 — 未连接时每 3 秒检测一次,连上后停止。
148
+ * 用户安装扩展后会自动发现。
149
+ */
150
+ startConnectionPolling: () => {
151
+ // 已连接就不轮询
152
+ if (get().browserStatus === "online") return;
153
+ if (_pollTimer) return; // 已有轮询在跑
154
+
155
+ _pollTimer = setInterval(async () => {
156
+ await get().checkBrowser();
157
+ // 连上了就停止轮询
158
+ if (get().browserStatus === "online") {
159
+ if (_pollTimer) {
160
+ clearInterval(_pollTimer);
161
+ _pollTimer = null;
162
+ }
163
+ }
164
+ }, 3000);
165
+ },
166
+
167
+ stopConnectionPolling: () => {
168
+ if (_pollTimer) {
169
+ clearInterval(_pollTimer);
170
+ _pollTimer = null;
171
+ }
172
+ },
173
+ }));
@@ -0,0 +1,27 @@
1
+ import { create } from "zustand";
2
+ import type { Locale } from "../lib/i18n";
3
+
4
+ interface LocaleState {
5
+ locale: Locale;
6
+ setLocale: (locale: Locale) => void;
7
+ }
8
+
9
+ function getInitialLocale(): Locale {
10
+ if (typeof window === "undefined") return "en";
11
+ const stored = localStorage.getItem("locale");
12
+ if (stored === "en" || stored === "zh") return stored;
13
+ const browserLang = navigator.language.toLowerCase();
14
+ if (browserLang.startsWith("zh")) return "zh";
15
+ return "en";
16
+ }
17
+
18
+ export const useLocaleStore = create<LocaleState>((set) => ({
19
+ locale: getInitialLocale(),
20
+ setLocale: (locale) => {
21
+ localStorage.setItem("locale", locale);
22
+ import("../lib/i18n").then((i18n) => {
23
+ i18n.default.changeLanguage(locale);
24
+ });
25
+ set({ locale });
26
+ },
27
+ }));
@@ -0,0 +1,16 @@
1
+ import { create } from "zustand";
2
+
3
+ interface LogState {
4
+ logs: string[];
5
+ addLog: (message: string) => void;
6
+ }
7
+
8
+ const MAX_LOGS = 100;
9
+
10
+ export const useLogStore = create<LogState>((set) => ({
11
+ logs: [],
12
+ addLog: (message) =>
13
+ set((state) => ({
14
+ logs: [...state.logs.slice(-(MAX_LOGS - 1)), `[${new Date().toISOString().slice(11, 19)}] ${message}`],
15
+ })),
16
+ }));
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Network Panel state — shared open/close state between TopBar button
3
+ * and the AppLayout drawer.
4
+ */
5
+
6
+ import { create } from "zustand";
7
+
8
+ interface NetworkPanelState {
9
+ open: boolean;
10
+ toggle: () => void;
11
+ setOpen: (open: boolean) => void;
12
+ }
13
+
14
+ export const useNetworkPanelStore = create<NetworkPanelState>((set, get) => ({
15
+ open: false,
16
+ toggle: () => set({ open: !get().open }),
17
+ setOpen: (open) => set({ open }),
18
+ }));
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Record Store — 浏览器录制状态管理
3
+ *
4
+ * 管理录制生命周期:开始 → 录制中 → 停止 → 录制结果
5
+ * 录制开始时自动切到「加工」Tab,让用户看到录制状态。
6
+ */
7
+
8
+ import { create } from "zustand";
9
+ import { apiClient } from "../lib/api-client";
10
+ import { networkBus } from "../lib/network-bus";
11
+ import { useConnectionStore } from "./use-connection-store";
12
+
13
+ export interface RecordingResult {
14
+ actions: number;
15
+ network: number;
16
+ durationMs: number;
17
+ steps: number;
18
+ data: any;
19
+ }
20
+
21
+ interface RecordState {
22
+ isRecording: boolean;
23
+ recordSession: string | null;
24
+ actionCount: number;
25
+ lastRecording: RecordingResult | null;
26
+ error: string | null;
27
+
28
+ startRecording: () => Promise<boolean>;
29
+ stopRecording: () => Promise<RecordingResult | null>;
30
+ pollStatus: () => Promise<void>;
31
+ clearError: () => void;
32
+ }
33
+
34
+ let pollTimer: ReturnType<typeof setInterval> | null = null;
35
+
36
+ export const useRecordStore = create<RecordState>((set, get) => ({
37
+ isRecording: false,
38
+ recordSession: null,
39
+ actionCount: 0,
40
+ lastRecording: null,
41
+ error: null,
42
+
43
+ startRecording: async () => {
44
+ set({ error: null });
45
+ try {
46
+ // 获取当前选中标签页
47
+ const connState = useConnectionStore.getState();
48
+ const tabIdx = connState.selectedTabIndex ?? connState.activeTabIndex;
49
+ const currentTab = connState.tabs[tabIdx];
50
+ const url = currentTab?.url && currentTab.url !== "about:blank" ? currentTab.url : undefined;
51
+
52
+ // 先导航 daemon 到目标 URL(确保录制正确的页面)
53
+ if (url) {
54
+ try {
55
+ await apiClient.call("browser.execXbrowser", { command: `goto "${url}"` });
56
+ } catch {
57
+ /* ignore navigation errors */
58
+ }
59
+ }
60
+
61
+ networkBus.emitRequest("browser.recordStart", { url });
62
+ const result = await apiClient.call("browser.recordStart", { url });
63
+ networkBus.emitResponse("browser.recordStart", 0);
64
+
65
+ if (result.success) {
66
+ set({
67
+ isRecording: true,
68
+ recordSession: result.session,
69
+ actionCount: 0,
70
+ lastRecording: null,
71
+ });
72
+
73
+ // 启动轮询,更新操作计数
74
+ if (pollTimer) clearInterval(pollTimer);
75
+ pollTimer = setInterval(() => {
76
+ get().pollStatus();
77
+ }, 2000);
78
+
79
+ return true;
80
+ } else {
81
+ set({ error: "录制启动失败" });
82
+ return false;
83
+ }
84
+ } catch (err) {
85
+ set({ error: err instanceof Error ? err.message : "录制启动失败" });
86
+ return false;
87
+ }
88
+ },
89
+
90
+ stopRecording: async () => {
91
+ const session = get().recordSession;
92
+ if (!session) return null;
93
+
94
+ // 停止轮询
95
+ if (pollTimer) {
96
+ clearInterval(pollTimer);
97
+ pollTimer = null;
98
+ }
99
+
100
+ try {
101
+ networkBus.emitRequest("browser.recordStop", { session });
102
+ const result = await apiClient.call("browser.recordStop", { session });
103
+ networkBus.emitResponse("browser.recordStop", 0);
104
+
105
+ const recording: RecordingResult = {
106
+ actions: result.actions || 0,
107
+ network: result.network || 0,
108
+ durationMs: result.durationMs || 0,
109
+ steps: result.steps || 0,
110
+ data: result.data,
111
+ };
112
+
113
+ console.log("[record] stopRecording result:", { actions: recording.actions, network: recording.network, durationMs: recording.durationMs, dataKeys: recording.data ? Object.keys(recording.data) : null });
114
+
115
+ set({
116
+ isRecording: false,
117
+ recordSession: null,
118
+ actionCount: 0,
119
+ lastRecording: recording,
120
+ });
121
+
122
+ return recording;
123
+ } catch (err) {
124
+ set({
125
+ isRecording: false,
126
+ recordSession: null,
127
+ error: err instanceof Error ? err.message : "停止录制失败",
128
+ });
129
+ return null;
130
+ }
131
+ },
132
+
133
+ pollStatus: async () => {
134
+ const session = get().recordSession;
135
+ if (!session) return;
136
+ try {
137
+ const result = await apiClient.call("browser.recordStatus", { session });
138
+ if (result.recording) {
139
+ set({ actionCount: result.actions || 0 });
140
+ }
141
+ } catch {
142
+ /* ignore poll errors */
143
+ }
144
+ },
145
+
146
+ clearError: () => set({ error: null }),
147
+ }));