sparkecoder 0.1.52 → 0.1.54

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 (138) hide show
  1. package/dist/agent/index.d.ts +2 -2
  2. package/dist/{index-dJv_dqUq.d.ts → index-BYOHniN4.d.ts} +5 -5
  3. package/dist/index.d.ts +3 -3
  4. package/dist/{search-DrztQ_iP.d.ts → search-DALwmPRX.d.ts} +5 -5
  5. package/dist/tools/index.d.ts +2 -2
  6. package/package.json +1 -1
  7. package/web/.next/BUILD_ID +1 -1
  8. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  9. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  10. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  11. package/web/.next/standalone/web/.next/server/app/(main)/page.js.nft.json +1 -1
  12. package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
  13. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
  14. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
  15. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  16. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  17. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  18. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  19. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  20. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  21. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  22. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  23. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  24. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  25. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/api/config/route.js.nft.json +1 -1
  31. package/web/.next/standalone/web/.next/server/app/api/health/route.js.nft.json +1 -1
  32. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  33. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  42. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  48. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  51. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  60. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/embed/[id]/page.js.nft.json +1 -1
  68. package/web/.next/standalone/web/.next/server/app/embed/[id]/page_client-reference-manifest.js +1 -1
  69. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  70. package/web/.next/standalone/web/.next/server/app/index.rsc +3 -3
  71. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
  72. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
  73. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +3 -3
  74. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_40c1da73._.js → 2374f_06a5ea48._.js} +1 -1
  78. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_ec658806._.js → 2374f_2572135b._.js} +1 -1
  79. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_c8f8a326._.js → 2374f_273991ba._.js} +1 -1
  80. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_13da7b2a._.js → 2374f_460c0d78._.js} +1 -1
  81. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_1de2f628._.js → 2374f_5ee28d4c._.js} +1 -1
  82. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_9f2fae06._.js → 2374f_65b86b54._.js} +1 -1
  83. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_f3c65774._.js → 2374f_7b421f78._.js} +1 -1
  84. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_41d07cce._.js → 2374f_88cbeb7b._.js} +1 -1
  85. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_2bfcd3a2._.js → 2374f_8d018190._.js} +1 -1
  86. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_e5142825._.js → 2374f_a7457131._.js} +1 -1
  87. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_dd21a4e9._.js → 2374f_c9e3cd7b._.js} +1 -1
  88. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_88aa1671._.js → 2374f_de035f79._.js} +1 -1
  89. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_ac79ddf4._.js → 2374f_df3c414e._.js} +1 -1
  90. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_6d8e5e94._.js → 2374f_ec997752._.js} +1 -1
  91. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__a87e1c27._.js +3 -3
  92. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__43405ad6._.js → [root-of-the-server]__c94aac98._.js} +2 -2
  93. package/web/.next/standalone/web/.next/server/chunks/ssr/{web_273500a6._.js → web_9c9f0e3b._.js} +2 -2
  94. package/web/.next/standalone/web/.next/server/chunks/ssr/{web_329773d1._.js → web_b85931da._.js} +2 -2
  95. package/web/.next/standalone/web/.next/server/chunks/ssr/{web_8305f089._.js → web_d08270f7._.js} +2 -2
  96. package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_components_sessions-sidebar_tsx_92510070._.js +1 -1
  97. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  98. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  99. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  100. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  101. package/web/.next/standalone/web/.next/static/chunks/3f295b6960943c38.js +1 -0
  102. package/web/.next/standalone/web/.next/static/chunks/{e69c4473f80e8752.js → 9b4c4424a720586b.js} +6 -6
  103. package/web/.next/standalone/web/.next/static/chunks/a2b4737b190d1b54.js +5 -0
  104. package/web/.next/{static/chunks/b7d722dab2a7ecc0.js → standalone/web/.next/static/chunks/e97212fcc8221479.js} +2 -2
  105. package/web/.next/standalone/web/.next/static/chunks/f6e47c8a9766ce91.js +7 -0
  106. package/web/.next/standalone/web/.next/static/static/chunks/3f295b6960943c38.js +1 -0
  107. package/web/.next/standalone/web/.next/static/static/chunks/{e69c4473f80e8752.js → 9b4c4424a720586b.js} +6 -6
  108. package/web/.next/standalone/web/.next/static/static/chunks/a2b4737b190d1b54.js +5 -0
  109. package/web/.next/standalone/web/.next/static/static/chunks/{b7d722dab2a7ecc0.js → e97212fcc8221479.js} +2 -2
  110. package/web/.next/standalone/web/.next/static/static/chunks/f6e47c8a9766ce91.js +7 -0
  111. package/web/.next/standalone/web/src/components/ai-elements/search-tool.tsx +26 -3
  112. package/web/.next/standalone/web/src/components/ai-elements/subagent-modal.tsx +13 -1
  113. package/web/.next/standalone/web/src/components/chat-interface.tsx +79 -74
  114. package/web/.next/standalone/web/src/components/sessions-sidebar.tsx +23 -1
  115. package/web/.next/standalone/web/src/hooks/use-notification-sound.ts +78 -0
  116. package/web/.next/static/chunks/3f295b6960943c38.js +1 -0
  117. package/web/.next/static/chunks/{e69c4473f80e8752.js → 9b4c4424a720586b.js} +6 -6
  118. package/web/.next/static/chunks/a2b4737b190d1b54.js +5 -0
  119. package/web/.next/{standalone/web/.next/static/chunks/b7d722dab2a7ecc0.js → static/chunks/e97212fcc8221479.js} +2 -2
  120. package/web/.next/static/chunks/f6e47c8a9766ce91.js +7 -0
  121. package/web/.next/standalone/web/.next/static/chunks/96ec96279ada0efe.js +0 -1
  122. package/web/.next/standalone/web/.next/static/chunks/cc6d43f798bbe415.js +0 -5
  123. package/web/.next/standalone/web/.next/static/chunks/de71e63276f488bb.js +0 -7
  124. package/web/.next/standalone/web/.next/static/static/chunks/96ec96279ada0efe.js +0 -1
  125. package/web/.next/standalone/web/.next/static/static/chunks/cc6d43f798bbe415.js +0 -5
  126. package/web/.next/standalone/web/.next/static/static/chunks/de71e63276f488bb.js +0 -7
  127. package/web/.next/static/chunks/96ec96279ada0efe.js +0 -1
  128. package/web/.next/static/chunks/cc6d43f798bbe415.js +0 -5
  129. package/web/.next/static/chunks/de71e63276f488bb.js +0 -7
  130. /package/web/.next/standalone/web/.next/static/{TLPvH3fh2g6xnXoqOVcq8 → 7rKMR1VNC_1_vH6S9H5aS}/_buildManifest.js +0 -0
  131. /package/web/.next/standalone/web/.next/static/{TLPvH3fh2g6xnXoqOVcq8 → 7rKMR1VNC_1_vH6S9H5aS}/_clientMiddlewareManifest.json +0 -0
  132. /package/web/.next/standalone/web/.next/static/{TLPvH3fh2g6xnXoqOVcq8 → 7rKMR1VNC_1_vH6S9H5aS}/_ssgManifest.js +0 -0
  133. /package/web/.next/standalone/web/.next/static/static/{TLPvH3fh2g6xnXoqOVcq8 → 7rKMR1VNC_1_vH6S9H5aS}/_buildManifest.js +0 -0
  134. /package/web/.next/standalone/web/.next/static/static/{TLPvH3fh2g6xnXoqOVcq8 → 7rKMR1VNC_1_vH6S9H5aS}/_clientMiddlewareManifest.json +0 -0
  135. /package/web/.next/standalone/web/.next/static/static/{TLPvH3fh2g6xnXoqOVcq8 → 7rKMR1VNC_1_vH6S9H5aS}/_ssgManifest.js +0 -0
  136. /package/web/.next/static/{TLPvH3fh2g6xnXoqOVcq8 → 7rKMR1VNC_1_vH6S9H5aS}/_buildManifest.js +0 -0
  137. /package/web/.next/static/{TLPvH3fh2g6xnXoqOVcq8 → 7rKMR1VNC_1_vH6S9H5aS}/_clientMiddlewareManifest.json +0 -0
  138. /package/web/.next/static/{TLPvH3fh2g6xnXoqOVcq8 → 7rKMR1VNC_1_vH6S9H5aS}/_ssgManifest.js +0 -0
