@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,329 @@
1
+ /**
2
+ * ProcessPanel — 加工面板(录制结果 + Agent 加工)
3
+ *
4
+ * 展示录制摘要、操作时间线,触发 Agent 加工分析。
5
+ * 独立于会话,不混入聊天列表。
6
+ */
7
+
8
+ import { useState, useCallback } from "react";
9
+ import {
10
+ Cpu,
11
+ Clock,
12
+ MousePointerClick,
13
+ Network,
14
+ FileText,
15
+ Loader2,
16
+ CheckCircle2,
17
+ Camera,
18
+ ChevronDown,
19
+ ChevronRight,
20
+ } from "lucide-react";
21
+ import { useRecordStore } from "../../stores/use-record-store";
22
+ import { useSessionStore } from "../../stores/use-session-store";
23
+ import { useConnectionStore } from "../../stores/use-connection-store";
24
+ import { apiClient } from "../../lib/api-client";
25
+
26
+ const ACTION_ICONS: Record<string, string> = {
27
+ click: "👆", input: "⌨️", change: "📝", keydown: "🔑",
28
+ submit: "✅", scroll: "⬇️", navigation: "🧭", goto: "🧭",
29
+ dblclick: "👆👆", contextmenu: "🖱️", hover: "💡", drag: "🎯",
30
+ };
31
+
32
+ export function ProcessPanel() {
33
+ // ===== 所有 Hooks 必须在早期 return 之前声明 =====
34
+ const [expandedAction, setExpandedAction] = useState<number | null>(null);
35
+ const [capturing, setCapturing] = useState<number | null>(null);
36
+ const [screenshots, setScreenshots] = useState<Record<number, string>>({});
37
+ const [fullScreenshot, setFullScreenshot] = useState<string | null>(null);
38
+ const [capturingFull, setCapturingFull] = useState(false);
39
+
40
+ const captureActionScreenshot = useCallback(async (actionIndex: number) => {
41
+ setCapturing(actionIndex);
42
+ try {
43
+ const tabIdx = useConnectionStore.getState().selectedTabIndex ?? useConnectionStore.getState().activeTabIndex;
44
+ const cmd = `screenshot${tabIdx !== undefined ? ` --tab ${tabIdx}` : ''}`;
45
+ const result = await apiClient.call("browser.execXbrowser", { command: cmd });
46
+ if (result.data?.data) {
47
+ setScreenshots(prev => ({ ...prev, [actionIndex]: result.data.data }));
48
+ }
49
+ } catch (err) {
50
+ console.warn("截图失败:", err);
51
+ } finally {
52
+ setCapturing(null);
53
+ }
54
+ }, []);
55
+
56
+ const captureFullScreenshot = useCallback(async () => {
57
+ setCapturingFull(true);
58
+ try {
59
+ const tabIdx = useConnectionStore.getState().selectedTabIndex ?? useConnectionStore.getState().activeTabIndex;
60
+ const cmd = `screenshot --full-page${tabIdx !== undefined ? ` --tab ${tabIdx}` : ''}`;
61
+ const result = await apiClient.call("browser.execXbrowser", { command: cmd });
62
+ if (result.data?.data) {
63
+ setFullScreenshot(result.data.data);
64
+ }
65
+ } catch (err) {
66
+ console.warn("全页截图失败:", err);
67
+ } finally {
68
+ setCapturingFull(false);
69
+ }
70
+ }, []);
71
+
72
+ const lastRecording = useRecordStore((s) => s.lastRecording);
73
+ const ensureDefaultSession = useSessionStore((s) => s.ensureDefaultSession);
74
+ const [analyzing, setAnalyzing] = useState(false);
75
+ const [result, setResult] = useState<string | null>(null);
76
+ const [thinking, setThinking] = useState("");
77
+
78
+ const handleProcess = useCallback(async () => {
79
+ if (!lastRecording) return;
80
+ setAnalyzing(true);
81
+ setResult(null);
82
+ setThinking("");
83
+ try {
84
+ const sessionId = await ensureDefaultSession();
85
+ const messageId = `proc_${Date.now()}`;
86
+ const subs: string[] = [];
87
+ subs.push(
88
+ await apiClient.subscribe("browser.thinking", (evt: any) => {
89
+ if (evt.messageId === messageId) setThinking((prev) => prev + (evt.delta || ""));
90
+ }),
91
+ );
92
+ subs.push(
93
+ await apiClient.subscribe("browser.textDelta", (evt: any) => {
94
+ if (evt.messageId === messageId) setResult((prev) => (prev || "") + (evt.delta || ""));
95
+ }),
96
+ );
97
+ subs.push(
98
+ await apiClient.subscribe("browser.done", (evt: any) => {
99
+ if (evt.messageId === messageId) { setResult(evt.reply || ""); setAnalyzing(false); }
100
+ }),
101
+ );
102
+ await new Promise((r) => setTimeout(r, 300));
103
+ const res = await apiClient.call("browser.processRecording", { sessionId, recordingData: lastRecording.data, title: "录制加工" });
104
+ if (!result && res?.text) setResult(res.text);
105
+ setAnalyzing(false);
106
+ subs.forEach((id) => apiClient.unsubscribe(id));
107
+ } catch (err) {
108
+ setResult(`❌ 加工失败: ${err instanceof Error ? err.message : String(err)}`);
109
+ setAnalyzing(false);
110
+ }
111
+ }, [lastRecording, ensureDefaultSession, result]);
112
+
113
+ // ===== 无录制数据时的空状态 =====
114
+ if (!lastRecording) {
115
+ return (
116
+ <div className="flex-1 flex items-center justify-center text-center p-8">
117
+ <div>
118
+ <div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-[var(--color-bg-tertiary)] mb-4">
119
+ <Cpu className="w-8 h-8 text-[var(--color-text-tertiary)]" />
120
+ </div>
121
+ <h3 className="text-lg font-semibold mb-2">暂无录制数据</h3>
122
+ <p className="text-sm text-[var(--color-text-tertiary)] max-w-sm">
123
+ 点击顶栏的录制按钮,在浏览器中操作后停止录制,
124
+ 录制结果会显示在这里,可以交给 Agent 加工分析。
125
+ </p>
126
+ </div>
127
+ </div>
128
+ );
129
+ }
130
+
131
+ // ===== 有录制数据 =====
132
+ const durationSec = Math.round(lastRecording.durationMs / 1000);
133
+ const rawActions = lastRecording.data?.actions;
134
+ const rawNetworks = lastRecording.data?.network;
135
+ const actions = Array.isArray(rawActions) ? rawActions : (Array.isArray(lastRecording.data?.data?.actions) ? lastRecording.data.data.actions : []);
136
+ const networks = Array.isArray(rawNetworks) ? rawNetworks : (Array.isArray(lastRecording.data?.data?.network) ? lastRecording.data.data.network : []);
137
+
138
+
139
+ return (
140
+ <div className="flex-1 overflow-auto p-4">
141
+ {/* 录制摘要卡片 */}
142
+ <div className="bg-[var(--color-bg-sidebar)] border border-[var(--color-border-primary)] rounded-xl p-4 mb-4">
143
+ <div className="flex items-center justify-between mb-3">
144
+ <h3 className="text-sm font-semibold flex items-center gap-2">
145
+ <CheckCircle2 className="w-4 h-4 text-[var(--color-text-success)]" />
146
+ 录制完成
147
+ </h3>
148
+ <button
149
+ onClick={handleProcess}
150
+ disabled={analyzing}
151
+ className="px-4 py-1.5 text-xs bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] rounded-lg transition-colors disabled:opacity-50 flex items-center gap-1.5"
152
+ >
153
+ {analyzing ? <Loader2 className="w-3 h-3 animate-spin" /> : <Cpu className="w-3 h-3" />}
154
+ {analyzing ? "加工中..." : "Agent 加工"}
155
+ </button>
156
+ </div>
157
+ <div className="grid grid-cols-4 gap-3 text-center">
158
+ <div className="p-2 bg-[var(--color-bg-tertiary)] rounded-lg">
159
+ <MousePointerClick className="w-4 h-4 text-[var(--color-text-accent)] mx-auto mb-1" />
160
+ <div className="text-lg font-bold">{actions.length || lastRecording.actions}</div>
161
+ <div className="text-[10px] text-[var(--color-text-tertiary)]">操作数</div>
162
+ </div>
163
+ <div className="p-2 bg-[var(--color-bg-tertiary)] rounded-lg">
164
+ <Network className="w-4 h-4 text-[var(--color-text-accent)] mx-auto mb-1" />
165
+ <div className="text-lg font-bold">{networks.length || lastRecording.network}</div>
166
+ <div className="text-[10px] text-[var(--color-text-tertiary)]">网络请求</div>
167
+ </div>
168
+ <div className="p-2 bg-[var(--color-bg-tertiary)] rounded-lg">
169
+ <Clock className="w-4 h-4 text-[var(--color-text-accent)] mx-auto mb-1" />
170
+ <div className="text-lg font-bold">{durationSec}s</div>
171
+ <div className="text-[10px] text-[var(--color-text-tertiary)]">耗时</div>
172
+ </div>
173
+ <div className="p-2 bg-[var(--color-bg-tertiary)] rounded-lg">
174
+ <FileText className="w-4 h-4 text-[var(--color-text-accent)] mx-auto mb-1" />
175
+ <div className="text-lg font-bold">{lastRecording.steps}</div>
176
+ <div className="text-[10px] text-[var(--color-text-tertiary)]">步骤</div>
177
+ </div>
178
+ </div>
179
+ </div>
180
+
181
+ {/* 操作时间线 */}
182
+ {actions.length > 0 && (
183
+ <div className="bg-[var(--color-bg-sidebar)] border border-[var(--color-border-primary)] rounded-xl p-4 mb-4">
184
+ <div className="flex items-center justify-between mb-3">
185
+ <h4 className="text-xs font-semibold text-[var(--color-text-tertiary)] uppercase tracking-wide">
186
+ 📋 操作时间线 ({actions.length})
187
+ </h4>
188
+ <button
189
+ onClick={captureFullScreenshot}
190
+ disabled={capturingFull}
191
+ className="px-2 py-1 text-[10px] border border-[var(--color-border-secondary)] rounded hover:bg-[var(--color-bg-hover)] flex items-center gap-1"
192
+ >
193
+ <Camera className={`w-3 h-3 ${capturingFull ? "animate-pulse" : ""}`} />
194
+ {capturingFull ? "截取中..." : "📸 全页截图"}
195
+ </button>
196
+ </div>
197
+
198
+ {fullScreenshot && (
199
+ <div className="mb-3">
200
+ <img src={`data:image/png;base64,${fullScreenshot}`} alt="页面截图"
201
+ className="w-full rounded-lg border border-[var(--color-border-secondary)] max-h-48 object-cover" />
202
+ </div>
203
+ )}
204
+
205
+ <div className="space-y-1 max-h-96 overflow-auto">
206
+ {actions.slice(0, 50).map((action: any, i: number) => {
207
+ const type = action.type || action.action?.type || "unknown";
208
+ const selector = action.element?.selector || action.action?.element?.selector || "";
209
+ const value = action.value || action.action?.value || "";
210
+ const url = action.url || action.action?.url || "";
211
+ const tag = action.element?.tag || action.action?.element?.tag || "";
212
+ const text = action.element?.text || action.action?.element?.text || "";
213
+ const x = action.x || action.action?.x;
214
+ const y = action.y || action.action?.y;
215
+ const ts = action.timestamp || 0;
216
+ const baseTs = actions[0]?.timestamp || ts;
217
+ const elapsed = ts - baseTs;
218
+ const icon = ACTION_ICONS[type] || "•";
219
+ const isExpanded = expandedAction === i;
220
+ const hasScreenshot = screenshots[i];
221
+
222
+ return (
223
+ <div key={i}>
224
+ <div
225
+ className={`flex items-center gap-2 px-2 py-1.5 text-xs hover:bg-[var(--color-bg-hover)] rounded cursor-pointer ${isExpanded ? "bg-[var(--color-bg-tertiary)]" : ""}`}
226
+ onClick={() => setExpandedAction(isExpanded ? null : i)}
227
+ >
228
+ <span className="flex-shrink-0 w-5 text-center text-sm">{icon}</span>
229
+ <span className="text-[var(--color-text-tertiary)] font-mono w-6">#{i + 1}</span>
230
+ <span className="font-mono text-[var(--color-text-accent)] w-16">{type}</span>
231
+ {elapsed > 0 && <span className="text-[var(--color-text-tertiary)] font-mono w-12">+{fmt(elapsed)}</span>}
232
+ <span className="text-[var(--color-text-secondary)] truncate flex-1">
233
+ {selector ? selector.slice(0, 50) : tag}
234
+ {value && <span className="ml-1 text-[var(--color-text-tertiary)]">={value.slice(0, 20)}</span>}
235
+ </span>
236
+ {isExpanded ? <ChevronDown className="w-3 h-3 text-[var(--color-text-tertiary)]" /> : <ChevronRight className="w-3 h-3 text-[var(--color-text-tertiary)]" />}
237
+ </div>
238
+
239
+ {isExpanded && (
240
+ <div className="ml-8 mb-2 p-3 bg-[var(--color-bg-tertiary)] rounded-lg space-y-2">
241
+ <div className="grid grid-cols-2 gap-2 text-[11px]">
242
+ {selector && <D label="选择器" v={selector} />}
243
+ {value && <D label="值" v={value} />}
244
+ {tag && <D label="标签" v={tag} />}
245
+ {text && <D label="文本" v={text} />}
246
+ {url && <D label="URL" v={url} />}
247
+ {x !== undefined && y !== undefined && <D label="坐标" v={`(${x},${y})`} />}
248
+ <D label="时间" v={new Date(ts).toLocaleTimeString()} />
249
+ <D label="耗时" v={`+${fmt(elapsed)}`} />
250
+ </div>
251
+ {hasScreenshot ? (
252
+ <div>
253
+ <img src={`data:image/png;base64,${hasScreenshot}`} alt={`步骤${i+1}`}
254
+ className="w-full rounded border border-[var(--color-border-secondary)] max-h-40 object-cover" />
255
+ </div>
256
+ ) : (
257
+ <button onClick={() => captureActionScreenshot(i)} disabled={capturing === i}
258
+ className="flex items-center gap-1 px-2 py-1 text-[10px] border rounded hover:bg-[var(--color-bg-hover)]">
259
+ <Camera className={`w-3 h-3 ${capturing === i ? "animate-pulse" : ""}`} />
260
+ {capturing === i ? "截取中..." : "📸 截图此元素"}
261
+ </button>
262
+ )}
263
+ </div>
264
+ )}
265
+ </div>
266
+ );
267
+ })}
268
+ {actions.length > 50 && <div className="text-center text-xs text-[var(--color-text-tertiary)] py-1">还有 {actions.length - 50} 条</div>}
269
+ </div>
270
+ </div>
271
+ )}
272
+
273
+ {/* 网络请求时间线 */}
274
+ {actions.length === 0 && networks.length > 0 && (
275
+ <div className="bg-[var(--color-bg-sidebar)] border border-[var(--color-border-primary)] rounded-xl p-4 mb-4">
276
+ <h4 className="text-xs font-semibold text-[var(--color-text-tertiary)] uppercase tracking-wide mb-3">🌐 网络请求 ({networks.length})</h4>
277
+ <div className="space-y-1 max-h-64 overflow-auto">
278
+ {networks.slice(0, 30).map((n: any, i: number) => (
279
+ <div key={i} className="flex items-center gap-2 px-2 py-1 text-xs hover:bg-[var(--color-bg-hover)] rounded">
280
+ <span className="flex-shrink-0 px-1.5 py-0.5 rounded text-[10px] font-mono bg-[var(--color-bg-tertiary)] text-[var(--color-text-tertiary)]">{n.method || 'GET'}</span>
281
+ <span className="text-[var(--color-text-secondary)] truncate flex-1">{n.path || n.url}</span>
282
+ <span className="flex-shrink-0 text-[var(--color-text-tertiary)]">{n.status || '—'}</span>
283
+ </div>
284
+ ))}
285
+ {networks.length > 30 && <div className="text-center text-xs text-[var(--color-text-tertiary)] py-1">还有 {networks.length - 30} 个</div>}
286
+ </div>
287
+ </div>
288
+ )}
289
+
290
+ {/* Agent 思考过程 */}
291
+ {thinking && (
292
+ <details className="mb-4 text-xs text-[var(--color-text-tertiary)]" open>
293
+ <summary className="cursor-pointer mb-1">💭 Agent 思考中...</summary>
294
+ <div className="p-2 bg-[var(--color-bg-tertiary)] rounded-lg whitespace-pre-wrap max-h-40 overflow-auto">{thinking.slice(-1000)}</div>
295
+ </details>
296
+ )}
297
+
298
+ {/* 加工结果 */}
299
+ {result && (
300
+ <div className="bg-[var(--color-bg-sidebar)] border border-[var(--color-accent)]/30 rounded-xl p-4">
301
+ <h4 className="text-xs font-semibold text-[var(--color-text-tertiary)] uppercase tracking-wide mb-2">加工结果</h4>
302
+ <div className="text-sm leading-relaxed whitespace-pre-wrap">{result}</div>
303
+ </div>
304
+ )}
305
+
306
+ {analyzing && !result && !thinking && (
307
+ <div className="text-center py-8 text-sm text-[var(--color-text-tertiary)]">
308
+ <Loader2 className="w-6 h-6 animate-spin mx-auto mb-2" />
309
+ Agent 正在分析录制数据...
310
+ </div>
311
+ )}
312
+ </div>
313
+ );
314
+ }
315
+
316
+ // ===== 详情项 =====
317
+ function D({ label, v }: { label: string; v: string }) {
318
+ return (
319
+ <div className="flex flex-col">
320
+ <span className="text-[var(--color-text-tertiary)] text-[10px]">{label}</span>
321
+ <span className="text-[var(--color-text-primary)] font-mono text-xs break-all">{v}</span>
322
+ </div>
323
+ );
324
+ }
325
+
326
+ function fmt(ms: number): string {
327
+ if (ms < 1000) return `${ms}ms`;
328
+ return `${(ms / 1000).toFixed(1)}s`;
329
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * 会话侧栏 — 历史会话列表
3
+ *
4
+ * 支持两种模式:完整(带区块折叠)+ 图标条(collapsed)
5
+ */
6
+
7
+ import { useEffect } from "react";
8
+ import { useTranslation } from "react-i18next";
9
+ import { Plus, MessagesSquare } from "lucide-react";
10
+ import { useSessionStore } from "../../stores/use-session-store";
11
+ import { useSidebarStore } from "../../stores/use-sidebar-store";
12
+
13
+ interface SessionSidebarProps {
14
+ /** 图标条模式 */
15
+ collapsed?: boolean;
16
+ }
17
+
18
+ export function SessionSidebar({ collapsed }: SessionSidebarProps) {
19
+ const { t } = useTranslation();
20
+ const sessions = useSessionStore((s) => s.sessions);
21
+ const currentSessionId = useSessionStore((s) => s.currentSessionId);
22
+ const refreshSessions = useSessionStore((s) => s.refreshSessions);
23
+ const newSessionSmart = useSessionStore((s) => s.newSessionSmart);
24
+ const loadSession = useSessionStore((s) => s.loadSession);
25
+
26
+ const sectionCollapsed = useSidebarStore((s) => s.collapsedSections.has("sessions"));
27
+ const toggleSection = useSidebarStore((s) => s.toggleSection);
28
+
29
+ useEffect(() => {
30
+ refreshSessions();
31
+ }, []);
32
+
33
+ const handleNewSession = async () => {
34
+ await newSessionSmart();
35
+ };
36
+
37
+ const handleSwitchSession = async (id: string) => {
38
+ await loadSession(id);
39
+ };
40
+
41
+ // ── 图标条模式:只显示会话入口图标 + 新建按钮 ──
42
+ if (collapsed) {
43
+ return (
44
+ <div className="p-2 flex flex-col items-center gap-1">
45
+ <button
46
+ onClick={handleNewSession}
47
+ title={t("session.new")}
48
+ className="w-10 h-10 flex items-center justify-center rounded-lg bg-[var(--color-accent)]/15 text-[var(--color-text-accent)] hover:bg-[var(--color-accent)]/25 active:scale-95 transition-all"
49
+ >
50
+ <Plus className="w-4 h-4" />
51
+ </button>
52
+ <div className="w-6 h-px bg-[var(--color-border-secondary)] my-1" />
53
+ {sessions.slice(0, 8).map((s) => (
54
+ <button
55
+ key={s.id}
56
+ onClick={() => handleSwitchSession(s.id)}
57
+ title={s.title}
58
+ className={`w-10 h-8 flex items-center justify-center rounded-lg text-xs font-medium transition-all active:scale-95 ${
59
+ s.id === currentSessionId
60
+ ? "bg-[var(--color-bg-active)] text-[var(--color-text-primary)]"
61
+ : "text-[var(--color-text-tertiary)] hover:bg-[var(--color-bg-hover)] hover:text-[var(--color-text-primary)]"
62
+ }`}
63
+ >
64
+ {(s.title || "?").charAt(0).toUpperCase()}
65
+ </button>
66
+ ))}
67
+ {sessions.length === 0 && (
68
+ <div title="暂无会话" className="w-10 h-8 flex items-center justify-center text-[var(--color-text-placeholder)]">
69
+ <MessagesSquare className="w-4 h-4 opacity-50" />
70
+ </div>
71
+ )}
72
+ </div>
73
+ );
74
+ }
75
+
76
+ // ── 完整模式:带 section header 可折叠 ──
77
+ return (
78
+ <div className="p-2">
79
+ <div className="flex items-center justify-between px-2 mb-1">
80
+ <button
81
+ onClick={() => toggleSection("sessions")}
82
+ className="flex items-center gap-1 text-xs font-semibold text-[var(--color-text-secondary)] uppercase tracking-wider hover:text-[var(--color-text-primary)] transition-colors"
83
+ >
84
+ <span className="text-[10px]">{sectionCollapsed ? "▸" : "▾"}</span>
85
+ 历史会话
86
+ </button>
87
+ <button
88
+ onClick={handleNewSession}
89
+ className="p-1 rounded hover:bg-[var(--color-bg-hover)] text-[var(--color-text-tertiary)] hover:text-[var(--color-text-primary)]"
90
+ title={t("session.new")}
91
+ >
92
+ <Plus className="w-3.5 h-3.5" />
93
+ </button>
94
+ </div>
95
+ {!sectionCollapsed && (
96
+ <div className="space-y-0.5">
97
+ {sessions.map((s) => (
98
+ <button
99
+ key={s.id}
100
+ onClick={() => handleSwitchSession(s.id)}
101
+ className={`w-full text-left px-3 py-1.5 rounded text-sm transition-colors ${
102
+ s.id === currentSessionId
103
+ ? "bg-[var(--color-bg-active)] text-[var(--color-text-primary)]"
104
+ : "hover:bg-[var(--color-bg-hover)] text-[var(--color-text-secondary)]"
105
+ }`}
106
+ >
107
+ <div className="truncate">{s.title}</div>
108
+ <div className="text-xs text-[var(--color-text-tertiary)]">
109
+ {s.messageCount} 条消息
110
+ </div>
111
+ </button>
112
+ ))}
113
+ {sessions.length === 0 && (
114
+ <div className="px-3 py-2 text-xs text-[var(--color-text-tertiary)]">
115
+ 暂无会话
116
+ </div>
117
+ )}
118
+ </div>
119
+ )}
120
+ </div>
121
+ );
122
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * 技能侧栏 — 内置采集技能列表
3
+ *
4
+ * 点击技能 → 创建会话 → 触发 Agent 对话(带流式订阅)
5
+ * 支持两种模式:完整(带区块折叠)+ 图标条(collapsed)
6
+ */
7
+
8
+ import { useSessionStore } from "../../stores/use-session-store";
9
+ import { useAgentChat } from "../../hooks/use-agent-chat";
10
+ import { useSidebarStore } from "../../stores/use-sidebar-store";
11
+
12
+ interface SkillSidebarProps {
13
+ /** 图标条模式:只显示技能图标,hover 显示名称 */
14
+ collapsed?: boolean;
15
+ }
16
+
17
+ const BUILTIN_SKILLS = [
18
+ {
19
+ id: "xhs-explore",
20
+ name: "小红书首页采集",
21
+ icon: "📕",
22
+ description: "采集小红书首页推荐笔记",
23
+ prompt: "采集小红书首页热门笔记",
24
+ },
25
+ {
26
+ id: "xhs-search",
27
+ name: "关键词搜索采集",
28
+ icon: "🔍",
29
+ description: "搜索指定关键词的小红书笔记",
30
+ prompt: "搜索小红书关于美妆的笔记",
31
+ },
32
+ {
33
+ id: "xhs-blogger",
34
+ name: "博主主页采集",
35
+ icon: "👤",
36
+ description: "采集小红书博主主页的全部笔记",
37
+ prompt: "采集这个小红书博主的主页内容",
38
+ },
39
+ ];
40
+
41
+ export function SkillSidebar({ collapsed }: SkillSidebarProps) {
42
+ const running = useSessionStore((s) => s.running);
43
+ const newSessionSmart = useSessionStore((s) => s.newSessionSmart);
44
+ const currentSessionId = useSessionStore((s) => s.currentSessionId);
45
+ const { chat } = useAgentChat();
46
+
47
+ const sectionCollapsed = useSidebarStore((s) => s.collapsedSections.has("skills"));
48
+ const toggleSection = useSidebarStore((s) => s.toggleSection);
49
+
50
+ const runSkill = async (skill: (typeof BUILTIN_SKILLS)[0]): Promise<void> => {
51
+ if (running) return;
52
+
53
+ // 智能创建会话(空会话复用)
54
+ const sessionId = currentSessionId || (await newSessionSmart());
55
+
56
+ // 触发 Agent 对话(useAgentChat 内部会订阅流式事件)
57
+ await chat(skill.prompt, sessionId, ["xiaohongshu"]);
58
+ };
59
+
60
+ // ── 图标条模式:只显示技能图标 ──
61
+ if (collapsed) {
62
+ return (
63
+ <div className="p-2 flex flex-col items-center gap-1">
64
+ {BUILTIN_SKILLS.map((skill) => (
65
+ <button
66
+ key={skill.id}
67
+ onClick={() => runSkill(skill)}
68
+ disabled={running}
69
+ title={skill.name}
70
+ className="w-10 h-10 flex items-center justify-center text-xl rounded-lg hover:bg-[var(--color-bg-hover)] active:scale-95 transition-all disabled:opacity-50"
71
+ >
72
+ {skill.icon}
73
+ </button>
74
+ ))}
75
+ </div>
76
+ );
77
+ }
78
+
79
+ // ── 完整模式:带 section header 可折叠 ──
80
+ return (
81
+ <div className="p-2">
82
+ <button
83
+ onClick={() => toggleSection("skills")}
84
+ className="w-full flex items-center gap-1 px-2 mb-1 text-xs font-semibold text-[var(--color-text-secondary)] uppercase tracking-wider hover:text-[var(--color-text-primary)] transition-colors"
85
+ >
86
+ <span className="text-[10px]">{sectionCollapsed ? "▸" : "▾"}</span>
87
+ 技能库
88
+ </button>
89
+ {!sectionCollapsed && (
90
+ <div className="space-y-1">
91
+ {BUILTIN_SKILLS.map((skill) => (
92
+ <button
93
+ key={skill.id}
94
+ onClick={() => runSkill(skill)}
95
+ disabled={running}
96
+ className="w-full text-left px-3 py-2 rounded-lg hover:bg-[var(--color-bg-hover)] transition-colors disabled:opacity-50"
97
+ >
98
+ <div className="flex items-center gap-2">
99
+ <span className="text-lg">{skill.icon}</span>
100
+ <div className="flex-1 min-w-0">
101
+ <div className="text-sm font-medium truncate">
102
+ {skill.name}
103
+ </div>
104
+ <div className="text-xs text-[var(--color-text-tertiary)] truncate">
105
+ {skill.description}
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </button>
110
+ ))}
111
+ </div>
112
+ )}
113
+ </div>
114
+ );
115
+ }