@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
@@ -13,13 +13,16 @@
13
13
  import ChoicePrompt from './ChoicePrompt.svelte';
14
14
  import TextInputPrompt from './TextInputPrompt.svelte';
15
15
  import FormPrompt from './FormPrompt.svelte';
16
+ import ReviewPrompt from './ReviewPrompt.svelte';
16
17
  import type {
17
18
  Interrupt,
18
19
  InterruptType,
19
20
  ConfirmationConfig,
20
21
  ChoiceConfig,
21
22
  TextConfig,
22
- FormConfig
23
+ FormConfig,
24
+ ReviewConfig,
25
+ ReviewResolution
23
26
  } from '../../types/interrupt.js';
24
27
  import {
25
28
  isTerminalState,
@@ -28,11 +31,12 @@
28
31
  getResolvedValue
29
32
  } from '../../types/interruptState.js';
30
33
  import {
31
- interrupts,
34
+ getInterruptsMap,
32
35
  interruptActions,
33
36
  type InterruptWithState
34
- } from '../../stores/interruptStore.js';
37
+ } from '../../stores/interruptStore.svelte.js';
35
38
  import { interruptService } from '../../services/interruptService.js';
39
+ import { logger } from '../../utils/logger.js';
36
40
 
37
41
  /**
38
42
  * Component props
@@ -53,7 +57,7 @@
53
57
  * This ensures we react to store updates (like status changes).
54
58
  */
55
59
  const currentInterrupt = $derived(
56
- $interrupts.get(initialInterrupt.id) ?? addMachineState(initialInterrupt)
60
+ getInterruptsMap().get(initialInterrupt.id) ?? addMachineState(initialInterrupt)
57
61
  );
58
62
 