@@ -116,6 +116,7 @@ import {
116
116
  import { TodoPanel } from '@/components/ai-elements/todo-panel';
117
117
  import { getConfig, type AppConfig } from '@/lib/config';
118
118
  import { mutateSessions } from '@/hooks/use-sessions';
119
+ import { useNotificationSound } from '@/hooks/use-notification-sound';
119
120
  import {
120
121
  Select,
121
122
  SelectContent,
@@ -368,6 +369,10 @@ export function ChatInterface({ session, isEmbed = false }: ChatInterfaceProps)
368
369
  const [pendingSelectedElements, setPendingSelectedElements] = useState<string | null>(null);
369
370
  const [isRunning, setIsRunning] = useState(false);
370
371
  const [messageQueue, setMessageQueue] = useState<QueuedMessage[]>([]);
372
+ // Ref mirror of messageQueue so SSE event handlers can read the latest queue
373
+ // without stale closures. Updated on every render.
374
+ const messageQueueRef = useRef<QueuedMessage[]>([]);
375
+ messageQueueRef.current = messageQueue;
371
376
  const [editingQueueId, setEditingQueueId] = useState<string | null>(null);
372
377
  const [editingQueueText, setEditingQueueText] = useState('');
373
378
  const [queueExpanded, setQueueExpanded] = useState(true);
@@ -409,6 +414,9 @@ export function ChatInterface({ session, isEmbed = false }: ChatInterfaceProps)
409
414
  const sessionIdRef = useRef(session.id);
410
415
  sessionIdRef.current = session.id;
411
416
 
417
+ // Notification sound
418
+ const { playDing } = useNotificationSound();
419
+
412
420
  // Version check state
413
421
  const [versionInfo, setVersionInfo] = useState<VersionInfo | null>(null);
414
422
  const [updateBannerDismissed, setUpdateBannerDismissed] = useState(false);
@@ -1051,15 +1059,40 @@ export function ChatInterface({ session, isEmbed = false }: ChatInterfaceProps)
1051
1059
  setCurrentText('');
1052
1060
  }
1053
1061
 
1054
- // Create a new streaming tool call
1055
- const streamingToolCall: ToolCallInfo = {
1056
- toolCallId: event.toolCallId,
1057
- toolName: event.toolName,
1058
- input: {},
1059
- status: 'streaming' as const,
1060
- streamingArgsText: '',
1061
- };
1062
- toolCallsRef.current = [...toolCallsRef.current, streamingToolCall];
1062
+ // Check if there's already a placeholder for this tool type
1063
+ // (created from early tool-progress events before this SSE arrives)
1064
+ {
1065
+ const placeholderPrefix = `${event.toolName}_pending_`;
1066
+ const existingPlaceholder = toolCallsRef.current.find(
1067
+ tc => tc.toolName === event.toolName && tc.toolCallId.startsWith(placeholderPrefix)
1068
+ );
1069
+ const alreadyExists = toolCallsRef.current.some(tc => tc.toolCallId === event.toolCallId);
1070
+
1071
+ if (existingPlaceholder) {
1072
+ // Replace placeholder with real tool call, preserving accumulated data
1073
+ toolCallsRef.current = toolCallsRef.current.map((tc) => {
1074
+ if (tc.toolCallId !== existingPlaceholder.toolCallId) return tc;
1075
+ return {
1076
+ ...tc,
1077
+ toolCallId: event.toolCallId,
1078
+ toolName: event.toolName,
1079
+ status: 'streaming' as const,
1080
+ streamingArgsText: '',
1081
+ };
1082
+ });
1083
+ } else if (!alreadyExists) {
1084
+ // Create a new streaming tool call
1085
+ const streamingToolCall: ToolCallInfo = {
1086
+ toolCallId: event.toolCallId,
1087
+ toolName: event.toolName,
1088
+ input: {},
1089
+ status: 'streaming' as const,
1090
+ streamingArgsText: '',
1091
+ };
1092
+ toolCallsRef.current = [...toolCallsRef.current, streamingToolCall];
1093
+ }
1094
+ // If alreadyExists, do nothing - tool-input-available will update it
1095
+ }
1063
1096
  setCurrentToolCalls([...toolCallsRef.current]);
1064
1097
  break;
1065
1098
 
@@ -1110,19 +1143,20 @@ export function ChatInterface({ session, isEmbed = false }: ChatInterfaceProps)
1110
1143
  setCurrentText('');
1111
1144
  }
1112
1145
 
1113
- // Create/update the tool call info, preserving live content from placeholder
1146
+ // Create/update the tool call info, preserving live content from any source
1147
+ // (placeholder, existing streaming entry, or tool-input-start entry)
1114
1148
  const toolCallInfo: ToolCallInfo = {
1115
1149
  toolCallId: event.toolCallId,
1116
1150
  toolName: event.toolName,
1117
1151
  input: event.input,
1118
1152
  status: 'running' as const,
1119
1153
  streamingArgsText: existingToolCall?.streamingArgsText,
1120
- // Preserve live content from placeholder if it exists
1121
- liveContent: placeholderWriteFile?.liveContent,
1122
- liveOldString: placeholderWriteFile?.liveOldString,
1123
- liveNewString: placeholderWriteFile?.liveNewString,
1124
- // Preserve explore steps from placeholder if it exists
1125
- exploreSteps: placeholderExplore?.exploreSteps,
1154
+ // Preserve live content from whatever source has it
1155
+ liveContent: placeholderWriteFile?.liveContent || existingToolCall?.liveContent,
1156
+ liveOldString: placeholderWriteFile?.liveOldString || existingToolCall?.liveOldString,
1157
+ liveNewString: placeholderWriteFile?.liveNewString || existingToolCall?.liveNewString,
1158
+ // Preserve explore steps from whatever source has them
1159
+ exploreSteps: placeholderExplore?.exploreSteps || existingToolCall?.exploreSteps,
1126
1160
  };
1127
1161
 
1128
1162
  // Update toolCallsRef
@@ -1287,26 +1321,33 @@ export function ChatInterface({ session, isEmbed = false }: ChatInterfaceProps)
1287
1321
  // Don't reset lastKnownStreamIdRef here - it helps prevent reconnecting to same stream
1288
1322
  setIsRunning(false);
1289
1323
  setIsWatching(false);
1324
+ playDing();
1290
1325
 
1291
- // Reload messages and checkpoints after stream finishes
1292
- // This ensures messages have proper messageSequence for the revert button.
1293
- // We DON'T clear chatItems first - the current items stay visible until
1294
- // the API response arrives, preventing the "flash" where everything disappears.
1326
+ // Only refresh checkpoints (for revert buttons) - NOT chatItems.
1295
1327
  {
1296
1328
  const finishSessionId = session.id;
1297
- Promise.all([
1298
- getSessionMessages(finishSessionId),
1299
- getSessionCheckpoints(finishSessionId).catch(() => ({ checkpoints: [] })),
1300
- ]).then(([apiMessages, checkpointsData]) => {
1301
- // Guard: don't overwrite if the user switched sessions while we were loading
1302
- if (sessionIdRef.current !== finishSessionId) return;
1303
- const sorted = [...apiMessages].sort((a, b) =>
1304
- new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
1305
- );
1306
- const converted = convertApiMessages(sorted);
1307
- setChatItems(converted);
1308
- setCheckpoints(checkpointsData.checkpoints || []);
1309
- }).catch(() => {}); // Silently ignore errors
1329
+ getSessionCheckpoints(finishSessionId)
1330
+ .then((checkpointsData) => {
1331
+ if (sessionIdRef.current !== finishSessionId) return;
1332
+ setCheckpoints(checkpointsData.checkpoints || []);
1333
+ })
1334
+ .catch(() => {});
1335
+ }
1336
+
1337
+ // Send next queued message directly from the finish event.
1338
+ // This is the correct place to do it: one event → one send.
1339
+ // No useEffect, no timers, no race conditions.
1340
+ {
1341
+ const queue = messageQueueRef.current;
1342
+ if (queue.length > 0) {
1343
+ const next = queue[0];
1344
+ setMessageQueue((prev) => prev.slice(1));
1345
+ // Small delay so React can commit the state reset above first,
1346
+ // then start the new stream in a fresh render cycle
1347
+ setTimeout(() => {
1348
+ executeSubmitRef.current(next.text, next.attachments, next.selectedElements);
1349
+ }, 50);
1350
+ }
1310
1351
  }
