@rexvane/piweb 0.3.16 → 0.3.18

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 (288) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +8 -11
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +6 -6
  5. package/.next/react-loadable-manifest.json +4 -16
  6. package/.next/required-server-files.js +1 -3
  7. package/.next/required-server-files.json +1 -3
  8. package/.next/routes-manifest.json +0 -20
  9. package/.next/server/app/_global-error/page.js +2 -2
  10. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/.next/server/app/_global-error.html +1 -1
  12. package/.next/server/app/_global-error.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/server/app/_not-found/page.js +1 -1
  17. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/server/app/_not-found.html +1 -1
  19. package/.next/server/app/_not-found.rsc +4 -7
  20. package/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  21. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -5
  22. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  23. package/.next/server/app/api/agent/[id]/events/route.js +2 -2
  24. package/.next/server/app/api/agent/[id]/events/route.js.nft.json +1 -1
  25. package/.next/server/app/api/agent/[id]/route.js +1 -1
  26. package/.next/server/app/api/agent/[id]/route.js.nft.json +1 -1
  27. package/.next/server/app/api/agent/[id]/tree/route.js +1 -1
  28. package/.next/server/app/api/agent/[id]/tree/route.js.nft.json +1 -1
  29. package/.next/server/app/api/agent/new/route.js +1 -1
  30. package/.next/server/app/api/agent/new/route.js.nft.json +1 -1
  31. package/.next/server/app/api/config/route.js +1 -1
  32. package/.next/server/app/api/config/route.js.nft.json +1 -1
  33. package/.next/server/app/api/files/route.js +1 -1
  34. package/.next/server/app/api/files/route.js.nft.json +1 -1
  35. package/.next/server/app/api/git/route.js +2 -2
  36. package/.next/server/app/api/git/route.js.nft.json +1 -1
  37. package/.next/server/app/api/growth/route.js +1 -1
  38. package/.next/server/app/api/growth/route.js.nft.json +1 -1
  39. package/.next/server/app/api/health/route.js +1 -1
  40. package/.next/server/app/api/models/route.js +1 -1
  41. package/.next/server/app/api/models/route.js.nft.json +1 -1
  42. package/.next/server/app/api/pi-settings/route.js +1 -1
  43. package/.next/server/app/api/pi-settings/route.js.nft.json +1 -1
  44. package/.next/server/app/api/plugins/route.js +1 -1
  45. package/.next/server/app/api/plugins/route.js.nft.json +1 -1
  46. package/.next/server/app/api/prompts/route.js +1 -1
  47. package/.next/server/app/api/prompts/route.js.nft.json +1 -1
  48. package/.next/server/app/api/security/route.js +1 -1
  49. package/.next/server/app/api/security/route.js.nft.json +1 -1
  50. package/.next/server/app/api/sessions/[id]/export/route.js +1 -1
  51. package/.next/server/app/api/sessions/[id]/export/route.js.nft.json +1 -1
  52. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  53. package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  54. package/.next/server/app/api/sessions/import/route.js +3 -3
  55. package/.next/server/app/api/sessions/import/route.js.nft.json +1 -1
  56. package/.next/server/app/api/sessions/route.js +1 -1
  57. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  58. package/.next/server/app/api/skills/route.js +2 -2
  59. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  60. package/.next/server/app/api/update/route.js +2 -2
  61. package/.next/server/app/api/update/route.js.nft.json +1 -1
  62. package/.next/server/app/api/version/route.js +1 -1
  63. package/.next/server/app/api/version/route.js.nft.json +1 -1
  64. package/.next/server/app/api/web-auth/route.js +1 -1
  65. package/.next/server/app/api/workspaces/route.js +1 -1
  66. package/.next/server/app/api/workspaces/route.js.nft.json +1 -1
  67. package/.next/server/app/icon.svg/route.js +1 -1
  68. package/.next/server/app/index.html +1 -1
  69. package/.next/server/app/index.rsc +6 -9
  70. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -7
  71. package/.next/server/app/index.segments/_full.segment.rsc +6 -9
  72. package/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  73. package/.next/server/app/login/page.js +1 -1
  74. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/login.html +1 -1
  76. package/.next/server/app/login.rsc +5 -8
  77. package/.next/server/app/login.segments/_full.segment.rsc +5 -8
  78. package/.next/server/app/login.segments/_tree.segment.rsc +2 -5
  79. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +3 -6
  80. package/.next/server/app/page.js +1 -1
  81. package/.next/server/app/page_client-reference-manifest.js +1 -1
  82. package/.next/server/app-paths-manifest.json +8 -11
  83. package/.next/server/chunks/496.js +1 -1
  84. package/.next/server/chunks/532.js +1 -1
  85. package/.next/server/chunks/686.js +4 -8
  86. package/.next/server/middleware-build-manifest.js +1 -1
  87. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  88. package/.next/server/pages/404.html +1 -1
  89. package/.next/server/pages/500.html +1 -1
  90. package/.next/server/server-reference-manifest.json +1 -1
  91. package/.next/static/chunks/2608.ec8ff1f5767c9056.js +1 -0
  92. package/.next/static/chunks/2716.93be8ad5c970c516.js +1 -0
  93. package/.next/static/chunks/4632.112d2e893d48d188.js +1 -0
  94. package/.next/static/chunks/4673.c1fb1580efc6ace7.js +1 -0
  95. package/.next/static/chunks/4686-f4a037d609cea3f2.js +1 -0
  96. package/.next/static/chunks/app/_global-error/page-f77e9ede9808b18e.js +1 -0
  97. package/.next/static/chunks/app/api/agent/[id]/events/route-f77e9ede9808b18e.js +1 -0
  98. package/.next/static/chunks/app/api/agent/[id]/route-f77e9ede9808b18e.js +1 -0
  99. package/.next/static/chunks/app/api/agent/[id]/tree/route-f77e9ede9808b18e.js +1 -0
  100. package/.next/static/chunks/app/api/agent/new/route-f77e9ede9808b18e.js +1 -0
  101. package/.next/static/chunks/app/api/config/route-f77e9ede9808b18e.js +1 -0
  102. package/.next/static/chunks/app/api/files/route-f77e9ede9808b18e.js +1 -0
  103. package/.next/static/chunks/app/api/git/route-f77e9ede9808b18e.js +1 -0
  104. package/.next/static/chunks/app/api/growth/route-f77e9ede9808b18e.js +1 -0
  105. package/.next/static/chunks/app/api/health/route-f77e9ede9808b18e.js +1 -0
  106. package/.next/static/chunks/app/api/models/route-f77e9ede9808b18e.js +1 -0
  107. package/.next/static/chunks/app/api/pi-settings/route-f77e9ede9808b18e.js +1 -0
  108. package/.next/static/chunks/app/api/plugins/route-f77e9ede9808b18e.js +1 -0
  109. package/.next/static/chunks/app/api/prompts/route-f77e9ede9808b18e.js +1 -0
  110. package/.next/static/chunks/app/api/security/route-f77e9ede9808b18e.js +1 -0
  111. package/.next/static/chunks/app/api/sessions/[id]/export/route-f77e9ede9808b18e.js +1 -0
  112. package/.next/static/chunks/app/api/sessions/[id]/route-f77e9ede9808b18e.js +1 -0
  113. package/.next/static/chunks/app/api/sessions/import/route-f77e9ede9808b18e.js +1 -0
  114. package/.next/static/chunks/app/api/sessions/route-f77e9ede9808b18e.js +1 -0
  115. package/.next/static/chunks/app/api/skills/route-f77e9ede9808b18e.js +1 -0
  116. package/.next/static/chunks/app/api/update/route-f77e9ede9808b18e.js +1 -0
  117. package/.next/static/chunks/app/api/version/route-f77e9ede9808b18e.js +1 -0
  118. package/.next/static/chunks/app/api/web-auth/route-f77e9ede9808b18e.js +1 -0
  119. package/.next/static/chunks/app/api/workspaces/route-f77e9ede9808b18e.js +1 -0
  120. package/.next/static/chunks/app/page-b51087831582ee37.js +1 -0
  121. package/.next/static/chunks/next/dist/client/components/builtin/app-error-f77e9ede9808b18e.js +1 -0
  122. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-f77e9ede9808b18e.js +1 -0
  123. package/.next/static/chunks/next/dist/client/components/builtin/not-found-f77e9ede9808b18e.js +1 -0
  124. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-f77e9ede9808b18e.js +1 -0
  125. package/.next/static/chunks/webpack-c31263fd83d75ce6.js +1 -0
  126. package/.next/static/css/0cd968b9b62035b5.css +1 -0
  127. package/.next/static/en03hnPiuro0rnf8QkFEe/_buildManifest.js +1 -0
  128. package/.next/types/routes.d.ts +1 -4
  129. package/.next/types/validator.ts +0 -27
  130. package/README.md +17 -29
  131. package/assets/archive.jpg +0 -0
  132. package/assets/growth-1.jpg +0 -0
  133. package/assets/growth-2.jpg +0 -0
  134. package/assets/import.jpg +0 -0
  135. package/assets/main.jpg +0 -0
  136. package/assets/outline.jpg +0 -0
  137. package/assets/prompts-1.jpg +0 -0
  138. package/assets/prompts-2.jpg +0 -0
  139. package/assets/providers-1.jpg +0 -0
  140. package/assets/providers-2.jpg +0 -0
  141. package/assets/providers-3.jpg +0 -0
  142. package/assets/trace-1.jpg +0 -0
  143. package/assets/trace-2.png +0 -0
  144. package/assets/trace-3.png +0 -0
  145. package/assets/trace-4.png +0 -0
  146. package/assets/viewer-1.jpg +0 -0
  147. package/assets/viewer-2.jpg +0 -0
  148. package/bin/pi.js +50 -0
  149. package/next.config.ts +32 -7
  150. package/package.json +4 -9
  151. package/scripts/launcher.mjs +1 -1
  152. package/scripts/pick-folder.ps1 +2 -11
  153. package/scripts/release.mjs +31 -11
  154. package/scripts/verify-package.mjs +0 -53
  155. package/src/app/api/config/route.ts +1 -4
  156. package/src/app/api/growth/route.ts +14 -14
  157. package/src/app/api/models/route.ts +2 -1
  158. package/src/app/api/security/route.ts +3 -8
  159. package/src/app/api/update/route.ts +2 -8
  160. package/src/app/globals.css +92 -777
  161. package/src/app/layout.tsx +6 -13
  162. package/src/components/AppShell.tsx +229 -521
  163. package/src/components/ChatInput.tsx +26 -153
  164. package/src/components/ChatWindow.tsx +231 -51
  165. package/src/components/ContextMeter.tsx +17 -11
  166. package/src/components/FileViewer.tsx +11 -10
  167. package/src/components/GitPanel.tsx +11 -13
  168. package/src/components/ModelSelector.tsx +6 -19
  169. package/src/components/PiMark.tsx +38 -5
  170. package/src/components/ProjectPanel.tsx +111 -95
  171. package/src/components/PromptPanel.tsx +51 -132
  172. package/src/components/SessionImportSection.tsx +37 -53
  173. package/src/components/SessionSidebar.tsx +57 -159
  174. package/src/components/SettingsPanel.tsx +193 -330
  175. package/src/components/icons.tsx +0 -23
  176. package/src/hooks/useGrowth.ts +123 -156
  177. package/src/hooks/usePiWeb.ts +15 -122
  178. package/src/i18n.tsx +42 -98
  179. package/src/lib/agent-manager.ts +21 -187
  180. package/src/lib/command-validation.ts +1 -9
  181. package/src/lib/growth-service.ts +390 -166
  182. package/src/lib/growth-tracker.ts +64 -264
  183. package/src/lib/growth-turns.ts +31 -1
  184. package/src/lib/models/model-scope.ts +15 -0
  185. package/src/lib/models-service.ts +16 -0
  186. package/src/lib/pi-settings.ts +7 -0
  187. package/src/lib/pi.ts +2 -3
  188. package/src/lib/session-import/claude.ts +2 -13
  189. package/src/lib/session-import/codex.ts +8 -44
  190. package/src/lib/session-import/files.ts +0 -14
  191. package/src/lib/session-import/grok.ts +24 -54
  192. package/src/lib/session-import/index.ts +0 -5
  193. package/src/lib/session-import/types.ts +0 -12
  194. package/src/lib/session-import/writer.ts +3 -8
  195. package/src/lib/skills-service.ts +9 -16
  196. package/src/lib/theme.ts +1 -68
  197. package/src/lib/trajectory.ts +0 -1
  198. package/src/lib/types.ts +27 -36
  199. package/tsconfig.json +2 -1
  200. package/.next/server/app/api/swarm/[id]/route.js +0 -1
  201. package/.next/server/app/api/swarm/[id]/route.js.nft.json +0 -1
  202. package/.next/server/app/api/swarm/[id]/route_client-reference-manifest.js +0 -1
  203. package/.next/server/app/api/swarm/route.js +0 -1
  204. package/.next/server/app/api/swarm/route.js.nft.json +0 -1
  205. package/.next/server/app/api/swarm/route_client-reference-manifest.js +0 -1
  206. package/.next/server/app/api/tests/route.js +0 -2
  207. package/.next/server/app/api/tests/route.js.nft.json +0 -1
  208. package/.next/server/app/api/tests/route_client-reference-manifest.js +0 -1
  209. package/.next/server/chunks/757.js +0 -1
  210. package/.next/server/chunks/775.js +0 -3
  211. package/.next/static/0t1jBUAuVaTFTXxRyIo3q/_buildManifest.js +0 -1
  212. package/.next/static/chunks/2608.43c58236c9cce8e6.js +0 -1
  213. package/.next/static/chunks/2716.4ec42df1d51354c9.js +0 -1
  214. package/.next/static/chunks/4632.62139b565b657aac.js +0 -1
  215. package/.next/static/chunks/4673.7796104395deb8d7.js +0 -1
  216. package/.next/static/chunks/4686-17f21a006739a596.js +0 -1
  217. package/.next/static/chunks/7577.10af9bb661652da8.js +0 -1
  218. package/.next/static/chunks/8866.38ec4ac4ee5a1b74.js +0 -1
  219. package/.next/static/chunks/app/_global-error/page-5148173b3f55e415.js +0 -1
  220. package/.next/static/chunks/app/api/agent/[id]/events/route-5148173b3f55e415.js +0 -1
  221. package/.next/static/chunks/app/api/agent/[id]/route-5148173b3f55e415.js +0 -1
  222. package/.next/static/chunks/app/api/agent/[id]/tree/route-5148173b3f55e415.js +0 -1
  223. package/.next/static/chunks/app/api/agent/new/route-5148173b3f55e415.js +0 -1
  224. package/.next/static/chunks/app/api/config/route-5148173b3f55e415.js +0 -1
  225. package/.next/static/chunks/app/api/files/route-5148173b3f55e415.js +0 -1
  226. package/.next/static/chunks/app/api/git/route-5148173b3f55e415.js +0 -1
  227. package/.next/static/chunks/app/api/growth/route-5148173b3f55e415.js +0 -1
  228. package/.next/static/chunks/app/api/health/route-5148173b3f55e415.js +0 -1
  229. package/.next/static/chunks/app/api/models/route-5148173b3f55e415.js +0 -1
  230. package/.next/static/chunks/app/api/pi-settings/route-5148173b3f55e415.js +0 -1
  231. package/.next/static/chunks/app/api/plugins/route-5148173b3f55e415.js +0 -1
  232. package/.next/static/chunks/app/api/prompts/route-5148173b3f55e415.js +0 -1
  233. package/.next/static/chunks/app/api/security/route-5148173b3f55e415.js +0 -1
  234. package/.next/static/chunks/app/api/sessions/[id]/export/route-5148173b3f55e415.js +0 -1
  235. package/.next/static/chunks/app/api/sessions/[id]/route-5148173b3f55e415.js +0 -1
  236. package/.next/static/chunks/app/api/sessions/import/route-5148173b3f55e415.js +0 -1
  237. package/.next/static/chunks/app/api/sessions/route-5148173b3f55e415.js +0 -1
  238. package/.next/static/chunks/app/api/skills/route-5148173b3f55e415.js +0 -1
  239. package/.next/static/chunks/app/api/swarm/[id]/route-5148173b3f55e415.js +0 -1
  240. package/.next/static/chunks/app/api/swarm/route-5148173b3f55e415.js +0 -1
  241. package/.next/static/chunks/app/api/tests/route-5148173b3f55e415.js +0 -1
  242. package/.next/static/chunks/app/api/update/route-5148173b3f55e415.js +0 -1
  243. package/.next/static/chunks/app/api/version/route-5148173b3f55e415.js +0 -1
  244. package/.next/static/chunks/app/api/web-auth/route-5148173b3f55e415.js +0 -1
  245. package/.next/static/chunks/app/api/workspaces/route-5148173b3f55e415.js +0 -1
  246. package/.next/static/chunks/app/page-14379b8060d5cf07.js +0 -1
  247. package/.next/static/chunks/next/dist/client/components/builtin/app-error-5148173b3f55e415.js +0 -1
  248. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-5148173b3f55e415.js +0 -1
  249. package/.next/static/chunks/next/dist/client/components/builtin/not-found-5148173b3f55e415.js +0 -1
  250. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-5148173b3f55e415.js +0 -1
  251. package/.next/static/chunks/webpack-d1a69ad9edb38b11.js +0 -1
  252. package/.next/static/css/d0a0162cb481abe8.css +0 -1
  253. package/.next/types/app/api/swarm/[id]/route.ts +0 -353
  254. package/.next/types/app/api/swarm/route.ts +0 -353
  255. package/.next/types/app/api/tests/route.ts +0 -353
  256. package/assets/archive.png +0 -0
  257. package/assets/growth-1.png +0 -0
  258. package/assets/growth-2.png +0 -0
  259. package/assets/import.png +0 -0
  260. package/assets/main.png +0 -0
  261. package/assets/outline.png +0 -0
  262. package/assets/prompts-1.png +0 -0
  263. package/assets/prompts-2.png +0 -0
  264. package/assets/providers-1.png +0 -0
  265. package/assets/providers-2.png +0 -0
  266. package/assets/providers-3.png +0 -0
  267. package/assets/trace-1.png +0 -0
  268. package/assets/viewer-1.png +0 -0
  269. package/assets/viewer-2.png +0 -0
  270. package/scripts/managed-niubash-assets.mjs +0 -146
  271. package/scripts/prepare-niubash-packages.mjs +0 -182
  272. package/scripts/run-test-file.mjs +0 -34
  273. package/scripts/smoke-managed-niubash.mjs +0 -62
  274. package/scripts/verify-release-config.mjs +0 -24
  275. package/src/app/api/swarm/[id]/route.ts +0 -28
  276. package/src/app/api/swarm/route.ts +0 -24
  277. package/src/app/api/tests/route.ts +0 -27
  278. package/src/components/SwarmCoordinatorPod.tsx +0 -1021
  279. package/src/components/TestInspectorPod.tsx +0 -549
  280. package/src/lib/delegation.ts +0 -93
  281. package/src/lib/growth-rounds.ts +0 -84
  282. package/src/lib/managed-niubash.ts +0 -231
  283. package/src/lib/runtime-activity.ts +0 -27
  284. package/src/lib/session-import/lock.ts +0 -25
  285. package/src/lib/swarm-service.ts +0 -371
  286. package/src/lib/test-run-service.ts +0 -122
  287. package/src/lib/workflow.ts +0 -55
  288. /package/.next/static/{0t1jBUAuVaTFTXxRyIo3q → en03hnPiuro0rnf8QkFEe}/_ssgManifest.js +0 -0
