@d34dman/flowdrop 0.0.60 → 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 (207) 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 +203 -172
  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 +5 -4
  139. package/dist/playground/index.js +15 -11
  140. package/dist/playground/mount.d.ts +20 -1
  141. package/dist/playground/mount.js +24 -6
  142. package/dist/services/agentSpecExecutionService.js +2 -1
  143. package/dist/services/api.js +10 -18
  144. package/dist/services/apiVariableService.js +2 -1
  145. package/dist/services/autoSaveService.d.ts +3 -3
  146. package/dist/services/autoSaveService.js +21 -17
  147. package/dist/services/categoriesApi.js +13 -5
  148. package/dist/services/draftStorage.js +5 -4
  149. package/dist/services/dynamicSchemaService.js +4 -4
  150. package/dist/services/globalSave.d.ts +60 -11
  151. package/dist/services/globalSave.js +160 -83
  152. package/dist/services/historyService.d.ts +2 -1
  153. package/dist/services/historyService.js +7 -3
  154. package/dist/services/interruptService.js +9 -8
  155. package/dist/services/nodeExecutionService.js +14 -6
  156. package/dist/services/playgroundService.d.ts +3 -2
  157. package/dist/services/playgroundService.js +8 -7
  158. package/dist/services/portConfigApi.js +11 -7
  159. package/dist/services/toastService.d.ts +1 -1
  160. package/dist/services/toastService.js +6 -5
  161. package/dist/services/variableService.js +3 -2
  162. package/dist/settings/index.d.ts +1 -1
  163. package/dist/settings/index.js +1 -1
  164. package/dist/stores/{categoriesStore.d.ts → categoriesStore.svelte.d.ts} +3 -3
  165. package/dist/stores/{categoriesStore.js → categoriesStore.svelte.js} +15 -18
  166. package/dist/stores/editorStateMachine.svelte.d.ts +42 -0
  167. package/dist/stores/editorStateMachine.svelte.js +132 -0
  168. package/dist/stores/{historyStore.d.ts → historyStore.svelte.d.ts} +18 -15
  169. package/dist/stores/{historyStore.js → historyStore.svelte.js} +40 -21
  170. package/dist/stores/{interruptStore.d.ts → interruptStore.svelte.d.ts} +16 -15
  171. package/dist/stores/{interruptStore.js → interruptStore.svelte.js} +85 -94
  172. package/dist/stores/{playgroundStore.d.ts → playgroundStore.svelte.d.ts} +52 -34
  173. package/dist/stores/{playgroundStore.js → playgroundStore.svelte.js} +193 -100
  174. package/dist/stores/{portCoordinateStore.d.ts → portCoordinateStore.svelte.d.ts} +10 -4
  175. package/dist/stores/{portCoordinateStore.js → portCoordinateStore.svelte.js} +38 -35
  176. package/dist/stores/{settingsStore.d.ts → settingsStore.svelte.d.ts} +45 -28
  177. package/dist/stores/{settingsStore.js → settingsStore.svelte.js} +169 -128
  178. package/dist/stores/{workflowStore.d.ts → workflowStore.svelte.d.ts} +101 -65
  179. package/dist/stores/{workflowStore.js → workflowStore.svelte.js} +285 -239
  180. package/dist/stories/CanvasDecorator.svelte +50 -0
  181. package/dist/stories/CanvasDecorator.svelte.d.ts +8 -0
  182. package/dist/stories/NodeDecorator.svelte +74 -0
  183. package/dist/stories/NodeDecorator.svelte.d.ts +8 -0
  184. package/dist/stories/utils.d.ts +93 -0
  185. package/dist/stories/utils.js +122 -0
  186. package/dist/styles/base.css +114 -61
  187. package/dist/styles/toast.css +2 -2
  188. package/dist/styles/tokens.css +250 -185
  189. package/dist/svelte-app.d.ts +0 -6
  190. package/dist/svelte-app.js +13 -31
  191. package/dist/types/index.d.ts +2 -0
  192. package/dist/types/interrupt.d.ts +89 -5
  193. package/dist/types/interrupt.js +13 -1
  194. package/dist/types/playground.d.ts +42 -1
  195. package/dist/types/playground.js +38 -0
  196. package/dist/types/settings.js +1 -1
  197. package/dist/utils/colors.js +4 -4
  198. package/dist/utils/connections.js +33 -8
  199. package/dist/utils/icons.js +1 -1
  200. package/dist/utils/logger.d.ts +47 -0
  201. package/dist/utils/logger.js +72 -0
  202. package/dist/utils/nodeWrapper.js +1 -1
  203. package/dist/utils/sanitize.d.ts +19 -0
  204. package/dist/utils/sanitize.js +31 -0
  205. package/dist/utils/validation.d.ts +29 -0
  206. package/dist/utils/validation.js +39 -0
  207. package/package.json +243 -232
