@nocturnium/svelte-ide 1.0.0-rc.1

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 (330) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +251 -0
  3. package/dist/components/agents/AgentActivityPanel.svelte +565 -0
  4. package/dist/components/agents/AgentActivityPanel.svelte.d.ts +24 -0
  5. package/dist/components/agents/AgentAvatar.svelte +417 -0
  6. package/dist/components/agents/AgentAvatar.svelte.d.ts +23 -0
  7. package/dist/components/agents/AgentCursor.svelte +224 -0
  8. package/dist/components/agents/AgentCursor.svelte.d.ts +35 -0
  9. package/dist/components/agents/AgentPresenceBar.svelte +261 -0
  10. package/dist/components/agents/AgentPresenceBar.svelte.d.ts +20 -0
  11. package/dist/components/agents/index.d.ts +4 -0
  12. package/dist/components/agents/index.js +5 -0
  13. package/dist/components/ai/AIConversationList.svelte +524 -0
  14. package/dist/components/ai/AIConversationList.svelte.d.ts +17 -0
  15. package/dist/components/ai/AIEditPreview.svelte +132 -0
  16. package/dist/components/ai/AIEditPreview.svelte.d.ts +8 -0
  17. package/dist/components/ai/AIInlineEdit.svelte +155 -0
  18. package/dist/components/ai/AIInlineEdit.svelte.d.ts +10 -0
  19. package/dist/components/ai/AIMessage.svelte +239 -0
  20. package/dist/components/ai/AIMessage.svelte.d.ts +13 -0
  21. package/dist/components/ai/AIMessageActions.svelte +176 -0
  22. package/dist/components/ai/AIMessageActions.svelte.d.ts +12 -0
  23. package/dist/components/ai/AIMessageContent.svelte +355 -0
  24. package/dist/components/ai/AIMessageContent.svelte.d.ts +7 -0
  25. package/dist/components/ai/AIPanel.svelte +561 -0
  26. package/dist/components/ai/AIPanel.svelte.d.ts +7 -0
  27. package/dist/components/ai/AISuggestionWidget.svelte +132 -0
  28. package/dist/components/ai/AISuggestionWidget.svelte.d.ts +10 -0
  29. package/dist/components/ai/AIToolCallDisplay.svelte +317 -0
  30. package/dist/components/ai/AIToolCallDisplay.svelte.d.ts +12 -0
  31. package/dist/components/ai/index.d.ts +9 -0
  32. package/dist/components/ai/index.js +10 -0
  33. package/dist/components/core/Avatar.svelte +110 -0
  34. package/dist/components/core/Avatar.svelte.d.ts +12 -0
  35. package/dist/components/core/Badge.svelte +98 -0
  36. package/dist/components/core/Badge.svelte.d.ts +11 -0
  37. package/dist/components/core/Button.svelte +175 -0
  38. package/dist/components/core/Button.svelte.d.ts +18 -0
  39. package/dist/components/core/ConnectionStatus.svelte +294 -0
  40. package/dist/components/core/ConnectionStatus.svelte.d.ts +20 -0
  41. package/dist/components/core/ContextMenu.svelte +176 -0
  42. package/dist/components/core/ContextMenu.svelte.d.ts +19 -0
  43. package/dist/components/core/ErrorBoundary.svelte +277 -0
  44. package/dist/components/core/ErrorBoundary.svelte.d.ts +23 -0
  45. package/dist/components/core/Icon.svelte +107 -0
  46. package/dist/components/core/Icon.svelte.d.ts +8 -0
  47. package/dist/components/core/Input.svelte +138 -0
  48. package/dist/components/core/Input.svelte.d.ts +20 -0
  49. package/dist/components/core/Kbd.svelte +34 -0
  50. package/dist/components/core/Kbd.svelte.d.ts +7 -0
  51. package/dist/components/core/ResizeHandle.svelte +200 -0
  52. package/dist/components/core/ResizeHandle.svelte.d.ts +23 -0
  53. package/dist/components/core/Spinner.svelte +35 -0
  54. package/dist/components/core/Spinner.svelte.d.ts +7 -0
  55. package/dist/components/core/Textarea.svelte +112 -0
  56. package/dist/components/core/Textarea.svelte.d.ts +18 -0
  57. package/dist/components/core/Tooltip.svelte +103 -0
  58. package/dist/components/core/Tooltip.svelte.d.ts +11 -0
  59. package/dist/components/core/index.d.ts +13 -0
  60. package/dist/components/core/index.js +14 -0
  61. package/dist/components/editor/AIFocusLayer.svelte +430 -0
  62. package/dist/components/editor/AIFocusLayer.svelte.d.ts +32 -0
  63. package/dist/components/editor/Breadcrumbs.svelte +435 -0
  64. package/dist/components/editor/Breadcrumbs.svelte.d.ts +33 -0
  65. package/dist/components/editor/BreakpointLayer.svelte +642 -0
  66. package/dist/components/editor/BreakpointLayer.svelte.d.ts +20 -0
  67. package/dist/components/editor/CognitiveLoadMeter.svelte +324 -0
  68. package/dist/components/editor/CognitiveLoadMeter.svelte.d.ts +18 -0
  69. package/dist/components/editor/CollaborativeEditor.svelte +218 -0
  70. package/dist/components/editor/CollaborativeEditor.svelte.d.ts +32 -0
  71. package/dist/components/editor/CommandPalette.svelte +434 -0
  72. package/dist/components/editor/CommandPalette.svelte.d.ts +11 -0
  73. package/dist/components/editor/ComplexityLayer.svelte +293 -0
  74. package/dist/components/editor/ComplexityLayer.svelte.d.ts +23 -0
  75. package/dist/components/editor/ConflictZoneLayer.svelte +441 -0
  76. package/dist/components/editor/ConflictZoneLayer.svelte.d.ts +25 -0
  77. package/dist/components/editor/ContextLens.svelte +262 -0
  78. package/dist/components/editor/ContextLens.svelte.d.ts +27 -0
  79. package/dist/components/editor/CustomEditor.svelte +1242 -0
  80. package/dist/components/editor/CustomEditor.svelte.d.ts +37 -0
  81. package/dist/components/editor/DebugConsole.svelte +646 -0
  82. package/dist/components/editor/DebugConsole.svelte.d.ts +41 -0
  83. package/dist/components/editor/EchoCursorLayer.svelte +363 -0
  84. package/dist/components/editor/EchoCursorLayer.svelte.d.ts +24 -0
  85. package/dist/components/editor/Editor.svelte +61 -0
  86. package/dist/components/editor/Editor.svelte.d.ts +22 -0
  87. package/dist/components/editor/EditorGutter.svelte +119 -0
  88. package/dist/components/editor/EditorGutter.svelte.d.ts +19 -0
  89. package/dist/components/editor/EditorLines.svelte +182 -0
  90. package/dist/components/editor/EditorLines.svelte.d.ts +43 -0
  91. package/dist/components/editor/EditorPane.svelte +134 -0
  92. package/dist/components/editor/EditorPane.svelte.d.ts +9 -0
  93. package/dist/components/editor/EditorSelections.svelte +186 -0
  94. package/dist/components/editor/EditorSelections.svelte.d.ts +25 -0
  95. package/dist/components/editor/EditorTabs.svelte +170 -0
  96. package/dist/components/editor/EditorTabs.svelte.d.ts +12 -0
  97. package/dist/components/editor/FileExplorer.svelte +811 -0
  98. package/dist/components/editor/FileExplorer.svelte.d.ts +67 -0
  99. package/dist/components/editor/FileIcon.svelte +110 -0
  100. package/dist/components/editor/FileIcon.svelte.d.ts +10 -0
  101. package/dist/components/editor/FindReplace.svelte +448 -0
  102. package/dist/components/editor/FindReplace.svelte.d.ts +40 -0
  103. package/dist/components/editor/GhostBracketLayer.svelte +391 -0
  104. package/dist/components/editor/GhostBracketLayer.svelte.d.ts +24 -0
  105. package/dist/components/editor/GitBlameLayer.svelte +436 -0
  106. package/dist/components/editor/GitBlameLayer.svelte.d.ts +18 -0
  107. package/dist/components/editor/InlineDiagnosticsLayer.svelte +540 -0
  108. package/dist/components/editor/InlineDiagnosticsLayer.svelte.d.ts +35 -0
  109. package/dist/components/editor/InlineDiffLayer.svelte +337 -0
  110. package/dist/components/editor/InlineDiffLayer.svelte.d.ts +31 -0
  111. package/dist/components/editor/MinimalEditor.svelte +75 -0
  112. package/dist/components/editor/MinimalEditor.svelte.d.ts +6 -0
  113. package/dist/components/editor/MinimalEditor2.svelte +84 -0
  114. package/dist/components/editor/MinimalEditor2.svelte.d.ts +6 -0
  115. package/dist/components/editor/Minimap.svelte +327 -0
  116. package/dist/components/editor/Minimap.svelte.d.ts +34 -0
  117. package/dist/components/editor/PluginPreviewSandbox.svelte +793 -0
  118. package/dist/components/editor/PluginPreviewSandbox.svelte.d.ts +49 -0
  119. package/dist/components/editor/ProblemsPanel.svelte +628 -0
  120. package/dist/components/editor/ProblemsPanel.svelte.d.ts +25 -0
  121. package/dist/components/editor/QuickActionsMenu.svelte +403 -0
  122. package/dist/components/editor/QuickActionsMenu.svelte.d.ts +18 -0
  123. package/dist/components/editor/SnippetPalette.svelte +530 -0
  124. package/dist/components/editor/SnippetPalette.svelte.d.ts +16 -0
  125. package/dist/components/editor/StructureMap.svelte +431 -0
  126. package/dist/components/editor/StructureMap.svelte.d.ts +37 -0
  127. package/dist/components/editor/SymbolOutline.svelte +722 -0
  128. package/dist/components/editor/SymbolOutline.svelte.d.ts +44 -0
  129. package/dist/components/editor/TimelineScrubber.svelte +470 -0
  130. package/dist/components/editor/TimelineScrubber.svelte.d.ts +40 -0
  131. package/dist/components/editor/TokenRenderer.svelte +69 -0
  132. package/dist/components/editor/TokenRenderer.svelte.d.ts +15 -0
  133. package/dist/components/editor/constants.d.ts +32 -0
  134. package/dist/components/editor/constants.js +36 -0
  135. package/dist/components/editor/core/ai-awareness.d.ts +176 -0
  136. package/dist/components/editor/core/ai-awareness.js +210 -0
  137. package/dist/components/editor/core/bracket-healer.d.ts +189 -0
  138. package/dist/components/editor/core/bracket-healer.js +406 -0
  139. package/dist/components/editor/core/breakpoints.d.ts +203 -0
  140. package/dist/components/editor/core/breakpoints.js +414 -0
  141. package/dist/components/editor/core/commands.d.ts +108 -0
  142. package/dist/components/editor/core/commands.js +246 -0
  143. package/dist/components/editor/core/complexity-analyzer.d.ts +123 -0
  144. package/dist/components/editor/core/complexity-analyzer.js +376 -0
  145. package/dist/components/editor/core/conflict-predictor.d.ts +135 -0
  146. package/dist/components/editor/core/conflict-predictor.js +316 -0
  147. package/dist/components/editor/core/crdt-binding.d.ts +118 -0
  148. package/dist/components/editor/core/crdt-binding.js +286 -0
  149. package/dist/components/editor/core/diagnostics.d.ts +210 -0
  150. package/dist/components/editor/core/diagnostics.js +335 -0
  151. package/dist/components/editor/core/echo-cursor.d.ts +201 -0
  152. package/dist/components/editor/core/echo-cursor.js +267 -0
  153. package/dist/components/editor/core/folding.d.ts +124 -0
  154. package/dist/components/editor/core/folding.js +672 -0
  155. package/dist/components/editor/core/ghost-pair.d.ts +122 -0
  156. package/dist/components/editor/core/ghost-pair.js +221 -0
  157. package/dist/components/editor/core/git-blame.d.ts +170 -0
  158. package/dist/components/editor/core/git-blame.js +324 -0
  159. package/dist/components/editor/core/index.d.ts +26 -0
  160. package/dist/components/editor/core/index.js +24 -0
  161. package/dist/components/editor/core/keybindings.d.ts +79 -0
  162. package/dist/components/editor/core/keybindings.js +357 -0
  163. package/dist/components/editor/core/multi-cursor.d.ts +196 -0
  164. package/dist/components/editor/core/multi-cursor.js +521 -0
  165. package/dist/components/editor/core/navigation.d.ts +107 -0
  166. package/dist/components/editor/core/navigation.js +408 -0
  167. package/dist/components/editor/core/quick-actions.d.ts +189 -0
  168. package/dist/components/editor/core/quick-actions.js +427 -0
  169. package/dist/components/editor/core/search.d.ts +88 -0
  170. package/dist/components/editor/core/search.js +192 -0
  171. package/dist/components/editor/core/semantic-analyzer.d.ts +77 -0
  172. package/dist/components/editor/core/semantic-analyzer.js +424 -0
  173. package/dist/components/editor/core/snippet-manager.d.ts +202 -0
  174. package/dist/components/editor/core/snippet-manager.js +565 -0
  175. package/dist/components/editor/core/state.d.ts +367 -0
  176. package/dist/components/editor/core/state.js +900 -0
  177. package/dist/components/editor/core/timeline.d.ts +204 -0
  178. package/dist/components/editor/core/timeline.js +349 -0
  179. package/dist/components/editor/editor-find.d.ts +56 -0
  180. package/dist/components/editor/editor-find.js +148 -0
  181. package/dist/components/editor/editor-input.d.ts +77 -0
  182. package/dist/components/editor/editor-input.js +445 -0
  183. package/dist/components/editor/editor-multicursor.d.ts +21 -0
  184. package/dist/components/editor/editor-multicursor.js +196 -0
  185. package/dist/components/editor/editor-scroll.d.ts +14 -0
  186. package/dist/components/editor/editor-scroll.js +34 -0
  187. package/dist/components/editor/index.d.ts +15 -0
  188. package/dist/components/editor/index.js +21 -0
  189. package/dist/components/editor/languages.d.ts +62 -0
  190. package/dist/components/editor/languages.js +285 -0
  191. package/dist/components/editor/theme.d.ts +88 -0
  192. package/dist/components/editor/theme.js +139 -0
  193. package/dist/components/editor/tokenizer/base.d.ts +40 -0
  194. package/dist/components/editor/tokenizer/base.js +203 -0
  195. package/dist/components/editor/tokenizer/index.d.ts +56 -0
  196. package/dist/components/editor/tokenizer/index.js +215 -0
  197. package/dist/components/editor/tokenizer/languages/css.d.ts +17 -0
  198. package/dist/components/editor/tokenizer/languages/css.js +194 -0
  199. package/dist/components/editor/tokenizer/languages/go.d.ts +17 -0
  200. package/dist/components/editor/tokenizer/languages/go.js +220 -0
  201. package/dist/components/editor/tokenizer/languages/html.d.ts +24 -0
  202. package/dist/components/editor/tokenizer/languages/html.js +145 -0
  203. package/dist/components/editor/tokenizer/languages/javascript.d.ts +56 -0
  204. package/dist/components/editor/tokenizer/languages/javascript.js +452 -0
  205. package/dist/components/editor/tokenizer/languages/json.d.ts +12 -0
  206. package/dist/components/editor/tokenizer/languages/json.js +91 -0
  207. package/dist/components/editor/tokenizer/languages/markdown.d.ts +16 -0
  208. package/dist/components/editor/tokenizer/languages/markdown.js +156 -0
  209. package/dist/components/editor/tokenizer/languages/python.d.ts +20 -0
  210. package/dist/components/editor/tokenizer/languages/python.js +227 -0
  211. package/dist/components/editor/tokenizer/languages/svelte.d.ts +40 -0
  212. package/dist/components/editor/tokenizer/languages/svelte.js +326 -0
  213. package/dist/components/editor/tokenizer/types.d.ts +86 -0
  214. package/dist/components/editor/tokenizer/types.js +4 -0
  215. package/dist/components/layout/IDELayout.svelte +274 -0
  216. package/dist/components/layout/IDELayout.svelte.d.ts +29 -0
  217. package/dist/components/layout/StatusBar.svelte +511 -0
  218. package/dist/components/layout/StatusBar.svelte.d.ts +47 -0
  219. package/dist/components/layout/index.d.ts +2 -0
  220. package/dist/components/layout/index.js +3 -0
  221. package/dist/components/lsp/AutocompleteWidget.svelte +364 -0
  222. package/dist/components/lsp/AutocompleteWidget.svelte.d.ts +33 -0
  223. package/dist/components/lsp/DiagnosticMarker.svelte +166 -0
  224. package/dist/components/lsp/DiagnosticMarker.svelte.d.ts +19 -0
  225. package/dist/components/lsp/DiagnosticsPanel.svelte +388 -0
  226. package/dist/components/lsp/DiagnosticsPanel.svelte.d.ts +21 -0
  227. package/dist/components/lsp/HoverTooltip.svelte +274 -0
  228. package/dist/components/lsp/HoverTooltip.svelte.d.ts +24 -0
  229. package/dist/components/lsp/LSPEditor.svelte +486 -0
  230. package/dist/components/lsp/LSPEditor.svelte.d.ts +39 -0
  231. package/dist/components/lsp/SignatureHelpWidget.svelte +216 -0
  232. package/dist/components/lsp/SignatureHelpWidget.svelte.d.ts +22 -0
  233. package/dist/components/lsp/index.d.ts +6 -0
  234. package/dist/components/lsp/index.js +7 -0
  235. package/dist/components/plugins/PluginCard.svelte +153 -0
  236. package/dist/components/plugins/PluginCard.svelte.d.ts +19 -0
  237. package/dist/components/plugins/PluginPanel.svelte +280 -0
  238. package/dist/components/plugins/PluginPanel.svelte.d.ts +8 -0
  239. package/dist/components/plugins/PluginProposalForm.svelte +250 -0
  240. package/dist/components/plugins/PluginProposalForm.svelte.d.ts +6 -0
  241. package/dist/components/plugins/PluginStatusBadge.svelte +14 -0
  242. package/dist/components/plugins/PluginStatusBadge.svelte.d.ts +8 -0
  243. package/dist/components/plugins/index.d.ts +4 -0
  244. package/dist/components/plugins/index.js +5 -0
  245. package/dist/components/vfs/LockConflictDialog.svelte +705 -0
  246. package/dist/components/vfs/LockConflictDialog.svelte.d.ts +21 -0
  247. package/dist/components/vfs/LockIndicator.svelte +194 -0
  248. package/dist/components/vfs/LockIndicator.svelte.d.ts +29 -0
  249. package/dist/components/vfs/LockOverlay.svelte +344 -0
  250. package/dist/components/vfs/LockOverlay.svelte.d.ts +17 -0
  251. package/dist/components/vfs/VersionConflictDialog.svelte +549 -0
  252. package/dist/components/vfs/VersionConflictDialog.svelte.d.ts +24 -0
  253. package/dist/components/vfs/index.d.ts +4 -0
  254. package/dist/components/vfs/index.js +5 -0
  255. package/dist/crdt/awareness.d.ts +42 -0
  256. package/dist/crdt/awareness.js +109 -0
  257. package/dist/crdt/document.d.ts +101 -0
  258. package/dist/crdt/document.js +187 -0
  259. package/dist/crdt/index.d.ts +9 -0
  260. package/dist/crdt/index.js +8 -0
  261. package/dist/crdt/provider.d.ts +85 -0
  262. package/dist/crdt/provider.js +150 -0
  263. package/dist/crdt/types.d.ts +61 -0
  264. package/dist/crdt/types.js +4 -0
  265. package/dist/crdt/undo.d.ts +34 -0
  266. package/dist/crdt/undo.js +70 -0
  267. package/dist/index.d.ts +277 -0
  268. package/dist/index.js +280 -0
  269. package/dist/plugins/index.d.ts +103 -0
  270. package/dist/plugins/index.js +153 -0
  271. package/dist/services/error-handling.d.ts +95 -0
  272. package/dist/services/error-handling.js +413 -0
  273. package/dist/services/ide-integration.d.ts +83 -0
  274. package/dist/services/ide-integration.js +367 -0
  275. package/dist/services/lsp-client.d.ts +69 -0
  276. package/dist/services/lsp-client.js +667 -0
  277. package/dist/services/mock-ai.d.ts +37 -0
  278. package/dist/services/mock-ai.js +318 -0
  279. package/dist/services/optimistic.d.ts +141 -0
  280. package/dist/services/optimistic.js +367 -0
  281. package/dist/services/vfs-client.d.ts +81 -0
  282. package/dist/services/vfs-client.js +348 -0
  283. package/dist/stores/agents.svelte.d.ts +85 -0
  284. package/dist/stores/agents.svelte.js +459 -0
  285. package/dist/stores/ai-persistence.svelte.d.ts +76 -0
  286. package/dist/stores/ai-persistence.svelte.js +334 -0
  287. package/dist/stores/ai.svelte.d.ts +140 -0
  288. package/dist/stores/ai.svelte.js +383 -0
  289. package/dist/stores/collaboration.svelte.d.ts +164 -0
  290. package/dist/stores/collaboration.svelte.js +334 -0
  291. package/dist/stores/editor.svelte.d.ts +131 -0
  292. package/dist/stores/editor.svelte.js +250 -0
  293. package/dist/stores/index.d.ts +10 -0
  294. package/dist/stores/index.js +29 -0
  295. package/dist/stores/layout.svelte.d.ts +171 -0
  296. package/dist/stores/layout.svelte.js +351 -0
  297. package/dist/stores/plugin.svelte.d.ts +121 -0
  298. package/dist/stores/plugin.svelte.js +410 -0
  299. package/dist/stores/vfs.svelte.d.ts +123 -0
  300. package/dist/stores/vfs.svelte.js +680 -0
  301. package/dist/styles/theme.css +623 -0
  302. package/dist/types/agents.d.ts +127 -0
  303. package/dist/types/agents.js +5 -0
  304. package/dist/types/ai.d.ts +137 -0
  305. package/dist/types/ai.js +4 -0
  306. package/dist/types/crdt.d.ts +222 -0
  307. package/dist/types/crdt.js +5 -0
  308. package/dist/types/editor.d.ts +52 -0
  309. package/dist/types/editor.js +18 -0
  310. package/dist/types/events.d.ts +133 -0
  311. package/dist/types/events.js +4 -0
  312. package/dist/types/filesystem.d.ts +77 -0
  313. package/dist/types/filesystem.js +4 -0
  314. package/dist/types/index.d.ts +9 -0
  315. package/dist/types/index.js +12 -0
  316. package/dist/types/lsp.d.ts +691 -0
  317. package/dist/types/lsp.js +108 -0
  318. package/dist/types/plugin.d.ts +239 -0
  319. package/dist/types/plugin.js +5 -0
  320. package/dist/types/vfs.d.ts +191 -0
  321. package/dist/types/vfs.js +18 -0
  322. package/dist/utils/format.d.ts +55 -0
  323. package/dist/utils/format.js +152 -0
  324. package/dist/utils/index.d.ts +3 -0
  325. package/dist/utils/index.js +4 -0
  326. package/dist/utils/keybindings.d.ts +33 -0
  327. package/dist/utils/keybindings.js +171 -0
  328. package/dist/utils/language.d.ts +27 -0
  329. package/dist/utils/language.js +222 -0
  330. package/package.json +178 -0
