@d34dman/flowdrop 0.0.37 → 0.0.39

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 (50) hide show
  1. package/LICENSE +21 -0
  2. package/dist/components/NodeSidebar.svelte +1 -0
  3. package/dist/components/form/FormCodeEditor.svelte +6 -1
  4. package/dist/components/interrupt/ChoicePrompt.svelte +389 -0
  5. package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +21 -0
  6. package/dist/components/interrupt/ConfirmationPrompt.svelte +280 -0
  7. package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +23 -0
  8. package/dist/components/interrupt/FormPrompt.svelte +223 -0
  9. package/dist/components/interrupt/FormPrompt.svelte.d.ts +21 -0
  10. package/dist/components/interrupt/InterruptBubble.svelte +621 -0
  11. package/dist/components/interrupt/InterruptBubble.svelte.d.ts +16 -0
  12. package/dist/components/interrupt/TextInputPrompt.svelte +333 -0
  13. package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +21 -0
  14. package/dist/components/interrupt/index.d.ts +13 -0
  15. package/dist/components/interrupt/index.js +15 -0
  16. package/dist/components/nodes/GatewayNode.svelte +1 -3
  17. package/dist/components/nodes/IdeaNode.svelte +30 -35
  18. package/dist/components/nodes/IdeaNode.svelte.d.ts +1 -1
  19. package/dist/components/nodes/SimpleNode.svelte +1 -3
  20. package/dist/components/nodes/TerminalNode.svelte +1 -3
  21. package/dist/components/nodes/ToolNode.svelte +2 -2
  22. package/dist/components/nodes/WorkflowNode.svelte +1 -3
  23. package/dist/components/playground/ChatPanel.svelte +144 -7
  24. package/dist/components/playground/ChatPanel.svelte.d.ts +2 -0
  25. package/dist/components/playground/MessageBubble.svelte +1 -3
  26. package/dist/components/playground/Playground.svelte +50 -5
  27. package/dist/components/playground/PlaygroundModal.svelte +8 -7
  28. package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -3
  29. package/dist/config/endpoints.d.ts +12 -0
  30. package/dist/config/endpoints.js +7 -0
  31. package/dist/playground/index.d.ts +5 -0
  32. package/dist/playground/index.js +21 -0
  33. package/dist/playground/mount.d.ts +3 -3
  34. package/dist/playground/mount.js +30 -22
  35. package/dist/services/interruptService.d.ts +133 -0
  36. package/dist/services/interruptService.js +279 -0
  37. package/dist/stores/interruptStore.d.ts +200 -0
  38. package/dist/stores/interruptStore.js +424 -0
  39. package/dist/stores/playgroundStore.d.ts +11 -1
  40. package/dist/stores/playgroundStore.js +34 -0
  41. package/dist/styles/base.css +89 -0
  42. package/dist/types/index.d.ts +1 -1
  43. package/dist/types/interrupt.d.ts +305 -0
  44. package/dist/types/interrupt.js +126 -0
  45. package/dist/types/interruptState.d.ts +211 -0
  46. package/dist/types/interruptState.js +308 -0
  47. package/dist/utils/colors.js +1 -0
  48. package/dist/utils/connections.js +2 -2
  49. package/dist/utils/icons.js +1 -0
  50. package/package.json +1 -1
