@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
@@ -69,7 +69,12 @@
69
69
  }
70
70
  </script>
71
71
 
72
- <div class="plugin-form-overlay" onclick={onClose} onkeydown={(e) => e.key === 'Escape' && onClose()} role="presentation">
72
+ <div
73
+ class="plugin-form-overlay"
74
+ onclick={onClose}
75
+ onkeydown={(e) => e.key === 'Escape' && onClose()}
76
+ role="presentation"
77
+ >
73
78
  <div
74
79
  class="plugin-form"
75
80
  onclick={(e) => e.stopPropagation()}
@@ -85,7 +90,13 @@
85
90
  </Button>
86
91
  </div>
87
92
 
88
- <form class="plugin-form__content" onsubmit={(e) => { e.preventDefault(); handleSubmit(); }}>
93
+ <form
94
+ class="plugin-form__content"
95
+ onsubmit={(e) => {
96
+ e.preventDefault();
97
+ handleSubmit();
98
+ }}
99
+ >
89
100
  {#if error}
90
101
  <div class="plugin-form__error">
91
102
  <Icon name="error" size={14} />
@@ -95,12 +106,7 @@
95
106
 
96
107
  <div class="plugin-form__field">
97
108
  <label for="name">Name *</label>
98
- <Input
99
- id="name"
100
- bind:value={name}
101
- placeholder="my-awesome-plugin"
102
- fullWidth
103
- />
109
+ <Input id="name" bind:value={name} placeholder="my-awesome-plugin" fullWidth />
104
110
  </div>
105
111
 
106
112
  <div class="plugin-form__field">
@@ -116,11 +122,7 @@
116
122
 
117
123
  <div class="plugin-form__field">
118
124
  <label for="category">Category</label>
119
- <select
120
- id="category"
121
- class="plugin-form__select"
122
- bind:value={category}
123
- >
125
+ <select id="category" class="plugin-form__select" bind:value={category}>
124
126
  {#each categories as cat (cat.value)}
125
127
  <option value={cat.value}>{cat.label}</option>
126
128
  {/each}
@@ -129,31 +131,17 @@
129
131
 
130
132
  <div class="plugin-form__field">
131
133
  <label for="tags">Tags</label>
132
- <Input
133
- id="tags"
134
- bind:value={tags}
135
- placeholder="comma, separated, tags"
136
- fullWidth
137
- />
134
+ <Input id="tags" bind:value={tags} placeholder="comma, separated, tags" fullWidth />
138
135
  </div>
139
136
 
140
137
  <div class="plugin-form__field">
141
138
  <label for="author">Author *</label>
142
- <Input
143
- id="author"
144
- bind:value={author}
145
- placeholder="your@email.com"
146
- fullWidth
147
- />
139
+ <Input id="author" bind:value={author} placeholder="your@email.com" fullWidth />
148
140
  </div>
149
141
 
150
142
  <div class="plugin-form__actions">
151
- <Button variant="ghost" onclick={onClose} disabled={isSubmitting}>
152
- Cancel
153
- </Button>
154
- <Button variant="primary" type="submit" loading={isSubmitting}>
155
- Create Proposal
156
- </Button>
143
+ <Button variant="ghost" onclick={onClose} disabled={isSubmitting}>Cancel</Button>
144
+ <Button variant="primary" type="submit" loading={isSubmitting}>Create Proposal</Button>
157
145
  </div>
158
146
  </form>
159
147
  </div>
@@ -111,7 +111,14 @@
111
111
  <!-- Header -->
112
112
  <header class="lock-dialog__header">
113
113
  <div class="lock-dialog__icon">
114
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
114
+ <svg
115
+ viewBox="0 0 24 24"
116
+ fill="none"
117
+ stroke="currentColor"
118
+ stroke-width="2"
119
+ stroke-linecap="round"
120
+ stroke-linejoin="round"
121
+ >
115
122
  <rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
116
123
  <path d="M7 11V7a5 5 0 0 1 10 0v4" />
117
124
  </svg>
@@ -120,11 +127,7 @@
120
127
  <h2 id="lock-dialog-title">File is Locked</h2>
121
128
  <p class="lock-dialog__filename">{fileName}</p>
122
129
  </div>
123
- <button
124
- class="lock-dialog__close"
125
- onclick={onClose}
126
- aria-label="Close dialog"
127
- >
130
+ <button class="lock-dialog__close" onclick={onClose} aria-label="Close dialog">
128
131
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
129
132
  <path d="M18 6 6 18M6 6l12 12" />
130
133
  </svg>
@@ -158,7 +161,14 @@
158
161
  {/if}
159
162
  </div>
160
163
  <div class="lock-holder__timer">
161
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
164
+ <svg
165
+ viewBox="0 0 24 24"
166
+ fill="none"
167
+ stroke="currentColor"
168
+ stroke-width="2"
169
+ width="14"
170
+ height="14"
171
+ >
162
172
  <circle cx="12" cy="12" r="10" />
163
173
  <polyline points="12 6 12 12 16 14" />
164
174
  </svg>
@@ -170,7 +180,14 @@
170
180
  <!-- Error message -->
171
181
  {#if errorMessage}
172
182
  <div class="lock-dialog__error" role="alert">
173
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
183
+ <svg
184
+ viewBox="0 0 24 24"
185
+ fill="none"
186
+ stroke="currentColor"
187
+ stroke-width="2"
188
+ width="16"
189
+ height="16"
190
+ >
174
191
  <circle cx="12" cy="12" r="10" />
175
192
  <line x1="12" y1="8" x2="12" y2="12" />
176
193
  <line x1="12" y1="16" x2="12.01" y2="16" />
@@ -183,7 +200,14 @@
183
200
  <div class="lock-dialog__reassurance">
184
201
  {#if pendingChanges > 0}
185
202
  <div class="reassurance-item reassurance-item--saved">
186
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
203
+ <svg
204
+ viewBox="0 0 24 24"
205
+ fill="none"
206
+ stroke="currentColor"
207
+ stroke-width="2"
208
+ width="14"
209
+ height="14"
210
+ >
187
211
  <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
188
212
  <polyline points="22 4 12 14.01 9 11.01" />
189
213
  </svg>
@@ -192,7 +216,14 @@
192
216
  {/if}
193
217
  {#if lastSyncDisplay}
194
218
  <div class="reassurance-item">
195
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
219
+ <svg
220
+ viewBox="0 0 24 24"
221
+ fill="none"
222
+ stroke="currentColor"
223
+ stroke-width="2"
224
+ width="14"
225
+ height="14"
226
+ >
196
227
  <polyline points="23 4 23 10 17 10" />
197
228
  <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10" />
198
229
  </svg>
@@ -207,11 +238,15 @@
207
238
  <!-- Safe options row -->
208
239
  <div class="action-row action-row--safe">
209
240
  {#if onOpenReadOnly}
210
- <button
211
- class="action-btn action-btn--safe"
212
- onclick={onOpenReadOnly}
213
- >
214
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
241
+ <button class="action-btn action-btn--safe" onclick={onOpenReadOnly}>
242
+ <svg
243
+ viewBox="0 0 24 24"
244
+ fill="none"
245
+ stroke="currentColor"
246
+ stroke-width="2"
247
+ width="18"
248
+ height="18"
249
+ >
215
250
  <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
216
251
  <circle cx="12" cy="12" r="3" />
217
252
  </svg>
@@ -219,11 +254,15 @@
219
254
  </button>
220
255
  {/if}
221
256
  {#if onWait}
222
- <button
223
- class="action-btn action-btn--safe"
224
- onclick={onWait}
225
- >
226
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
257
+ <button class="action-btn action-btn--safe" onclick={onWait}>
258
+ <svg
259
+ viewBox="0 0 24 24"
260
+ fill="none"
261
+ stroke="currentColor"
262
+ stroke-width="2"
263
+ width="18"
264
+ height="18"
265
+ >
227
266
  <circle cx="12" cy="12" r="10" />
228
267
  <polyline points="12 6 12 12 16 14" />
229
268
  </svg>
@@ -234,11 +273,15 @@
234
273
 
235
274
  <!-- Primary action -->
236
275
  {#if onRequestAccess}
237
- <button
238
- class="action-btn action-btn--primary"
239
- onclick={onRequestAccess}
240
- >
241
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
276
+ <button class="action-btn action-btn--primary" onclick={onRequestAccess}>
277
+ <svg
278
+ viewBox="0 0 24 24"
279
+ fill="none"
280
+ stroke="currentColor"
281
+ stroke-width="2"
282
+ width="18"
283
+ height="18"
284
+ >
242
285
  <line x1="22" y1="2" x2="11" y2="13" />
243
286
  <polygon points="22 2 15 22 11 13 2 9 22 2" />
244
287
  </svg>
@@ -250,27 +293,30 @@
250
293
  <!-- Dangerous action (gated) -->
251
294
  {#if canForceUnlock && onForceUnlock}
252
295
  {#if !showForceSection}
253
- <button
254
- class="action-toggle"
255
- onclick={() => showForceSection = true}
256
- >
296
+ <button class="action-toggle" onclick={() => (showForceSection = true)}>
257
297
  More options...
258
298
  </button>
259
299
  {:else}
260
300
  <div class="force-section">
261
301
  <div class="force-warning">
262
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
263
- <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" />
302
+ <svg
303
+ viewBox="0 0 24 24"
304
+ fill="none"
305
+ stroke="currentColor"
306
+ stroke-width="2"
307
+ width="16"
308
+ height="16"
309
+ >
310
+ <path
311
+ 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"
312
+ />
264
313
  <line x1="12" y1="9" x2="12" y2="13" />
265
314
  <line x1="12" y1="17" x2="12.01" y2="17" />
266
315
  </svg>
267
316
  <span>Force unlock may cause data loss for the current editor</span>
268
317
  </div>
269
318
  <label class="force-confirm">
270
- <input
271
- type="checkbox"
272
- bind:checked={forceUnlockConfirmed}
273
- />
319
+ <input type="checkbox" bind:checked={forceUnlockConfirmed} />
274
320
  <span>I understand the risks</span>
275
321
  </label>
276
322
  <button
@@ -278,7 +324,14 @@
278
324
  onclick={handleForceUnlock}
279
325
  disabled={!forceUnlockConfirmed}
280
326
  >
281
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
327
+ <svg
328
+ viewBox="0 0 24 24"
329
+ fill="none"
330
+ stroke="currentColor"
331
+ stroke-width="2"
332
+ width="18"
333
+ height="18"
334
+ >
282
335
  <rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
283
336
  <path d="M7 11V7a5 5 0 0 1 9.9-1" />
284
337
  </svg>
@@ -291,9 +344,7 @@
291
344
 
292
345
  <!-- Footer -->
293
346
  <footer class="lock-dialog__footer">
294
- <button class="cancel-btn" onclick={onClose}>
295
- Cancel
296
- </button>
347
+ <button class="cancel-btn" onclick={onClose}> Cancel </button>
297
348
  </footer>
298
349
  </div>
299
350
  </div>
@@ -314,8 +365,12 @@
314
365
  }
315
366
 
316
367
  @keyframes fade-in {
317
- from { opacity: 0; }
318
- to { opacity: 1; }
368
+ from {
369
+ opacity: 0;
370
+ }
371
+ to {
372
+ opacity: 1;
373
+ }
319
374
  }
320
375
 
321
376
  .lock-dialog {
@@ -324,14 +379,22 @@
324
379
  background: var(--ide-bg-secondary);
325
380
  border: 1px solid var(--ide-border);
326
381
  border-radius: var(--ide-radius-xl);
327
- box-shadow: var(--ide-shadow-xl), 0 0 60px rgba(0, 0, 0, 0.3);
382
+ box-shadow:
383
+ var(--ide-shadow-xl),
384
+ 0 0 60px rgba(0, 0, 0, 0.3);
328
385
  animation: slide-up 0.2s ease-out;
329
386
  overflow: hidden;
330
387
  }
331
388
 
332
389
  @keyframes slide-up {
333
- from { opacity: 0; transform: translateY(20px) scale(0.98); }
334
- to { opacity: 1; transform: translateY(0) scale(1); }
390
+ from {
391
+ opacity: 0;
392
+ transform: translateY(20px) scale(0.98);
393
+ }
394
+ to {
395
+ opacity: 1;
396
+ transform: translateY(0) scale(1);
397
+ }
335
398
  }
336
399
 
337
400
  /* Header */
@@ -558,7 +621,11 @@
558
621
  .action-btn--primary {
559
622
  flex-direction: column;
560
623
  gap: 4px;
561
- background: linear-gradient(135deg, var(--ide-interactive) 0%, var(--ide-interactive-active) 100%);
624
+ background: linear-gradient(
625
+ 135deg,
626
+ var(--ide-interactive) 0%,
627
+ var(--ide-interactive-active) 100%
628
+ );
562
629
  color: white;
563
630
  padding: 14px 16px;
564
631
  }
@@ -81,7 +81,6 @@
81
81
  if (minutes > 0) return `${minutes}:${seconds.toString().padStart(2, '0')}`;
82
82
  return `${seconds}s`;
83
83
  }
84
-
85
84
  </script>
86
85
 
87
86
  {#if status.status !== 'unlocked'}
@@ -1,58 +1,58 @@
1
1
  <script lang="ts">
2
- /**
3
- * LockOverlay Component
4
- *
5
- * Displays a read-only overlay when a file is locked by another user/agent.
6
- * Shows lock holder info, time remaining, and options to request access.
7
- */
8
-
9
- import type { VFSFileLock } from '../../types';
10
-
11
- interface Props {
12
- lock: VFSFileLock;
13
- onRequestAccess?: () => void;
14
- onOpenReadOnly?: () => void;
15
- onClose?: () => void;
16
- showActions?: boolean;
17
- }
18
-
19
- let { lock, onRequestAccess, onOpenReadOnly, onClose, showActions = true }: Props = $props();
20
-
21
- // Calculate time remaining
22
- let timeRemaining = $derived.by(() => {
23
- const expires = new Date(lock.expiresAt).getTime();
24
- const now = Date.now();
25
- const remaining = Math.max(0, expires - now);
26
-
27
- if (remaining === 0) return 'Expired';
28
-
29
- const minutes = Math.floor(remaining / 60000);
30
- const seconds = Math.floor((remaining % 60000) / 1000);
31
-
32
- if (minutes > 0) {
33
- return `${minutes}m ${seconds}s remaining`;
2
+ /**
3
+ * LockOverlay Component
4
+ *
5
+ * Displays a read-only overlay when a file is locked by another user/agent.
6
+ * Shows lock holder info, time remaining, and options to request access.
7
+ */
8
+
9
+ import type { VFSFileLock } from '../../types';
10
+
11
+ interface Props {
12
+ lock: VFSFileLock;
13
+ onRequestAccess?: () => void;
14
+ onOpenReadOnly?: () => void;
15
+ onClose?: () => void;
16
+ showActions?: boolean;
34
17
  }
35
- return `${seconds}s remaining`;
36
- });
37
-
38
- // Lock holder display name
39
- let holderDisplay = $derived(lock.holderType === 'agent' ? `AI: ${lock.holder}` : lock.holder);
40
-
41
- // Lock purpose display
42
- let purposeDisplay = $derived.by(() => {
43
- switch (lock.purpose) {
44
- case 'edit':
45
- return 'Editing';
46
- case 'refactor':
47
- return 'Refactoring';
48
- case 'delete':
49
- return 'Deleting';
50
- case 'rename':
51
- return 'Renaming';
52
- default:
53
- return 'Modifying';
54
- }
55
- });
18
+
19
+ let { lock, onRequestAccess, onOpenReadOnly, onClose, showActions = true }: Props = $props();
20
+
21
+ // Calculate time remaining
22
+ let timeRemaining = $derived.by(() => {
23
+ const expires = new Date(lock.expiresAt).getTime();
24
+ const now = Date.now();
25
+ const remaining = Math.max(0, expires - now);
26
+
27
+ if (remaining === 0) return 'Expired';
28
+
29
+ const minutes = Math.floor(remaining / 60000);
30
+ const seconds = Math.floor((remaining % 60000) / 1000);
31
+
32
+ if (minutes > 0) {
33
+ return `${minutes}m ${seconds}s remaining`;
34
+ }
35
+ return `${seconds}s remaining`;
36
+ });
37
+
38
+ // Lock holder display name
39
+ let holderDisplay = $derived(lock.holderType === 'agent' ? `AI: ${lock.holder}` : lock.holder);
40
+
41
+ // Lock purpose display
42
+ let purposeDisplay = $derived.by(() => {
43
+ switch (lock.purpose) {
44
+ case 'edit':
45
+ return 'Editing';
46
+ case 'refactor':
47
+ return 'Refactoring';
48
+ case 'delete':
49
+ return 'Deleting';
50
+ case 'rename':
51
+ return 'Renaming';
52
+ default:
53
+ return 'Modifying';
54
+ }
55
+ });
56
56
  </script>
57
57
 
58
58
  <div class="lock-overlay">
@@ -1,9 +1,9 @@
1
1
  /**
2
- * LockOverlay Component
3
- *
4
- * Displays a read-only overlay when a file is locked by another user/agent.
5
- * Shows lock holder info, time remaining, and options to request access.
6
- */
2
+ * LockOverlay Component
3
+ *
4
+ * Displays a read-only overlay when a file is locked by another user/agent.
5
+ * Shows lock holder info, time remaining, and options to request access.
6
+ */
7
7
  import type { VFSFileLock } from '../../types';
8
8
  interface Props {
9
9
  lock: VFSFileLock;