@d34dman/flowdrop 0.0.61 → 0.0.62

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 (204) hide show
  1. package/README.md +6 -0
  2. package/dist/adapters/WorkflowAdapter.d.ts +1 -1
  3. package/dist/adapters/agentspec/AgentSpecAdapter.js +3 -1
  4. package/dist/api/client.d.ts +4 -0
  5. package/dist/api/client.js +6 -1
  6. package/dist/api/enhanced-client.js +7 -6
  7. package/dist/components/App.svelte +143 -219
  8. package/dist/components/CanvasBanner.stories.svelte +25 -0
  9. package/dist/components/CanvasBanner.stories.svelte.d.ts +27 -0
  10. package/dist/components/CanvasBanner.svelte +2 -2
  11. package/dist/components/ConfigForm.svelte +37 -36
  12. package/dist/components/ConfigPanel.stories.svelte +38 -0
  13. package/dist/components/ConfigPanel.stories.svelte.d.ts +27 -0
  14. package/dist/components/ConfigPanel.svelte +2 -2
  15. package/dist/components/ConnectionLine.svelte +2 -2
  16. package/dist/components/FlowDropZone.svelte +18 -2
  17. package/dist/components/FlowDropZone.svelte.d.ts +2 -0
  18. package/dist/components/LoadingSpinner.stories.svelte +30 -0
  19. package/dist/components/LoadingSpinner.stories.svelte.d.ts +27 -0
  20. package/dist/components/Logo.stories.svelte +22 -0
  21. package/dist/components/Logo.stories.svelte.d.ts +27 -0
  22. package/dist/components/Logo.svelte +33 -13
  23. package/dist/components/Logo.svelte.d.ts +1 -1
  24. package/dist/components/MarkdownDisplay.stories.svelte +21 -0
  25. package/dist/components/MarkdownDisplay.stories.svelte.d.ts +27 -0
  26. package/dist/components/MarkdownDisplay.svelte +4 -3
  27. package/dist/components/Navbar.stories.svelte +41 -0
  28. package/dist/components/Navbar.stories.svelte.d.ts +27 -0
  29. package/dist/components/Navbar.svelte +4 -4
  30. package/dist/components/NodeSidebar.svelte +12 -12
  31. package/dist/components/NodeStatusOverlay.stories.svelte +74 -0
  32. package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +27 -0
  33. package/dist/components/PipelineStatus.svelte +11 -4
  34. package/dist/components/PortCoordinateTracker.svelte +1 -1
  35. package/dist/components/SchemaForm.stories.svelte +101 -0
  36. package/dist/components/SchemaForm.stories.svelte.d.ts +27 -0
  37. package/dist/components/SchemaForm.svelte +17 -12
  38. package/dist/components/SettingsModal.svelte +3 -3
  39. package/dist/components/SettingsPanel.svelte +23 -22
  40. package/dist/components/StatusIcon.stories.svelte +60 -0
  41. package/dist/components/StatusIcon.stories.svelte.d.ts +27 -0
  42. package/dist/components/StatusIcon.svelte +7 -0
  43. package/dist/components/StatusLabel.stories.svelte +17 -0
  44. package/dist/components/StatusLabel.stories.svelte.d.ts +27 -0
  45. package/dist/components/ThemeToggle.stories.svelte +25 -0
  46. package/dist/components/ThemeToggle.stories.svelte.d.ts +27 -0
  47. package/dist/components/ThemeToggle.svelte +8 -8
  48. package/dist/components/UniversalNode.svelte +1 -1
  49. package/dist/components/WorkflowEditor.svelte +298 -294
  50. package/dist/components/form/FormAutocomplete.svelte +20 -19
  51. package/dist/components/form/FormCheckboxGroup.stories.svelte +28 -0
  52. package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +27 -0
  53. package/dist/components/form/FormField.svelte +3 -3
  54. package/dist/components/form/FormFieldLight.svelte +2 -2
  55. package/dist/components/form/FormFieldWrapper.stories.svelte +31 -0
  56. package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +27 -0
  57. package/dist/components/form/FormFieldset.svelte +7 -7
  58. package/dist/components/form/FormNumberField.stories.svelte +33 -0
  59. package/dist/components/form/FormNumberField.stories.svelte.d.ts +27 -0
  60. package/dist/components/form/FormRangeField.stories.svelte +31 -0
  61. package/dist/components/form/FormRangeField.stories.svelte.d.ts +27 -0
  62. package/dist/components/form/FormSelect.stories.svelte +50 -0
  63. package/dist/components/form/FormSelect.stories.svelte.d.ts +27 -0
  64. package/dist/components/form/FormTemplateEditor.svelte +2 -1
  65. package/dist/components/form/FormTextField.stories.svelte +30 -0
  66. package/dist/components/form/FormTextField.stories.svelte.d.ts +27 -0
  67. package/dist/components/form/FormTextarea.stories.svelte +31 -0
  68. package/dist/components/form/FormTextarea.stories.svelte.d.ts +27 -0
  69. package/dist/components/form/FormToggle.stories.svelte +30 -0
  70. package/dist/components/form/FormToggle.stories.svelte.d.ts +27 -0
  71. package/dist/components/form/FormUISchemaRenderer.svelte +1 -1
  72. package/dist/components/form/types.d.ts +15 -47
  73. package/dist/components/interrupt/ChoicePrompt.stories.svelte +43 -0
  74. package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +27 -0
  75. package/dist/components/interrupt/ChoicePrompt.svelte +24 -24
  76. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +49 -0
  77. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +27 -0
  78. package/dist/components/interrupt/ConfirmationPrompt.svelte +19 -19
  79. package/dist/components/interrupt/FormPrompt.svelte +15 -15
  80. package/dist/components/interrupt/InterruptBubble.svelte +202 -236
  81. package/dist/components/interrupt/InterruptBubble.svelte.d.ts +1 -1
  82. package/dist/components/interrupt/ReviewPrompt.stories.svelte +46 -0
  83. package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +27 -0
  84. package/dist/components/interrupt/ReviewPrompt.svelte +842 -0
  85. package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +23 -0
  86. package/dist/components/interrupt/TextInputPrompt.stories.svelte +34 -0
  87. package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +27 -0
  88. package/dist/components/interrupt/TextInputPrompt.svelte +21 -21
  89. package/dist/components/nodes/GatewayNode.stories.svelte +76 -0
  90. package/dist/components/nodes/GatewayNode.stories.svelte.d.ts +26 -0
  91. package/dist/components/nodes/GatewayNode.svelte +19 -17
  92. package/dist/components/nodes/IdeaNode.stories.svelte +48 -0
  93. package/dist/components/nodes/IdeaNode.stories.svelte.d.ts +26 -0
  94. package/dist/components/nodes/IdeaNode.svelte +10 -26
  95. package/dist/components/nodes/NotesNode.stories.svelte +69 -0
  96. package/dist/components/nodes/NotesNode.stories.svelte.d.ts +26 -0
  97. package/dist/components/nodes/NotesNode.svelte +8 -8
  98. package/dist/components/nodes/SimpleNode.stories.svelte +101 -0
  99. package/dist/components/nodes/SimpleNode.stories.svelte.d.ts +26 -0
  100. package/dist/components/nodes/SimpleNode.svelte +16 -24
  101. package/dist/components/nodes/SquareNode.stories.svelte +56 -0
  102. package/dist/components/nodes/SquareNode.stories.svelte.d.ts +26 -0
  103. package/dist/components/nodes/SquareNode.svelte +13 -21
  104. package/dist/components/nodes/TerminalNode.stories.svelte +25 -0
  105. package/dist/components/nodes/TerminalNode.stories.svelte.d.ts +26 -0
  106. package/dist/components/nodes/TerminalNode.svelte +6 -6
  107. package/dist/components/nodes/ToolNode.stories.svelte +71 -0
  108. package/dist/components/nodes/ToolNode.stories.svelte.d.ts +26 -0
  109. package/dist/components/nodes/ToolNode.svelte +7 -15
  110. package/dist/components/nodes/WorkflowNode.stories.svelte +50 -0
  111. package/dist/components/nodes/WorkflowNode.stories.svelte.d.ts +26 -0
  112. package/dist/components/nodes/WorkflowNode.svelte +13 -13
  113. package/dist/components/playground/ChatPanel.svelte +48 -48
  114. package/dist/components/playground/ExecutionLogs.svelte +23 -23
  115. package/dist/components/playground/InputCollector.svelte +24 -24
  116. package/dist/components/playground/MessageBubble.stories.svelte +49 -0
  117. package/dist/components/playground/MessageBubble.stories.svelte.d.ts +27 -0
  118. package/dist/components/playground/MessageBubble.svelte +49 -46
  119. package/dist/components/playground/Playground.svelte +194 -129
  120. package/dist/components/playground/PlaygroundModal.svelte +5 -5
  121. package/dist/components/playground/SessionManager.svelte +26 -26
  122. package/dist/config/constants.d.ts +22 -0
  123. package/dist/config/constants.js +22 -0
  124. package/dist/config/endpoints.d.ts +19 -0
  125. package/dist/config/runtimeConfig.js +2 -1
  126. package/dist/core/index.d.ts +5 -2
  127. package/dist/core/index.js +9 -1
  128. package/dist/editor/index.d.ts +13 -9
  129. package/dist/editor/index.js +15 -11
  130. package/dist/form/code.d.ts +2 -1
  131. package/dist/form/code.js +1 -3
  132. package/dist/form/markdown.d.ts +2 -1
  133. package/dist/form/markdown.js +1 -3
  134. package/dist/helpers/workflowEditorHelper.js +13 -9
  135. package/dist/mocks/app-forms.js +1 -0
  136. package/dist/mocks/app-navigation.js +3 -1
  137. package/dist/mocks/app-stores.d.ts +4 -4
  138. package/dist/playground/index.d.ts +4 -3
  139. package/dist/playground/index.js +12 -10
  140. package/dist/playground/mount.js +6 -13
  141. package/dist/services/agentSpecExecutionService.js +2 -1
  142. package/dist/services/api.js +10 -18
  143. package/dist/services/apiVariableService.js +2 -1
  144. package/dist/services/autoSaveService.d.ts +3 -3
  145. package/dist/services/autoSaveService.js +21 -17
  146. package/dist/services/categoriesApi.js +13 -5
  147. package/dist/services/draftStorage.js +5 -4
  148. package/dist/services/dynamicSchemaService.js +4 -4
  149. package/dist/services/globalSave.d.ts +60 -11
  150. package/dist/services/globalSave.js +160 -83
  151. package/dist/services/historyService.d.ts +2 -1
  152. package/dist/services/historyService.js +7 -3
  153. package/dist/services/interruptService.js +9 -8
  154. package/dist/services/nodeExecutionService.js +14 -6
  155. package/dist/services/playgroundService.js +2 -1
  156. package/dist/services/portConfigApi.js +11 -7
  157. package/dist/services/toastService.d.ts +1 -1
  158. package/dist/services/toastService.js +6 -5
  159. package/dist/services/variableService.js +3 -2
  160. package/dist/settings/index.d.ts +1 -1
  161. package/dist/settings/index.js +1 -1
  162. package/dist/stores/{categoriesStore.d.ts → categoriesStore.svelte.d.ts} +3 -3
  163. package/dist/stores/{categoriesStore.js → categoriesStore.svelte.js} +15 -18
  164. package/dist/stores/editorStateMachine.svelte.d.ts +42 -0
  165. package/dist/stores/editorStateMachine.svelte.js +132 -0
  166. package/dist/stores/{historyStore.d.ts → historyStore.svelte.d.ts} +18 -15
  167. package/dist/stores/{historyStore.js → historyStore.svelte.js} +40 -21
  168. package/dist/stores/{interruptStore.d.ts → interruptStore.svelte.d.ts} +16 -15
  169. package/dist/stores/{interruptStore.js → interruptStore.svelte.js} +85 -94
  170. package/dist/stores/{playgroundStore.d.ts → playgroundStore.svelte.d.ts} +41 -33
  171. package/dist/stores/{playgroundStore.js → playgroundStore.svelte.js} +164 -84
  172. package/dist/stores/{portCoordinateStore.d.ts → portCoordinateStore.svelte.d.ts} +10 -4
  173. package/dist/stores/{portCoordinateStore.js → portCoordinateStore.svelte.js} +38 -35
  174. package/dist/stores/{settingsStore.d.ts → settingsStore.svelte.d.ts} +45 -28
  175. package/dist/stores/{settingsStore.js → settingsStore.svelte.js} +169 -128
  176. package/dist/stores/{workflowStore.d.ts → workflowStore.svelte.d.ts} +101 -65
  177. package/dist/stores/{workflowStore.js → workflowStore.svelte.js} +285 -239
  178. package/dist/stories/CanvasDecorator.svelte +50 -0
  179. package/dist/stories/CanvasDecorator.svelte.d.ts +8 -0
  180. package/dist/stories/NodeDecorator.svelte +74 -0
  181. package/dist/stories/NodeDecorator.svelte.d.ts +8 -0
  182. package/dist/stories/utils.d.ts +93 -0
  183. package/dist/stories/utils.js +122 -0
  184. package/dist/styles/base.css +114 -61
  185. package/dist/styles/toast.css +2 -2
  186. package/dist/styles/tokens.css +250 -185
  187. package/dist/svelte-app.d.ts +0 -6
  188. package/dist/svelte-app.js +13 -31
  189. package/dist/types/index.d.ts +2 -0
  190. package/dist/types/interrupt.d.ts +89 -5
  191. package/dist/types/interrupt.js +13 -1
  192. package/dist/types/playground.d.ts +5 -0
  193. package/dist/types/settings.js +1 -1
  194. package/dist/utils/colors.js +4 -4
  195. package/dist/utils/connections.js +33 -8
  196. package/dist/utils/icons.js +1 -1
  197. package/dist/utils/logger.d.ts +47 -0
  198. package/dist/utils/logger.js +72 -0
  199. package/dist/utils/nodeWrapper.js +1 -1
  200. package/dist/utils/sanitize.d.ts +19 -0
  201. package/dist/utils/sanitize.js +31 -0
  202. package/dist/utils/validation.d.ts +29 -0
  203. package/dist/utils/validation.js +39 -0
  204. package/package.json +243 -232
