@nocturnium/svelte-ide 1.0.1 → 1.0.3

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 (74) hide show
  1. package/README.md +5 -3
  2. package/dist/components/ai/AIMessageContent.svelte +24 -14
  3. package/dist/components/ai/AIPanel.svelte +22 -0
  4. package/dist/components/editor/CollaborativeEditor.svelte +68 -5
  5. package/dist/components/editor/CollaborativeEditor.svelte.d.ts +14 -0
  6. package/dist/components/editor/CustomEditor.svelte +52 -33
  7. package/dist/components/editor/CustomEditor.svelte.d.ts +2 -2
  8. package/dist/components/editor/Editor.svelte +17 -0
  9. package/dist/components/editor/Editor.svelte.d.ts +9 -0
  10. package/dist/components/editor/EditorPane.svelte +18 -1
  11. package/dist/components/editor/EditorPane.svelte.d.ts +5 -0
  12. package/dist/components/editor/EditorSelections.svelte +27 -11
  13. package/dist/components/editor/EditorSelections.svelte.d.ts +1 -0
  14. package/dist/components/editor/core/folding.d.ts +11 -0
  15. package/dist/components/editor/core/folding.js +41 -0
  16. package/dist/components/editor/core/index.d.ts +0 -5
  17. package/dist/components/editor/core/index.js +4 -5
  18. package/dist/components/editor/core/state.d.ts +5 -0
  19. package/dist/components/editor/core/state.js +131 -12
  20. package/dist/components/editor/editor-find.d.ts +1 -0
  21. package/dist/components/editor/editor-find.js +6 -5
  22. package/dist/components/editor/editor-input.d.ts +1 -0
  23. package/dist/components/editor/editor-input.js +4 -1
  24. package/dist/components/editor/editor-scroll.d.ts +1 -0
  25. package/dist/components/editor/editor-scroll.js +2 -1
  26. package/dist/components/editor/index.d.ts +19 -3
  27. package/dist/components/editor/index.js +18 -4
  28. package/dist/components/editor/tokenizer/base.d.ts +1 -25
  29. package/dist/components/editor/tokenizer/base.js +0 -172
  30. package/dist/components/editor/tokenizer/index.d.ts +4 -0
  31. package/dist/components/editor/tokenizer/index.js +1 -1
  32. package/dist/components/editor/tokenizer/languages/html.d.ts +3 -2
  33. package/dist/components/editor/tokenizer/languages/html.js +64 -6
  34. package/dist/components/editor/tokenizer/languages/javascript.d.ts +13 -5
  35. package/dist/components/editor/tokenizer/languages/javascript.js +69 -57
  36. package/dist/components/editor/tokenizer/languages/svelte.d.ts +1 -1
  37. package/dist/components/editor/tokenizer/languages/svelte.js +6 -1
  38. package/dist/components/editor/tokenizer/types.d.ts +0 -28
  39. package/dist/crdt/awareness.d.ts +8 -2
  40. package/dist/crdt/awareness.js +11 -4
  41. package/dist/crdt/document.d.ts +10 -1
  42. package/dist/crdt/document.js +15 -7
  43. package/dist/crdt/index.d.ts +8 -2
  44. package/dist/crdt/index.js +5 -2
  45. package/dist/crdt/undo.d.ts +2 -7
  46. package/dist/crdt/undo.js +1 -8
  47. package/dist/index.d.ts +7 -9
  48. package/dist/index.js +7 -9
  49. package/dist/services/error-handling.d.ts +2 -11
  50. package/dist/services/error-handling.js +15 -4
  51. package/dist/services/lsp-client.d.ts +3 -0
  52. package/dist/services/lsp-client.js +55 -10
  53. package/dist/services/optimistic.d.ts +8 -5
  54. package/dist/services/optimistic.js +36 -10
  55. package/dist/services/vfs-client.js +11 -3
  56. package/dist/stores/agents.svelte.js +3 -2
  57. package/dist/stores/ai-persistence.svelte.js +7 -2
  58. package/dist/stores/ai.svelte.js +2 -1
  59. package/dist/stores/collaboration.svelte.d.ts +1 -1
  60. package/dist/stores/collaboration.svelte.js +3 -2
  61. package/dist/stores/editor.svelte.js +29 -5
  62. package/dist/stores/layout.svelte.js +3 -0
  63. package/dist/stores/plugin.svelte.js +9 -3
  64. package/dist/stores/vfs.svelte.js +26 -9
  65. package/dist/styles/theme.css +43 -0
  66. package/dist/types/vfs.d.ts +15 -1
  67. package/dist/types/vfs.js +9 -0
  68. package/dist/utils/language.d.ts +4 -3
  69. package/dist/utils/language.js +8 -18
  70. package/package.json +1 -1
  71. package/dist/components/editor/MinimalEditor.svelte +0 -75
  72. package/dist/components/editor/MinimalEditor.svelte.d.ts +0 -6
  73. package/dist/components/editor/MinimalEditor2.svelte +0 -84
  74. package/dist/components/editor/MinimalEditor2.svelte.d.ts +0 -6