@@ -6,7 +6,7 @@
6
6
  * 技能 / 提示模板,含扩展与 npm 包提供的那些);热会话额外给出"组装后的系统提示词"
7
7
  * 与每个工具的定义,它们不是文件、没有路径,直接在本面板内展开查看。
8
8
  */
9
- import { useCallback, useEffect, useRef, useState } from "react";
9
+ import { useCallback, useEffect, useState } from "react";
10
10
  import { useI18n } from "@/i18n";
11
11
  import { IconRefreshOutline14, IconCloseOutline14 } from "@/components/icons";
12
12
 
@@ -67,46 +67,30 @@ export function PromptPanel({
67
67
  onClose: () => void;
68
68
  }) {
69
69
  const { t } = useI18n();
70
- const owner = JSON.stringify([cwd, sessionId]);
71
- const [catalog, setCatalog] = useState<{ owner: string; data: PromptSourcesData } | null>(null);
72
- const data = catalog?.owner === owner ? catalog.data : null;
70
+ const [data, setData] = useState<PromptSourcesData | null>(null);
73
71
  const [error, setError] = useState<string | null>(null);
74
72
  const [busy, setBusy] = useState(false);
75
73
  const [opening, setOpening] = useState<string | null>(null);
76
- const listRequest = useRef<AbortController | null>(null);
77
- const readRequest = useRef<AbortController | null>(null);
78
74
 
79
75
  const load = useCallback(async () => {
80
- listRequest.current?.abort();
81
- readRequest.current?.abort();
82
- const controller = new AbortController();
83
- listRequest.current = controller;
84
- const current = () => listRequest.current === controller && !controller.signal.aborted;
85
- setCatalog(null);
86
- setOpening(null);
87
76
  setBusy(true);
88
77
  setError(null);
89
78
  try {
90
79
  const query = new URLSearchParams({ cwd });
91
80
  if (sessionId) query.set("session", sessionId);
92
- const response = await fetch(`/api/prompts?${query.toString()}`, { signal: controller.signal });
81
+ const response = await fetch(`/api/prompts?${query.toString()}`);
93
82
  const body = await response.json();
94
- if (!current()) return;
95
83
  if (!response.ok || !body.success) throw new Error(body.error || `request failed (${response.status})`);
96
- setCatalog({ owner, data: body.data as PromptSourcesData });
84
+ setData(body.data as PromptSourcesData);
97
85
  } catch (err) {
98
- if (current()) setError(err instanceof Error ? err.message : String(err));
86
+ setError(err instanceof Error ? err.message : String(err));
99
87
  } finally {
100
- if (current()) setBusy(false);
88
+ setBusy(false);
101
89
  }
102
- }, [cwd, sessionId, owner]);
90
+ }, [cwd, sessionId]);
103
91
 
