repoburg 1.3.188 → 1.3.196

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 (265) hide show
  1. package/agent-pane/.prettierignore +5 -0
  2. package/agent-pane/.prettierrc +8 -0
  3. package/agent-pane/backend/coverage/base.css +224 -0
  4. package/agent-pane/backend/coverage/block-navigation.js +87 -0
  5. package/agent-pane/backend/coverage/clover.xml +887 -0
  6. package/agent-pane/backend/coverage/coverage-final.json +10 -0
  7. package/agent-pane/backend/coverage/favicon.png +0 -0
  8. package/agent-pane/backend/coverage/index.html +176 -0
  9. package/agent-pane/backend/coverage/prettify.css +1 -0
  10. package/agent-pane/backend/coverage/prettify.js +2 -0
  11. package/agent-pane/backend/coverage/sort-arrow-sprite.png +0 -0
  12. package/agent-pane/backend/coverage/sorter.js +210 -0
  13. package/agent-pane/backend/coverage/src/codex/codex-provider.ts.html +1402 -0
  14. package/agent-pane/backend/coverage/src/codex/index.html +131 -0
  15. package/agent-pane/backend/coverage/src/codex/item-mapper.ts.html +331 -0
  16. package/agent-pane/backend/coverage/src/db/index.html +131 -0
  17. package/agent-pane/backend/coverage/src/db/index.ts.html +436 -0
  18. package/agent-pane/backend/coverage/src/db/schema.ts.html +175 -0
  19. package/agent-pane/backend/coverage/src/index.html +116 -0
  20. package/agent-pane/backend/coverage/src/index.ts.html +262 -0
  21. package/agent-pane/backend/coverage/src/routes/index.html +146 -0
  22. package/agent-pane/backend/coverage/src/routes/sessions.ts.html +991 -0
  23. package/agent-pane/backend/coverage/src/routes/turns.ts.html +256 -0
  24. package/agent-pane/backend/coverage/src/routes/workspaces.ts.html +406 -0
  25. package/agent-pane/backend/coverage/src/ws/index.html +116 -0
  26. package/agent-pane/backend/coverage/src/ws/index.ts.html +238 -0
  27. package/agent-pane/backend/data.db +0 -0
  28. package/agent-pane/backend/data.db-shm +0 -0
  29. package/agent-pane/backend/data.db-wal +0 -0
  30. package/agent-pane/backend/dist/index.js +70869 -0
  31. package/agent-pane/backend/package-lock.json +4529 -1013
  32. package/agent-pane/backend/package.json +10 -6
  33. package/agent-pane/backend/src/claude/claude-message-mapper.test.ts +163 -0
  34. package/agent-pane/backend/src/claude/claude-message-mapper.ts +154 -0
  35. package/agent-pane/backend/src/claude/claude-provider.test.ts +65 -0
  36. package/agent-pane/backend/src/claude/claude-provider.ts +482 -0
  37. package/agent-pane/backend/src/claude/claude-types.ts +33 -0
  38. package/agent-pane/backend/src/codex/app-server-client.test.ts +183 -0
  39. package/agent-pane/backend/src/codex/app-server-client.ts +225 -0
  40. package/agent-pane/backend/src/codex/app-server-types.ts +259 -0
  41. package/agent-pane/backend/src/codex/codex-provider-runtime-config.test.ts +56 -0
  42. package/agent-pane/backend/src/codex/codex-provider.test.ts +60 -0
  43. package/agent-pane/backend/src/codex/codex-provider.ts +521 -265
  44. package/agent-pane/backend/src/codex/item-mapper.test.ts +221 -0
  45. package/agent-pane/backend/src/codex/item-mapper.ts +35 -8
  46. package/agent-pane/backend/src/codex/shared-app-server.ts +25 -0
  47. package/agent-pane/backend/src/db/index.test.ts +125 -0
  48. package/agent-pane/backend/src/db/index.ts +39 -8
  49. package/agent-pane/backend/src/db/schema.ts +28 -74
  50. package/agent-pane/backend/src/index.ts +29 -2
  51. package/agent-pane/backend/src/integration/__fixtures__/cancel-turn.json +29 -0
  52. package/agent-pane/backend/src/integration/__fixtures__/delta-streaming.json +40 -0
  53. package/agent-pane/backend/src/integration/__fixtures__/failed-turn.json +16 -0
  54. package/agent-pane/backend/src/integration/__fixtures__/mcp-tool-call.json +60 -0
  55. package/agent-pane/backend/src/integration/__fixtures__/missing-item-started.json +34 -0
  56. package/agent-pane/backend/src/integration/__fixtures__/multi-item-turn.json +85 -0
  57. package/agent-pane/backend/src/integration/__fixtures__/multi-turn.json +48 -0
  58. package/agent-pane/backend/src/integration/__fixtures__/simple-turn.json +35 -0
  59. package/agent-pane/backend/src/integration/delta-streaming.test.ts +130 -0
  60. package/agent-pane/backend/src/integration/helpers/app-server-mock.ts +272 -0
  61. package/agent-pane/backend/src/integration/helpers/test-app.ts +108 -0
  62. package/agent-pane/backend/src/integration/helpers/ws-capture.ts +64 -0
  63. package/agent-pane/backend/src/integration/item-lifecycle.test.ts +133 -0
  64. package/agent-pane/backend/src/integration/mcp-tool-call.test.ts +102 -0
  65. package/agent-pane/backend/src/integration/missing-item-started.test.ts +91 -0
  66. package/agent-pane/backend/src/integration/multi-turn.test.ts +121 -0
  67. package/agent-pane/backend/src/integration/session-operations.test.ts +168 -0
  68. package/agent-pane/backend/src/integration/title-generation.test.ts +109 -0
  69. package/agent-pane/backend/src/integration/turn-cancel.test.ts +111 -0
  70. package/agent-pane/backend/src/integration/turn-failure.test.ts +97 -0
  71. package/agent-pane/backend/src/integration/turn-lifecycle.test.ts +141 -0
  72. package/agent-pane/backend/src/providers/index.ts +14 -0
  73. package/agent-pane/backend/src/providers/registry.test.ts +92 -0
  74. package/agent-pane/backend/src/providers/registry.ts +43 -0
  75. package/agent-pane/backend/src/providers/runtime-provider.ts +25 -0
  76. package/agent-pane/backend/src/routes/files.ts +31 -0
  77. package/agent-pane/backend/src/routes/mcp.ts +33 -0
  78. package/agent-pane/backend/src/routes/models.test.ts +92 -0
  79. package/agent-pane/backend/src/routes/models.ts +16 -0
  80. package/agent-pane/backend/src/routes/plugins.ts +40 -0
  81. package/agent-pane/backend/src/routes/providers.test.ts +69 -0
  82. package/agent-pane/backend/src/routes/providers.ts +57 -0
  83. package/agent-pane/backend/src/routes/sessions.test.ts +424 -0
  84. package/agent-pane/backend/src/routes/sessions.ts +295 -42
  85. package/agent-pane/backend/src/routes/skills.test.ts +114 -0
  86. package/agent-pane/backend/src/routes/skills.ts +70 -0
  87. package/agent-pane/backend/src/routes/turns.test.ts +152 -0
  88. package/agent-pane/backend/src/routes/turns.ts +36 -16
  89. package/agent-pane/backend/src/routes/workspaces.test.ts +197 -0
  90. package/agent-pane/backend/src/routes/workspaces.ts +73 -55
  91. package/agent-pane/backend/src/ws/index.test.ts +107 -0
  92. package/agent-pane/backend/src/ws/index.ts +19 -11
  93. package/agent-pane/backend/tsconfig.json +4 -2
  94. package/agent-pane/backend/vitest.config.ts +20 -0
  95. package/agent-pane/eslint.config.js +33 -0
  96. package/agent-pane/frontend/coverage/base.css +224 -0
  97. package/agent-pane/frontend/coverage/block-navigation.js +87 -0
  98. package/agent-pane/frontend/coverage/clover.xml +2962 -0
  99. package/agent-pane/frontend/coverage/coverage-final.json +37 -0
  100. package/agent-pane/frontend/coverage/favicon.png +0 -0
  101. package/agent-pane/frontend/coverage/index.html +251 -0
  102. package/agent-pane/frontend/coverage/prettify.css +1 -0
  103. package/agent-pane/frontend/coverage/prettify.js +2 -0
  104. package/agent-pane/frontend/coverage/sort-arrow-sprite.png +0 -0
  105. package/agent-pane/frontend/coverage/sorter.js +210 -0
  106. package/agent-pane/frontend/coverage/src/App.tsx.html +217 -0
  107. package/agent-pane/frontend/coverage/src/AppInitializer.tsx.html +223 -0
  108. package/agent-pane/frontend/coverage/src/api/client.ts.html +187 -0
  109. package/agent-pane/frontend/coverage/src/api/index.html +161 -0
  110. package/agent-pane/frontend/coverage/src/api/sessions.ts.html +316 -0
  111. package/agent-pane/frontend/coverage/src/api/websocket.ts.html +544 -0
  112. package/agent-pane/frontend/coverage/src/api/workspaces.ts.html +199 -0
  113. package/agent-pane/frontend/coverage/src/components/CollapsibleToolCalls.tsx.html +226 -0
  114. package/agent-pane/frontend/coverage/src/components/CommandInputBar.tsx.html +382 -0
  115. package/agent-pane/frontend/coverage/src/components/CommandPalette.tsx.html +715 -0
  116. package/agent-pane/frontend/coverage/src/components/IdeWorkspace.tsx.html +160 -0
  117. package/agent-pane/frontend/coverage/src/components/ModelSelector.tsx.html +478 -0
  118. package/agent-pane/frontend/coverage/src/components/NewSessionDialog.tsx.html +472 -0
  119. package/agent-pane/frontend/coverage/src/components/RenderArea.tsx.html +574 -0
  120. package/agent-pane/frontend/coverage/src/components/RightPanel.tsx.html +205 -0
  121. package/agent-pane/frontend/coverage/src/components/RuntimeIcon.tsx.html +133 -0
  122. package/agent-pane/frontend/coverage/src/components/SessionTabs.tsx.html +217 -0
  123. package/agent-pane/frontend/coverage/src/components/StatusBar.tsx.html +271 -0
  124. package/agent-pane/frontend/coverage/src/components/StatusDot.tsx.html +109 -0
  125. package/agent-pane/frontend/coverage/src/components/Toast.tsx.html +313 -0
  126. package/agent-pane/frontend/coverage/src/components/TurnContent.tsx.html +1216 -0
  127. package/agent-pane/frontend/coverage/src/components/WorkspaceSidebar.tsx.html +1138 -0
  128. package/agent-pane/frontend/coverage/src/components/index.html +326 -0
  129. package/agent-pane/frontend/coverage/src/components/panels/ChangesPanel.tsx.html +247 -0
  130. package/agent-pane/frontend/coverage/src/components/panels/LogsPanel.tsx.html +160 -0
  131. package/agent-pane/frontend/coverage/src/components/panels/MetricsPanel.tsx.html +427 -0
  132. package/agent-pane/frontend/coverage/src/components/panels/TurnsPanel.tsx.html +397 -0
  133. package/agent-pane/frontend/coverage/src/components/panels/index.html +161 -0
  134. package/agent-pane/frontend/coverage/src/constants/index.html +116 -0
  135. package/agent-pane/frontend/coverage/src/constants/models.ts.html +406 -0
  136. package/agent-pane/frontend/coverage/src/hooks/index.html +146 -0
  137. package/agent-pane/frontend/coverage/src/hooks/useEscapeKey.ts.html +124 -0
  138. package/agent-pane/frontend/coverage/src/hooks/useOutsideClick.ts.html +142 -0
  139. package/agent-pane/frontend/coverage/src/hooks/useSessionStatus.ts.html +187 -0
  140. package/agent-pane/frontend/coverage/src/index.html +146 -0
  141. package/agent-pane/frontend/coverage/src/main.tsx.html +115 -0
  142. package/agent-pane/frontend/coverage/src/store/index.html +116 -0
  143. package/agent-pane/frontend/coverage/src/store/store.ts.html +2404 -0
  144. package/agent-pane/frontend/coverage/src/test/component-helpers.ts.html +190 -0
  145. package/agent-pane/frontend/coverage/src/test/fixtures.ts.html +367 -0
  146. package/agent-pane/frontend/coverage/src/test/index.html +131 -0
  147. package/agent-pane/frontend/coverage/src/types/index.html +116 -0
  148. package/agent-pane/frontend/coverage/src/types/index.ts.html +466 -0
  149. package/agent-pane/frontend/coverage/src/utils/changes.ts.html +202 -0
  150. package/agent-pane/frontend/coverage/src/utils/duration.ts.html +127 -0
  151. package/agent-pane/frontend/coverage/src/utils/index.html +131 -0
  152. package/agent-pane/frontend/dist/assets/index-Bg0PF2aV.css +1 -0
  153. package/agent-pane/frontend/dist/assets/index-BlybeX5e.js +281 -0
  154. package/agent-pane/frontend/dist/index.html +19 -0
  155. package/agent-pane/frontend/package-lock.json +2434 -213
  156. package/agent-pane/frontend/package.json +10 -3
  157. package/agent-pane/frontend/src/App.test.tsx +74 -0
  158. package/agent-pane/frontend/src/App.tsx +1 -1
  159. package/agent-pane/frontend/src/AppInitializer.test.tsx +142 -0
  160. package/agent-pane/frontend/src/AppInitializer.tsx +1 -1
  161. package/agent-pane/frontend/src/api/client.test.ts +126 -0
  162. package/agent-pane/frontend/src/api/client.ts +22 -29
  163. package/agent-pane/frontend/src/api/models.ts +7 -0
  164. package/agent-pane/frontend/src/api/providers.ts +12 -0
  165. package/agent-pane/frontend/src/api/sessions.test.ts +241 -0
  166. package/agent-pane/frontend/src/api/sessions.ts +43 -1
  167. package/agent-pane/frontend/src/api/skills.ts +12 -0
  168. package/agent-pane/frontend/src/api/websocket.test.ts +288 -0
  169. package/agent-pane/frontend/src/api/websocket.ts +27 -2
  170. package/agent-pane/frontend/src/api/workspaces.test.ts +112 -0
  171. package/agent-pane/frontend/src/api/workspaces.ts +17 -3
  172. package/agent-pane/frontend/src/components/CollapsibleToolCalls.test.tsx +49 -0
  173. package/agent-pane/frontend/src/components/CollapsibleToolCalls.tsx +2 -5
  174. package/agent-pane/frontend/src/components/CommandInputBar.test.tsx +133 -0
  175. package/agent-pane/frontend/src/components/CommandInputBar.tsx +296 -17
  176. package/agent-pane/frontend/src/components/CommandPalette.test.tsx +230 -0
  177. package/agent-pane/frontend/src/components/CommandPalette.tsx +26 -23
  178. package/agent-pane/frontend/src/components/IdeWorkspace.tsx +1 -1
  179. package/agent-pane/frontend/src/components/ModelSelector.test.tsx +129 -0
  180. package/agent-pane/frontend/src/components/ModelSelector.tsx +191 -0
  181. package/agent-pane/frontend/src/components/NewSessionDialog.test.tsx +95 -0
  182. package/agent-pane/frontend/src/components/NewSessionDialog.tsx +58 -13
  183. package/agent-pane/frontend/src/components/RenderArea.test.tsx +160 -0
  184. package/agent-pane/frontend/src/components/RenderArea.tsx +18 -25
  185. package/agent-pane/frontend/src/components/RightPanel.test.tsx +43 -0
  186. package/agent-pane/frontend/src/components/RightPanel.tsx +1 -1
  187. package/agent-pane/frontend/src/components/RuntimeIcon.test.tsx +32 -0
  188. package/agent-pane/frontend/src/components/RuntimeIcon.tsx +1 -1
  189. package/agent-pane/frontend/src/components/SessionTabs.test.tsx +72 -0
  190. package/agent-pane/frontend/src/components/SessionTabs.tsx +12 -12
  191. package/agent-pane/frontend/src/components/StatusBar.test.tsx +56 -0
  192. package/agent-pane/frontend/src/components/StatusBar.tsx +25 -31
  193. package/agent-pane/frontend/src/components/StatusDot.test.tsx +25 -0
  194. package/agent-pane/frontend/src/components/StatusDot.tsx +2 -7
  195. package/agent-pane/frontend/src/components/Toast.test.tsx +79 -0
  196. package/agent-pane/frontend/src/components/Toast.tsx +2 -6
  197. package/agent-pane/frontend/src/components/TurnContent.test.tsx +287 -0
  198. package/agent-pane/frontend/src/components/TurnContent.tsx +107 -24
  199. package/agent-pane/frontend/src/components/WorkspaceSidebar.test.tsx +297 -0
  200. package/agent-pane/frontend/src/components/WorkspaceSidebar.tsx +33 -32
  201. package/agent-pane/frontend/src/components/input/OptionSubPopup.tsx +32 -0
  202. package/agent-pane/frontend/src/components/input/SkillMentionPopup.test.tsx +63 -0
  203. package/agent-pane/frontend/src/components/input/SkillMentionPopup.tsx +78 -0
  204. package/agent-pane/frontend/src/components/input/SlashPopup.test.tsx +96 -0
  205. package/agent-pane/frontend/src/components/input/SlashPopup.tsx +63 -0
  206. package/agent-pane/frontend/src/components/panels/ChangesPanel.test.tsx +61 -0
  207. package/agent-pane/frontend/src/components/panels/ChangesPanel.tsx +12 -39
  208. package/agent-pane/frontend/src/components/panels/LogsPanel.test.tsx +58 -0
  209. package/agent-pane/frontend/src/components/panels/LogsPanel.tsx +1 -1
  210. package/agent-pane/frontend/src/components/panels/MetricsPanel.test.tsx +71 -0
  211. package/agent-pane/frontend/src/components/panels/MetricsPanel.tsx +63 -31
  212. package/agent-pane/frontend/src/components/panels/TurnsPanel.test.tsx +83 -0
  213. package/agent-pane/frontend/src/components/panels/TurnsPanel.tsx +66 -7
  214. package/agent-pane/frontend/src/constants/models.test.ts +97 -0
  215. package/agent-pane/frontend/src/constants/models.ts +129 -0
  216. package/agent-pane/frontend/src/hooks/useEscapeKey.test.ts +42 -0
  217. package/agent-pane/frontend/src/hooks/useEscapeKey.ts +13 -0
  218. package/agent-pane/frontend/src/hooks/useOutsideClick.test.ts +92 -0
  219. package/agent-pane/frontend/src/hooks/useOutsideClick.ts +19 -0
  220. package/agent-pane/frontend/src/hooks/useProvider.ts +44 -0
  221. package/agent-pane/frontend/src/hooks/useSessionStatus.test.ts +114 -0
  222. package/agent-pane/frontend/src/hooks/useSessionStatus.ts +34 -0
  223. package/agent-pane/frontend/src/main.test.tsx +37 -0
  224. package/agent-pane/frontend/src/main.tsx +1 -1
  225. package/agent-pane/frontend/src/store/sessionSlice.ts +417 -0
  226. package/agent-pane/frontend/src/store/store.test.ts +1284 -0
  227. package/agent-pane/frontend/src/store/store.ts +16 -617
  228. package/agent-pane/frontend/src/store/uiSlice.ts +83 -0
  229. package/agent-pane/frontend/src/store/workspaceSlice.ts +77 -0
  230. package/agent-pane/frontend/src/store/wsSlice.ts +292 -0
  231. package/agent-pane/frontend/src/styles/app.css +113 -7
  232. package/agent-pane/frontend/src/test/component-helpers.ts +36 -0
  233. package/agent-pane/frontend/src/test/fixtures.ts +96 -0
  234. package/agent-pane/frontend/src/test-setup.ts +5 -0
  235. package/agent-pane/frontend/src/types/index.test.ts +128 -0
  236. package/agent-pane/frontend/src/types/index.ts +80 -104
  237. package/agent-pane/frontend/src/utils/changes.test.ts +81 -0
  238. package/agent-pane/frontend/src/utils/changes.ts +39 -0
  239. package/agent-pane/frontend/src/utils/duration.test.ts +71 -0
  240. package/agent-pane/frontend/src/utils/duration.ts +14 -0
  241. package/agent-pane/frontend/tsconfig.json +4 -1
  242. package/agent-pane/frontend/vite.config.ts +6 -0
  243. package/agent-pane/frontend/vitest.config.ts +29 -0
  244. package/agent-pane/package-lock.json +1527 -0
  245. package/agent-pane/package.json +19 -0
  246. package/agent-pane/shared/provider-types.ts +53 -0
  247. package/agent-pane/shared/types.ts +107 -0
  248. package/agentpane-branch-session.png +0 -0
  249. package/agentpane-expanded-all.png +0 -0
  250. package/agentpane-fixed-rendering.png +0 -0
  251. package/agentpane-focus-check.png +0 -0
  252. package/agentpane-initial.png +0 -0
  253. package/agentpane-mcp-detail.png +0 -0
  254. package/agentpane-no-focus-ring.png +0 -0
  255. package/agentpane-soft-focus.png +0 -0
  256. package/backend/dist/src/llm-provider/ollama-llm.provider.js +1 -0
  257. package/backend/dist/src/llm-provider/ollama-llm.provider.js.map +1 -1
  258. package/backend/dist/tsconfig.build.tsbuildinfo +1 -1
  259. package/data.db +0 -0
  260. package/empty-state.png +0 -0
  261. package/frontend-home.png +0 -0
  262. package/model-selector-open.png +0 -0
  263. package/package.json +1 -1
  264. package/slash-popup-working.png +0 -0
  265. package/agent-pane/frontend/src/components/DiffViewer.tsx +0 -27