1311
1352
  break;
1312
1353
 
@@ -1848,46 +1889,12 @@ export function ChatInterface({ session, isEmbed = false }: ChatInterfaceProps)
1848
1889
  setIsWatching(false);
1849
1890
  };
1850
1891
 
1851
- // Keep a ref to executeSubmit so the auto-send effect always calls the
1852
- // latest version (avoids stale closure capturing old handleSSEEvent, etc.)
1892
+ // Ref to executeSubmit so SSE handlers and sendNow can always call the latest version
1853
1893
  const executeSubmitRef = useRef(executeSubmit);
1854
1894
  executeSubmitRef.current = executeSubmit;
1855
-
1856
- // Auto-send next queued message when assistant finishes
1857
- const prevIsRunningRef = useRef(isRunning);
1858
- const skipAutoSendRef = useRef(false); // Set by sendNow to prevent double-send
1859
- useEffect(() => {
1860
- const wasRunning = prevIsRunningRef.current;
1861
- prevIsRunningRef.current = isRunning;
1862
-
1863
- // Auto-send whenever we're idle and there are queued messages.
1864
- // This covers both:
1865
- // 1. Agent just finished (wasRunning=true → isRunning=false) with a queue
1866
- // 2. Queue got a new item while already idle (e.g., agent finished BEFORE
1867
- // the user queued a message, so the running→stopped transition was missed)
1868
- // Safe because executeSubmit sets isRunning=true, preventing re-entry
1869
- // until the next agent response finishes.
1870
- const shouldAutoSend = !isRunning && messageQueue.length > 0;
1871
-
1872
- if (shouldAutoSend) {
1873
- // If sendNow triggered the stop, skip auto-send (it handles its own send)
1874
- if (skipAutoSendRef.current) {
1875
- skipAutoSendRef.current = false;
1876
- return;
1877
- }
1878
- // Small delay to let UI settle
1879
- const timer = setTimeout(() => {
1880
- setMessageQueue((prev) => {
1881
- if (prev.length === 0) return prev;
1882
- const [next, ...rest] = prev;
1883
- // Use ref to always call the latest executeSubmit (not a stale closure)
1884
- executeSubmitRef.current(next.text, next.attachments, next.selectedElements);
1885
- return rest;
1886
- });
1887
- }, 300);
1888
- return () => clearTimeout(timer);
1889
- }
1890
- }, [isRunning, messageQueue.length]);
1895
+
1896
+ // Note: Queue auto-send is handled directly in the 'finish' SSE event handler,
1897
+ // not via useEffect. This avoids timers, stale closures, and double-fires.
1891
1898
 
1892
1899
  // Queue management helpers