59
63
  /**
@@ -94,6 +98,8 @@
94
98
  return 'mdi:text-box';
95
99
  case 'form':
96
100
  return 'mdi:form-select';
101
+ case 'review':
102
+ return 'mdi:file-compare';
97
103
  default:
98
104
  return 'mdi:bell';
99
105
  }
@@ -112,6 +118,8 @@
112
118
  return 'Input Required';
113
119
  case 'form':
114
120
  return 'Form Required';
121
+ case 'review':
122
+ return 'Review Required';
115
123
  default:
116
124
  return 'Action Required';
117
125
  }
@@ -128,6 +136,8 @@
128
136
  return 'Input Submitted';
129
137
  case 'form':
130
138
  return 'Form Submitted';
139
+ case 'review':
140
+ return 'Review Submitted';
131
141
  default:
132
142
  return 'Response Submitted';
133
143
  }
@@ -153,7 +163,7 @@
153
163
  // Start the submission - state machine validates this transition
154
164
  const startResult = interruptActions.startSubmit(currentInterrupt.id, value);
155
165
  if (!startResult.valid) {
156
- console.warn('[InterruptBubble] Cannot submit:', startResult.error);
166
+ logger.warn('[InterruptBubble] Cannot submit:', startResult.error);
157
167
  return;
158
168
  }
159
169
 
@@ -172,7 +182,7 @@
172
182
  // Mark as failed - transitions to error state (can retry)
173
183
  const errorMessage = err instanceof Error ? err.message : 'Failed to submit response';
174
184
  interruptActions.submitFailure(currentInterrupt.id, errorMessage);
175
- console.error('[InterruptBubble] Resolve error:', err);
185
+ logger.error('[InterruptBubble] Resolve error:', err);
176
186
  }
177
187
  }
178
188
 
@@ -183,7 +193,7 @@
183
193
  // Start the cancel - state machine validates this transition
184
194
  const startResult = interruptActions.startCancel(currentInterrupt.id);
185
195
  if (!startResult.valid) {
186
- console.warn('[InterruptBubble] Cannot cancel:', startResult.error);
196
+ logger.warn('[InterruptBubble] Cannot cancel:', startResult.error);
187
197
  return;
188
198
  }
189
199
 
@@ -202,7 +212,7 @@
202
212
  // Mark as failed - transitions to error state (can retry)
203
213
  const errorMessage = err instanceof Error ? err.message : 'Failed to cancel';
204
214
  interruptActions.submitFailure(currentInterrupt.id, errorMessage);
205
- console.error('[InterruptBubble] Cancel error:', err);
215
+ logger.error('[InterruptBubble] Cancel error:', err);
206
216
  }
207
217
  }
208
218
 
@@ -218,6 +228,7 @@
218
228
  const choiceConfig = $derived(currentInterrupt.config as ChoiceConfig);
219
229
  const textConfig = $derived(currentInterrupt.config as TextConfig);
220
230
  const formConfig = $derived(currentInterrupt.config as FormConfig);
231
+ const reviewConfig = $derived(currentInterrupt.config as ReviewConfig);
221
232
 
222
233
  // Determine the actual resolved value to pass to prompt components
223
234
  const displayResolvedValue = $derived(resolvedValue ?? currentInterrupt.responseValue);
@@ -240,103 +251,105 @@
240
251
  class:interrupt-bubble--submitting={isSubmitting}
241
252
  class:interrupt-bubble--error={currentInterrupt.machineState.status === 'error'}
242
253
  >
243
- <!-- Avatar / Icon -->
244
- <div class="interrupt-bubble__avatar">
245
- {#if currentInterrupt.machineState.status === 'cancelled'}
246
- <Icon icon="mdi:close-circle" />
247
- {:else if currentInterrupt.machineState.status === 'resolved'}
248
- <Icon icon="mdi:check-circle" />
249
- {:else if currentInterrupt.machineState.status === 'error'}
250
- <Icon icon="mdi:alert-circle" />
251
- {:else}
252
- <Icon icon="mdi:bell-ring" />
254
+ <!-- Header -->
255
+ <div class="interrupt-bubble__header">
256
+ <span class="interrupt-bubble__type">
257
+ <Icon icon={getTypeIcon(currentInterrupt.type)} />
258
+ {#if isResolved}
259
+ {currentInterrupt.machineState.status === 'cancelled'
260
+ ? 'Cancelled'
261
+ : getResolvedLabel(currentInterrupt.type)}
262
+ {:else if currentInterrupt.machineState.status === 'error'}
263
+ Error - Click to Retry
264
+ {:else}
265
+ {getTypeLabel(currentInterrupt.type)}
266
+ {/if}
267
+ </span>
268
+ {#if showTimestamp}
269
+ <span class="interrupt-bubble__timestamp">
270
+ {formatTimestamp(currentInterrupt.resolvedAt ?? currentInterrupt.createdAt)}
271
+ </span>
253
272
  {/if}
254
273
  </div>
255
274
 
256
- <!-- Content -->
257
- <div class="interrupt-bubble__content">
258
- <!-- Header -->
259
- <div class="interrupt-bubble__header">
260
- <span class="interrupt-bubble__type">
261
- <Icon icon={getTypeIcon(currentInterrupt.type)} />
262
- {#if isResolved}
263
- {currentInterrupt.machineState.status === 'cancelled'
264
- ? 'Cancelled'
265
- : getResolvedLabel(currentInterrupt.type)}
266
- {:else if currentInterrupt.machineState.status === 'error'}
267
- Error - Click to Retry
268
- {:else}
269
- {getTypeLabel(currentInterrupt.type)}
270
- {/if}
271
- </span>
272
- {#if showTimestamp}
273
- <span class="interrupt-bubble__timestamp">
274
- {formatTimestamp(currentInterrupt.resolvedAt ?? currentInterrupt.createdAt)}
275
- </span>
276
- {/if}
275
+ <!-- Error message with retry button -->
276
+ {#if currentInterrupt.machineState.status === 'error'}
277
+ <div class="interrupt-bubble__error">
278
+ <Icon icon="mdi:alert-circle" />
279
+ <span>{error}</span>
280
+ <button type="button" class="interrupt-bubble__retry-btn" onclick={handleRetry}>
281
+ <Icon icon="mdi:refresh" />
282
+ Retry
283
+ </button>
277
284
  </div>
278
-
279
- <!-- Error message with retry button -->
280
- {#if currentInterrupt.machineState.status === 'error'}
281
- <div class="interrupt-bubble__error">
282
- <Icon icon="mdi:alert-circle" />
283
- <span>{error}</span>
284
- <button type="button" class="interrupt-bubble__retry-btn" onclick={handleRetry}>
285
- <Icon icon="mdi:refresh" />
286
- Retry
287
- </button>
288
- </div>
285
+ {/if}
286
+
287
+ <!-- Prompt content based on type -->
288
+ <div class="interrupt-bubble__body">
289
+ {#if currentInterrupt.type === 'confirmation'}
290
+ <ConfirmationPrompt
291
+ config={confirmationConfig}
292
+ {isResolved}
293
+ resolvedValue={displayResolvedValue as boolean | undefined}
294
+ {isSubmitting}
295
+ {error}
296
+ {resolvedByUserName}
297
+ onConfirm={() => handleResolve(true)}
298
+ onDecline={() => handleResolve(false)}
299
+ />
300
+ {:else if currentInterrupt.type === 'choice'}
301
+ <ChoicePrompt
302
+ config={choiceConfig}
303
+ {isResolved}
304
+ resolvedValue={displayResolvedValue as string | string[] | undefined}
305
+ {isSubmitting}
306
+ {error}
307
+ {resolvedByUserName}
308
+ onSubmit={(value) => handleResolve(value)}
309
+ />
310
+ {:else if currentInterrupt.type === 'text'}
311
+ <TextInputPrompt
312
+ config={textConfig}
313
+ {isResolved}
314
+ resolvedValue={displayResolvedValue as string | undefined}
315
+ {isSubmitting}
316
+ {error}
317
+ {resolvedByUserName}
318
+ onSubmit={(value) => handleResolve(value)}
319
+ />
320
+ {:else if currentInterrupt.type === 'form'}
321
+ <FormPrompt
322
+ config={formConfig}
323
+ {isResolved}
324
+ resolvedValue={displayResolvedValue as Record<string, unknown> | undefined}
325
+ {isSubmitting}
326
+ {error}
327
+ {resolvedByUserName}
328
+ onSubmit={(value) => handleResolve(value)}
329
+ />
330
+ {:else if currentInterrupt.type === 'review'}
331
+ <ReviewPrompt
332
+ config={reviewConfig}
333
+ {isResolved}
334
+ resolvedValue={displayResolvedValue as ReviewResolution | undefined}
335
+ {isSubmitting}
336
+ {error}
337
+ {resolvedByUserName}
338
+ onSubmit={(value) => handleResolve(value)}
339
+ />
289
340
  {/if}
341
+ </div>
290
342
 
291
- <!-- Prompt content based on type -->
292
- <div class="interrupt-bubble__prompt">
293
- {#if currentInterrupt.type === 'confirmation'}
294
- <ConfirmationPrompt
295
- config={confirmationConfig}
296
- {isResolved}
297
- resolvedValue={displayResolvedValue as boolean | undefined}
298
- {isSubmitting}
299
- {error}
300
- {resolvedByUserName}
301
- onConfirm={() => handleResolve(true)}
302
- onDecline={() => handleResolve(false)}
303
- />
304
- {:else if currentInterrupt.type === 'choice'}
305
- <ChoicePrompt
306
- config={choiceConfig}
307
- {isResolved}
308
- resolvedValue={displayResolvedValue as string | string[] | undefined}
309
- {isSubmitting}
310
- {error}
311
- {resolvedByUserName}
312
- onSubmit={(value) => handleResolve(value)}
313
- />
314
- {:else if currentInterrupt.type === 'text'}
315
- <TextInputPrompt
316
- config={textConfig}
317
- {isResolved}
318
- resolvedValue={displayResolvedValue as string | undefined}
319
- {isSubmitting}
320
- {error}
321
- {resolvedByUserName}
322
- onSubmit={(value) => handleResolve(value)}
323
- />
324
- {:else if currentInterrupt.type === 'form'}
325
- <FormPrompt
326
- config={formConfig}
327
- {isResolved}
328
- resolvedValue={displayResolvedValue as Record<string, unknown> | undefined}
329
- {isSubmitting}
330
- {error}
331
- {resolvedByUserName}
332
- onSubmit={(value) => handleResolve(value)}
333
- />
343
+ <!-- Footer -->
344
+ {#if currentInterrupt.nodeId || (currentInterrupt.allowCancel && !isResolved && currentInterrupt.type !== 'confirmation')}
345
+ <div class="interrupt-bubble__footer">
346
+ {#if currentInterrupt.nodeId}
347
+ <span class="interrupt-bubble__node" title="Node ID: {currentInterrupt.nodeId}">
348
+ <Icon icon="mdi:graph" />
349
+ <span>From workflow node</span>
350
+ </span>
334
351
  {/if}
335
- </div>
336
-
337
- <!-- Cancel button (if allowed and not in terminal state) -->
338
- {#if currentInterrupt.allowCancel && !isResolved && currentInterrupt.type !== 'confirmation'}
339
- <div class="interrupt-bubble__cancel-wrapper">
352
+ {#if currentInterrupt.allowCancel && !isResolved && currentInterrupt.type !== 'confirmation'}
340
353
  <button
341
354
  type="button"
342
355
  class="interrupt-bubble__cancel-btn"
@@ -346,33 +359,23 @@
346
359
  <Icon icon="mdi:close" />
347
360
  <span>Cancel</span>
348
361
  </button>
349
- </div>
350
- {/if}
351
-
352
- <!-- Node info footer -->
353
- {#if currentInterrupt.nodeId}
354
- <div class="interrupt-bubble__footer">
355
- <span class="interrupt-bubble__node" title="Node ID: {currentInterrupt.nodeId}">
356
- <Icon icon="mdi:graph" />
357
- <span>From workflow node</span>
358
- </span>
359
- </div>
360
- {/if}
361
- </div>
362
+ {/if}
363
+ </div>
364
+ {/if}
362
365
  </div>
363
366
 
364
367
  <style>
365
368
  /* Uses design tokens from base.css: --fd-interrupt-* */