@@ -0,0 +1,424 @@
1
+ /**
2
+ * Interrupt Store
3
+ *
4
+ * Svelte stores for managing interrupt state using a lightweight state machine.
5
+ * Ensures valid state transitions and prevents deadlocks.
6
+ *
7
+ * @module stores/interruptStore
8
+ */
9
+ import { writable, derived, get } from 'svelte/store';
10
+ import { initialState, transition, isTerminalState, isSubmitting as checkIsSubmitting, hasError as checkHasError, getErrorMessage, getResolvedValue, toLegacyStatus } from '../types/interruptState.js';
11
+ // =========================================================================
12
+ // Core Stores
13
+ // =========================================================================
14
+ /**
15
+ * Map of all interrupts by ID
16
+ * Key: interrupt ID, Value: Interrupt object with state
17
+ */
18
+ export const interrupts = writable(new Map());
19
+ // =========================================================================
20
+ // Derived Stores
21
+ // =========================================================================
22
+ /**
23
+ * Derived store for pending interrupt IDs
24
+ */
25
+ export const pendingInterruptIds = derived(interrupts, ($interrupts) => {
26
+ const pending = [];
27
+ $interrupts.forEach((interrupt, id) => {
28
+ if (!isTerminalState(interrupt.machineState)) {
29
+ pending.push(id);
30
+ }
31
+ });
32
+ return pending;
33
+ });
34
+ /**
35
+ * Derived store for pending interrupts array
36
+ */
37
+ export const pendingInterrupts = derived(interrupts, ($interrupts) => {
38
+ const pending = [];
39
+ $interrupts.forEach((interrupt) => {
40
+ if (!isTerminalState(interrupt.machineState)) {
41
+ pending.push(interrupt);
42
+ }
43
+ });
44
+ return pending;
45
+ });
46
+ /**
47
+ * Derived store for count of pending interrupts
48
+ */
49
+ export const pendingInterruptCount = derived(pendingInterruptIds, ($pendingIds) => $pendingIds.length);
50
+ /**
51
+ * Derived store for resolved interrupts
52
+ */
53
+ export const resolvedInterrupts = derived(interrupts, ($interrupts) => {
54
+ const resolved = [];
55
+ $interrupts.forEach((interrupt) => {
56
+ if (interrupt.machineState.status === 'resolved') {
57
+ resolved.push(interrupt);
58
+ }
59
+ });
60
+ return resolved;
61
+ });
62
+ /**
63
+ * Derived store to check if any interrupt is currently submitting
64
+ */
65
+ export const isAnySubmitting = derived(interrupts, ($interrupts) => {
66
+ for (const interrupt of $interrupts.values()) {
67
+ if (checkIsSubmitting(interrupt.machineState)) {
68
+ return true;
69
+ }
70
+ }
71
+ return false;
72
+ });
73
+ /**
74
+ * Legacy derived store for submitting interrupt IDs
75
+ * @deprecated Use interrupt.machineState.status === "submitting" instead
76
+ */
77
+ export const submittingInterrupts = derived(interrupts, ($interrupts) => {
78
+ const submitting = new Set();
79
+ $interrupts.forEach((interrupt, id) => {
80
+ if (checkIsSubmitting(interrupt.machineState)) {
81
+ submitting.add(id);
82
+ }
83
+ });
84
+ return submitting;
85
+ });
86
+ /**
87
+ * Legacy derived store for interrupt errors
88
+ * @deprecated Use interrupt.machineState.error instead
89
+ */
90
+ export const interruptErrors = derived(interrupts, ($interrupts) => {
91
+ const errors = new Map();
92
+ $interrupts.forEach((interrupt, id) => {
93
+ const errorMsg = getErrorMessage(interrupt.machineState);
94
+ if (errorMsg) {
95
+ errors.set(id, errorMsg);
96
+ }
97
+ });
98
+ return errors;
99
+ });
100
+ // =========================================================================
101
+ // State Machine Actions
102
+ // =========================================================================
103
+ /**
104
+ * Apply a state machine action to an interrupt
105
+ *
106
+ * @param interruptId - The interrupt ID
107
+ * @param action - The action to apply
108
+ * @returns Transition result with validity and any errors
109
+ */
110
+ function applyAction(interruptId, action) {
111
+ const currentInterrupts = get(interrupts);
112
+ const interrupt = currentInterrupts.get(interruptId);
113
+ if (!interrupt) {
114
+ return {
115
+ state: initialState,
116
+ valid: false,
117
+ error: `Interrupt not found: ${interruptId}`
118
+ };
119
+ }
120
+ const result = transition(interrupt.machineState, action);
121
+ if (result.valid) {
122
+ interrupts.update(($interrupts) => {
123
+ const updated = new Map($interrupts);
124
+ const current = updated.get(interruptId);
125
+ if (current) {
126
+ // Update machine state and sync legacy fields
127
+ const newInterrupt = {
128
+ ...current,
129
+ machineState: result.state,
130
+ status: toLegacyStatus(result.state),
131
+ responseValue: getResolvedValue(result.state) ?? current.responseValue,
132
+ resolvedAt: result.state.status === 'resolved'
133
+ ? result.state.resolvedAt
134
+ : result.state.status === 'cancelled'
135
+ ? result.state.cancelledAt
136
+ : current.resolvedAt
137
+ };
138
+ updated.set(interruptId, newInterrupt);
139
+ }
140
+ return updated;
141
+ });
142
+ }
143
+ else {
144
+ console.warn(`[InterruptStore] Invalid transition: ${result.error}`);
145
+ }
146
+ return result;
147
+ }
148
+ // =========================================================================
149
+ // Public Actions
150
+ // =========================================================================
151
+ /**
152
+ * Interrupt store actions for modifying state
153
+ */
154
+ export const interruptActions = {
155
+ /**
156
+ * Add or update an interrupt in the store
157
+ *
158
+ * @param interrupt - The interrupt to add or update
159
+ */
160
+ addInterrupt: (interrupt) => {
161
+ interrupts.update(($interrupts) => {
162
+ const updated = new Map($interrupts);
163
+ const existing = updated.get(interrupt.id);
164
+ // Preserve existing machine state if interrupt already exists
165
+ const machineState = existing?.machineState ?? initialState;
166
+ const interruptWithState = {
167
+ ...interrupt,
168
+ machineState
169
+ };
170
+ updated.set(interrupt.id, interruptWithState);
171
+ return updated;
172
+ });
173
+ },
174
+ /**
175
+ * Add multiple interrupts to the store
176
+ *
177
+ * @param interruptList - Array of interrupts to add
178
+ */
179
+ addInterrupts: (interruptList) => {
180
+ if (interruptList.length === 0)
181
+ return;
182
+ interrupts.update(($interrupts) => {
183
+ const updated = new Map($interrupts);
184
+ interruptList.forEach((interrupt) => {
185
+ const existing = updated.get(interrupt.id);
186
+ const machineState = existing?.machineState ?? initialState;
187
+ const interruptWithState = {
188
+ ...interrupt,
189
+ machineState
190
+ };
191
+ updated.set(interrupt.id, interruptWithState);
192
+ });
193
+ return updated;
194
+ });
195
+ },
196
+ /**
197
+ * Start submitting an interrupt (user clicked submit)
198
+ *
199
+ * @param interruptId - The interrupt ID
200
+ * @param value - The value being submitted
201
+ * @returns Transition result
202
+ */
203
+ startSubmit: (interruptId, value) => {
204
+ return applyAction(interruptId, { type: 'SUBMIT', value });
205
+ },
206
+ /**
207
+ * Start cancelling an interrupt (user clicked cancel)
208
+ *
209
+ * @param interruptId - The interrupt ID
210
+ * @returns Transition result
211
+ */
212
+ startCancel: (interruptId) => {
213
+ return applyAction(interruptId, { type: 'CANCEL' });
214
+ },
215
+ /**
216
+ * Mark submission as successful
217
+ *
218
+ * @param interruptId - The interrupt ID
219
+ * @returns Transition result
220
+ */
221
+ submitSuccess: (interruptId) => {
222
+ return applyAction(interruptId, { type: 'SUCCESS' });
223
+ },
224
+ /**
225
+ * Mark submission as failed
226
+ *
227
+ * @param interruptId - The interrupt ID
228
+ * @param error - Error message
229
+ * @returns Transition result
230
+ */
231
+ submitFailure: (interruptId, error) => {
232
+ return applyAction(interruptId, { type: 'FAILURE', error });
233
+ },
234
+ /**
235
+ * Retry a failed submission
236
+ *
237
+ * @param interruptId - The interrupt ID
238
+ * @returns Transition result
239
+ */
240
+ retry: (interruptId) => {
241
+ return applyAction(interruptId, { type: 'RETRY' });
242
+ },
243
+ /**
244
+ * Reset an interrupt to idle state
245
+ *
246
+ * @param interruptId - The interrupt ID
247
+ * @returns Transition result
248
+ */
249
+ resetInterrupt: (interruptId) => {
250
+ return applyAction(interruptId, { type: 'RESET' });
251
+ },
252
+ // =========================================================================
253
+ // Legacy Actions (for backward compatibility)
254
+ // =========================================================================
255
+ /**
256
+ * Update an interrupt's status (legacy)
257
+ * @deprecated Use startSubmit/submitSuccess/submitFailure instead
258
+ */
259
+ updateStatus: (interruptId, status, responseValue) => {
260
+ // Map legacy status to state machine actions
261
+ if (status === 'resolved' && responseValue !== undefined) {
262
+ const submitResult = applyAction(interruptId, { type: 'SUBMIT', value: responseValue });
263
+ if (submitResult.valid) {
264
+ applyAction(interruptId, { type: 'SUCCESS' });
265
+ }
266
+ }
267
+ else if (status === 'cancelled') {
268
+ const cancelResult = applyAction(interruptId, { type: 'CANCEL' });
269
+ if (cancelResult.valid) {
270
+ applyAction(interruptId, { type: 'SUCCESS' });
271
+ }
272
+ }
273
+ },
274
+ /**
275
+ * Mark an interrupt as resolved with the user's response (legacy)
276
+ * @deprecated Use startSubmit + submitSuccess instead
277
+ */
278
+ resolveInterrupt: (interruptId, value) => {
279
+ // For backward compatibility, immediately resolve
280
+ // (assumes sync operation or already completed API call)
281
+ const submitResult = applyAction(interruptId, { type: 'SUBMIT', value });
282
+ if (submitResult.valid) {
283
+ applyAction(interruptId, { type: 'SUCCESS' });
284
+ }
285
+ },
286
+ /**
287
+ * Mark an interrupt as cancelled (legacy)
288
+ * @deprecated Use startCancel + submitSuccess instead
289
+ */
290
+ cancelInterrupt: (interruptId) => {
291
+ const cancelResult = applyAction(interruptId, { type: 'CANCEL' });
292
+ if (cancelResult.valid) {
293
+ applyAction(interruptId, { type: 'SUCCESS' });
294
+ }
295
+ },
296
+ /**
297
+ * Set submitting state for an interrupt (legacy)
298
+ * @deprecated State is automatically managed by startSubmit/submitSuccess
299
+ */
300
+ setSubmitting: (interruptId, isSubmitting) => {
301
+ // This is now a no-op - state is managed by the state machine
302
+ // Kept for backward compatibility
303
+ if (isSubmitting) {
304
+ console.warn('[InterruptStore] setSubmitting(true) is deprecated. Use startSubmit() instead.');
305
+ }
306
+ },
307
+ /**
308
+ * Set error for an interrupt (legacy)
309
+ * @deprecated Use submitFailure() instead
310
+ */
311
+ setError: (interruptId, error) => {
312
+ if (error) {
313
+ applyAction(interruptId, { type: 'FAILURE', error });
314
+ }
315
+ // Clearing error is not directly supported - use retry or reset
316
+ },
317
+ /**
318
+ * Remove an interrupt from the store
319
+ *
320
+ * @param interruptId - The interrupt ID to remove
321
+ */
322
+ removeInterrupt: (interruptId) => {
323
+ interrupts.update(($interrupts) => {
324
+ const updated = new Map($interrupts);
325
+ updated.delete(interruptId);
326
+ return updated;
327
+ });
328
+ },
329
+ /**
330
+ * Clear all interrupts for a specific session
331
+ *
332
+ * @param sessionId - The session ID to clear interrupts for
333
+ */
334
+ clearSessionInterrupts: (sessionId) => {
335
+ interrupts.update(($interrupts) => {
336
+ const updated = new Map($interrupts);
337
+ $interrupts.forEach((interrupt, id) => {
338
+ if (interrupt.sessionId === sessionId) {
339
+ updated.delete(id);
340
+ }
341
+ });
342
+ return updated;
343
+ });
344
+ },
345
+ /**
346
+ * Alias for clearSessionInterrupts
347
+ */
348
+ clearInterrupts: () => {
349
+ interrupts.set(new Map());
350
+ },
351
+ /**
352
+ * Reset all interrupt state
353
+ */
354
+ reset: () => {
355
+ interrupts.set(new Map());
356
+ }
357
+ };
358
+ // =========================================================================
359
+ // Utilities
360
+ // =========================================================================
361
+ /**
362
+ * Get an interrupt by ID
363
+ *
364
+ * @param interruptId - The interrupt ID
365
+ * @returns The interrupt or undefined
366
+ */
367
+ export function getInterrupt(interruptId) {
368
+ return get(interrupts).get(interruptId);
369
+ }
370
+ /**
371
+ * Check if an interrupt is pending (not resolved or cancelled)
372
+ *
373
+ * @param interruptId - The interrupt ID
374
+ * @returns True if the interrupt exists and is pending
375
+ */
376
+ export function isInterruptPending(interruptId) {
377
+ const interrupt = get(interrupts).get(interruptId);
378
+ return interrupt ? !isTerminalState(interrupt.machineState) : false;
379
+ }
380
+ /**
381
+ * Check if an interrupt is currently submitting
382
+ *
383
+ * @param interruptId - The interrupt ID
384
+ * @returns True if the interrupt is being submitted
385
+ */
386
+ export function isInterruptSubmitting(interruptId) {
387
+ const interrupt = get(interrupts).get(interruptId);
388
+ return interrupt ? checkIsSubmitting(interrupt.machineState) : false;
389
+ }
390
+ /**
391
+ * Get the error for an interrupt
392
+ *
393
+ * @param interruptId - The interrupt ID
394
+ * @returns The error message or undefined
395
+ */
396
+ export function getInterruptError(interruptId) {
397
+ const interrupt = get(interrupts).get(interruptId);
398
+ return interrupt ? getErrorMessage(interrupt.machineState) : undefined;
399
+ }
400
+ /**
401
+ * Get an interrupt by its associated message ID
402
+ *
403
+ * @param messageId - The message ID
404
+ * @returns The interrupt or undefined
405
+ */
406
+ export function getInterruptByMessageId(messageId) {
407
+ const interruptMap = get(interrupts);
408
+ for (const interrupt of interruptMap.values()) {
409
+ if (interrupt.messageId === messageId) {
410
+ return interrupt;
411
+ }
412
+ }
413
+ return undefined;
414
+ }
415
+ /**
416
+ * Check if an interrupt has an error
417
+ *
418
+ * @param interruptId - The interrupt ID
419
+ * @returns True if the interrupt has an error
420
+ */
421
+ export function interruptHasError(interruptId) {
422
+ const interrupt = get(interrupts).get(interruptId);
423
+ return interrupt ? checkHasError(interrupt.machineState) : false;
424
+ }
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @module stores/playgroundStore
8
8
  */