@@ -1,84 +1,146 @@
1
1
  /**
2
2
  * Playground Store
3
3
  *
4
- * Svelte stores for managing playground state including sessions,
4
+ * Svelte 5 rune-based state for managing playground state including sessions,
5
5
  * messages, and execution status.
6
6
  *
7
7
  * @module stores/playgroundStore
8
8
  */
9
- import { writable, derived, get } from 'svelte/store';
10
- import { isChatInputNode } from '../types/playground.js';
9
+ import { isChatInputNode, defaultIsTerminalStatus } from '../types/playground.js';
10
+ import { logger } from '../utils/logger.js';
11
11
  // =========================================================================
12
- // Core Stores
12
+ // Core State
13
13
  // =========================================================================
14
14
  /**
15
15
  * Currently active playground session
16
16
  */
17
- export const currentSession = writable(null);
17
+ let _currentSession = $state(null);
18
18
  /**
19
19
  * List of all sessions for the current workflow
20
20
  */
21
- export const sessions = writable([]);
21
+ let _sessions = $state([]);
22
22
  /**
23
23
  * Messages in the current session
24
24
  */
25
- export const messages = writable([]);
25
+ let _messages = $state([]);
26
26
  /**
27
27
  * Whether an execution is currently running
28
28
  */
29
- export const isExecuting = writable(false);
29
+ let _isExecuting = $state(false);
30
30
  /**
31
31
  * Whether we are currently loading data
32
32
  */
33
- export const isLoading = writable(false);
33
+ let _isLoading = $state(false);
34
34
  /**
35
35
  * Current error message, if any
36
36
  */
37
- export const error = writable(null);
37
+ let _error = $state(null);
38
38
  /**
39
39
  * Current workflow being tested
40
40
  */
41
- export const currentWorkflow = writable(null);
41
+ let _currentWorkflow = $state(null);
42
42
  /**
43
43
  * Last polling timestamp for incremental message fetching
44
44
  */
45
- export const lastPollTimestamp = writable(null);
45
+ let _lastPollTimestamp = $state(null);
46
46
  // =========================================================================
47
- // Derived Stores
47
+ // Getter Functions (for reactive access in components)
48
48
  // =========================================================================
49
49
  /**
50
- * Derived store for current session status
50
+ * Get the current session
51
51
  */
52
- export const sessionStatus = derived(currentSession, ($session) => $session?.status ?? 'idle');
52
+ export function getCurrentSession() {
53
+ return _currentSession;
54
+ }
55
+ /**
56
+ * Get all sessions
57
+ */
58
+ export function getSessions() {
59
+ return _sessions;
60
+ }
61
+ /**
62
+ * Get all messages
63
+ */
64
+ export function getMessages() {
65
+ return _messages;
66
+ }
67
+ /**
68
+ * Get executing state
69
+ */
70
+ export function getIsExecuting() {
71
+ return _isExecuting;
72
+ }
73
+ /**
74
+ * Get loading state
75
+ */
76
+ export function getIsLoading() {
77
+ return _isLoading;
78
+ }
79
+ /**
80
+ * Get error state
81
+ */
82
+ export function getError() {
83
+ return _error;
84
+ }
53
85
  /**
54
- * Derived store for message count
86
+ * Get the current workflow
55
87
  */
56
- export const messageCount = derived(messages, ($messages) => $messages.length);
88
+ export function getCurrentWorkflow() {
89
+ return _currentWorkflow;
90
+ }
91
+ /**
92
+ * Get the last poll timestamp
93
+ */
94
+ export function getLastPollTimestamp() {
95
+ return _lastPollTimestamp;
96
+ }
97
+ // =========================================================================
98
+ // Derived Getters
99
+ // =========================================================================
100
+ /**
101
+ * Get current session status
102
+ */
103
+ export function getSessionStatus() {
104
+ return _currentSession?.status ?? 'idle';
105
+ }
106
+ /**
107
+ * Get message count
108
+ */
109
+ export function getMessageCount() {
110
+ return _messages.length;
111
+ }
57
112
  /**
58
- * Derived store for chat messages (excludes log messages)
113
+ * Get chat messages (excludes log messages)
59
114
  */
