@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,133 @@
1
+ /**
2
+ * 上下文面板 — 文件夹 / 连接器 / 工作文件
3
+ */
4
+ import { useEffect } from 'react';
5
+ import { Folder, Globe, FileText, ChevronDown, ChevronRight } from 'lucide-react';
6
+ import { useContextStore } from '../../stores/use-context-store';
7
+ import { useViewStore } from '../../stores/use-view-store';
8
+
9
+ function SubSection({
10
+ label,
11
+ icon: Icon,
12
+ count,
13
+ collapsed,
14
+ onToggle,
15
+ children,
16
+ }: {
17
+ label: string;
18
+ icon: typeof Folder;
19
+ count?: number;
20
+ collapsed: boolean;
21
+ onToggle: () => void;
22
+ children: React.ReactNode;
23
+ }) {
24
+ return (
25
+ <div className="mb-1">
26
+ <button
27
+ onClick={onToggle}
28
+ className="w-full flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors"
29
+ >
30
+ {collapsed ? (
31
+ <ChevronRight className="w-3.5 h-3.5" />
32
+ ) : (
33
+ <ChevronDown className="w-3.5 h-3.5" />
34
+ )}
35
+ <Icon className="w-3.5 h-3.5" />
36
+ <span>{label}</span>
37
+ {count !== undefined && (
38
+ <span className="ml-auto text-[var(--color-text-tertiary)]">{count}</span>
39
+ )}
40
+ </button>
41
+ {!collapsed && <div className="pl-7 pt-0.5">{children}</div>}
42
+ </div>
43
+ );
44
+ }
45
+
46
+ export function ContextPanel() {
47
+ const folders = useContextStore((s) => s.folders);
48
+ const connectors = useContextStore((s) => s.connectors);
49
+ const workingFiles = useContextStore((s) => s.workingFiles);
50
+ const fetchAll = useContextStore((s) => s.fetchAll);
51
+
52
+ const collapsed = useViewStore((s) => s.rightPanelCollapsed['context']);
53
+ const toggle = useViewStore((s) => s.toggleRightPanel);
54
+ const rightCollapsed = useViewStore((s) => s.rightPanelCollapsed);
55
+
56
+ useEffect(() => {
57
+ fetchAll();
58
+ }, []);
59
+
60
+ return (
61
+ <div className="border-b border-[var(--color-border-secondary)]">
62
+ <button
63
+ onClick={() => toggle('context')}
64
+ className="w-full flex items-center gap-1.5 px-4 py-3 text-sm font-semibold text-[var(--color-text-primary)] hover:bg-[var(--color-bg-hover)] transition-colors"
65
+ >
66
+ {collapsed ? <ChevronRight className="w-4 h-4" /> : <ChevronDown className="w-4 h-4" />}
67
+ Context
68
+ </button>
69
+ {!collapsed && (
70
+ <div className="px-3 pb-3">
71
+ {/* Selected folders */}
72
+ <SubSection
73
+ label="Selected folders"
74
+ icon={Folder}
75
+ count={folders.length}
76
+ collapsed={!!rightCollapsed['context-folders']}
77
+ onToggle={() => toggle('context-folders')}
78
+ >
79
+ {folders.map((f) => (
80
+ <div
81
+ key={f.path}
82
+ className="flex items-center gap-2 px-2 py-1 text-xs text-[var(--color-text-secondary)]"
83
+ >
84
+ <span className="w-1.5 h-1.5 rounded-full bg-[var(--color-text-accent)]" />
85
+ <span className="truncate">{f.name}</span>
86
+ </div>
87
+ ))}
88
+ </SubSection>
89
+
90
+ {/* Connectors */}
91
+ <SubSection
92
+ label="Connectors"
93
+ icon={Globe}
94
+ count={connectors.filter((c) => c.enabled).length}
95
+ collapsed={!!rightCollapsed['context-connectors']}
96
+ onToggle={() => toggle('context-connectors')}
97
+ >
98
+ {connectors.map((c) => (
99
+ <div
100
+ key={c.id}
101
+ className="flex items-center gap-2 px-2 py-1 text-xs text-[var(--color-text-secondary)]"
102
+ >
103
+ <span
104
+ className={`w-1.5 h-1.5 rounded-full ${c.enabled ? 'bg-green-500' : 'bg-[var(--color-text-tertiary)]'}`}
105
+ />
106
+ <span className="truncate">{c.name}</span>
107
+ </div>
108
+ ))}
109
+ </SubSection>
110
+
111
+ {/* Working files */}
112
+ <SubSection
113
+ label="Working files"
114
+ icon={FileText}
115
+ count={workingFiles.length}
116
+ collapsed={!!rightCollapsed['context-files']}
117
+ onToggle={() => toggle('context-files')}
118
+ >
119
+ {workingFiles.map((f) => (
120
+ <div
121
+ key={f.path}
122
+ className="flex items-center gap-2 px-2 py-1 text-xs text-[var(--color-text-secondary)]"
123
+ >
124
+ <FileText className="w-3 h-3 text-[var(--color-text-tertiary)]" />
125
+ <span className="truncate">{f.name}</span>
126
+ </div>
127
+ ))}
128
+ </SubSection>
129
+ </div>
130
+ )}
131
+ </div>
132
+ );
133
+ }
@@ -0,0 +1,206 @@
1
+ /**
2
+ * 元素选择器 — 在 iframe 中选取元素,提取 CSS selector
3
+ *
4
+ * 工作方式:
5
+ * 1. 启用 inspect 模式 → 在 iframe 内容文档添加事件监听
6
+ * 2. hover → 高亮元素;click → 提取 CSS selector
7
+ * 3. 用户可复制 selector 到聊天输入框
8
+ */
9
+ import { useState, useCallback, useRef, useEffect } from 'react';
10
+ import { MousePointer2, Copy, Check } from 'lucide-react';
11
+
12
+ interface ElementPickerProps {
13
+ iframeRef: React.RefObject<HTMLIFrameElement | null>;
14
+ onElementSelected: (selector: string, tagName: string) => void;
15
+ enabled: boolean;
16
+ }
17
+
18
+ function generateSelector(el: Element): string {
19
+ if (!el || el === document.documentElement) return 'html';
20
+ if (el.id) return `#${CSS.escape(el.id)}`;
21
+
22
+ const tag = el.tagName.toLowerCase();
23
+ const parent = el.parentElement;
24
+ if (!parent) return tag;
25
+
26
+ const siblings = Array.from(parent.children).filter((c) => c.tagName === el.tagName);
27
+ const path = generateSelector(parent);
28
+
29
+ if (siblings.length <= 1) return `${path} > ${tag}`;
30
+ const index = Array.from(parent.children).indexOf(el) + 1;
31
+ return `${path} > ${tag}:nth-child(${index})`;
32
+ }
33
+
34
+ export function ElementPicker({ iframeRef, onElementSelected, enabled }: ElementPickerProps) {
35
+ const [active, setActive] = useState(false);
36
+ const [selectedEl, setSelectedEl] = useState<{ selector: string; tagName: string } | null>(null);
37
+ const [copied, setCopied] = useState(false);
38
+
39
+ const highlightRef = useRef<Element | null>(null);
40
+ const activeRef = useRef(false);
41
+
42
+ // 用 ref 保存回调,避免事件监听中的闭包陈旧问题
43
+ const onElementSelectedRef = useRef(onElementSelected);
44
+ onElementSelectedRef.current = onElementSelected;
45
+
46
+ const removeHighlight = useCallback(() => {
47
+ if (highlightRef.current) {
48
+ (highlightRef.current as HTMLElement).style.outline = '';
49
+ highlightRef.current = null;
50
+ }
51
+ }, []);
52
+
53
+ // 用 ref 保存稳定的事件处理函数
54
+ const handleRef = useRef({
55
+ click: null as ((e: MouseEvent) => void) | null,
56
+ over: null as ((e: MouseEvent) => void) | null,
57
+ out: null as ((e: MouseEvent) => void) | null,
58
+ });
59
+
60
+ const addListeners = useCallback(
61
+ (doc: Document) => {
62
+ removeHighlight();
63
+
64
+ const clickHandler = (e: MouseEvent) => {
65
+ if (!activeRef.current) return;
66
+ e.preventDefault();
67
+ e.stopPropagation();
68
+
69
+ const target = e.target as Element;
70
+ if (target === doc.documentElement) return;
71
+
72
+ const selector = generateSelector(target);
73
+ const tagName = target.tagName.toLowerCase();
74
+
75
+ setSelectedEl({ selector, tagName });
76
+ onElementSelectedRef.current(selector, tagName);
77
+
78
+ setActive(false);
79
+ activeRef.current = false;
80
+ removeListeners(doc);
81
+ doc.body.style.cursor = '';
82
+ };
83
+
84
+ const overHandler = (e: MouseEvent) => {
85
+ if (!activeRef.current) return;
86
+ const target = e.target as Element;
87
+ if (target === doc.documentElement) return;
88
+ removeHighlight();
89
+ (target as HTMLElement).style.outline = '2px solid #6366f1';
90
+ (target as HTMLElement).style.outlineOffset = '-2px';
91
+ highlightRef.current = target;
92
+ };
93
+
94
+ const outHandler = (_e: MouseEvent) => {
95
+ removeHighlight();
96
+ };
97
+
98
+ handleRef.current = { click: clickHandler, over: overHandler, out: outHandler };
99
+
100
+ doc.addEventListener('click', clickHandler, true);
101
+ doc.addEventListener('mouseover', overHandler, true);
102
+ doc.addEventListener('mouseout', outHandler, true);
103
+ doc.body.style.cursor = 'crosshair';
104
+ },
105
+ [removeHighlight],
106
+ );
107
+
108
+ const removeListeners = useCallback((doc: Document) => {
109
+ const { click, over, out } = handleRef.current;
110
+ if (click) doc.removeEventListener('click', click, true);
111
+ if (over) doc.removeEventListener('mouseover', over, true);
112
+ if (out) doc.removeEventListener('mouseout', out, true);
113
+ doc.body.style.cursor = '';
114
+ handleRef.current = { click: null, over: null, out: null };
115
+ }, []);
116
+
117
+ const toggleInspect = useCallback(() => {
118
+ const nextActive = !active;
119
+ setActive(nextActive);
120
+ activeRef.current = nextActive;
121
+
122
+ if (!nextActive) {
123
+ setSelectedEl(null);
124
+ }
125
+
126
+ const iframe = iframeRef.current;
127
+ if (!iframe) return;
128
+
129
+ try {
130
+ const doc = iframe.contentDocument || iframe.contentWindow?.document;
131
+ if (!doc) return;
132
+
133
+ if (nextActive) {
134
+ addListeners(doc);
135
+ } else {
136
+ removeListeners(doc);
137
+ removeHighlight();
138
+ }
139
+ } catch {
140
+ setActive(false);
141
+ activeRef.current = false;
142
+ }
143
+ }, [active, iframeRef, addListeners, removeListeners, removeHighlight]);
144
+
145
+ const handleCopy = useCallback(() => {
146
+ if (!selectedEl) return;
147
+ navigator.clipboard.writeText(selectedEl.selector);
148
+ setCopied(true);
149
+ setTimeout(() => setCopied(false), 1500);
150
+ }, [selectedEl]);
151
+
152
+ // 组件卸载时清理
153
+ useEffect(() => {
154
+ return () => {
155
+ const iframe = iframeRef.current;
156
+ if (iframe) {
157
+ try {
158
+ const doc = iframe.contentDocument || iframe.contentWindow?.document;
159
+ if (doc) removeListeners(doc);
160
+ } catch {
161
+ /* ignore */
162
+ }
163
+ }
164
+ removeHighlight();
165
+ };
166
+ }, [iframeRef, removeListeners, removeHighlight]);
167
+
168
+ if (!enabled) return null;
169
+
170
+ return (
171
+ <div className="border-t border-[var(--color-border-secondary)]">
172
+ <div className="flex items-center gap-1 px-3 py-2">
173
+ <button
174
+ onClick={toggleInspect}
175
+ className={`flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg text-xs font-medium transition-all ${
176
+ active
177
+ ? 'bg-[var(--color-accent)] text-white shadow-sm'
178
+ : 'text-[var(--color-text-secondary)] hover:bg-[var(--color-bg-hover)]'
179
+ }`}
180
+ >
181
+ <MousePointer2 className={`w-3.5 h-3.5 ${active ? 'animate-pulse' : ''}`} />
182
+ {active ? '选取中...' : '选取元素'}
183
+ </button>
184
+ </div>
185
+
186
+ {selectedEl && (
187
+ <div className="flex items-center gap-1.5 px-3 pb-2">
188
+ <div className="flex-1 px-2.5 py-1.5 rounded-md bg-[var(--color-bg-tertiary)] font-mono text-xs text-[var(--color-text-accent)] truncate">
189
+ {selectedEl.selector}
190
+ </div>
191
+ <button
192
+ onClick={handleCopy}
193
+ className="p-1.5 rounded-md hover:bg-[var(--color-bg-hover)] transition-colors text-[var(--color-text-tertiary)] hover:text-[var(--color-text-accent)]"
194
+ title="复制选择器"
195
+ >
196
+ {copied ? (
197
+ <Check className="w-3.5 h-3.5 text-green-500" />
198
+ ) : (
199
+ <Copy className="w-3.5 h-3.5" />
200
+ )}
201
+ </button>
202
+ </div>
203
+ )}
204
+ </div>
205
+ );
206
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * 右侧预览区块 — 浏览器预览 + 地址栏 + 元素选择器
3
+ *
4
+ * 两种使用场景:
5
+ * - Code Tab 主内容:自带的标题栏 + 关闭(closeTab)
6
+ * - 聊天链接展开预览:由父级传入 onClose(closePreview),复用同一套 UI
7
+ */
8
+ import { useRef, useCallback, useState } from 'react';
9
+ import { Globe, X, ArrowLeft, RotateCw, Loader2 } from 'lucide-react';
10
+ import { usePreviewStore } from '../../stores/use-preview-store';
11
+ import { ElementPicker } from './ElementPicker';
12
+
13
+ interface PreviewBlockProps {
14
+ /** 关闭按钮回调;未传则使用 store 的 closeTab(Code Tab 场景) */
15
+ onClose?: () => void;
16
+ }
17
+
18
+ export function PreviewBlock({ onClose }: PreviewBlockProps) {
19
+ const currentTab = usePreviewStore((s) => s.currentTab);
20
+ const closeTab = usePreviewStore((s) => s.closeTab);
21
+ const openUrl = usePreviewStore((s) => s.openUrl);
22
+ const navigate = usePreviewStore((s) => s.navigate);
23
+ const navState = usePreviewStore((s) => s.navState);
24
+ const iframeRef = useRef<HTMLIFrameElement | null>(null);
25
+ const [urlInput, setUrlInput] = useState(currentTab?.url ?? '');
26
+
27
+ const handleElementSelected = useCallback((selector: string, tagName: string) => {
28
+ console.warn(`[ElementPicker] Selected ${tagName}: ${selector}`);
29
+ }, []);
30
+
31
+ const handleUrlSubmit = useCallback(() => {
32
+ if (urlInput.trim()) openUrl(urlInput.trim());
33
+ }, [urlInput, openUrl]);
34
+
35
+ const handleClose = onClose ?? closeTab;
36
+
37
+ // 加载中且尚无 tab:显示加载态,避免空状态文案误闪
38
+ if (!currentTab && navState === 'loading') {
39
+ return (
40
+ <div className="flex-1 flex flex-col">
41
+ <div className="flex items-center justify-between px-3 py-2.5 border-b border-[var(--color-border-secondary)]">
42
+ <span className="text-sm font-semibold text-[var(--color-text-primary)]">Preview</span>
43
+ {onClose && (
44
+ <button
45
+ onClick={handleClose}
46
+ title="关闭预览"
47
+ className="p-1 rounded hover:bg-[var(--color-bg-hover)] text-[var(--color-text-tertiary)] hover:text-[var(--color-text-primary)] transition-colors"
48
+ >
49
+ <X className="w-4 h-4" />
50
+ </button>
51
+ )}
52
+ </div>
53
+ <div className="flex-1 flex items-center justify-center">
54
+ <Loader2 className="w-5 h-5 animate-spin text-[var(--color-text-tertiary)]" />
55
+ </div>
56
+ </div>
57
+ );
58
+ }
59
+
60
+ // 空状态:提示用户从聊天中点击 localhost 链接打开预览
61
+ if (!currentTab) {
62
+ return (
63
+ <div className="flex-1 flex flex-col">
64
+ <div className="flex items-center justify-between px-3 py-2.5 border-b border-[var(--color-border-secondary)]">
65
+ <span className="text-sm font-semibold text-[var(--color-text-primary)]">Preview</span>
66
+ {onClose && (
67
+ <button
68
+ onClick={handleClose}
69
+ title="关闭预览"
70
+ className="p-1 rounded hover:bg-[var(--color-bg-hover)] text-[var(--color-text-tertiary)] hover:text-[var(--color-text-primary)] transition-colors"
71
+ >
72
+ <X className="w-4 h-4" />
73
+ </button>
74
+ )}
75
+ </div>
76
+ <div className="flex-1 flex items-center justify-center px-4">
77
+ <div className="text-center w-full">
78
+ <div className="w-12 h-12 rounded-xl bg-[var(--color-bg-tertiary)] flex items-center justify-center mx-auto mb-3">
79
+ <Globe className="w-6 h-6 text-[var(--color-text-tertiary)]" />
80
+ </div>
81
+ <p className="text-sm text-[var(--color-text-secondary)] mb-1">暂无预览</p>
82
+ <p className="text-xs text-[var(--color-text-tertiary)] leading-relaxed">
83
+ 当聊天中出现 localhost 链接时,点击即可在此打开预览。
84
+ </p>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ );
89
+ }
90
+
91
+ return (
92
+ <div className="flex flex-col h-full">
93
+ {/* 标题栏 */}
94
+ <div className="flex items-center justify-between px-3 py-2 border-b border-[var(--color-border-secondary)]">
95
+ <div className="flex items-center gap-2 min-w-0">
96
+ <Globe className="w-3.5 h-3.5 text-[var(--color-text-accent)] flex-shrink-0" />
97
+ <span className="text-sm font-semibold text-[var(--color-text-primary)]">Preview</span>
98
+ </div>
99
+ <button
100
+ onClick={handleClose}
101
+ className="p-1 rounded hover:bg-[var(--color-bg-hover)] transition-colors text-[var(--color-text-tertiary)]"
102
+ title="关闭预览"
103
+ >
104
+ <X className="w-3.5 h-3.5" />
105
+ </button>
106
+ </div>
107
+
108
+ {/* 地址栏 */}
109
+ <div className="flex items-center gap-1 px-2 py-1.5 border-b border-[var(--color-border-secondary)]">
110
+ <button
111
+ onClick={() => navigate('back')}
112
+ disabled={!currentTab.canGoBack}
113
+ className="p-1 rounded hover:bg-[var(--color-bg-hover)] disabled:opacity-30 transition-colors text-[var(--color-text-tertiary)]"
114
+ >
115
+ <ArrowLeft className="w-3.5 h-3.5" />
116
+ </button>
117
+ <button
118
+ onClick={() => navigate('reload')}
119
+ className="p-1 rounded hover:bg-[var(--color-bg-hover)] transition-colors text-[var(--color-text-tertiary)]"
120
+ >
121
+ {navState === 'loading' ? (
122
+ <Loader2 className="w-3.5 h-3.5 animate-spin" />
123
+ ) : (
124
+ <RotateCw className="w-3.5 h-3.5" />
125
+ )}
126
+ </button>
127
+ <input
128
+ value={urlInput || currentTab.url}
129
+ onChange={(e) => setUrlInput(e.target.value)}
130
+ onKeyDown={(e) => e.key === 'Enter' && handleUrlSubmit()}
131
+ placeholder="URL"
132
+ className="flex-1 min-w-0 px-2 py-1 rounded bg-[var(--color-bg-primary)] border border-[var(--color-border-primary)] text-[11px] font-mono text-[var(--color-text-primary)] focus:border-[var(--color-text-accent)] outline-none transition-colors"
133
+ />
134
+ </div>
135
+
136
+ {/* iframe 浏览器 */}
137
+ <div className="flex-1 min-h-[150px] overflow-hidden bg-white mx-3 my-2 rounded-lg border border-[var(--color-border-primary)]">
138
+ <iframe
139
+ ref={iframeRef}
140
+ src={currentTab.url}
141
+ className="w-full h-full border-0"
142
+ title={currentTab.url}
143
+ sandbox="allow-scripts allow-same-origin allow-forms"
144
+ />
145
+ </div>
146
+
147
+ {/* 元素选择器 */}
148
+ <ElementPicker
149
+ iframeRef={iframeRef}
150
+ onElementSelected={handleElementSelected}
151
+ enabled={true}
152
+ />
153
+ </div>
154
+ );
155
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * 进度面板 — 步骤可视化(带状态文字 + 详情)
3
+ */
4
+ import {
5
+ CheckCircle2,
6
+ Circle,
7
+ Loader2,
8
+ AlertCircle,
9
+ ChevronDown,
10
+ ChevronRight,
11
+ type LucideIcon,
12
+ } from 'lucide-react';
13
+ import { useTaskStore, type Step } from '../../stores/use-task-store';
14
+ import { useViewStore } from '../../stores/use-view-store';
15
+
16
+ const STEP_ICON: Record<Step['status'], { icon: LucideIcon; color: string; bg: string }> = {
17
+ pending: { icon: Circle, color: 'text-slate-400', bg: 'bg-slate-100 dark:bg-slate-700/50' },
18
+ running: { icon: Loader2, color: 'text-indigo-500', bg: 'bg-indigo-100 dark:bg-indigo-900/30' },
19
+ done: { icon: CheckCircle2, color: 'text-green-600', bg: 'bg-green-100 dark:bg-green-900/30' },
20
+ error: { icon: AlertCircle, color: 'text-red-500', bg: 'bg-red-100 dark:bg-red-900/30' },
21
+ };
22
+
23
+ export function ProgressPanel() {
24
+ const currentTaskId = useTaskStore((s) => s.currentTaskId);
25
+ const tasks = useTaskStore((s) => s.tasks);
26
+ const currentTask = tasks.find((t) => t.id === currentTaskId);
27
+ const steps = currentTask?.progress?.steps ?? [];
28
+
29
+ const collapsed = useViewStore((s) => s.rightPanelCollapsed['progress']);
30
+ const toggle = useViewStore((s) => s.toggleRightPanel);
31
+
32
+ return (
33
+ <div className="border-b border-[var(--color-border-secondary)]">
34
+ <button
35
+ onClick={() => toggle('progress')}
36
+ className="w-full flex items-center gap-2 px-4 py-3 text-sm font-semibold text-[var(--color-text-primary)] hover:bg-[var(--color-bg-hover)] transition-colors"
37
+ >
38
+ {collapsed ? <ChevronRight className="w-4 h-4" /> : <ChevronDown className="w-4 h-4" />}
39
+ Progress
40
+ {steps.length > 0 && (
41
+ <span className="ml-auto text-xs font-normal text-[var(--color-text-tertiary)]">
42
+ {steps.filter((s) => s.status === 'done').length}/{steps.length}
43
+ </span>
44
+ )}
45
+ </button>
46
+ {!collapsed && (
47
+ <div className="px-4 pb-4">
48
+ {steps.length === 0 ? (
49
+ <p className="text-xs text-[var(--color-text-tertiary)] leading-relaxed">
50
+ Steps will show as the task unfolds.
51
+ </p>
52
+ ) : (
53
+ <div className="space-y-2.5">
54
+ {steps.map((step, i) => {
55
+ const cfg = STEP_ICON[step.status] ?? STEP_ICON.pending;
56
+ const Icon = cfg.icon;
57
+ return (
58
+ <div key={i} className="flex items-center gap-2.5">
59
+ <div
60
+ className={`w-7 h-7 rounded-full flex items-center justify-center flex-shrink-0 ${cfg.bg}`}
61
+ >
62
+ <Icon
63
+ className={`w-3.5 h-3.5 ${cfg.color} ${step.status === 'running' ? 'animate-spin' : ''}`}
64
+ />
65
+ </div>
66
+ <div className="flex-1 min-w-0">
67
+ <div className="text-[13px] text-[var(--color-text-secondary)] truncate">
68
+ {step.label}
69
+ </div>
70
+ {step.detail && (
71
+ <div className="text-[11px] text-[var(--color-text-tertiary)] truncate mt-0.5">
72
+ {step.detail}
73
+ </div>
74
+ )}
75
+ </div>
76
+ </div>
77
+ );
78
+ })}
79
+ </div>
80
+ )}
81
+ </div>
82
+ )}
83
+ </div>
84
+ );
85
+ }