9
- import type { PlaygroundSession, PlaygroundMessage, PlaygroundInputField, PlaygroundSessionStatus } from '../types/playground.js';
9
+ import type { PlaygroundSession, PlaygroundMessage, PlaygroundInputField, PlaygroundSessionStatus, PlaygroundMessagesApiResponse } from '../types/playground.js';
10
10
  import type { Workflow } from '../types/index.js';
11
11
  /**
12
12
  * Currently active playground session
@@ -200,3 +200,13 @@ export declare function getMessagesSnapshot(): PlaygroundMessage[];
200
200
  * @returns ISO 8601 timestamp of the latest message, or null
201
201
  */
202
202
  export declare function getLatestMessageTimestamp(): string | null;
203
+ /**
204
+ * Refresh messages for the current session
205
+ *
206
+ * This function is useful after interrupt resolution when polling
207
+ * has stopped but new messages may exist on the server.
208
+ *
209
+ * @param fetchMessages - Async function to fetch messages from the API
210
+ * @returns Promise that resolves when messages are refreshed
211
+ */
212
+ export declare function refreshSessionMessages(fetchMessages: (sessionId: string) => Promise<PlaygroundMessagesApiResponse>): Promise<void>;
@@ -386,3 +386,37 @@ export function getLatestMessageTimestamp() {
386
386
  return null;
387
387
  return msgs[msgs.length - 1].timestamp;
388
388
  }
