@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,311 @@
1
+ /**
2
+ * Browser Agent — 响应式三栏布局
3
+ *
4
+ * 侧边栏三态折叠:full (展开) → icon (图标条) → hidden (隐藏)
5
+ * TopBar 的侧栏按钮循环切换。移动端走抽屉模式。
6
+ *
7
+ * 断点策略(由 use-breakpoint.ts 自动控制):
8
+ * - wide (≥1280px):侧栏固定 + 资源面板固定,中间对话区自适应
9
+ * - desktop (1024-1279px):侧栏固定,资源面板折叠为抽屉
10
+ * - tablet (768-1023px):侧栏抽屉,资源面板抽屉
11
+ * - mobile (<768px):全部抽屉,默认收起
12
+ */
13
+
14
+ import { useTranslation } from "react-i18next";
15
+ import { PanelLeftClose, PanelRightClose, PanelRightOpen } from "lucide-react";
16
+ import { TopBar } from "../topbar/TopBar";
17
+ import { SkillSidebar } from "../sidebar/SkillSidebar";
18
+ import { SessionSidebar } from "../sidebar/SessionSidebar";
19
+ import { ChatPanel } from "../chat/ChatPanel";
20
+ import { AssetsPanel } from "../assets/AssetsPanel";
21
+ import { NetworkDrawer } from "../dev/NetworkPanel";
22
+ import { useSidebarStore, useAssetsPanelStore, SIDEBAR_ICON_WIDTH } from "../../stores/use-sidebar-store";
23
+ import { useViewStore } from "../../stores/use-view-store";
24
+ import { ProcessPanel } from "../process/ProcessPanel";
25
+
26
+ export type CenterTab = "chat" | "process";
27
+
28
+ interface AppLayoutProps {
29
+ sidebarWidth: number;
30
+ handleResizeStart: (e: React.MouseEvent) => void;
31
+ }
32
+
33
+ export function AppLayout({
34
+ sidebarWidth,
35
+ handleResizeStart,
36
+ }: AppLayoutProps) {
37
+ useTranslation();
38
+
39
+ // 视图 Tab(会话/加工)— 来自全局 store
40
+ const centerTab = useViewStore((s) => s.activeView);
41
+ const setCenterTab = useViewStore((s) => s.setActiveView);
42
+
43
+ // 侧栏状态
44
+ const sbBreakpoint = useSidebarStore((s) => s.breakpoint);
45
+ const sbSidebarMode = useSidebarStore((s) => s.sidebarMode);
46
+ const sbDrawerOpen = useSidebarStore((s) => s.drawerOpen);
47
+ const sbSetDrawerOpen = useSidebarStore((s) => s.setDrawerOpen);
48
+
49
+ // 资源面板状态
50
+ const apVisible = useAssetsPanelStore((s) => s.assetsVisible);
51
+ const apDrawerOpen = useAssetsPanelStore((s) => s.assetsDrawerOpen);
52
+ const apSetDrawerOpen = useAssetsPanelStore((s) => s.setAssetsDrawerOpen);
53
+
54
+ // 侧栏:full/icon 占据布局空间;hidden 不占
55
+ const sidebarInLayout =
56
+ (sbSidebarMode === "full" || sbSidebarMode === "icon") &&
57
+ sbBreakpoint !== "mobile";
58
+ // 移动端抽屉
59
+ const sidebarDrawer = sbDrawerOpen && !sidebarInLayout;
60
+
61
+ // 实际渲染宽度:icon 模式锁定 56px
62
+ const effectiveWidth = sbSidebarMode === "icon" ? SIDEBAR_ICON_WIDTH : sidebarWidth;
63
+ const isCollapsed = sbSidebarMode === "icon";
64
+
65
+ // 资源面板:visible 时固定占据空间;否则抽屉
66
+ const assetsPinned = apVisible && sbBreakpoint === "wide";
67
+ const assetsShown = assetsPinned || apDrawerOpen;
68
+
69
+ return (
70
+ <div className="h-screen bg-[var(--color-bg-primary)] text-[var(--color-text-primary)] flex flex-col overflow-hidden">
71
+ {/* 顶栏 */}
72
+ <TopBar />
73
+
74
+ <div className="flex-1 flex overflow-hidden relative">
75
+ {/* ── 左:侧栏 ── */}
76
+ {sidebarInLayout ? (
77
+ /* 固定模式(full 或 icon) */
78
+ <div
79
+ className="sidebar-container bg-[var(--color-bg-sidebar)] border-r border-[var(--color-border-primary)] flex flex-col flex-shrink-0 overflow-hidden relative"
80
+ style={{ width: effectiveWidth }}
81
+ >
82
+ <SidebarInner
83
+ handleResizeStart={handleResizeStart}
84
+ isCollapsed={isCollapsed}
85
+ centerTab={centerTab}
86
+ setCenterTab={setCenterTab}
87
+ />
88
+ </div>
89
+ ) : sidebarDrawer ? (
90
+ /* 抽屉模式:浮层 + 遮罩(移动端) */
91
+ <>
92
+ <div
93
+ className="absolute inset-0 bg-black/40 z-20"
94
+ onClick={() => sbSetDrawerOpen(false)}
95
+ />
96
+ <div
97
+ className="absolute top-0 left-0 bottom-0 bg-[var(--color-bg-sidebar)] border-r border-[var(--color-border-primary)] flex flex-col z-30 shadow-xl"
98
+ style={{ width: sidebarWidth }}
99
+ >
100
+ <SidebarInner
101
+ isCollapsed={false}
102
+ showClose={true}
103
+ onClose={() => sbSetDrawerOpen(false)}
104
+ centerTab={centerTab}
105
+ setCenterTab={setCenterTab}
106
+ />
107
+ </div>
108
+ </>
109
+ ) : null}
110
+
111
+ {/* ── 中:对话区 ── */}
112
+ <div className="flex-1 flex flex-col overflow-hidden min-w-0">
113
+ {centerTab === "chat" ? <ChatPanel /> : <ProcessPanel />}
114
+ </div>
115
+
116
+ {/* ── 右:资源面板 ── */}
117
+ {assetsPinned ? (
118
+ /* 固定模式 */
119
+ <div className="bg-[var(--color-bg-secondary)] border-l border-[var(--color-border-primary)] flex flex-col flex-shrink-0 overflow-hidden w-[300px]">
120
+ <AssetsInner showClose={false} />
121
+ </div>
122
+ ) : assetsShown ? (
123
+ /* 抽屉模式 */
124
+ <>
125
+ <div
126
+ className="absolute inset-0 bg-black/40 z-20"
127
+ onClick={() => apSetDrawerOpen(false)}
128
+ />
129
+ <div className="absolute top-0 right-0 bottom-0 bg-[var(--color-bg-secondary)] border-l border-[var(--color-border-primary)] flex flex-col z-30 shadow-xl w-[300px]">
130
+ <AssetsInner
131
+ showClose={true}
132
+ onClose={() => apSetDrawerOpen(false)}
133
+ />
134
+ </div>
135
+ </>
136
+ ) : null}
137
+
138
+ {/* ── 右侧边缘:资源面板触发条(抽屉模式时显示) ── */}
139
+ {!assetsPinned && !apDrawerOpen && (
140
+ <button
141
+ onClick={() => apSetDrawerOpen(true)}
142
+ title="打开资源面板"
143
+ className="absolute top-1/2 right-0 -translate-y-1/2 z-10 px-1 py-3 bg-[var(--color-bg-secondary)] border border-r-0 border-[var(--color-border-primary)] rounded-l-lg hover:bg-[var(--color-bg-hover)] transition-colors"
144
+ >
145
+ <PanelRightOpen className="w-4 h-4 text-[var(--color-text-tertiary)]" />
146
+ </button>
147
+ )}
148
+ </div>
149
+
150
+ {/* 网络通讯面板(底部抽屉) */}
151
+ <NetworkDrawer />
152
+ </div>
153
+ );
154
+ }
155
+
156
+ // ===== 侧栏内容 =====
157
+
158
+ function SidebarInner({
159
+ handleResizeStart,
160
+ isCollapsed,
161
+ showClose,
162
+ onClose,
163
+ centerTab,
164
+ setCenterTab,
165
+ }: {
166
+ handleResizeStart?: (e: React.MouseEvent) => void;
167
+ isCollapsed: boolean;
168
+ showClose?: boolean;
169
+ onClose?: () => void;
170
+ centerTab: CenterTab;
171
+ setCenterTab: (tab: CenterTab) => void;
172
+ }) {
173
+ return (
174
+ <>
175
+ {/* 抽屉头部(关闭按钮,仅移动端抽屉模式) */}
176
+ {showClose && (
177
+ <div className="flex items-center justify-end px-2 py-1.5 border-b border-[var(--color-border-secondary)]">
178
+ <button
179
+ onClick={onClose}
180
+ title="关闭"
181
+ className="text-[var(--color-text-tertiary)] hover:text-[var(--color-text-primary)] p-1"
182
+ >
183
+ <PanelLeftClose className="w-4 h-4" />
184
+ </button>
185
+ </div>
186
+ )}
187
+
188
+ {/* Tab 切换(会话/加工) */}
189
+ <div className={`flex items-center gap-0.5 border-b border-[var(--color-border-secondary)] ${isCollapsed ? "flex-col py-2" : "px-2 py-1.5"}`}>
190
+ <SidebarTab
191
+ active={centerTab === "chat"}
192
+ onClick={() => setCenterTab("chat")}
193
+ label="会话"
194
+ icon="💬"
195
+ collapsed={isCollapsed}
196
+ />
197
+ <SidebarTab
198
+ active={centerTab === "process"}
199
+ onClick={() => setCenterTab("process")}
200
+ label="加工"
201
+ icon="⚙️"
202
+ collapsed={isCollapsed}
203
+ />
204
+ </div>
205
+
206
+ {/* 技能库 */}
207
+ {!isCollapsed && <SkillSidebar />}
208
+ {isCollapsed && <SkillSidebar collapsed />}
209
+
210
+ {/* 会话列表 */}
211
+ <div className={isCollapsed ? "flex-1 overflow-hidden" : "flex-1 overflow-auto"}>
212
+ <SessionSidebar collapsed={isCollapsed} />
213
+ </div>
214
+
215
+ {/* 拖拽条(仅完整模式) */}
216
+ {!showClose && !isCollapsed && handleResizeStart && (
217
+ <div
218
+ className="absolute right-0 top-0 bottom-0 w-1 cursor-col-resize hover:bg-[var(--color-accent)]/50 active:bg-[var(--color-accent)] transition-colors z-10 group"
219
+ onMouseDown={handleResizeStart}
220
+ style={{ width: 4, marginRight: -4 }}
221
+ >
222
+ <div className="absolute inset-y-0 left-1/2 w-0.5 bg-[var(--color-border-primary)] group-hover:bg-[var(--color-text-accent)] transition-colors -translate-x-1/2" />
223
+ </div>
224
+ )}
225
+ </>
226
+ );
227
+ }
228
+
229
+ function AssetsInner({
230
+ showClose,
231
+ onClose,
232
+ }: {
233
+ showClose: boolean;
234
+ onClose?: () => void;
235
+ }) {
236
+ const apSetVisible = useAssetsPanelStore((s) => s.setAssetsVisible);
237
+ const breakpoint = useSidebarStore((s) => s.breakpoint);
238
+
239
+ return (
240
+ <>
241
+ {showClose && (
242
+ <div className="flex items-center justify-end px-2 py-1.5 border-b border-[var(--color-border-secondary)]">
243
+ {breakpoint === "wide" && (
244
+ <button
245
+ onClick={() => {
246
+ apSetVisible(true);
247
+ onClose?.();
248
+ }}
249
+ title="固定资源面板"
250
+ className="text-[var(--color-text-tertiary)] hover:text-[var(--color-text-primary)] p-1 mr-1"
251
+ >
252
+ <PanelRightOpen className="w-4 h-4" />
253
+ </button>
254
+ )}
255
+ <button
256
+ onClick={onClose}
257
+ title="关闭"
258
+ className="text-[var(--color-text-tertiary)] hover:text-[var(--color-text-primary)] p-1"
259
+ >
260
+ <PanelRightClose className="w-4 h-4" />
261
+ </button>
262
+ </div>
263
+ )}
264
+ <AssetsPanel />
265
+ </>
266
+ );
267
+ }
268
+
269
+ // ===== 侧边栏 Tab 按钮 =====
270
+
271
+ function SidebarTab({
272
+ active,
273
+ onClick,
274
+ label,
275
+ icon,
276
+ collapsed,
277
+ }: {
278
+ active: boolean;
279
+ onClick: () => void;
280
+ label: string;
281
+ icon: string;
282
+ collapsed: boolean;
283
+ }) {
284
+ if (collapsed) {
285
+ return (
286
+ <button
287
+ onClick={onClick}
288
+ title={label}
289
+ className={`flex-1 flex items-center justify-center py-2 text-lg rounded-md transition-colors ${
290
+ active
291
+ ? "bg-[var(--color-accent)]/15"
292
+ : "hover:bg-[var(--color-bg-hover)]"
293
+ }`}
294
+ >
295
+ {icon}
296
+ </button>
297
+ );
298
+ }
299
+ return (
300
+ <button
301
+ onClick={onClick}
302
+ className={`flex-1 px-3 py-1.5 text-xs font-medium rounded-md transition-colors ${
303
+ active
304
+ ? "bg-[var(--color-accent)]/15 text-[var(--color-text-accent)]"
305
+ : "text-[var(--color-text-tertiary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-hover)]"
306
+ }`}
307
+ >
308
+ {label}
309
+ </button>
310
+ );
311
+ }
@@ -0,0 +1,310 @@
1
+ /**
2
+ * SetupWizard — 浏览器连接向导 Modal
3
+ *
4
+ * 未连接时,从顶栏入口触发。全屏遮罩 + 居中步骤卡片。
5
+ * 实时检测连接状态,用户装好扩展后自动跳到成功页。
6
+ */
7
+
8
+ import { useState, useEffect, useCallback } from "react";
9
+ import {
10
+ Globe,
11
+ CheckCircle2,
12
+ Loader2,
13
+ Download,
14
+ Key,
15
+ Puzzle,
16
+ ExternalLink,
17
+ X,
18
+ PartyPopper,
19
+ AlertCircle,
20
+ } from "lucide-react";
21
+ import { useConnectionStore } from "../../stores/use-connection-store";
22
+ import { apiClient } from "../../lib/api-client";
23
+
24
+ export function SetupWizard({ onClose }: { onClose: () => void }) {
25
+ const browserStatus = useConnectionStore((s) => s.browserStatus);
26
+ const checkBrowser = useConnectionStore((s) => s.checkBrowser);
27
+ const startConnectionPolling = useConnectionStore((s) => s.startConnectionPolling);
28
+
29
+ const [browserKey, setBrowserKey] = useState<string | null>(null);
30
+ const [creating, setCreating] = useState(false);
31
+ const [downloading, setDownloading] = useState(false);
32
+ const [error, setError] = useState<string | null>(null);
33
+
34
+ const isConnected = browserStatus === "online";
35
+
36
+ // 启动轮询(如果还没在轮询)
37
+ useEffect(() => {
38
+ startConnectionPolling();
39
+ }, [startConnectionPolling]);
40
+
41
+ const handleCreate = async (): Promise<void> => {
42
+ setCreating(true);
43
+ setError(null);
44
+ try {
45
+ const baseUrl = apiClient.getBaseUrl();
46
+ const token = apiClient.getAuthToken();
47
+ const res = await fetch(`${baseUrl}/api/create-browser?token=${token}`, {
48
+ method: "POST",
49
+ headers: { "Content-Type": "application/json" },
50
+ body: JSON.stringify({ name: "Browser Agent" }),
51
+ });
52
+ if (!res.ok) throw new Error(`创建失败 (${res.status})`);
53
+ const data = await res.json();
54
+ if (data.key) {
55
+ setBrowserKey(data.key);
56
+ } else {
57
+ throw new Error(data.error || "未返回 key");
58
+ }
59
+ } catch (err) {
60
+ setError(err instanceof Error ? err.message : "创建连接失败");
61
+ } finally {
62
+ setCreating(false);
63
+ }
64
+ };
65
+
66
+ const handleDownload = async (): Promise<void> => {
67
+ if (!browserKey) return;
68
+ setDownloading(true);
69
+ setError(null);
70
+ try {
71
+ const baseUrl = apiClient.getBaseUrl();
72
+ const token = apiClient.getAuthToken();
73
+ const res = await fetch(`${baseUrl}/api/pack-extension?token=${token}`, {
74
+ method: "POST",
75
+ headers: { "Content-Type": "application/json" },
76
+ body: JSON.stringify({ key: browserKey }),
77
+ });
78
+ if (!res.ok) {
79
+ const errData = await res.json().catch(() => ({}));
80
+ throw new Error(errData.error || `下载失败 (${res.status})`);
81
+ }
82
+ const blob = await res.blob();
83
+ const url = URL.createObjectURL(blob);
84
+ const a = document.createElement("a");
85
+ a.href = url;
86
+ a.download = "browser-agent-extension.zip";
87
+ a.click();
88
+ URL.revokeObjectURL(url);
89
+ } catch (err) {
90
+ setError(err instanceof Error ? err.message : "下载扩展失败");
91
+ } finally {
92
+ setDownloading(false);
93
+ }
94
+ };
95
+
96
+ const handleManualCheck = useCallback(async (): Promise<void> => {
97
+ await checkBrowser();
98
+ }, [checkBrowser]);
99
+
100
+ return (
101
+ <div
102
+ className="fixed inset-0 bg-black/60 backdrop-blur-sm z-50 flex items-center justify-center p-6"
103
+ onClick={onClose}
104
+ >
105
+ <div
106
+ className="max-w-lg w-full bg-[var(--color-bg-sidebar)] border border-[var(--color-border-primary)] rounded-2xl shadow-2xl max-h-[90vh] overflow-auto"
107
+ onClick={(e) => e.stopPropagation()}
108
+ >
109
+ {/* 成功状态 */}
110
+ {isConnected ? (
111
+ <SuccessView onClose={onClose} />
112
+ ) : (
113
+ <>
114
+ {/* 头部 */}
115
+ <div className="flex items-center justify-between p-5 border-b border-[var(--color-border-primary)]">
116
+ <div className="flex items-center gap-3">
117
+ <div className="w-10 h-10 rounded-xl bg-[var(--color-accent)]/10 flex items-center justify-center">
118
+ <Globe className="w-5 h-5 text-[var(--color-text-accent)]" />
119
+ </div>
120
+ <div>
121
+ <h2 className="text-base font-semibold">连接你的浏览器</h2>
122
+ <p className="text-xs text-[var(--color-text-tertiary)]">
123
+ 安装扩展,1 分钟搞定
124
+ </p>
125
+ </div>
126
+ </div>
127
+ <button
128
+ onClick={onClose}
129
+ className="text-[var(--color-text-tertiary)] hover:text-[var(--color-text-primary)] p-1"
130
+ >
131
+ <X className="w-5 h-5" />
132
+ </button>
133
+ </div>
134
+
135
+ {/* 步骤内容 */}
136
+ <div className="p-5 space-y-3">
137
+ {/* 步骤 1 */}
138
+ <Step
139
+ icon={<Key className="w-4 h-4" />}
140
+ title="创建连接"
141
+ desc="生成你的专属浏览器连接"
142
+ state={browserKey ? "done" : "active"}
143
+ >
144
+ {!browserKey && (
145
+ <button
146
+ onClick={handleCreate}
147
+ disabled={creating}
148
+ className="px-3 py-1.5 text-xs bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] rounded transition-colors disabled:opacity-50 flex items-center gap-1.5"
149
+ >
150
+ {creating ? (
151
+ <Loader2 className="w-3 h-3 animate-spin" />
152
+ ) : (
153
+ <Key className="w-3 h-3" />
154
+ )}
155
+ 创建连接
156
+ </button>
157
+ )}
158
+ </Step>
159
+
160
+ {/* 步骤 2 */}
161
+ <Step
162
+ icon={<Download className="w-4 h-4" />}
163
+ title="下载扩展"
164
+ desc="下载已配置好连接的 Chrome 扩展"
165
+ state={browserKey ? "active" : "pending"}
166
+ >
167
+ {browserKey && (
168
+ <button
169
+ onClick={handleDownload}
170
+ disabled={downloading}
171
+ className="px-3 py-1.5 text-xs bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] rounded transition-colors disabled:opacity-50 flex items-center gap-1.5"
172
+ >
173
+ {downloading ? (
174
+ <Loader2 className="w-3 h-3 animate-spin" />
175
+ ) : (
176
+ <Download className="w-3 h-3" />
177
+ )}
178
+ 下载扩展 (ZIP)
179
+ </button>
180
+ )}
181
+ </Step>
182
+
183
+ {/* 步骤 3 */}
184
+ <Step
185
+ icon={<Puzzle className="w-4 h-4" />}
186
+ title="加载到 Chrome"
187
+ desc="安装扩展后自动连接,无需手动操作"
188
+ state={browserKey ? "active" : "pending"}
189
+ >
190
+ {browserKey && (
191
+ <div className="space-y-2">
192
+ <ol className="text-xs text-[var(--color-text-secondary)] space-y-1">
193
+ <li>① 解压下载的 ZIP 文件</li>
194
+ <li>② 打开 chrome://extensions/</li>
195
+ <li>③ 开启右上角「开发者模式」</li>
196
+ <li>④ 点击「加载已解压的扩展程序」</li>
197
+ </ol>
198
+ <div className="flex gap-2">
199
+ <a
200
+ href="chrome://extensions/"
201
+ className="px-2.5 py-1.5 text-xs border border-[var(--color-border-primary)] rounded hover:bg-[var(--color-bg-hover)] flex items-center gap-1"
202
+ >
203
+ <ExternalLink className="w-3 h-3" />
204
+ 打开扩展页
205
+ </a>
206
+ <button
207
+ onClick={handleManualCheck}
208
+ className="px-2.5 py-1.5 text-xs bg-[var(--color-accent)]/20 text-[var(--color-text-accent)] rounded hover:bg-[var(--color-accent)]/30 flex items-center gap-1"
209
+ >
210
+ 立即检测
211
+ </button>
212
+ </div>
213
+ </div>
214
+ )}
215
+ </Step>
216
+
217
+ {/* 错误 */}
218
+ {error && (
219
+ <div className="flex items-start gap-2 p-2.5 bg-red-500/10 border border-red-500/20 rounded-lg text-xs text-[var(--color-text-error)]">
220
+ <AlertCircle className="w-3.5 h-3.5 flex-shrink-0 mt-0.5" />
221
+ <span>{error}</span>
222
+ </div>
223
+ )}
224
+ </div>
225
+
226
+ {/* 底部:实时检测提示 */}
227
+ <div className="px-5 py-3 border-t border-[var(--color-border-primary)] bg-[var(--color-bg-secondary)] rounded-b-2xl flex items-center justify-center gap-2 text-xs text-[var(--color-text-tertiary)]">
228
+ <span className="relative flex w-2 h-2">
229
+ <span className="absolute inline-flex w-full h-full rounded-full bg-[var(--color-text-accent)] opacity-60 animate-ping" />
230
+ <span className="relative inline-flex w-2 h-2 rounded-full bg-[var(--color-text-accent)]" />
231
+ </span>
232
+ <span>正在实时检测,扩展加载后自动进入工作台</span>
233
+ </div>
234
+ </>
235
+ )}
236
+ </div>
237
+ </div>
238
+ );
239
+ }
240
+
241
+ // ===== 成功视图 =====
242
+
243
+ function SuccessView({ onClose }: { onClose: () => void }) {
244
+ return (
245
+ <div className="p-8 text-center">
246
+ <div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-[var(--color-text-success)]/10 mb-4">
247
+ <PartyPopper className="w-8 h-8 text-[var(--color-text-success)]" />
248
+ </div>
249
+ <h2 className="text-xl font-bold mb-2">连接成功!</h2>
250
+ <p className="text-sm text-[var(--color-text-secondary)] mb-6">
251
+ 浏览器已连接,可以开始使用了。
252
+ </p>
253
+ <button
254
+ onClick={onClose}
255
+ className="px-6 py-2.5 text-sm bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] rounded-lg transition-colors"
256
+ >
257
+ 开始使用
258
+ </button>
259
+ </div>
260
+ );
261
+ }
262
+
263
+ // ===== 步骤组件 =====
264
+
265
+ type StepState = "pending" | "active" | "done";
266
+
267
+ function Step({
268
+ icon,
269
+ title,
270
+ desc,
271
+ state,
272
+ children,
273
+ }: {
274
+ icon: React.ReactNode;
275
+ title: string;
276
+ desc: string;
277
+ state: StepState;
278
+ children?: React.ReactNode;
279
+ }) {
280
+ return (
281
+ <div
282
+ className={`p-3.5 rounded-xl border transition-all ${
283
+ state === "done"
284
+ ? "border-[var(--color-text-success)]/30 bg-[var(--color-text-success)]/5"
285
+ : state === "active"
286
+ ? "border-[var(--color-accent)] bg-[var(--color-accent)]/5"
287
+ : "border-[var(--color-border-secondary)] opacity-50"
288
+ }`}
289
+ >
290
+ <div className="flex items-center gap-3">
291
+ <div
292
+ className={`w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0 ${
293
+ state === "done"
294
+ ? "bg-[var(--color-text-success)]/20 text-[var(--color-text-success)]"
295
+ : state === "active"
296
+ ? "bg-[var(--color-accent)]/20 text-[var(--color-text-accent)]"
297
+ : "bg-[var(--color-bg-tertiary)] text-[var(--color-text-tertiary)]"
298
+ }`}
299
+ >
300
+ {state === "done" ? <CheckCircle2 className="w-4 h-4" /> : icon}
301
+ </div>
302
+ <div className="flex-1 min-w-0">
303
+ <div className="text-sm font-medium">{title}</div>
304
+ <div className="text-xs text-[var(--color-text-tertiary)] mt-0.5">{desc}</div>
305
+ </div>
306
+ </div>
307
+ {state === "active" && children && <div className="mt-3 pl-11">{children}</div>}
308
+ </div>
309
+ );
310
+ }