@nocturnium/svelte-ide 1.0.0 → 1.0.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.
- package/README.md +43 -47
- package/dist/components/agents/AgentActivityPanel.svelte +3 -1
- package/dist/components/agents/AgentAvatar.svelte +127 -35
- package/dist/components/agents/AgentCursor.svelte +15 -5
- package/dist/components/agents/AgentPresenceBar.svelte +7 -2
- package/dist/components/ai/AIConversationList.svelte +39 -34
- package/dist/components/ai/AIInlineEdit.svelte +1 -3
- package/dist/components/ai/AIMessage.svelte +5 -5
- package/dist/components/ai/AIMessageActions.svelte +18 -3
- package/dist/components/ai/AIMessageContent.svelte +22 -20
- package/dist/components/ai/AIPanel.svelte +17 -9
- package/dist/components/ai/AISuggestionWidget.svelte +1 -3
- package/dist/components/ai/AIToolCallDisplay.svelte +10 -14
- package/dist/components/core/Badge.svelte +9 -1
- package/dist/components/core/ConnectionStatus.svelte +73 -68
- package/dist/components/core/ErrorBoundary.svelte +56 -56
- package/dist/components/core/ErrorBoundary.svelte.d.ts +5 -5
- package/dist/components/core/Icon.svelte +22 -11
- package/dist/components/core/ResizeHandle.svelte +1 -1
- package/dist/components/core/Tooltip.svelte +1 -7
- package/dist/components/editor/AIFocusLayer.svelte +15 -7
- package/dist/components/editor/Breadcrumbs.svelte +18 -6
- package/dist/components/editor/BreakpointLayer.svelte +51 -60
- package/dist/components/editor/CognitiveLoadMeter.svelte +4 -2
- package/dist/components/editor/CollaborativeEditor.svelte +1 -5
- package/dist/components/editor/CommandPalette.svelte +1 -4
- package/dist/components/editor/ComplexityLayer.svelte +8 -6
- package/dist/components/editor/ConflictZoneLayer.svelte +2 -8
- package/dist/components/editor/ContextLens.svelte +1 -4
- package/dist/components/editor/CustomEditor.svelte +85 -41
- package/dist/components/editor/DebugConsole.svelte +8 -17
- package/dist/components/editor/EchoCursorLayer.svelte +3 -1
- package/dist/components/editor/EditorGutter.svelte +8 -2
- package/dist/components/editor/EditorLines.svelte +6 -3
- package/dist/components/editor/EditorPane.svelte +1 -6
- package/dist/components/editor/EditorSelections.svelte +29 -11
- package/dist/components/editor/FileExplorer.svelte +26 -4
- package/dist/components/editor/FileIcon.svelte +3 -1
- package/dist/components/editor/FindReplace.svelte +16 -4
- package/dist/components/editor/GhostBracketLayer.svelte +2 -2
- package/dist/components/editor/GitBlameLayer.svelte +2 -1
- package/dist/components/editor/InlineDiagnosticsLayer.svelte +4 -13
- package/dist/components/editor/InlineDiffLayer.svelte +18 -9
- package/dist/components/editor/Minimap.svelte +16 -9
- package/dist/components/editor/PluginPreviewSandbox.svelte +3 -2
- package/dist/components/editor/ProblemsPanel.svelte +11 -35
- package/dist/components/editor/QuickActionsMenu.svelte +5 -14
- package/dist/components/editor/SnippetPalette.svelte +11 -12
- package/dist/components/editor/StructureMap.svelte +2 -1
- package/dist/components/editor/SymbolOutline.svelte +14 -19
- package/dist/components/editor/TimelineScrubber.svelte +7 -6
- package/dist/components/editor/core/complexity-analyzer.js +42 -12
- package/dist/components/editor/core/conflict-predictor.js +2 -4
- package/dist/components/editor/core/folding.d.ts +9 -0
- package/dist/components/editor/core/folding.js +40 -5
- package/dist/components/editor/core/multi-cursor.js +4 -8
- package/dist/components/editor/core/navigation.js +2 -6
- package/dist/components/editor/core/quick-actions.js +22 -17
- package/dist/components/editor/core/search.js +2 -6
- package/dist/components/editor/core/semantic-analyzer.js +1 -3
- package/dist/components/editor/core/snippet-manager.js +4 -3
- package/dist/components/editor/core/state.js +2 -2
- package/dist/components/editor/core/timeline.js +1 -3
- package/dist/components/editor/editor-input.js +9 -6
- package/dist/components/editor/editor-multicursor.js +2 -2
- package/dist/components/editor/tokenizer/languages/css.js +146 -24
- package/dist/components/editor/tokenizer/languages/go.js +76 -13
- package/dist/components/editor/tokenizer/languages/javascript.js +210 -29
- package/dist/components/editor/tokenizer/languages/python.js +116 -19
- package/dist/components/editor/tokenizer/languages/svelte.js +20 -7
- package/dist/components/layout/IDELayout.svelte +6 -2
- package/dist/components/layout/StatusBar.svelte +32 -20
- package/dist/components/lsp/AutocompleteWidget.svelte +19 -19
- package/dist/components/lsp/DiagnosticMarker.svelte +61 -52
- package/dist/components/lsp/DiagnosticsPanel.svelte +45 -27
- package/dist/components/lsp/HoverTooltip.svelte +56 -61
- package/dist/components/lsp/LSPEditor.svelte +7 -18
- package/dist/components/lsp/SignatureHelpWidget.svelte +12 -9
- package/dist/components/plugins/PluginCard.svelte +3 -13
- package/dist/components/plugins/PluginProposalForm.svelte +19 -31
- package/dist/components/vfs/LockConflictDialog.svelte +112 -45
- package/dist/components/vfs/LockIndicator.svelte +0 -1
- package/dist/components/vfs/LockOverlay.svelte +53 -53
- package/dist/components/vfs/LockOverlay.svelte.d.ts +5 -5
- package/dist/components/vfs/VersionConflictDialog.svelte +107 -77
- package/dist/services/error-handling.js +1 -7
- package/dist/services/mock-ai.js +9 -7
- package/dist/stores/agents.svelte.js +50 -10
- package/dist/stores/ai.svelte.js +66 -18
- package/dist/stores/collaboration.svelte.js +70 -14
- package/dist/stores/editor.svelte.js +50 -10
- package/dist/stores/plugin.svelte.js +60 -12
- package/dist/stores/vfs.svelte.js +77 -19
- package/dist/styles/theme.css +16 -7
- package/package.json +186 -1
package/README.md
CHANGED
|
@@ -50,17 +50,13 @@ without the design tokens):
|
|
|
50
50
|
|
|
51
51
|
```svelte
|
|
52
52
|
<script>
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
import { CustomEditor } from '@nocturnium/svelte-ide';
|
|
54
|
+
import '@nocturnium/svelte-ide/theme.css';
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
let code = $state('function hello() {\n console.log("world");\n}');
|
|
57
57
|
</script>
|
|
58
58
|
|
|
59
|
-
<CustomEditor
|
|
60
|
-
content={code}
|
|
61
|
-
language="javascript"
|
|
62
|
-
onChange={(value) => (code = value)}
|
|
63
|
-
/>
|
|
59
|
+
<CustomEditor content={code} language="javascript" onChange={(value) => (code = value)} />
|
|
64
60
|
```
|
|
65
61
|
|
|
66
62
|
`<CustomEditor>` also accepts `readonly`, `folding`, `multiCursor`, `maxCursors`,
|
|
@@ -83,24 +79,24 @@ to enumerate them at runtime.
|
|
|
83
79
|
|
|
84
80
|
```svelte
|
|
85
81
|
<script>
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
import { LSPEditor, createLSPClient } from '@nocturnium/svelte-ide';
|
|
83
|
+
import '@nocturnium/svelte-ide/theme.css';
|
|
88
84
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
85
|
+
const client = createLSPClient({
|
|
86
|
+
serverUrl: 'ws://localhost:8765/lsp?language=typescript',
|
|
87
|
+
rootUri: 'file:///workspace'
|
|
88
|
+
});
|
|
93
89
|
|
|
94
|
-
|
|
90
|
+
let code = $state('const greeting: string = "hi";');
|
|
95
91
|
</script>
|
|
96
92
|
|
|
97
93
|
<LSPEditor
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
94
|
+
content={code}
|
|
95
|
+
uri="file:///workspace/main.ts"
|
|
96
|
+
language="typescript"
|
|
97
|
+
lspClient={client}
|
|
98
|
+
onChange={(value) => (code = value)}
|
|
99
|
+
onDiagnostics={(diagnostics) => console.log(diagnostics)}
|
|
104
100
|
/>
|
|
105
101
|
```
|
|
106
102
|
|
|
@@ -112,18 +108,18 @@ You supply the LSP bridge. A ready-to-run Go WebSocket bridge lives in
|
|
|
112
108
|
|
|
113
109
|
```svelte
|
|
114
110
|
<script>
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
111
|
+
import { CollaborativeEditor } from '@nocturnium/svelte-ide';
|
|
112
|
+
import '@nocturnium/svelte-ide/theme.css';
|
|
113
|
+
// requires: npm install yjs y-websocket y-protocols
|
|
118
114
|
|
|
119
|
-
|
|
115
|
+
let content = $state('');
|
|
120
116
|
</script>
|
|
121
117
|
|
|
122
118
|
<CollaborativeEditor
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
119
|
+
documentId="room-1"
|
|
120
|
+
initialContent="// edit together"
|
|
121
|
+
language="javascript"
|
|
122
|
+
onChange={(value) => (content = value)}
|
|
127
123
|
/>
|
|
128
124
|
```
|
|
129
125
|
|
|
@@ -134,8 +130,8 @@ See the [Collaboration guide](https://github.com/nocturnium/svelte-ide/blob/main
|
|
|
134
130
|
|
|
135
131
|
```svelte
|
|
136
132
|
<script>
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
import { AIPanel } from '@nocturnium/svelte-ide';
|
|
134
|
+
import '@nocturnium/svelte-ide/theme.css';
|
|
139
135
|
</script>
|
|
140
136
|
|
|
141
137
|
<AIPanel />
|
|
@@ -152,22 +148,22 @@ The package root exposes the **stable core**. Backend-dependent and
|
|
|
152
148
|
experimental subsystems live behind dedicated subpaths — this keeps intent
|
|
153
149
|
explicit and tree-shaking clean.
|
|
154
150
|
|
|
155
|
-
| Import
|
|
156
|
-
|
|
|
157
|
-
| `@nocturnium/svelte-ide`
|
|
158
|
-
| `@nocturnium/svelte-ide/theme.css` | Default theme (design tokens + component styles)
|
|
159
|
-
| `.../components/editor`
|
|
160
|
-
| `.../components/core`
|
|
161
|
-
| `.../components/ai`
|
|
162
|
-
| `.../components/lsp`
|
|
163
|
-
| `.../components/agents`
|
|
164
|
-
| `.../components/vfs`
|
|
165
|
-
| `.../components/layout`
|
|
166
|
-
| `.../components/plugins`
|
|
167
|
-
| `.../stores`
|
|
168
|
-
| `.../plugins`
|
|
169
|
-
| `.../crdt`
|
|
170
|
-
| `.../types`, `.../utils`
|
|
151
|
+
| Import | Contents |
|
|
152
|
+
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
153
|
+
| `@nocturnium/svelte-ide` | Stable core: editors, layout shell, file explorer, core UI primitives, editor/language/tokenizer/theme utilities, LSP client, layout-store functions, public types |
|
|
154
|
+
| `@nocturnium/svelte-ide/theme.css` | Default theme (design tokens + component styles) |
|
|
155
|
+
| `.../components/editor` | `CustomEditor`, `Editor`, `EditorPane`, `EditorTabs`, … |
|
|
156
|
+
| `.../components/core` | `Button`, `Icon`, `Input`, `Tooltip`, `ResizeHandle`, … |
|
|
157
|
+
| `.../components/ai` | `AIPanel`, `AIMessage`, `AIInlineEdit`, … |
|
|
158
|
+
| `.../components/lsp` | `LSPEditor`, `AutocompleteWidget`, `HoverTooltip`, … |
|
|
159
|
+
| `.../components/agents` | `AgentAvatar`, `AgentActivityPanel`, `AgentCursor`, … |
|
|
160
|
+
| `.../components/vfs` | `LockIndicator`, `LockConflictDialog`, … |
|
|
161
|
+
| `.../components/layout` | `IDELayout`, `StatusBar` |
|
|
162
|
+
| `.../components/plugins` | `PluginPanel`, `PluginCard`, … |
|
|
163
|
+
| `.../stores` | Full Svelte 5 runes store surface (layout, editor, ai, plugin, …) |
|
|
164
|
+
| `.../plugins` | Plugin runtime (`createPluginLoader`, `definePlugin`, `defineCommand`, `definePanel`, `pluginRegistry`) |
|
|
165
|
+
| `.../crdt` | CRDT collaboration primitives (requires Yjs) |
|
|
166
|
+
| `.../types`, `.../utils` | Full type and helper-function surface |
|
|
171
167
|
|
|
172
168
|
## API Stability
|
|
173
169
|
|
|
@@ -57,7 +57,9 @@
|
|
|
57
57
|
selectedAgentId ? activities.filter((a) => a.agentId === selectedAgentId) : activities
|
|
58
58
|
);
|
|
59
59
|
|
|
60
|
-
let onlineCount = $derived(
|
|
60
|
+
let onlineCount = $derived(
|
|
61
|
+
agents.filter((a) => a.status === 'online' || a.status === 'busy').length
|
|
62
|
+
);
|
|
61
63
|
let busyCount = $derived(agents.filter((a) => a.status === 'busy').length);
|
|
62
64
|
|
|
63
65
|
function formatTime(timestamp: string): string {
|
|
@@ -52,20 +52,25 @@
|
|
|
52
52
|
if (!agent.currentTask?.progress.phase) return null;
|
|
53
53
|
const phase = agent.currentTask.progress.phase;
|
|
54
54
|
switch (phase) {
|
|
55
|
-
case 'planning':
|
|
56
|
-
|
|
57
|
-
case '
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
case 'planning':
|
|
56
|
+
return 'Planning...';
|
|
57
|
+
case 'implementing':
|
|
58
|
+
return 'Coding...';
|
|
59
|
+
case 'testing':
|
|
60
|
+
return 'Testing...';
|
|
61
|
+
case 'complete':
|
|
62
|
+
return 'Done';
|
|
63
|
+
default:
|
|
64
|
+
return phase;
|
|
60
65
|
}
|
|
61
66
|
});
|
|
62
67
|
|
|
63
68
|
// Is this an AI agent?
|
|
64
69
|
let isAI = $derived(
|
|
65
70
|
agent.type === 'coder' ||
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
agent.type === 'reviewer' ||
|
|
72
|
+
agent.type === 'tester' ||
|
|
73
|
+
agent.type === 'architect'
|
|
69
74
|
);
|
|
70
75
|
|
|
71
76
|
// Unique ID for SVG gradients
|
|
@@ -93,10 +98,10 @@
|
|
|
93
98
|
</linearGradient>
|
|
94
99
|
<!-- Glow filter -->
|
|
95
100
|
<filter id="glow-{agent.id.slice(0, 8)}" x="-50%" y="-50%" width="200%" height="200%">
|
|
96
|
-
<feGaussianBlur stdDeviation="2" result="coloredBlur"/>
|
|
101
|
+
<feGaussianBlur stdDeviation="2" result="coloredBlur" />
|
|
97
102
|
<feMerge>
|
|
98
|
-
<feMergeNode in="coloredBlur"/>
|
|
99
|
-
<feMergeNode in="SourceGraphic"/>
|
|
103
|
+
<feMergeNode in="coloredBlur" />
|
|
104
|
+
<feMergeNode in="SourceGraphic" />
|
|
100
105
|
</feMerge>
|
|
101
106
|
</filter>
|
|
102
107
|
</defs>
|
|
@@ -159,30 +164,65 @@
|
|
|
159
164
|
<div class="agent-avatar__badge-inner">
|
|
160
165
|
{#if agent.type === 'coder'}
|
|
161
166
|
<!-- Code brackets icon -->
|
|
162
|
-
<svg
|
|
167
|
+
<svg
|
|
168
|
+
viewBox="0 0 24 24"
|
|
169
|
+
fill="none"
|
|
170
|
+
stroke="currentColor"
|
|
171
|
+
stroke-width="2.5"
|
|
172
|
+
stroke-linecap="round"
|
|
173
|
+
stroke-linejoin="round"
|
|
174
|
+
>
|
|
163
175
|
<polyline points="16 18 22 12 16 6" />
|
|
164
176
|
<polyline points="8 6 2 12 8 18" />
|
|
165
177
|
</svg>
|
|
166
178
|
{:else if agent.type === 'reviewer'}
|
|
167
179
|
<!-- Checkmark icon -->
|
|
168
|
-
<svg
|
|
180
|
+
<svg
|
|
181
|
+
viewBox="0 0 24 24"
|
|
182
|
+
fill="none"
|
|
183
|
+
stroke="currentColor"
|
|
184
|
+
stroke-width="2.5"
|
|
185
|
+
stroke-linecap="round"
|
|
186
|
+
stroke-linejoin="round"
|
|
187
|
+
>
|
|
169
188
|
<polyline points="20 6 9 17 4 12" />
|
|
170
189
|
</svg>
|
|
171
190
|
{:else if agent.type === 'tester'}
|
|
172
191
|
<!-- Flask icon -->
|
|
173
|
-
<svg
|
|
192
|
+
<svg
|
|
193
|
+
viewBox="0 0 24 24"
|
|
194
|
+
fill="none"
|
|
195
|
+
stroke="currentColor"
|
|
196
|
+
stroke-width="2.5"
|
|
197
|
+
stroke-linecap="round"
|
|
198
|
+
stroke-linejoin="round"
|
|
199
|
+
>
|
|
174
200
|
<path d="M9 3h6v6l4 9H5l4-9V3z" />
|
|
175
201
|
<path d="M9 3h6" />
|
|
176
202
|
</svg>
|
|
177
203
|
{:else if agent.type === 'architect'}
|
|
178
204
|
<!-- Blueprint/compass icon -->
|
|
179
|
-
<svg
|
|
205
|
+
<svg
|
|
206
|
+
viewBox="0 0 24 24"
|
|
207
|
+
fill="none"
|
|
208
|
+
stroke="currentColor"
|
|
209
|
+
stroke-width="2.5"
|
|
210
|
+
stroke-linecap="round"
|
|
211
|
+
stroke-linejoin="round"
|
|
212
|
+
>
|
|
180
213
|
<circle cx="12" cy="12" r="10" />
|
|
181
214
|
<polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76" />
|
|
182
215
|
</svg>
|
|
183
216
|
{:else}
|
|
184
217
|
<!-- User icon -->
|
|
185
|
-
<svg
|
|
218
|
+
<svg
|
|
219
|
+
viewBox="0 0 24 24"
|
|
220
|
+
fill="none"
|
|
221
|
+
stroke="currentColor"
|
|
222
|
+
stroke-width="2.5"
|
|
223
|
+
stroke-linecap="round"
|
|
224
|
+
stroke-linejoin="round"
|
|
225
|
+
>
|
|
186
226
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
|
|
187
227
|
<circle cx="12" cy="7" r="4" />
|
|
188
228
|
</svg>
|
|
@@ -230,8 +270,13 @@
|
|
|
230
270
|
}
|
|
231
271
|
|
|
232
272
|
@keyframes avatar-breathe {
|
|
233
|
-
0%,
|
|
234
|
-
|
|
273
|
+
0%,
|
|
274
|
+
100% {
|
|
275
|
+
transform: scale(1);
|
|
276
|
+
}
|
|
277
|
+
50% {
|
|
278
|
+
transform: scale(1.02);
|
|
279
|
+
}
|
|
235
280
|
}
|
|
236
281
|
|
|
237
282
|
/* Status Ring */
|
|
@@ -274,7 +319,8 @@
|
|
|
274
319
|
}
|
|
275
320
|
|
|
276
321
|
@keyframes ring-pulse {
|
|
277
|
-
0%,
|
|
322
|
+
0%,
|
|
323
|
+
100% {
|
|
278
324
|
opacity: 1;
|
|
279
325
|
box-shadow: 0 0 8px color-mix(in srgb, var(--ide-agent-online) 40%, transparent);
|
|
280
326
|
}
|
|
@@ -285,18 +331,34 @@
|
|
|
285
331
|
}
|
|
286
332
|
|
|
287
333
|
@keyframes ring-spin {
|
|
288
|
-
from {
|
|
289
|
-
|
|
334
|
+
from {
|
|
335
|
+
transform: rotate(0deg);
|
|
336
|
+
}
|
|
337
|
+
to {
|
|
338
|
+
transform: rotate(360deg);
|
|
339
|
+
}
|
|
290
340
|
}
|
|
291
341
|
|
|
292
342
|
@keyframes ring-error {
|
|
293
|
-
0%,
|
|
294
|
-
|
|
343
|
+
0%,
|
|
344
|
+
100% {
|
|
345
|
+
opacity: 1;
|
|
346
|
+
transform: scale(1);
|
|
347
|
+
}
|
|
348
|
+
50% {
|
|
349
|
+
opacity: 0.6;
|
|
350
|
+
transform: scale(1.05);
|
|
351
|
+
}
|
|
295
352
|
}
|
|
296
353
|
|
|
297
354
|
@keyframes ring-stalled {
|
|
298
|
-
0%,
|
|
299
|
-
|
|
355
|
+
0%,
|
|
356
|
+
100% {
|
|
357
|
+
opacity: 0.8;
|
|
358
|
+
}
|
|
359
|
+
50% {
|
|
360
|
+
opacity: 0.3;
|
|
361
|
+
}
|
|
300
362
|
}
|
|
301
363
|
|
|
302
364
|
/* Progress Ring */
|
|
@@ -361,8 +423,13 @@
|
|
|
361
423
|
}
|
|
362
424
|
|
|
363
425
|
@keyframes badge-shimmer {
|
|
364
|
-
0%,
|
|
365
|
-
|
|
426
|
+
0%,
|
|
427
|
+
100% {
|
|
428
|
+
background-position: 0% 50%;
|
|
429
|
+
}
|
|
430
|
+
50% {
|
|
431
|
+
background-position: 100% 50%;
|
|
432
|
+
}
|
|
366
433
|
}
|
|
367
434
|
|
|
368
435
|
/* Badge Glow */
|
|
@@ -380,8 +447,15 @@
|
|
|
380
447
|
}
|
|
381
448
|
|
|
382
449
|
@keyframes glow-pulse {
|
|
383
|
-
0%,
|
|
384
|
-
|
|
450
|
+
0%,
|
|
451
|
+
100% {
|
|
452
|
+
opacity: 0.5;
|
|
453
|
+
transform: scale(1);
|
|
454
|
+
}
|
|
455
|
+
50% {
|
|
456
|
+
opacity: 1;
|
|
457
|
+
transform: scale(1.3);
|
|
458
|
+
}
|
|
385
459
|
}
|
|
386
460
|
|
|
387
461
|
/* Phase Label */
|
|
@@ -394,15 +468,33 @@
|
|
|
394
468
|
}
|
|
395
469
|
|
|
396
470
|
@keyframes phase-fade-in {
|
|
397
|
-
from {
|
|
398
|
-
|
|
471
|
+
from {
|
|
472
|
+
opacity: 0;
|
|
473
|
+
transform: translateY(-4px);
|
|
474
|
+
}
|
|
475
|
+
to {
|
|
476
|
+
opacity: 1;
|
|
477
|
+
transform: translateY(0);
|
|
478
|
+
}
|
|
399
479
|
}
|
|
400
480
|
|
|
401
481
|
/* Size-specific adjustments */
|
|
402
|
-
.agent-avatar--xs .agent-avatar__ring {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
482
|
+
.agent-avatar--xs .agent-avatar__ring {
|
|
483
|
+
inset: -2px;
|
|
484
|
+
border-width: 1.5px;
|
|
485
|
+
}
|
|
486
|
+
.agent-avatar--sm .agent-avatar__ring {
|
|
487
|
+
inset: -2px;
|
|
488
|
+
border-width: 1.5px;
|
|
489
|
+
}
|
|
490
|
+
.agent-avatar--lg .agent-avatar__ring {
|
|
491
|
+
inset: -4px;
|
|
492
|
+
border-width: 2.5px;
|
|
493
|
+
}
|
|
494
|
+
.agent-avatar--xl .agent-avatar__ring {
|
|
495
|
+
inset: -4px;
|
|
496
|
+
border-width: 3px;
|
|
497
|
+
}
|
|
406
498
|
|
|
407
499
|
/* Hover state */
|
|
408
500
|
.agent-avatar:hover .agent-avatar__inner {
|
|
@@ -56,7 +56,9 @@
|
|
|
56
56
|
|
|
57
57
|
// Calculate selection dimensions if present
|
|
58
58
|
let hasSelection = $derived(
|
|
59
|
-
selection &&
|
|
59
|
+
selection &&
|
|
60
|
+
(selection.start.line !== selection.end.line ||
|
|
61
|
+
selection.start.column !== selection.end.column)
|
|
60
62
|
);
|
|
61
63
|
|
|
62
64
|
function getSelectionStyle() {
|
|
@@ -64,10 +66,18 @@
|
|
|
64
66
|
|
|
65
67
|
const startLine = Math.min(selection.start.line, selection.end.line);
|
|
66
68
|
const endLine = Math.max(selection.start.line, selection.end.line);
|
|
67
|
-
const startCol =
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
const startCol =
|
|
70
|
+
selection.start.line < selection.end.line
|
|
71
|
+
? selection.start.column
|
|
72
|
+
: selection.start.line === selection.end.line
|
|
73
|
+
? Math.min(selection.start.column, selection.end.column)
|
|
74
|
+
: selection.end.column;
|
|
75
|
+
const endCol =
|
|
76
|
+
selection.start.line < selection.end.line
|
|
77
|
+
? selection.end.column
|
|
78
|
+
: selection.start.line === selection.end.line
|
|
79
|
+
? Math.max(selection.start.column, selection.end.column)
|
|
80
|
+
: selection.start.column;
|
|
71
81
|
|
|
72
82
|
// For single line selection
|
|
73
83
|
if (startLine === endLine) {
|
|
@@ -57,7 +57,10 @@
|
|
|
57
57
|
{#if activeAgents.length > 0}
|
|
58
58
|
<div class="presence-bar__avatars">
|
|
59
59
|
{#each visibleAgents as agent, i (agent.id)}
|
|
60
|
-
<Tooltip
|
|
60
|
+
<Tooltip
|
|
61
|
+
content="{agent.name} ({agent.status})"
|
|
62
|
+
position={orientation === 'vertical' ? 'right' : 'bottom'}
|
|
63
|
+
>
|
|
61
64
|
<button
|
|
62
65
|
class="presence-bar__avatar"
|
|
63
66
|
style="--index: {i}; --total: {visibleAgents.length}"
|
|
@@ -146,7 +149,9 @@
|
|
|
146
149
|
background: transparent;
|
|
147
150
|
padding: 0;
|
|
148
151
|
cursor: pointer;
|
|
149
|
-
transition:
|
|
152
|
+
transition:
|
|
153
|
+
transform var(--ide-transition-fast),
|
|
154
|
+
z-index var(--ide-transition-fast);
|
|
150
155
|
}
|
|
151
156
|
|
|
152
157
|
/* Stacked effect for horizontal - overlap avatars */
|
|
@@ -19,16 +19,8 @@
|
|
|
19
19
|
onExport?: (conversation: AIConversation, format: 'json' | 'md') => void;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
let {
|
|
23
|
-
|
|
24
|
-
activeId,
|
|
25
|
-
onSelect,
|
|
26
|
-
onNew,
|
|
27
|
-
onDelete,
|
|
28
|
-
onRename,
|
|
29
|
-
onStar,
|
|
30
|
-
onExport
|
|
31
|
-
}: Props = $props();
|
|
22
|
+
let { conversations, activeId, onSelect, onNew, onDelete, onRename, onStar, onExport }: Props =
|
|
23
|
+
$props();
|
|
32
24
|
|
|
33
25
|
let searchQuery = $state('');
|
|
34
26
|
let filter = $state<'all' | 'starred' | 'today'>('all');
|
|
@@ -138,21 +130,12 @@
|
|
|
138
130
|
|
|
139
131
|
<!-- Search -->
|
|
140
132
|
<div class="list-search">
|
|
141
|
-
<Input
|
|
142
|
-
type="search"
|
|
143
|
-
placeholder="Search conversations..."
|
|
144
|
-
bind:value={searchQuery}
|
|
145
|
-
size="sm"
|
|
146
|
-
/>
|
|
133
|
+
<Input type="search" placeholder="Search conversations..." bind:value={searchQuery} size="sm" />
|
|
147
134
|
</div>
|
|
148
135
|
|
|
149
136
|
<!-- Filters -->
|
|
150
137
|
<div class="list-filters">
|
|
151
|
-
<button
|
|
152
|
-
class="filter-btn"
|
|
153
|
-
class:active={filter === 'all'}
|
|
154
|
-
onclick={() => (filter = 'all')}
|
|
155
|
-
>
|
|
138
|
+
<button class="filter-btn" class:active={filter === 'all'} onclick={() => (filter = 'all')}>
|
|
156
139
|
All
|
|
157
140
|
</button>
|
|
158
141
|
<button
|
|
@@ -163,11 +146,7 @@
|
|
|
163
146
|
<Icon name="star" size={12} />
|
|
164
147
|
Starred
|
|
165
148
|
</button>
|
|
166
|
-
<button
|
|
167
|
-
class="filter-btn"
|
|
168
|
-
class:active={filter === 'today'}
|
|
169
|
-
onclick={() => (filter = 'today')}
|
|
170
|
-
>
|
|
149
|
+
<button class="filter-btn" class:active={filter === 'today'} onclick={() => (filter = 'today')}>
|
|
171
150
|
Today
|
|
172
151
|
</button>
|
|
173
152
|
</div>
|
|
@@ -209,7 +188,10 @@
|
|
|
209
188
|
<div class="item-actions" bind:this={menuRef}>
|
|
210
189
|
<button
|
|
211
190
|
class="action-trigger"
|
|
212
|
-
onclick={(e) => {
|
|
191
|
+
onclick={(e) => {
|
|
192
|
+
e.stopPropagation();
|
|
193
|
+
toggleMenu(conv.id);
|
|
194
|
+
}}
|
|
213
195
|
aria-label="Conversation options"
|
|
214
196
|
aria-expanded={menuOpenId === conv.id}
|
|
215
197
|
aria-haspopup="menu"
|
|
@@ -220,7 +202,13 @@
|
|
|
220
202
|
{#if menuOpenId === conv.id}
|
|
221
203
|
<div class="action-menu" role="menu" aria-label="Conversation actions">
|
|
222
204
|
{#if onStar}
|
|
223
|
-
<button
|
|
205
|
+
<button
|
|
206
|
+
role="menuitem"
|
|
207
|
+
onclick={() => {
|
|
208
|
+
onStar(conv, !conv.starred);
|
|
209
|
+
menuOpenId = null;
|
|
210
|
+
}}
|
|
211
|
+
>
|
|
224
212
|
<Icon name={conv.starred ? 'star-off' : 'star'} size={14} />
|
|
225
213
|
{conv.starred ? 'Unstar' : 'Star'}
|
|
226
214
|
</button>
|
|
@@ -232,17 +220,36 @@
|
|
|
232
220
|
</button>
|
|
233
221
|
{/if}
|
|
234
222
|
{#if onExport}
|
|
235
|
-
<button
|
|
223
|
+
<button
|
|
224
|
+
role="menuitem"
|
|
225
|
+
onclick={() => {
|
|
226
|
+
onExport(conv, 'md');
|
|
227
|
+
menuOpenId = null;
|
|
228
|
+
}}
|
|
229
|
+
>
|
|
236
230
|
<Icon name="download" size={14} />
|
|
237
231
|
Export Markdown
|
|
238
232
|
</button>
|
|
239
|
-
<button
|
|
233
|
+
<button
|
|
234
|
+
role="menuitem"
|
|
235
|
+
onclick={() => {
|
|
236
|
+
onExport(conv, 'json');
|
|
237
|
+
menuOpenId = null;
|
|
238
|
+
}}
|
|
239
|
+
>
|
|
240
240
|
<Icon name="code" size={14} />
|
|
241
241
|
Export JSON
|
|
242
242
|
</button>
|
|
243
243
|
{/if}
|
|
244
244
|
{#if onDelete}
|
|
245
|
-
<button
|
|
245
|
+
<button
|
|
246
|
+
role="menuitem"
|
|
247
|
+
class="danger"
|
|
248
|
+
onclick={() => {
|
|
249
|
+
onDelete(conv);
|
|
250
|
+
menuOpenId = null;
|
|
251
|
+
}}
|
|
252
|
+
>
|
|
246
253
|
<Icon name="trash" size={14} />
|
|
247
254
|
Delete
|
|
248
255
|
</button>
|
|
@@ -262,9 +269,7 @@
|
|
|
262
269
|
<p>No conversations today</p>
|
|
263
270
|
{:else}
|
|
264
271
|
<p>No conversations yet</p>
|
|
265
|
-
<Button variant="primary" size="sm" onclick={onNew}>
|
|
266
|
-
Start a conversation
|
|
267
|
-
</Button>
|
|
272
|
+
<Button variant="primary" size="sm" onclick={onNew}>Start a conversation</Button>
|
|
268
273
|
{/if}
|
|
269
274
|
</div>
|
|
270
275
|
{/each}
|
|
@@ -68,9 +68,7 @@
|
|
|
68
68
|
</div>
|
|
69
69
|
|
|
70
70
|
<div class="ai-inline-edit__actions">
|
|
71
|
-
<Button variant="ghost" size="sm" onclick={onCancel} disabled={isSubmitting}>
|
|
72
|
-
Cancel
|
|
73
|
-
</Button>
|
|
71
|
+
<Button variant="ghost" size="sm" onclick={onCancel} disabled={isSubmitting}>Cancel</Button>
|
|
74
72
|
<Button
|
|
75
73
|
variant="primary"
|
|
76
74
|
size="sm"
|
|
@@ -86,10 +86,7 @@
|
|
|
86
86
|
{#if message.toolCalls && message.toolCalls.length > 0}
|
|
87
87
|
<div class="ai-message__tool-calls">
|
|
88
88
|
{#each message.toolCalls as toolCall (toolCall.id)}
|
|
89
|
-
<AIToolCallDisplay
|
|
90
|
-
{toolCall}
|
|
91
|
-
status="completed"
|
|
92
|
-
/>
|
|
89
|
+
<AIToolCallDisplay {toolCall} status="completed" />
|
|
93
90
|
{/each}
|
|
94
91
|
</div>
|
|
95
92
|
{/if}
|
|
@@ -185,7 +182,10 @@
|
|
|
185
182
|
}
|
|
186
183
|
|
|
187
184
|
.ai-message--user .ai-message__text {
|
|
188
|
-
background: var(
|
|
185
|
+
background: var(
|
|
186
|
+
--ide-ai-user,
|
|
187
|
+
color-mix(in srgb, var(--color-nocturnium-wave) 25%, var(--ide-bg-secondary))
|
|
188
|
+
);
|
|
189
189
|
color: var(--ide-text-primary);
|
|
190
190
|
border-bottom-right-radius: var(--ide-radius-sm);
|
|
191
191
|
border: 1px solid color-mix(in srgb, var(--color-nocturnium-wave) 40%, transparent);
|
|
@@ -53,7 +53,12 @@
|
|
|
53
53
|
}
|
|
54
54
|
</script>
|
|
55
55
|
|
|
56
|
-
<div
|
|
56
|
+
<div
|
|
57
|
+
class="message-actions"
|
|
58
|
+
class:message-actions--user={isUser}
|
|
59
|
+
role="group"
|
|
60
|
+
aria-label="Message actions"
|
|
61
|
+
>
|
|
57
62
|
<!-- Copy -->
|
|
58
63
|
<button
|
|
59
64
|
class="action-btn"
|
|
@@ -78,14 +83,24 @@
|
|
|
78
83
|
|
|
79
84
|
<!-- Retry (user messages to resend, assistant to regenerate) -->
|
|
80
85
|
{#if onRetry}
|
|
81
|
-
<button
|
|
86
|
+
<button
|
|
87
|
+
class="action-btn"
|
|
88
|
+
onclick={handleRetry}
|
|
89
|
+
title={isUser ? 'Resend' : 'Regenerate'}
|
|
90
|
+
aria-label={isUser ? 'Resend message' : 'Regenerate response'}
|
|
91
|
+
>
|
|
82
92
|
<Icon name="refresh" size={16} />
|
|
83
93
|
</button>
|
|
84
94
|
{/if}
|
|
85
95
|
|
|
86
96
|
<!-- Branch conversation from this point -->
|
|
87
97
|
{#if onBranch}
|
|
88
|
-
<button
|
|
98
|
+
<button
|
|
99
|
+
class="action-btn"
|
|
100
|
+
onclick={handleBranch}
|
|
101
|
+
title="Branch from here"
|
|
102
|
+
aria-label="Create branch from this message"
|
|
103
|
+
>
|
|
89
104
|
<Icon name="git-branch" size={16} />
|
|
90
105
|
</button>
|
|
91
106
|
{/if}
|