@@ -0,0 +1,811 @@
1
+ <script lang="ts" module>
2
+ /**
3
+ * FileExplorer - File tree navigation component
4
+ *
5
+ * Displays a hierarchical file tree with expandable folders,
6
+ * file icons, and selection support. Supports VFS lock,
7
+ * agent presence, and file change status indicators.
8
+ */
9
+
10
+ export interface FileNode {
11
+ id: string;
12
+ name: string;
13
+ type: 'file' | 'folder';
14
+ path: string;
15
+ children?: FileNode[];
16
+ expanded?: boolean;
17
+ }
18
+
19
+ /** File change status type - for transaction/git operations */
20
+ export type FileChangeStatus = 'created' | 'modified' | 'deleted' | 'renamed' | 'clean';
21
+
22
+ /** @deprecated Use FileChangeStatus instead */
23
+ export type GitFileStatus = FileChangeStatus;
24
+ </script>
25
+
26
+ <script lang="ts">
27
+ import { Icon, Button, ContextMenu, Tooltip } from '../core';
28
+ import type { ContextMenuItem } from '../core/ContextMenu.svelte';
29
+ import FileIcon from './FileIcon.svelte';
30
+ import LockIndicator from '../vfs/LockIndicator.svelte';
31
+ import AgentAvatar from '../agents/AgentAvatar.svelte';
32
+ import type { VFSLockStatus, Agent } from '../../types';
33
+ import { tick, onDestroy } from 'svelte';
34
+
35
+ interface Props {
36
+ /** Root file nodes */
37
+ files: FileNode[];
38
+ /** Currently selected file path */
39
+ selectedPath?: string | null;
40
+ /** Current user ID for lock ownership detection */
41
+ userId?: string;
42
+ /** Map of file path to lock status */
43
+ lockStatuses?: Map<string, VFSLockStatus>;
44
+ /** Map of file path to agents currently editing */
45
+ agentsByFile?: Map<string, Agent[]>;
46
+ /** Map of file path to change status (created, modified, deleted, renamed) */
47
+ fileStatuses?: Map<string, FileChangeStatus>;
48
+ /** @deprecated Use fileStatuses instead */
49
+ gitStatuses?: Map<string, FileChangeStatus>;
50
+ /** Show lock indicators */
51
+ showLocks?: boolean;
52
+ /** Show agent indicators */
53
+ showAgents?: boolean;
54
+ /** Show file change status indicators */
55
+ showFileStatus?: boolean;
56
+ /** @deprecated Use showFileStatus instead */
57
+ showGitStatus?: boolean;
58
+ /** Called when a file is selected */
59
+ onSelect?: (node: FileNode) => void;
60
+ /** Called when a file is double-clicked (open) */
61
+ onOpen?: (node: FileNode) => void;
62
+ /** Called when a folder is toggled */
63
+ onToggle?: (node: FileNode) => void;
64
+ /** Called when a new file is requested (with name from inline input) */
65
+ onNewFile?: (parentPath: string, name: string) => void;
66
+ /** Called when a new folder is requested (with name from inline input) */
67
+ onNewFolder?: (parentPath: string, name: string) => void;
68
+ /** Called when rename is requested */
69
+ onRename?: (node: FileNode) => void;
70
+ /** Called when delete is requested */
71
+ onDelete?: (node: FileNode) => void;
72
+ /** Called when lock is requested */
73
+ onLock?: (node: FileNode) => void;
74
+ /** Called when unlock is requested */
75
+ onUnlock?: (node: FileNode) => void;
76
+ /** Additional CSS class */
77
+ class?: string;
78
+ }
79
+
80
+ let {
81
+ files,
82
+ selectedPath = null,
83
+ userId = '',
84
+ lockStatuses = new Map(),
85
+ agentsByFile = new Map(),
86
+ fileStatuses,
87
+ gitStatuses,
88
+ showLocks = true,
89
+ showAgents = true,
90
+ showFileStatus,
91
+ showGitStatus,
92
+ onSelect,
93
+ onOpen,
94
+ onToggle,
95
+ onNewFile,
96
+ onNewFolder,
97
+ onRename,
98
+ onDelete,
99
+ onLock,
100
+ onUnlock,
101
+ class: className = ''
102
+ }: Props = $props();
103
+
104
+ // Use fileStatuses if provided, fall back to gitStatuses for backwards compatibility
105
+ const statusMap = $derived(fileStatuses ?? gitStatuses ?? new Map<string, FileChangeStatus>());
106
+ const showStatus = $derived(showFileStatus ?? showGitStatus ?? true);
107
+
108
+ // Helper to get file change status for a file path
109
+ function getFileStatus(path: string): FileChangeStatus {
110
+ return statusMap.get(path) ?? 'clean';
111
+ }
112
+
113
+ // Helper to check if a folder contains any files with changes
114
+ function folderHasChanges(node: FileNode): boolean {
115
+ if (node.type === 'file') {
116
+ return getFileStatus(node.path) !== 'clean';
117
+ }
118
+ if (!node.children) return false;
119
+ return node.children.some((child) => folderHasChanges(child));
120
+ }
121
+
122
+ // Get the most "important" status for a folder (deleted > modified > created > renamed)
123
+ function getFolderStatus(node: FileNode): FileChangeStatus {
124
+ if (node.type === 'file') return getFileStatus(node.path);
125
+ if (!node.children) return 'clean';
126
+
127
+ let hasDeleted = false;
128
+ let hasModified = false;
129
+ let hasCreated = false;
130
+ let hasRenamed = false;
131
+
132
+ function checkChildren(children: FileNode[]) {
133
+ for (const child of children) {
134
+ if (child.type === 'file') {
135
+ const status = getFileStatus(child.path);
136
+ if (status === 'deleted') hasDeleted = true;
137
+ else if (status === 'modified') hasModified = true;
138
+ else if (status === 'created') hasCreated = true;
139
+ else if (status === 'renamed') hasRenamed = true;
140
+ } else if (child.children) {
141
+ checkChildren(child.children);
142
+ }
143
+ }
144
+ }
145
+
146
+ checkChildren(node.children);
147
+
148
+ if (hasDeleted) return 'deleted';
149
+ if (hasModified) return 'modified';
150
+ if (hasCreated) return 'created';
151
+ if (hasRenamed) return 'renamed';
152
+ return 'clean';
153
+ }
154
+
155
+ // Helper to check if file is locked by current user
156
+ function isOwnedByMe(path: string): boolean {
157
+ const status = lockStatuses.get(path);
158
+ if (status?.status !== 'locked') return false;
159
+ return status.lock.holder === userId;
160
+ }
161
+
162
+ // Helper to check if file is locked by an AI agent
163
+ function isLockedByAI(path: string): boolean {
164
+ const status = lockStatuses.get(path);
165
+ if (status?.status !== 'locked') return false;
166
+ return status.lock.holderType === 'agent';
167
+ }
168
+
169
+ // Get agents currently editing a file
170
+ function getAgentsForFile(path: string): Agent[] {
171
+ return agentsByFile.get(path) ?? [];
172
+ }
173
+
174
+ let expandedFolders = $state<Set<string>>(new Set());
175
+ let contextMenuNode = $state<FileNode | null>(null);
176
+ let contextMenuPos = $state({ x: 0, y: 0 });
177
+ let showContextMenu = $state(false);
178
+
179
+ // Inline creation state
180
+ let inlineCreation = $state<{
181
+ parentPath: string;
182
+ type: 'file' | 'folder';
183
+ name: string;
184
+ } | null>(null);
185
+ let inlineInputRef = $state<HTMLInputElement | null>(null);
186
+
187
+ // Cleanup on component destruction
188
+ onDestroy(() => {
189
+ // Clear inline creation state to release any DOM references
190
+ inlineCreation = null;
191
+ inlineInputRef = null;
192
+ });
193
+
194
+ function toggleFolder(node: FileNode) {
195
+ if (node.type !== 'folder') return;
196
+
197
+ const newExpanded = new Set(expandedFolders);
198
+ if (newExpanded.has(node.path)) {
199
+ newExpanded.delete(node.path);
200
+ } else {
201
+ newExpanded.add(node.path);
202
+ }
203
+ expandedFolders = newExpanded;
204
+ onToggle?.(node);
205
+ }
206
+
207
+ // Inline creation functions
208
+ async function startInlineCreation(parentPath: string, type: 'file' | 'folder') {
209
+ // Expand parent folder if it's not root
210
+ if (parentPath) {
211
+ const newExpanded = new Set(expandedFolders);
212
+ newExpanded.add(parentPath);
213
+ expandedFolders = newExpanded;
214
+ }
215
+
216
+ inlineCreation = {
217
+ parentPath,
218
+ type,
219
+ name: ''
220
+ };
221
+
222
+ // Focus the input after DOM update
223
+ await tick();
224
+ inlineInputRef?.focus();
225
+ }
226
+
227
+ function confirmInlineCreation() {
228
+ if (!inlineCreation || !inlineCreation.name.trim()) {
229
+ cancelInlineCreation();
230
+ return;
231
+ }
232
+
233
+ const { parentPath, type, name } = inlineCreation;
234
+ const trimmedName = name.trim();
235
+
236
+ if (type === 'file') {
237
+ onNewFile?.(parentPath, trimmedName);
238
+ } else {
239
+ onNewFolder?.(parentPath, trimmedName);
240
+ }
241
+
242
+ inlineCreation = null;
243
+ }
244
+
245
+ function cancelInlineCreation() {
246
+ inlineCreation = null;
247
+ }
248
+
249
+ function handleInlineKeydown(e: KeyboardEvent) {
250
+ if (e.key === 'Enter') {
251
+ e.preventDefault();
252
+ confirmInlineCreation();
253
+ } else if (e.key === 'Escape') {
254
+ e.preventDefault();
255
+ cancelInlineCreation();
256
+ }
257
+ }
258
+
259
+ function handleClick(node: FileNode) {
260
+ if (node.type === 'folder') {
261
+ toggleFolder(node);
262
+ }
263
+ onSelect?.(node);
264
+ }
265
+
266
+ function handleDoubleClick(node: FileNode) {
267
+ if (node.type === 'file') {
268
+ onOpen?.(node);
269
+ }
270
+ }
271
+
272
+ function handleKeyDown(e: KeyboardEvent, node: FileNode) {
273
+ if (e.key === 'Enter') {
274
+ if (node.type === 'folder') {
275
+ toggleFolder(node);
276
+ } else {
277
+ onOpen?.(node);
278
+ }
279
+ } else if (e.key === 'ArrowRight' && node.type === 'folder') {
280
+ if (!expandedFolders.has(node.path)) {
281
+ toggleFolder(node);
282
+ }
283
+ } else if (e.key === 'ArrowLeft' && node.type === 'folder') {
284
+ if (expandedFolders.has(node.path)) {
285
+ toggleFolder(node);
286
+ }
287
+ }
288
+ }
289
+
290
+ function handleContextMenu(e: MouseEvent, node: FileNode) {
291
+ e.preventDefault();
292
+ contextMenuNode = node;
293
+ contextMenuPos = { x: e.clientX, y: e.clientY };
294
+ showContextMenu = true;
295
+ }
296
+
297
+ function closeContextMenu() {
298
+ showContextMenu = false;
299
+ contextMenuNode = null;
300
+ }
301
+
302
+ // Memoized context menu items - only recalculates when dependencies change
303
+ let contextMenuItems = $derived.by((): ContextMenuItem[] => {
304
+ if (!contextMenuNode) return [];
305
+
306
+ const items: ContextMenuItem[] = [];
307
+
308
+ if (contextMenuNode.type === 'folder') {
309
+ items.push(
310
+ {
311
+ id: 'new-file',
312
+ label: 'New File',
313
+ icon: 'file-plus'
314
+ },
315
+ {
316
+ id: 'new-folder',
317
+ label: 'New Folder',
318
+ icon: 'folder-plus'
319
+ },
320
+ {
321
+ id: 'separator-1',
322
+ label: '',
323
+ separator: true
324
+ }
325
+ );
326
+ }
327
+
328
+ // Lock/Unlock options for files
329
+ if (contextMenuNode.type === 'file' && showLocks) {
330
+ const lockStatus = lockStatuses.get(contextMenuNode.path);
331
+ if (lockStatus?.status === 'locked' && isOwnedByMe(contextMenuNode.path)) {
332
+ items.push({
333
+ id: 'unlock',
334
+ label: 'Unlock',
335
+ icon: 'unlock'
336
+ });
337
+ } else if (lockStatus?.status !== 'locked') {
338
+ items.push({
339
+ id: 'lock',
340
+ label: 'Lock for Editing',
341
+ icon: 'lock'
342
+ });
343
+ }
344
+ items.push({
345
+ id: 'separator-2',
346
+ label: '',
347
+ separator: true
348
+ });
349
+ }
350
+
351
+ items.push(
352
+ {
353
+ id: 'rename',
354
+ label: 'Rename',
355
+ icon: 'edit',
356
+ shortcut: ['F2']
357
+ },
358
+ {
359
+ id: 'delete',
360
+ label: 'Delete',
361
+ icon: 'trash',
362
+ danger: true
363
+ }
364
+ );
365
+
366
+ return items;
367
+ });
368
+
369
+ function handleContextMenuSelect(item: ContextMenuItem) {
370
+ if (!contextMenuNode) return;
371
+
372
+ switch (item.id) {
373
+ case 'new-file':
374
+ startInlineCreation(contextMenuNode.path, 'file');
375
+ break;
376
+ case 'new-folder':
377
+ startInlineCreation(contextMenuNode.path, 'folder');
378
+ break;
379
+ case 'rename':
380
+ onRename?.(contextMenuNode);
381
+ break;
382
+ case 'delete':
383
+ onDelete?.(contextMenuNode);
384
+ break;
385
+ case 'lock':
386
+ onLock?.(contextMenuNode);
387
+ break;
388
+ case 'unlock':
389
+ onUnlock?.(contextMenuNode);
390
+ break;
391
+ }
392
+ }
393
+
394
+ function isExpanded(node: FileNode): boolean {
395
+ return expandedFolders.has(node.path);
396
+ }
397
+
398
+ function sortNodes(nodes: FileNode[]): FileNode[] {
399
+ return [...nodes].sort((a, b) => {
400
+ // Folders first
401
+ if (a.type !== b.type) {
402
+ return a.type === 'folder' ? -1 : 1;
403
+ }
404
+ // Then alphabetically
405
+ return a.name.localeCompare(b.name);
406
+ });
407
+ }
408
+ </script>
409
+
410
+ <div class="file-explorer {className}">
411
+ <div class="file-explorer__header">
412
+ <span class="file-explorer__title">Explorer</span>
413
+ <div class="file-explorer__actions">
414
+ <Button variant="ghost" size="xs" onclick={() => startInlineCreation('', 'file')} title="New File">
415
+ <Icon name="file-plus" size={14} />
416
+ </Button>
417
+ <Button variant="ghost" size="xs" onclick={() => startInlineCreation('', 'folder')} title="New Folder">
418
+ <Icon name="folder-plus" size={14} />
419
+ </Button>
420
+ </div>
421
+ </div>
422
+
423
+ <div class="file-explorer__tree" role="tree">
424
+ <!-- Inline creation at root level -->
425
+ {#if inlineCreation && inlineCreation.parentPath === ''}
426
+ {@render inlineInput(0)}
427
+ {/if}
428
+ {#each sortNodes(files) as node (node.id)}
429
+ {@render fileNode(node, 0)}
430
+ {/each}
431
+ </div>
432
+
433
+ {#if showContextMenu && contextMenuNode}
434
+ <ContextMenu
435
+ items={contextMenuItems}
436
+ x={contextMenuPos.x}
437
+ y={contextMenuPos.y}
438
+ onSelect={handleContextMenuSelect}
439
+ onClose={closeContextMenu}
440
+ />
441
+ {/if}
442
+ </div>
443
+
444
+ {#snippet fileNode(node: FileNode, depth: number)}
445
+ {@const lockStatus = lockStatuses.get(node.path)}
446
+ {@const fileAgents = getAgentsForFile(node.path)}
447
+ {@const isLockedByAnother = lockStatus?.status === 'locked' && !isOwnedByMe(node.path)}
448
+ {@const changeStatus = node.type === 'file' ? getFileStatus(node.path) : getFolderStatus(node)}
449
+ <div
450
+ class="file-node"
451
+ class:file-node--selected={selectedPath === node.path}
452
+ class:file-node--folder={node.type === 'folder'}
453
+ class:file-node--locked={isLockedByAnother}
454
+ class:file-node--status-created={showStatus && changeStatus === 'created'}
455
+ class:file-node--status-modified={showStatus && changeStatus === 'modified'}
456
+ class:file-node--status-deleted={showStatus && changeStatus === 'deleted'}
457
+ class:file-node--status-renamed={showStatus && changeStatus === 'renamed'}
458
+ style="--depth: {depth}"
459
+ role="treeitem"
460
+ aria-selected={selectedPath === node.path}
461
+ aria-expanded={node.type === 'folder' ? isExpanded(node) : undefined}
462
+ tabindex={0}
463
+ onclick={() => handleClick(node)}
464
+ ondblclick={() => handleDoubleClick(node)}
465
+ onkeydown={(e) => handleKeyDown(e, node)}
466
+ oncontextmenu={(e) => handleContextMenu(e, node)}
467
+ >
468
+ <div class="file-node__content">
469
+ <!-- File change status dot indicator -->
470
+ {#if showStatus && changeStatus !== 'clean'}
471
+ <span
472
+ class="file-node__status-dot"
473
+ class:file-node__status-dot--created={changeStatus === 'created'}
474
+ class:file-node__status-dot--modified={changeStatus === 'modified'}
475
+ class:file-node__status-dot--deleted={changeStatus === 'deleted'}
476
+ class:file-node__status-dot--renamed={changeStatus === 'renamed'}
477
+ title={changeStatus === 'created' ? 'New' : changeStatus === 'modified' ? 'Modified' : changeStatus === 'deleted' ? 'Deleted' : 'Renamed'}
478
+ ></span>
479
+ {/if}
480
+ {#if node.type === 'folder'}
481
+ <span class="file-node__chevron" class:file-node__chevron--expanded={isExpanded(node)}>
482
+ <Icon name="chevron-right" size={12} />
483
+ </span>
484
+ <Icon name={isExpanded(node) ? 'folder-open' : 'folder'} size={16} />
485
+ {:else}
486
+ <span class="file-node__spacer"></span>
487
+ <div class="file-node__icon-wrapper">
488
+ <FileIcon filename={node.name} size={16} />
489
+ {#if showLocks && lockStatus && lockStatus.status !== 'unlocked'}
490
+ <div class="file-node__lock-badge">
491
+ <LockIndicator
492
+ status={lockStatus}
493
+ isOwned={isOwnedByMe(node.path)}
494
+ isAI={isLockedByAI(node.path)}
495
+ size="xs"
496
+ />
497
+ </div>
498
+ {/if}
499
+ </div>
500
+ {/if}
501
+ <span class="file-node__name">{node.name}</span>
502
+
503
+ <!-- Agent indicators -->
504
+ {#if showAgents && fileAgents.length > 0}
505
+ <div class="file-node__agents">
506
+ {#each fileAgents.slice(0, 3) as agent (agent.id)}
507
+ <Tooltip content="{agent.name} is editing">
508
+ <AgentAvatar {agent} size="xs" showStatus={false} showBadge={false} showProgress={false} />
509
+ </Tooltip>
510
+ {/each}
511
+ {#if fileAgents.length > 3}
512
+ <Tooltip content="{fileAgents.length - 3} more agents editing">
513
+ <span class="file-node__agent-count">+{fileAgents.length - 3}</span>
514
+ </Tooltip>
515
+ {/if}
516
+ </div>
517
+ {/if}
518
+ </div>
519
+ </div>
520
+
521
+ {#if node.type === 'folder' && isExpanded(node)}
522
+ <div class="file-node__children" role="group">
523
+ <!-- Inline creation inside this folder -->
524
+ {#if inlineCreation && inlineCreation.parentPath === node.path}
525
+ {@render inlineInput(depth + 1)}
526
+ {/if}
527
+ {#if node.children}
528
+ {#each sortNodes(node.children) as child (child.id)}
529
+ {@render fileNode(child, depth + 1)}
530
+ {/each}
531
+ {/if}
532
+ </div>
533
+ {/if}
534
+ {/snippet}
535
+
536
+ {#snippet inlineInput(depth: number)}
537
+ {#if inlineCreation}
538
+ <div class="file-node file-node--inline-create" style="--depth: {depth}">
539
+ <div class="file-node__content">
540
+ <span class="file-node__spacer"></span>
541
+ {#if inlineCreation.type === 'folder'}
542
+ <Icon name="folder" size={16} />
543
+ {:else}
544
+ <Icon name="file" size={16} />
545
+ {/if}
546
+ <input
547
+ bind:this={inlineInputRef}
548
+ type="text"
549
+ class="file-node__inline-input"
550
+ bind:value={inlineCreation.name}
551
+ onkeydown={handleInlineKeydown}
552
+ onblur={confirmInlineCreation}
553
+ placeholder={inlineCreation.type === 'folder' ? 'folder name' : 'file name'}
554
+ />
555
+ </div>
556
+ </div>
557
+ {/if}
558
+ {/snippet}
559
+
560
+ <style>
561
+ .file-explorer {
562
+ display: flex;
563
+ flex-direction: column;
564
+ height: 100%;
565
+ background: var(--ide-bg-secondary);
566
+ overflow: hidden;
567
+ }
568
+
569
+ .file-explorer__header {
570
+ display: flex;
571
+ align-items: center;
572
+ justify-content: space-between;
573
+ padding: var(--ide-spacing-sm) var(--ide-spacing-md);
574
+ border-bottom: 1px solid var(--ide-border);
575
+ }
576
+
577
+ .file-explorer__title {
578
+ font-size: var(--ide-font-size-xs);
579
+ font-weight: 600;
580
+ text-transform: uppercase;
581
+ letter-spacing: 0.05em;
582
+ color: var(--ide-text-secondary);
583
+ }
584
+
585
+ .file-explorer__actions {
586
+ display: flex;
587
+ gap: var(--ide-spacing-xs);
588
+ }
589
+
590
+ .file-explorer__tree {
591
+ flex: 1;
592
+ overflow-y: auto;
593
+ overflow-x: hidden;
594
+ padding: var(--ide-spacing-xs) 0;
595
+ }
596
+
597
+ .file-node {
598
+ display: flex;
599
+ align-items: center;
600
+ cursor: pointer;
601
+ user-select: none;
602
+ }
603
+
604
+ .file-node__content {
605
+ display: flex;
606
+ align-items: center;
607
+ gap: var(--ide-spacing-xs);
608
+ padding: 2px var(--ide-spacing-sm);
609
+ padding-left: calc(var(--ide-spacing-sm) + var(--depth) * 12px);
610
+ width: 100%;
611
+ min-height: 24px;
612
+ transition: background-color 0.1s ease;
613
+ }
614
+
615
+ .file-node:hover .file-node__content {
616
+ background: var(--ide-bg-hover);
617
+ }
618
+
619
+ .file-node--selected .file-node__content {
620
+ background: var(--ide-bg-tertiary);
621
+ }
622
+
623
+ .file-node--selected:hover .file-node__content {
624
+ background: var(--ide-bg-tertiary);
625
+ }
626
+
627
+ .file-node:focus {
628
+ outline: none;
629
+ }
630
+
631
+ .file-node:focus-visible .file-node__content {
632
+ outline: 1px solid var(--ide-interactive);
633
+ outline-offset: -1px;
634
+ }
635
+
636
+ .file-node__chevron {
637
+ display: flex;
638
+ align-items: center;
639
+ justify-content: center;
640
+ width: 12px;
641
+ height: 12px;
642
+ transition: transform 0.15s ease;
643
+ color: var(--ide-text-muted);
644
+ }
645
+
646
+ .file-node__chevron--expanded {
647
+ transform: rotate(90deg);
648
+ }
649
+
650
+ .file-node__spacer {
651
+ width: 12px;
652
+ }
653
+
654
+ .file-node__name {
655
+ flex: 1;
656
+ font-size: var(--ide-font-size-sm);
657
+ color: var(--ide-text-primary);
658
+ white-space: nowrap;
659
+ overflow: hidden;
660
+ text-overflow: ellipsis;
661
+ }
662
+
663
+ .file-node--folder .file-node__name {
664
+ color: var(--ide-text-primary);
665
+ }
666
+
667
+ .file-node__children {
668
+ display: flex;
669
+ flex-direction: column;
670
+ }
671
+
672
+ /* Folder icons */
673
+ .file-node--folder :global(.icon) {
674
+ color: var(--color-nocturnium-aurora-yellow, #f0c674);
675
+ }
676
+
677
+ /* Locked file styling */
678
+ .file-node--locked .file-node__name {
679
+ opacity: 0.6;
680
+ }
681
+
682
+ /* Icon wrapper for positioning lock badge */
683
+ .file-node__icon-wrapper {
684
+ position: relative;
685
+ display: flex;
686
+ align-items: center;
687
+ }
688
+
689
+ .file-node__lock-badge {
690
+ position: absolute;
691
+ bottom: -4px;
692
+ right: -4px;
693
+ background: var(--ide-bg-secondary);
694
+ border-radius: 50%;
695
+ display: flex;
696
+ align-items: center;
697
+ justify-content: center;
698
+ }
699
+
700
+ /* Agent indicators */
701
+ .file-node__agents {
702
+ display: flex;
703
+ align-items: center;
704
+ gap: 2px;
705
+ margin-left: auto;
706
+ padding-left: var(--ide-spacing-xs);
707
+ }
708
+
709
+ .file-node__agent-count {
710
+ font-size: 10px;
711
+ color: var(--ide-text-muted);
712
+ background: var(--ide-bg-tertiary);
713
+ padding: 0 4px;
714
+ border-radius: var(--ide-radius-sm);
715
+ }
716
+
717
+ /* Inline creation input */
718
+ .file-node--inline-create {
719
+ background: var(--ide-bg-tertiary);
720
+ }
721
+
722
+ .file-node__inline-input {
723
+ flex: 1;
724
+ background: var(--ide-bg-primary);
725
+ border: 1px solid var(--ide-interactive);
726
+ border-radius: var(--ide-radius-sm);
727
+ color: var(--ide-text-primary);
728
+ font-size: var(--ide-font-size-sm);
729
+ font-family: inherit;
730
+ padding: 2px 6px;
731
+ outline: none;
732
+ min-width: 0;
733
+ }
734
+
735
+ .file-node__inline-input::placeholder {
736
+ color: var(--ide-text-muted);
737
+ }
738
+
739
+ .file-node__inline-input:focus {
740
+ border-color: var(--ide-interactive);
741
+ box-shadow: 0 0 0 2px rgba(var(--ide-interactive-rgb, 79, 140, 201), 0.2);
742
+ }
743
+
744
+ /* ==================== File Change Status Indicators ==================== */
745
+
746
+ /* Status dot indicator */
747
+ .file-node__status-dot {
748
+ width: 6px;
749
+ height: 6px;
750
+ border-radius: 50%;
751
+ flex-shrink: 0;
752
+ margin-right: 2px;
753
+ }
754
+
755
+ .file-node__status-dot--created {
756
+ background: var(--ide-status-created, #4ade80);
757
+ box-shadow: 0 0 4px var(--ide-status-created, #4ade80);
758
+ }
759
+
760
+ .file-node__status-dot--modified {
761
+ background: var(--ide-status-modified, #facc15);
762
+ box-shadow: 0 0 4px var(--ide-status-modified, #facc15);
763
+ }
764
+
765
+ .file-node__status-dot--deleted {
766
+ background: var(--ide-status-deleted, #ef4444);
767
+ box-shadow: 0 0 4px var(--ide-status-deleted, #ef4444);
768
+ }
769
+
770
+ .file-node__status-dot--renamed {
771
+ background: var(--ide-status-renamed, #a78bfa);
772
+ box-shadow: 0 0 4px var(--ide-status-renamed, #a78bfa);
773
+ }
774
+
775
+ /* Status text colors */
776
+ .file-node--status-created .file-node__name {
777
+ color: var(--ide-status-created, #4ade80);
778
+ }
779
+
780
+ .file-node--status-modified .file-node__name {
781
+ color: var(--ide-status-modified, #facc15);
782
+ }
783
+
784
+ .file-node--status-deleted .file-node__name {
785
+ color: var(--ide-status-deleted, #ef4444);
786
+ text-decoration: line-through;
787
+ opacity: 0.7;
788
+ }
789
+
790
+ .file-node--status-renamed .file-node__name {
791
+ color: var(--ide-status-renamed, #a78bfa);
792
+ font-style: italic;
793
+ }
794
+
795
+ /* Folder icon color when it contains changes */
796
+ .file-node--folder.file-node--status-created :global(.icon) {
797
+ color: var(--ide-status-created, #4ade80);
798
+ }
799
+
800
+ .file-node--folder.file-node--status-modified :global(.icon) {
801
+ color: var(--ide-status-modified, #facc15);
802
+ }
803
+
804
+ .file-node--folder.file-node--status-deleted :global(.icon) {
805
+ color: var(--ide-status-deleted, #ef4444);
806
+ }
807
+
808
+ .file-node--folder.file-node--status-renamed :global(.icon) {
809
+ color: var(--ide-status-renamed, #a78bfa);
810
+ }
811
+ </style>