next-ai-editor 0.2.5 → 1.0.0

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 (97) hide show
  1. package/README.md +2 -2
  2. package/dist/index.cjs +2108 -33
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +187 -4
  5. package/dist/index.js +2108 -33
  6. package/dist/index.js.map +1 -1
  7. package/dist/next-ai-editor.css +489 -112
  8. package/package.json +4 -20
  9. package/dist/AIEditorProvider-CLgf1Vwa.cjs +0 -1488
  10. package/dist/AIEditorProvider-CLgf1Vwa.cjs.map +0 -1
  11. package/dist/AIEditorProvider-DWId5Qmv.js +0 -1489
  12. package/dist/AIEditorProvider-DWId5Qmv.js.map +0 -1
  13. package/dist/client/AIEditorProvider.d.ts +0 -21
  14. package/dist/client/AIEditorProvider.d.ts.map +0 -1
  15. package/dist/client/components/ChatPanel.d.ts +0 -18
  16. package/dist/client/components/ChatPanel.d.ts.map +0 -1
  17. package/dist/client/components/ControlPill.d.ts +0 -8
  18. package/dist/client/components/ControlPill.d.ts.map +0 -1
  19. package/dist/client/components/MessageItem.d.ts +0 -7
  20. package/dist/client/components/MessageItem.d.ts.map +0 -1
  21. package/dist/client/components/MessageList.d.ts +0 -7
  22. package/dist/client/components/MessageList.d.ts.map +0 -1
  23. package/dist/client/components/TaskHistoryPanel.d.ts +0 -10
  24. package/dist/client/components/TaskHistoryPanel.d.ts.map +0 -1
  25. package/dist/client/components/index.d.ts +0 -11
  26. package/dist/client/components/index.d.ts.map +0 -1
  27. package/dist/client/fiber-utils.d.ts +0 -35
  28. package/dist/client/fiber-utils.d.ts.map +0 -1
  29. package/dist/client/hooks/index.d.ts +0 -3
  30. package/dist/client/hooks/index.d.ts.map +0 -1
  31. package/dist/client/hooks/useChatStream.d.ts +0 -66
  32. package/dist/client/hooks/useChatStream.d.ts.map +0 -1
  33. package/dist/client/hooks/useHotReload.d.ts +0 -10
  34. package/dist/client/hooks/useHotReload.d.ts.map +0 -1
  35. package/dist/client/index.cjs +0 -1
  36. package/dist/client/index.d.ts +0 -6
  37. package/dist/client/index.d.ts.map +0 -1
  38. package/dist/client/index.js +0 -1
  39. package/dist/client/query-params.d.ts +0 -9
  40. package/dist/client/query-params.d.ts.map +0 -1
  41. package/dist/client.cjs +0 -12
  42. package/dist/client.cjs.map +0 -1
  43. package/dist/client.js +0 -12
  44. package/dist/client.js.map +0 -1
  45. package/dist/comments-2HX-AAwu.cjs +0 -1512
  46. package/dist/comments-2HX-AAwu.cjs.map +0 -1
  47. package/dist/comments-BYFEhf6K.js +0 -1495
  48. package/dist/comments-BYFEhf6K.js.map +0 -1
  49. package/dist/index.d.ts.map +0 -1
  50. package/dist/path-utils-Bai2xKx9.js +0 -36
  51. package/dist/path-utils-Bai2xKx9.js.map +0 -1
  52. package/dist/path-utils-DYzEWUGy.cjs +0 -35
  53. package/dist/path-utils-DYzEWUGy.cjs.map +0 -1
  54. package/dist/server/agent/sdk-client.d.ts +0 -54
  55. package/dist/server/agent/sdk-client.d.ts.map +0 -1
  56. package/dist/server/agent/session-store.d.ts +0 -101
  57. package/dist/server/agent/session-store.d.ts.map +0 -1
  58. package/dist/server/handlers/absolute-path.d.ts +0 -3
  59. package/dist/server/handlers/absolute-path.d.ts.map +0 -1
  60. package/dist/server/handlers/chat.d.ts +0 -6
  61. package/dist/server/handlers/chat.d.ts.map +0 -1
  62. package/dist/server/handlers/comments.d.ts +0 -10
  63. package/dist/server/handlers/comments.d.ts.map +0 -1
  64. package/dist/server/handlers/config.d.ts +0 -7
  65. package/dist/server/handlers/config.d.ts.map +0 -1
  66. package/dist/server/handlers/index.d.ts +0 -18
  67. package/dist/server/handlers/index.d.ts.map +0 -1
  68. package/dist/server/handlers/read.d.ts +0 -3
  69. package/dist/server/handlers/read.d.ts.map +0 -1
  70. package/dist/server/handlers/resolve.d.ts +0 -3
  71. package/dist/server/handlers/resolve.d.ts.map +0 -1
  72. package/dist/server/handlers/undo.d.ts +0 -3
  73. package/dist/server/handlers/undo.d.ts.map +0 -1
  74. package/dist/server/handlers/validate-session.d.ts +0 -3
  75. package/dist/server/handlers/validate-session.d.ts.map +0 -1
  76. package/dist/server/index.cjs +0 -1
  77. package/dist/server/index.d.ts +0 -11
  78. package/dist/server/index.d.ts.map +0 -1
  79. package/dist/server/index.js +0 -1
  80. package/dist/server/utils/ast.d.ts +0 -49
  81. package/dist/server/utils/ast.d.ts.map +0 -1
  82. package/dist/server/utils/file-system.d.ts +0 -24
  83. package/dist/server/utils/file-system.d.ts.map +0 -1
  84. package/dist/server/utils/source-map.d.ts +0 -39
  85. package/dist/server/utils/source-map.d.ts.map +0 -1
  86. package/dist/server.cjs +0 -28
  87. package/dist/server.cjs.map +0 -1
  88. package/dist/server.js +0 -28
  89. package/dist/server.js.map +0 -1
  90. package/dist/shared/comment-types.d.ts +0 -140
  91. package/dist/shared/comment-types.d.ts.map +0 -1
  92. package/dist/shared/path-utils.d.ts +0 -24
  93. package/dist/shared/path-utils.d.ts.map +0 -1
  94. package/dist/shared/storage.d.ts +0 -53
  95. package/dist/shared/storage.d.ts.map +0 -1
  96. package/dist/shared/types.d.ts +0 -74
  97. package/dist/shared/types.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -1,36 +1,2111 @@