@@ -0,0 +1,202 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for src/utils/changes.ts</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="../../prettify.css" />
9
+ <link rel="stylesheet" href="../../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(../../sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="../../index.html">All files</a> / <a href="index.html">src/utils</a> changes.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">100% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>20/20</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">100% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>10/10</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">100% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>2/2</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">100% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>20/20</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line high'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a>
81
+ <a name='L16'></a><a href='#L16'>16</a>
82
+ <a name='L17'></a><a href='#L17'>17</a>
83
+ <a name='L18'></a><a href='#L18'>18</a>
84
+ <a name='L19'></a><a href='#L19'>19</a>
85
+ <a name='L20'></a><a href='#L20'>20</a>
86
+ <a name='L21'></a><a href='#L21'>21</a>
87
+ <a name='L22'></a><a href='#L22'>22</a>
88
+ <a name='L23'></a><a href='#L23'>23</a>
89
+ <a name='L24'></a><a href='#L24'>24</a>
90
+ <a name='L25'></a><a href='#L25'>25</a>
91
+ <a name='L26'></a><a href='#L26'>26</a>
92
+ <a name='L27'></a><a href='#L27'>27</a>
93
+ <a name='L28'></a><a href='#L28'>28</a>
94
+ <a name='L29'></a><a href='#L29'>29</a>
95
+ <a name='L30'></a><a href='#L30'>30</a>
96
+ <a name='L31'></a><a href='#L31'>31</a>
97
+ <a name='L32'></a><a href='#L32'>32</a>
98
+ <a name='L33'></a><a href='#L33'>33</a>
99
+ <a name='L34'></a><a href='#L34'>34</a>
100
+ <a name='L35'></a><a href='#L35'>35</a>
101
+ <a name='L36'></a><a href='#L36'>36</a>
102
+ <a name='L37'></a><a href='#L37'>37</a>
103
+ <a name='L38'></a><a href='#L38'>38</a>
104
+ <a name='L39'></a><a href='#L39'>39</a>
105
+ <a name='L40'></a><a href='#L40'>40</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
106
+ <span class="cline-any cline-neutral">&nbsp;</span>
107
+ <span class="cline-any cline-neutral">&nbsp;</span>
108
+ <span class="cline-any cline-neutral">&nbsp;</span>
109
+ <span class="cline-any cline-neutral">&nbsp;</span>
110
+ <span class="cline-any cline-neutral">&nbsp;</span>
111
+ <span class="cline-any cline-neutral">&nbsp;</span>
112
+ <span class="cline-any cline-neutral">&nbsp;</span>
113
+ <span class="cline-any cline-neutral">&nbsp;</span>
114
+ <span class="cline-any cline-neutral">&nbsp;</span>
115
+ <span class="cline-any cline-neutral">&nbsp;</span>
116
+ <span class="cline-any cline-neutral">&nbsp;</span>
117
+ <span class="cline-any cline-neutral">&nbsp;</span>
118
+ <span class="cline-any cline-neutral">&nbsp;</span>
119
+ <span class="cline-any cline-yes">1x</span>
120
+ <span class="cline-any cline-yes">17x</span>
121
+ <span class="cline-any cline-neutral">&nbsp;</span>
122
+ <span class="cline-any cline-yes">17x</span>
123
+ <span class="cline-any cline-yes">16x</span>
124
+ <span class="cline-any cline-yes">17x</span>
125
+ <span class="cline-any cline-yes">1x</span>
126
+ <span class="cline-any cline-yes">1x</span>
127
+ <span class="cline-any cline-yes">1x</span>
128
+ <span class="cline-any cline-neutral">&nbsp;</span>
129
+ <span class="cline-any cline-neutral">&nbsp;</span>
130
+ <span class="cline-any cline-yes">17x</span>
131
+ <span class="cline-any cline-yes">17x</span>
132
+ <span class="cline-any cline-yes">17x</span>
133
+ <span class="cline-any cline-yes">17x</span>
134
+ <span class="cline-any cline-neutral">&nbsp;</span>
135
+ <span class="cline-any cline-neutral">&nbsp;</span>
136
+ <span class="cline-any cline-yes">15x</span>
137
+ <span class="cline-any cline-yes">15x</span>
138
+ <span class="cline-any cline-yes">14x</span>
139
+ <span class="cline-any cline-yes">13x</span>
140
+ <span class="cline-any cline-yes">13x</span>
141
+ <span class="cline-any cline-yes">13x</span>
142
+ <span class="cline-any cline-yes">14x</span>
143
+ <span class="cline-any cline-yes">15x</span>
144
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import type { Turn, ChangesScope } from '../types/index.ts';
145
+ &nbsp;
146
+ export interface FileChangeEntry {
147
+ path: string;
148
+ kind: string;
149
+ turnIdx: number;
150
+ }
151
+ &nbsp;
152
+ /** Collect file changes from turns, optionally scoped to a single turn.
153
+ * Deduplicates by path (keeps last occurrence).
154
+ * @param turns All turns in the session.
155
+ * @param scope 'session' = all turns, 'turngroup' = only `turnIdx`.
156
+ * @param turnIdx Index of the selected turn (used when scope = 'turngroup').
157
+ * @returns Deduplicated list of file changes. */
158
+ export function collectFileChanges(turns: Turn[], scope: ChangesScope = 'session', turnIdx = 0): FileChangeEntry[] {
159
+ const entries: FileChangeEntry[] = [];
160
+ &nbsp;
161
+ if (scope === 'session') {
162
+ turns.forEach((t, ti) =&gt; extractChanges(t, ti, entries));
163
+ } else {
164
+ const turn = turns[turnIdx];
165
+ if (turn) extractChanges(turn, turnIdx, entries);
166
+ }
167
+ &nbsp;
168
+ // Deduplicate by path (keep last occurrence)
169
+ const seen = new Map&lt;string, FileChangeEntry&gt;();
170
+ for (const e of entries) seen.set(e.path, e);
171
+ return Array.from(seen.values());
172
+ }
173
+ &nbsp;
174
+ /** Extract file_change items from a single turn into the entries array. */
175
+ function extractChanges(turn: Turn, turnIdx: number, entries: FileChangeEntry[]): void {
176
+ for (const item of turn.items) {
177
+ if (item.type === 'file_change' &amp;&amp; item.data?.changes) {
178
+ const changes = item.data.changes as Array&lt;{ path: string; kind: string }&gt;;
179
+ for (const c of changes) entries.push({ path: c.path, kind: c.kind, turnIdx });
180
+ }
181
+ }
182
+ }
183
+ &nbsp;</pre></td></tr></table></pre>
184
+
185
+ <div class='push'></div><!-- for sticky footer -->
186
+ </div><!-- /wrapper -->
187
+ <div class='footer quiet pad2 space-top1 center small'>
188
+ Code coverage generated by
189
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
190
+ at 2026-08-15T08:27:09.571Z
191
+ </div>
192
+ <script src="../../prettify.js"></script>
193
+ <script>
194
+ window.onload = function () {
195
+ prettyPrint();
196
+ };
197
+ </script>
198
+ <script src="../../sorter.js"></script>
199
+ <script src="../../block-navigation.js"></script>
200
+ </body>
201
+ </html>
202
+
@@ -0,0 +1,127 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for src/utils/duration.ts</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="../../prettify.css" />
9
+ <link rel="stylesheet" href="../../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(../../sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="../../index.html">All files</a> / <a href="index.html">src/utils</a> duration.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">100% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>8/8</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">100% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>6/6</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">100% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>1/1</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">100% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>8/8</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line high'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
81
+ <span class="cline-any cline-yes">1x</span>
82
+ <span class="cline-any cline-neutral">&nbsp;</span>
83
+ <span class="cline-any cline-neutral">&nbsp;</span>
84
+ <span class="cline-any cline-neutral">&nbsp;</span>
85
+ <span class="cline-any cline-neutral">&nbsp;</span>
86
+ <span class="cline-any cline-neutral">&nbsp;</span>
87
+ <span class="cline-any cline-yes">1x</span>
88
+ <span class="cline-any cline-yes">13x</span>
89
+ <span class="cline-any cline-yes">6x</span>
90
+ <span class="cline-any cline-yes">6x</span>
91
+ <span class="cline-any cline-yes">13x</span>
92
+ <span class="cline-any cline-yes">13x</span>
93
+ <span class="cline-any cline-yes">13x</span>
94
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import type { SessionDetail } from '../types/index.ts';
95
+ import { formatDuration } from '../types/index.ts';
96
+ &nbsp;
97
+ /** Calculate the total duration of a session from first turn to last turn (or now if running).
98
+ * @param detail SessionDetail with turns.
99
+ * @param isRunning Whether the session is currently running (extends to now).
100
+ * @returns Formatted duration string, or '—' if no turns. */
101
+ export function calcSessionDuration(detail: SessionDetail | null, isRunning: boolean): string {
102
+ if (!detail || detail.turns.length === 0) return '—';
103
+ const firstTurn = detail.turns[0];
104
+ const lastTurn = detail.turns[detail.turns.length - 1];
105
+ const endISO = isRunning ? null : lastTurn.updated_at;
106
+ return formatDuration(firstTurn.created_at, endISO);
107
+ }
108
+ &nbsp;</pre></td></tr></table></pre>
109
+
110
+ <div class='push'></div><!-- for sticky footer -->
111
+ </div><!-- /wrapper -->
112
+ <div class='footer quiet pad2 space-top1 center small'>
113
+ Code coverage generated by
114
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
115
+ at 2026-08-15T08:27:09.571Z
116
+ </div>
117
+ <script src="../../prettify.js"></script>
118
+ <script>
119
+ window.onload = function () {
120
+ prettyPrint();
121
+ };
122
+ </script>
123
+ <script src="../../sorter.js"></script>
124
+ <script src="../../block-navigation.js"></script>
125
+ </body>
126
+ </html>
127
+
@@ -0,0 +1,131 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for src/utils</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="../../prettify.css" />
9
+ <link rel="stylesheet" href="../../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(../../sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="../../index.html">All files</a> src/utils</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">100% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>28/28</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">100% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>16/16</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">100% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>3/3</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">100% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>28/28</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line high'></div>
65
+ <div class="pad1">
66
+ <table class="coverage-summary">
67
+ <thead>
68
+ <tr>
69
+ <th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
70
+ <th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
71
+ <th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
72
+ <th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
73
+ <th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
74
+ <th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
75
+ <th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
76
+ <th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
77
+ <th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
78
+ <th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
79
+ </tr>
80
+ </thead>
81
+ <tbody><tr>
82
+ <td class="file high" data-value="changes.ts"><a href="changes.ts.html">changes.ts</a></td>
83
+ <td data-value="100" class="pic high">
84
+ <div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
85
+ </td>
86
+ <td data-value="100" class="pct high">100%</td>
87
+ <td data-value="20" class="abs high">20/20</td>
88
+ <td data-value="100" class="pct high">100%</td>
89
+ <td data-value="10" class="abs high">10/10</td>
90
+ <td data-value="100" class="pct high">100%</td>
91
+ <td data-value="2" class="abs high">2/2</td>
92
+ <td data-value="100" class="pct high">100%</td>
93
+ <td data-value="20" class="abs high">20/20</td>
94
+ </tr>
95
+
96
+ <tr>
97
+ <td class="file high" data-value="duration.ts"><a href="duration.ts.html">duration.ts</a></td>
98
+ <td data-value="100" class="pic high">
99
+ <div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
100
+ </td>
101
+ <td data-value="100" class="pct high">100%</td>
102
+ <td data-value="8" class="abs high">8/8</td>
103
+ <td data-value="100" class="pct high">100%</td>
104
+ <td data-value="6" class="abs high">6/6</td>
105
+ <td data-value="100" class="pct high">100%</td>
106
+ <td data-value="1" class="abs high">1/1</td>
107
+ <td data-value="100" class="pct high">100%</td>
108
+ <td data-value="8" class="abs high">8/8</td>
109
+ </tr>
110
+
111
+ </tbody>
112
+ </table>
113
+ </div>
114
+ <div class='push'></div><!-- for sticky footer -->
115
+ </div><!-- /wrapper -->
116
+ <div class='footer quiet pad2 space-top1 center small'>
117
+ Code coverage generated by
118
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
119
+ at 2026-08-15T08:27:09.571Z
120
+ </div>
121
+ <script src="../../prettify.js"></script>
122
+ <script>
123
+ window.onload = function () {
124
+ prettyPrint();
125
+ };
126
+ </script>
127
+ <script src="../../sorter.js"></script>
128
+ <script src="../../block-navigation.js"></script>
129
+ </body>
130
+ </html>
131
+
@@ -0,0 +1 @@
1
+ @import"https://fonts.googleapis.com/css2?family=Inter:wght@400;450;510;590;600&family=JetBrains+Mono:wght@400;500&display=swap";:root{--canvas: #fdfdfc;--surface-0: #f8f7f5;--surface-1: #f0efed;--surface-2: #e6e4e0;--surface-3: #d6d3cd;--border: #e2e0db;--border-muted: #edebe7;--border-hover: #ccc8c0;--text: #1c1b18;--text-2: #54504a;--text-3: #78736c;--text-muted: #a8a399;--accent: #d97706;--accent-hover: #b45309;--accent-soft: rgba(217, 119, 6, .08);--accent-glow: rgba(217, 119, 6, .2);--green: #16a34a;--amber: #ca8a04;--red: #dc2626;--green-soft: rgba(22, 163, 74, .08);--amber-soft: rgba(202, 138, 4, .08);--red-soft: rgba(220, 38, 38, .08);--ic-claude: #c2410c;--ic-codex: #6366f1;--ic-repoburg: #059669;--ic-cursor: #db2777;--font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--font-mono: "JetBrains Mono", "SF Mono", "Fira Code", monospace;--r-sm: 4px;--r-md: 6px;--r-lg: 8px;--r-xl: 12px;--r-pill: 9999px;--ease: cubic-bezier(.25, .46, .45, .94);--ease-out: cubic-bezier(.22, 1, .36, 1);--dur-fast: .1s;--dur-normal: .15s;--dur-slow: .25s;--inset-highlight: inset 0 1px 0 rgba(0, 0, 0, .03);--inset-strong: inset 0 1px 0 rgba(0, 0, 0, .05);--focus-ring: 0 0 0 3px var(--accent-glow)}*{margin:0;padding:0;box-sizing:border-box}html,body{height:100%;overflow:hidden}body{font-family:var(--font-sans);font-size:13px;font-weight:400;background:var(--canvas);color:var(--text-2);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility;font-feature-settings:"ss03","cv11";font-variant-numeric:tabular-nums;letter-spacing:-.01em}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--surface-3);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--border-hover)}:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:var(--r-md)}.ide-root{display:flex;flex-direction:column;height:100vh}.ide-layout{display:grid;grid-template-columns:240px 1fr 300px;flex:1;overflow:hidden}.ide-sidebar{background:var(--surface-0);border-right:1px solid var(--border);overflow-y:auto;display:flex;flex-direction:column}.sidebar-header{padding:10px 12px 8px;display:flex;align-items:center;justify-content:space-between}.sidebar-header-title{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted)}.sidebar-add{width:20px;height:20px;border-radius:var(--r-sm);border:none;background:transparent;color:var(--text-muted);cursor:pointer;font-size:15px;display:flex;align-items:center;justify-content:center;transition:all var(--dur-normal) var(--ease)}.sidebar-add:hover{background:#0000000f;color:var(--text)}.tree-section{margin-bottom:2px}.tree-section-header{padding:5px 8px;display:flex;align-items:center;gap:6px;font-size:11px;font-weight:590;color:var(--text-2);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:var(--r-sm);transition:background var(--dur-fast) var(--ease)}.tree-section-header:hover{background:#0000000a}.tree-chevron{font-size:9px;color:var(--text-muted);width:10px;transition:transform var(--dur-normal) var(--ease)}.tree-section.collapsed .tree-chevron{transform:rotate(-90deg)}.tree-section.collapsed .tree-children{display:none}.tree-count{margin-left:auto;font-size:10px;background:var(--surface-2);padding:1px 6px;border-radius:var(--r-pill);color:var(--text-muted);font-variant-numeric:tabular-nums}.tree-children{padding-left:4px}.tree-item{padding:4px 8px 4px 26px;border-radius:var(--r-sm);font-size:12px;cursor:pointer;display:flex;align-items:center;gap:6px;color:var(--text-2);-webkit-user-select:none;user-select:none;transition:all var(--dur-fast) var(--ease);position:relative}.tree-item:hover{background:#0000000a;color:var(--text)}.tree-item.active{background:var(--accent-soft);color:var(--text)}.tree-item.active:before{content:"";position:absolute;left:0;top:4px;bottom:4px;width:2px;background:var(--accent);border-radius:var(--r-pill)}.tree-item .ri{width:16px;height:16px;border-radius:3px;display:flex;align-items:center;justify-content:center;font-size:8px;font-weight:700;color:#fff;flex-shrink:0}.tree-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-footer{margin-top:auto;padding:8px 12px;border-top:1px solid var(--border-muted);font-size:11px;color:var(--text-muted);display:flex;align-items:center;gap:6px;cursor:pointer}.sidebar-footer:hover{color:var(--text-2)}.ide-center{display:flex;flex-direction:column;background:var(--canvas);overflow:hidden;min-height:0}.ide-tabs{display:flex;background:var(--surface-0);border-bottom:1px solid var(--border);overflow-x:auto;flex-shrink:0;scrollbar-width:none}.ide-tabs::-webkit-scrollbar{display:none}.ide-tab{padding:8px 12px;font-size:12px;color:var(--text-3);border-right:1px solid var(--border-muted);cursor:pointer;display:flex;align-items:center;gap:6px;white-space:nowrap;-webkit-user-select:none;user-select:none;transition:all var(--dur-fast) var(--ease);position:relative}.ide-tab:hover{background:#00000008;color:var(--text-2)}.ide-tab.active{color:var(--text);background:var(--canvas)}.ide-tab.active:after{content:"";position:absolute;left:0;right:0;top:0;height:2px;background:var(--accent)}.ide-tab .ri{width:14px;height:14px;font-size:7px;border-radius:3px}.ide-tab-close{margin-left:4px;color:var(--text-muted);font-size:14px;opacity:0;transition:opacity var(--dur-fast) var(--ease);display:flex;align-items:center}.ide-tab:hover .ide-tab-close{opacity:1}.ide-tab-close:hover{color:var(--red)}.ide-tab-add{padding:8px 10px;color:var(--text-muted);cursor:pointer;font-size:14px;transition:color var(--dur-fast) var(--ease);display:flex;align-items:center}.ide-tab-add:hover{color:var(--text)}.ide-render{flex:1;overflow:hidden;display:flex;flex-direction:column;position:relative;min-height:0}.render-scroll{flex:1;padding:20px 28px;overflow-y:auto;font-size:14px;line-height:1.7;color:var(--text);min-height:0}.render-content{max-width:720px}.render-content h1,.render-content h2,.render-content h3{margin:20px 0 8px;font-weight:600;color:var(--text);line-height:1.3}.render-content h1{font-size:20px}.render-content h2{font-size:17px}.render-content h3{font-size:15px}.render-content p{margin-bottom:12px;color:var(--text-2)}.render-content ul,.render-content ol{margin-bottom:12px;padding-left:24px}.render-content li{margin-bottom:4px;color:var(--text-2)}.render-content code{font-family:var(--font-mono);font-size:12px;background:var(--surface-1);padding:2px 6px;border-radius:var(--r-sm);color:var(--accent)}.render-content pre{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);padding:12px 16px;overflow-x:auto;margin-bottom:12px}.render-content pre code{background:none;padding:0;color:var(--text);font-size:12.5px;line-height:1.6}.render-content a{color:var(--accent);text-decoration:none}.render-content a:hover{text-decoration:underline}.render-content blockquote{border-left:3px solid var(--border);padding-left:14px;color:var(--text-3);margin-bottom:12px}.render-content table{width:100%;border-collapse:collapse;margin-bottom:12px}.render-content th,.render-content td{border:1px solid var(--border);padding:6px 10px;font-size:13px}.render-content th{background:var(--surface-1);font-weight:510}.turn-header{display:flex;align-items:center;gap:8px;margin-bottom:14px}.turn-header-icon{width:24px;height:24px;border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:9px;font-weight:700;color:#fff}.turn-header-title{font-size:14px;font-weight:600;color:var(--text)}.turn-header-meta{font-size:11px;color:var(--text-muted)}.tool-calls{margin-bottom:16px}.tool-calls-header{display:flex;align-items:center;gap:8px;padding:6px 12px;background:var(--surface-1);border:1px solid var(--border);border-radius:var(--r-sm);cursor:pointer;transition:background .15s ease-out;-webkit-user-select:none;user-select:none}.tool-calls-header:hover{background:var(--surface-2)}.tool-calls-icon{display:flex;align-items:center;color:var(--text-3);flex-shrink:0}.tool-calls-summary{font-size:13px;font-weight:500;color:var(--text-2);flex:1}.tool-calls-chevron{color:var(--text-muted);transition:transform .15s ease-out;flex-shrink:0}.tool-calls-body{margin-top:8px;padding-left:16px;border-left:2px solid var(--border)}.intermediate-segment{margin-bottom:16px}.intermediate-segment:last-child{margin-bottom:0}.user-message{font-size:14px;color:var(--text);background:var(--accent-soft);padding:12px 16px;border-radius:var(--r-md);border:1px solid rgba(217,119,6,.15)}.cmd-bar{position:relative;display:flex;align-items:flex-end;gap:8px;padding:8px 12px;background:var(--surface-0);border-top:1px solid var(--border);flex-shrink:0}.cmd-bar:focus-within{box-shadow:inset 0 0 0 1px #d9770666}.cmd-textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:13px;font-family:var(--font-sans);outline:none;resize:none;overflow-y:auto;line-height:1.5;padding:6px 0}.cmd-textarea::placeholder{color:var(--text-muted)}.cmd-textarea:disabled{opacity:.5}.cmd-textarea:focus-visible{box-shadow:none}.cmd-send-btn{width:28px;height:28px;border:none;border-radius:var(--r-sm);background:var(--surface-2);color:var(--text-muted);cursor:default;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all var(--dur-fast) var(--ease)}.cmd-send-btn:not(:disabled){background:var(--accent);color:#fff;cursor:pointer}.cmd-send-btn:not(:disabled):hover{background:var(--accent-hover)}.cmd-send-btn:disabled{opacity:.4}.cmd-stop-btn{width:28px;height:28px;border:none;border-radius:var(--r-sm);background:var(--red);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all var(--dur-fast) var(--ease)}.cmd-stop-btn:hover{background:#b91c1c}.ide-right{background:var(--surface-0);border-left:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden}.right-tabs{display:flex;padding:0 8px;border-bottom:1px solid var(--border);flex-shrink:0;gap:2px}.right-tab{padding:7px 10px;font-size:11px;font-weight:510;color:var(--text-3);cursor:pointer;border-bottom:2px solid transparent;-webkit-user-select:none;user-select:none;transition:all var(--dur-fast) var(--ease);margin-bottom:-1px}.right-tab:hover{color:var(--text-2)}.right-tab.active{color:var(--text);border-bottom-color:var(--accent)}.right-content{flex:1;overflow-y:auto;padding:14px}.right-section{margin-bottom:20px}.right-section-title{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);margin-bottom:8px}.metric-row{display:flex;justify-content:space-between;align-items:center;font-size:12px;padding:4px 0;border-bottom:1px solid var(--border-muted)}.metric-row:last-child{border:none}.metric-label{color:var(--text-3)}.metric-val{color:var(--text);font-weight:510;font-variant-numeric:tabular-nums}.turn-item{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:var(--r-sm);cursor:pointer;font-size:12px;color:var(--text-3);transition:all var(--dur-fast) var(--ease);position:relative}.turn-item:hover{background:#0000000a;color:var(--text-2)}.turn-item.active{background:var(--accent-soft);color:var(--text)}.turn-item.active:before{content:"";position:absolute;left:0;top:4px;bottom:4px;width:2px;background:var(--accent);border-radius:var(--r-pill)}.turn-item-icon{width:18px;height:18px;border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:8px;font-weight:700;color:#fff}.turn-item-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.turn-item-meta{font-size:10px;color:var(--text-muted);flex-shrink:0}.file-change{display:flex;align-items:center;gap:8px;padding:5px 0;font-size:12px;border-bottom:1px solid var(--border-muted)}.file-change:last-child{border:none}.file-change.clickable{cursor:pointer;transition:background var(--dur-fast) var(--ease)}.file-change.clickable:hover{background:#00000008}.fc-status{width:14px;text-align:center;font-weight:700;font-size:11px;flex-shrink:0}.fc-add{color:var(--green)}.fc-mod{color:var(--amber)}.fc-del{color:var(--red)}.fc-name{flex:1;color:var(--text-2);font-family:var(--font-mono);font-size:11px}.fc-delta{font-size:10px;color:var(--text-muted);flex-shrink:0;font-variant-numeric:tabular-nums}.diff-file-header{display:flex;align-items:center;gap:10px;padding:10px 14px;background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md) var(--r-md) 0 0;border-bottom:none}.diff-file-status{width:16px;height:16px;border-radius:3px;display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:700;flex-shrink:0}.diff-file-name{font-family:var(--font-mono);font-size:13px;font-weight:510;color:var(--text)}.diff-file-stats{display:flex;align-items:center;gap:6px;margin-left:auto;font-size:11px;font-variant-numeric:tabular-nums}.diff-file-badge{padding:1px 7px;border-radius:var(--r-pill);background:var(--surface-2);color:var(--text-3);font-size:10px}.diff-body{border:1px solid var(--border);border-radius:0 0 var(--r-md) var(--r-md);overflow:hidden;margin-bottom:20px}.diff-line{display:flex;align-items:flex-start;font-family:var(--font-mono);font-size:12px;line-height:1.6}.diff-line-num{width:42px;flex-shrink:0;text-align:right;padding:0 8px;color:var(--text-muted);background:var(--surface-0);-webkit-user-select:none;user-select:none;border-right:1px solid var(--border-muted)}.diff-sign{width:20px;flex-shrink:0;text-align:center;-webkit-user-select:none;user-select:none;font-weight:700}.diff-line-content{flex:1;padding:0 8px;white-space:pre-wrap;word-break:break-all;min-width:0}.diff-line-add{background:#16a34a0f}.diff-line-add .diff-sign{color:var(--green)}.diff-line-del{background:#dc26260f}.diff-line-del .diff-sign{color:var(--red)}.diff-line-ctx .diff-sign{color:var(--text-muted)}.diff-line-ctx .diff-line-content{color:var(--text-3)}.changes-scope-toggle{display:flex;gap:2px;margin-bottom:12px;padding:2px;background:var(--surface-1);border-radius:var(--r-md)}.scope-btn{flex:1;padding:5px 10px;border:none;background:transparent;color:var(--text-3);font-size:11px;font-weight:510;cursor:pointer;border-radius:var(--r-sm);font-family:var(--font-sans);transition:all var(--dur-fast) var(--ease)}.scope-btn:hover{color:var(--text-2)}.scope-btn.active{background:var(--surface-0);color:var(--text);box-shadow:var(--inset-highlight)}.log-entry{padding:5px 0;font-size:11px;line-height:1.5;border-bottom:1px solid var(--border-muted);font-family:var(--font-mono)}.log-entry:last-child{border:none}.log-time{color:var(--text-muted);margin-right:8px}.log-level{font-weight:700;margin-right:6px}.log-info{color:var(--accent)}.log-warn{color:var(--amber)}.log-error{color:var(--red)}.log-debug{color:var(--text-muted)}.log-msg{color:var(--text-2)}.ide-statusbar{display:flex;align-items:center;gap:12px;padding:0 12px;height:24px;background:var(--surface-0);border-top:1px solid var(--border);font-size:11px;color:var(--text-muted);flex-shrink:0;font-variant-numeric:tabular-nums}.sb-item{display:flex;align-items:center;gap:3px;cursor:pointer;transition:color var(--dur-fast) var(--ease)}.sb-item:hover{color:var(--text-2)}.sb-spacer{flex:1}.sb-divider{color:var(--border)}.model-selector{position:relative}.model-selector-btn{display:flex;align-items:center;gap:4px;background:none;border:none;cursor:pointer;color:var(--text-muted);font-size:11px;padding:2px 6px;border-radius:3px;transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}.model-selector-btn:hover{background:var(--surface-1);color:var(--text-2)}.model-selector-provider{font-weight:500;color:var(--accent)}.model-selector-sep{color:var(--border);margin:0 1px}.model-selector-model{color:var(--text-2)}.model-selector-reasoning{color:var(--text-muted);font-style:italic}.model-selector-chevron{opacity:.5;flex-shrink:0}.model-selector-popover{position:absolute;bottom:calc(100% + 4px);left:0;display:flex;gap:1px;background:var(--surface-0);border:1px solid var(--border);border-radius:6px;box-shadow:0 4px 16px #0003;z-index:100;min-width:0;overflow:hidden}.model-selector-column{min-width:140px;max-width:220px;padding:4px 0;background:var(--surface-0)}.model-selector-col-header{padding:4px 10px;font-size:9px;font-weight:600;text-transform:uppercase;color:var(--text-muted);letter-spacing:.5px}.model-selector-item{display:flex;align-items:center;gap:6px;padding:6px 10px;cursor:pointer;font-size:11px;color:var(--text-2);transition:background var(--dur-fast) var(--ease)}.model-selector-item:hover{background:var(--surface-1)}.model-selector-item.selected{color:var(--accent)}.model-selector-item.disabled{cursor:default;opacity:.5}.model-selector-item.disabled:hover{background:none}.model-selector-item-main{display:flex;flex-direction:column;gap:1px;flex:1;min-width:0}.model-selector-item-name{font-weight:500;white-space:nowrap}.model-selector-item-desc{font-size:9px;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.model-selector-coming-soon{display:flex;align-items:center;gap:2px;font-size:9px;color:var(--text-muted);font-style:italic}.model-selector-empty{padding:8px 10px;font-size:10px;color:var(--text-muted);font-style:italic}.dialog-select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 8px center;padding-right:26px}.badge{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:var(--r-pill);font-size:11px;font-weight:510;white-space:nowrap}.badge-running{background:var(--green-soft);color:var(--green)}.badge-queued{background:var(--amber-soft);color:var(--amber)}.badge-done{background:var(--accent-soft);color:var(--accent)}.badge-failed{background:var(--red-soft);color:var(--red)}.badge-paused{background:#a8a3991f;color:var(--text-muted)}.runtime-icon{width:20px;height:20px;border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:700;color:#fff;flex-shrink:0;letter-spacing:0}.ic-claude{background:var(--ic-claude)}.ic-codex{background:var(--ic-codex)}.ic-repoburg{background:var(--ic-repoburg)}.ic-cursor{background:var(--ic-cursor)}.status-dot{width:6px;height:6px;border-radius:50%;display:inline-block;flex-shrink:0}.status-dot.running{background:var(--green);animation:dot-pulse 1.5s ease-in-out infinite}.status-dot.queued{background:var(--amber)}.status-dot.error{background:var(--red)}.status-dot.done{background:var(--accent)}.status-dot.paused{background:var(--text-muted)}[data-lucide],svg.lucide{width:16px;height:16px;stroke-width:1.5;flex-shrink:0}.icon-xs{width:12px!important;height:12px!important}.icon-sm{width:14px!important;height:14px!important}.icon-lg{width:20px!important;height:20px!important}.dialog-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#0000004d;display:flex;align-items:center;justify-content:center;z-index:100}.dialog{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-lg);width:400px;max-width:90vw;box-shadow:0 8px 32px #00000029}.dialog-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--border-muted)}.dialog-title{font-size:14px;font-weight:600;color:var(--text)}.dialog-close{border:none;background:transparent;color:var(--text-muted);cursor:pointer;padding:4px;border-radius:var(--r-sm);display:flex;align-items:center;transition:all var(--dur-fast) var(--ease)}.dialog-close:hover{background:#0000000f;color:var(--text)}.dialog-body{padding:16px;display:flex;flex-direction:column;gap:14px}.dialog-label{display:flex;flex-direction:column;gap:4px;font-size:11px;font-weight:510;color:var(--text-muted)}.dialog-input{border:1px solid var(--border);border-radius:var(--r-sm);padding:8px 10px;font-size:13px;font-family:var(--font-sans);color:var(--text);background:var(--canvas);outline:none;transition:border-color var(--dur-fast) var(--ease)}.dialog-input:focus{border-color:var(--accent);box-shadow:var(--focus-ring)}.dialog-footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--border-muted)}.dialog-btn-cancel{padding:6px 14px;border-radius:var(--r-sm);border:1px solid var(--border);background:transparent;color:var(--text-2);font-size:12px;cursor:pointer;font-family:var(--font-sans);transition:all var(--dur-fast) var(--ease)}.dialog-btn-cancel:hover{background:var(--surface-2);color:var(--text)}.dialog-btn-create{padding:6px 14px;border-radius:var(--r-sm);border:none;background:var(--accent);color:#fff;font-size:12px;font-weight:510;cursor:pointer;font-family:var(--font-sans);transition:all var(--dur-fast) var(--ease)}.dialog-btn-create:hover{background:var(--accent-hover)}.turn-group{margin-bottom:24px}.turn-block{margin-bottom:32px;padding-bottom:8px;border-bottom:1px solid var(--border)}.turn-block:last-child{border-bottom:none}.cmd-block{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);padding:10px 14px;overflow-x:auto;margin-bottom:12px}.cmd-block code{font-family:var(--font-mono);font-size:12px;color:var(--text)}.cmd-output{background:var(--surface-0);border:1px solid var(--border-muted);border-radius:var(--r-md);padding:10px 14px;overflow-x:auto;margin-bottom:12px;max-height:200px;overflow-y:auto}.cmd-output code{font-family:var(--font-mono);font-size:12px;color:var(--text-3)}.cmd-output-toggle{border:1px solid var(--border);border-radius:var(--r-sm);background:var(--surface-1);color:var(--text-muted);font-size:11px;font-family:var(--font-sans);padding:4px 10px;cursor:pointer;margin-bottom:12px;transition:all var(--dur-fast) var(--ease)}.cmd-output-toggle:hover{background:var(--surface-2);color:var(--text-2)}.mcp-args{margin-bottom:12px}.mcp-arg{margin-bottom:6px}.mcp-arg-key{font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em;display:block;margin-bottom:3px}.mcp-arg-value{font-size:12px;color:var(--text-2);white-space:pre-wrap;word-break:break-word}.file-change-list{display:flex;flex-direction:column;gap:2px}.todo-list{list-style:none;padding-left:0}.todo-done{color:var(--text-3);text-decoration:line-through}.todo-pending{color:var(--text-2)}.empty-state{padding:40px 20px;text-align:center;color:var(--text-muted);font-size:13px}.palette-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000040;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);display:flex;align-items:flex-start;justify-content:center;padding-top:120px;z-index:200}.palette{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-lg);width:520px;max-width:90vw;box-shadow:0 12px 40px #0003;overflow:hidden}.palette-search{display:flex;align-items:center;gap:8px;padding:12px 16px;border-bottom:1px solid var(--border-muted)}.palette-search input{flex:1;border:none;background:transparent;color:var(--text);font-size:15px;font-family:var(--font-sans);outline:none}.palette-search input::placeholder{color:var(--text-muted)}.palette-esc{font-size:10px;font-weight:600;color:var(--text-muted);background:var(--surface-2);padding:2px 6px;border-radius:var(--r-sm)}.palette-list{max-height:360px;overflow-y:auto;padding:4px}.palette-empty{padding:24px;text-align:center;color:var(--text-muted);font-size:13px}.palette-item{display:flex;align-items:center;gap:10px;padding:8px 12px;border-radius:var(--r-sm);cursor:pointer;transition:background var(--dur-fast) var(--ease)}.palette-item.selected{background:var(--accent-soft)}.palette-item-icon{color:var(--text-muted);flex-shrink:0;display:flex;align-items:center}.palette-item.selected .palette-item-icon{color:var(--accent)}.palette-item-label{font-size:13px;color:var(--text);font-weight:510}.palette-item-hint{font-size:11px;color:var(--text-muted);margin-left:auto}.palette-item-enter{color:var(--text-muted);flex-shrink:0}.toast-container{position:fixed;bottom:36px;right:16px;display:flex;flex-direction:column-reverse;gap:8px;z-index:300;pointer-events:none}.toast{display:flex;align-items:center;gap:8px;padding:10px 14px;border-radius:var(--r-md);font-size:12px;font-weight:500;min-width:280px;max-width:400px;pointer-events:auto;animation:toast-in .2s ease-out;border:1px solid var(--border);background:var(--surface-0);box-shadow:0 4px 16px #0000001f}@keyframes toast-in{0%{opacity:0;transform:translate(20px)}to{opacity:1;transform:translate(0)}}.toast-success{border-left:3px solid var(--green)}.toast-success svg{color:var(--green)}.toast-error{border-left:3px solid var(--red)}.toast-error svg{color:var(--red)}.toast-info{border-left:3px solid var(--accent)}.toast-info svg{color:var(--accent)}.toast-warn{border-left:3px solid var(--amber)}.toast-warn svg{color:var(--amber)}.toast-message{flex:1;color:var(--text-2)}.toast-close{border:none;background:transparent;color:var(--text-muted);cursor:pointer;padding:2px;border-radius:var(--r-sm);display:flex;align-items:center;transition:color var(--dur-fast) var(--ease)}.toast-close:hover{color:var(--text)}.error-banner{display:flex;align-items:center;gap:10px;padding:10px 16px;background:#dc262614;border:1px solid rgba(220,38,38,.2);border-radius:var(--r-md);margin-bottom:16px}.banner-icon{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex-shrink:0}.error-banner .banner-icon{background:var(--red);color:#fff}.error-banner .banner-text{color:var(--red);font-size:13px;font-weight:500}.aborted-banner{display:flex;align-items:center;gap:10px;padding:10px 16px;background:#d9770614;border:1px solid rgba(217,119,6,.2);border-radius:var(--r-md);margin-bottom:16px}.aborted-banner .banner-icon{background:var(--amber);color:#fff}.aborted-banner .banner-text{color:var(--amber);font-size:13px;font-weight:500}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}.skeleton-bars{width:80%;max-width:500px;margin:20px 0}.skeleton-bar{height:10px;border-radius:var(--r-sm);background:var(--surface-1);margin-bottom:8px;animation:shimmer 1.2s infinite}.skeleton-bar:nth-child(1){width:60%}.skeleton-bar:nth-child(2){width:85%}.skeleton-bar:nth-child(3){width:70%}.skeleton-bar:nth-child(4){width:90%}.skeleton-bar:nth-child(5){width:50%}@keyframes shimmer{0%{opacity:.3}50%{opacity:.6}to{opacity:.3}}@keyframes dot-pulse{0%{opacity:1}to{opacity:.4}}.diff-file-header{transition:background .3s ease-out}.diff-file-header.diff-highlight{background:var(--accent-soft)}.palette-footer{display:flex;gap:16px;padding:8px 16px;border-top:1px solid var(--border-muted);font-size:11px;color:var(--text-muted)}.palette-footer-hint{display:flex;align-items:center;gap:4px}.kbd{font-family:var(--font-mono);font-size:10px;padding:1px 5px;border-radius:var(--r-sm);background:var(--surface-2);border:1px solid var(--border)}.toast-undo{font-size:12px;font-weight:500;color:var(--accent);background:transparent;border:none;cursor:pointer;padding:2px 8px;border-radius:var(--r-sm);display:flex;align-items:center;gap:4px;transition:background var(--dur-fast) var(--ease)}.toast-undo:hover{background:var(--accent-soft)}.tree-section-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px}.tree-section-add{width:18px;height:18px;border:none;border-radius:var(--r-sm);background:transparent;color:var(--text-muted);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all var(--dur-fast) var(--ease);flex-shrink:0}.tree-section-add:hover{background:var(--accent-soft);color:var(--accent)}.tree-empty{padding:4px 8px 4px 26px;font-size:11px;color:var(--text-muted);font-style:italic}.tree-subgroup{margin-bottom:1px}.tree-subgroup-header{padding:3px 8px 3px 18px;display:flex;align-items:center;gap:5px;font-size:10px;font-weight:590;color:var(--text-muted);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:var(--r-sm);transition:background var(--dur-fast) var(--ease)}.tree-subgroup-header:hover{background:#0000000a;color:var(--text-2)}.tree-subgroup.collapsed .tree-chevron{transform:rotate(-90deg)}.tree-subgroup.collapsed .tree-subgroup-items{display:none}.tree-subgroup-label{text-transform:uppercase;letter-spacing:.05em}.tree-subgroup-count{margin-left:auto;font-size:9px;color:var(--text-muted);font-variant-numeric:tabular-nums}.tree-subgroup-items{padding-left:0}.tree-item-finished .tree-label{color:var(--text-muted);opacity:.6}.tree-item-finished:hover .tree-label{opacity:.85}.ctx-menu{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);box-shadow:0 4px 16px #0000001f;padding:4px;min-width:160px}.ctx-menu-item{display:flex;align-items:center;gap:8px;padding:6px 10px;border-radius:var(--r-sm);font-size:12px;color:var(--text-2);cursor:pointer;transition:background var(--dur-fast) var(--ease)}.ctx-menu-item:hover{background:var(--accent-soft);color:var(--text)}.ctx-menu-item.ctx-danger:hover{background:#dc262614;color:var(--red)}.ctx-menu-item.ctx-disabled{opacity:.4;cursor:default}.ctx-menu-item.ctx-disabled:hover{background:transparent;color:var(--text-2)}.tree-rename-input{flex:1;border:1px solid var(--accent);border-radius:var(--r-sm);padding:1px 6px;font-size:12px;font-family:var(--font-sans);color:var(--text);background:var(--canvas);outline:none;box-shadow:var(--focus-ring);min-width:0}.slash-popup{position:absolute;bottom:100%;left:12px;right:12px;margin-bottom:4px;background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);box-shadow:0 4px 16px #0000001f;max-height:280px;overflow-y:auto;z-index:100}.slash-popup-header{padding:6px 10px;font-size:10px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:4px}.slash-popup-back{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:11px;padding:2px 4px;border-radius:var(--r-sm)}.slash-popup-back:hover{background:var(--surface-1);color:var(--text-2)}.slash-popup-empty{padding:12px 10px;font-size:12px;color:var(--text-muted);text-align:center}.slash-popup-item{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 10px;cursor:pointer;border-radius:var(--r-sm);transition:background var(--dur-fast) var(--ease)}.slash-popup-item:hover,.slash-popup-item.selected{background:var(--accent-soft)}.slash-popup-label{font-size:12px;font-weight:500;color:var(--text-2);font-family:var(--font-mono)}.slash-popup-hint{font-size:11px;color:var(--text-muted)}.slash-popup-item-main{display:flex;flex-direction:column;gap:1px}.slash-popup-check{color:var(--accent);font-size:13px}.skill-badges{display:flex;flex-wrap:wrap;gap:4px;padding:4px 12px 0}.skill-badge{display:inline-flex;align-items:center;gap:4px;padding:2px 6px;font-size:11px;font-family:var(--font-mono);color:var(--accent);background:var(--accent-soft);border-radius:var(--r-sm)}.skill-badge-remove{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:13px;line-height:1;padding:0}.skill-badge-remove:hover{color:var(--red)}