@@ -21,18 +21,17 @@
21
21
  import { interruptService } from '../../services/interruptService.js';
22
22
  import { setEndpointConfig } from '../../services/api.js';
23
23
  import {
24
- currentSession,
25
- sessions,
26
- messages,
27
- isExecuting,
28
- isLoading,
29
- error,
24
+ getCurrentSession,
25
+ getSessions,
26
+ getIsExecuting,
27
+ getIsLoading,
28
+ getError,
30
29
  playgroundActions,
31
- inputFields,
30
+ getInputFields,
32
31
  createPollingCallback
33
- } from '../../stores/playgroundStore.js';
34
- import { interruptActions } from '../../stores/interruptStore.js';
35
- import { get } from 'svelte/store';
32
+ } from '../../stores/playgroundStore.svelte.js';
33
+ import { interruptActions } from '../../stores/interruptStore.svelte.js';
34
+ import { logger } from '../../utils/logger.js';
36
35
 
37
36
  /**
38
37
  * Component props
@@ -70,8 +69,8 @@
70
69
  /** Track session being edited for rename */
71
70
  let editingSessionId = $state<string | null>(null);
72
71
 
73
- /** Track session pending delete */
74
- let pendingDeleteId = $state<string | null>(null);
72
+ /** Track which session's dropdown menu is open */
73
+ let openMenuId = $state<string | null>(null);
75
74
 
