next-ai-editor 0.2.6 → 1.0.1

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