@nocturnium/svelte-ide 1.0.0-rc.1 → 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 +16 -6
- package/dist/components/agents/AgentPresenceBar.svelte +7 -3
- package/dist/components/ai/AIConversationList.svelte +40 -34
- package/dist/components/ai/AIInlineEdit.svelte +7 -4
- package/dist/components/ai/AIMessage.svelte +6 -6
- package/dist/components/ai/AIMessageActions.svelte +18 -4
- package/dist/components/ai/AIMessageContent.svelte +23 -21
- package/dist/components/ai/AIPanel.svelte +24 -17
- package/dist/components/ai/AISuggestionWidget.svelte +1 -3
- package/dist/components/ai/AIToolCallDisplay.svelte +10 -14
- package/dist/components/core/Avatar.svelte +1 -1
- package/dist/components/core/Badge.svelte +9 -1
- package/dist/components/core/ConnectionStatus.svelte +73 -68
- package/dist/components/core/ContextMenu.svelte +1 -1
- package/dist/components/core/ErrorBoundary.svelte +57 -57
- 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 +54 -63
- package/dist/components/editor/CognitiveLoadMeter.svelte +5 -3
- package/dist/components/editor/CollaborativeEditor.svelte +3 -7
- package/dist/components/editor/CommandPalette.svelte +8 -10
- package/dist/components/editor/ComplexityLayer.svelte +9 -6
- package/dist/components/editor/ComplexityLayer.svelte.d.ts +0 -7
- package/dist/components/editor/ConflictZoneLayer.svelte +4 -10
- package/dist/components/editor/ContextLens.svelte +2 -5
- package/dist/components/editor/CustomEditor.svelte +87 -45
- package/dist/components/editor/DebugConsole.svelte +13 -27
- package/dist/components/editor/EchoCursorLayer.svelte +7 -7
- package/dist/components/editor/EditorGutter.svelte +10 -4
- package/dist/components/editor/EditorLines.svelte +6 -3
- package/dist/components/editor/EditorPane.svelte +2 -7
- package/dist/components/editor/EditorSelections.svelte +31 -13
- package/dist/components/editor/FileExplorer.svelte +32 -22
- package/dist/components/editor/FileIcon.svelte +3 -1
- package/dist/components/editor/FindReplace.svelte +18 -9
- package/dist/components/editor/GhostBracketLayer.svelte +3 -4
- package/dist/components/editor/GitBlameLayer.svelte +2 -1
- package/dist/components/editor/InlineDiagnosticsLayer.svelte +8 -16
- package/dist/components/editor/InlineDiffLayer.svelte +18 -9
- package/dist/components/editor/MinimalEditor.svelte +1 -1
- package/dist/components/editor/MinimalEditor2.svelte +1 -1
- package/dist/components/editor/Minimap.svelte +16 -9
- package/dist/components/editor/PluginPreviewSandbox.svelte +5 -5
- package/dist/components/editor/PluginPreviewSandbox.svelte.d.ts +7 -0
- package/dist/components/editor/ProblemsPanel.svelte +16 -41
- package/dist/components/editor/QuickActionsMenu.svelte +5 -16
- package/dist/components/editor/SnippetPalette.svelte +15 -15
- package/dist/components/editor/SnippetPalette.svelte.d.ts +6 -0
- package/dist/components/editor/StructureMap.svelte +10 -4
- package/dist/components/editor/SymbolOutline.svelte +27 -44
- package/dist/components/editor/TimelineScrubber.svelte +9 -9
- package/dist/components/editor/TokenRenderer.svelte +1 -1
- package/dist/components/editor/core/bracket-healer.js +1 -1
- 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/crdt-binding.js +1 -1
- package/dist/components/editor/core/folding.d.ts +9 -0
- package/dist/components/editor/core/folding.js +42 -7
- package/dist/components/editor/core/git-blame.js +1 -1
- package/dist/components/editor/core/keybindings.js +0 -4
- package/dist/components/editor/core/multi-cursor.d.ts +1 -1
- package/dist/components/editor/core/multi-cursor.js +5 -9
- 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 +5 -4
- package/dist/components/editor/core/state.js +4 -4
- package/dist/components/editor/core/timeline.js +1 -3
- package/dist/components/editor/editor-input.js +13 -10
- package/dist/components/editor/editor-multicursor.js +2 -2
- package/dist/components/editor/languages.js +1 -1
- package/dist/components/editor/tokenizer/languages/css.js +146 -29
- package/dist/components/editor/tokenizer/languages/go.js +76 -13
- package/dist/components/editor/tokenizer/languages/html.js +1 -1
- package/dist/components/editor/tokenizer/languages/javascript.js +211 -32
- package/dist/components/editor/tokenizer/languages/markdown.js +2 -2
- package/dist/components/editor/tokenizer/languages/python.js +116 -19
- package/dist/components/editor/tokenizer/languages/svelte.js +21 -8
- package/dist/components/layout/IDELayout.svelte +34 -9
- package/dist/components/layout/IDELayout.svelte.d.ts +26 -24
- package/dist/components/layout/StatusBar.svelte +32 -21
- package/dist/components/lsp/AutocompleteWidget.svelte +26 -24
- package/dist/components/lsp/DiagnosticMarker.svelte +62 -52
- package/dist/components/lsp/DiagnosticsPanel.svelte +51 -39
- package/dist/components/lsp/HoverTooltip.svelte +59 -63
- package/dist/components/lsp/LSPEditor.svelte +15 -27
- package/dist/components/lsp/SignatureHelpWidget.svelte +12 -9
- package/dist/components/plugins/PluginCard.svelte +4 -13
- package/dist/components/plugins/PluginProposalForm.svelte +21 -34
- package/dist/components/vfs/LockConflictDialog.svelte +114 -47
- package/dist/components/vfs/LockIndicator.svelte +0 -7
- 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 -74
- package/dist/services/error-handling.js +1 -7
- package/dist/services/lsp-client.js +2 -2
- package/dist/services/mock-ai.js +9 -7
- package/dist/services/optimistic.d.ts +1 -1
- package/dist/services/vfs-client.js +1 -1
- package/dist/stores/agents.svelte.js +69 -12
- package/dist/stores/ai-persistence.svelte.d.ts +3 -1
- package/dist/stores/ai-persistence.svelte.js +19 -6
- package/dist/stores/ai.svelte.js +72 -16
- package/dist/stores/collaboration.svelte.js +81 -17
- package/dist/stores/editor.svelte.js +51 -11
- package/dist/stores/layout.svelte.js +1 -1
- package/dist/stores/plugin.svelte.js +64 -14
- package/dist/stores/vfs.svelte.d.ts +1 -1
- package/dist/stores/vfs.svelte.js +89 -25
- package/dist/styles/theme.css +16 -7
- package/dist/types/plugin.d.ts +0 -12
- package/package.json +184 -176
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 {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - Typing indicator animation
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type { Agent,
|
|
12
|
+
import type { Agent, CursorPosition, CursorSelection } from '../../types';
|
|
13
13
|
|
|
14
14
|
interface Props {
|
|
15
15
|
/** The agent this cursor belongs to */
|
|
@@ -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) {
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
let overflowCount = $derived(Math.max(0, activeAgents.length - maxVisible));
|
|
46
46
|
|
|
47
47
|
// Group by status for summary
|
|
48
|
-
let onlineCount = $derived(agents.filter((a) => a.status === 'online').length);
|
|
49
48
|
let busyCount = $derived(agents.filter((a) => a.status === 'busy').length);
|
|
50
49
|
let stalledCount = $derived(agents.filter((a) => a.status === 'stalled').length);
|
|
51
50
|
</script>
|
|
@@ -58,7 +57,10 @@
|
|
|
58
57
|
{#if activeAgents.length > 0}
|
|
59
58
|
<div class="presence-bar__avatars">
|
|
60
59
|
{#each visibleAgents as agent, i (agent.id)}
|
|
61
|
-
<Tooltip
|
|
60
|
+
<Tooltip
|
|
61
|
+
content="{agent.name} ({agent.status})"
|
|
62
|
+
position={orientation === 'vertical' ? 'right' : 'bottom'}
|
|
63
|
+
>
|
|
62
64
|
<button
|
|
63
65
|
class="presence-bar__avatar"
|
|
64
66
|
style="--index: {i}; --total: {visibleAgents.length}"
|
|
@@ -147,7 +149,9 @@
|
|
|
147
149
|
background: transparent;
|
|
148
150
|
padding: 0;
|
|
149
151
|
cursor: pointer;
|
|
150
|
-
transition:
|
|
152
|
+
transition:
|
|
153
|
+
transform var(--ide-transition-fast),
|
|
154
|
+
z-index var(--ide-transition-fast);
|
|
151
155
|
}
|
|
152
156
|
|
|
153
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');
|
|
@@ -78,6 +70,7 @@
|
|
|
78
70
|
if (filter === 'starred') {
|
|
79
71
|
result = result.filter((c) => c.starred);
|
|
80
72
|
} else if (filter === 'today') {
|
|
73
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- temporary comparison value, not reactive UI state
|
|
81
74
|
const today = new Date();
|
|
82
75
|
today.setHours(0, 0, 0, 0);
|
|
83
76
|
result = result.filter((c) => new Date(c.updatedAt) >= today);
|
|
@@ -137,21 +130,12 @@
|
|
|
137
130
|
|
|
138
131
|
<!-- Search -->
|
|
139
132
|
<div class="list-search">
|
|
140
|
-
<Input
|
|
141
|
-
type="search"
|
|
142
|
-
placeholder="Search conversations..."
|
|
143
|
-
bind:value={searchQuery}
|
|
144
|
-
size="sm"
|
|
145
|
-
/>
|
|
133
|
+
<Input type="search" placeholder="Search conversations..." bind:value={searchQuery} size="sm" />
|
|
146
134
|
</div>
|
|
147
135
|
|
|
148
136
|
<!-- Filters -->
|
|
149
137
|
<div class="list-filters">
|
|
150
|
-
<button
|
|
151
|
-
class="filter-btn"
|
|
152
|
-
class:active={filter === 'all'}
|
|
153
|
-
onclick={() => (filter = 'all')}
|
|
154
|
-
>
|
|
138
|
+
<button class="filter-btn" class:active={filter === 'all'} onclick={() => (filter = 'all')}>
|
|
155
139
|
All
|
|
156
140
|
</button>
|
|
157
141
|
<button
|
|
@@ -162,11 +146,7 @@
|
|
|
162
146
|
<Icon name="star" size={12} />
|
|
163
147
|
Starred
|
|
164
148
|
</button>
|
|
165
|
-
<button
|
|
166
|
-
class="filter-btn"
|
|
167
|
-
class:active={filter === 'today'}
|
|
168
|
-
onclick={() => (filter = 'today')}
|
|
169
|
-
>
|
|
149
|
+
<button class="filter-btn" class:active={filter === 'today'} onclick={() => (filter = 'today')}>
|
|
170
150
|
Today
|
|
171
151
|
</button>
|
|
172
152
|
</div>
|
|
@@ -208,7 +188,10 @@
|
|
|
208
188
|
<div class="item-actions" bind:this={menuRef}>
|
|
209
189
|
<button
|
|
210
190
|
class="action-trigger"
|
|
211
|
-
onclick={(e) => {
|
|
191
|
+
onclick={(e) => {
|
|
192
|
+
e.stopPropagation();
|
|
193
|
+
toggleMenu(conv.id);
|
|
194
|
+
}}
|
|
212
195
|
aria-label="Conversation options"
|
|
213
196
|
aria-expanded={menuOpenId === conv.id}
|
|
214
197
|
aria-haspopup="menu"
|
|
@@ -219,7 +202,13 @@
|
|
|
219
202
|
{#if menuOpenId === conv.id}
|
|
220
203
|
<div class="action-menu" role="menu" aria-label="Conversation actions">
|
|
221
204
|
{#if onStar}
|
|
222
|
-
<button
|
|
205
|
+
<button
|
|
206
|
+
role="menuitem"
|
|
207
|
+
onclick={() => {
|
|
208
|
+
onStar(conv, !conv.starred);
|
|
209
|
+
menuOpenId = null;
|
|
210
|
+
}}
|
|
211
|
+
>
|
|
223
212
|
<Icon name={conv.starred ? 'star-off' : 'star'} size={14} />
|
|
224
213
|
{conv.starred ? 'Unstar' : 'Star'}
|
|
225
214
|
</button>
|
|
@@ -231,17 +220,36 @@
|
|
|
231
220
|
</button>
|
|
232
221
|
{/if}
|
|
233
222
|
{#if onExport}
|
|
234
|
-
<button
|
|
223
|
+
<button
|
|
224
|
+
role="menuitem"
|
|
225
|
+
onclick={() => {
|
|
226
|
+
onExport(conv, 'md');
|
|
227
|
+
menuOpenId = null;
|
|
228
|
+
}}
|
|
229
|
+
>
|
|
235
230
|
<Icon name="download" size={14} />
|
|
236
231
|
Export Markdown
|
|
237
232
|
</button>
|
|
238
|
-
<button
|
|
233
|
+
<button
|
|
234
|
+
role="menuitem"
|
|
235
|
+
onclick={() => {
|
|
236
|
+
onExport(conv, 'json');
|
|
237
|
+
menuOpenId = null;
|
|
238
|
+
}}
|
|
239
|
+
>
|
|
239
240
|
<Icon name="code" size={14} />
|
|
240
241
|
Export JSON
|
|
241
242
|
</button>
|
|
242
243
|
{/if}
|
|
243
244
|
{#if onDelete}
|
|
244
|
-
<button
|
|
245
|
+
<button
|
|
246
|
+
role="menuitem"
|
|
247
|
+
class="danger"
|
|
248
|
+
onclick={() => {
|
|
249
|
+
onDelete(conv);
|
|
250
|
+
menuOpenId = null;
|
|
251
|
+
}}
|
|
252
|
+
>
|
|
245
253
|
<Icon name="trash" size={14} />
|
|
246
254
|
Delete
|
|
247
255
|
</button>
|
|
@@ -261,9 +269,7 @@
|
|
|
261
269
|
<p>No conversations today</p>
|
|
262
270
|
{:else}
|
|
263
271
|
<p>No conversations yet</p>
|
|
264
|
-
<Button variant="primary" size="sm" onclick={onNew}>
|
|
265
|
-
Start a conversation
|
|
266
|
-
</Button>
|
|
272
|
+
<Button variant="primary" size="sm" onclick={onNew}>Start a conversation</Button>
|
|
267
273
|
{/if}
|
|
268
274
|
</div>
|
|
269
275
|
{/each}
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
class: className = ''
|
|
18
18
|
}: Props = $props();
|
|
19
19
|
|
|
20
|
+
// Seeded once from the prop: this is the editable input buffer, mounted fresh per edit.
|
|
21
|
+
// svelte-ignore state_referenced_locally
|
|
20
22
|
let prompt = $state(initialPrompt);
|
|
21
23
|
let isSubmitting = $state(false);
|
|
22
24
|
|
|
@@ -40,6 +42,9 @@
|
|
|
40
42
|
}
|
|
41
43
|
</script>
|
|
42
44
|
|
|
45
|
+
<!-- Wrapper-level keydown only captures Escape / Cmd+Enter shortcuts; the real controls
|
|
46
|
+
(textarea, buttons) inside are the focusable interactive elements. -->
|
|
47
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
43
48
|
<div class="ai-inline-edit {className}" onkeydown={handleKeydown}>
|
|
44
49
|
<div class="ai-inline-edit__header">
|
|
45
50
|
<Icon name="sparkles" size={14} />
|
|
@@ -63,9 +68,7 @@
|
|
|
63
68
|
</div>
|
|
64
69
|
|
|
65
70
|
<div class="ai-inline-edit__actions">
|
|
66
|
-
<Button variant="ghost" size="sm" onclick={onCancel} disabled={isSubmitting}>
|
|
67
|
-
Cancel
|
|
68
|
-
</Button>
|
|
71
|
+
<Button variant="ghost" size="sm" onclick={onCancel} disabled={isSubmitting}>Cancel</Button>
|
|
69
72
|
<Button
|
|
70
73
|
variant="primary"
|
|
71
74
|
size="sm"
|
|
@@ -75,7 +78,7 @@
|
|
|
75
78
|
{#if isSubmitting}
|
|
76
79
|
<Spinner size="xs" />
|
|
77
80
|
{:else}
|
|
78
|
-
{#snippet
|
|
81
|
+
{#snippet _icon()}<Icon name="wand" size={14} />{/snippet}
|
|
79
82
|
{/if}
|
|
80
83
|
Apply
|
|
81
84
|
</Button>
|