76
75
  /** Track if initial session has been loaded to prevent duplicate loads */
77
76
  let initialSessionLoaded = $state(false);
@@ -111,11 +110,11 @@
111
110
  if (config.autoRun && !autoRunTriggered) {
112
111
  autoRunTriggered = true;
113
112
  const predefinedMessage = config.predefinedMessage ?? 'Run workflow';
114
- console.log('[Playground] Auto-run triggered with message:', predefinedMessage);
113
+ logger.debug('[Playground] Auto-run triggered with message:', predefinedMessage);
115
114
  await handleSendMessage(predefinedMessage);
116
115
  }
117
116
  } catch (err) {
118
- console.error('[Playground] Initialization error:', err);
117
+ logger.error('[Playground] Initialization error:', err);
119
118
  }
120
119
  };
121
120
 
@@ -139,8 +138,8 @@
139
138
  }
140
139
 
141
140
  // Skip if sessions haven't been loaded yet (will be handled by onMount)
142
- const sessionList = get(sessions);
143
- if (sessionList.length === 0 && get(isLoading)) {
141
+ const sessionList = getSessions();
142
+ if (sessionList.length === 0 && getIsLoading()) {
144
143
  return;
145
144
  }
146
145
 
@@ -157,11 +156,11 @@
157
156
  */
158
157
  async function loadInitialSession(sessionId: string): Promise<void> {
159
158
  // Validate session exists in loaded sessions
160
- const sessionList = get(sessions);
159
+ const sessionList = getSessions();
161
160
  const sessionExists = sessionList.some((s) => s.id === sessionId);
162
161
 
163
162
  if (!sessionExists) {
164
- console.warn(
163
+ logger.warn(
165
164
  `[Playground] Initial session "${sessionId}" not found in available sessions. ` +
166
165
  `Available sessions: ${sessionList.map((s) => s.id).join(', ') || 'none'}`
167
166
  );
@@ -176,7 +175,7 @@
176
175
  initialSessionLoaded = true;
177
176
  loadedInitialSessionId = sessionId;
178
177
  } catch (err) {
179
- console.error('[Playground] Failed to load initial session:', err);
178
+ logger.error('[Playground] Failed to load initial session:', err);
180
179
  // Mark as attempted to prevent retry loops
181
180
  initialSessionLoaded = true;
182
181
  loadedInitialSessionId = sessionId;
@@ -193,6 +192,20 @@
193
192
  interruptActions.reset();
194
193
  });
195
194
 
195
+ /**
196
+ * Close dropdown menu when clicking outside
197
+ */
198
+ $effect(() => {
199
+ if (!openMenuId) return;
200
+
201
+ function onDocumentClick() {
202
+ openMenuId = null;
203
+ }
204
+
205
+ document.addEventListener('click', onDocumentClick);
206
+ return () => document.removeEventListener('click', onDocumentClick);
207
+ });
208
+
196
209
  /**
197
210
  * Load sessions for the workflow
198
211
  */
@@ -206,7 +219,7 @@
206
219
  } catch (err) {
207
220
  const errorMessage = err instanceof Error ? err.message : 'Failed to load sessions';
208
221
  playgroundActions.setError(errorMessage);
209
- console.error('Failed to load sessions:', err);
222
+ logger.error('Failed to load sessions:', err);
210
223
  } finally {
211
224
  playgroundActions.setLoading(false);
212
225
  }
@@ -235,7 +248,7 @@
235
248
  } catch (err) {
236
249
  const errorMessage = err instanceof Error ? err.message : 'Failed to load session';
237
250
  playgroundActions.setError(errorMessage);
238
- console.error('Failed to load session:', err);
251
+ logger.error('Failed to load session:', err);
239
252
  } finally {
240
253
  playgroundActions.setLoading(false);
241
254
  }