package/README.md CHANGED
@@ -23,7 +23,7 @@ LSP, collaboration, AI, and plugin pieces into a full IDE experience.
23
23
  - **Find & replace** with regex support.
24
24
  - **LSP client** — autocomplete, hover, signatures, diagnostics over WebSocket.
25
25
  - **Realtime collaboration** (optional) — CRDT/Yjs, tree-shakeable.
26
- - **AI panel & agent presence** layers for assistant-driven editing.
26
+ - **AI panel & agent presence** layers for assistant UI and presence patterns.
27
27
  - **Plugin system** with a proposal-based lifecycle (bring your own backend).
28
28
  - **Themeable** — every color/size is a CSS custom property you can override.
29
29
  - **Zero external UI dependencies**; collaboration deps are optional peers.
@@ -138,8 +138,10 @@ See the [Collaboration guide](https://github.com/nocturnium/svelte-ide/blob/main
138
138
  ```
139
139
 
140
140
  `<AIPanel>` talks to **your own** chat endpoint (configurable; defaults to
141
- `/api/chat`) via the AI store. Model output is HTML-escaped with link-scheme
142
- whitelisting before rendering. See the
141
+ `/api/chat`) via the AI store. The repository's demo route returns canned mock
142
+ responses only; it does not connect to a real model provider. Consumers should
143
+ bring their own backend for inference. Model output is HTML-escaped with
144
+ link-scheme whitelisting before rendering. See the
143
145
  [AI & agents guide](https://github.com/nocturnium/svelte-ide/blob/main/docs/guides/ai-and-agents.md).
144
146
 
145
147
  ## Entry points
@@ -286,56 +286,60 @@
286
286
 
287
287
  /* Syntax highlighting tokens */
288
288
  .code-content :global(.token-keyword) {
289
- color: var(--syntax-keyword, #c792ea);
289
+ color: var(--ide-syntax-keyword);
290
290
  }
291
291
 
292
292
  .code-content :global(.token-string) {
293
- color: var(--syntax-string, #c3e88d);
293
+ color: var(--ide-syntax-string);
294
294
  }
295
295
 
296
296
  .code-content :global(.token-number) {
297
- color: var(--syntax-number, #f78c6c);
297
+ color: var(--ide-syntax-number);
298
298
  }
299
299
 
300
300
  .code-content :global(.token-comment) {
301
- color: var(--syntax-comment, #546e7a);
301
+ color: var(--ide-syntax-comment);
302
302
  font-style: italic;
303
303
  }
304
304
 
305
305
  .code-content :global(.token-function) {
306
- color: var(--syntax-function, #82aaff);
306
+ color: var(--ide-syntax-function);
307
307
  }
308
308
 
309
309
  .code-content :global(.token-class) {
310
- color: var(--syntax-class, #ffcb6b);
310
+ color: var(--ide-syntax-type);
311
311
  }
312
312
 
313
313
  .code-content :global(.token-operator) {
314
- color: var(--syntax-operator, #89ddff);
314
+ color: var(--ide-syntax-operator);
315
315
  }
316
316
 
317
317
  .code-content :global(.token-punctuation) {
318
- color: var(--syntax-punctuation, #89ddff);
318
+ color: var(--ide-syntax-punctuation);
319
319
  }
320
320
 
321
321
  .code-content :global(.token-variable) {
322
- color: var(--syntax-variable, #f07178);
322
+ color: var(--ide-syntax-variable);
323
323
  }
324
324
 
325
325
  .code-content :global(.token-property) {
326
- color: var(--syntax-property, #f07178);
326
+ color: var(--ide-accent);
327
327
  }
328
328
 
329
329
  .code-content :global(.token-type) {
330
- color: var(--syntax-type, #ffcb6b);
330
+ color: var(--ide-syntax-type);
331
331
  }
332
332
 
333
333
  .code-content :global(.token-tag) {
334
- color: var(--syntax-tag, #f07178);
334
+ color: var(--ide-syntax-tag);
335
335
  }
336
336
 
337
337
  .code-content :global(.token-attribute) {
338
- color: var(--syntax-attribute, #c792ea);
338
+ color: var(--ide-syntax-attribute);
339
+ }
340
+
341
+ .code-content :global(.token-constant) {
342
+ color: var(--ide-syntax-constant);
339
343
  }
340
344
 
341
345
  .code-content :global(.token-text),
@@ -346,7 +350,7 @@
346
350
  /* Streaming cursor */
347
351
  .cursor {
348
352
  animation: blink 1s step-end infinite;
349
- color: var(--color-nocturnium-wave);
353
+ color: var(--ide-accent);
350
354
  }
351
355
 
352
356
  @keyframes blink {
@@ -354,4 +358,10 @@
354
358
  opacity: 0;
355
359
  }
356
360
  }
361
+
362
+ @media (prefers-reduced-motion: reduce) {
363
+ .cursor {
364
+ animation: none;
365
+ }
366
+ }
357
367
  </style>
@@ -208,6 +208,7 @@
208
208
  <Icon name="sparkles" size={16} />
209
209
  <span>AI Assistant</span>
210
210
  </div>
211
+ <span class="ai-panel__mock-badge">Demo mock - no real model</span>
211
212
  </div>
212
213
  <div class="ai-panel__actions">
213
214
  <Button variant="ghost" size="xs" onclick={handleNewConversation} title="New conversation">
@@ -337,6 +338,7 @@
337
338
  display: flex;
338
339
  align-items: center;
339
340
  gap: var(--ide-spacing-sm);
341
+ min-width: 0;
340
342
  }
341
343
 
342
344
  .ai-panel__title {
@@ -346,6 +348,22 @@
346
348
  font-size: var(--ide-font-size-sm);
347
349
  font-weight: 600;
348
350
  color: var(--ide-text-primary);
351
+ flex-shrink: 0;
352
+ }
353
+
354
+ .ai-panel__mock-badge {
355
+ display: inline-flex;
356
+ align-items: center;
357
+ min-width: 0;
358
+ padding: 0.125rem var(--ide-spacing-sm);
359
+ border: 1px solid color-mix(in srgb, var(--ide-accent) 40%, var(--ide-border));
360
+ border-radius: var(--ide-radius-full);
361
+ background: color-mix(in srgb, var(--ide-accent) 10%, var(--ide-bg-secondary));
362
+ color: var(--ide-text-secondary);
363
+ font-size: var(--ide-font-size-xs);
364
+ font-weight: 500;
365
+ line-height: var(--ide-line-height-normal);
366
+ white-space: nowrap;
349
367
  }
350
368
 
351
369
  .ai-panel__actions {
@@ -541,6 +559,10 @@
541
559
  .ai-panel__input {
542
560
  padding: var(--ide-spacing-sm);
543
561
  }
562
+
563
+ .ai-panel__mock-badge {
564
+ white-space: normal;
565
+ }
544
566
  }
545
567
 
546
568
  @media (max-width: 480px) {
@@ -8,14 +8,30 @@
8
8
 
9
9
  import { onMount, onDestroy } from 'svelte';
10
10
  import * as Y from 'yjs';
11
+ import type { Awareness } from 'y-protocols/awareness';
11
12
  import CustomEditor from './CustomEditor.svelte';
12
- import { createEditorState, createCRDTBinding, type CRDTBinding } from './core';
13
+ import { createEditorState } from './core/state';
14
+ import { createCRDTBinding, type CRDTBinding } from './core/crdt-binding';
15
+ import { createAwarenessProtocol, type AwarenessProtocol } from '../../crdt/awareness';
16
+ import {
17
+ CollaborativeProvider,
18
+ createProvider,
19
+ type CollaborativeProvider as CollaborativeProviderType
20
+ } from '../../crdt/provider';
13
21
  import type { EditorPreferences } from '../../types';
14
22
  import type { CollaborationUser } from '../../types/crdt';
15
23
 
16
24
  interface Props {
17
25
  /** Yjs document for collaboration (optional - will create one if not provided) */
18
26
  doc?: Y.Doc;
27
+ /** Existing provider; its awareness is used for transmitted presence */
28
+ provider?: CollaborativeProviderType;
29
+ /** Existing provider-attached awareness for transmitted presence */
30
+ awareness?: Awareness;
31
+ /** WebSocket server URL when the component should create a provider */
32
+ serverUrl?: string;
33
+ /** WebSocket room ID when the component should create a provider */
34
+ roomId?: string;
19
35
  /** Document ID for standalone mode */
20
36
  documentId?: string;
21
37
  /** Initial content when creating a new document */
@@ -32,6 +48,10 @@
32
48
  class?: string;
33
49
  /** Current user info for cursor display */
34
50
  currentUser?: CollaborationUser;
51
+ /** File path this user is viewing */
52
+ viewingFile?: string;
53
+ /** File path this user is editing */
54
+ editingFile?: string;
35
55
  /** Called when content changes */
36
56
  onChange?: (content: string) => void;
37
57
  /** Called when cursor position changes */
@@ -42,14 +62,20 @@
42
62
 
43
63
  let {
44
64
  doc: externalDoc,
45
- documentId: _documentId,
65
+ provider: externalProvider,
66
+ awareness: externalAwareness,
67
+ serverUrl,
68
+ roomId,
69
+ documentId = 'document',
46
70
  initialContent = '',
47
71
  textName = 'content',
48
72
  language = 'plaintext',
49
73
  readonly = false,
50
74
  preferences = {},
51
75
  class: className = '',
52
- currentUser: _currentUser,
76
+ currentUser,
77
+ viewingFile,
78
+ editingFile,
53
79
  onChange,
54
80
  onCursorChange,
55
81
  onSave
@@ -57,6 +83,8 @@
57
83
 
58
84
  // Create internal doc if none provided
59
85
  let internalDoc: Y.Doc | null = null;
86
+ let ownedProvider: CollaborativeProvider | null = null;
87
+ let awarenessProtocol: AwarenessProtocol | null = null;
60
88
 
61
89
  // Editor state and CRDT binding
62
90
  let editorState = $state<ReturnType<typeof createEditorState> | null>(null);
@@ -82,6 +110,27 @@
82
110
  }
83
111
  }
84
112
 
113
+ const provider =
114
+ externalProvider ??
115
+ (serverUrl && roomId
116
+ ? createProvider(doc, serverUrl, roomId, currentUser ?? createAnonymousUser(documentId))
117
+ : null);
118
+ if (provider && !externalProvider) {
119
+ ownedProvider = provider;
120
+ }
121
+
122
+ const awareness = provider?.awareness ?? externalAwareness;
123
+ awarenessProtocol = createAwarenessProtocol(awareness ?? doc);
124
+ if (currentUser) {
125
+ awarenessProtocol.setUser(currentUser);
126
+ }
127
+ if (viewingFile !== undefined) {
128
+ awarenessProtocol.setViewingFile(viewingFile);
129
+ }
130
+ if (editingFile !== undefined) {
131
+ awarenessProtocol.setEditingFile(editingFile);
132
+ }
133
+
85
134
  // Create editor state
86
135
  editorState = createEditorState({
87
136
  content: initialContent,
@@ -131,9 +180,21 @@
131
180
  yTextObserver?.();
132
181
  yTextObserver = null;
133
182
  crdtBinding?.destroy();
183
+ awarenessProtocol?.destroy();
184
+ awarenessProtocol = null;
185
+ ownedProvider?.destroy();
186
+ ownedProvider = null;
134
187
  internalDoc?.destroy();
135
188
  });
136
189
 
190
+ function createAnonymousUser(id: string): CollaborationUser {
191
+ return {
192
+ id,
193
+ name: 'Anonymous',
194
+ color: '#60a5fa'
195
+ };
196
+ }
197
+
137
198
  // Handle content changes from the inner editor (local typing).
138
199
  //
139
200
  // The inner CustomEditor maintains its OWN EditorState, so local edits never
@@ -157,8 +218,10 @@
157
218
  function handleCursorChange(line: number, column: number) {
158
219
  onCursorChange?.(line, column);
159
220
 
160
- // Could broadcast cursor position to other collaborators here
161
- // using Yjs awareness protocol
221
+ if (!crdtBinding || !awarenessProtocol) return;
222
+ const index = crdtBinding.positionToIndex({ line, column });
223
+ awarenessProtocol.setCursor(index, index);
224
+ awarenessProtocol.setSelection(index, index);
162
225
  }
163
226
  </script>
164
227
 
@@ -1,9 +1,19 @@
1
1
  import * as Y from 'yjs';
2
+ import type { Awareness } from 'y-protocols/awareness';
3
+ import { type CollaborativeProvider as CollaborativeProviderType } from '../../crdt/provider';
2
4
  import type { EditorPreferences } from '../../types';
3
5
  import type { CollaborationUser } from '../../types/crdt';
4
6
  interface Props {
5
7
  /** Yjs document for collaboration (optional - will create one if not provided) */
6
8
  doc?: Y.Doc;
9
+ /** Existing provider; its awareness is used for transmitted presence */
10
+ provider?: CollaborativeProviderType;
11
+ /** Existing provider-attached awareness for transmitted presence */
12
+ awareness?: Awareness;
13
+ /** WebSocket server URL when the component should create a provider */
14
+ serverUrl?: string;
15
+ /** WebSocket room ID when the component should create a provider */
16
+ roomId?: string;
7
17
  /** Document ID for standalone mode */
8
18
  documentId?: string;
9
19
  /** Initial content when creating a new document */
@@ -20,6 +30,10 @@ interface Props {
20
30
  class?: string;
21
31
  /** Current user info for cursor display */
22
32
  currentUser?: CollaborationUser;
33
+ /** File path this user is viewing */
34
+ viewingFile?: string;
35
+ /** File path this user is editing */
36
+ editingFile?: string;
23
37
  /** Called when content changes */
24
38
  onChange?: (content: string) => void;
25
39
  /** Called when cursor position changes */
@@ -53,7 +53,7 @@
53
53
  multiCursor?: boolean;
54
54
  /** Maximum number of cursors (default: 100) */
55
55
  maxCursors?: number;
56
- /** Enable complexity highlighting (default: true) */
56
+ /** Enable complexity highlighting (default: false) */
57
57
  complexityHighlighting?: boolean;
58
58
  /** Minimum complexity score to show highlighting (default: 50) */
59
59
  complexityThreshold?: number;
@@ -61,7 +61,7 @@
61
61
  aiAgents?: AIAwareness[];
62
62
  /** Show AI cursor labels (default: true) */
63
63
  showAILabels?: boolean;
64
- /** Show AI focus regions (default: true) */
64
+ /** Show AI focus regions (default: false) */
65
65
  showAIFocusRegions?: boolean;
66
66
  onChange?: (content: string) => void;
67
67
  onCursorChange?: (line: number, column: number) => void;
@@ -81,11 +81,11 @@
81
81
  folding = true,
82
82
  multiCursor = true,
83
83
  maxCursors = 100,
84
- complexityHighlighting = true,
84
+ complexityHighlighting = false,
85
85
  complexityThreshold = 50,
86
86
  aiAgents = [],
87
87
  showAILabels = true,
88
- showAIFocusRegions = true,
88
+ showAIFocusRegions = false,
89
89
  onChange,
90
90
  onCursorChange,
91
91
  onCursorsChange,
@@ -171,10 +171,23 @@
171
171
  // Input handler module (created in initEditor)
172
172
  let inputHandlers = $state(null as unknown as ReturnType<typeof createEditorInput>);
173
173
 
174
+ function lineToVisualRow(line: number): number {
175
+ const lineCount = editorState?.lineCount ?? lines.length;
176
+ if (!folding || lineCount <= 0) return Math.max(0, Math.floor(line));
177
+ return foldManager.lineToVisualRow(line, lineCount);
178
+ }
179
+
180
+ function visualRowToLine(visualRow: number): number {
181
+ const lineCount = editorState?.lineCount ?? lines.length;
182
+ if (!folding || lineCount <= 0) return Math.max(0, Math.floor(visualRow));
183
+ return foldManager.visualRowToLine(visualRow, lineCount);
184
+ }
185
+
174
186
  // Scroll management module
175
187
  const editorScroll = createEditorScroll({
176
188
  getEditorContent: () => editorContent,
177
189
  getSelection: () => selection,
190
+ lineToVisualRow: (line) => lineToVisualRow(line),
178
191
  getMeasurements: () => ({ lineHeight, charWidth, gutterWidth, contentPadding: CONTENT_PADDING })
179
192
  });
180
193
  const { scrollCursorIntoView } = editorScroll;
@@ -378,6 +391,7 @@
378
391
  getCursors: () => cursors,
379
392
  getScrollPosition: () => ({ scrollTop, scrollLeft }),
380
393
  getMeasurements: () => ({ charWidth, lineHeight, gutterWidth }),
394
+ visualRowToLine: (visualRow) => visualRowToLine(visualRow),
381
395
 
382
396
  onOpenFind: (withReplace) => openFind(withReplace),
383
397
  onCloseFind: () => closeFind(),
@@ -507,10 +521,12 @@
507
521
  if (!folding || visibleLineIndices.length === 0) {
508
522
  return lines.map((line, index) => ({ line, index }));
509
523
  }
510
- return visibleLineIndices.map((index) => ({
511
- line: lines[index],
512
- index
513
- }));
524
+ return visibleLineIndices
525
+ .filter((index) => index >= 0 && index < lines.length)
526
+ .map((index) => ({
527
+ line: lines[index],
528
+ index
529
+ }));
514
530
  });
515
531
 
516
532
  /** Extra rows rendered above/below the viewport to avoid blank edges while scrolling. */
@@ -540,6 +556,7 @@
540
556
  }> = [];
541
557
  for (let visualRow = firstRow; visualRow <= lastRow; visualRow++) {
542
558
  const entry = visibleLines[visualRow];
559
+ if (!entry) continue;
543
560
  slice.push({ line: entry.line, index: entry.index, visualRow });
544
561
  }
545
562
  return slice;
@@ -590,7 +607,8 @@
590
607
  setContent: (content) => editorState.setContent(content),
591
608
  scrollCursorIntoView: () => scrollCursorIntoView(),
592
609
  focusEditor: () => hiddenInput?.focus(),
593
- isReadonly: () => readonly
610
+ isReadonly: () => readonly,
611
+ lineToVisualRow: (line) => lineToVisualRow(line)
594
612
  });
595
613
  }
596
614
 
@@ -1006,6 +1024,7 @@
1006
1024
  {viewportHeight}
1007
1025
  getLine={(n) => editorState.getLine(n)}
1008
1026
  lineCount={editorState?.lineCount ?? 0}
1027
+ lineToVisualRow={(line) => lineToVisualRow(line)}
1009
1028
  />
1010
1029
 
1011
1030
  <!-- Lines (virtualized: only the windowed slice is rendered) -->
@@ -1134,21 +1153,21 @@
1134
1153
  :global(.token-comment-line),
1135
1154
  :global(.token-comment-block),
1136
1155
  :global(.token-comment-doc) {
1137
- color: var(--ide-text-muted);
1156
+ color: var(--ide-syntax-comment);
1138
1157
  font-style: italic;
1139
1158
  }
1140
1159
 
1141
1160
  :global(.token-string),
1142
1161
  :global(.token-string-template) {
1143
- color: var(--color-nocturnium-aurora-green);
1162
+ color: var(--ide-syntax-string);
1144
1163
  }
1145
1164
 
1146
1165
  :global(.token-string-regex) {
1147
- color: var(--color-nocturnium-aurora-pink);
1166
+ color: var(--ide-syntax-tag);
1148
1167
  }
1149
1168
 
1150
1169
  :global(.token-string-escape) {
1151
- color: var(--color-nocturnium-aurora-yellow);
1170
+ color: var(--ide-syntax-constant);
1152
1171
  }
1153
1172
 
1154
1173
  :global(.token-number),
@@ -1156,7 +1175,7 @@
1156
1175
  :global(.token-number-float),
1157
1176
  :global(.token-number-hex),
1158
1177
  :global(.token-number-binary) {
1159
- color: var(--color-nocturnium-aurora-yellow);
1178
+ color: var(--ide-syntax-number);
1160
1179
  }
1161
1180
 
1162
1181
  :global(.token-keyword),
@@ -1165,7 +1184,7 @@
1165
1184
  :global(.token-keyword-definition),
1166
1185
  :global(.token-keyword-module),
1167
1186
  :global(.token-keyword-storage) {
1168
- color: var(--color-nocturnium-aurora-purple);
1187
+ color: var(--ide-syntax-keyword);
1169
1188
  }
1170
1189
 
1171
1190
  :global(.token-operator),
@@ -1173,30 +1192,30 @@
1173
1192
  :global(.token-operator-comparison),
1174
1193
  :global(.token-operator-logical),
1175
1194
  :global(.token-operator-assignment) {
1176
- color: var(--ide-text-primary);
1195
+ color: var(--ide-syntax-operator);
1177
1196
  }
1178
1197
 
1179
1198
  :global(.token-variable) {
1180
- color: var(--ide-text-primary);
1199
+ color: var(--ide-syntax-variable);
1181
1200
  }
1182
1201
 
1183
1202
  :global(.token-variable-definition) {
1184
- color: var(--color-nocturnium-wave);
1203
+ color: var(--ide-accent);
1185
1204
  }
1186
1205
 
1187
1206
  :global(.token-variable-parameter) {
1188
- color: color-mix(in srgb, var(--color-nocturnium-wave) 80%, var(--ide-text-muted));
1207
+ color: color-mix(in srgb, var(--ide-accent) 80%, var(--ide-text-muted));
1189
1208
  }
1190
1209
 
1191
1210
  :global(.token-function),
1192
1211
  :global(.token-function-definition),
1193
1212
  :global(.token-function-call) {
1194
- color: var(--color-nocturnium-aurora-blue);
1213
+ color: var(--ide-syntax-function);
1195
1214
  }
1196
1215
 
1197
1216
  :global(.token-property),
1198
1217
  :global(.token-property-definition) {
1199
- color: var(--color-nocturnium-wave);
1218
+ color: var(--ide-accent);
1200
1219
  }
1201
1220
 
1202
1221
  :global(.token-type),
@@ -1204,14 +1223,14 @@
1204
1223
  :global(.token-type-interface),
1205
1224
  :global(.token-type-namespace),
1206
1225
  :global(.token-type-builtin) {
1207
- color: var(--color-nocturnium-teal);
1226
+ color: var(--ide-syntax-type);
1208
1227
  }
1209
1228
 
1210
1229
  :global(.token-constant),
1211
1230
  :global(.token-constant-boolean),
1212
1231
  :global(.token-constant-null),
1213
1232
  :global(.token-constant-builtin) {
1214
- color: var(--color-nocturnium-aurora-yellow);
1233
+ color: var(--ide-syntax-constant);
1215
1234
  }
1216
1235
 
1217
1236
  :global(.token-punctuation),
@@ -1220,34 +1239,34 @@
1220
1239
  :global(.token-punctuation-paren),
1221
1240
  :global(.token-punctuation-separator),
1222
1241
  :global(.token-punctuation-accessor) {
1223
- color: var(--ide-text-secondary);
1242
+ color: var(--ide-syntax-punctuation);
1224
1243
  }
1225
1244
 
1226
1245
  /* Svelte template braces - make them stand out */
1227
1246
  :global(.token-punctuation-brace) {
1228
- color: var(--color-nocturnium-aurora-yellow);
1247
+ color: var(--ide-syntax-constant);
1229
1248
  font-weight: 600;
1230
1249
  }
1231
1250
 
1232
1251
  :global(.token-tag),
1233
1252
  :global(.token-tag-name) {
1234
- color: var(--color-nocturnium-aurora-pink);
1253
+ color: var(--ide-syntax-tag);
1235
1254
  }
1236
1255
 
1237
1256
  :global(.token-tag-attribute) {
1238
- color: var(--color-nocturnium-aurora-yellow);
1257
+ color: var(--ide-syntax-attribute);
1239
1258
  }
1240
1259
 
1241
1260
  :global(.token-tag-attribute-value) {
1242
- color: var(--color-nocturnium-aurora-green);
1261
+ color: var(--ide-syntax-string);
1243
1262
  }
1244
1263
 
1245
1264
  :global(.token-tag-punctuation) {
1246
- color: var(--ide-text-secondary);
1265
+ color: var(--ide-syntax-punctuation);
1247
1266
  }
1248
1267
 
1249
1268
  :global(.token-markup-heading) {
1250
- color: var(--color-nocturnium-aurora-blue);
1269
+ color: var(--ide-syntax-function);
1251
1270
  font-weight: bold;
1252
1271
  }
1253
1272
 
@@ -1260,12 +1279,12 @@
1260
1279
  }
1261
1280
 
1262
1281
  :global(.token-markup-link) {
1263
- color: var(--color-nocturnium-wave);
1282
+ color: var(--ide-accent);
1264
1283
  text-decoration: underline;
1265
1284
  }
1266
1285
 
1267
1286
  :global(.token-markup-code) {
1268
- color: var(--color-nocturnium-aurora-green);
1287
+ color: var(--ide-syntax-string);
1269
1288
  background: var(--ide-bg-tertiary);
1270
1289
  }
1271
1290
 
@@ -1275,7 +1294,7 @@
1275
1294
  }
1276
1295
 
1277
1296
  :global(.token-markup-list) {
1278
- color: var(--color-nocturnium-ember);
1297
+ color: var(--ide-text-accent);
1279
1298
  }
1280
1299
 
1281
1300
  :global(.token-invalid) {
@@ -14,7 +14,7 @@ interface Props {
14
14
  multiCursor?: boolean;
15
15
  /** Maximum number of cursors (default: 100) */
16
16
  maxCursors?: number;
17
- /** Enable complexity highlighting (default: true) */
17
+ /** Enable complexity highlighting (default: false) */
18
18
  complexityHighlighting?: boolean;
19
19
  /** Minimum complexity score to show highlighting (default: 50) */
20
20
  complexityThreshold?: number;
@@ -22,7 +22,7 @@ interface Props {
22
22
  aiAgents?: AIAwareness[];
23
23
  /** Show AI cursor labels (default: true) */
24
24
  showAILabels?: boolean;
25
- /** Show AI focus regions (default: true) */
25
+ /** Show AI focus regions (default: false) */
26
26
  showAIFocusRegions?: boolean;
27
27
  onChange?: (content: string) => void;
28
28
  onCursorChange?: (line: number, column: number) => void;
@@ -8,6 +8,7 @@
8
8
 
9
9
  import CustomEditor from './CustomEditor.svelte';
10
10
  import type { EditorPreferences } from '../../types';
11
+ import type { AIAwareness } from './core/ai-awareness';
11
12
 
12
13
  interface Props {
13
14
  /** Document content */
@@ -20,6 +21,14 @@
20
21
  preferences?: Partial<EditorPreferences>;
21
22
  /** Additional CSS class */
22
23
  class?: string;
24
+ /** Enable code folding */
25
+ folding?: boolean;
26
+ /** Enable multi-cursor editing */
27
+ multiCursor?: boolean;
28
+ /** Maximum number of cursors */
29
+ maxCursors?: number;
30
+ /** AI agents for Ghost Pair visualization */
31
+ aiAgents?: AIAwareness[];
23
32
  /** Called when content changes */
24
33
  onChange?: (content: string) => void;
25
34
  /** Called when cursor position changes */
@@ -34,6 +43,10 @@
34
43
  readonly = false,
35
44
  preferences = {},
36
45
  class: className = '',
46
+ folding = true,
47
+ multiCursor = true,
48
+ maxCursors = 100,
49
+ aiAgents = [],
37
50
  onChange,
38
51
  onCursorChange,
39
52
  onSave
@@ -46,6 +59,10 @@
46
59
  {language}
47
60
  {readonly}
48
61
  {preferences}
62
+ {folding}
63
+ {multiCursor}
64
+ {maxCursors}
65
+ {aiAgents}
49
66
  {onChange}
50
67
  {onCursorChange}
51
68
  {onSave}
@@ -1,4 +1,5 @@
1
1
  import type { EditorPreferences } from '../../types';
2
+ import type { AIAwareness } from './core/ai-awareness';
2
3
  interface Props {
3
4
  /** Document content */
4
5
  content: string;
@@ -10,6 +11,14 @@ interface Props {
10
11
  preferences?: Partial<EditorPreferences>;
11
12
  /** Additional CSS class */
12
13
  class?: string;
14
+ /** Enable code folding */
15
+ folding?: boolean;
16
+ /** Enable multi-cursor editing */
17
+ multiCursor?: boolean;
18
+ /** Maximum number of cursors */
19
+ maxCursors?: number;
20
+ /** AI agents for Ghost Pair visualization */
21
+ aiAgents?: AIAwareness[];
13
22
  /** Called when content changes */
14
23
  onChange?: (content: string) => void;
15
24
  /** Called when cursor position changes */