@nocturnium/svelte-ide 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +43 -47
  2. package/dist/components/agents/AgentActivityPanel.svelte +3 -1
  3. package/dist/components/agents/AgentAvatar.svelte +127 -35
  4. package/dist/components/agents/AgentCursor.svelte +15 -5
  5. package/dist/components/agents/AgentPresenceBar.svelte +7 -2
  6. package/dist/components/ai/AIConversationList.svelte +39 -34
  7. package/dist/components/ai/AIInlineEdit.svelte +1 -3
  8. package/dist/components/ai/AIMessage.svelte +5 -5
  9. package/dist/components/ai/AIMessageActions.svelte +18 -3
  10. package/dist/components/ai/AIMessageContent.svelte +22 -20
  11. package/dist/components/ai/AIPanel.svelte +17 -9
  12. package/dist/components/ai/AISuggestionWidget.svelte +1 -3
  13. package/dist/components/ai/AIToolCallDisplay.svelte +10 -14
  14. package/dist/components/core/Badge.svelte +9 -1
  15. package/dist/components/core/ConnectionStatus.svelte +73 -68
  16. package/dist/components/core/ErrorBoundary.svelte +56 -56
  17. package/dist/components/core/ErrorBoundary.svelte.d.ts +5 -5
  18. package/dist/components/core/Icon.svelte +22 -11
  19. package/dist/components/core/ResizeHandle.svelte +1 -1
  20. package/dist/components/core/Tooltip.svelte +1 -7
  21. package/dist/components/editor/AIFocusLayer.svelte +15 -7
  22. package/dist/components/editor/Breadcrumbs.svelte +18 -6
  23. package/dist/components/editor/BreakpointLayer.svelte +51 -60
  24. package/dist/components/editor/CognitiveLoadMeter.svelte +4 -2
  25. package/dist/components/editor/CollaborativeEditor.svelte +1 -5
  26. package/dist/components/editor/CommandPalette.svelte +1 -4
  27. package/dist/components/editor/ComplexityLayer.svelte +8 -6
  28. package/dist/components/editor/ConflictZoneLayer.svelte +2 -8
  29. package/dist/components/editor/ContextLens.svelte +1 -4
  30. package/dist/components/editor/CustomEditor.svelte +85 -41
  31. package/dist/components/editor/DebugConsole.svelte +8 -17
  32. package/dist/components/editor/EchoCursorLayer.svelte +3 -1
  33. package/dist/components/editor/EditorGutter.svelte +8 -2
  34. package/dist/components/editor/EditorLines.svelte +6 -3
  35. package/dist/components/editor/EditorPane.svelte +1 -6
  36. package/dist/components/editor/EditorSelections.svelte +29 -11
  37. package/dist/components/editor/FileExplorer.svelte +26 -4
  38. package/dist/components/editor/FileIcon.svelte +3 -1
  39. package/dist/components/editor/FindReplace.svelte +16 -4
  40. package/dist/components/editor/GhostBracketLayer.svelte +2 -2
  41. package/dist/components/editor/GitBlameLayer.svelte +2 -1
  42. package/dist/components/editor/InlineDiagnosticsLayer.svelte +4 -13
  43. package/dist/components/editor/InlineDiffLayer.svelte +18 -9
  44. package/dist/components/editor/Minimap.svelte +16 -9
  45. package/dist/components/editor/PluginPreviewSandbox.svelte +3 -2
  46. package/dist/components/editor/ProblemsPanel.svelte +11 -35
  47. package/dist/components/editor/QuickActionsMenu.svelte +5 -14
  48. package/dist/components/editor/SnippetPalette.svelte +11 -12
  49. package/dist/components/editor/StructureMap.svelte +2 -1
  50. package/dist/components/editor/SymbolOutline.svelte +14 -19
  51. package/dist/components/editor/TimelineScrubber.svelte +7 -6
  52. package/dist/components/editor/core/complexity-analyzer.js +42 -12
  53. package/dist/components/editor/core/conflict-predictor.js +2 -4
  54. package/dist/components/editor/core/folding.d.ts +9 -0
  55. package/dist/components/editor/core/folding.js +40 -5
  56. package/dist/components/editor/core/multi-cursor.js +4 -8
  57. package/dist/components/editor/core/navigation.js +2 -6
  58. package/dist/components/editor/core/quick-actions.js +22 -17
  59. package/dist/components/editor/core/search.js +2 -6
  60. package/dist/components/editor/core/semantic-analyzer.js +1 -3
  61. package/dist/components/editor/core/snippet-manager.js +4 -3
  62. package/dist/components/editor/core/state.js +2 -2
  63. package/dist/components/editor/core/timeline.js +1 -3
  64. package/dist/components/editor/editor-input.js +9 -6
  65. package/dist/components/editor/editor-multicursor.js +2 -2
  66. package/dist/components/editor/tokenizer/languages/css.js +146 -24
  67. package/dist/components/editor/tokenizer/languages/go.js +76 -13
  68. package/dist/components/editor/tokenizer/languages/javascript.d.ts +13 -2
  69. package/dist/components/editor/tokenizer/languages/javascript.js +278 -84
  70. package/dist/components/editor/tokenizer/languages/python.js +116 -19
  71. package/dist/components/editor/tokenizer/languages/svelte.js +20 -7
  72. package/dist/components/layout/IDELayout.svelte +6 -2
  73. package/dist/components/layout/StatusBar.svelte +32 -20
  74. package/dist/components/lsp/AutocompleteWidget.svelte +19 -19
  75. package/dist/components/lsp/DiagnosticMarker.svelte +61 -52
  76. package/dist/components/lsp/DiagnosticsPanel.svelte +45 -27
  77. package/dist/components/lsp/HoverTooltip.svelte +56 -61
  78. package/dist/components/lsp/LSPEditor.svelte +7 -18
  79. package/dist/components/lsp/SignatureHelpWidget.svelte +12 -9
  80. package/dist/components/plugins/PluginCard.svelte +3 -13
  81. package/dist/components/plugins/PluginProposalForm.svelte +19 -31
  82. package/dist/components/vfs/LockConflictDialog.svelte +112 -45
  83. package/dist/components/vfs/LockIndicator.svelte +0 -1
  84. package/dist/components/vfs/LockOverlay.svelte +53 -53
  85. package/dist/components/vfs/LockOverlay.svelte.d.ts +5 -5
  86. package/dist/components/vfs/VersionConflictDialog.svelte +107 -77
  87. package/dist/services/error-handling.js +1 -7
  88. package/dist/services/mock-ai.js +9 -7
  89. package/dist/stores/agents.svelte.js +50 -10
  90. package/dist/stores/ai.svelte.js +66 -18
  91. package/dist/stores/collaboration.svelte.js +70 -14
  92. package/dist/stores/editor.svelte.js +50 -10
  93. package/dist/stores/plugin.svelte.js +60 -12
  94. package/dist/stores/vfs.svelte.js +77 -19
  95. package/dist/styles/theme.css +16 -7
  96. package/package.json +186 -1