@@ -249,7 +262,7 @@
249
262
  playgroundActions.setError(null);
250
263
 
251
264
  try {
252
- const sessionName = `Session ${get(sessions).length + 1}`;
265
+ const sessionName = `Session ${getSessions().length + 1}`;
253
266
  const session = await playgroundService.createSession(workflowId, sessionName);
254
267
  playgroundActions.addSession(session);
255
268
  playgroundActions.setCurrentSession(session);
@@ -257,7 +270,7 @@
257
270
  } catch (err) {
258
271
  const errorMessage = err instanceof Error ? err.message : 'Failed to create session';
259
272
  playgroundActions.setError(errorMessage);
260
- console.error('Failed to create session:', err);
273
+ logger.error('Failed to create session:', err);
261
274
  } finally {
262
275
  playgroundActions.setLoading(false);
263
276
  }
@@ -267,7 +280,7 @@
267
280
  * Select a session
268
281
  */
269
282
  async function handleSelectSession(sessionId: string): Promise<void> {
270
- const currentSessionId = get(currentSession)?.id;
283
+ const currentSessionId = getCurrentSession()?.id;
271
284
  if (currentSessionId === sessionId) {
272
285
  return;
273
286
  }
@@ -287,34 +300,31 @@
287
300
  playgroundActions.removeSession(sessionId);
288
301
 
289
302
  // If we deleted the current session, clear it
290
- if (get(currentSession)?.id === sessionId) {
303
+ if (getCurrentSession()?.id === sessionId) {
291
304
  playgroundService.stopPolling();
292
305
  }
293
- pendingDeleteId = null;
294
306
  } catch (err) {
295
307
  const errorMessage = err instanceof Error ? err.message : 'Failed to delete session';
296
308
  playgroundActions.setError(errorMessage);
297
- console.error('Failed to delete session:', err);
309
+ logger.error('Failed to delete session:', err);
298
310
  }
299
311
  }
300
312
 
301
313
  /**
302
- * Handle delete click - show confirmation or execute
314
+ * Toggle session dropdown menu
303
315
  */