60
- export const chatMessages = derived(messages, ($messages) => $messages.filter((m) => m.role !== 'log'));
115
+ export function getChatMessages() {
116
+ return _messages.filter((m) => m.role !== 'log');
117
+ }
61
118
  /**
62
- * Derived store for log messages only
119
+ * Get log messages only
63
120
  */
64
- export const logMessages = derived(messages, ($messages) => $messages.filter((m) => m.role === 'log'));
121
+ export function getLogMessages() {
122
+ return _messages.filter((m) => m.role === 'log');
123
+ }
65
124
  /**
66
- * Derived store for the latest message
125
+ * Get the latest message
67
126
  */
68
- export const latestMessage = derived(messages, ($messages) => $messages.length > 0 ? $messages[$messages.length - 1] : null);
127
+ export function getLatestMessage() {
128
+ return _messages.length > 0 ? _messages[_messages.length - 1] : null;
129
+ }
69
130
  /**
70
- * Derived store for input fields from workflow input nodes
131
+ * Get input fields from workflow input nodes
71
132
  *
72
133
  * Analyzes the workflow to extract input nodes and their configuration
73
134
  * schemas for auto-generating input forms.
74
135
  */
75
- export const inputFields = derived(currentWorkflow, ($workflow) => {
76
- if (!$workflow) {
136
+ export function getInputFields() {
137
+ const workflow = _currentWorkflow;
138
+ if (!workflow) {
77
139
  return [];
78
140
  }
79
141
  const fields = [];
80
142
  // Find input nodes in the workflow
81
- $workflow.nodes.forEach((node) => {
143
+ workflow.nodes.forEach((node) => {
82
144
  const category = node.data.metadata?.category;
83
145
  const nodeTypeId = node.data.metadata?.id ?? node.type;
84
146
  // Check if this is an input-type node
@@ -128,15 +190,20 @@ export const inputFields = derived(currentWorkflow, ($workflow) => {
128
190
  }
129
191
  });
130
192
  return fields;
131
- });
193
+ }
132
194
  /**
133
- * Derived store for detecting if workflow has a chat input
195
+ * Check if workflow has a chat input
134
196
  */
135
- export const hasChatInput = derived(inputFields, ($fields) => $fields.some((field) => isChatInputNode(field.nodeId) || field.type === 'string'));
197
+ export function getHasChatInput() {
198
+ const fields = getInputFields();
199
+ return fields.some((field) => isChatInputNode(field.nodeId) || field.type === 'string');
200
+ }
136
201
  /**
137
- * Derived store for session count
202
+ * Get session count
138
203
  */
139
- export const sessionCount = derived(sessions, ($sessions) => $sessions.length);
204
+ export function getSessionCount() {
205
+ return _sessions.length;
206
+ }
140
207
  // =========================================================================
141
208
  // Helper Functions
142
209
  // =========================================================================
@@ -184,7 +251,7 @@ export const playgroundActions = {
184
251
  * @param workflow - The workflow to test
185
252
  */
186
253
  setWorkflow: (workflow) => {
187
- currentWorkflow.set(workflow);
254
+ _currentWorkflow = workflow;
188
255
  },
189
256
  /**
190
257
  * Set the current session
@@ -192,10 +259,10 @@ export const playgroundActions = {
192
259
  * @param session - The session to set as active
193
260
  */
194
261
  setCurrentSession: (session) => {
195
- currentSession.set(session);
262
+ _currentSession = session;
196
263
  if (session) {
197
264
  // Update session in the list
198
- sessions.update(($sessions) => $sessions.map((s) => (s.id === session.id ? session : s)));
265
+ _sessions = _sessions.map((s) => (s.id === session.id ? session : s));
199
266
  }
200
267
  },
201
268
  /**
@@ -204,15 +271,13 @@ export const playgroundActions = {
204
271
  * @param status - The new status
205
272
  */
206
273
  updateSessionStatus: (status) => {
207
- currentSession.update(($session) => {
208
- if (!$session)
209
- return null;
210
- return { ...$session, status, updatedAt: new Date().toISOString() };
211
- });
274
+ if (_currentSession) {
275
+ _currentSession = { ..._currentSession, status, updatedAt: new Date().toISOString() };
276
+ }
212
277
  // Also update in sessions list
213
- const session = get(currentSession);
278
+ const session = _currentSession;
214
279
  if (session) {
215
- sessions.update(($sessions) => $sessions.map((s) => (s.id === session.id ? { ...s, status } : s)));
280
+ _sessions = _sessions.map((s) => (s.id === session.id ? { ...s, status } : s));
216
281
  }
217
282
  },
218
283
  /**
@@ -221,7 +286,7 @@ export const playgroundActions = {
221
286
  * @param sessionList - Array of sessions
222
287
  */
223
288
  setSessions: (sessionList) => {
224
- sessions.set(sessionList);
289
+ _sessions = sessionList;
225
290
  },
226
291
  /**
227
292
  * Add a new session to the list
@@ -229,7 +294,7 @@ export const playgroundActions = {
229
294
  * @param session - The session to add
230
295
  */
231
296
  addSession: (session) => {
232
- sessions.update(($sessions) => [session, ...$sessions]);
297
+ _sessions = [session, ..._sessions];
233
298
  },
234
299
  /**
235
300
  * Remove a session from the list
@@ -237,12 +302,11 @@ export const playgroundActions = {
237
302
  * @param sessionId - The session ID to remove
238
303
  */
239
304
  removeSession: (sessionId) => {
240
- sessions.update(($sessions) => $sessions.filter((s) => s.id !== sessionId));
305
+ _sessions = _sessions.filter((s) => s.id !== sessionId);
241
306
  // Clear current session if it was removed
242
- const current = get(currentSession);
243
- if (current?.id === sessionId) {
244
- currentSession.set(null);
245
- messages.set([]);
307
+ if (_currentSession?.id === sessionId) {
308
+ _currentSession = null;
309
+ _messages = [];
246
310
  }
247
311
  },
248
312
  /**
@@ -252,7 +316,7 @@ export const playgroundActions = {
252
316
  * @param messageList - Array of messages
253
317
  */
254
318
  setMessages: (messageList) => {
255
- messages.set(sortMessagesChronologically(messageList));
319
+ _messages = sortMessagesChronologically(messageList);
256
320
  },
257
321
  /**
258
322
  * Add a message to the current session
@@ -261,7 +325,7 @@ export const playgroundActions = {
261
325
  * @param message - The message to add
262
326
  */
263
327
  addMessage: (message) => {
264
- messages.update(($messages) => sortMessagesChronologically([...$messages, message]));
328
+ _messages = sortMessagesChronologically([..._messages, message]);
265
329
  },
266
330
  /**
267
331
  * Add multiple messages to the current session
@@ -272,20 +336,18 @@ export const playgroundActions = {
272
336
  addMessages: (newMessages) => {
273
337
  if (newMessages.length === 0)
274
338
  return;
275
- messages.update(($messages) => {
276
- // Deduplicate by message ID
277
- const existingIds = new Set($messages.map((m) => m.id));
278
- const uniqueNewMessages = newMessages.filter((m) => !existingIds.has(m.id));
279
- // Sort the combined messages chronologically
280
- return sortMessagesChronologically([...$messages, ...uniqueNewMessages]);
281
- });
339
+ // Deduplicate by message ID
340
+ const existingIds = new Set(_messages.map((m) => m.id));
341
+ const uniqueNewMessages = newMessages.filter((m) => !existingIds.has(m.id));
342
+ // Sort the combined messages chronologically
343
+ _messages = sortMessagesChronologically([..._messages, ...uniqueNewMessages]);
282
344
  },
283
345
  /**
284
346
  * Clear all messages
285
347
  */
286
348
  clearMessages: () => {
287
- messages.set([]);
288
- lastPollTimestamp.set(null);
349
+ _messages = [];
350
+ _lastPollTimestamp = null;
289
351
  },
290
352
  /**
291
353
  * Set the executing state
@@ -293,7 +355,7 @@ export const playgroundActions = {
293
355
  * @param executing - Whether execution is in progress
294
356
  */
295
357
  setExecuting: (executing) => {
296
- isExecuting.set(executing);
358
+ _isExecuting = executing;
297
359
  },
298
360
  /**
299
361
  * Set the loading state
@@ -301,7 +363,7 @@ export const playgroundActions = {
301
363
  * @param loading - Whether loading is in progress
302
364
  */
303
365
  setLoading: (loading) => {
304
- isLoading.set(loading);
366
+ _isLoading = loading;
305
367
  },
306
368
  /**
307
369
  * Set an error message
@@ -309,7 +371,7 @@ export const playgroundActions = {
309
371
  * @param errorMessage - The error message or null to clear
310
372
  */
311
373
  setError: (errorMessage) => {
312
- error.set(errorMessage);
374
+ _error = errorMessage;
313
375
  },
314
376
  /**
315
377
  * Update the last poll timestamp
@@ -317,20 +379,20 @@ export const playgroundActions = {
317
379
  * @param timestamp - ISO 8601 timestamp
318
380
  */
319
381
  updateLastPollTimestamp: (timestamp) => {
320
- lastPollTimestamp.set(timestamp);
382
+ _lastPollTimestamp = timestamp;
321
383
  },
322
384
  /**
323
385
  * Reset all playground state
324
386
  */
325
387
  reset: () => {
326
- currentSession.set(null);
327
- sessions.set([]);
328
- messages.set([]);
329
- isExecuting.set(false);
330
- isLoading.set(false);
331
- error.set(null);
332
- currentWorkflow.set(null);
333
- lastPollTimestamp.set(null);
388
+ _currentSession = null;
389
+ _sessions = [];
390
+ _messages = [];
391
+ _isExecuting = false;
392
+ _isLoading = false;
393
+ _error = null;
394
+ _currentWorkflow = null;
395
+ _lastPollTimestamp = null;
334
396
  },
335
397
  /**
336
398
  * Switch to a different session
@@ -338,16 +400,39 @@ export const playgroundActions = {
338
400
  * @param sessionId - The session ID to switch to
339
401
  */
340
402
  switchSession: (sessionId) => {
341
- const sessionList = get(sessions);
342
- const session = sessionList.find((s) => s.id === sessionId);
403
+ const session = _sessions.find((s) => s.id === sessionId);
343
404
  if (session) {
344
- currentSession.set(session);
345
- messages.set([]);
346
- lastPollTimestamp.set(null);
405
+ _currentSession = session;
406
+ _messages = [];
407
+ _lastPollTimestamp = null;
347
408
  }
348
409
  }
349
410
  };
350
411
  // =========================================================================
412
+ // Polling Callback Factory
413
+ // =========================================================================
414
+ /**
415
+ * Create a polling callback that processes poll responses.
416
+ * This is the single source of truth for how poll responses update stores.
417
+ * Used by mount.ts, Playground.svelte, and refreshSessionMessages.
418
+ *
419
+ * @param isTerminalStatus - Function to determine if a status clears isExecuting (default: defaultIsTerminalStatus)
420
+ * @returns A callback suitable for playgroundService.startPolling() or pushMessages()
421
+ */
422
+ export function createPollingCallback(isTerminalStatus = defaultIsTerminalStatus) {
423
+ return (response) => {
424
+ if (response.data && response.data.length > 0) {
425
+ playgroundActions.addMessages(response.data);
426
+ }
427
+ if (response.sessionStatus) {
428
+ playgroundActions.updateSessionStatus(response.sessionStatus);
429
+ if (isTerminalStatus(response.sessionStatus)) {
430
+ playgroundActions.setExecuting(false);
431
+ }
432
+ }
433
+ };
434
+ }
435
+ // =========================================================================
351
436
  // Utilities
352
437
  // =========================================================================
353
438
  /**
@@ -356,7 +441,7 @@ export const playgroundActions = {
356
441
  * @returns The current session ID or null
357
442
  */
358
443
  export function getCurrentSessionId() {
359
- return get(currentSession)?.id ?? null;
444
+ return _currentSession?.id ?? null;
360
445
  }
361
446
  /**
362
447
  * Check if a specific session is selected
@@ -365,7 +450,7 @@ export function getCurrentSessionId() {
365
450
  * @returns True if the session is currently selected
366
451
  */
367
452
  export function isSessionSelected(sessionId) {
368
- return get(currentSession)?.id === sessionId;
453
+ return _currentSession?.id === sessionId;
369
454
  }
370
455
  /**
371
456
  * Get all messages as a snapshot
@@ -373,7 +458,7 @@ export function isSessionSelected(sessionId) {
373
458
  * @returns Array of all messages
374
459
  */
375
460
  export function getMessagesSnapshot() {
376
- return get(messages);
461
+ return _messages;
377
462
  }
378
463
  /**
379
464
  * Get the latest message timestamp for polling
@@ -381,10 +466,29 @@ export function getMessagesSnapshot() {
381
466
  * @returns ISO 8601 timestamp of the latest message, or null
382
467
  */
383
468
  export function getLatestMessageTimestamp() {
384
- const msgs = get(messages);
385
- if (msgs.length === 0)
469
+ if (_messages.length === 0)
386
470
  return null;
387
- return msgs[msgs.length - 1].timestamp;
471
+ return _messages[_messages.length - 1].timestamp;
472
+ }
473
+ /**
474
+ * Subscribe to session status changes using $effect.root.
475
+ * This is designed for use in non-component contexts (e.g., mount.ts).
476
+ *
477
+ * @param callback - Called when session status changes
478
+ * @returns Cleanup function to stop the subscription
479
+ */
480
+ export function subscribeToSessionStatus(callback) {
481
+ let previousStatus = getSessionStatus();
482
+ const cleanup = $effect.root(() => {
483
+ $effect(() => {
484
+ const status = getSessionStatus();
485
+ if (status !== previousStatus) {
486
+ callback(status, previousStatus);
487
+ previousStatus = status;
488
+ }
489
+ });
490
+ });
491
+ return cleanup;
388
492
  }
389
493
  /**
390
494
  * Refresh messages for the current session
@@ -393,30 +497,19 @@ export function getLatestMessageTimestamp() {
393
497
  * has stopped but new messages may exist on the server.
394
498
  *
395
499
  * @param fetchMessages - Async function to fetch messages from the API
500
+ * @param isTerminalStatus - Optional override for terminal status check
396
501
  * @returns Promise that resolves when messages are refreshed
397
502
  */
398
- export async function refreshSessionMessages(fetchMessages) {
399
- const session = get(currentSession);
503
+ export async function refreshSessionMessages(fetchMessages, isTerminalStatus) {
504
+ const session = _currentSession;
400
505
  if (!session)
401
506
  return;
402
507
  try {
403
508
  const response = await fetchMessages(session.id);
404
- // Add new messages (deduplicates automatically)
405
- if (response.data && response.data.length > 0) {
406
- playgroundActions.addMessages(response.data);
407
- }
408
- // Update session status
409
- if (response.sessionStatus) {
410
- playgroundActions.updateSessionStatus(response.sessionStatus);
411
- // Update executing state based on session status
412
- if (response.sessionStatus === 'idle' ||
413
- response.sessionStatus === 'completed' ||
414
- response.sessionStatus === 'failed') {
415
- isExecuting.set(false);
416
- }
417
- }
509
+ const callback = createPollingCallback(isTerminalStatus);
510
+ callback(response);
418
511
  }
419
512
  catch (err) {
420
- console.error('[playgroundStore] Failed to refresh messages:', err);
513
+ logger.error('[playgroundStore] Failed to refresh messages:', err);
421
514
  }
422
515
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Port Coordinate Store
2
+ * Port Coordinate Store (Svelte 5 Runes)
3
3
  *
4
4
  * General-purpose store that maintains absolute canvas-space coordinates
5
5
  * for all port handles in the workflow. Built from SvelteFlow's internal
@@ -14,8 +14,6 @@
14
14
  */
15
15
  import type { WorkflowNode as WorkflowNodeType, PortCoordinate, PortCoordinateMap } from '../types/index.js';
16
16
  import type { InternalNode } from '@xyflow/svelte';
17
- /** Store holding all port absolute coordinates, keyed by handleId */
18
- export declare const portCoordinateStore: import("svelte/store").Writable<PortCoordinateMap>;
19
17
  /**
20
18
  * Rebuild coordinates for ALL nodes from SvelteFlow internals.
21
19
  * Call on initial workflow load (after render) and after bulk changes.
@@ -53,8 +51,16 @@ export declare function getPortCoordinate(handleId: string): PortCoordinate | un
53
51
  */
54
52
  export declare function getNodePortCoordinates(nodeId: string): PortCoordinate[];
55
53
  /**
56
- * Get the current snapshot of all port coordinates (non-reactive).
54
+ * Get the current snapshot of all port coordinates.
55
+ * Returns the reactive SvelteMap directly.
57
56
  *
58
57
  * @returns Current port coordinate map
59
58
  */
60
59
  export declare function getPortCoordinateSnapshot(): PortCoordinateMap;
60
+ /**
61
+ * Get the reactive port coordinates state.
62
+ * Useful for components that need to reactively read the coordinates.
63
+ *
64
+ * @returns The reactive port coordinate map
65
+ */
66
+ export declare function getPortCoordinates(): PortCoordinateMap;