1893
1900
  const removeFromQueue = (id: string) => {
@@ -1924,11 +1931,9 @@ export function ChatInterface({ session, isEmbed = false }: ChatInterfaceProps)
1924
1931
  // Remove from queue
1925
1932
  setMessageQueue((prev) => prev.filter((m) => m.id !== id));
1926
1933
 
1927
- // Stop current if running
1934
+ // Stop current if running, then send after it settles
1928
1935
  if (isRunning) {
1929
- skipAutoSendRef.current = true; // Prevent auto-send from firing
1930
1936
  await handleStop();
1931
- // Wait for stop to settle, then send using ref for fresh closure
1932
1937
  setTimeout(() => {
1933
1938
  executeSubmitRef.current(item.text, item.attachments, item.selectedElements);
1934
1939
  }, 500);
@@ -4,7 +4,7 @@ import { useState, useEffect, useRef } from 'react';
4
4
  import { useRouter, usePathname } from 'next/navigation';
5
5
  import Link from 'next/link';
6
6
  import Image from 'next/image';
7
- import { Plus, MessageSquare, Trash2, Loader2, Settings, PanelLeftClose, PanelLeft, Key, Check, X, Eye, EyeOff } from 'lucide-react';
7
+ import { Plus, MessageSquare, Trash2, Loader2, Settings, PanelLeftClose, PanelLeft, Key, Check, X, Eye, EyeOff, Volume2 } from 'lucide-react';
8
8
  import {
9
9
  Sidebar,
10
10
  SidebarContent,
@@ -45,6 +45,7 @@ import { createSession, deleteSession, getApiKeys, setApiKey, type ApiKeyStatus
45
45
  import { getConfig, type AppConfig } from '@/lib/config';
46
46
  import { cn } from '@/lib/utils';
47
47
  import { useSessions, mutateSessions } from '@/hooks/use-sessions';
48
+ import { useNotificationSound } from '@/hooks/use-notification-sound';
48
49
 
49
50
  // Format relative time like "2m", "1h", "3d"
50
51
  function formatRelativeTime(dateString: string): string {
@@ -87,6 +88,9 @@ export function SessionsSidebar() {
87
88
  const [showApiKey, setShowApiKey] = useState(false);
88
89
  const [savingApiKey, setSavingApiKey] = useState(false);
89
90
 
91
+ // Notification sound setting
92
+ const { enabled: soundEnabled, setEnabled: setSoundEnabled } = useNotificationSound();
93
+
90
94
  // Detect if we're in embed mode
91
95
  const isEmbedMode = pathname.startsWith('/embed/');
92
96
 
@@ -828,6 +832,24 @@ export function SessionsSidebar() {
828
832
  </div>
829
833
  </div>
830
834
 
835
+ {/* Notification Sound */}
836
+ <div className="space-y-1.5">
837
+ <Label className="flex items-center gap-2 text-sm font-medium">
838
+ <Volume2 className="size-4" />
839
+ Notification Sound
840
+ </Label>
841
+ <div className="flex items-center justify-between rounded-lg border p-2.5 bg-muted/30">
842
+ <div className="space-y-0">
843
+ <span className="text-sm font-medium">Play sound when done</span>
844
+ <p className="text-[11px] text-muted-foreground">Ding when the assistant finishes responding</p>
845
+ </div>
846
+ <Switch
847
+ checked={soundEnabled}
848
+ onCheckedChange={setSoundEnabled}
849
+ />
850
+ </div>
851
+ </div>
852
+
831
853
  <p className="text-xs text-muted-foreground">
832
854
  These settings apply to new sessions. You can also change the model per-session in the chat header.
833
855
  </p>
@@ -0,0 +1,78 @@
1
+ 'use client';
2
+
3
+ import { useState, useCallback, useRef, useEffect } from 'react';
4
+
5
+ const STORAGE_KEY = 'sparkecoder_notification_sound';
6
+
7
+ /**
8
+ * Synthesize a pleasant two-tone "ding" using the Web Audio API.
9
+ * No audio file needed – it generates the tones on the fly.
10
+ */
11
+ function playDingSound() {
12
+ try {
13
+ const ctx = new (window.AudioContext || (window as any).webkitAudioContext)();
14
+
15
+ // --- first tone (higher, shorter) ---
16
+ const osc1 = ctx.createOscillator();
17
+ const gain1 = ctx.createGain();
18
+ osc1.type = 'sine';
19
+ osc1.frequency.setValueAtTime(880, ctx.currentTime); // A5
20
+ gain1.gain.setValueAtTime(0.3, ctx.currentTime);
21
+ gain1.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.3);
22
+ osc1.connect(gain1);
23
+ gain1.connect(ctx.destination);
24
+ osc1.start(ctx.currentTime);
25
+ osc1.stop(ctx.currentTime + 0.3);
26
+
27
+ // --- second tone (slightly higher, slightly delayed) ---
28
+ const osc2 = ctx.createOscillator();
29
+ const gain2 = ctx.createGain();
30
+ osc2.type = 'sine';
31
+ osc2.frequency.setValueAtTime(1174.66, ctx.currentTime + 0.15); // D6
32
+ gain2.gain.setValueAtTime(0.0001, ctx.currentTime);
33
+ gain2.gain.setValueAtTime(0.25, ctx.currentTime + 0.15);
34
+ gain2.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.5);
35
+ osc2.connect(gain2);
36
+ gain2.connect(ctx.destination);
37
+ osc2.start(ctx.currentTime + 0.15);
38
+ osc2.stop(ctx.currentTime + 0.5);
39
+
40
+ // Clean up context after the sound finishes
41
+ setTimeout(() => ctx.close(), 600);
42
+ } catch {
43
+ // Silently ignore – e.g. if AudioContext isn't available
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Hook to manage the notification sound setting and playback.
49
+ *
50
+ * - `enabled` / `setEnabled` – toggle stored in localStorage
51
+ * - `playDing()` – plays the ding only when enabled
52
+ */
53
+ export function useNotificationSound() {
54
+ const [enabled, setEnabledState] = useState(() => {
55
+ if (typeof window === 'undefined') return true;
56
+ const stored = localStorage.getItem(STORAGE_KEY);
57
+ return stored === null ? true : stored === 'true'; // default ON
58
+ });
59
+
60
+ // Keep a ref so callbacks that capture stale closures still see the latest value
61
+ const enabledRef = useRef(enabled);
62
+ useEffect(() => {
63
+ enabledRef.current = enabled;
64
+ }, [enabled]);
65
+
66
+ const setEnabled = useCallback((value: boolean) => {
67
+ setEnabledState(value);
68
+ localStorage.setItem(STORAGE_KEY, String(value));
69
+ }, []);
70
+
71
+ const playDing = useCallback(() => {
72
+ if (enabledRef.current) {
73
+ playDingSound();
74
+ }
75
+ }, []);
76
+
77
+ return { enabled, setEnabled, playDing } as const;
78
+ }
@@ -0,0 +1 @@
1
+ (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,819609,(e,t,s)=>{"use strict";Object.defineProperty(s,"__esModule",{value:!0}),Object.defineProperty(s,"warnOnce",{enumerable:!0,get:function(){return r}});let r=e=>{}},215232,(e,t,s)=>{"use strict";Object.defineProperty(s,"__esModule",{value:!0}),Object.defineProperty(s,"useMergedRef",{enumerable:!0,get:function(){return n}});let r=e.r(430878);function n(e,t){let s=(0,r.useRef)(null),n=(0,r.useRef)(null);return(0,r.useCallback)(r=>{if(null===r){let e=s.current;e&&(s.current=null,e());let t=n.current;t&&(n.current=null,t())}else e&&(s.current=a(e,r)),t&&(n.current=a(t,r))},[e,t])}function a(e,t){if("function"!=typeof e)return e.current=t,()=>{e.current=null};{let s=e(t);return"function"==typeof s?s:()=>e(null)}}("function"==typeof s.default||"object"==typeof s.default&&null!==s.default)&&void 0===s.default.__esModule&&(Object.defineProperty(s.default,"__esModule",{value:!0}),Object.assign(s.default,s),t.exports=s.default)},325203,(e,t,s)=>{"use strict";Object.defineProperty(s,"__esModule",{value:!0});var r={assign:function(){return o},searchParamsToUrlQuery:function(){return a},urlQueryToSearchParams:function(){return l}};for(var n in r)Object.defineProperty(s,n,{enumerable:!0,get:r[n]});function a(e){let t={};for(let[s,r]of e.entries()){let e=t[s];void 0===e?t[s]=r:Array.isArray(e)?e.push(r):t[s]=[e,r]}return t}function i(e){return"string"==typeof e?e:("number"!=typeof e||isNaN(e))&&"boolean"!=typeof e?"":String(e)}function l(e){let t=new URLSearchParams;for(let[s,r]of Object.entries(e))if(Array.isArray(r))for(let e of r)t.append(s,i(e));else t.set(s,i(r));return t}function o(e,...t){for(let s of t){for(let t of s.keys())e.delete(t);for(let[t,r]of s.entries())e.append(t,r)}return e}},971746,(e,t,s)=>{"use strict";Object.defineProperty(s,"__esModule",{value:!0});var r={formatUrl:function(){return l},formatWithValidation:function(){return c},urlObjectKeys:function(){return o}};for(var n in r)Object.defineProperty(s,n,{enumerable:!0,get:r[n]});let a=e.r(279510)._(e.r(325203)),i=/https?|ftp|gopher|file/;function l(e){let{auth:t,hostname:s}=e,r=e.protocol||"",n=e.pathname||"",l=e.hash||"",o=e.query||"",c=!1;t=t?encodeURIComponent(t).replace(/%3A/i,":")+"@":"",e.host?c=t+e.host:s&&(c=t+(~s.indexOf(":")?`[${s}]`:s),e.port&&(c+=":"+e.port)),o&&"object"==typeof o&&(o=String(a.urlQueryToSearchParams(o)));let d=e.search||o&&`?${o}`||"";return r&&!r.endsWith(":")&&(r+=":"),e.slashes||(!r||i.test(r))&&!1!==c?(c="//"+(c||""),n&&"/"!==n[0]&&(n="/"+n)):c||(c=""),l&&"#"!==l[0]&&(l="#"+l),d&&"?"!==d[0]&&(d="?"+d),n=n.replace(/[?#]/g,encodeURIComponent),d=d.replace("#","%23"),`${r}${c}${n}${d}${l}`}let o=["auth","hash","host","hostname","href","path","pathname","port","protocol","query","search","slashes"];function c(e){return l(e)}},309008,(e,t,s)=>{"use strict";Object.defineProperty(s,"__esModule",{value:!0});var r={DecodeError:function(){return g},MiddlewareNotFoundError:function(){return b},MissingStaticPage:function(){return v},NormalizeError:function(){return j},PageNotFoundError:function(){return y},SP:function(){return x},ST:function(){return f},WEB_VITALS:function(){return a},execOnce:function(){return i},getDisplayName:function(){return u},getLocationOrigin:function(){return c},getURL:function(){return d},isAbsoluteUrl:function(){return o},isResSent:function(){return m},loadGetInitialProps:function(){return h},normalizeRepeatedSlashes:function(){return p},stringifyError:function(){return N}};for(var n in r)Object.defineProperty(s,n,{enumerable:!0,get:r[n]});let a=["CLS","FCP","FID","INP","LCP","TTFB"];function i(e){let t,s=!1;return(...r)=>(s||(s=!0,t=e(...r)),t)}let l=/^[a-zA-Z][a-zA-Z\d+\-.]*?:/,o=e=>l.test(e);function c(){let{protocol:e,hostname:t,port:s}=window.location;return`${e}//${t}${s?":"+s:""}`}function d(){let{href:e}=window.location,t=c();return e.substring(t.length)}function u(e){return"string"==typeof e?e:e.displayName||e.name||"Unknown"}function m(e){return e.finished||e.headersSent}function p(e){let t=e.split("?");return t[0].replace(/\\/g,"/").replace(/\/\/+/g,"/")+(t[1]?`?${t.slice(1).join("?")}`:"")}async function h(e,t){let s=t.res||t.ctx&&t.ctx.res;if(!e.getInitialProps)return t.ctx&&t.Component?{pageProps:await h(t.Component,t.ctx)}:{};let r=await e.getInitialProps(t);if(s&&m(s))return r;if(!r)throw Object.defineProperty(Error(`"${u(e)}.getInitialProps()" should resolve to an object. But found "${r}" instead.`),"__NEXT_ERROR_CODE",{value:"E394",enumerable:!1,configurable:!0});return r}let x="u">typeof performance,f=x&&["mark","measure","getEntriesByName"].every(e=>"function"==typeof performance[e]);class g extends Error{}class j extends Error{}class y extends Error{constructor(e){super(),this.code="ENOENT",this.name="PageNotFoundError",this.message=`Cannot find module for page: ${e}`}}class v extends Error{constructor(e,t){super(),this.message=`Failed to load static file for page: ${e} ${t}`}}class b extends Error{constructor(){super(),this.code="ENOENT",this.message="Cannot find the middleware module"}}function N(e){return JSON.stringify({message:e.message,stack:e.stack})}},868988,(e,t,s)=>{"use strict";Object.defineProperty(s,"__esModule",{value:!0}),Object.defineProperty(s,"isLocalURL",{enumerable:!0,get:function(){return a}});let r=e.r(309008),n=e.r(698018);function a(e){if(!(0,r.isAbsoluteUrl)(e))return!0;try{let t=(0,r.getLocationOrigin)(),s=new URL(e,t);return s.origin===t&&(0,n.hasBasePath)(s.pathname)}catch(e){return!1}}},312491,(e,t,s)=>{"use strict";Object.defineProperty(s,"__esModule",{value:!0}),Object.defineProperty(s,"errorOnce",{enumerable:!0,get:function(){return r}});let r=e=>{}},504561,(e,t,s)=>{"use strict";Object.defineProperty(s,"__esModule",{value:!0});var r={default:function(){return g},useLinkStatus:function(){return y}};for(var n in r)Object.defineProperty(s,n,{enumerable:!0,get:r[n]});let a=e.r(279510),i=e.r(414294),l=a._(e.r(430878)),o=e.r(971746),c=e.r(369168),d=e.r(215232),u=e.r(309008),m=e.r(869343);e.r(819609);let p=e.r(93505),h=e.r(868988),x=e.r(291544);function f(e){return"string"==typeof e?e:(0,o.formatUrl)(e)}function g(t){var s;let r,n,a,[o,g]=(0,l.useOptimistic)(p.IDLE_LINK_STATUS),y=(0,l.useRef)(null),{href:v,as:b,children:N,prefetch:S=null,passHref:k,replace:C,shallow:T,scroll:w,onClick:P,onMouseEnter:z,onTouchStart:M,legacyBehavior:E=!1,onNavigate:O,ref:A,unstable_dynamicOnHover:_,...L}=t;r=N,E&&("string"==typeof r||"number"==typeof r)&&(r=(0,i.jsx)("a",{children:r}));let $=l.default.useContext(c.AppRouterContext),I=!1!==S,D=!1!==S?null===(s=S)||"auto"===s?x.FetchStrategy.PPR:x.FetchStrategy.Full:x.FetchStrategy.PPR,{href:R,as:B}=l.default.useMemo(()=>{let e=f(v);return{href:e,as:b?f(b):e}},[v,b]);if(E){if(r?.$$typeof===Symbol.for("react.lazy"))throw Object.defineProperty(Error("`<Link legacyBehavior>` received a direct child that is either a Server Component, or JSX that was loaded with React.lazy(). This is not supported. Either remove legacyBehavior, or make the direct child a Client Component that renders the Link's `<a>` tag."),"__NEXT_ERROR_CODE",{value:"E863",enumerable:!1,configurable:!0});n=l.default.Children.only(r)}let F=E?n&&"object"==typeof n&&n.ref:A,U=l.default.useCallback(e=>(null!==$&&(y.current=(0,p.mountLinkInstance)(e,R,$,D,I,g)),()=>{y.current&&((0,p.unmountLinkForCurrentNavigation)(y.current),y.current=null),(0,p.unmountPrefetchableInstance)(e)}),[I,R,$,D,g]),K={ref:(0,d.useMergedRef)(U,F),onClick(t){E||"function"!=typeof P||P(t),E&&n.props&&"function"==typeof n.props.onClick&&n.props.onClick(t),!$||t.defaultPrevented||function(t,s,r,n,a,i,o){if("u">typeof window){let c,{nodeName:d}=t.currentTarget;if("A"===d.toUpperCase()&&((c=t.currentTarget.getAttribute("target"))&&"_self"!==c||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey||t.nativeEvent&&2===t.nativeEvent.which)||t.currentTarget.hasAttribute("download"))return;if(!(0,h.isLocalURL)(s)){a&&(t.preventDefault(),location.replace(s));return}if(t.preventDefault(),o){let e=!1;if(o({preventDefault:()=>{e=!0}}),e)return}let{dispatchNavigateAction:u}=e.r(389867);l.default.startTransition(()=>{u(r||s,a?"replace":"push",i??!0,n.current)})}}(t,R,B,y,C,w,O)},onMouseEnter(e){E||"function"!=typeof z||z(e),E&&n.props&&"function"==typeof n.props.onMouseEnter&&n.props.onMouseEnter(e),$&&I&&(0,p.onNavigationIntent)(e.currentTarget,!0===_)},onTouchStart:function(e){E||"function"!=typeof M||M(e),E&&n.props&&"function"==typeof n.props.onTouchStart&&n.props.onTouchStart(e),$&&I&&(0,p.onNavigationIntent)(e.currentTarget,!0===_)}};return(0,u.isAbsoluteUrl)(B)?K.href=B:E&&!k&&("a"!==n.type||"href"in n.props)||(K.href=(0,m.addBasePath)(B)),a=E?l.default.cloneElement(n,K):(0,i.jsx)("a",{...L,...K,children:r}),(0,i.jsx)(j.Provider,{value:o,children:a})}e.r(312491);let j=(0,l.createContext)(p.IDLE_LINK_STATUS),y=()=>(0,l.useContext)(j);("function"==typeof s.default||"object"==typeof s.default&&null!==s.default)&&void 0===s.default.__esModule&&(Object.defineProperty(s.default,"__esModule",{value:!0}),Object.assign(s.default,s),t.exports=s.default)},996720,e=>{"use strict";var t=e.i(257868);e.s(["Plus",()=>t.default])},667249,e=>{"use strict";let t=(0,e.i(292511).default)("message-square",[["path",{d:"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z",key:"18887p"}]]);e.s(["MessageSquare",()=>t],667249)},846193,e=>{"use strict";let t=(0,e.i(292511).default)("key",[["path",{d:"m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4",key:"g0fldk"}],["path",{d:"m21 2-9.6 9.6",key:"1j0ho8"}],["circle",{cx:"7.5",cy:"15.5",r:"5.5",key:"yqb3hr"}]]);e.s(["Key",()=>t],846193)},421722,e=>{"use strict";var t=e.i(414294),s=e.i(430878),r=e.i(353913),n=e.i(504561),a=e.i(292623),i=e.i(996720),l=e.i(667249),o=e.i(904781),c=e.i(461957),d=e.i(816187),u=e.i(292511);let m=(0,u.default)("panel-left-close",[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M9 3v18",key:"fh3hqa"}],["path",{d:"m16 15-3-3 3-3",key:"14y99z"}]]);var p=e.i(220563),h=e.i(846193),x=e.i(719583),f=e.i(707387),g=e.i(481298),g=g;let j=(0,u.default)("eye-off",[["path",{d:"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49",key:"ct8e1f"}],["path",{d:"M14.084 14.158a3 3 0 0 1-4.242-4.242",key:"151rxh"}],["path",{d:"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143",key:"13bj9a"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]]),y=(0,u.default)("volume-2",[["path",{d:"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z",key:"uqj9uw"}],["path",{d:"M16 9a5 5 0 0 1 0 6",key:"1q6k2b"}],["path",{d:"M19.364 18.364a9 9 0 0 0 0-12.728",key:"ijwkga"}]]);var v=e.i(529757),b=e.i(666904),N=e.i(836191),S=e.i(77982),k=e.i(634066),C=e.i(865259),T=e.i(553880),w=e.i(87614),P=e.i(524741),z=e.i(739963),M=e.i(555552),E=e.i(300739),O=e.i(335130);function A(){let e=(0,r.useRouter)(),u=(0,r.usePathname)(),{state:A,toggleSidebar:_}=(0,v.useSidebar)(),{sessions:L,isLoading:$}=(0,E.useSessions)(),[I,D]=(0,s.useState)(!1),[R,B]=(0,s.useState)(!1),[F,U]=(0,s.useState)(!1),[K,q]=(0,s.useState)(null),[V,W]=(0,s.useState)(null),H=(0,s.useRef)(null),[X,G]=(0,s.useState)(""),[Q,J]=(0,s.useState)(""),[Z,Y]=(0,s.useState)({}),[ee,et]=(0,s.useState)([]),[es,er]=(0,s.useState)(null),[en,ea]=(0,s.useState)(""),[ei,el]=(0,s.useState)(!1),[eo,ec]=(0,s.useState)(!1),{enabled:ed,setEnabled:eu}=(0,O.useNotificationSound)(),em=u.startsWith("/embed/"),ep=u.startsWith("/session/")?u.split("/session/")[1]:u.startsWith("/embed/")?u.split("/embed/")[1]:null,eh=em?"/embed":"/session",ex=L.some(e=>e.isStreaming),ef=async()=>{let e=await (0,z.getConfig)();q(e),J(e.defaultModel),Y(e.defaultToolApprovals)},eg=async()=>{try{let e=await (0,P.getApiKeys)();et(e.providers)}catch(e){console.error("Failed to load API keys:",e)}};(0,s.useEffect)(()=>{ef(),eg()},[]),(0,s.useEffect)(()=>{F&&eg()},[F]);let ej=async e=>{if(en.trim()){ec(!0);try{await (0,P.setApiKey)(e,en),await eg(),er(null),ea(""),el(!1)}catch(e){console.error("Failed to save API key:",e)}finally{ec(!1)}}},ey=()=>{er(null),ea(""),el(!1)};(0,s.useEffect)(()=>{H.current&&(ex?H.current.play().catch(()=>{}):(H.current.pause(),H.current.currentTime=0))},[ex]);let ev=async()=>{if(!I){D(!0);try{let t=await (0,P.createSession)({name:`Session ${L.length+1}`,model:K?.defaultModel||"anthropic/claude-opus-4-6",toolApprovals:Z});(0,E.mutateSessions)(),e.push(`${eh}/${t.id}`)}catch(e){console.error("Failed to create session:",e)}finally{D(!1)}}},eb=async()=>{D(!0);try{let t=await (0,P.createSession)({name:X||`Session ${L.length+1}`,model:Q,toolApprovals:Z});(0,E.mutateSessions)(),eN(),B(!1),e.push(`${eh}/${t.id}`)}catch(e){console.error("Failed to create session:",e)}finally{D(!1)}},eN=()=>{G(""),K&&(J(K.defaultModel),Y(K.defaultToolApprovals))},eS=async(t,s)=>{t.preventDefault(),t.stopPropagation();try{await (0,P.deleteSession)(s),(0,E.mutateSessions)(),ep===s&&e.push("/")}catch(e){console.error("Failed to delete session:",e)}},ek=e=>{Y(t=>({...t,[e]:!t[e]}))},eC="collapsed"===A;return(0,t.jsxs)(v.Sidebar,{collapsible:em?"offcanvas":"icon",className:"border-r border-border/50",children:[(0,t.jsxs)(v.SidebarHeader,{className:(0,M.cn)(eC?"p-2 space-y-2":"p-3 space-y-3"),children:[!eC&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsxs)("div",{className:"relative shrink-0 overflow-hidden rounded-xl size-10 shadow-md ring-1 ring-white/10",children:[(0,t.jsx)(a.default,{src:"/sparke-coder.png",alt:"Sparke",width:40,height:40,className:"absolute inset-0 size-full object-cover",priority:!0}),(0,t.jsx)("video",{ref:H,src:"/sparkecode.mp4",muted:!0,loop:!0,playsInline:!0,className:(0,M.cn)("absolute inset-0 size-full object-cover transition-opacity duration-300",ex?"opacity-100":"opacity-0")})]}),(0,t.jsxs)("div",{className:"flex flex-1 items-center justify-between min-w-0",children:[(0,t.jsx)("h1",{className:"text-lg font-bold text-foreground",children:"SparkECoder"}),(0,t.jsx)(w.TooltipProvider,{children:(0,t.jsxs)(w.Tooltip,{children:[(0,t.jsx)(w.TooltipTrigger,{asChild:!0,children:(0,t.jsx)(b.Button,{size:"icon",variant:"ghost",className:"size-7 hover:bg-accent transition-colors",onClick:_,children:(0,t.jsx)(m,{className:"size-4"})})}),(0,t.jsxs)(w.TooltipContent,{side:"bottom",children:["Collapse ",(0,t.jsx)("kbd",{className:"ml-1 text-[10px] opacity-60",children:"⌘B"})]})]})})]})]}),(0,t.jsxs)(b.Button,{onClick:ev,disabled:I,className:"w-full justify-center gap-2 h-9",children:[I?(0,t.jsx)(c.Loader2,{className:"size-4 animate-spin"}):(0,t.jsx)(i.Plus,{className:"size-4"}),"New Agent"]})]}),eC&&(0,t.jsxs)("div",{className:"flex flex-col items-center gap-2 w-full",children:[(0,t.jsx)(w.TooltipProvider,{children:(0,t.jsxs)(w.Tooltip,{children:[(0,t.jsx)(w.TooltipTrigger,{asChild:!0,children:(0,t.jsx)(b.Button,{size:"icon",variant:"ghost",onClick:_,className:"size-8 mx-auto",children:(0,t.jsx)(p.PanelLeft,{className:"size-4"})})}),(0,t.jsxs)(w.TooltipContent,{side:"right",children:["Expand ",(0,t.jsx)("kbd",{className:"ml-1 text-[10px] opacity-60",children:"⌘B"})]})]})}),(0,t.jsxs)("div",{className:"relative overflow-hidden rounded-xl size-8 shadow-md ring-1 ring-white/10 mx-auto",children:[(0,t.jsx)(a.default,{src:"/sparke-coder.png",alt:"SparkECoder",width:32,height:32,className:"absolute inset-0 size-full object-cover",priority:!0}),(0,t.jsx)("video",{ref:H,src:"/sparkecode.mp4",muted:!0,loop:!0,playsInline:!0,className:(0,M.cn)("absolute inset-0 size-full object-cover transition-opacity duration-300",ex?"opacity-100":"opacity-0")})]}),(0,t.jsx)(w.TooltipProvider,{children:(0,t.jsxs)(w.Tooltip,{children:[(0,t.jsx)(w.TooltipTrigger,{asChild:!0,children:(0,t.jsx)(b.Button,{size:"icon",onClick:ev,disabled:I,className:"size-8 mx-auto",children:I?(0,t.jsx)(c.Loader2,{className:"size-4 animate-spin"}):(0,t.jsx)(i.Plus,{className:"size-4"})})}),(0,t.jsx)(w.TooltipContent,{side:"right",children:"New Agent"})]})})]})]}),(0,t.jsx)(N.Dialog,{open:R,onOpenChange:e=>{B(e),e&&eN()},children:(0,t.jsxs)(N.DialogContent,{className:"sm:max-w-md",children:[(0,t.jsx)(N.DialogHeader,{children:(0,t.jsxs)(N.DialogTitle,{className:"flex items-center gap-2",children:[(0,t.jsx)("div",{className:"size-8 rounded-lg bg-primary flex items-center justify-center",children:(0,t.jsx)(d.Settings,{className:"size-4 text-primary-foreground"})}),"New Agent"]})}),(0,t.jsxs)("div",{className:"space-y-4 pt-2",children:[(0,t.jsxs)("div",{className:"space-y-1.5",children:[(0,t.jsx)(k.Label,{htmlFor:"name",className:"text-sm font-medium",children:"Session Name"}),(0,t.jsx)(S.Input,{id:"name",placeholder:"My Coding Project (optional)",value:X,onChange:e=>G(e.target.value),className:"transition-all focus:ring-2 focus:ring-primary/20"})]}),(0,t.jsxs)("div",{className:"space-y-1.5",children:[(0,t.jsx)(k.Label,{className:"text-sm font-medium",children:"Model"}),(0,t.jsxs)(T.Select,{value:Q,onValueChange:J,children:[(0,t.jsx)(T.SelectTrigger,{className:"transition-all hover:border-primary/50",children:(0,t.jsx)(T.SelectValue,{placeholder:"Select a model"})}),(0,t.jsx)(T.SelectContent,{children:K?.availableModels.map(e=>(0,t.jsx)(T.SelectItem,{value:e.id,children:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{children:e.name}),(0,t.jsx)("span",{className:"text-xs text-muted-foreground",children:e.provider})]})},e.id))})]})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(k.Label,{className:"flex items-center gap-2 text-sm font-medium",children:"Tool Approvals"}),(0,t.jsx)("p",{className:"text-xs text-muted-foreground -mt-0.5",children:"Toggle on to require approval before tool executes"}),(0,t.jsx)("div",{className:"space-y-1 rounded-lg border p-2.5 bg-muted/30",children:K?.availableTools.map(e=>(0,t.jsxs)("div",{className:"flex items-center justify-between py-1.5 hover:bg-muted/50 rounded px-2 -mx-1 transition-colors",children:[(0,t.jsxs)("div",{className:"space-y-0",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium",children:e.name}),e.dangerous&&(0,t.jsx)("span",{className:"text-[10px] bg-amber-500/20 text-amber-600 dark:text-amber-400 px-1.5 py-0.5 rounded font-medium",children:"risky"})]}),(0,t.jsx)("p",{className:"text-[11px] text-muted-foreground",children:e.description})]}),(0,t.jsx)(C.Switch,{checked:Z[e.id]??!1,onCheckedChange:()=>ek(e.id)})]},e.id))})]}),(0,t.jsxs)(b.Button,{onClick:eb,disabled:I,className:"w-full",children:[I?(0,t.jsx)(c.Loader2,{className:"size-4 animate-spin mr-2"}):(0,t.jsx)(i.Plus,{className:"size-4 mr-2"}),"Create Session"]})]})]})}),(0,t.jsx)(v.SidebarContent,{className:"px-2",children:(0,t.jsx)(v.SidebarGroup,{className:"p-0",children:(0,t.jsx)(v.SidebarGroupContent,{children:(0,t.jsx)(v.SidebarMenu,{className:"gap-1",children:$?(0,t.jsx)("div",{className:"flex justify-center py-8",children:(0,t.jsx)(c.Loader2,{className:"size-5 animate-spin text-muted-foreground"})}):0===L.length?!eC&&(0,t.jsxs)("div",{className:"text-center py-8 px-4",children:[(0,t.jsxs)("div",{className:"relative overflow-hidden rounded-xl size-12 mx-auto mb-3 shadow-md ring-1 ring-white/10",children:[(0,t.jsx)(a.default,{src:"/sparke-coder.png",alt:"SparkECoder",width:48,height:48,className:"absolute inset-0 size-full object-cover"}),ex&&(0,t.jsx)("video",{src:"/sparkecode.mp4",autoPlay:!0,muted:!0,loop:!0,playsInline:!0,className:"absolute inset-0 size-full object-cover"})]}),(0,t.jsx)("p",{className:"text-sm text-foreground",children:"No sessions yet"}),(0,t.jsx)("p",{className:"text-xs text-muted-foreground mt-1",children:"Click New Agent above"})]}):L.map(e=>{let s,r,a,i,c=e.id===ep,d=V===e.id,u=!0===e.isStreaming,m=!eC&&(d||c);return(0,t.jsx)(v.SidebarMenuItem,{onMouseEnter:()=>W(e.id),onMouseLeave:()=>W(null),children:eC?(0,t.jsx)(w.TooltipProvider,{children:(0,t.jsxs)(w.Tooltip,{children:[(0,t.jsx)(w.TooltipTrigger,{asChild:!0,children:(0,t.jsx)(n.default,{href:`${eh}/${e.id}`,className:(0,M.cn)("flex items-center justify-center size-8 rounded-lg transition-colors mx-auto",c?"bg-accent":"hover:bg-accent/60",u&&!c&&"bg-emerald-500/10"),children:u?(0,t.jsx)("span",{className:"size-2 rounded-full bg-emerald-500 animate-pulse"}):(0,t.jsx)(l.MessageSquare,{className:(0,M.cn)("size-4",c?"text-primary":"text-muted-foreground")})})}),(0,t.jsxs)(w.TooltipContent,{side:"right",children:[e.name||"Untitled",u&&" (Running)"]})]})}):(0,t.jsx)(v.SidebarMenuButton,{asChild:!0,isActive:c,className:(0,M.cn)("h-9 transition-all duration-150","hover:bg-accent/60",c&&"bg-accent",u&&!c&&"bg-emerald-500/5"),children:(0,t.jsxs)(n.default,{href:`${eh}/${e.id}`,className:"flex items-center gap-2.5 px-2",children:[u?(0,t.jsx)("span",{className:"size-2 rounded-full bg-emerald-500 animate-pulse shrink-0"}):(0,t.jsx)(l.MessageSquare,{className:(0,M.cn)("size-4 shrink-0",c?"text-primary":"text-muted-foreground")}),(0,t.jsx)("span",{className:(0,M.cn)("truncate flex-1 text-sm",u&&"text-emerald-600 dark:text-emerald-400"),children:e.name||"Untitled"}),m?(0,t.jsx)(w.TooltipProvider,{children:(0,t.jsxs)(w.Tooltip,{children:[(0,t.jsx)(w.TooltipTrigger,{asChild:!0,children:(0,t.jsx)(b.Button,{size:"icon",variant:"ghost",className:"size-6 shrink-0 hover:bg-destructive/10 hover:text-destructive transition-colors",onClick:t=>eS(t,e.id),children:(0,t.jsx)(o.Trash2,{className:"size-3.5"})})}),(0,t.jsx)(w.TooltipContent,{side:"right",children:"Delete session"})]})}):u?(0,t.jsx)("span",{className:"inline-flex items-center gap-1 text-[10px] text-emerald-600 dark:text-emerald-400 shrink-0 font-medium",children:"Active"}):"waiting"===e.status?(0,t.jsx)("span",{className:"text-[10px] text-amber-600 dark:text-amber-400 shrink-0 font-medium",children:"Waiting"}):"error"===e.status?(0,t.jsx)("span",{className:"text-[10px] text-red-600 dark:text-red-400 shrink-0 font-medium",children:"Error"}):(0,t.jsx)("span",{className:"text-[11px] text-muted-foreground shrink-0 tabular-nums",children:(s=new Date(e.createdAt),i=Math.floor((a=Math.floor((r=Math.floor(Math.floor((new Date().getTime()-s.getTime())/1e3)/60))/60))/24),r<1?"now":r<60?`${r}m`:a<24?`${a}h`:i<7?`${i}d`:`${Math.floor(i/7)}w`)})]})})},e.id)})})})})}),(0,t.jsx)(v.SidebarFooter,{className:(0,M.cn)("border-t border-border/50",eC?"p-2":"p-3"),children:(0,t.jsx)("div",{className:"flex items-center justify-between",children:eC?(0,t.jsxs)("div",{className:"flex flex-col items-center gap-2 w-full",children:[(0,t.jsx)(w.TooltipProvider,{children:(0,t.jsxs)(w.Tooltip,{children:[(0,t.jsx)(w.TooltipTrigger,{asChild:!0,children:(0,t.jsx)("div",{className:"flex items-center justify-center",children:(0,t.jsx)("span",{className:(0,M.cn)("size-2 rounded-full",K?.serverConnected?"bg-emerald-500 animate-pulse":"bg-red-500")})})}),(0,t.jsx)(w.TooltipContent,{side:"right",children:K?.serverConnected?"Connected":"Disconnected"})]})}),(0,t.jsx)(N.Dialog,{open:F,onOpenChange:U,children:(0,t.jsx)(w.TooltipProvider,{children:(0,t.jsxs)(w.Tooltip,{children:[(0,t.jsx)(w.TooltipTrigger,{asChild:!0,children:(0,t.jsx)(N.DialogTrigger,{asChild:!0,children:(0,t.jsx)(b.Button,{size:"icon",variant:"ghost",className:"size-8",children:(0,t.jsx)(d.Settings,{className:"size-4"})})})}),(0,t.jsx)(w.TooltipContent,{side:"right",children:"Settings"})]})})})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"flex items-center gap-2 text-xs",children:[K?.serverConnected?(0,t.jsxs)("div",{className:"flex items-center gap-1.5 text-emerald-600 dark:text-emerald-400",children:[(0,t.jsx)("span",{className:"size-1.5 rounded-full bg-current animate-pulse"}),(0,t.jsx)("span",{children:"Connected"})]}):(0,t.jsxs)("div",{className:"flex items-center gap-1.5 text-red-500",children:[(0,t.jsx)("span",{className:"size-1.5 rounded-full bg-current"}),(0,t.jsx)("span",{children:"Disconnected"})]}),(0,t.jsx)("span",{className:"text-muted-foreground",children:"·"}),(0,t.jsx)("span",{className:"text-muted-foreground",children:L.length})]}),(0,t.jsxs)(N.Dialog,{open:F,onOpenChange:U,children:[(0,t.jsx)(w.TooltipProvider,{children:(0,t.jsxs)(w.Tooltip,{children:[(0,t.jsx)(w.TooltipTrigger,{asChild:!0,children:(0,t.jsx)(N.DialogTrigger,{asChild:!0,children:(0,t.jsx)(b.Button,{size:"icon",variant:"ghost",className:"size-7 hover:bg-accent transition-colors",children:(0,t.jsx)(d.Settings,{className:"size-4"})})})}),(0,t.jsx)(w.TooltipContent,{side:"top",children:"Settings"})]})}),(0,t.jsxs)(N.DialogContent,{className:"sm:max-w-md",children:[(0,t.jsx)(N.DialogHeader,{children:(0,t.jsxs)(N.DialogTitle,{className:"flex items-center gap-2",children:[(0,t.jsx)("div",{className:"size-8 rounded-lg bg-muted flex items-center justify-center",children:(0,t.jsx)(d.Settings,{className:"size-4"})}),"Settings"]})}),(0,t.jsxs)("div",{className:"space-y-4 pt-2",children:[(0,t.jsxs)("div",{className:"space-y-1.5",children:[(0,t.jsx)(k.Label,{className:"text-sm font-medium",children:"Default Model"}),(0,t.jsxs)(T.Select,{value:Q,onValueChange:J,children:[(0,t.jsx)(T.SelectTrigger,{className:"transition-all hover:border-primary/50",children:(0,t.jsx)(T.SelectValue,{placeholder:"Select a model"})}),(0,t.jsx)(T.SelectContent,{children:K?.availableModels.map(e=>(0,t.jsx)(T.SelectItem,{value:e.id,children:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{children:e.name}),(0,t.jsx)("span",{className:"text-xs text-muted-foreground",children:e.provider})]})},e.id))})]})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)(k.Label,{className:"flex items-center gap-2 text-sm font-medium",children:"Tool Approvals"}),(0,t.jsx)("p",{className:"text-xs text-muted-foreground -mt-0.5",children:"Toggle on to require approval before tool executes"}),(0,t.jsx)("div",{className:"space-y-1 rounded-lg border p-2.5 bg-muted/30",children:K?.availableTools.map(e=>(0,t.jsxs)("div",{className:"flex items-center justify-between py-1.5 hover:bg-muted/50 rounded px-2 -mx-1 transition-colors",children:[(0,t.jsxs)("div",{className:"space-y-0",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium",children:e.name}),e.dangerous&&(0,t.jsx)("span",{className:"text-[10px] bg-amber-500/20 text-amber-600 dark:text-amber-400 px-1.5 py-0.5 rounded font-medium",children:"risky"})]}),(0,t.jsx)("p",{className:"text-[11px] text-muted-foreground",children:e.description})]}),(0,t.jsx)(C.Switch,{checked:Z[e.id]??!1,onCheckedChange:()=>ek(e.id)})]},e.id))})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)(k.Label,{className:"flex items-center gap-2 text-sm font-medium",children:[(0,t.jsx)(h.Key,{className:"size-4"}),"API Keys"]}),(0,t.jsx)("p",{className:"text-xs text-muted-foreground -mt-0.5",children:"Configure API keys for different providers. Keys are stored securely on your machine."}),(0,t.jsx)("div",{className:"space-y-1 rounded-lg border p-2.5 bg-muted/30",children:ee.map(e=>(0,t.jsx)("div",{className:"py-1.5 hover:bg-muted/50 rounded px-2 -mx-1 transition-colors",children:es===e.provider?(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsx)("span",{className:"text-sm font-medium capitalize",children:e.provider}),(0,t.jsx)("span",{className:"text-[10px] text-muted-foreground font-mono",children:e.envVar})]}),(0,t.jsxs)("div",{className:"flex gap-2",children:[(0,t.jsxs)("div",{className:"relative flex-1",children:[(0,t.jsx)(S.Input,{type:ei?"text":"password",value:en,onChange:e=>ea(e.target.value),placeholder:"Paste your API key...",className:"pr-8 text-sm font-mono",autoFocus:!0}),(0,t.jsx)(b.Button,{type:"button",variant:"ghost",size:"icon",className:"absolute right-0 top-0 h-full px-2 hover:bg-transparent",onClick:()=>el(!ei),children:ei?(0,t.jsx)(j,{className:"size-4"}):(0,t.jsx)(g.default,{className:"size-4"})})]}),(0,t.jsx)(b.Button,{size:"icon",variant:"ghost",className:"shrink-0",onClick:()=>ej(e.provider),disabled:eo||!en.trim(),children:eo?(0,t.jsx)(c.Loader2,{className:"size-4 animate-spin"}):(0,t.jsx)(x.Check,{className:"size-4 text-green-500"})}),(0,t.jsx)(b.Button,{size:"icon",variant:"ghost",className:"shrink-0",onClick:ey,children:(0,t.jsx)(f.X,{className:"size-4 text-muted-foreground"})})]})]}):(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsxs)("div",{className:"space-y-0",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium capitalize",children:e.provider}),e.configured&&(0,t.jsx)("span",{className:(0,M.cn)("text-[10px] px-1.5 py-0.5 rounded font-medium","env"===e.source?"bg-blue-500/20 text-blue-600 dark:text-blue-400":"bg-green-500/20 text-green-600 dark:text-green-400"),children:"env"===e.source?"from env":"saved"})]}),(0,t.jsx)("p",{className:"text-[11px] text-muted-foreground font-mono",children:e.configured?e.maskedKey:"Not configured"})]}),(0,t.jsx)(b.Button,{size:"sm",variant:"ghost",className:"h-7 text-xs",onClick:()=>er(e.provider),children:e.configured?"Update":"Add"})]})},e.provider))})]}),(0,t.jsxs)("div",{className:"space-y-1.5",children:[(0,t.jsxs)(k.Label,{className:"flex items-center gap-2 text-sm font-medium",children:[(0,t.jsx)(y,{className:"size-4"}),"Notification Sound"]}),(0,t.jsxs)("div",{className:"flex items-center justify-between rounded-lg border p-2.5 bg-muted/30",children:[(0,t.jsxs)("div",{className:"space-y-0",children:[(0,t.jsx)("span",{className:"text-sm font-medium",children:"Play sound when done"}),(0,t.jsx)("p",{className:"text-[11px] text-muted-foreground",children:"Ding when the assistant finishes responding"})]}),(0,t.jsx)(C.Switch,{checked:ed,onCheckedChange:eu})]})]}),(0,t.jsx)("p",{className:"text-xs text-muted-foreground",children:"These settings apply to new sessions. You can also change the model per-session in the chat header."})]})]})]})]})})})]})}e.s(["SessionsSidebar",()=>A],421722)},138134,e=>{"use strict";var t=e.i(414294),s=e.i(529757),r=e.i(421722);function n({children:e}){return(0,t.jsxs)(s.SidebarProvider,{defaultOpen:!0,children:[(0,t.jsx)(r.SessionsSidebar,{}),(0,t.jsx)(s.SidebarInset,{className:"h-screen flex flex-col bg-background min-w-0",children:(0,t.jsx)("div",{className:"flex-1 overflow-hidden min-w-0",children:e})})]})}e.s(["default",()=>n])}]);