304
- function handleDeleteClick(event: Event, sessionId: string): void {
316
+ function handleMenuToggle(event: Event, sessionId: string): void {
305
317
  event.stopPropagation();
306
- if (pendingDeleteId === sessionId) {
307
- // Confirm deletion
308
- void handleDeleteSession(sessionId);
309
- } else {
310
- pendingDeleteId = sessionId;
311
- // Auto-reset after 3 seconds
312
- setTimeout(() => {
313
- if (pendingDeleteId === sessionId) {
314
- pendingDeleteId = null;
315
- }
316
- }, 3000);
317
- }
318
+ openMenuId = openMenuId === sessionId ? null : sessionId;
319
+ }
320
+
321
+ /**
322
+ * Handle delete from dropdown menu
323
+ */
324
+ function handleMenuDelete(event: Event, sessionId: string): void {
325
+ event.stopPropagation();
326
+ openMenuId = null;
327
+ void handleDeleteSession(sessionId);
318
328
  }
319
329
 
320
330
  /**
@@ -326,7 +336,7 @@
326
336
  playgroundActions.setCurrentSession(null);
327
337
  playgroundActions.clearMessages();
328
338
  // Clear interrupts for this session
329
- const sessionId = get(currentSession)?.id;
339
+ const sessionId = getCurrentSession()?.id;
330
340
  if (sessionId) {
331
341
  interruptActions.clearSessionInterrupts(sessionId);
332
342
  }
@@ -336,17 +346,17 @@
336
346
  * Send a message
337
347
  */
338
348
  async function handleSendMessage(content: string): Promise<void> {
339
- const session = get(currentSession);
349
+ const session = getCurrentSession();
340
350
  if (!session) {
341
351
  // Create a session first if none exists
342
352
  await handleCreateSession();
343
- const newSession = get(currentSession);
353
+ const newSession = getCurrentSession();
344
354
  if (!newSession) {
345
355
  return;
346
356
  }
347
357
  }
348
358
 
349
- const sessionId = get(currentSession)?.id;
359
+ const sessionId = getCurrentSession()?.id;
350
360
  if (!sessionId) {
351
361
  return;
352
362
  }
@@ -357,7 +367,7 @@
357
367
  try {
358
368
  // Prepare inputs from the input collector
359
369
  const inputs: Record<string, unknown> = {};
360
- const fields = get(inputFields);
370
+ const fields = getInputFields();
361
371
 
362
372
  fields.forEach((field) => {
363
373
  const key = `${field.nodeId}:${field.fieldId}`;
@@ -383,7 +393,7 @@
383
393
  const errorMessage = err instanceof Error ? err.message : 'Failed to send message';
384
394
  playgroundActions.setError(errorMessage);
385
395
  playgroundActions.setExecuting(false);
386
- console.error('Failed to send message:', err);
396
+ logger.error('Failed to send message:', err);
387
397
  }
388
398
  }
389
399
 
@@ -391,7 +401,7 @@
391
401
  * Stop execution
392
402
  */
393
403
  async function handleStopExecution(): Promise<void> {
394
- const sessionId = get(currentSession)?.id;
404
+ const sessionId = getCurrentSession()?.id;
395
405
  if (!sessionId) {
396
406
  return;
397
407
  }
@@ -404,7 +414,7 @@
404
414
  } catch (err) {
405
415
  const errorMessage = err instanceof Error ? err.message : 'Failed to stop execution';
406
416
  playgroundActions.setError(errorMessage);
407
- console.error('Failed to stop execution:', err);
417
+ logger.error('Failed to stop execution:', err);
408
418
  }
409
419
  }
410
420
 
@@ -430,14 +440,14 @@
430
440
  * Called after interrupt resolution when polling has stopped
431
441
  */
432
442
  async function handleInterruptResolved(): Promise<void> {
433
- const sessionId = get(currentSession)?.id;
443
+ const sessionId = getCurrentSession()?.id;
434
444
  if (!sessionId) return;
435
445
 
436
446
  try {
437
447
  const response = await playgroundService.getMessages(sessionId);
438
448
  pollingCallback(response);
439
449
  } catch (err) {
440
- console.error('[Playground] Failed to refresh messages after interrupt:', err);
450
+ logger.error('[Playground] Failed to refresh messages after interrupt:', err);
441
451
  }
442
452
  }
443
453
 
@@ -481,7 +491,10 @@
481
491
  <div class="playground__container">
482
492
  <!-- Sidebar (conditionally rendered based on config.showSidebar) -->
483
493
  {#if config.showSidebar !== false}
484
- <aside class="playground__sidebar">
494
+ <aside
495
+ class="playground__sidebar"
496
+ style={config.sidebarWidth ? `--fd-playground-sidebar-width: ${config.sidebarWidth}` : ''}
497
+ >
485
498
  <!-- Sidebar Header -->
486
499
  <div class="playground__sidebar-header">
487
500
  <div class="playground__sidebar-title">
@@ -509,7 +522,7 @@
509
522
  type="button"
510
523
  class="playground__new-session-btn"
511
524
  onclick={handleCreateSession}
512
- disabled={$isLoading}
525
+ disabled={getIsLoading()}
513
526
  title="Start a new session"
514
527
  >
515
528
  <Icon icon="mdi:plus" />
@@ -518,19 +531,19 @@
518
531
 
519
532
  <!-- Sessions List - click a session to load it -->
520
533
  <div class="playground__sessions-wrap">
521
- {#if $sessions.length > 0}
534
+ {#if getSessions().length > 0}
522
535
  <p class="playground__sessions-hint">Click a session to load it</p>
523
536
  {/if}
524
537
  <div class="playground__sessions">
525
- {#if $sessions.length === 0 && !$isLoading}
538
+ {#if getSessions().length === 0 && !getIsLoading()}
526
539
  <div class="playground__sessions-empty">
527
540
  <span>No sessions yet</span>
528
541
  </div>
529
542
  {:else}
530
- {#each $sessions as session (session.id)}
543
+ {#each getSessions() as session (session.id)}
531
544
  <div
532
545
  class="playground__session"
533
- class:playground__session--active={$currentSession?.id === session.id}
546
+ class:playground__session--active={getCurrentSession()?.id === session.id}
534
547
  role="button"
535
548
  tabindex="0"
536
549
  title="Click to load this session"
@@ -541,21 +554,29 @@
541
554
  <span class="playground__session-name" title={session.name}>
542
555
  {session.name}
543
556
  </span>
544
- <button
545
- type="button"
546
- class="playground__session-menu"
547
- class:playground__session-menu--delete={pendingDeleteId === session.id}
548
- onclick={(e) => handleDeleteClick(e, session.id)}
549
- title={pendingDeleteId === session.id
550
- ? 'Click to confirm delete'
551
- : 'Delete session'}
552
- >
553
- {#if pendingDeleteId === session.id}
554
- <Icon icon="mdi:check" />
555
- {:else}
556
- <Icon icon="mdi:dots-horizontal" />
557
+ <div class="playground__session-actions">
558
+ <button
559
+ type="button"
560
+ class="playground__session-menu"
561
+ class:playground__session-menu--open={openMenuId === session.id}
562
+ onclick={(e) => handleMenuToggle(e, session.id)}
563
+ title="Session options"
564
+ >
565
+ <Icon icon="mdi:dots-vertical" />
566
+ </button>
567
+ {#if openMenuId === session.id}
568
+ <div class="playground__session-dropdown">
569
+ <button
570
+ type="button"
571
+ class="playground__session-dropdown-item playground__session-dropdown-item--danger"
572
+ onclick={(e) => handleMenuDelete(e, session.id)}
573
+ >
574
+ <Icon icon="mdi:delete-outline" />
575
+ <span>Delete</span>
576
+ </button>
577
+ </div>
557
578
  {/if}
558
- </button>
579
+ </div>
559
580
  </div>
560
581
  {/each}
561
582
  {/if}
@@ -568,9 +589,9 @@
568
589
  <!-- Main Content -->
569
590
  <main class="playground__main">
570
591
  <!-- Session Header (conditionally rendered based on config.showSessionHeader) -->
571
- {#if $currentSession && config.showSessionHeader !== false}
592
+ {#if getCurrentSession() && config.showSessionHeader !== false}
572
593
  <header class="playground__header">
573
- <h2 class="playground__header-title">{$currentSession.name}</h2>
594
+ <h2 class="playground__header-title">{getCurrentSession()?.name}</h2>
574
595
  <button
575
596
  type="button"
576
597
  class="playground__header-close"
@@ -583,10 +604,10 @@
583
604
  {/if}
584
605
 
585
606
  <!-- Error Banner -->
586
- {#if $error}
607
+ {#if getError()}
587
608
  <div class="playground__error">
588
609
  <Icon icon="mdi:alert-circle" />
589
- <span>{$error}</span>
610
+ <span>{getError()}</span>
590
611
  <button
591
612
  type="button"
592
613
  class="playground__error-dismiss"
@@ -599,7 +620,7 @@
599
620
 
600
621
  <!-- Chat Content -->
601
622
  <div class="playground__content">
602
- {#if $isLoading && !$currentSession}
623
+ {#if getIsLoading() && !getCurrentSession()}
603
624
  <div class="playground__loading">
604
625
  <Icon icon="mdi:loading" class="playground__loading-icon" />
605
626
  <span>Loading...</span>
@@ -668,7 +689,7 @@
668
689
 
669
690
  /* Sidebar */
670
691
  .playground__sidebar {
671
- width: 220px;
692
+ width: var(--fd-playground-sidebar-width);
672
693
  background-color: var(--fd-background);
673
694
  border-right: 1px solid var(--fd-border);
674
695
  display: flex;
@@ -680,8 +701,8 @@
680
701
  display: flex;
681
702
  align-items: center;
682
703
  justify-content: space-between;
683
- height: 3.25rem;
684
- padding: 0 1rem;
704
+ height: var(--fd-playground-header-height);
705
+ padding: 0 var(--fd-space-xl);
685
706
  border-bottom: 1px solid var(--fd-border);
686
707
  box-sizing: border-box;
687
708
  flex-shrink: 0;
@@ -690,8 +711,8 @@
690
711
  .playground__sidebar-title {
691
712
  display: flex;
692
713
  align-items: center;
693
- gap: 0.5rem;
694
- font-size: 0.9375rem;
714
+ gap: var(--fd-space-xs);
715
+ font-size: var(--fd-text-md);
695
716
  font-weight: 600;
696
717
  line-height: 1.25;
697
718
  color: var(--fd-foreground);
@@ -701,14 +722,14 @@
701
722
  display: flex;
702
723
  align-items: center;
703
724
  justify-content: center;
704
- width: 1.75rem;
705
- height: 1.75rem;
725
+ width: var(--fd-playground-icon-btn-size);
726
+ height: var(--fd-playground-icon-btn-size);
706
727
  border: none;
707
- border-radius: 0.375rem;
728
+ border-radius: var(--fd-radius-md);
708
729
  background: transparent;
709
730
  color: var(--fd-muted-foreground);
710
731
  cursor: pointer;
711
- transition: all 0.15s ease;
732
+ transition: all var(--fd-transition-fast);
712
733
  }
713
734
 
714
735
  .playground__sidebar-close:hover {
@@ -722,7 +743,7 @@
722
743
  display: flex;
723
744
  flex-direction: column;
724
745
  min-height: 0;
725
- padding: 0.75rem 0.5rem 0;
746
+ padding: var(--fd-space-md) var(--fd-space-xs) 0;
726
747
  }
727
748
 
728
749
  /* New Session – neutral full-width button with icon */
@@ -730,19 +751,19 @@
730
751
  display: flex;
731
752
  align-items: center;
732
753
  justify-content: center;
733
- gap: 0.5rem;
754
+ gap: var(--fd-space-xs);
734
755
  width: 100%;
735
- padding: 0.625rem 1rem;
756
+ padding: var(--fd-space-sm) var(--fd-space-xl);
736
757
  border: 1px solid var(--fd-border);
737
758
  border-radius: var(--fd-radius-md);
738
759
  background-color: var(--fd-background);
739
760
  color: var(--fd-foreground);
740
- font-size: 0.875rem;
761
+ font-size: var(--fd-text-sm);
741
762
  font-weight: 500;
742
763
  cursor: pointer;
743
764
  transition:
744
- background-color 0.15s ease,
745
- border-color 0.15s ease,
765
+ background-color var(--fd-transition-fast),
766
+ border-color var(--fd-transition-fast),
746
767
  transform 0.1s ease;
747
768
  box-sizing: border-box;
748
769
  }
@@ -778,23 +799,23 @@
778
799
  }
779
800
 
780
801
  .playground__sessions-hint {
781
- font-size: 0.6875rem;
802
+ font-size: var(--fd-text-2xs);
782
803
  color: var(--fd-muted-foreground);
783
- margin: 0.75rem 0 0.375rem 0.75rem;
804
+ margin: var(--fd-space-md) 0 var(--fd-space-2xs) var(--fd-space-md);
784
805
  line-height: 1.3;
785
806
  }
786
807
 
787
808
  .playground__sessions {
788
809
  flex: 1;
789
810
  overflow-y: auto;
790
- padding: 0 0.5rem 1rem;
811
+ padding: 0 var(--fd-space-xs) var(--fd-space-xl);
791
812
  min-height: 0;
792
813
  }
793
814
 
794
815
  .playground__sessions-empty {
795
- padding: 1rem;
816
+ padding: var(--fd-space-xl);
796
817
  text-align: center;
797
- font-size: 0.8125rem;
818
+ font-size: var(--fd-text-xsm);
798
819
  color: var(--fd-muted-foreground);
799
820
  }
800
821
 
@@ -803,14 +824,14 @@
803
824
  display: flex;
804
825
  align-items: center;
805
826
  justify-content: space-between;
806
- padding: 0.625rem 0.75rem;
807
- margin-bottom: 0.25rem;
827
+ padding: var(--fd-space-sm) var(--fd-space-md);
828
+ margin-bottom: var(--fd-space-3xs);
808
829
  border-radius: var(--fd-radius-md);
809
830
  border-left: 3px solid transparent;
810
831
  cursor: pointer;
811
832
  transition:
812
- background-color 0.15s ease,
813
- border-left-color 0.15s ease;
833
+ background-color var(--fd-transition-fast),
834
+ border-left-color var(--fd-transition-fast);
814
835
  }
815
836
 
816
837
  .playground__session:hover {
@@ -830,7 +851,7 @@
830
851
 
831
852
  .playground__session-name {
832
853
  flex: 1;
833
- font-size: 0.875rem;
854
+ font-size: var(--fd-text-sm);
834
855
  color: var(--fd-foreground);
835
856
  white-space: nowrap;
836
857
  overflow: hidden;
@@ -846,15 +867,15 @@
846
867
  display: flex;
847
868
  align-items: center;
848
869
  justify-content: center;
849
- width: 1.5rem;
850
- height: 1.5rem;
870
+ width: var(--fd-space-3xl);
871
+ height: var(--fd-space-3xl);
851
872
  border: none;
852
- border-radius: 0.25rem;
873
+ border-radius: var(--fd-radius-sm);
853
874
  background: transparent;
854
875
  color: var(--fd-muted-foreground);
855
876
  cursor: pointer;
856
877
  opacity: 0;
857
- transition: all 0.15s ease;
878
+ transition: all var(--fd-transition-fast);
858
879
  }
859
880
 
860
881
  .playground__session:hover .playground__session-menu {
@@ -862,19 +883,63 @@
862
883
  }
863
884
 
864
885
  .playground__session-menu:hover {
865
- background-color: var(--fd-error-muted);
866
- color: var(--fd-error);
886
+ background-color: var(--fd-muted);
887
+ color: var(--fd-foreground);
867
888
  }
868
889
 
869
- .playground__session-menu--delete {
890
+ .playground__session-menu--open {
870
891
  opacity: 1;
871
- background-color: var(--fd-success-muted);
872
- color: var(--fd-success);
892
+ background-color: var(--fd-muted);
893
+ color: var(--fd-foreground);
873
894
  }
874
895
 
875
- .playground__session-menu--delete:hover {
876
- background-color: var(--fd-success-muted);
877
- color: var(--fd-success-hover);
896
+ .playground__session-actions {
897
+ position: relative;
898
+ display: flex;
899
+ align-items: center;
900
+ flex-shrink: 0;
901
+ }
902
+
903
+ .playground__session-dropdown {
904
+ position: absolute;
905
+ top: 100%;
906
+ right: 0;
907
+ z-index: 50;
908
+ min-width: 140px;
909
+ padding: var(--fd-space-xs);
910
+ background-color: var(--fd-background);
911
+ border: 1px solid var(--fd-border);
912
+ border-radius: var(--fd-radius-md);
913
+ box-shadow: var(--fd-shadow-lg);
914
+ }
915
+
916
+ .playground__session-dropdown-item {
917
+ display: flex;
918
+ align-items: center;
919
+ gap: var(--fd-space-sm);
920
+ width: 100%;
921
+ padding: var(--fd-space-sm) var(--fd-space-md);
922
+ border: none;
923
+ border-radius: var(--fd-radius-sm);
924
+ background: transparent;
925
+ color: var(--fd-foreground);
926
+ font-size: var(--fd-text-sm);
927
+ cursor: pointer;
928
+ transition: all var(--fd-transition-fast);
929
+ white-space: nowrap;
930
+ }
931
+
932
+ .playground__session-dropdown-item:hover {
933
+ background-color: var(--fd-muted);
934
+ }
935
+
936
+ .playground__session-dropdown-item--danger {
937
+ color: var(--fd-error);
938
+ }
939
+
940
+ .playground__session-dropdown-item--danger:hover {
941
+ background-color: var(--fd-error-muted);
942
+ color: var(--fd-error);
878
943
  }
879
944
 
880
945
  /* Main Content */
@@ -893,8 +958,8 @@
893
958
  display: flex;
894
959
  align-items: center;
895
960
  justify-content: space-between;
896
- height: 3.25rem;
897
- padding: 0 1.25rem;
961
+ height: var(--fd-playground-header-height);
962
+ padding: 0 var(--fd-space-2xl);
898
963
  border-bottom: 1px solid var(--fd-border);
899
964
  background-color: var(--fd-background);
900
965
  box-sizing: border-box;
@@ -902,7 +967,7 @@
902
967
  }
903
968
 
904
969
  .playground__header-title {
905
- font-size: 0.9375rem;
970
+ font-size: var(--fd-text-md);
906
971
  font-weight: 600;
907
972
  line-height: 1.25;
908
973
  color: var(--fd-foreground);
@@ -913,14 +978,14 @@
913
978
  display: flex;
914
979
  align-items: center;
915
980
  justify-content: center;
916
- width: 1.75rem;
917
- height: 1.75rem;
981
+ width: var(--fd-playground-icon-btn-size);
982
+ height: var(--fd-playground-icon-btn-size);
918
983
  border: none;
919
- border-radius: 0.375rem;
984
+ border-radius: var(--fd-radius-md);
920
985
  background: transparent;
921
986
  color: var(--fd-muted-foreground);
922
987
  cursor: pointer;
923
- transition: all 0.15s ease;
988
+ transition: all var(--fd-transition-fast);
924
989
  }
925
990
 
926
991
  .playground__header-close:hover {
@@ -932,12 +997,12 @@
932
997
  .playground__error {
933
998
  display: flex;
934
999
  align-items: center;
935
- gap: 0.5rem;
936
- padding: 0.75rem 1rem;
1000
+ gap: var(--fd-space-xs);
1001
+ padding: var(--fd-space-md) var(--fd-space-xl);
937
1002
  background-color: var(--fd-error-muted);
938
1003
  border-bottom: 1px solid var(--fd-error);
939
1004
  color: var(--fd-error);
940
- font-size: 0.875rem;
1005
+ font-size: var(--fd-text-sm);
941
1006
  }
942
1007
 
943
1008
  .playground__error-dismiss {
@@ -945,14 +1010,14 @@
945
1010
  display: flex;
946
1011
  align-items: center;
947
1012
  justify-content: center;
948
- width: 1.5rem;
949
- height: 1.5rem;
1013
+ width: var(--fd-space-3xl);
1014
+ height: var(--fd-space-3xl);
950
1015
  border: none;
951
- border-radius: 0.25rem;
1016
+ border-radius: var(--fd-radius-sm);
952
1017
  background: transparent;
953
1018
  color: var(--fd-error);
954
1019
  cursor: pointer;
955
- transition: background-color 0.15s ease;
1020
+ transition: background-color var(--fd-transition-fast);
956
1021
  }
957
1022
 
958
1023
  .playground__error-dismiss:hover {
@@ -974,12 +1039,12 @@
974
1039
  align-items: center;
975
1040
  justify-content: center;
976
1041
  flex: 1;
977
- gap: 1rem;
1042
+ gap: var(--fd-space-xl);
978
1043
  color: var(--fd-muted-foreground);
979
1044
  }
980
1045
 
981
1046
  :global(.playground__loading-icon) {
982
- font-size: 2rem;
1047
+ font-size: var(--fd-text-2xl);
983
1048
  animation: spin 1s linear infinite;
984
1049
  }
985
1050