366
369
  .interrupt-bubble {
367
370
  display: flex;
368
- gap: 0.75rem;
369
- padding: 1rem 1.25rem;
370
- margin: 0.75rem 1rem;
371
- border-radius: 0.75rem;
372
- background: var(--fd-interrupt-pending-bg);
373
- border: 1px solid var(--fd-interrupt-pending-border);
371
+ flex-direction: column;
372
+ margin: var(--fd-space-md) var(--fd-space-xl);
373
+ border-radius: var(--fd-radius-xl);
374
+ background-color: var(--fd-interrupt-prompt-bg);
375
+ border: 1px solid var(--fd-interrupt-prompt-border-pending);
374
376
  box-shadow: 0 2px 8px var(--fd-interrupt-pending-shadow);
375
377
  animation: interruptSlideIn 0.3s ease-out;
378
+ overflow: hidden;
376
379
  }
377
380
 
378
381
  @keyframes interruptSlideIn {
@@ -386,22 +389,19 @@
386
389
  }
387
390
  }
388
391
 
389
- /* Completed state - neutral blue to indicate response received without implying good/bad */
392
+ /* State border colors */
390
393
  .interrupt-bubble--completed {
391
- background: var(--fd-interrupt-completed-bg);
392
- border-color: var(--fd-interrupt-completed-border);
394
+ border-color: var(--fd-interrupt-prompt-border-completed);
393
395
  box-shadow: 0 2px 8px var(--fd-interrupt-completed-shadow);
394
396
  }