@@ -1,67 +1,67 @@
1
1
  <script lang="ts">
2
- /**
3
- * VersionConflictDialog Component
4
- *
5
- * Displays when a file version conflict is detected, allowing the user
6
- * to choose how to resolve the conflict (merge, overwrite, or discard).
7
- */
8
-
9
- interface ConflictDetails {
10
- path: string;
11
- localVersion: number;
12
- serverVersion: number;
13
- localContent: string;
14
- serverContent: string;
15
- baseContent?: string;
16
- lastModifiedBy?: string;
17
- lastModifiedAt?: string;
18
- }
19
-
20
- interface Props {
21
- conflict: ConflictDetails;
22
- onResolve: (resolution: 'merge' | 'overwrite' | 'discard', mergedContent?: string) => void;
23
- onCancel: () => void;
24
- }
25
-
26
- let { conflict, onResolve, onCancel }: Props = $props();
27
-
28
- // View state
29
- let activeView = $state<'side-by-side' | 'unified' | 'local' | 'server'>('side-by-side');
30
- // Editable merge buffer is intentionally seeded once from the prop: the dialog is
31
- // mounted per-conflict, so resetting the user's edits if `conflict` changed would be wrong.
32
- // svelte-ignore state_referenced_locally
33
- let mergedContent = $state(conflict.localContent);
34
- let showMergeEditor = $state(false);
35
-
36
- // Computed
37
- let fileName = $derived(conflict.path.split('/').pop() ?? conflict.path);
38
- let hasChanges = $derived(mergedContent !== conflict.localContent);
39
-
40
- // Line diff (simplified)
41
- let localLines = $derived(conflict.localContent.split('\n'));
42
- let serverLines = $derived(conflict.serverContent.split('\n'));
43
-
44
- function handleOverwrite() {
45
- onResolve('overwrite', conflict.localContent);
46
- }
47
-
48
- function handleDiscard() {
49
- onResolve('discard');
50
- }
51
-
52
- function handleMerge() {
53
- if (showMergeEditor) {
54
- onResolve('merge', mergedContent);
55
- } else {
56
- showMergeEditor = true;
57
- }
58
- }
59
-
60
- function handleKeydown(event: KeyboardEvent) {
61
- if (event.key === 'Escape') {
62
- onCancel();
63
- }
64
- }
2
+ /**
3
+ * VersionConflictDialog Component
4
+ *
5
+ * Displays when a file version conflict is detected, allowing the user
6
+ * to choose how to resolve the conflict (merge, overwrite, or discard).
7
+ */
8
+
9
+ interface ConflictDetails {
10
+ path: string;
11
+ localVersion: number;
12
+ serverVersion: number;
13
+ localContent: string;
14
+ serverContent: string;
15
+ baseContent?: string;
16
+ lastModifiedBy?: string;
17
+ lastModifiedAt?: string;
18
+ }
19
+
20
+ interface Props {
21
+ conflict: ConflictDetails;
22
+ onResolve: (resolution: 'merge' | 'overwrite' | 'discard', mergedContent?: string) => void;
23
+ onCancel: () => void;
24
+ }
25
+
26
+ let { conflict, onResolve, onCancel }: Props = $props();
27
+
28
+ // View state
29
+ let activeView = $state<'side-by-side' | 'unified' | 'local' | 'server'>('side-by-side');
30
+ // Editable merge buffer is intentionally seeded once from the prop: the dialog is
31
+ // mounted per-conflict, so resetting the user's edits if `conflict` changed would be wrong.
32
+ // svelte-ignore state_referenced_locally
33
+ let mergedContent = $state(conflict.localContent);
34
+ let showMergeEditor = $state(false);
35
+
36
+ // Computed
37
+ let fileName = $derived(conflict.path.split('/').pop() ?? conflict.path);
38
+ let hasChanges = $derived(mergedContent !== conflict.localContent);
39
+
40
+ // Line diff (simplified)
41
+ let localLines = $derived(conflict.localContent.split('\n'));
42
+ let serverLines = $derived(conflict.serverContent.split('\n'));
43
+
44
+ function handleOverwrite() {
45
+ onResolve('overwrite', conflict.localContent);
46
+ }
47
+
48
+ function handleDiscard() {
49
+ onResolve('discard');
50
+ }
51
+
52
+ function handleMerge() {
53
+ if (showMergeEditor) {
54
+ onResolve('merge', mergedContent);
55
+ } else {
56
+ showMergeEditor = true;
57
+ }
58
+ }
59
+
60
+ function handleKeydown(event: KeyboardEvent) {
61
+ if (event.key === 'Escape') {
62
+ onCancel();
63
+ }
64
+ }
65
65
  </script>