1
- import { A, C, a } from "./AIEditorProvider-DWId5Qmv.js";
2
- import "react/jsx-runtime";
3
- import "react";
4
- import "react-markdown";
5
- import "remark-gfm";
6
- import { j, t, g, l, o, m, x, h, d, f, a as a2, c, b, e, i, n, q, u, p, r, w, s, v, k } from "./comments-BYFEhf6K.js";
1
+ "use client";
2
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
3
+ import { useState, useEffect, useRef, useMemo, useCallback, forwardRef, createElement, createContext } from "react";
4
+ import ReactMarkdown from "react-markdown";
5
+ import remarkGfm from "remark-gfm";
6
+ import { flushSync } from "react-dom";
7
+ function cleanPath(filePath) {
8
+ if (!filePath) return "";
9
+ let cleaned = filePath;
10
+ cleaned = cleaned.replace(/^about:\/\/React\/Server\//, "");
11
+ if (cleaned.startsWith("file://")) {
12
+ cleaned = cleaned.replace(/^file:\/\//, "");
13
+ }
14
+ try {
15
+ if (cleaned.includes("%")) {
16
+ cleaned = decodeURIComponent(cleaned);
17
+ }
18
+ } catch (e) {
19
+ }
20
+ cleaned = cleaned.replace(/^webpack-internal:\/\/\/\([^)]+\)\/\.\//, "").replace(/^webpack-internal:\/\/\/\([^)]+\)\//, "").replace(/^webpack-internal:\/\//, "").replace(/^webpack:\/\/[^/]*\//, "").replace(/^\([^)]+\)\//, "").replace(/^\.\//, "").replace(/\?.*$/, "");
21
+ return cleaned;
22
+ }
23
+ function shouldSkipPath(filePath, additionalSkipPatterns = []) {
24
+ if (!filePath) return true;
25
+ const defaultSkipPatterns = ["node_modules", "next/dist", "react-dom"];
26
+ const allPatterns = [...defaultSkipPatterns, ...additionalSkipPatterns];
27
+ return allPatterns.some((pattern) => filePath.includes(pattern));
28
+ }
29
+ function getFiberFromElement(element) {
30
+ const key = Object.keys(element).find(
31
+ (k) => k.startsWith("__reactFiber$") || k.startsWith("__reactInternalInstance$")
32
+ );
33
+ return key ? element[key] : null;
34
+ }
35
+ function getComponentName(fiber) {
36
+ var _a, _b;
37
+ if (!fiber) return "Unknown";
38
+ const type = fiber.type;
39
+ if ((_a = fiber._debugSource) == null ? void 0 : _a.fileName) {
40
+ const fileName = fiber._debugSource.fileName;
41
+ const match = fileName.match(/\/([^/]+)\.(tsx?|jsx?)$/);
42
+ if (match) return match[1];
43
+ }
44
+ if (typeof type === "string") return type;
45
+ if (typeof type === "function")
46
+ return type.displayName || type.name || "Anonymous";
47
+ if (type == null ? void 0 : type.displayName) return type.displayName;
48
+ if ((_b = type == null ? void 0 : type.render) == null ? void 0 : _b.name) return type.render.name;
49
+ if (fiber._debugStack) {
50
+ const stack = String(fiber._debugStack.stack || fiber._debugStack);
51
+ const match = stack.match(/at\s+([A-Z][a-zA-Z0-9]*)\s*\(/);
52
+ if (match && match[1] !== "Object") {
53
+ return match[1];
54
+ }
55
+ }
56
+ return "Unknown";
57
+ }
58
+ function isUserComponent(fiber) {
59
+ if (fiber.tag === 5 || fiber.tag === 6 || fiber.tag === 3) return false;
60
+ const type = fiber.type;
61
+ if (!type || typeof type === "string") return false;
62
+ return true;
63
+ }
64
+ function countNthOfType(element, tagName) {
65
+ let boundary = element.parentElement;
66
+ while (boundary) {
67
+ const fiber = getFiberFromElement(boundary);
68
+ if (fiber && isUserComponent(fiber)) break;
69
+ boundary = boundary.parentElement;
70
+ }
71
+ if (!boundary) boundary = element.parentElement;
72
+ if (!boundary) return 1;
73
+ const sameTagElements = [];
74
+ if (boundary.tagName.toLowerCase() === tagName.toLowerCase()) {
75
+ sameTagElements.push(boundary);
76
+ }
77
+ sameTagElements.push(...Array.from(boundary.querySelectorAll(tagName)));
78
+ let count = 1;
79
+ for (const el of sameTagElements) {
80
+ if (el === element) break;
81
+ count++;
82
+ }
83
+ return count;
84
+ }
85
+ function extractProps(fiber) {
86
+ if (!fiber) return void 0;
87
+ const fiberProps = fiber.memoizedProps || fiber.pendingProps;
88
+ if (!fiberProps || typeof fiberProps !== "object") return void 0;
89
+ const props = {};
90
+ const identifyingKeys = [
91
+ "id",
92
+ "name",
93
+ "type",
94
+ "href",
95
+ "src",
96
+ "alt",
97
+ "role",
98
+ "aria-label",
99
+ "data-testid"
100
+ ];
101
+ for (const key of identifyingKeys) {
102
+ if (key in fiberProps && typeof fiberProps[key] === "string") {
103
+ props[key] = fiberProps[key];
104
+ }
105
+ }
106
+ if (fiberProps.style && typeof fiberProps.style === "object") {
107
+ props._styleKeys = Object.keys(fiberProps.style).slice(0, 5);
108
+ }
109
+ return Object.keys(props).length > 0 ? props : void 0;
110
+ }
111
+ function captureElementContext(element, fiber) {
112
+ const tagName = element.tagName.toLowerCase();
113
+ let textContent;
114
+ const directText = Array.from(element.childNodes).filter((n) => n.nodeType === Node.TEXT_NODE).map((n) => {
115
+ var _a;
116
+ return (_a = n.textContent) == null ? void 0 : _a.trim();
117
+ }).filter(Boolean).join(" ");
118
+ if (directText) {
119
+ textContent = directText.slice(0, 50);
120
+ } else if (element.textContent) {
121
+ textContent = element.textContent.trim().slice(0, 50);
122
+ }
123
+ const className = typeof element.className === "string" ? element.className.slice(0, 100) : void 0;
124
+ const nthOfType = countNthOfType(element, tagName);
125
+ const key = (fiber == null ? void 0 : fiber.key) ? String(fiber.key) : void 0;
126
+ const props = extractProps(fiber);
127
+ return { tagName, textContent, className, key, nthOfType, props };
128
+ }
129
+ function extractFromDebugStack(fiber) {
130
+ const stack = fiber._debugStack;
131
+ if (!stack) return null;
132
+ const stackStr = stack.stack || String(stack);
133
+ const frames = stackStr.split("\n");
134
+ const skipPatterns = [
135
+ "node_modules",
136
+ "SegmentViewNode",
137
+ "LayoutRouter",
138
+ "ErrorBoundary",
139
+ "fakeJSXCallSite"
140
+ ];
141
+ for (const frame of frames) {
142
+ if (skipPatterns.some((p) => frame.includes(p))) continue;
143
+ const match = frame.match(/at\s+(\w+)\s+\((.+?):(\d+):(\d+)\)?$/);
144
+ if (match) {
145
+ const fileName = cleanPath(match[2].replace(/\?[^:]*$/, ""));
146
+ if (!shouldSkipPath(fileName, ["ai-editor-provider"])) {
147
+ return {
148
+ fileName,
149
+ lineNumber: parseInt(match[3], 10),
150
+ columnNumber: parseInt(match[4], 10)
151
+ };
152
+ }
153
+ }
154
+ }
155
+ return null;
156
+ }
157
+ function extractFromDebugOwner(fiber) {
158
+ var _a, _b;
159
+ const owner = fiber._debugOwner;
160
+ if (!owner) return null;
161
+ if ((_a = owner._debugSource) == null ? void 0 : _a.fileName) {
162
+ return owner._debugSource;
163
+ }
164
+ const stack = owner.stack;
165
+ if (Array.isArray(stack) && ((_b = stack[0]) == null ? void 0 : _b.fileName)) {
166
+ return stack[0];
167
+ }
168
+ return null;
169
+ }
170
+ function findSourceFromFiber(fiber) {
171
+ if (!fiber) return null;
172
+ let actualComponentName = null;
173
+ if (fiber._debugOwner && typeof fiber._debugOwner === "object") {
174
+ const debugOwner = fiber._debugOwner;
175
+ if (debugOwner.name && typeof debugOwner.name === "string") {
176
+ actualComponentName = debugOwner.name;
177
+ }
178
+ }
179
+ let current = fiber;
180
+ const visited = /* @__PURE__ */ new Set();
181
+ let iterations = 0;
182
+ while (current && !visited.has(current) && iterations < 10) {
183
+ iterations++;
184
+ visited.add(current);
185
+ const sourceData = current._debugSource || extractFromDebugStack(current) || extractFromDebugOwner(current);
186
+ if (sourceData == null ? void 0 : sourceData.fileName) {
187
+ const filePath = cleanPath(sourceData.fileName);
188
+ if (!shouldSkipPath(filePath, ["ai-editor-provider"])) {
189
+ if (actualComponentName) {
190
+ const rawDebugStack = current._debugStack ? String(current._debugStack.stack || current._debugStack) : void 0;
191
+ return {
192
+ filePath,
193
+ lineNumber: sourceData.lineNumber || 1,
194
+ columnNumber: sourceData.columnNumber || 0,
195
+ componentName: actualComponentName,
196
+ debugStack: rawDebugStack
197
+ };
198
+ } else {
199
+ let componentFiber = current;
200
+ while (componentFiber) {
201
+ if (isUserComponent(componentFiber)) {
202
+ const componentName = getComponentName(componentFiber);
203
+ const isNextJSInternal = [
204
+ "Segment",
205
+ "Boundary",
206
+ "Router",
207
+ "Handler",
208
+ "Context",
209
+ "Layout",
210
+ "Template",
211
+ "Scroll",
212
+ "Focus",
213
+ "Loading",
214
+ "Error"
215
+ ].some((pattern) => componentName.includes(pattern));
216
+ if (!isNextJSInternal) {
217
+ const rawDebugStack = current._debugStack ? String(current._debugStack.stack || current._debugStack) : void 0;
218
+ return {
219
+ filePath,
220
+ lineNumber: sourceData.lineNumber || 1,
221
+ columnNumber: sourceData.columnNumber || 0,
222
+ componentName,
223
+ debugStack: rawDebugStack
224
+ };
225
+ }
226
+ }
227
+ componentFiber = componentFiber.return || componentFiber._debugOwner || null;
228
+ }
229
+ }
230
+ }
231
+ }
232
+ current = current.return || current._debugOwner || null;
233
+ }
234
+ return null;
235
+ }
236
+ function findParentComponentFromFiber(childFiber, childComponentName) {
237
+ if (!childFiber) return null;
238
+ let childComponentFiber = null;
239
+ if (childFiber._debugOwner && typeof childFiber._debugOwner === "object") {
240
+ const debugOwner = childFiber._debugOwner;
241
+ if (debugOwner.type && typeof debugOwner.type === "function") {
242
+ const ownerComponentName = getComponentName(debugOwner);
243
+ if (ownerComponentName === childComponentName) {
244
+ childComponentFiber = debugOwner;
245
+ }
246
+ }
247
+ }
248
+ if (!childComponentFiber) {
249
+ let current2 = childFiber;
250
+ let iterations2 = 0;
251
+ while (current2 && iterations2 < 20) {
252
+ iterations2++;
253
+ const componentName = getComponentName(current2);
254
+ current2.index;
255
+ if (isUserComponent(current2)) {
256
+ if (componentName === childComponentName) {
257
+ childComponentFiber = current2;
258
+ break;
259
+ }
260
+ }
261
+ if (current2._debugOwner && typeof current2._debugOwner === "object") {
262
+ const debugOwner = current2._debugOwner;
263
+ if (debugOwner.name === childComponentName && !debugOwner.type) {
264
+ const parent = current2.return;
265
+ const parentDebugOwner = parent == null ? void 0 : parent._debugOwner;
266
+ const isRootElement = !parentDebugOwner || parentDebugOwner.name !== childComponentName;
267
+ if (isRootElement) {
268
+ childComponentFiber = current2;
269
+ break;
270
+ }
271
+ }
272
+ }
273
+ current2 = current2.return;
274
+ }
275
+ }
276
+ let childKey;
277
+ if (childComponentFiber == null ? void 0 : childComponentFiber.key) {
278
+ childKey = String(childComponentFiber.key);
279
+ } else if (childComponentFiber && typeof childComponentFiber.index === "number") {
280
+ childKey = String(childComponentFiber.index);
281
+ }
282
+ if (childFiber._debugOwner && typeof childFiber._debugOwner === "object") {
283
+ const debugOwner = childFiber._debugOwner;
284
+ if (debugOwner.owner && debugOwner.owner.name) {
285
+ const parentName = debugOwner.owner.name;
286
+ const parentDebugLocation = debugOwner.owner.debugLocation;
287
+ if (parentDebugLocation) {
288
+ const stack = String(parentDebugLocation.stack || parentDebugLocation);
289
+ return {
290
+ filePath: "",
291
+ // Will be resolved on server
292
+ lineNumber: 0,
293
+ columnNumber: 0,
294
+ componentName: parentName,
295
+ debugStack: stack,
296
+ childKey
297
+ };
298
+ }
299
+ }
300
+ if (debugOwner.type && typeof debugOwner.type === "function") {
301
+ const componentFiberOwner = debugOwner._debugOwner;
302
+ if (componentFiberOwner && typeof componentFiberOwner === "object") {
303
+ const parentName = componentFiberOwner.name;
304
+ const parentDebugLocation = componentFiberOwner.debugLocation;
305
+ if (parentName && typeof parentName === "string") {
306
+ if (parentDebugLocation) {
307
+ const stack = String(
308
+ parentDebugLocation.stack || parentDebugLocation
309
+ );
310
+ return {
311
+ filePath: "",
312
+ // Will be resolved on server
313
+ lineNumber: 0,
314
+ columnNumber: 0,
315
+ componentName: parentName,
316
+ debugStack: stack,
317
+ childKey
318
+ };
319
+ }
320
+ }
321
+ }
322
+ }
323
+ }
324
+ let current = childFiber.return;
325
+ const visited = /* @__PURE__ */ new Set();
326
+ let iterations = 0;
327
+ while (current && !visited.has(current) && iterations < 20) {
328
+ iterations++;
329
+ visited.add(current);
330
+ if (isUserComponent(current)) {
331
+ const componentName = getComponentName(current);
332
+ if (componentName === childComponentName) {
333
+ current = current._debugOwner || null;
334
+ continue;
335
+ }
336
+ const shouldSkipComponent = componentName.includes("AIEditorProvider") || // Skip the AI Editor wrapper itself
337
+ componentName.startsWith("__next") || // Skip all Next.js internal components like __next_root_layout_boundary__
338
+ componentName.startsWith("_") || // Skip internal components starting with underscore
339
+ [
340
+ "Segment",
341
+ "Boundary",
342
+ "Router",
343
+ "Handler",
344
+ "Context",
345
+ "Layout",
346
+ "Template",
347
+ "Scroll",
348
+ "Focus",
349
+ "Loading",
350
+ "Error",
351
+ "RootLayout",
352
+ // Skip root layout wrapper
353
+ "NotFound"
354
+ ].some((pattern) => componentName.includes(pattern));
355
+ if (shouldSkipComponent) {
356
+ current = current._debugOwner || null;
357
+ continue;
358
+ }
359
+ const sourceData = current._debugSource || extractFromDebugStack(current) || extractFromDebugOwner(current);
360
+ if (sourceData == null ? void 0 : sourceData.fileName) {
361
+ const filePath = cleanPath(sourceData.fileName);
362
+ if (!shouldSkipPath(filePath, ["ai-editor-provider"])) {
363
+ const rawDebugStack = current._debugStack ? String(current._debugStack.stack || current._debugStack) : void 0;
364
+ return {
365
+ filePath,
366
+ lineNumber: sourceData.lineNumber || 1,
367
+ columnNumber: sourceData.columnNumber || 0,
368
+ componentName,
369
+ debugStack: rawDebugStack,
370
+ childKey
371
+ };
372
+ }
373
+ }
374
+ }
375
+ const nextOwner = current._debugOwner;
376
+ current = nextOwner || null;
377
+ }
378
+ const childDebugStack = childFiber._debugStack ? String(childFiber._debugStack.stack || childFiber._debugStack) : null;
379
+ if (childDebugStack) {
380
+ return {
381
+ filePath: "",
382
+ // Will be resolved on server from debugStack
383
+ lineNumber: 0,
384
+ columnNumber: 0,
385
+ componentName: "",
386
+ // Will be determined on server
387
+ debugStack: childDebugStack,
388
+ // Use child's debugStack for server-side resolution
389
+ childKey
390
+ };
391
+ }
392
+ return null;
393
+ }
394
+ function getSourceFromElement(element) {
395
+ var _a;
396
+ let current = element;
397
+ let elementWithSource = null;
398
+ let fiberWithSource = null;
399
+ while (current && current !== document.body) {
400
+ const fiber = getFiberFromElement(current);
401
+ if (fiber) {
402
+ const hasSourceInfo = ((_a = fiber._debugSource) == null ? void 0 : _a.fileName) || fiber._debugStack || fiber._debugOwner && typeof fiber._debugOwner === "object";
403
+ if (hasSourceInfo && !fiberWithSource) {
404
+ elementWithSource = current;
405
+ fiberWithSource = fiber;
406
+ }
407
+ }
408
+ current = current.parentElement;
409
+ }
410
+ if (!fiberWithSource || !elementWithSource) return null;
411
+ const source = findSourceFromFiber(fiberWithSource);
412
+ if (!source) return null;
413
+ const elementContext = captureElementContext(elementWithSource, fiberWithSource);
414
+ const parentComponent = findParentComponentFromFiber(
415
+ fiberWithSource,
416
+ source.componentName
417
+ );
418
+ return {
419
+ ...source,
420
+ elementContext,
421
+ parentComponent: parentComponent || void 0
422
+ };
423
+ }
424
+ if (typeof window !== "undefined") {
425
+ window.__getSource = getSourceFromElement;
426
+ }
427
+ function TaskHistoryPanel({
428
+ isOpen,
429
+ onClose,
430
+ tasks,
431
+ onTaskClick
432
+ }) {
433
+ if (!isOpen) {
434
+ return null;
435
+ }
436
+ return /* @__PURE__ */ jsxs("div", { className: "task-history-panel ai-editor-ui", children: [
437
+ /* @__PURE__ */ jsx("div", { className: "task-history-overlay", onClick: onClose }),
438
+ /* @__PURE__ */ jsxs("div", { className: "task-history-content", children: [
439
+ /* @__PURE__ */ jsxs("div", { className: "task-history-header", children: [
440
+ /* @__PURE__ */ jsxs("div", { className: "header-title", children: [
441
+ /* @__PURE__ */ jsx("span", { className: "header-icon", children: "📝" }),
442
+ /* @__PURE__ */ jsx("h2", { children: "Task History" })
443
+ ] }),
444
+ /* @__PURE__ */ jsx(
445
+ "button",
446
+ {
447
+ className: "close-btn",
448
+ onClick: onClose,
449
+ "aria-label": "Close",
450
+ title: "Close (Esc)",
451
+ children: "✕"
452
+ }
453
+ )
454
+ ] }),
455
+ /* @__PURE__ */ jsx("div", { className: "task-history-body", children: tasks.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "empty-state", children: [
456
+ /* @__PURE__ */ jsx("div", { className: "empty-icon", children: "🎯" }),
457
+ /* @__PURE__ */ jsx("h3", { children: "No tasks yet" }),
458
+ /* @__PURE__ */ jsx("p", { children: "Create a comment and send a message to see AI actions here." })
459
+ ] }) : /* @__PURE__ */ jsx("div", { className: "task-list", children: tasks.map((task) => /* @__PURE__ */ jsx(
460
+ TaskItem,
461
+ {
462
+ task,
463
+ onClick: () => onTaskClick == null ? void 0 : onTaskClick(task.id)
464
+ },
465
+ task.id
466
+ )) }) })
467
+ ] })
468
+ ] });
469
+ }
470
+ function TaskItem({ task, onClick }) {
471
+ const getStatusIcon = () => {
472
+ switch (task.status) {
473
+ case "pending":
474
+ return "⏳";
475
+ case "done":
476
+ return "✅";
477
+ case "failed":
478
+ return "❌";
479
+ default:
480
+ return "⏳";
481
+ }
482
+ };
483
+ const getStatusLabel = () => {
484
+ switch (task.status) {
485
+ case "pending":
486
+ return "In Progress";
487
+ case "done":
488
+ return "Complete";
489
+ case "failed":
490
+ return "Failed";
491
+ default:
492
+ return "Unknown";
493
+ }
494
+ };
495
+ const formatTime = (timestamp) => {
496
+ const date = new Date(timestamp);
497
+ const now = /* @__PURE__ */ new Date();
498
+ const diffMs = now.getTime() - date.getTime();
499
+ const diffMins = Math.floor(diffMs / 6e4);
500
+ if (diffMins < 1) return "Just now";
501
+ if (diffMins < 60) return `${diffMins}m ago`;
502
+ const diffHours = Math.floor(diffMins / 60);
503
+ if (diffHours < 24) return `${diffHours}h ago`;
504
+ const diffDays = Math.floor(diffHours / 24);
505
+ return `${diffDays}d ago`;
506
+ };
507
+ return /* @__PURE__ */ jsxs(
508
+ "div",
509
+ {
510
+ className: `task-item status-${task.status}`,
511
+ onClick,
512
+ children: [
513
+ /* @__PURE__ */ jsxs("div", { className: "task-header", children: [
514
+ /* @__PURE__ */ jsxs("div", { className: "task-status", children: [
515
+ /* @__PURE__ */ jsx("span", { className: "status-icon", children: getStatusIcon() }),
516
+ /* @__PURE__ */ jsx("span", { className: "status-label", children: getStatusLabel() })
517
+ ] }),
518
+ /* @__PURE__ */ jsx("div", { className: "task-time", children: formatTime(task.createdAt) })
519
+ ] }),
520
+ /* @__PURE__ */ jsx("div", { className: "task-request", children: task.userRequest }),
521
+ task.actions.length > 0 && /* @__PURE__ */ jsx("div", { className: "task-actions", children: task.actions.map((action, idx) => /* @__PURE__ */ jsxs("div", { className: "action-item", children: [
522
+ action.type === "tool_use" && /* @__PURE__ */ jsxs("span", { className: "action-text", children: [
523
+ "🔧 ",
524
+ action.tool
525
+ ] }),
526
+ action.type === "result" && /* @__PURE__ */ jsxs("span", { className: "action-text", children: [
527
+ "✓ ",
528
+ action.result
529
+ ] }),
530
+ action.type === "error" && /* @__PURE__ */ jsxs("span", { className: "action-text error", children: [
531
+ "⚠️ ",
532
+ action.error
533
+ ] })
534
+ ] }, idx)) }),
535
+ task.affectedFiles.length > 0 && /* @__PURE__ */ jsxs("div", { className: "task-files", children: [
536
+ /* @__PURE__ */ jsx("span", { className: "files-label", children: "Files:" }),
537
+ task.affectedFiles.map((file, idx) => /* @__PURE__ */ jsx("span", { className: "file-badge", children: file.split("/").pop() }, idx))
538
+ ] })
539
+ ]
540
+ }
541
+ );
542
+ }
543
+ function MessageItem({ message }) {
544
+ var _a, _b, _c;
545
+ if ("role" in message) {
546
+ const commentMsg = message;
547
+ if (commentMsg.role === "user") {
548
+ return /* @__PURE__ */ jsx("div", { className: "message message-user", children: /* @__PURE__ */ jsx("div", { className: "message-content", children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: commentMsg.content }) }) });
549
+ }
550
+ if (commentMsg.role === "assistant") {
551
+ return /* @__PURE__ */ jsx("div", { className: "message message-assistant", children: /* @__PURE__ */ jsx("div", { className: "message-content", children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: commentMsg.content }) }) });
552
+ }
553
+ }
554
+ const chatMsg = message;
555
+ if (chatMsg.type === "connected" || chatMsg.type === "system") {
556
+ return null;
557
+ }
558
+ if (chatMsg.type === "user") {
559
+ return /* @__PURE__ */ jsx("div", { className: "message message-user", children: /* @__PURE__ */ jsx("div", { className: "message-content", children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: chatMsg.message }) }) });
560
+ }
561
+ if (chatMsg.type === "assistant") {
562
+ const content = typeof chatMsg.message === "string" ? chatMsg.message : ((_c = (_b = (_a = chatMsg.message) == null ? void 0 : _a.content) == null ? void 0 : _b[0]) == null ? void 0 : _c.text) || "";
563
+ if (!content.trim()) return null;
564
+ return /* @__PURE__ */ jsx("div", { className: "message message-assistant", children: /* @__PURE__ */ jsx("div", { className: "message-content", children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: content }) }) });
565
+ }
566
+ if (chatMsg.type === "error") {
567
+ return /* @__PURE__ */ jsx("div", { className: "message message-error", children: /* @__PURE__ */ jsxs("div", { className: "message-content", children: [
568
+ /* @__PURE__ */ jsx("strong", { children: "Error:" }),
569
+ " ",
570
+ chatMsg.error
571
+ ] }) });
572
+ }
573
+ return null;
574
+ }
575
+ function groupStepsIntoPhases(steps) {
576
+ const phases = [];
577
+ let currentPhase = null;
578
+ for (const step of steps) {
579
+ if (step.type === "status" || step.type === "completion") {
580
+ if (currentPhase) {
581
+ phases.push(currentPhase);
582
+ }
583
+ currentPhase = {
584
+ statusStep: step,
585
+ toolSteps: []
586
+ };
587
+ } else if (step.type === "tool") {
588
+ if (!currentPhase) {
589
+ currentPhase = {
590
+ toolSteps: []
591
+ };
592
+ }
593
+ currentPhase.toolSteps.push(step);
594
+ }
595
+ }
596
+ if (currentPhase) {
597
+ phases.push(currentPhase);
598
+ }
599
+ return phases;
600
+ }
601
+ function PhaseItem({
602
+ phase,
603
+ isStreaming
604
+ }) {
605
+ var _a, _b;
606
+ const hasTools = phase.toolSteps.length > 0;
607
+ const allToolsComplete = phase.toolSteps.length === 0 || phase.toolSteps.every((t) => t.isComplete);
608
+ const phaseIsComplete = allToolsComplete && (!phase.statusStep || phase.statusStep.isComplete);
609
+ const isActive = !phaseIsComplete && isStreaming && (((_a = phase.statusStep) == null ? void 0 : _a.isLast) || hasTools);
610
+ const hasIncompleteTools = phase.toolSteps.some((step) => !step.isComplete);
611
+ const shouldAutoExpand = isActive || hasIncompleteTools && isStreaming;
612
+ const [isToolsExpanded, setIsToolsExpanded] = useState(false);
613
+ const [wasManuallyExpanded, setWasManuallyExpanded] = useState(false);
614
+ const [secondsElapsed, setSecondsElapsed] = useState(0);
615
+ useEffect(() => {
616
+ if (shouldAutoExpand) {
617
+ setIsToolsExpanded(true);
618
+ } else if (!wasManuallyExpanded) {
619
+ setIsToolsExpanded(false);
620
+ }
621
+ }, [shouldAutoExpand, wasManuallyExpanded]);
622
+ useEffect(() => {
623
+ var _a2;
624
+ if (!isActive) {
625
+ setSecondsElapsed(0);
626
+ return;
627
+ }
628
+ console.log("[PhaseItem] Starting timer for phase:", (_a2 = phase.statusStep) == null ? void 0 : _a2.text);
629
+ const startTime = Date.now();
630
+ const interval = setInterval(() => {
631
+ var _a3;
632
+ const elapsed = Math.floor((Date.now() - startTime) / 1e3);
633
+ setSecondsElapsed(elapsed);
634
+ if (elapsed % 5 === 0) {
635
+ console.log("[PhaseItem] Timer update:", (_a3 = phase.statusStep) == null ? void 0 : _a3.text, elapsed + "s");
636
+ }
637
+ }, 1e3);
638
+ return () => {
639
+ var _a3;
640
+ console.log("[PhaseItem] Stopping timer for phase:", (_a3 = phase.statusStep) == null ? void 0 : _a3.text);
641
+ clearInterval(interval);
642
+ };
643
+ }, [isActive, (_b = phase.statusStep) == null ? void 0 : _b.text]);
644
+ const showElapsedTime = isActive && secondsElapsed >= 3;
645
+ return /* @__PURE__ */ jsxs("div", { className: "phase-item", children: [
646
+ phase.statusStep && /* @__PURE__ */ jsxs(
647
+ "div",
648
+ {
649
+ className: `task-step ${phase.statusStep.type} ${phaseIsComplete ? "complete" : "pending"} ${isActive ? "current" : ""} ${hasTools ? "has-dropdown" : ""}`,
650
+ onClick: hasTools ? () => {
651
+ setIsToolsExpanded(!isToolsExpanded);
652
+ setWasManuallyExpanded(true);
653
+ } : void 0,
654
+ children: [
655
+ /* @__PURE__ */ jsx("div", { className: "task-step-indicator", children: phaseIsComplete ? /* @__PURE__ */ jsx("span", { className: "task-checkmark", children: "✓" }) : /* @__PURE__ */ jsx("span", { className: "task-spinner" }) }),
656
+ /* @__PURE__ */ jsxs("span", { className: "task-step-text", children: [
657
+ phase.statusStep.isThinkingPlaceholder ? "Thinking..." : phase.statusStep.text || "",
658
+ phase.statusStep.target && /* @__PURE__ */ jsxs("span", { className: "task-step-target", children: [
659
+ " ",
660
+ phase.statusStep.target
661
+ ] }),
662
+ showElapsedTime && /* @__PURE__ */ jsxs("span", { className: "task-step-elapsed", children: [
663
+ " (",
664
+ secondsElapsed,
665
+ "s)"
666
+ ] })
667
+ ] }),
668
+ hasTools && /* @__PURE__ */ jsx("span", { className: "task-step-dropdown-icon", children: isToolsExpanded ? "▼" : "▶" })
669
+ ]
670
+ }
671
+ ),
672
+ isToolsExpanded && /* @__PURE__ */ jsxs("div", { className: "task-step-details", children: [
673
+ hasTools === false && isActive && phase.statusStep && !phase.statusStep.isThinkingPlaceholder && /* @__PURE__ */ jsxs("div", { className: "task-step-detail executing", children: [
674
+ /* @__PURE__ */ jsx("div", { className: "task-step-indicator", children: /* @__PURE__ */ jsx("span", { className: "task-spinner" }) }),
675
+ /* @__PURE__ */ jsx("span", { className: "task-step-text", children: "Thinking..." })
676
+ ] }),
677
+ phase.toolSteps.map((step, index) => /* @__PURE__ */ jsxs(
678
+ "div",
679
+ {
680
+ className: `task-step-detail ${step.isComplete ? "complete" : "executing"}`,
681
+ children: [
682
+ /* @__PURE__ */ jsx("div", { className: "task-step-indicator", children: step.isComplete ? /* @__PURE__ */ jsx("span", { className: "task-checkmark", children: "✓" }) : /* @__PURE__ */ jsx("span", { className: "task-spinner" }) }),
683
+ /* @__PURE__ */ jsxs("span", { className: "task-step-text", children: [
684
+ step.text || "",
685
+ step.target && /* @__PURE__ */ jsxs("span", { className: "task-step-target", children: [
686
+ " ",
687
+ step.target
688
+ ] })
689
+ ] })
690
+ ]
691
+ },
692
+ index
693
+ ))
694
+ ] })
695
+ ] });
696
+ }
697
+ function TaskBlock({ userMessage, steps, isStreaming }) {
698
+ let userContent = "";
699
+ if (userMessage) {
700
+ if ("role" in userMessage) {
701
+ userContent = userMessage.content;
702
+ } else {
703
+ const chatMsg = userMessage;
704
+ if (chatMsg.type === "user") {
705
+ userContent = chatMsg.message;
706
+ }
707
+ }
708
+ }
709
+ const phases = groupStepsIntoPhases(steps);
710
+ return /* @__PURE__ */ jsxs("div", { className: "task-block", children: [
711
+ userContent && /* @__PURE__ */ jsxs("div", { className: "task-block-header", children: [
712
+ /* @__PURE__ */ jsx("div", { className: "task-block-title", children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: userContent }) }),
713
+ /* @__PURE__ */ jsx("button", { className: "task-block-undo", title: "Undo this task", children: "↶" })
714
+ ] }),
715
+ /* @__PURE__ */ jsx("div", { className: "task-block-steps", children: phases.map((phase, index) => /* @__PURE__ */ jsx(PhaseItem, { phase, isStreaming }, index)) })
716
+ ] });
717
+ }
718
+ function isCompletionMessage(content) {
719
+ if (!content) return false;
720
+ const trimmed = content.trim().toLowerCase();
721
+ return trimmed.startsWith("done.") || trimmed.startsWith("complete.") || trimmed.startsWith("finished.");
722
+ }
723
+ function isStatusMessage(content) {
724
+ if (!content) return false;
725
+ const trimmed = content.trim();
726
+ if (isCompletionMessage(trimmed)) {
727
+ return true;
728
+ }
729
+ if (trimmed.length < 100) {
730
+ const actionStarters = [
731
+ "searching",
732
+ "reading",
733
+ "writing",
734
+ "editing",
735
+ "looking",
736
+ "finding",
737
+ "checking",
738
+ "analyzing",
739
+ "processing",
740
+ "updating",
741
+ "creating",
742
+ "modifying",
743
+ "changing",
744
+ "applying",
745
+ "converting",
746
+ "transforming"
747
+ ];
748
+ const lowerContent = trimmed.toLowerCase();
749
+ if (actionStarters.some((starter) => lowerContent.startsWith(starter))) {
750
+ return true;
751
+ }
752
+ }
753
+ return false;
754
+ }
755
+ function groupMessages(messages, options) {
756
+ var _a, _b, _c, _d;
757
+ const groups = [];
758
+ let currentTaskBlock = { steps: [] };
759
+ const { isStreaming = false } = options || {};
760
+ const flushTaskBlock = () => {
761
+ if (currentTaskBlock.userMessage || currentTaskBlock.steps.length > 0) {
762
+ groups.push({
763
+ type: "task-block",
764
+ userMessage: currentTaskBlock.userMessage,
765
+ messages: currentTaskBlock.steps
766
+ });
767
+ currentTaskBlock = { steps: [] };
768
+ }
769
+ };
770
+ for (let i = 0; i < messages.length; i++) {
771
+ const msg = messages[i];
772
+ const isLastMessage = i === messages.length - 1;
773
+ if ("role" in msg) {
774
+ if (msg.role === "user") {
775
+ flushTaskBlock();
776
+ currentTaskBlock.userMessage = msg;
777
+ } else if (msg.role === "assistant") {
778
+ if (isStatusMessage(msg.content)) {
779
+ currentTaskBlock.steps.push(msg);
780
+ } else {
781
+ flushTaskBlock();
782
+ groups.push({ type: "assistant", messages: [msg] });
783
+ }
784
+ }
785
+ continue;
786
+ }
787
+ const chatMsg = msg;
788
+ if (chatMsg.type === "user") {
789
+ flushTaskBlock();
790
+ currentTaskBlock.userMessage = msg;
791
+ } else if (chatMsg.type === "error") {
792
+ flushTaskBlock();
793
+ groups.push({ type: "error", messages: [msg] });
794
+ } else if (chatMsg.type === "assistant") {
795
+ const content = typeof chatMsg.message === "string" ? chatMsg.message : ((_c = (_b = (_a = chatMsg.message) == null ? void 0 : _a.content) == null ? void 0 : _b[0]) == null ? void 0 : _c.text) || "";
796
+ const contentBlocks = ((_d = chatMsg.message) == null ? void 0 : _d.content) || [];
797
+ const hasToolUse = contentBlocks.some((block) => block.type === "tool_use");
798
+ const shouldBeInTaskBlock = isStatusMessage(content) || hasToolUse || isStreaming && isLastMessage;
799
+ if (shouldBeInTaskBlock) {
800
+ currentTaskBlock.steps.push(msg);
801
+ } else if (content.trim()) {
802
+ flushTaskBlock();
803
+ groups.push({ type: "assistant", messages: [msg] });
804
+ }
805
+ } else if (chatMsg.type === "tool_use" || chatMsg.type === "tool_result" || chatMsg.type === "result" || chatMsg.type === "done") {
806
+ currentTaskBlock.steps.push(msg);
807
+ }
808
+ }
809
+ flushTaskBlock();
810
+ return groups;
811
+ }
812
+ function convertToTaskSteps(messages, isStreaming, startedToolIds = /* @__PURE__ */ new Set(), completedToolIds = /* @__PURE__ */ new Set()) {
813
+ var _a;
814
+ const steps = [];
815
+ for (let i = 0; i < messages.length; i++) {
816
+ const msg = messages[i];
817
+ if ("role" in msg) {
818
+ if (msg.role === "assistant" && msg.content) {
819
+ const isCompletion = isCompletionMessage(msg.content);
820
+ steps.push({
821
+ type: isCompletion ? "completion" : "status",
822
+ text: msg.content,
823
+ isComplete: false,
824
+ // Will be set later
825
+ isLast: false
826
+ });
827
+ }
828
+ continue;
829
+ }
830
+ const chatMsg = msg;
831
+ if (chatMsg.type === "assistant") {
832
+ const contentBlocks = ((_a = chatMsg.message) == null ? void 0 : _a.content) || [];
833
+ for (const block of contentBlocks) {
834
+ if (block.type === "text") {
835
+ const text = block.text || "";
836
+ if (text && text.trim()) {
837
+ const isCompletion = isCompletionMessage(text);
838
+ steps.push({
839
+ type: isCompletion ? "completion" : "status",
840
+ text,
841
+ isComplete: false,
842
+ // Will be set later
843
+ isLast: false
844
+ });
845
+ }
846
+ }
847
+ if (block.type === "tool_use") {
848
+ const toolDescriptions = {
849
+ Read: "Reading",
850
+ Write: "Writing",
851
+ Edit: "Editing",
852
+ Glob: "Searching",
853
+ Grep: "Searching",
854
+ Bash: "Running",
855
+ Task: "Running task"
856
+ };
857
+ const action = toolDescriptions[block.name] || block.name;
858
+ let target = "";
859
+ const input = block.input || {};
860
+ if (block.name === "Task") {
861
+ target = input.description || (input.prompt ? input.prompt.split("\n")[0].substring(0, 50) : "");
862
+ } else if (input.file_path) {
863
+ const fileName = input.file_path.split("/").pop() || input.file_path;
864
+ target = fileName;
865
+ } else if (input.pattern) {
866
+ target = `"${input.pattern}"`;
867
+ } else if (input.command) {
868
+ target = input.command.split(" ")[0];
869
+ }
870
+ steps.push({
871
+ type: "tool",
872
+ text: action,
873
+ tool: block.name,
874
+ target,
875
+ toolId: block.id,
876
+ isComplete: false,
877
+ // Will be set later
878
+ isLast: false
879
+ });
880
+ }
881
+ }
882
+ } else if (chatMsg.type === "tool_use") {
883
+ const toolDescriptions = {
884
+ read_file: "Reading file",
885
+ write_file: "Writing file",
886
+ edit_file: "Editing file",
887
+ search_files: "Searching files",
888
+ list_files: "Listing files",
889
+ run_command: "Running command"
890
+ };
891
+ const description = toolDescriptions[chatMsg.tool] || `Running ${chatMsg.tool}`;
892
+ steps.push({
893
+ type: "tool",
894
+ text: description,
895
+ tool: chatMsg.tool,
896
+ isComplete: false,
897
+ // Will be set later
898
+ isLast: false
899
+ });
900
+ } else if (chatMsg.type === "result") {
901
+ if (chatMsg.result && chatMsg.result.trim()) {
902
+ steps.push({
903
+ type: "status",
904
+ text: chatMsg.result,
905
+ isComplete: true,
906
+ isLast: false
907
+ });
908
+ }
909
+ }
910
+ }
911
+ if (steps.length > 0) {
912
+ const lastStepIndex = steps.length - 1;
913
+ for (let i = 0; i < steps.length; i++) {
914
+ const step = steps[i];
915
+ const isLastStep = i === lastStepIndex;
916
+ step.isLast = isLastStep;
917
+ if (step.type === "tool") {
918
+ const toolId = step.toolId;
919
+ if (toolId) {
920
+ const hasCompleted = completedToolIds.has(toolId);
921
+ const hasStarted = startedToolIds.has(toolId);
922
+ if (!hasCompleted && !isStreaming) {
923
+ console.warn(`[MessageList] Tool ${toolId} (${step.text}) not in completedToolIds after streaming ended`, {
924
+ completedToolIds: Array.from(completedToolIds),
925
+ startedToolIds: Array.from(startedToolIds)
926
+ });
927
+ }
928
+ step.isComplete = !isStreaming || hasCompleted;
929
+ step.isExecuting = isStreaming && hasStarted && !hasCompleted;
930
+ step.isQueued = isStreaming && !hasStarted && !hasCompleted;
931
+ } else {
932
+ step.isComplete = true;
933
+ step.isExecuting = false;
934
+ step.isQueued = false;
935
+ }
936
+ } else if (step.type === "status") {
937
+ step.isComplete = !isStreaming || !isLastStep;
938
+ } else if (step.type === "completion") {
939
+ step.isComplete = true;
940
+ }
941
+ }
942
+ }
943
+ return steps;
944
+ }
945
+ function MessageList({
946
+ messages,
947
+ isStreaming,
948
+ startedToolIds = /* @__PURE__ */ new Set(),
949
+ completedToolIds = /* @__PURE__ */ new Set(),
950
+ todos = []
951
+ }) {
952
+ const messagesEndRef = useRef(null);
953
+ const groups = useMemo(() => groupMessages(messages, { isStreaming }), [messages, isStreaming]);
954
+ useEffect(() => {
955
+ if (messagesEndRef.current) {
956
+ messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
957
+ }
958
+ }, [messages]);
959
+ if (messages.length === 0) {
960
+ return /* @__PURE__ */ jsx("div", { className: "message-list-empty" });
961
+ }
962
+ return /* @__PURE__ */ jsxs("div", { className: "message-list", children: [
963
+ todos.length > 0 && /* @__PURE__ */ jsxs("div", { className: "todo-list", children: [
964
+ /* @__PURE__ */ jsx("div", { className: "todo-list-header", children: "Tasks" }),
965
+ todos.map((todo, idx) => /* @__PURE__ */ jsxs("div", { className: `todo-item todo-${todo.status}`, children: [
966
+ /* @__PURE__ */ jsx("div", { className: "todo-indicator", children: todo.status === "completed" ? /* @__PURE__ */ jsx("span", { className: "todo-checkmark", children: "✓" }) : todo.status === "in_progress" ? /* @__PURE__ */ jsx("span", { className: "todo-spinner" }) : /* @__PURE__ */ jsx("span", { className: "todo-pending", children: "○" }) }),
967
+ /* @__PURE__ */ jsx("span", { className: "todo-text", children: todo.status === "in_progress" ? todo.activeForm : todo.content })
968
+ ] }, idx))
969
+ ] }),
970
+ groups.map((group, groupIndex) => {
971
+ const isLastGroup = groupIndex === groups.length - 1;
972
+ if (group.type === "assistant" || group.type === "error") {
973
+ return /* @__PURE__ */ jsx(MessageItem, { message: group.messages[0] }, groupIndex);
974
+ }
975
+ if (group.type === "task-block") {
976
+ const steps = convertToTaskSteps(
977
+ group.messages,
978
+ !!(isStreaming && isLastGroup),
979
+ startedToolIds,
980
+ completedToolIds
981
+ );
982
+ const allStepsComplete = steps.length === 0 || steps.every((step) => step.isComplete);
983
+ const shouldShowThinking = isStreaming && isLastGroup && allStepsComplete;
984
+ const displaySteps = shouldShowThinking ? [
985
+ ...steps,
986
+ {
987
+ type: "status",
988
+ isComplete: false,
989
+ isLast: true,
990
+ isThinkingPlaceholder: true
991
+ }
992
+ ] : steps;
993
+ return /* @__PURE__ */ jsx(
994
+ TaskBlock,
995
+ {
996
+ userMessage: group.userMessage,
997
+ steps: displaySteps,
998
+ isStreaming: !!(isStreaming && isLastGroup)
999
+ },
1000
+ groupIndex
1001
+ );
1002
+ }
1003
+ return null;
1004
+ }),
1005
+ /* @__PURE__ */ jsx("div", { ref: messagesEndRef })
1006
+ ] });
1007
+ }
1008
+ function getServiceUrl() {
1009
+ var _a, _b;
1010
+ if (typeof window !== "undefined" && ((_a = window.env) == null ? void 0 : _a.NEXT_PUBLIC_AI_EDITOR_SERVICE_URL)) {
1011
+ return window.env.NEXT_PUBLIC_AI_EDITOR_SERVICE_URL;
1012
+ }
1013
+ if (typeof process !== "undefined" && ((_b = process.env) == null ? void 0 : _b.NEXT_PUBLIC_AI_EDITOR_SERVICE_URL)) {
1014
+ return process.env.NEXT_PUBLIC_AI_EDITOR_SERVICE_URL;
1015
+ }
1016
+ return "http://localhost:3456";
1017
+ }
1018
+ function buildServiceUrl(path) {
1019
+ const baseUrl = getServiceUrl();
1020
+ const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
1021
+ return `${baseUrl}/${normalizedPath}`;
1022
+ }
1023
+ function useChatStream(options) {
1024
+ const { threadId, sessionId: initialSessionId, onMessage, onError, onDone } = options;
1025
+ const [state, setState] = useState({
1026
+ messages: [],
1027
+ isConnected: false,
1028
+ isStreaming: false,
1029
+ error: null,
1030
+ sessionId: initialSessionId || null
1031
+ });
1032
+ const wsRef = useRef(null);
1033
+ const [startedToolIds, setStartedToolIds] = useState(/* @__PURE__ */ new Set());
1034
+ const [completedToolIds, setCompletedToolIds] = useState(/* @__PURE__ */ new Set());
1035
+ const [todos, setTodos] = useState([]);
1036
+ const parseEventData = useCallback((data) => {
1037
+ try {
1038
+ return JSON.parse(data);
1039
+ } catch (error) {
1040
+ console.error("Failed to parse SSE data:", data, error);
1041
+ return null;
1042
+ }
1043
+ }, []);
1044
+ const sendMessage = useCallback(
1045
+ async (message, componentContext) => {
1046
+ if (wsRef.current) {
1047
+ wsRef.current.close();
1048
+ wsRef.current = null;
1049
+ }
1050
+ const userMessage = { type: "user", message };
1051
+ setState((prev) => ({
1052
+ ...prev,
1053
+ messages: [...prev.messages, userMessage],
1054
+ isStreaming: true,
1055
+ error: null
1056
+ }));
1057
+ try {
1058
+ const wsUrl = buildServiceUrl("ws/chat").replace(/^http/, "ws");
1059
+ const ws = new WebSocket(wsUrl);
1060
+ wsRef.current = ws;
1061
+ let currentAssistantMessage = null;
1062
+ ws.onopen = () => {
1063
+ console.log("[WebSocket] Connected");
1064
+ const logToServer = (level, ...args) => {
1065
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
1066
+ const logMessage = args.map(
1067
+ (arg) => typeof arg === "object" ? JSON.stringify(arg) : String(arg)
1068
+ ).join(" ");
1069
+ ws.send(JSON.stringify({
1070
+ type: "client_log",
1071
+ level,
1072
+ timestamp,
1073
+ message: logMessage
1074
+ }));
1075
+ console[level](`[${timestamp}]`, ...args);
1076
+ };
1077
+ ws.logToServer = logToServer;
1078
+ ws.send(
1079
+ JSON.stringify({
1080
+ type: "chat",
1081
+ threadId,
1082
+ sessionId: state.sessionId,
1083
+ message,
1084
+ componentContext
1085
+ })
1086
+ );
1087
+ };
1088
+ ws.onmessage = (event) => {
1089
+ var _a, _b;
1090
+ const data = parseEventData(event.data);
1091
+ if (!data) return;
1092
+ if (ws.logToServer) {
1093
+ ws.logToServer("log", `[useChatStream] Received event: ${data.type}`);
1094
+ }
1095
+ if (data.type === "assistant") {
1096
+ const content = ((_a = data.message) == null ? void 0 : _a.content) || [];
1097
+ for (const block of content) {
1098
+ if (block.type === "tool_use" && block.name === "TodoWrite") {
1099
+ const todosData = ((_b = block.input) == null ? void 0 : _b.todos) || [];
1100
+ setTodos(todosData);
1101
+ }
1102
+ }
1103
+ if (currentAssistantMessage) {
1104
+ setState((prev) => {
1105
+ var _a2, _b2, _c;
1106
+ const messages = [...prev.messages];
1107
+ const lastIndex = messages.length - 1;
1108
+ if (((_a2 = messages[lastIndex]) == null ? void 0 : _a2.type) === "assistant") {
1109
+ const existingContent = ((_b2 = messages[lastIndex].message) == null ? void 0 : _b2.content) || [];
1110
+ const newContent = ((_c = data.message) == null ? void 0 : _c.content) || [];
1111
+ messages[lastIndex] = {
1112
+ ...messages[lastIndex],
1113
+ message: {
1114
+ ...messages[lastIndex].message,
1115
+ content: [...existingContent, ...newContent]
1116
+ }
1117
+ };
1118
+ }
1119
+ return { ...prev, messages };
1120
+ });
1121
+ } else {
1122
+ currentAssistantMessage = data;
1123
+ setState((prev) => ({
1124
+ ...prev,
1125
+ messages: [...prev.messages, data]
1126
+ }));
1127
+ }
1128
+ onMessage == null ? void 0 : onMessage(data);
1129
+ return;
1130
+ }
1131
+ currentAssistantMessage = null;
1132
+ if (data.type === "tool_start") {
1133
+ const toolId = data.toolId;
1134
+ if (toolId) {
1135
+ if (ws.logToServer) {
1136
+ ws.logToServer("log", `[CLIENT] Tool STARTED: ${data.toolName} (${toolId})`);
1137
+ }
1138
+ setStartedToolIds((prev) => new Set(prev).add(toolId));
1139
+ }
1140
+ return;
1141
+ }
1142
+ if (data.type === "tool_complete") {
1143
+ const toolId = data.toolId;
1144
+ if (toolId) {
1145
+ if (ws.logToServer) {
1146
+ ws.logToServer("log", `[CLIENT] Tool COMPLETED: ${data.toolName} (${toolId})`);
1147
+ }
1148
+ flushSync(() => {
1149
+ setCompletedToolIds((prev) => new Set(prev).add(toolId));
1150
+ });
1151
+ }
1152
+ return;
1153
+ }
1154
+ if (data.type === "user") {
1155
+ return;
1156
+ }
1157
+ if (data.type === "tool_use") {
1158
+ setState((prev) => ({
1159
+ ...prev,
1160
+ messages: [...prev.messages, data]
1161
+ }));
1162
+ onMessage == null ? void 0 : onMessage(data);
1163
+ return;
1164
+ }
1165
+ if (data.type === "result") {
1166
+ setState((prev) => {
1167
+ var _a2, _b2, _c;
1168
+ const lastMsg = prev.messages[prev.messages.length - 1];
1169
+ if ((lastMsg == null ? void 0 : lastMsg.type) === "assistant") {
1170
+ const lastText = ((_c = (_b2 = (_a2 = lastMsg.message) == null ? void 0 : _a2.content) == null ? void 0 : _b2[0]) == null ? void 0 : _c.text) || "";
1171
+ const resultText = data.result || "";
1172
+ if (lastText.includes(resultText) || resultText.includes(lastText)) {
1173
+ return prev;
1174
+ }
1175
+ }
1176
+ return {
1177
+ ...prev,
1178
+ messages: [...prev.messages, data]
1179
+ };
1180
+ });
1181
+ onMessage == null ? void 0 : onMessage(data);
1182
+ return;
1183
+ }
1184
+ if (data.type === "connected") {
1185
+ setState((prev) => ({
1186
+ ...prev,
1187
+ sessionId: data.sessionId,
1188
+ isConnected: true
1189
+ }));
1190
+ return;
1191
+ }
1192
+ if (data.type === "done") {
1193
+ setState((prev) => ({
1194
+ ...prev,
1195
+ isStreaming: false,
1196
+ messages: [...prev.messages, data]
1197
+ }));
1198
+ onDone == null ? void 0 : onDone();
1199
+ return;
1200
+ }
1201
+ if (data.type === "error") {
1202
+ setState((prev) => ({
1203
+ ...prev,
1204
+ isStreaming: false,
1205
+ error: data.error,
1206
+ messages: [...prev.messages, data]
1207
+ }));
1208
+ onError == null ? void 0 : onError(data.error);
1209
+ return;
1210
+ }
1211
+ setState((prev) => ({
1212
+ ...prev,
1213
+ messages: [...prev.messages, data]
1214
+ }));
1215
+ onMessage == null ? void 0 : onMessage(data);
1216
+ };
1217
+ ws.onerror = (error) => {
1218
+ console.error("[WebSocket] Error:", error);
1219
+ setState((prev) => ({
1220
+ ...prev,
1221
+ isStreaming: false,
1222
+ error: "WebSocket connection error"
1223
+ }));
1224
+ onError == null ? void 0 : onError("WebSocket connection error");
1225
+ };
1226
+ ws.onclose = () => {
1227
+ console.log("[WebSocket] Disconnected");
1228
+ setState((prev) => ({
1229
+ ...prev,
1230
+ isStreaming: false
1231
+ }));
1232
+ };
1233
+ } catch (error) {
1234
+ const errorMessage = error.message || "Failed to send message";
1235
+ setState((prev) => ({
1236
+ ...prev,
1237
+ isStreaming: false,
1238
+ error: errorMessage
1239
+ }));
1240
+ onError == null ? void 0 : onError(errorMessage);
1241
+ }
1242
+ },
1243
+ [threadId, state.sessionId, parseEventData, onMessage, onError, onDone]
1244
+ );
1245
+ useEffect(() => {
1246
+ return () => {
1247
+ if (wsRef.current) {
1248
+ wsRef.current.close();
1249
+ }
1250
+ };
1251
+ }, []);
1252
+ return {
1253
+ ...state,
1254
+ sendMessage,
1255
+ startedToolIds,
1256
+ completedToolIds,
1257
+ todos
1258
+ };
1259
+ }
1260
+ /**
1261
+ * @license lucide-react v0.562.0 - ISC
1262
+ *
1263
+ * This source code is licensed under the ISC license.
1264
+ * See the LICENSE file in the root directory of this source tree.
1265
+ */
1266
+ const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
1267
+ const toCamelCase = (string) => string.replace(
1268
+ /^([A-Z])|[\s-_]+(\w)/g,
1269
+ (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
1270
+ );
1271
+ const toPascalCase = (string) => {
1272
+ const camelCase = toCamelCase(string);
1273
+ return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
1274
+ };
1275
+ const mergeClasses = (...classes) => classes.filter((className, index, array) => {
1276
+ return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
1277
+ }).join(" ").trim();
1278
+ const hasA11yProp = (props) => {
1279
+ for (const prop in props) {
1280
+ if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
1281
+ return true;
1282
+ }
1283
+ }
1284
+ };
1285
+ /**
1286
+ * @license lucide-react v0.562.0 - ISC
1287
+ *
1288
+ * This source code is licensed under the ISC license.
1289
+ * See the LICENSE file in the root directory of this source tree.
1290
+ */
1291
+ var defaultAttributes = {
1292
+ xmlns: "http://www.w3.org/2000/svg",
1293
+ width: 24,
1294
+ height: 24,
1295
+ viewBox: "0 0 24 24",
1296
+ fill: "none",
1297
+ stroke: "currentColor",
1298
+ strokeWidth: 2,
1299
+ strokeLinecap: "round",
1300
+ strokeLinejoin: "round"
1301
+ };
1302
+ /**
1303
+ * @license lucide-react v0.562.0 - ISC
1304
+ *
1305
+ * This source code is licensed under the ISC license.
1306
+ * See the LICENSE file in the root directory of this source tree.
1307
+ */
1308
+ const Icon = forwardRef(
1309
+ ({
1310
+ color = "currentColor",
1311
+ size = 24,
1312
+ strokeWidth = 2,
1313
+ absoluteStrokeWidth,
1314
+ className = "",
1315
+ children,
1316
+ iconNode,
1317
+ ...rest
1318
+ }, ref) => createElement(
1319
+ "svg",
1320
+ {
1321
+ ref,
1322
+ ...defaultAttributes,
1323
+ width: size,
1324
+ height: size,
1325
+ stroke: color,
1326
+ strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
1327
+ className: mergeClasses("lucide", className),
1328
+ ...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
1329
+ ...rest
1330
+ },
1331
+ [
1332
+ ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),
1333
+ ...Array.isArray(children) ? children : [children]
1334
+ ]
1335
+ )
1336
+ );
1337
+ /**
1338
+ * @license lucide-react v0.562.0 - ISC
1339
+ *
1340
+ * This source code is licensed under the ISC license.
1341
+ * See the LICENSE file in the root directory of this source tree.
1342
+ */
1343
+ const createLucideIcon = (iconName, iconNode) => {
1344
+ const Component = forwardRef(
1345
+ ({ className, ...props }, ref) => createElement(Icon, {
1346
+ ref,
1347
+ iconNode,
1348
+ className: mergeClasses(
1349
+ `lucide-${toKebabCase(toPascalCase(iconName))}`,
1350
+ `lucide-${iconName}`,
1351
+ className
1352
+ ),
1353
+ ...props
1354
+ })
1355
+ );
1356
+ Component.displayName = toPascalCase(iconName);
1357
+ return Component;
1358
+ };
1359
+ /**
1360
+ * @license lucide-react v0.562.0 - ISC
1361
+ *
1362
+ * This source code is licensed under the ISC license.
1363
+ * See the LICENSE file in the root directory of this source tree.
1364
+ */
1365
+ const __iconNode$4 = [
1366
+ [
1367
+ "path",
1368
+ {
1369
+ d: "M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z",
1370
+ key: "hh9hay"
1371
+ }
1372
+ ],
1373
+ ["path", { d: "m3.3 7 8.7 5 8.7-5", key: "g66t2b" }],
1374
+ ["path", { d: "M12 22V12", key: "d0xqtd" }]
1375
+ ];
1376
+ const Box = createLucideIcon("box", __iconNode$4);
1377
+ /**
1378
+ * @license lucide-react v0.562.0 - ISC
1379
+ *
1380
+ * This source code is licensed under the ISC license.
1381
+ * See the LICENSE file in the root directory of this source tree.
1382
+ */
1383
+ const __iconNode$3 = [
1384
+ [
1385
+ "path",
1386
+ {
1387
+ d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
1388
+ key: "1oefj6"
1389
+ }
1390
+ ],
1391
+ ["path", { d: "M14 2v5a1 1 0 0 0 1 1h5", key: "wfsgrz" }],
1392
+ ["path", { d: "M10 12.5 8 15l2 2.5", key: "1tg20x" }],
1393
+ ["path", { d: "m14 12.5 2 2.5-2 2.5", key: "yinavb" }]
1394
+ ];
1395
+ const FileCode = createLucideIcon("file-code", __iconNode$3);
1396
+ /**
1397
+ * @license lucide-react v0.562.0 - ISC
1398
+ *
1399
+ * This source code is licensed under the ISC license.
1400
+ * See the LICENSE file in the root directory of this source tree.
1401
+ */
1402
+ const __iconNode$2 = [
1403
+ [
1404
+ "path",
1405
+ {
1406
+ d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",
1407
+ key: "1a8usu"
1408
+ }
1409
+ ],
1410
+ ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
1411
+ ];
1412
+ const Pencil = createLucideIcon("pencil", __iconNode$2);
1413
+ /**
1414
+ * @license lucide-react v0.562.0 - ISC
1415
+ *
1416
+ * This source code is licensed under the ISC license.
1417
+ * See the LICENSE file in the root directory of this source tree.
1418
+ */
1419
+ const __iconNode$1 = [
1420
+ ["path", { d: "M12 4v16", key: "1654pz" }],
1421
+ ["path", { d: "M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2", key: "e0r10z" }],
1422
+ ["path", { d: "M9 20h6", key: "s66wpe" }]
1423
+ ];
1424
+ const Type = createLucideIcon("type", __iconNode$1);
1425
+ /**
1426
+ * @license lucide-react v0.562.0 - ISC
1427
+ *
1428
+ * This source code is licensed under the ISC license.
1429
+ * See the LICENSE file in the root directory of this source tree.
1430
+ */
1431
+ const __iconNode = [
1432
+ ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
1433
+ ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
1434
+ ];
1435
+ const X = createLucideIcon("x", __iconNode);
1436
+ function ChatPanel({
1437
+ isExpanded,
1438
+ onToggle,
1439
+ activeTool,
1440
+ onToolChange,
1441
+ attachedContext,
1442
+ onClearContext,
1443
+ theme = "dark"
1444
+ }) {
1445
+ const [message, setMessage] = useState("");
1446
+ const [threadId] = useState(() => `thread-${Date.now()}`);
1447
+ const textareaRef = useRef(null);
1448
+ const [contextRanges, setContextRanges] = useState([]);
1449
+ const [isMessagesCollapsed, setMessagesCollapsed] = useState(false);
1450
+ const { messages, isStreaming, sendMessage, startedToolIds, completedToolIds, todos } = useChatStream({
1451
+ threadId
1452
+ });
1453
+ useEffect(() => {
1454
+ if (attachedContext) {
1455
+ setContextRanges((prev) => [...prev, {
1456
+ start: 0,
1457
+ end: 0,
1458
+ context: attachedContext
1459
+ }]);
1460
+ if (textareaRef.current) {
1461
+ textareaRef.current.focus();
1462
+ }
1463
+ onClearContext();
1464
+ }
1465
+ }, [attachedContext, onClearContext]);
1466
+ const handleInput = useCallback((e) => {
1467
+ const target = e.target;
1468
+ setMessage(target.value);
1469
+ target.style.height = "auto";
1470
+ target.style.height = Math.min(target.scrollHeight, 200) + "px";
1471
+ }, []);
1472
+ const handleSend = useCallback(async () => {
1473
+ if (!message.trim() || isStreaming) return;
1474
+ const messageText = message;
1475
+ const componentContext = contextRanges.length > 0 && contextRanges[0].context.type === "component" ? contextRanges[0].context.data : void 0;
1476
+ setMessage("");
1477
+ setContextRanges([]);
1478
+ if (textareaRef.current) {
1479
+ textareaRef.current.style.height = "auto";
1480
+ }
1481
+ await sendMessage(messageText, componentContext);
1482
+ }, [message, isStreaming, contextRanges, sendMessage]);
1483
+ const handleKeyDown = useCallback((e) => {
1484
+ if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
1485
+ e.preventDefault();
1486
+ handleSend();
1487
+ }
1488
+ if (e.key === "Escape") {
1489
+ e.preventDefault();
1490
+ onToggle();
1491
+ }
1492
+ }, [handleSend, onToggle]);
1493
+ const commentMessages = messages;
1494
+ const visibleCount = useMemo(() => {
1495
+ var _a, _b, _c, _d;
1496
+ let count = 0;
1497
+ let hasUserMessage = false;
1498
+ for (const msg of commentMessages) {
1499
+ if ("role" in msg) {
1500
+ if (msg.role === "user") {
1501
+ if (hasUserMessage) {
1502
+ count++;
1503
+ }
1504
+ hasUserMessage = true;
1505
+ } else if (msg.role === "assistant" && !hasUserMessage) {
1506
+ if ((_a = msg.content) == null ? void 0 : _a.trim()) count++;
1507
+ }
1508
+ continue;
1509
+ }
1510
+ const chatMsg = msg;
1511
+ if (chatMsg.type === "user") {
1512
+ if (hasUserMessage) {
1513
+ count++;
1514
+ }
1515
+ hasUserMessage = true;
1516
+ } else if (chatMsg.type === "error") {
1517
+ if (hasUserMessage) {
1518
+ count++;
1519
+ hasUserMessage = false;
1520
+ }
1521
+ count++;
1522
+ } else if (chatMsg.type === "assistant") {
1523
+ const content = typeof chatMsg.message === "string" ? chatMsg.message : ((_d = (_c = (_b = chatMsg.message) == null ? void 0 : _b.content) == null ? void 0 : _c[0]) == null ? void 0 : _d.text) || "";
1524
+ const isStatus = content && content.trim().length < 80 && (content.endsWith(".") || content.endsWith("..."));
1525
+ if (!isStatus && content.trim() && !hasUserMessage) {
1526
+ count++;
1527
+ }
1528
+ }
1529
+ }
1530
+ if (hasUserMessage) {
1531
+ count++;
1532
+ }
1533
+ return count;
1534
+ }, [commentMessages]);
1535
+ if (!isExpanded) {
1536
+ return null;
1537
+ }
1538
+ return /* @__PURE__ */ jsxs("div", { className: `chat-panel ai-editor-ui ${theme} ${commentMessages.length === 0 ? "empty" : ""}`, children: [
1539
+ commentMessages.length > 0 && /* @__PURE__ */ jsxs("div", { className: `chat-panel-messages-container ${isMessagesCollapsed ? "collapsed" : "expanded"}`, children: [
1540
+ /* @__PURE__ */ jsx("div", { className: "chat-panel-messages-header", children: /* @__PURE__ */ jsxs(
1541
+ "div",
1542
+ {
1543
+ className: "chat-panel-messages-header-left",
1544
+ onClick: () => setMessagesCollapsed(!isMessagesCollapsed),
1545
+ children: [
1546
+ /* @__PURE__ */ jsxs("span", { className: "chat-panel-messages-title", children: [
1547
+ visibleCount,
1548
+ " task",
1549
+ visibleCount !== 1 ? "s" : ""
1550
+ ] }),
1551
+ /* @__PURE__ */ jsx("span", { className: "chat-panel-messages-toggle", children: "▼" })
1552
+ ]
1553
+ }
1554
+ ) }),
1555
+ /* @__PURE__ */ jsx("div", { className: "chat-panel-messages", children: /* @__PURE__ */ jsx(
1556
+ MessageList,
1557
+ {
1558
+ messages: commentMessages,
1559
+ isStreaming,
1560
+ startedToolIds,
1561
+ completedToolIds,
1562
+ todos
1563
+ }
1564
+ ) })
1565
+ ] }),
1566
+ commentMessages.length === 0 && /* @__PURE__ */ jsx("div", { className: "chat-panel-empty-content", children: /* @__PURE__ */ jsx(
1567
+ MessageList,
1568
+ {
1569
+ messages: [],
1570
+ isStreaming: false,
1571
+ startedToolIds: /* @__PURE__ */ new Set(),
1572
+ completedToolIds: /* @__PURE__ */ new Set(),
1573
+ todos: []
1574
+ }
1575
+ ) }),
1576
+ /* @__PURE__ */ jsxs("div", { className: "chat-panel-input", children: [
1577
+ contextRanges.length > 0 && /* @__PURE__ */ jsx("div", { className: "context-pills-container", children: contextRanges.map((range, idx) => /* @__PURE__ */ jsxs("div", { className: "context-pill-inline", children: [
1578
+ /* @__PURE__ */ jsx("span", { children: range.context.displayText }),
1579
+ /* @__PURE__ */ jsx(
1580
+ "button",
1581
+ {
1582
+ className: "context-pill-remove",
1583
+ onClick: () => {
1584
+ setContextRanges((prev) => prev.filter((_, i) => i !== idx));
1585
+ },
1586
+ title: "Remove context",
1587
+ children: "×"
1588
+ }
1589
+ )
1590
+ ] }, idx)) }),
1591
+ /* @__PURE__ */ jsxs("div", { className: "input-row", children: [
1592
+ /* @__PURE__ */ jsx(
1593
+ "textarea",
1594
+ {
1595
+ ref: textareaRef,
1596
+ className: "message-input",
1597
+ placeholder: "Ask Claude to edit your code...",
1598
+ value: message,
1599
+ onChange: handleInput,
1600
+ onKeyDown: handleKeyDown,
1601
+ disabled: isStreaming,
1602
+ rows: 1
1603
+ }
1604
+ ),
1605
+ /* @__PURE__ */ jsx(
1606
+ "button",
1607
+ {
1608
+ className: "send-button",
1609
+ onClick: handleSend,
1610
+ disabled: !message.trim() || isStreaming,
1611
+ children: "↑"
1612
+ }
1613
+ )
1614
+ ] }),
1615
+ /* @__PURE__ */ jsxs("div", { className: "chat-panel-toolbar", children: [
1616
+ /* @__PURE__ */ jsxs("div", { className: "chat-panel-tools", children: [
1617
+ /* @__PURE__ */ jsx(
1618
+ "button",
1619
+ {
1620
+ className: `tool-button ${activeTool === "component" ? "active" : ""}`,
1621
+ onClick: () => onToolChange(activeTool === "component" ? null : "component"),
1622
+ title: "Select Component",
1623
+ children: /* @__PURE__ */ jsx(FileCode, { size: 16 })
1624
+ }
1625
+ ),
1626
+ /* @__PURE__ */ jsx(
1627
+ "button",
1628
+ {
1629
+ className: `tool-button ${activeTool === "area" ? "active" : ""}`,
1630
+ onClick: () => onToolChange(activeTool === "area" ? null : "area"),
1631
+ title: "Select Area",
1632
+ children: /* @__PURE__ */ jsx(Box, { size: 16 })
1633
+ }
1634
+ ),
1635
+ /* @__PURE__ */ jsx(
1636
+ "button",
1637
+ {
1638
+ className: `tool-button ${activeTool === "text" ? "active" : ""}`,
1639
+ onClick: () => onToolChange(activeTool === "text" ? null : "text"),
1640
+ title: "Select Text",
1641
+ children: /* @__PURE__ */ jsx(Type, { size: 16 })
1642
+ }
1643
+ )
1644
+ ] }),
1645
+ /* @__PURE__ */ jsx(
1646
+ "button",
1647
+ {
1648
+ className: "close-button",
1649
+ onClick: onToggle,
1650
+ title: "Close (Esc)",
1651
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
1652
+ }
1653
+ )
1654
+ ] })
1655
+ ] })
1656
+ ] });
1657
+ }
1658
+ function ControlPill({
1659
+ isExpanded,
1660
+ onToggle,
1661
+ activeTool
1662
+ }) {
1663
+ useEffect(() => {
1664
+ const handleKeyDown = (e) => {
1665
+ if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) {
1666
+ return;
1667
+ }
1668
+ if (e.key === " " || e.key === "/") {
1669
+ e.preventDefault();
1670
+ onToggle();
1671
+ }
1672
+ if (e.key === "Escape" && isExpanded) {
1673
+ e.preventDefault();
1674
+ onToggle();
1675
+ }
1676
+ };
1677
+ window.addEventListener("keydown", handleKeyDown);
1678
+ return () => window.removeEventListener("keydown", handleKeyDown);
1679
+ }, [onToggle, isExpanded]);
1680
+ if (isExpanded) {
1681
+ return null;
1682
+ }
1683
+ return /* @__PURE__ */ jsxs("div", { className: "control-pill ai-editor-ui", onClick: onToggle, children: [
1684
+ /* @__PURE__ */ jsxs("div", { className: "control-pill-inner", children: [
1685
+ /* @__PURE__ */ jsx(Pencil, { size: 16, className: "pill-icon" }),
1686
+ /* @__PURE__ */ jsx("span", { className: "pill-label", children: "Edit" }),
1687
+ activeTool && /* @__PURE__ */ jsxs("span", { className: "active-tool-indicator", title: `${activeTool} tool active`, children: [
1688
+ activeTool === "component" && "🎯",
1689
+ activeTool === "area" && "⬛",
1690
+ activeTool === "text" && "📝"
1691
+ ] })
1692
+ ] }),
1693
+ /* @__PURE__ */ jsxs("div", { className: "control-pill-hint", children: [
1694
+ "Press ",
1695
+ /* @__PURE__ */ jsx("kbd", { children: "Space" }),
1696
+ " or ",
1697
+ /* @__PURE__ */ jsx("kbd", { children: "/" }),
1698
+ " to toggle"
1699
+ ] })
1700
+ ] });
1701
+ }
1702
+ const sourceResolutionCache = /* @__PURE__ */ new Map();
1703
+ const inflightSourceResolutions = /* @__PURE__ */ new Map();
1704
+ function inferComponentNameFromPath(filePath) {
1705
+ const fileName = filePath.split("/").pop() || "";
1706
+ const nameWithoutExt = fileName.replace(/\.(tsx?|jsx?)$/, "");
1707
+ return nameWithoutExt.charAt(0).toUpperCase() + nameWithoutExt.slice(1);
1708
+ }
1709
+ async function resolveSourceLocation(source) {
1710
+ if (typeof window === "undefined" || process.env.NODE_ENV !== "development") {
1711
+ return null;
1712
+ }
1713
+ if (!source.debugStack) {
1714
+ console.warn("No debugStack available for resolution:", source);
1715
+ return null;
1716
+ }
1717
+ const cacheKey = source.debugStack;
1718
+ const cached = sourceResolutionCache.get(cacheKey);
1719
+ if (cached) {
1720
+ const resolved2 = { ...source, ...cached };
1721
+ if (resolved2.componentName === "Unknown" && resolved2.filePath) {
1722
+ resolved2.componentName = inferComponentNameFromPath(resolved2.filePath);
1723
+ }
1724
+ return resolved2;
1725
+ }
1726
+ let inflight = inflightSourceResolutions.get(cacheKey);
1727
+ if (!inflight) {
1728
+ inflight = fetch(buildServiceUrl("api/resolve"), {
1729
+ method: "POST",
1730
+ headers: { "Content-Type": "application/json" },
1731
+ body: JSON.stringify({ debugStack: cacheKey })
1732
+ }).then(async (res) => {
1733
+ if (!res.ok) {
1734
+ console.error(`Resolve API error ${res.status}`);
1735
+ return null;
1736
+ }
1737
+ const data = await res.json();
1738
+ if ((data == null ? void 0 : data.success) && data.filePath && data.lineNumber) {
1739
+ const resolved2 = {
1740
+ filePath: data.filePath,
1741
+ lineNumber: data.lineNumber,
1742
+ columnNumber: typeof data.columnNumber === "number" ? data.columnNumber : source.columnNumber
1743
+ };
1744
+ sourceResolutionCache.set(cacheKey, resolved2);
1745
+ return resolved2;
1746
+ }
1747
+ return null;
1748
+ }).catch((err) => {
1749
+ console.error("Error calling resolve API:", err);
1750
+ return null;
1751
+ }).finally(() => {
1752
+ inflightSourceResolutions.delete(cacheKey);
1753
+ });
1754
+ inflightSourceResolutions.set(cacheKey, inflight);
1755
+ }
1756
+ const resolvedInfo = await inflight;
1757
+ if (!resolvedInfo) return null;
1758
+ const resolved = {
1759
+ ...source,
1760
+ filePath: resolvedInfo.filePath,
1761
+ lineNumber: resolvedInfo.lineNumber,
1762
+ columnNumber: resolvedInfo.columnNumber
1763
+ };
1764
+ if (resolved.componentName === "Unknown" && resolved.filePath) {
1765
+ resolved.componentName = inferComponentNameFromPath(resolved.filePath);
1766
+ }
1767
+ return resolved;
1768
+ }
1769
+ const EditorContext = createContext(null);
1770
+ function AIEditorProvider({
1771
+ children,
1772
+ theme = "dark",
1773
+ enabled
1774
+ }) {
1775
+ const [serverEnabled, setServerEnabled] = useState(null);
1776
+ useEffect(() => {
1777
+ if (enabled !== void 0) return;
1778
+ fetch(buildServiceUrl("api/config")).then((res) => res.json()).then((data) => {
1779
+ setServerEnabled(data.enabled === true);
1780
+ }).catch(() => {
1781
+ setServerEnabled(false);
1782
+ });
1783
+ }, [enabled]);
1784
+ const isEditorEnabled = enabled ?? serverEnabled;
1785
+ const [isEnabled, setEnabled] = useState(false);
1786
+ const [isHistoryOpen, setHistoryOpen] = useState(false);
1787
+ const [isChatExpanded, setChatExpanded] = useState(false);
1788
+ const [activeTool, setActiveTool] = useState(null);
1789
+ const [attachedContext, setAttachedContext] = useState(null);
1790
+ const handleChatToggle = useCallback(() => {
1791
+ setChatExpanded((prev) => !prev);
1792
+ }, []);
1793
+ const handleToolChange = useCallback((tool) => {
1794
+ setActiveTool(tool);
1795
+ if (tool === null) {
1796
+ setAttachedContext(null);
1797
+ }
1798
+ }, []);
1799
+ const handleClearContext = useCallback(() => {
1800
+ setAttachedContext(null);
1801
+ setActiveTool(null);
1802
+ }, []);
1803
+ useEffect(() => {
1804
+ const handleKey = (e) => {
1805
+ if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key.toLowerCase() === "e") {
1806
+ e.preventDefault();
1807
+ setEnabled((p) => !p);
1808
+ }
1809
+ if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key.toLowerCase() === "h") {
1810
+ e.preventDefault();
1811
+ setHistoryOpen((p) => !p);
1812
+ }
1813
+ if (e.key === "Escape" && isHistoryOpen) {
1814
+ e.preventDefault();
1815
+ setHistoryOpen(false);
1816
+ }
1817
+ };
1818
+ window.addEventListener("keydown", handleKey);
1819
+ return () => window.removeEventListener("keydown", handleKey);
1820
+ }, [isHistoryOpen]);
1821
+ if (!isEditorEnabled) {
1822
+ return /* @__PURE__ */ jsx(Fragment, { children });
1823
+ }
1824
+ return /* @__PURE__ */ jsxs(
1825
+ EditorContext.Provider,
1826
+ {
1827
+ value: {
1828
+ isEnabled,
1829
+ setEnabled
1830
+ },
1831
+ children: [
1832
+ children,
1833
+ activeTool === "component" && /* @__PURE__ */ jsx(
1834
+ EditorOverlay,
1835
+ {
1836
+ theme,
1837
+ onComponentSelect: (source, position) => {
1838
+ const contextData = {
1839
+ type: "component",
1840
+ data: source,
1841
+ displayText: `${source.componentName} (${source.filePath}:${source.lineNumber})`
1842
+ };
1843
+ setAttachedContext(contextData);
1844
+ setActiveTool(null);
1845
+ if (!isChatExpanded) {
1846
+ setChatExpanded(true);
1847
+ }
1848
+ }
1849
+ }
1850
+ ),
1851
+ /* @__PURE__ */ jsxs(
1852
+ "div",
1853
+ {
1854
+ className: `editor-container ai-editor-ui ${isChatExpanded ? "expanded" : "collapsed"} ${theme}`,
1855
+ children: [
1856
+ /* @__PURE__ */ jsx(
1857
+ ChatPanel,
1858
+ {
1859
+ isExpanded: isChatExpanded,
1860
+ onToggle: handleChatToggle,
1861
+ activeTool,
1862
+ onToolChange: handleToolChange,
1863
+ attachedContext,
1864
+ onClearContext: handleClearContext,
1865
+ theme
1866
+ }
1867
+ ),
1868
+ /* @__PURE__ */ jsx(
1869
+ ControlPill,
1870
+ {
1871
+ isExpanded: isChatExpanded,
1872
+ onToggle: handleChatToggle,
1873
+ activeTool
1874
+ }
1875
+ )
1876
+ ]
1877
+ }
1878
+ ),
1879
+ /* @__PURE__ */ jsx(
1880
+ TaskHistoryPanel,
1881
+ {
1882
+ isOpen: isHistoryOpen,
1883
+ onClose: () => setHistoryOpen(false),
1884
+ tasks: []
1885
+ }
1886
+ )
1887
+ ]
1888
+ }
1889
+ );
1890
+ }
1891
+ function EditorOverlay({ theme, onComponentSelect }) {
1892
+ var _a;
1893
+ const [hoveredSource, setHoveredSource] = useState(
1894
+ null
1895
+ );
1896
+ const [hoveredElement, setHoveredElement] = useState(null);
1897
+ const [hoveredRect, setHoveredRect] = useState(null);
1898
+ const [mousePos, setMousePos] = useState({ x: 0, y: 0 });
1899
+ const [isResolvingSource, setIsResolvingSource] = useState(false);
1900
+ const lastHoverStateRef = useRef(null);
1901
+ useEffect(() => {
1902
+ if (hoveredSource && hoveredElement) {
1903
+ lastHoverStateRef.current = {
1904
+ source: hoveredSource,
1905
+ element: hoveredElement
1906
+ };
1907
+ }
1908
+ }, [hoveredSource, hoveredElement]);
1909
+ const isDark = theme === "dark";
1910
+ const c = {
1911
+ text: isDark ? "#e4e4e7" : "#18181b",
1912
+ muted: isDark ? "#71717a" : "#a1a1aa",
1913
+ accent: "#818cf8",
1914
+ bg: isDark ? "#0d0d14" : "#fff",
1915
+ border: isDark ? "#27273f" : "#e4e4e7",
1916
+ success: "#34d399"
1917
+ };
1918
+ useEffect(() => {
1919
+ let lastEl = null;
1920
+ let raf;
1921
+ const onMove = (e) => {
1922
+ setMousePos({ x: e.clientX, y: e.clientY });
1923
+ cancelAnimationFrame(raf);
1924
+ raf = requestAnimationFrame(() => {
1925
+ const el = document.elementFromPoint(e.clientX, e.clientY);
1926
+ if (!el || el.closest(".ai-editor-ui") || el === lastEl) return;
1927
+ lastEl = el;
1928
+ const source = getSourceFromElement(el);
1929
+ if (source) {
1930
+ setHoveredElement(el);
1931
+ setHoveredRect(el.getBoundingClientRect());
1932
+ const isCompiledPath = source.filePath.includes(".next/") || source.filePath.includes("/chunks/") || source.filePath.startsWith("file://") || source.filePath.endsWith(".js") && (source.filePath.includes("/server/") || source.filePath.includes("/static/"));
1933
+ if (isCompiledPath && source.debugStack) {
1934
+ setIsResolvingSource(true);
1935
+ resolveSourceLocation(source).then((resolved) => {
1936
+ setIsResolvingSource(false);
1937
+ setHoveredSource(resolved || source);
1938
+ }).catch((err) => {
1939
+ console.error("Error resolving source location:", err);
1940
+ setIsResolvingSource(false);
1941
+ setHoveredSource(source);
1942
+ });
1943
+ } else {
1944
+ setIsResolvingSource(false);
1945
+ setHoveredSource(source);
1946
+ }
1947
+ } else {
1948
+ setHoveredSource(null);
1949
+ setHoveredElement(null);
1950
+ setHoveredRect(null);
1951
+ setIsResolvingSource(false);
1952
+ }
1953
+ });
1954
+ };
1955
+ const onClick = async (e) => {
1956
+ if (e.target.closest(".ai-editor-ui")) {
1957
+ return;
1958
+ }
1959
+ const el = e.target;
1960
+ const source = getSourceFromElement(el);
1961
+ if (source) {
1962
+ e.preventDefault();
1963
+ e.stopPropagation();
1964
+ const isCompiledPath = source.filePath.includes(".next/") || source.filePath.includes("/chunks/") || source.filePath.startsWith("file://") || source.filePath.endsWith(".js") && (source.filePath.includes("/server/") || source.filePath.includes("/static/"));
1965
+ if (isCompiledPath && source.debugStack) {
1966
+ const resolved = await resolveSourceLocation(source);
1967
+ onComponentSelect(resolved || source, { x: e.clientX, y: e.clientY });
1968
+ } else {
1969
+ onComponentSelect(source, { x: e.clientX, y: e.clientY });
1970
+ }
1971
+ }
1972
+ };
1973
+ document.addEventListener("mousemove", onMove, { passive: true });
1974
+ document.addEventListener("click", onClick, true);
1975
+ return () => {
1976
+ document.removeEventListener("mousemove", onMove);
1977
+ document.removeEventListener("click", onClick, true);
1978
+ cancelAnimationFrame(raf);
1979
+ };
1980
+ }, [onComponentSelect]);
1981
+ return /* @__PURE__ */ jsxs(
1982
+ "div",
1983
+ {
1984
+ className: "ai-editor-ui",
1985
+ style: { fontFamily: "system-ui, sans-serif" },
1986
+ children: [
1987
+ hoveredRect && /* @__PURE__ */ jsx(
1988
+ "div",
1989
+ {
1990
+ style: {
1991
+ position: "fixed",
1992
+ left: hoveredRect.left - 2,
1993
+ top: hoveredRect.top - 2,
1994
+ width: hoveredRect.width + 4,
1995
+ height: hoveredRect.height + 4,
1996
+ border: `2px solid ${c.accent}`,
1997
+ borderRadius: 6,
1998
+ background: `${c.accent}15`,
1999
+ pointerEvents: "none",
2000
+ zIndex: 99998
2001
+ }
2002
+ }
2003
+ ),
2004
+ hoveredSource && !isResolvingSource && /* @__PURE__ */ jsxs(
2005
+ "div",
2006
+ {
2007
+ style: {
2008
+ position: "fixed",
2009
+ left: Math.min(mousePos.x + 14, window.innerWidth - 340),
2010
+ top: mousePos.y + 14,
2011
+ background: c.bg,
2012
+ color: c.text,
2013
+ border: `1px solid ${c.border}`,
2014
+ borderRadius: 10,
2015
+ padding: "12px 16px",
2016
+ fontSize: 12,
2017
+ fontFamily: "ui-monospace, monospace",
2018
+ zIndex: 99999,
2019
+ boxShadow: `0 8px 30px rgba(0,0,0,${isDark ? 0.5 : 0.15})`,
2020
+ maxWidth: 320,
2021
+ pointerEvents: "none"
2022
+ },
2023
+ children: [
2024
+ /* @__PURE__ */ jsxs(
2025
+ "div",
2026
+ {
2027
+ style: {
2028
+ fontWeight: 700,
2029
+ color: c.accent,
2030
+ marginBottom: 4,
2031
+ fontSize: 14
2032
+ },
2033
+ children: [
2034
+ "<",
2035
+ hoveredSource.componentName,
2036
+ " />"
2037
+ ]
2038
+ }
2039
+ ),
2040
+ /* @__PURE__ */ jsxs("div", { style: { color: c.muted, fontSize: 11 }, children: [
2041
+ hoveredSource.filePath,
2042
+ ":",
2043
+ hoveredSource.lineNumber
2044
+ ] }),
2045
+ ((_a = hoveredSource.elementContext) == null ? void 0 : _a.textContent) && /* @__PURE__ */ jsxs(
2046
+ "div",
2047
+ {
2048
+ style: {
2049
+ color: c.muted,
2050
+ fontSize: 10,
2051
+ marginTop: 4,
2052
+ fontStyle: "italic"
2053
+ },
2054
+ children: [
2055
+ '"',
2056
+ hoveredSource.elementContext.textContent,
2057
+ '"'
2058
+ ]
2059
+ }
2060
+ )
2061
+ ]
2062
+ }
2063
+ ),
2064
+ /* @__PURE__ */ jsxs(
2065
+ "div",
2066
+ {
2067
+ style: {
2068
+ position: "fixed",
2069
+ bottom: 20,
2070
+ right: 20,
2071
+ background: c.bg,
2072
+ color: c.success,
2073
+ padding: "10px 16px",
2074
+ borderRadius: 20,
2075
+ fontSize: 13,
2076
+ fontWeight: 600,
2077
+ zIndex: 99997,
2078
+ display: "flex",
2079
+ alignItems: "center",
2080
+ gap: 8,
2081
+ border: `1px solid ${c.border}`,
2082
+ boxShadow: `0 4px 20px rgba(0,0,0,${isDark ? 0.4 : 0.1})`
2083
+ },
2084
+ children: [
2085
+ /* @__PURE__ */ jsx(
2086
+ "span",
2087
+ {
2088
+ style: {
2089
+ width: 8,
2090
+ height: 8,
2091
+ borderRadius: "50%",
2092
+ background: c.success
2093
+ }
2094
+ }
2095
+ ),
2096
+ "Select Component"
2097
+ ]
2098
+ }
2099
+ )
2100
+ ]
2101
+ }
2102
+ );
2103
+ }
7
2104
  export {
8
- A as AIEditorProvider,
9
- C as ChatPanel,
10
- a as ControlPill,
11
- j as extractComponentName,
12
- t as extractComponentNameFromStack,
13
- g as fileExists,
14
- l as findTargetElement,
15
- o as getAttributeValue,
16
- m as getJSXMemberName,
17
- x as getOriginalPositionFromDebugStack,
18
- h as handleAIEditorRequest,
19
- d as handleAbsolutePath,
20
- f as handleCommentsRequest,
21
- a2 as handleRead,
22
- c as handleResolve,
23
- b as handleUndo,
24
- e as handleValidateSession,
25
- i as isPathSecure,
26
- n as normalizePath,
27
- q as parseDebugStack,
28
- u as parseDebugStackFrames,
29
- p as parseFile,
30
- r as resolveFilePath,
31
- w as resolveOriginalPosition,
32
- s as scoreElementMatch,
33
- v as validateDevMode,
34
- k as validateGeneratedCode
2105
+ AIEditorProvider,
2106
+ ChatPanel,
2107
+ ControlPill,
2108
+ buildServiceUrl,
2109
+ getServiceUrl
35
2110
  };
36
2111
  //# sourceMappingURL=index.js.map