395
397
 
396
398
  .interrupt-bubble--cancelled {
397
- background: var(--fd-interrupt-cancelled-bg);
398
- border-color: var(--fd-interrupt-cancelled-border);
399
+ border-color: var(--fd-interrupt-prompt-border-cancelled);
399
400
  box-shadow: 0 2px 8px var(--fd-interrupt-cancelled-shadow);
400
401
  }
401
402
 
402
403
  .interrupt-bubble--error {
403
- background: var(--fd-interrupt-error-bg);
404
- border-color: var(--fd-interrupt-error-border);
404
+ border-color: var(--fd-interrupt-prompt-border-error);
405
405
  box-shadow: 0 2px 8px var(--fd-interrupt-error-shadow);
406
406
  }
407
407
 
@@ -409,55 +409,38 @@
409
409
  opacity: 0.9;
410
410
  }
411
411
 
412
- /* Avatar */
413
- .interrupt-bubble__avatar {
414
- flex-shrink: 0;
415
- width: 2.25rem;
416
- height: 2.25rem;
412
+ /* Header */
413
+ .interrupt-bubble__header {
417
414
  display: flex;
418
415
  align-items: center;
419
- justify-content: center;
420
- border-radius: 50%;
421
- background-color: var(--fd-interrupt-pending-avatar);
422
- color: #ffffff;
423
- font-size: 1.125rem;
424
- }
425
-
426
- .interrupt-bubble--completed .interrupt-bubble__avatar {
427
- background-color: var(--fd-interrupt-completed-avatar);
428
- }
429
-
430
- .interrupt-bubble--cancelled .interrupt-bubble__avatar {
431
- background-color: var(--fd-interrupt-cancelled-avatar);
416
+ justify-content: space-between;
417
+ gap: var(--fd-space-xs);
418
+ padding: var(--fd-space-md) var(--fd-space-xl);
419
+ background: var(--fd-interrupt-pending-bg);
420
+ border-bottom: 1px solid var(--fd-interrupt-prompt-border-pending);
432
421
  }
433
422
 
434
- .interrupt-bubble--error .interrupt-bubble__avatar {
435
- background-color: var(--fd-interrupt-error-avatar);
423
+ .interrupt-bubble--completed .interrupt-bubble__header {
424
+ background: var(--fd-interrupt-completed-bg);
425
+ border-bottom-color: var(--fd-interrupt-prompt-border-completed);
436
426
  }
437
427
 
438
- /* Content */
439
- .interrupt-bubble__content {
440
- flex: 1;
441
- min-width: 0;
442
- display: flex;
443
- flex-direction: column;
444
- gap: 0.75rem;
428
+ .interrupt-bubble--cancelled .interrupt-bubble__header {
429
+ background: var(--fd-interrupt-cancelled-bg);
430
+ border-bottom-color: var(--fd-interrupt-prompt-border-cancelled);
445
431
  }
446
432
 
447
- /* Header */
448
- .interrupt-bubble__header {
449
- display: flex;
450
- align-items: center;
451
- justify-content: space-between;
452
- gap: 0.5rem;
433
+ .interrupt-bubble--error .interrupt-bubble__header {
434
+ background: var(--fd-interrupt-error-bg);
435
+ border-bottom-color: var(--fd-interrupt-prompt-border-error);
453
436
  }
454
437
 
455
438
  .interrupt-bubble__type {
456
439
  display: flex;
457
440
  align-items: center;
458
- gap: 0.375rem;
441
+ gap: var(--fd-space-2xs);
459
442
  font-weight: 600;
460
- font-size: 0.875rem;
443
+ font-size: var(--fd-text-sm);
461
444
  color: var(--fd-interrupt-pending-text);
462
445
  }
463
446
 
@@ -474,9 +457,9 @@
474
457
  }
475
458
 
476
459
  .interrupt-bubble__timestamp {
477
- font-size: 0.6875rem;
460
+ font-size: var(--fd-text-2xs);
478
461
  color: var(--fd-interrupt-pending-text-light);
479
- font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
462
+ font-family: var(--fd-font-mono);
480
463
  }
481
464
 
482
465
  .interrupt-bubble--completed .interrupt-bubble__timestamp {
@@ -495,68 +478,92 @@
495
478
  .interrupt-bubble__error {
496
479
  display: flex;
497
480
  align-items: center;
498
- gap: 0.5rem;
499
- padding: 0.5rem 0.75rem;
481
+ gap: var(--fd-space-xs);
482
+ margin: var(--fd-space-md) var(--fd-space-xl) 0;
483
+ padding: var(--fd-space-xs) var(--fd-space-md);
500
484
  background-color: var(--fd-error-muted);
501
485
  border-radius: var(--fd-radius-md);
502
486
  color: var(--fd-interrupt-error-text);
503
- font-size: 0.8125rem;
487
+ font-size: var(--fd-interrupt-font-error);
504
488
  }
505
489
 
506
490
  .interrupt-bubble__retry-btn {
507
491
  display: inline-flex;
508
492
  align-items: center;
509
- gap: 0.25rem;
493
+ gap: var(--fd-space-3xs);
510
494
  margin-left: auto;
511
- padding: 0.25rem 0.5rem;
512
- font-size: 0.75rem;
495
+ padding: var(--fd-space-3xs) var(--fd-space-xs);
496
+ font-size: var(--fd-text-xs);
513
497
  font-weight: 500;
514
498
  font-family: inherit;
515
- color: #ffffff;
499
+ color: var(--fd-error-foreground);
516
500
  background-color: var(--fd-interrupt-error-avatar);
517
501
  border: none;
518
- border-radius: 0.25rem;
502
+ border-radius: var(--fd-radius-sm);
519
503
  cursor: pointer;
520
- transition: background-color 0.15s ease;
504
+ transition: background-color var(--fd-transition-fast);
521
505
  }
522
506
 
523
507
  .interrupt-bubble__retry-btn:hover {
524
508
  background-color: var(--fd-error-hover);
525
509
  }
526
510
 
527
- /* Prompt */
528
- .interrupt-bubble__prompt {
529
- background-color: var(--fd-interrupt-prompt-bg);
530
- border-radius: 0.5rem;
531
- padding: 1rem;
532
- border: 1px solid var(--fd-interrupt-prompt-border-pending);
511
+ /* Body - prompt content area, full width */
512
+ .interrupt-bubble__body {
513
+ padding: var(--fd-space-xl);
533
514
  }
534
515
 
535
- .interrupt-bubble--completed .interrupt-bubble__prompt {
536
- border-color: var(--fd-interrupt-prompt-border-completed);
516
+ .interrupt-bubble--cancelled .interrupt-bubble__body {
517
+ opacity: 0.75;
537
518
  }
538
519
 
539
- .interrupt-bubble--cancelled .interrupt-bubble__prompt {
540
- border-color: var(--fd-interrupt-prompt-border-cancelled);
541
- opacity: 0.75;
520
+ /* Desaturate body content in error state to reduce visual noise from green/red colors */
521
+ .interrupt-bubble--error .interrupt-bubble__body {
522
+ filter: saturate(0.2);
523
+ opacity: 0.7;
542
524
  }
543
525
 
544
- .interrupt-bubble--error .interrupt-bubble__prompt {
545
- border-color: var(--fd-interrupt-prompt-border-error);
526
+ /* Footer */
527
+ .interrupt-bubble__footer {
528
+ display: flex;
529
+ align-items: center;
530
+ justify-content: space-between;
531
+ gap: var(--fd-space-xs);
532
+ padding: var(--fd-space-md) var(--fd-space-xl);
533
+ background: var(--fd-interrupt-pending-bg);
534
+ border-top: 1px solid var(--fd-interrupt-prompt-border-pending);
535
+ }
536
+
537
+ .interrupt-bubble--completed .interrupt-bubble__footer {
538
+ background: var(--fd-interrupt-completed-bg);
539
+ border-top-color: var(--fd-interrupt-prompt-border-completed);
540
+ }
541
+
542
+ .interrupt-bubble--cancelled .interrupt-bubble__footer {
543
+ background: var(--fd-interrupt-cancelled-bg);
544
+ border-top-color: var(--fd-interrupt-prompt-border-cancelled);
545
+ }
546
+
547
+ .interrupt-bubble--error .interrupt-bubble__footer {
548
+ background: var(--fd-interrupt-error-bg);
549
+ border-top-color: var(--fd-interrupt-prompt-border-error);
546
550
  }
547
551
 
548
- /* Cancel button wrapper */
549
- .interrupt-bubble__cancel-wrapper {
552
+ .interrupt-bubble__node {
550
553
  display: flex;
551
- justify-content: flex-end;
554
+ align-items: center;
555
+ gap: var(--fd-space-3xs);
556
+ font-size: var(--fd-text-2xs);
557
+ color: var(--fd-muted-foreground);
552
558
  }
553
559
 
554
560
  .interrupt-bubble__cancel-btn {
555
561
  display: inline-flex;
556
562
  align-items: center;
557
- gap: 0.375rem;
558
- padding: 0.375rem 0.75rem;
559
- font-size: 0.75rem;
563
+ gap: var(--fd-space-2xs);
564
+ margin-left: auto;
565
+ padding: var(--fd-space-2xs) var(--fd-space-md);
566
+ font-size: var(--fd-text-xs);
560
567
  font-weight: 500;
561
568
  font-family: inherit;
562
569
  color: var(--fd-muted-foreground);
@@ -578,58 +585,17 @@
578
585
  cursor: not-allowed;
579
586
  }
580
587
 
581
- /* Footer */
582
- .interrupt-bubble__footer {
583
- display: flex;
584
- align-items: center;
585
- gap: 0.5rem;
586
- padding-top: 0.5rem;
587
- border-top: 1px solid var(--fd-interrupt-prompt-border-pending);
588
- }
589
-
590
- .interrupt-bubble--completed .interrupt-bubble__footer {
591
- border-color: var(--fd-interrupt-prompt-border-completed);
592
- }
593
-
594
- .interrupt-bubble--cancelled .interrupt-bubble__footer {
595
- border-color: var(--fd-interrupt-prompt-border-cancelled);
596
- }
597
-
598
- .interrupt-bubble--error .interrupt-bubble__footer {
599
- border-color: var(--fd-interrupt-prompt-border-error);
600
- }
601
-
602
- .interrupt-bubble__node {
603
- display: flex;
604
- align-items: center;
605
- gap: 0.25rem;
606
- font-size: 0.6875rem;
607
- color: var(--fd-interrupt-pending-text);
608
- }
609
-
610
- .interrupt-bubble--completed .interrupt-bubble__node {
611
- color: var(--fd-interrupt-completed-text);
612
- }
613
-
614
- .interrupt-bubble--cancelled .interrupt-bubble__node {
615
- color: var(--fd-interrupt-cancelled-text);
616
- }
617
-
618
- .interrupt-bubble--error .interrupt-bubble__node {
619
- color: var(--fd-interrupt-error-text);
620
- }
621
-
622
588
  /* Responsive */
623
589
  @media (max-width: 640px) {
624
590
  .interrupt-bubble {
625
- margin: 0.5rem;
626
- padding: 0.875rem 1rem;
591
+ margin: var(--fd-space-xs);
627
592
  }
628
593
 
629
- .interrupt-bubble__avatar {
630
- width: 2rem;
631
- height: 2rem;
632
- font-size: 1rem;
594
+ .interrupt-bubble__header,
595
+ .interrupt-bubble__body,
596
+ .interrupt-bubble__footer {
597
+ padding-left: var(--fd-space-lg);
598
+ padding-right: var(--fd-space-lg);
633
599
  }
634
600
  }
635
601
  </style>
@@ -1,5 +1,5 @@
1
1
  import type { Interrupt } from '../../types/interrupt.js';
2
- import { type InterruptWithState } from '../../stores/interruptStore.js';
2
+ import { type InterruptWithState } from '../../stores/interruptStore.svelte.js';
3
3
  /**
4
4
  * Component props
5
5
  */