66
66
 
67
67
  <svelte:window onkeydown={handleKeydown} />
@@ -82,14 +82,24 @@ function handleKeydown(event: KeyboardEvent) {
82
82
  stroke-linecap="round"
83
83
  stroke-linejoin="round"
84
84
  >
85
- <path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
85
+ <path
86
+ d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"
87
+ />
86
88
  <line x1="12" y1="9" x2="12" y2="13" />
87
89
  <line x1="12" y1="17" x2="12.01" y2="17" />
88
90
  </svg>
89
91
  <h2 id="conflict-title">Version Conflict</h2>
90
92
  </div>
91
93
  <button class="close-btn" onclick={onCancel} aria-label="Close">
92
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
94
+ <svg
95
+ xmlns="http://www.w3.org/2000/svg"
96
+ width="20"
97
+ height="20"
98
+ viewBox="0 0 24 24"
99
+ fill="none"
100
+ stroke="currentColor"
101
+ stroke-width="2"
102
+ >
93
103
  <path d="M18 6 6 18M6 6l12 12" />
94
104
  </svg>
95
105
  </button>
@@ -196,30 +206,42 @@ function handleKeydown(event: KeyboardEvent) {
196
206
  <span class="modified-indicator">Modified</span>
197
207
  {/if}
198
208
  </div>
199
- <textarea
200
- class="merge-textarea"
201
- bind:value={mergedContent}
202
- spellcheck="false"
203
- ></textarea>
209
+ <textarea class="merge-textarea" bind:value={mergedContent} spellcheck="false"></textarea>
204
210
  </div>
205
211
  {/if}
206
212
  </div>
207
213
 
208
214
  <footer class="conflict-footer">
209
215
  <div class="action-group secondary">
210
- <button class="action-btn cancel" onclick={onCancel}>
211
- Cancel
212
- </button>
216
+ <button class="action-btn cancel" onclick={onCancel}> Cancel </button>
213
217
  </div>
214
218
  <div class="action-group primary">
215
219
  <button class="action-btn discard" onclick={handleDiscard}>
216
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
217
- <path d="M3 6h18M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
220
+ <svg
221
+ xmlns="http://www.w3.org/2000/svg"
222
+ width="16"
223
+ height="16"
224
+ viewBox="0 0 24 24"
225
+ fill="none"
226
+ stroke="currentColor"
227
+ stroke-width="2"
228
+ >
229
+ <path
230
+ d="M3 6h18M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
231
+ />
218
232
  </svg>
219
233
  Use Server Version
220
234
  </button>
221
235
  <button class="action-btn merge" onclick={handleMerge}>
222
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
236
+ <svg
237
+ xmlns="http://www.w3.org/2000/svg"
238
+ width="16"
239
+ height="16"
240
+ viewBox="0 0 24 24"
241
+ fill="none"
242
+ stroke="currentColor"
243
+ stroke-width="2"
244
+ >
223
245
  <circle cx="18" cy="18" r="3" />
224
246
  <circle cx="6" cy="6" r="3" />
225
247
  <path d="M6 21V9a9 9 0 0 0 9 9" />
@@ -227,7 +249,15 @@ function handleKeydown(event: KeyboardEvent) {
227
249
  {showMergeEditor ? 'Save Merge' : 'Merge Changes'}
228
250
  </button>
229
251
  <button class="action-btn overwrite" onclick={handleOverwrite}>
230
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
252
+ <svg
253
+ xmlns="http://www.w3.org/2000/svg"
254
+ width="16"
255
+ height="16"
256
+ viewBox="0 0 24 24"
257
+ fill="none"
258
+ stroke="currentColor"
259
+ stroke-width="2"
260
+ >
231
261
  <path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" />
232
262
  </svg>
233
263
  Overwrite with Mine
@@ -103,13 +103,7 @@ export function isVFSError(error) {
103
103
  * Check if error code is retryable
104
104
  */
105
105
  function isRetryableError(code) {
106
- return [
107
- 'NETWORK_ERROR',
108
- 'CONNECTION_LOST',
109
- 'TIMEOUT',
110
- 'SERVER_ERROR',
111
- 'RATE_LIMITED'
112
- ].includes(code);
106
+ return ['NETWORK_ERROR', 'CONNECTION_LOST', 'TIMEOUT', 'SERVER_ERROR', 'RATE_LIMITED'].includes(code);
113
107
  }
114
108
  /**
115
109
  * Check if error is a conflict that needs user resolution
@@ -280,12 +280,14 @@ export function createMockMessage(role, content, options = {}) {
280
280
  content,
281
281
  timestamp: new Date(),
282
282
  ...options,
283
- metadata: role === 'assistant' ? {
284
- model: 'claude-3-5-sonnet-mock',
285
- tokensUsed: Math.floor(content.length / 4),
286
- latencyMs: Math.floor(500 + Math.random() * 1500),
287
- ...options.metadata
288
- } : options.metadata
283
+ metadata: role === 'assistant'
284
+ ? {
285
+ model: 'claude-3-5-sonnet-mock',
286
+ tokensUsed: Math.floor(content.length / 4),
287
+ latencyMs: Math.floor(500 + Math.random() * 1500),
288
+ ...options.metadata
289
+ }
290
+ : options.metadata
289
291
  };
290
292
  }
291
293
  /**
@@ -314,5 +316,5 @@ export function generateMockConversation(turns = 3) {
314
316
  }
315
317
  // Helper
316
318
  function sleep(ms) {
317
- return new Promise(resolve => setTimeout(resolve, ms));
319
+ return new Promise((resolve) => setTimeout(resolve, ms));
318
320
  }
@@ -105,16 +105,56 @@ export function getOnlineCount() {
105
105
  return getOnlineAgents().length;
106
106
  }
107
107
  // Legacy aliases for backward compatibility
108
- export const agents = { get current() { return getAgents(); } };
109
- export const onlineAgents = { get current() { return getOnlineAgents(); } };
110
- export const busyAgents = { get current() { return getBusyAgents(); } };
111
- export const events = { get current() { return getEvents(); } };
112
- export const activities = { get current() { return getActivities(); } };
113
- export const cursors = { get current() { return getCursors(); } };
114
- export const selectedAgent = { get current() { return getSelectedAgent(); } };
115
- export const filter = { get current() { return getFilter(); } };
116
- export const connected = { get current() { return getConnected(); } };
117
- export const error = { get current() { return getError(); } };
108
+ export const agents = {
109
+ get current() {
110
+ return getAgents();
111
+ }
112
+ };
113
+ export const onlineAgents = {
114
+ get current() {
115
+ return getOnlineAgents();
116
+ }
117
+ };
118
+ export const busyAgents = {
119
+ get current() {
120
+ return getBusyAgents();
121
+ }
122
+ };
123
+ export const events = {
124
+ get current() {
125
+ return getEvents();
126
+ }
127
+ };
128
+ export const activities = {
129
+ get current() {
130
+ return getActivities();
131
+ }
132
+ };
133
+ export const cursors = {
134
+ get current() {
135
+ return getCursors();
136
+ }
137
+ };
138
+ export const selectedAgent = {
139
+ get current() {
140
+ return getSelectedAgent();
141
+ }
142
+ };
143
+ export const filter = {
144
+ get current() {
145
+ return getFilter();
146
+ }
147
+ };
148
+ export const connected = {
149
+ get current() {
150
+ return getConnected();
151
+ }
152
+ };
153
+ export const error = {
154
+ get current() {
155
+ return getError();
156
+ }
157
+ };
118
158
  // ============================================================================
119
159
  // Agent Operations
120
160
  // ============================================================================
@@ -66,18 +66,66 @@ export function getError() {
66
66
  return state.error;
67
67
  }
68
68
  // Legacy aliases for backward compatibility
69
- export const conversations = { get current() { return getConversations(); } };
70
- export const activeConversationId = { get current() { return getActiveConversationId(); } };
71
- export const activeConversation = { get current() { return getActiveConversation(); } };
72
- export const messages = { get current() { return getMessages(); } };
73
- export const tools = { get current() { return getTools(); } };
74
- export const config = { get current() { return getConfig(); } };
75
- export const editSessions = { get current() { return getEditSessions(); } };
76
- export const activeEditSessions = { get current() { return getActiveEditSessions(); } };
77
- export const suggestions = { get current() { return getSuggestions(); } };
78
- export const isStreaming = { get current() { return getIsStreaming(); } };
79
- export const isPanelOpen = { get current() { return getIsPanelOpen(); } };
80
- export const error = { get current() { return getError(); } };
69
+ export const conversations = {
70
+ get current() {
71
+ return getConversations();
72
+ }
73
+ };
74
+ export const activeConversationId = {
75
+ get current() {
76
+ return getActiveConversationId();
77
+ }
78
+ };
79
+ export const activeConversation = {
80
+ get current() {
81
+ return getActiveConversation();
82
+ }
83
+ };
84
+ export const messages = {
85
+ get current() {
86
+ return getMessages();
87
+ }
88
+ };
89
+ export const tools = {
90
+ get current() {
91
+ return getTools();
92
+ }
93
+ };
94
+ export const config = {
95
+ get current() {
96
+ return getConfig();
97
+ }
98
+ };
99
+ export const editSessions = {
100
+ get current() {
101
+ return getEditSessions();
102
+ }
103
+ };
104
+ export const activeEditSessions = {
105
+ get current() {
106
+ return getActiveEditSessions();
107
+ }
108
+ };
109
+ export const suggestions = {
110
+ get current() {
111
+ return getSuggestions();
112
+ }
113
+ };
114
+ export const isStreaming = {
115
+ get current() {
116
+ return getIsStreaming();
117
+ }
118
+ };
119
+ export const isPanelOpen = {
120
+ get current() {
121
+ return getIsPanelOpen();
122
+ }
123
+ };
124
+ export const error = {
125
+ get current() {
126
+ return getError();
127
+ }
128
+ };
81
129
  /**
82
130
  * Create a new conversation
83
131
  */
@@ -129,8 +177,8 @@ export function addMessage(message) {
129
177
  timestamp: new Date()
130
178
  };
131
179
  state.conversations = state.conversations.map((c) => c.id === state.activeConversationId
132
- // eslint-disable-next-line svelte/prefer-svelte-reactivity -- timestamp snapshot on plain AIConversation object; type expects Date, not SvelteDate
133
- ? { ...c, messages: [...c.messages, newMessage], updatedAt: new Date() }
180
+ ? // eslint-disable-next-line svelte/prefer-svelte-reactivity -- timestamp snapshot on plain AIConversation object; type expects Date, not SvelteDate
181
+ { ...c, messages: [...c.messages, newMessage], updatedAt: new Date() }
134
182
  : c);
135
183
  return id;
136
184
  }
@@ -342,8 +390,8 @@ export function updateEditSession(sessionId, updates) {
342
390
  */
343
391
  export function completeEditSession(sessionId, proposedContent, diff) {
344
392
  state.editSessions = state.editSessions.map((s) => s.id === sessionId
345
- // eslint-disable-next-line svelte/prefer-svelte-reactivity -- timestamp snapshot on plain AIEditSession object; type expects Date, not SvelteDate
346
- ? { ...s, status: 'reviewing', proposedContent, diff, completedAt: new Date() }
393
+ ? // eslint-disable-next-line svelte/prefer-svelte-reactivity -- timestamp snapshot on plain AIEditSession object; type expects Date, not SvelteDate
394
+ { ...s, status: 'reviewing', proposedContent, diff, completedAt: new Date() }
347
395
  : s);
348
396
  }
349
397
  /**
@@ -379,8 +427,8 @@ export function updateContext(context) {
379
427
  if (!state.activeConversationId)
380
428
  return;
381
429
  state.conversations = state.conversations.map((c) => c.id === state.activeConversationId
382
- // eslint-disable-next-line svelte/prefer-svelte-reactivity -- timestamp snapshot on plain AIConversation object; type expects Date, not SvelteDate
383
- ? { ...c, context: { ...c.context, ...context }, updatedAt: new Date() }
430
+ ? // eslint-disable-next-line svelte/prefer-svelte-reactivity -- timestamp snapshot on plain AIConversation object; type expects Date, not SvelteDate
431
+ { ...c, context: { ...c.context, ...context }, updatedAt: new Date() }
384
432
  : c);
385
433
  }
386
434
  /**
@@ -66,20 +66,76 @@ export function getOtherUsers() {
66
66
  return state.users.filter((u) => u.id !== state.localUser?.id);
67
67
  }
68
68
  // Legacy aliases for backward compatibility
69
- export const config = { get current() { return getConfig(); } };
70
- export const status = { get current() { return getStatus(); } };
71
- export const error = { get current() { return getError(); } };
72
- export const synced = { get current() { return getSynced(); } };
73
- export const users = { get current() { return getUsers(); } };
74
- export const cursors = { get current() { return getCursors(); } };
75
- export const awareness = { get current() { return getAwareness(); } };
76
- export const aiSessions = { get current() { return getAISessions(); } };
77
- export const activeAISessions = { get current() { return getActiveAISessions(); } };
78
- export const pendingChanges = { get current() { return getPendingChanges(); } };
79
- export const snapshots = { get current() { return getSnapshots(); } };
80
- export const localUser = { get current() { return getLocalUser(); } };
81
- export const isConnected = { get current() { return getIsConnected(); } };
82
- export const otherUsers = { get current() { return getOtherUsers(); } };
69
+ export const config = {
70
+ get current() {
71
+ return getConfig();
72
+ }
73
+ };
74
+ export const status = {
75
+ get current() {
76
+ return getStatus();
77
+ }
78
+ };
79
+ export const error = {
80
+ get current() {
81
+ return getError();
82
+ }
83
+ };
84
+ export const synced = {
85
+ get current() {
86
+ return getSynced();
87
+ }
88
+ };
89
+ export const users = {
90
+ get current() {
91
+ return getUsers();
92
+ }
93
+ };
94
+ export const cursors = {
95
+ get current() {
96
+ return getCursors();
97
+ }
98
+ };
99
+ export const awareness = {
100
+ get current() {
101
+ return getAwareness();
102
+ }
103
+ };
104
+ export const aiSessions = {
105
+ get current() {
106
+ return getAISessions();
107
+ }
108
+ };
109
+ export const activeAISessions = {
110
+ get current() {
111
+ return getActiveAISessions();
112
+ }
113
+ };
114
+ export const pendingChanges = {
115
+ get current() {
116
+ return getPendingChanges();
117
+ }
118
+ };
119
+ export const snapshots = {
120
+ get current() {
121
+ return getSnapshots();
122
+ }
123
+ };
124
+ export const localUser = {
125
+ get current() {
126
+ return getLocalUser();
127
+ }
128
+ };
129
+ export const isConnected = {
130
+ get current() {
131
+ return getIsConnected();
132
+ }
133
+ };
134
+ export const otherUsers = {
135
+ get current() {
136
+ return getOtherUsers();
137
+ }
138
+ };
83
139
  // Collaboration colors for cursors
84
140
  const CURSOR_COLORS = [
85
141
  'var(--ide-collab-cursor-1)',
@@ -49,16 +49,56 @@ export function getHasDirtyTabs() {
49
49
  return state.tabs.some((t) => t.isDirty);
50
50
  }
51
51
  // Legacy aliases for backward compatibility
52
- export const tabs = { get current() { return getTabs(); } };
53
- export const activeTabId = { get current() { return getActiveTabId(); } };
54
- export const activeTab = { get current() { return getActiveTab(); } };
55
- export const splitMode = { get current() { return getSplitMode(); } };
56
- export const preferences = { get current() { return getPreferences(); } };
57
- export const recentFiles = { get current() { return getRecentFiles(); } };
58
- export const loading = { get current() { return getLoading(); } };
59
- export const error = { get current() { return getError(); } };
60
- export const dirtyTabs = { get current() { return getDirtyTabs(); } };
61
- export const hasDirtyTabs = { get current() { return getHasDirtyTabs(); } };
52
+ export const tabs = {
53
+ get current() {
54
+ return getTabs();
55
+ }
56
+ };
57
+ export const activeTabId = {
58
+ get current() {
59
+ return getActiveTabId();
60
+ }
61
+ };
62
+ export const activeTab = {
63
+ get current() {
64
+ return getActiveTab();
65
+ }
66
+ };
67
+ export const splitMode = {
68
+ get current() {
69
+ return getSplitMode();
70
+ }
71
+ };
72
+ export const preferences = {
73
+ get current() {
74
+ return getPreferences();
75
+ }
76
+ };
77
+ export const recentFiles = {
78
+ get current() {
79
+ return getRecentFiles();
80
+ }
81
+ };
82
+ export const loading = {
83
+ get current() {
84
+ return getLoading();
85
+ }
86
+ };
87
+ export const error = {
88
+ get current() {
89
+ return getError();
90
+ }
91
+ };
92
+ export const dirtyTabs = {
93
+ get current() {
94
+ return getDirtyTabs();
95
+ }
96
+ };
97
+ export const hasDirtyTabs = {
98
+ get current() {
99
+ return getHasDirtyTabs();
100
+ }
101
+ };
62
102
  /**
63
103
  * Open a file in a new tab or focus existing tab
64
104
  */