104
92
  useEffect(() => {
105
93
  void load();
106
- return () => {
107
- listRequest.current?.abort();
108
- readRequest.current?.abort();
109
- };
110
94
  }, [load, refreshKey]);
111
95
 
112
96
  const originLabel = (origin: PromptSourceOrigin): string => {
@@ -131,28 +115,21 @@ export function PromptPanel({
131
115
  /** 文件类:按需读内容,交给外部查看器 */
132
116
  const openFile = async (source: PromptSource) => {
133
117
  if (!source.path || !onOpenContent) return;
134
- readRequest.current?.abort();
135
- const controller = new AbortController();
136
- const catalogRequest = listRequest.current;
137
- readRequest.current = controller;
138
- const current = () => readRequest.current === controller && !controller.signal.aborted && listRequest.current === catalogRequest;
139
118
  setOpening(source.path);
140
119
  setError(null);
141
120
  try {
142
121
  const response = await fetch("/api/prompts", {
143
122
  method: "POST",
144
- signal: controller.signal,
145
123
  headers: { "Content-Type": "application/json" },
146
124
  body: JSON.stringify({ action: "read", filePath: source.path, cwd }),
147
125
  });
148
126
  const body = await response.json();
149
- if (!current()) return;
150
127
  if (!response.ok || !body.success) throw new Error(body.error || "read failed");
151
128
  onOpenContent(source.path, body.data.content as string);
152
129
  } catch (err) {
153
- if (current()) setError(err instanceof Error ? err.message : String(err));
130
+ setError(err instanceof Error ? err.message : String(err));
154
131
  } finally {
155
- if (current()) setOpening(null);
132
+ setOpening(null);
156
133
  }
157
134
  };
158
135
 
@@ -161,94 +138,50 @@ export function PromptPanel({
161
138
  );
162
139
  const hasTools = (data?.tools?.length ?? 0) > 0;
163
140
 
164
- const fileExtBadge = (name: string): string => {
165
- const ext = name.split(".").pop()?.toUpperCase() ?? "DOC";
166
- return ext.length <= 4 ? ext : "DOC";
167
- };
168
-
169
141
  return (
170
- <div className="flex min-h-0 flex-1 flex-col p-2 select-none">
171
- {/* Right Header (Screen 2 Claymorphism) */}
172
- <div className="flex items-center justify-between pb-3 mb-3 border-b border-slate-200 dark:border-slate-800 px-2">
173
- <div className="flex items-center gap-2">
174
- <div className="w-2.5 h-2.5 rounded-full bg-sky-500 animate-pulse" />
175
- <h2 className="text-sm font-bold text-slate-900 dark:text-slate-100 tracking-tight">{t.promptPanel}</h2>
176
- </div>
177
- <div className="flex items-center gap-1.5 text-slate-500">
178
- <button
179
- type="button"
180
- className="w-7 h-7 clay-btn bg-white dark:bg-slate-800 text-slate-700 hover:text-slate-950 dark:text-slate-300 dark:hover:text-white transition-colors shadow-sm"
181
- title={t.promptRefresh}
182
- aria-label={t.promptRefresh}
183
- onClick={() => void load()}
184
- >
185
- <span className={busy ? "piweb-spin" : undefined} style={{ display: "inline-flex" }}>
186
- <IconRefreshOutline14 size={13} />
187
- </span>
188
- </button>
189
- <button
190
- type="button"
191
- className="w-7 h-7 clay-btn bg-white dark:bg-slate-800 text-slate-700 hover:text-rose-600 dark:text-slate-300 transition-colors shadow-sm"
192
- title={t.close}
193
- aria-label={t.close}
194
- onClick={onClose}
195
- >
196
- <IconCloseOutline14 size={13} />
197
- </button>
198
- </div>
142
+ <div className="flex min-h-0 flex-1 flex-col">
143
+ <div className="hairline-b flex items-center gap-2 px-4 py-2.5">
144
+ <span className="min-w-0 flex-1 truncate" style={{ fontSize: 13.5, fontWeight: 600 }}>{t.promptPanel}</span>
145
+ <button type="button" className="icon-btn" style={{ width: 26, height: 26 }} title={t.promptRefresh} aria-label={t.promptRefresh} onClick={() => void load()}>
146
+ <span className={busy ? "piweb-spin" : undefined} style={{ display: "inline-flex" }}>
147
+ <IconRefreshOutline14 size={14} />
148
+ </span>
149
+ </button>
150
+ <button type="button" className="icon-btn" style={{ width: 26, height: 26 }} title={t.close} aria-label={t.close} onClick={onClose}>
151
+ <IconCloseOutline14 size={14} />
152
+ </button>
199
153
  </div>
200
-
201
- <div className="min-h-0 flex-1 overflow-y-auto px-1 space-y-4 text-xs">
154
+ <div className="min-h-0 flex-1 overflow-auto px-3 py-3" style={{ fontSize: 12.5 }}>
202
155
  {error && (
203
- <div className="rounded-xl px-3 py-2 bg-rose-50 text-rose-700 dark:bg-rose-950/40 dark:text-rose-300 font-semibold" role="alert">
156
+ <div className="mb-2 rounded-lg px-2 py-1.5" style={{ background: "var(--dsw-hover)", color: "var(--dsw-danger)" }} role="alert">
204
157
  {error}
205
158
  </div>
206
159
  )}
207
-
208
- {!data && busy && <div className="text-slate-500 py-4 text-center">{t.promptLoading}</div>}
209
-
160
+ {!data && busy && <div style={{ color: "var(--dsw-label-tertiary)" }}>{t.promptLoading}</div>}
210
161
  {data && !data.sessionReady && (
211
- <div className="rounded-xl px-3 py-2.5 clay-inset text-slate-600 dark:text-slate-300 leading-relaxed text-xs" role="status">
162
+ <div className="mb-2 rounded-lg px-2 py-1.5" style={{ background: "var(--dsw-hover)", color: "var(--dsw-label-caption)" }} role="status">
212
163
  {t.promptColdHint}
213
164
  </div>
214
165
  )}
215
166
 
216
167
  {groups.map((group) => (
217
- <section key={group.kind} className="space-y-1.5">
218
- <div className="flex items-center justify-between text-xs font-bold text-slate-800 dark:text-slate-200 px-1 mb-1">
219
- <span>{kindLabel(group.kind)}</span>
220
- <span className="text-[10px] text-slate-500 dark:text-slate-400 font-mono font-semibold">{group.items.length} 项</span>
221
- </div>
222
- <div className="flex flex-col gap-1.5">
168
+ <section key={group.kind} className="mb-3">
169
+ <div className="mb-1 px-1" style={{ fontSize: 11.5, color: "var(--dsw-label-caption)" }}>{kindLabel(group.kind)}</div>
170
+ <div className="flex flex-col gap-1">
223
171
  {group.items.map((source) => (
224
172
  <button
225
173
  key={`${source.kind}:${source.path ?? source.name}`}
226
174
  type="button"
227
- className={`clay-card p-3 flex items-center justify-between hover:scale-[1.01] transition-all cursor-pointer rounded-2xl text-left bg-white dark:bg-slate-900 shadow-sm border border-slate-200 dark:border-slate-800 ${
228
- opening === source.path ? "ring-2 ring-emerald-500" : ""
229
- }`}
175
+ className="flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-left"
176
+ style={{ background: opening === source.path ? "var(--dsw-active)" : "transparent", border: "0.5px solid var(--dsw-border-l2)" }}
230
177
  title={source.path ?? source.name}
231
178
  onClick={() => void openFile(source)}
232
179
  >
233
- <div className="flex items-center gap-2.5 min-w-0 flex-1 mr-2">
234
- <div className="w-7 h-7 clay-inset bg-emerald-50 text-emerald-700 dark:bg-emerald-950/70 dark:text-emerald-300 flex items-center justify-center rounded-xl font-mono font-bold text-[10px] flex-none">
235
- {fileExtBadge(source.name)}
236
- </div>
237
- <div className="min-w-0 flex-1">
238
- <div className="text-xs font-bold text-slate-900 dark:text-slate-100 truncate">{source.name}</div>
239
- <div className="text-[11px] text-slate-600 dark:text-slate-400 truncate">{source.path ?? kindLabel(source.kind)}</div>
240
- </div>
241
- </div>
242
- <div className="text-right flex-none flex flex-col items-end gap-0.5">
243
- {source.bytes !== undefined && (
244
- <span className="text-[11px] font-mono font-bold text-slate-800 dark:text-slate-200 block">
245
- {formatBytes(source.bytes)}
246
- </span>
247
- )}
248
- <span className="text-[10px] px-2 py-0.5 rounded-full bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300 font-semibold border border-slate-200 dark:border-slate-700">
249
- {originLabel(source.origin)}
250
- </span>
251
- </div>
180
+ <span className="min-w-0 flex-1 truncate" style={{ color: "var(--dsw-label-primary)" }}>{source.name}</span>
181
+ <span className="flex-none" style={{ fontSize: 10.5, color: "var(--dsw-label-tertiary)" }}>{formatBytes(source.bytes)}</span>
182
+ <span className="flex-none rounded-md px-1.5 py-0.5" style={{ fontSize: 10.5, border: "0.5px solid var(--dsw-border-l3)", color: "var(--dsw-label-tertiary)" }}>
183
+ {originLabel(source.origin)}
184
+ </span>
252
185
  </button>
253
186
  ))}
254
187
  </div>
@@ -256,17 +189,15 @@ export function PromptPanel({
256
189
  ))}
257
190
 
258
191
  {hasTools && (
259
- <section className="space-y-1.5">
260
- <div className="flex items-center justify-between text-xs font-bold text-slate-800 dark:text-slate-200 px-1 mb-1">
261
- <span>{t.promptKindTool}</span>
262
- <span className="text-[10px] text-slate-500 dark:text-slate-400 font-mono font-semibold">{data!.tools!.length} 个工具</span>
263
- </div>
264
- <div className="flex flex-col gap-1.5">
192
+ <section className="mb-3">
193
+ <div className="mb-1 px-1" style={{ fontSize: 11.5, color: "var(--dsw-label-caption)" }}>{t.promptKindTool}</div>
194
+ <div className="flex flex-col gap-1">
265
195
  {data!.tools!.map((tool) => (
266
196
  <button
267
197
  key={`tool:${tool.name}`}
268
198
  type="button"
269
- className="clay-card p-3 flex items-center justify-between hover:scale-[1.01] transition-all cursor-pointer rounded-2xl text-left bg-white dark:bg-slate-900 shadow-sm border border-slate-200 dark:border-slate-800"
199
+ className="flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-left"
200
+ style={{ border: "0.5px solid var(--dsw-border-l2)" }}
270
201
  title={tool.name}
271
202
  onClick={() =>
272
203
  onOpenContent?.(
@@ -283,16 +214,8 @@ export function PromptPanel({
283
214
  )
284
215
  }
285
216
  >
286
- <div className="flex items-center gap-2.5 min-w-0 flex-1 mr-2">
287
- <div className="w-7 h-7 clay-inset bg-sky-50 text-sky-700 dark:bg-sky-950/70 dark:text-sky-300 flex items-center justify-center rounded-xl font-mono font-bold text-[10px] flex-none">
288
- TOOL
289
- </div>
290
- <div className="min-w-0 flex-1">
291
- <div className="text-xs font-bold text-slate-900 dark:text-slate-100 truncate">{tool.name}</div>
292
- <div className="text-[11px] text-slate-600 dark:text-slate-400 truncate">{tool.description || t.promptKindTool}</div>
293
- </div>
294
- </div>
295
- <span className="text-[10px] px-2 py-0.5 rounded-full bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300 font-semibold border border-slate-200 dark:border-slate-700 flex-none">
217
+ <span className="min-w-0 flex-1 truncate" style={{ color: "var(--dsw-label-primary)" }}>{tool.name}</span>
218
+ <span className="flex-none rounded-md px-1.5 py-0.5" style={{ fontSize: 10.5, border: "0.5px solid var(--dsw-border-l3)", color: "var(--dsw-label-tertiary)" }}>
296
219
  {tool.source === "builtin" ? t.promptToolBuiltin : t.promptToolExtension}
297
220
  </span>
298
221
  </button>
@@ -302,35 +225,31 @@ export function PromptPanel({
302
225
  )}
303
226
 
304
227
  {data?.assembledSystemPrompt && (
305
- <section className="space-y-1.5">
306
- <div className="text-xs font-bold text-slate-800 dark:text-slate-200 px-1 mb-1">{t.promptKindAssembled}</div>
228
+ <section className="mb-3">
229
+ <div className="mb-1 px-1" style={{ fontSize: 11.5, color: "var(--dsw-label-caption)" }}>{t.promptKindAssembled}</div>
307
230
  <button
308
231
  type="button"
309
- className="w-full clay-card p-3 flex items-center gap-2.5 hover:scale-[1.01] transition-all cursor-pointer rounded-2xl text-left bg-white dark:bg-slate-900 shadow-sm border border-slate-200 dark:border-slate-800"
232
+ className="w-full rounded-lg px-2 py-1.5 text-left"
233
+ style={{ border: "0.5px solid var(--dsw-border-l2)" }}
310
234
  title={t.promptAssembledKey}
311
235
  onClick={() => onOpenContent?.("system-prompt.md", data.assembledSystemPrompt ?? "")}
312
236
  >
313
- <div className="w-7 h-7 clay-inset bg-emerald-50 text-emerald-700 dark:bg-emerald-950/70 dark:text-emerald-300 flex items-center justify-center rounded-xl font-bold text-sm flex-none">
314
- π
315
- </div>
316
- <span className="truncate font-bold text-slate-900 dark:text-slate-100 text-xs">{t.promptAssembledKey}</span>
237
+ <span className="truncate" style={{ color: "var(--dsw-label-primary)" }}>{t.promptAssembledKey}</span>
317
238
  </button>
318
239
  </section>
319
240
  )}
320
241
 
321
242
  {data?.compactedSummary && (
322
- <section className="space-y-1.5">
323
- <div className="text-xs font-bold text-slate-800 dark:text-slate-200 px-1 mb-1">{t.promptKindCompacted}</div>
243
+ <section className="mb-3">
244
+ <div className="mb-1 px-1" style={{ fontSize: 11.5, color: "var(--dsw-label-caption)" }}>{t.promptKindCompacted}</div>
324
245
  <button
325
246
  type="button"
326
- className="w-full clay-card p-3 flex items-center gap-2.5 hover:scale-[1.01] transition-all cursor-pointer rounded-2xl text-left bg-white dark:bg-slate-900 shadow-sm border border-slate-200 dark:border-slate-800"
247
+ className="w-full rounded-lg px-2 py-1.5 text-left"
248
+ style={{ border: "0.5px solid var(--dsw-border-l2)" }}
327
249
  title={t.promptCompactedKey}
328
250
  onClick={() => onOpenContent?.("compacted-summary.md", data.compactedSummary ?? "")}
329
251
  >
330
- <div className="w-7 h-7 clay-inset bg-amber-50 text-amber-700 dark:bg-amber-950/70 dark:text-amber-300 flex items-center justify-center rounded-xl font-bold text-xs flex-none">
331
- SUM
332
- </div>
333
- <span className="truncate font-bold text-slate-900 dark:text-slate-100 text-xs">{t.promptCompactedKey}</span>
252
+ <span className="truncate" style={{ color: "var(--dsw-label-primary)" }}>{t.promptCompactedKey}</span>
334
253
  </button>
335
254
  </section>
336
255
  )}
@@ -36,8 +36,6 @@ interface ImportOutcome {
36
36
  reason?: string;
37
37
  messageCount?: number;
38
38
  workspace?: string;
39
- /** 已成功导入,但源里的运行时注入/加密内容等无法作为对话还原 */
40
- skipped?: string[];
41
39
  }
42
40
 
43
41
  interface ImportReport {
@@ -62,8 +60,6 @@ function dayOf(ms?: number): string {
62
60
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
63
61
  }
64
62
 
65
- const summaryKey = (summary: Pick<Summary, "source" | "externalId">) => `${summary.source}:${summary.externalId}`;
66
-
67
63
  export function SessionImportSection({ cwd }: { cwd: string }) {
68
64
  const { t } = useI18n();
69
65
  const [summaries, setSummaries] = useState<Summary[]>([]);
@@ -87,14 +83,9 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
87
83
  setFailure(json.error || t.toastError);
88
84
  return;
89
85
  }
90
- const nextSummaries = (json.data.sessions ?? []) as Summary[];
91
- const nextImported = new Set<string>(json.data.imported ?? []);
92
- const selectable = new Set(nextSummaries.map(summaryKey));
93
- setSummaries(nextSummaries);
86
+ setSummaries(json.data.sessions ?? []);
94
87
  setErrors(json.data.errors ?? []);
95
- setImportedKeys(nextImported);
96
- // 重新扫描后,源会话可能已经消失或被另一个请求导入;不要留下幽灵选择
97
- setSelected((previous) => new Set([...previous].filter((item) => selectable.has(item) && !nextImported.has(item))));
88
+ setImportedKeys(new Set<string>(json.data.imported ?? []));
98
89
  } catch (error) {
99
90
  setFailure(error instanceof Error ? error.message : String(error));
100
91
  } finally {
@@ -118,6 +109,8 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
118
109
  void scan();
119
110
  }, [scan]);
120
111
 
112
+ const key = (summary: Summary) => `${summary.source}:${summary.externalId}`;
113
+
121
114
  const groups = useMemo(() => {
122
115
  const bySource = new Map<string, Summary[]>();
123
116
  for (const summary of summaries) {
@@ -127,30 +120,27 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
127
120
  }
128
121
  return SOURCE_ORDER.filter((source) => bySource.has(source)).map((source) => {
129
122
  const rows = [...(bySource.get(source) as Summary[])].sort((left, right) => (right.updatedAt ?? right.createdAt ?? 0) - (left.updatedAt ?? left.createdAt ?? 0));
130
- return { source, rows, imported: rows.filter((row) => importedKeys.has(summaryKey(row))).length };
123
+ return { source, rows, imported: rows.filter((row) => importedKeys.has(key(row))).length };
131
124
  });
132
125
  }, [summaries, importedKeys]);
133
126
 
134
127
  /**
135
128
  * 一次只显示一个来源:六个工具各列 15 条就是 90 行,全铺出来既难找也没必要。
136
- * 首次打开默认落到“最近活动会话”所在的来源;用户切换后保持选择。
137
- * 直接派生有效来源,不用 effect 回填,避免初始化 effect 覆盖用户刚完成的点击。
129
+ * 默认落在第一个有会话的来源上(SOURCE_ORDER 的顺序),用户切换后不被扫描结果重置。
138
130
  */
139
131
  const [activeSource, setActiveSource] = useState("");
140
- const defaultSource = groups.reduce<{ source: string; at: number } | null>((latest, group) => {
141
- const first = group.rows[0];
142
- const at = first?.updatedAt ?? first?.createdAt ?? 0;
143
- return !latest || at > latest.at ? { source: group.source, at } : latest;
144
- }, null)?.source ?? "";
145
- const visibleSource = activeSource && groups.some((group) => group.source === activeSource) ? activeSource : defaultSource;
146
- const activeGroup = groups.find((group) => group.source === visibleSource);
132
+ useEffect(() => {
133
+ if (activeSource && groups.some((group) => group.source === activeSource)) return;
134
+ setActiveSource(groups[0]?.source ?? "");
135
+ }, [groups, activeSource]);
136
+ const activeGroup = groups.find((group) => group.source === activeSource);
147
137
 
148
138
  const toggle = (summary: Summary) => {
149
- if (importedKeys.has(summaryKey(summary))) return;
139
+ if (importedKeys.has(key(summary))) return;
150
140
  setSelected((previous) => {
151
141
  const next = new Set(previous);
152
- if (next.has(summaryKey(summary))) next.delete(summaryKey(summary));
153
- else next.add(summaryKey(summary));
142
+ if (next.has(key(summary))) next.delete(key(summary));
143
+ else next.add(key(summary));
154
144
  return next;
155
145
  });
156
146
  };
@@ -159,9 +149,9 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
159
149
  setSelected((previous) => {
160
150
  const next = new Set(previous);
161
151
  for (const row of rows) {
162
- if (importedKeys.has(summaryKey(row))) continue;
163
- if (checked) next.add(summaryKey(row));
164
- else next.delete(summaryKey(row));
152
+ if (importedKeys.has(key(row))) continue;
153
+ if (checked) next.add(key(row));
154
+ else next.delete(key(row));
165
155
  }
166
156
  return next;
167
157
  });
@@ -169,7 +159,7 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
169
159
 
170
160
  const run = async () => {
171
161
  if (!selected.size) return;
172
- const items = summaries.filter((summary) => selected.has(summaryKey(summary))).map((summary) => ({ source: summary.source, externalId: summary.externalId }));
162
+ const items = summaries.filter((summary) => selected.has(key(summary))).map((summary) => ({ source: summary.source, externalId: summary.externalId }));
173
163
  setImporting(true);
174
164
  setFailure(null);
175
165
  setReport(null);
@@ -208,7 +198,6 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
208
198
 
209
199
  const failures = report?.results.filter((result) => result.status === "failed") ?? [];
210
200
  const skipped = report?.results.filter((result) => result.status === "skipped") ?? [];
211
- const importedWithNotes = report?.results.filter((result) => result.status === "imported" && result.skipped?.length) ?? [];
212
201
 
213
202
  return (
214
203
  <div className="flex flex-col gap-4" data-testid="session-import">
@@ -288,11 +277,6 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
288
277
  {sourceLabel(result.source)} · {result.title || result.externalId} — {result.reason}
289
278
  </div>
290
279
  ))}
291
- {importedWithNotes.map((result) => (
292
- <div key={`note-${result.source}-${result.externalId}`} className="mt-1" style={{ fontSize: 11.5, color: "var(--dsw-label-caption)" }}>
293
- {sourceLabel(result.source)} · {result.title || result.externalId} — {result.skipped?.join(";")}
294
- </div>
295
- ))}
296
280
  {failures.map((result) => (
297
281
  <div key={`fail-${result.source}-${result.externalId}`} className="mt-1" style={{ fontSize: 11.5, color: "var(--dsw-danger)" }}>
298
282
  {sourceLabel(result.source)} · {result.title || result.externalId} — {result.reason}
@@ -305,25 +289,27 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
305
289
 
306
290
  {/* 来源选择器:选中哪个就只列哪个工具的会话 */}
307
291
  {groups.length > 0 && (
308
- <div className="flex flex-wrap items-center gap-2 p-1.5 rounded-2xl bg-slate-100/80 dark:bg-slate-900/60" role="tablist" aria-label={t.importPickSource} data-testid="import-source-tabs">
292
+ <div className="flex flex-wrap items-center gap-1.5" role="tablist" aria-label={t.importPickSource} data-testid="import-source-tabs">
309
293
  {groups.map((group) => {
310
- const active = group.source === visibleSource;
294
+ const active = group.source === activeSource;
311
295
  return (
312
296
  <button
313
297
  key={group.source}
314
298
  type="button"
315
299
  role="tab"
316
300
  aria-selected={active}
317
- className={`clay-btn rounded-xl px-3.5 py-1.5 transition-all text-xs font-medium flex items-center gap-1.5 ${
318
- active
319
- ? "clay-btn-peach text-white shadow-sm font-semibold"
320
- : "clay-btn-soft text-slate-600 dark:text-slate-300"
321
- }`}
301
+ className="rounded-full px-3 py-1 transition-colors"
302
+ style={{
303
+ fontSize: 12,
304
+ border: `0.5px solid ${active ? "var(--dsw-accent)" : "var(--dsw-border-l2)"}`,
305
+ background: active ? "var(--dsw-accent)" : "transparent",
306
+ color: active ? "#fff" : "var(--dsw-label-tertiary)",
307
+ }}
322
308
  onClick={() => setActiveSource(group.source)}
323
309
  data-testid={`import-source-${group.source}`}
324
310
  >
325
- <span>{sourceLabel(group.source)}</span>
326
- <span className={`text-[10px] px-1.5 py-0.2 rounded-full ${active ? "bg-white/30 text-white" : "bg-slate-200 dark:bg-slate-700 text-slate-500"}`}>{group.rows.length}</span>
311
+ {sourceLabel(group.source)}
312
+ <span style={{ marginLeft: 6, opacity: 0.75 }}>{group.rows.length}</span>
327
313
  </button>
328
314
  );
329
315
  })}
@@ -337,37 +323,35 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
337
323
  {t.importGroupCount.replace("{n}", String(activeGroup.rows.length)).replace("{imported}", String(activeGroup.imported))}
338
324
  </span>
339
325
  <div className="flex-1" />
340
- <button className="clay-btn clay-btn-soft rounded-lg px-2.5 py-1 text-xs" onClick={() => selectGroup(activeGroup.rows, true)}>
326
+ <button className="rounded-lg px-2 py-0.5" style={{ fontSize: 11.5, color: "var(--dsw-label-tertiary)" }} onClick={() => selectGroup(activeGroup.rows, true)}>
341
327
  {t.importSelectAll}
342
328
  </button>
343
- <button className="clay-btn clay-btn-soft rounded-lg px-2.5 py-1 text-xs text-slate-400" onClick={() => selectGroup(activeGroup.rows, false)}>
329
+ <button className="rounded-lg px-2 py-0.5" style={{ fontSize: 11.5, color: "var(--dsw-label-caption)" }} onClick={() => selectGroup(activeGroup.rows, false)}>
344
330
  {t.importSelectNone}
345
331
  </button>
346
332
  </div>
347
333
  <div className="flex flex-col gap-1.5">
348
334
  {activeGroup.rows.map((row) => {
349
- const rowKey = summaryKey(row);
335
+ const rowKey = key(row);
350
336
  const done = importedKeys.has(rowKey);
351
337
  const checked = selected.has(rowKey);
352
338
  return (
353
339
  <label
354
340
  key={rowKey}
355
- className={`clay-card flex cursor-pointer items-center gap-3 rounded-2xl px-3.5 py-2.5 transition-all hover:translate-x-0.5 ${
356
- checked ? "ring-2 ring-emerald-500 bg-white dark:bg-slate-800" : "bg-white/70 dark:bg-slate-900/60"
357
- }`}
358
- style={{ opacity: done ? 0.55 : 1 }}
341
+ className="flex cursor-pointer items-center gap-3 rounded-xl px-3 py-2"
342
+ style={{ border: `0.5px solid ${checked ? "var(--dsw-accent)" : "var(--dsw-border-l2)"}`, opacity: done ? 0.55 : 1 }}
359
343
  >
360
344
  <input type="checkbox" checked={checked} disabled={done} onChange={() => toggle(row)} />
361
345
  <div className="min-w-0 flex-1">
362
- <div className="truncate text-xs font-medium text-slate-800 dark:text-slate-100" title={row.title}>
346
+ <div className="truncate" style={{ fontSize: 12.5 }} title={row.title}>
363
347
  {row.title || t.importUntitled}
364
348
  </div>
365
- <div className="truncate text-[11px] text-slate-400" title={row.projectPath}>
349
+ <div className="truncate" style={{ fontSize: 11, color: "var(--dsw-label-caption)" }} title={row.projectPath}>
366
350
  {row.projectPath || t.importNoProject}
367
351
  </div>
368
352
  </div>
369
353
  {done && (
370
- <span className="clay-badge rounded-full px-2 py-0.5 text-[10px] bg-slate-100 text-slate-400">
354
+ <span className="rounded-full px-2 py-0.5" style={{ fontSize: 10, background: "var(--dsw-hover)", color: "var(--dsw-label-caption)" }}>
371
355
  {t.importAlready}
372
356
  </span>
373
357
  )}