389
+ /**
390
+ * Refresh messages for the current session
391
+ *
392
+ * This function is useful after interrupt resolution when polling
393
+ * has stopped but new messages may exist on the server.
394
+ *
395
+ * @param fetchMessages - Async function to fetch messages from the API
396
+ * @returns Promise that resolves when messages are refreshed
397
+ */
398
+ export async function refreshSessionMessages(fetchMessages) {
399
+ const session = get(currentSession);
400
+ if (!session)
401
+ return;
402
+ try {
403
+ 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
+ }
418
+ }
419
+ catch (err) {
420
+ console.error('[playgroundStore] Failed to refresh messages:', err);
421
+ }
422
+ }
@@ -1180,6 +1180,95 @@
1180
1180
  --flowdrop-text-color-primary: var(--color-ref-gray-900);
1181
1181
  --flowdrop-text-color-secondary: var(--color-ref-gray-600);
1182
1182
 
1183
+ /* =========================================================================
1184
+ Interrupt Component Tokens
1185
+ ========================================================================= */
1186
+
1187
+ /* Interrupt state: Pending (awaiting user response) */
1188
+ --flowdrop-interrupt-pending-bg: linear-gradient(
1189
+ 135deg,
1190
+ var(--color-ref-amber-100) 0%,
1191
+ var(--color-ref-amber-200) 100%
1192
+ );
1193
+ --flowdrop-interrupt-pending-border: var(--color-ref-amber-500);
1194
+ --flowdrop-interrupt-pending-shadow: rgba(245, 158, 11, 0.15);
1195
+ --flowdrop-interrupt-pending-avatar: var(--color-ref-amber-500);
1196
+ --flowdrop-interrupt-pending-text: var(--color-ref-amber-800);
1197
+ --flowdrop-interrupt-pending-text-light: var(--color-ref-amber-700);
1198
+
1199
+ /* Interrupt state: Completed (response received - neutral) */
1200
+ --flowdrop-interrupt-completed-bg: linear-gradient(
1201
+ 135deg,
1202
+ var(--color-ref-blue-50) 0%,
1203
+ var(--color-ref-blue-100) 100%
1204
+ );
1205
+ --flowdrop-interrupt-completed-border: var(--color-ref-blue-500);
1206
+ --flowdrop-interrupt-completed-shadow: rgba(59, 130, 246, 0.15);
1207
+ --flowdrop-interrupt-completed-avatar: var(--color-ref-blue-500);
1208
+ --flowdrop-interrupt-completed-text: var(--color-ref-blue-800);
1209
+ --flowdrop-interrupt-completed-text-light: var(--color-ref-blue-600);
1210
+
1211
+ /* Interrupt state: Cancelled (dismissed without responding) */
1212
+ --flowdrop-interrupt-cancelled-bg: linear-gradient(
1213
+ 135deg,
1214
+ var(--color-ref-gray-100) 0%,
1215
+ var(--color-ref-gray-200) 100%
1216
+ );
1217
+ --flowdrop-interrupt-cancelled-border: var(--color-ref-gray-400);
1218
+ --flowdrop-interrupt-cancelled-shadow: rgba(107, 114, 128, 0.15);
1219
+ --flowdrop-interrupt-cancelled-avatar: var(--color-ref-gray-500);
1220
+ --flowdrop-interrupt-cancelled-text: var(--color-ref-gray-600);
1221
+ --flowdrop-interrupt-cancelled-text-light: var(--color-ref-gray-500);
1222
+
1223
+ /* Interrupt state: Error */
1224
+ --flowdrop-interrupt-error-bg: linear-gradient(
1225
+ 135deg,
1226
+ var(--color-ref-red-50) 0%,
1227
+ var(--color-ref-red-100) 100%
1228
+ );
1229
+ --flowdrop-interrupt-error-border: var(--color-ref-red-500);
1230
+ --flowdrop-interrupt-error-shadow: rgba(239, 68, 68, 0.15);
1231
+ --flowdrop-interrupt-error-avatar: var(--color-ref-red-500);
1232
+ --flowdrop-interrupt-error-text: var(--color-ref-red-700);
1233
+ --flowdrop-interrupt-error-text-light: var(--color-ref-red-600);
1234
+
1235
+ /* Interrupt prompt inner styling */
1236
+ --flowdrop-interrupt-prompt-bg: rgba(255, 255, 255, 0.85);
1237
+ --flowdrop-interrupt-prompt-border-pending: rgba(245, 158, 11, 0.2);
1238
+ --flowdrop-interrupt-prompt-border-completed: rgba(59, 130, 246, 0.2);
1239
+ --flowdrop-interrupt-prompt-border-cancelled: rgba(107, 114, 128, 0.2);
1240
+ --flowdrop-interrupt-prompt-border-error: rgba(239, 68, 68, 0.2);
1241
+
1242
+ /* Interrupt button tokens */
1243
+ --flowdrop-interrupt-btn-primary-bg: linear-gradient(
1244
+ 135deg,
1245
+ var(--color-ref-blue-500) 0%,
1246
+ var(--color-ref-blue-600) 100%
1247
+ );
1248
+ --flowdrop-interrupt-btn-primary-bg-hover: linear-gradient(
1249
+ 135deg,
1250
+ var(--color-ref-blue-600) 0%,
1251
+ var(--color-ref-blue-700) 100%
1252
+ );
1253
+ --flowdrop-interrupt-btn-primary-shadow: rgba(59, 130, 246, 0.3);
1254
+ --flowdrop-interrupt-btn-secondary-bg: var(--color-ref-gray-100);
1255
+ --flowdrop-interrupt-btn-secondary-border: var(--color-ref-gray-300);
1256
+ --flowdrop-interrupt-btn-secondary-text: var(--color-ref-gray-700);
1257
+
1258
+ /* Interrupt selection tokens (for confirmation/choice) */
1259
+ --flowdrop-interrupt-selected-confirm-bg: var(--flowdrop-interrupt-btn-primary-bg);
1260
+ --flowdrop-interrupt-selected-confirm-border: var(--color-ref-blue-700);
1261
+ --flowdrop-interrupt-selected-confirm-glow: rgba(59, 130, 246, 0.3);
1262
+ --flowdrop-interrupt-selected-decline-bg: var(--color-ref-red-50);
1263
+ --flowdrop-interrupt-selected-decline-border: var(--color-ref-red-400);
1264
+ --flowdrop-interrupt-selected-decline-text: var(--color-ref-red-600);
1265
+ --flowdrop-interrupt-selected-decline-glow: rgba(248, 113, 113, 0.2);
1266
+ --flowdrop-interrupt-not-selected-opacity: 0.4;
1267
+
1268
+ /* Interrupt badge tokens */
1269
+ --flowdrop-interrupt-badge-completed-bg: var(--color-ref-blue-50);
1270
+ --flowdrop-interrupt-badge-completed-text: var(--color-ref-blue-600);
1271
+
1183
1272
  /* NotesNode component variables */
1184
1273
  --notes-node-width: 500px;
1185
1274
  --notes-node-min-width: 250px;
@@ -8,7 +8,7 @@ import type { EndpointConfig } from '../config/endpoints.js';
8
8
  * Node category types for organizing nodes in the sidebar
9
9
  * Based on actual API response categories
10
10
  */
11
- export type NodeCategory = 'inputs' | 'outputs' | 'prompts' | 'models' | 'processing' | 'logic' | 'data' | 'tools' | 'helpers' | 'vector stores' | 'embeddings' | 'memories' | 'agents' | 'ai' | 'bundles';
11
+ export type NodeCategory = 'triggers' | 'inputs' | 'outputs' | 'prompts' | 'models' | 'processing' | 'logic' | 'data' | 'tools' | 'helpers' | 'vector stores' | 'embeddings' | 'memories' | 'agents' | 'ai' | 'bundles';
12
12
  /**
13
13
  * Port data type configuration
14
14
  */