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
@@ -1,1512 +0,0 @@
1
- "use strict";
2
- const server = require("next/server");
3
- const fs = require("fs/promises");
4
- const path = require("path");
5
- const sourceMap = require("@jridgewell/source-map");
6
- const pathUtils = require("./path-utils-DYzEWUGy.cjs");
7
- const parser = require("@babel/parser");
8
- const traverse = require("@babel/traverse");
9
- const t = require("@babel/types");
10
- const crypto = require("crypto");
11
- const claudeAgentSdk = require("@anthropic-ai/claude-agent-sdk");
12
- const fs$1 = require("fs");
13
- function _interopNamespaceDefault(e) {
14
- const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
15
- if (e) {
16
- for (const k in e) {
17
- if (k !== "default") {
18
- const d = Object.getOwnPropertyDescriptor(e, k);
19
- Object.defineProperty(n, k, d.get ? d : {
20
- enumerable: true,
21
- get: () => e[k]
22
- });
23
- }
24
- }
25
- }
26
- n.default = e;
27
- return Object.freeze(n);
28
- }
29
- const parser__namespace = /* @__PURE__ */ _interopNamespaceDefault(parser);
30
- const t__namespace = /* @__PURE__ */ _interopNamespaceDefault(t);
31
- function validateDevMode() {
32
- if (process.env.NODE_ENV !== "development") {
33
- return server.NextResponse.json(
34
- { success: false, error: "Development mode only" },
35
- { status: 403 }
36
- );
37
- }
38
- return null;
39
- }
40
- function normalizePath(filePath) {
41
- return filePath.replace(/^webpack-internal:\/\/\/\([^)]+\)\/\.?/, "").replace(/^webpack:\/\/[^/]*\//, "").replace(/^\.\//, "").replace(/\?.*$/, "");
42
- }
43
- async function resolveFilePath(projectRoot, normalizedPath) {
44
- const candidates = [
45
- path.resolve(projectRoot, normalizedPath),
46
- path.resolve(projectRoot, "src", normalizedPath),
47
- path.resolve(projectRoot, "app", normalizedPath)
48
- ];
49
- for (const candidate of candidates) {
50
- if (!candidate.startsWith(projectRoot)) continue;
51
- try {
52
- await fs.access(candidate);
53
- return candidate;
54
- } catch {
55
- }
56
- }
57
- return null;
58
- }
59
- function isPathSecure(absolutePath, projectRoot) {
60
- return absolutePath.startsWith(projectRoot);
61
- }
62
- async function fileExists$1(filePath) {
63
- try {
64
- await fs.access(filePath);
65
- return true;
66
- } catch {
67
- return false;
68
- }
69
- }
70
- function parseDebugStack(stack) {
71
- if (!stack) return null;
72
- const stackStr = typeof stack === "string" ? stack : stack.stack || String(stack);
73
- const frames = stackStr.split("\n");
74
- const skipPatterns = [
75
- "node_modules",
76
- "SegmentViewNode",
77
- "LayoutRouter",
78
- "ErrorBoundary",
79
- "fakeJSXCallSite"
80
- ];
81
- for (const frame of frames) {
82
- if (skipPatterns.some((p) => frame.includes(p))) continue;
83
- const match = frame.match(/at\s+(\w+)\s+\((.+?):(\d+):(\d+)\)?$/);
84
- if (match) {
85
- let filePath = match[2];
86
- const line = parseInt(match[3], 10);
87
- const column = parseInt(match[4], 10);
88
- let chunkId;
89
- const chunkMatch = filePath.match(/\?([^:]+)$/);
90
- if (chunkMatch) {
91
- chunkId = chunkMatch[1];
92
- filePath = filePath.replace(/\?[^:]*$/, "");
93
- }
94
- filePath = pathUtils.cleanPath(filePath);
95
- if (!pathUtils.shouldSkipPath(filePath)) {
96
- console.log("parseDebugStack extracted:", { filePath, line, column });
97
- return { filePath, line, column, chunkId };
98
- }
99
- }
100
- }
101
- console.log(
102
- "parseDebugStack: no valid frame found in stack:",
103
- stackStr.substring(0, 200)
104
- );
105
- return null;
106
- }
107
- function extractComponentNameFromStack(stack) {
108
- if (!stack) return null;
109
- const stackStr = typeof stack === "string" ? stack : stack.stack || String(stack);
110
- const frames = stackStr.split("\n");
111
- const skipPatterns = [
112
- "node_modules",
113
- "SegmentViewNode",
114
- "LayoutRouter",
115
- "ErrorBoundary",
116
- "fakeJSXCallSite",
117
- "react_stack_bottom_frame"
118
- ];
119
- for (const frame of frames) {
120
- if (skipPatterns.some((p) => frame.includes(p))) continue;
121
- const match = frame.match(/at\s+(\w+)\s+\(/);
122
- if (match && match[1]) {
123
- const componentName = match[1];
124
- if (componentName !== "Object" && componentName !== "anonymous") {
125
- return componentName;
126
- }
127
- }
128
- }
129
- return null;
130
- }
131
- function parseDebugStackFrames(stack) {
132
- if (!stack) return [];
133
- const stackStr = typeof stack === "string" ? stack : stack.stack || String(stack);
134
- const frames = stackStr.split("\n");
135
- const skipPatterns = [
136
- "node_modules",
137
- "SegmentViewNode",
138
- "LayoutRouter",
139
- "ErrorBoundary",
140
- "fakeJSXCallSite",
141
- "react_stack_bottom_frame"
142
- ];
143
- const positions = [];
144
- for (const frame of frames) {
145
- if (skipPatterns.some((p) => frame.includes(p))) continue;
146
- const match = frame.match(/at\s+(\w+)\s+\((.+?):(\d+):(\d+)\)?$/);
147
- if (match) {
148
- match[1];
149
- let filePath = match[2];
150
- const line = parseInt(match[3], 10);
151
- const column = parseInt(match[4], 10);
152
- let chunkId;
153
- const chunkMatch = filePath.match(/\?([^:]+)$/);
154
- if (chunkMatch) {
155
- chunkId = chunkMatch[1];
156
- filePath = filePath.replace(/\?[^:]*$/, "");
157
- }
158
- filePath = pathUtils.cleanPath(filePath);
159
- if (!pathUtils.shouldSkipPath(filePath)) {
160
- positions.push({ filePath, line, column, chunkId });
161
- if (positions.length >= 2) break;
162
- }
163
- }
164
- }
165
- console.log(`parseDebugStackFrames extracted ${positions.length} frames:`, positions);
166
- return positions;
167
- }
168
- async function resolveOriginalPosition(compiledPos, projectRoot) {
169
- try {
170
- console.log("resolveOriginalPosition called with:", compiledPos);
171
- let compiledFilePath = compiledPos.filePath;
172
- compiledFilePath = pathUtils.cleanPath(compiledFilePath);
173
- console.log("After cleanPath:", compiledFilePath);
174
- if (compiledFilePath.startsWith("http://") || compiledFilePath.startsWith("https://")) {
175
- const url = new URL(compiledFilePath);
176
- const pathname = url.pathname;
177
- if (pathname.startsWith("/_next/")) {
178
- const relativePath = pathname.substring("/_next/".length);
179
- compiledFilePath = path.join(projectRoot, ".next", "dev", relativePath);
180
- } else {
181
- console.warn("Unexpected HTTP URL path:", pathname);
182
- return null;
183
- }
184
- } else if (!path.isAbsolute(compiledFilePath)) {
185
- if (compiledFilePath.startsWith(".next/")) {
186
- compiledFilePath = path.resolve(projectRoot, compiledFilePath);
187
- } else {
188
- const resolved = path.resolve(projectRoot, compiledFilePath);
189
- if (await fileExists(resolved)) {
190
- compiledFilePath = resolved;
191
- } else {
192
- const possiblePaths = [
193
- path.join(projectRoot, ".next", "dev", compiledFilePath),
194
- path.join(projectRoot, compiledFilePath)
195
- ];
196
- for (const tryPath of possiblePaths) {
197
- if (await fileExists(tryPath)) {
198
- compiledFilePath = tryPath;
199
- break;
200
- }
201
- }
202
- }
203
- }
204
- } else {
205
- compiledFilePath = path.normalize(compiledFilePath);
206
- }
207
- console.log("Normalized compiled file path:", compiledFilePath);
208
- const compiledExists = await fileExists(compiledFilePath);
209
- console.log(
210
- "Compiled file exists:",
211
- compiledExists,
212
- "at:",
213
- compiledFilePath
214
- );
215
- if (!compiledExists) {
216
- console.error(
217
- `Compiled file not found: ${compiledFilePath} (from parsed: ${compiledPos.filePath})`
218
- );
219
- }
220
- const sourceMapPath = compiledFilePath + ".map";
221
- console.log("Looking for source map at:", sourceMapPath);
222
- const sourceMapExists = await fileExists(sourceMapPath);
223
- console.log("Source map exists:", sourceMapExists);
224
- if (!sourceMapExists) {
225
- console.error(
226
- `Source map not found: ${sourceMapPath} (from compiled: ${compiledPos.filePath}, normalized: ${compiledFilePath})`
227
- );
228
- const altPaths = [
229
- compiledFilePath.replace(/\.js$/, ".map"),
230
- path.join(
231
- path.dirname(compiledFilePath),
232
- path.basename(compiledFilePath) + ".map"
233
- )
234
- ];
235
- console.log("Trying alternative paths:", altPaths);
236
- for (const altPath of altPaths) {
237
- if (await fileExists(altPath)) {
238
- console.log("Found source map at alternative path:", altPath);
239
- return await resolveFromSourceMap(altPath, compiledPos, projectRoot);
240
- }
241
- }
242
- return null;
243
- }
244
- return await resolveFromSourceMap(sourceMapPath, compiledPos, projectRoot);
245
- } catch (error) {
246
- console.error("Error resolving source map:", error);
247
- return null;
248
- }
249
- }
250
- async function resolveFromSourceMap(sourceMapPath, compiledPos, projectRoot) {
251
- try {
252
- const sourceMapContent = await fs.readFile(sourceMapPath, "utf-8");
253
- const sourceMap$1 = JSON.parse(sourceMapContent);
254
- if ((!sourceMap$1.sources || sourceMap$1.sources.length === 0) && (!sourceMap$1.sections || sourceMap$1.sections.length === 0)) {
255
- console.warn(
256
- "Empty source map detected, cannot resolve position:",
257
- sourceMapPath
258
- );
259
- return null;
260
- }
261
- if (sourceMap$1.sections) {
262
- let matchingSection = null;
263
- for (let i = sourceMap$1.sections.length - 1; i >= 0; i--) {
264
- const section = sourceMap$1.sections[i];
265
- const offset = section.offset;
266
- const sectionStartLine1Indexed = offset.line + 1;
267
- if (compiledPos.line > sectionStartLine1Indexed || compiledPos.line === sectionStartLine1Indexed && compiledPos.column >= offset.column) {
268
- matchingSection = section;
269
- break;
270
- }
271
- }
272
- if (matchingSection && matchingSection.map) {
273
- const sectionMap = matchingSection.map;
274
- const offset = matchingSection.offset;
275
- let consumer2;
276
- try {
277
- consumer2 = await new sourceMap.SourceMapConsumer(sectionMap);
278
- } catch (error) {
279
- console.error("Error creating SourceMapConsumer:", error);
280
- return null;
281
- }
282
- try {
283
- const adjustedLine = compiledPos.line - offset.line;
284
- const adjustedColumn = compiledPos.line === offset.line + 1 ? compiledPos.column - offset.column : compiledPos.column;
285
- const originalPos = consumer2.originalPositionFor({
286
- line: adjustedLine,
287
- column: adjustedColumn
288
- });
289
- if (originalPos.source && originalPos.line !== null) {
290
- const source = pathUtils.normalizeSourcePath(
291
- originalPos.source || "",
292
- projectRoot
293
- );
294
- return {
295
- source,
296
- line: originalPos.line,
297
- column: originalPos.column ?? 0
298
- };
299
- }
300
- } finally {
301
- consumer2.destroy();
302
- }
303
- }
304
- return null;
305
- }
306
- const consumer = await new sourceMap.SourceMapConsumer(sourceMap$1);
307
- try {
308
- const originalPos = consumer.originalPositionFor({
309
- line: compiledPos.line,
310
- column: compiledPos.column
311
- });
312
- if (originalPos.source && originalPos.line !== null) {
313
- const source = pathUtils.normalizeSourcePath(
314
- originalPos.source || "",
315
- projectRoot
316
- );
317
- return {
318
- source,
319
- line: originalPos.line,
320
- column: originalPos.column ?? 0
321
- };
322
- }
323
- } finally {
324
- consumer.destroy();
325
- }
326
- return null;
327
- } catch (error) {
328
- console.error("Error resolving source map:", error);
329
- return null;
330
- }
331
- }
332
- async function fileExists(filePath) {
333
- try {
334
- await fs.access(filePath);
335
- return true;
336
- } catch {
337
- return false;
338
- }
339
- }
340
- async function getOriginalPositionFromDebugStack(debugStack, projectRoot) {
341
- const compiledPos = parseDebugStack(debugStack);
342
- if (!compiledPos) return null;
343
- return await resolveOriginalPosition(compiledPos, projectRoot);
344
- }
345
- function parseFile(content) {
346
- try {
347
- return parser__namespace.parse(content, {
348
- sourceType: "module",
349
- plugins: [
350
- "jsx",
351
- "typescript",
352
- "decorators-legacy",
353
- "classProperties",
354
- "optionalChaining",
355
- "nullishCoalescingOperator"
356
- ]
357
- });
358
- } catch (e) {
359
- console.error("Parse error:", e);
360
- return null;
361
- }
362
- }
363
- function extractComponentName(ast) {
364
- let componentName = null;
365
- traverse(ast, {
366
- ExportDefaultDeclaration(path2) {
367
- var _a;
368
- if (t__namespace.isFunctionDeclaration(path2.node.declaration)) {
369
- componentName = ((_a = path2.node.declaration.id) == null ? void 0 : _a.name) || null;
370
- } else if (t__namespace.isArrowFunctionExpression(path2.node.declaration)) {
371
- componentName = "default";
372
- } else if (t__namespace.isIdentifier(path2.node.declaration)) {
373
- componentName = path2.node.declaration.name;
374
- }
375
- },
376
- ExportNamedDeclaration(path2) {
377
- var _a;
378
- if (t__namespace.isFunctionDeclaration(path2.node.declaration)) {
379
- componentName = ((_a = path2.node.declaration.id) == null ? void 0 : _a.name) || null;
380
- } else if (t__namespace.isVariableDeclaration(path2.node.declaration)) {
381
- const declarator = path2.node.declaration.declarations[0];
382
- if (t__namespace.isIdentifier(declarator.id)) {
383
- componentName = declarator.id.name;
384
- }
385
- } else if (path2.node.specifiers && path2.node.specifiers.length > 0) {
386
- const specifier = path2.node.specifiers[0];
387
- if (t__namespace.isExportSpecifier(specifier) && t__namespace.isIdentifier(specifier.exported)) {
388
- componentName = specifier.exported.name;
389
- }
390
- }
391
- }
392
- });
393
- return componentName;
394
- }
395
- function validateGeneratedCode(newCode, originalCode, fileContent) {
396
- try {
397
- const isFullComponent = /^(export\s+)?(default\s+)?function\s+\w+/.test(newCode.trim()) || /^(export\s+)?(default\s+)?const\s+\w+\s*=/.test(newCode.trim());
398
- if (isFullComponent) {
399
- let codeToValidate = newCode;
400
- if (fileContent) {
401
- const interfaceMatches = fileContent.match(
402
- /^(interface|type)\s+\w+[^}]*\}/gm
403
- );
404
- if (interfaceMatches) {
405
- codeToValidate = interfaceMatches.join("\n\n") + "\n\n" + newCode;
406
- }
407
- }
408
- parser__namespace.parse(codeToValidate, {
409
- sourceType: "module",
410
- plugins: ["jsx", "typescript"]
411
- });
412
- } else {
413
- const wrapped = `function _() { return (${newCode}); }`;
414
- parser__namespace.parse(wrapped, {
415
- sourceType: "module",
416
- plugins: ["jsx", "typescript"]
417
- });
418
- }
419
- } catch (e) {
420
- console.error("Generated code parse error:", e);
421
- return false;
422
- }
423
- const origBraces = (originalCode.match(/[{}]/g) || []).length;
424
- const newBraces = (newCode.match(/[{}]/g) || []).length;
425
- const origTags = (originalCode.match(/[<>]/g) || []).length;
426
- const newTags = (newCode.match(/[<>]/g) || []).length;
427
- if (Math.abs(origBraces - newBraces) > 4 || Math.abs(origTags - newTags) > 4) {
428
- console.warn(
429
- `Structure changed significantly: braces ${origBraces}->${newBraces}, tags ${origTags}->${newTags}`
430
- );
431
- }
432
- return true;
433
- }
434
- function findTargetElement(ast, fileContent, options) {
435
- const { componentName, lineNumber, elementContext } = options;
436
- let componentNode = null;
437
- let componentStart = 0;
438
- let componentEnd = Infinity;
439
- let fallbackExportDefault = null;
440
- traverse(ast, {
441
- FunctionDeclaration(path2) {
442
- var _a, _b, _c;
443
- if (((_a = path2.node.id) == null ? void 0 : _a.name) === componentName) {
444
- componentNode = path2.node;
445
- componentStart = ((_b = path2.node.loc) == null ? void 0 : _b.start.line) || 0;
446
- componentEnd = ((_c = path2.node.loc) == null ? void 0 : _c.end.line) || Infinity;
447
- }
448
- },
449
- VariableDeclarator(path2) {
450
- var _a, _b;
451
- if (t__namespace.isIdentifier(path2.node.id) && path2.node.id.name === componentName) {
452
- componentNode = path2.node;
453
- const parent = path2.parentPath.parent;
454
- componentStart = ((_a = parent == null ? void 0 : parent.loc) == null ? void 0 : _a.start.line) || 0;
455
- componentEnd = ((_b = parent == null ? void 0 : parent.loc) == null ? void 0 : _b.end.line) || Infinity;
456
- }
457
- },
458
- ExportDefaultDeclaration(path2) {
459
- var _a, _b, _c, _d, _e;
460
- if (t__namespace.isFunctionDeclaration(path2.node.declaration)) {
461
- const funcName = (_a = path2.node.declaration.id) == null ? void 0 : _a.name;
462
- if (funcName === componentName || !funcName) {
463
- componentNode = path2.node;
464
- componentStart = ((_b = path2.node.loc) == null ? void 0 : _b.start.line) || 0;
465
- componentEnd = ((_c = path2.node.loc) == null ? void 0 : _c.end.line) || Infinity;
466
- } else if (!componentNode) {
467
- fallbackExportDefault = {
468
- node: path2.node,
469
- start: ((_d = path2.node.loc) == null ? void 0 : _d.start.line) || 0,
470
- end: ((_e = path2.node.loc) == null ? void 0 : _e.end.line) || Infinity
471
- };
472
- }
473
- }
474
- }
475
- });
476
- if (!componentNode && fallbackExportDefault !== null) {
477
- const fallback = fallbackExportDefault;
478
- console.log(
479
- `⚠️ Component "${componentName}" not found, using export default function as fallback`
480
- );
481
- componentNode = fallback.node;
482
- componentStart = fallback.start;
483
- componentEnd = fallback.end;
484
- }
485
- const allElementsByTag = /* @__PURE__ */ new Map();
486
- const elementsAtLine = [];
487
- traverse(ast, {
488
- JSXElement(path2) {
489
- const loc = path2.node.loc;
490
- if (!loc) return;
491
- const startLine = loc.start.line;
492
- const endLine = loc.end.line;
493
- if (startLine < componentStart || endLine > componentEnd) return;
494
- const opening = path2.node.openingElement;
495
- if (t__namespace.isJSXIdentifier(opening.name)) {
496
- const tagName = opening.name.name;
497
- if (!allElementsByTag.has(tagName)) {
498
- allElementsByTag.set(tagName, []);
499
- }
500
- allElementsByTag.get(tagName).push({ node: path2.node, startLine, endLine, score: 0 });
501
- }
502
- if (startLine === lineNumber) {
503
- elementsAtLine.push({ node: path2.node, startLine, endLine, score: 0 });
504
- }
505
- }
506
- });
507
- if (elementsAtLine.length > 0) {
508
- if (elementsAtLine.length === 1) {
509
- const target = elementsAtLine[0];
510
- return {
511
- startLine: target.startLine,
512
- endLine: target.endLine,
513
- componentStart,
514
- componentEnd
515
- };
516
- }
517
- if (elementContext) {
518
- for (const elem of elementsAtLine) {
519
- if (t__namespace.isJSXElement(elem.node)) {
520
- const score = scoreElementMatch(elem.node, elementContext, fileContent);
521
- elem.score = score;
522
- }
523
- }
524
- elementsAtLine.sort((a, b) => b.score - a.score);
525
- if (elementsAtLine[0].score > 0) {
526
- return {
527
- startLine: elementsAtLine[0].startLine,
528
- endLine: elementsAtLine[0].endLine,
529
- componentStart,
530
- componentEnd
531
- };
532
- }
533
- }
534
- return {
535
- startLine: elementsAtLine[0].startLine,
536
- endLine: elementsAtLine[0].endLine,
537
- componentStart,
538
- componentEnd
539
- };
540
- }
541
- if (elementContext == null ? void 0 : elementContext.tagName) {
542
- const allOfTag = allElementsByTag.get(elementContext.tagName);
543
- if (allOfTag && allOfTag.length > 0) {
544
- if (elementContext.textContent || elementContext.className) {
545
- for (const elem of allOfTag) {
546
- if (t__namespace.isJSXElement(elem.node)) {
547
- elem.score = scoreElementMatch(elem.node, elementContext, fileContent);
548
- }
549
- }
550
- allOfTag.sort((a, b) => b.score - a.score);
551
- if (allOfTag[0].score > 50) {
552
- return {
553
- startLine: allOfTag[0].startLine,
554
- endLine: allOfTag[0].endLine,
555
- componentStart,
556
- componentEnd
557
- };
558
- }
559
- }
560
- if (elementContext.nthOfType && allOfTag.length >= elementContext.nthOfType) {
561
- const target = allOfTag[elementContext.nthOfType - 1];
562
- return {
563
- startLine: target.startLine,
564
- endLine: target.endLine,
565
- componentStart,
566
- componentEnd
567
- };
568
- }
569
- }
570
- }
571
- const nearbyElements = [];
572
- traverse(ast, {
573
- JSXElement(path2) {
574
- const loc = path2.node.loc;
575
- if (!loc) return;
576
- const startLine = loc.start.line;
577
- const endLine = loc.end.line;
578
- if (startLine < componentStart || endLine > componentEnd) return;
579
- if (Math.abs(startLine - lineNumber) <= 5) {
580
- const score = elementContext ? scoreElementMatch(path2.node, elementContext, fileContent) : 100 - Math.abs(startLine - lineNumber);
581
- nearbyElements.push({ node: path2.node, startLine, endLine, score });
582
- }
583
- }
584
- });
585
- if (nearbyElements.length > 0) {
586
- nearbyElements.sort((a, b) => b.score - a.score);
587
- return {
588
- startLine: nearbyElements[0].startLine,
589
- endLine: nearbyElements[0].endLine,
590
- componentStart,
591
- componentEnd
592
- };
593
- }
594
- if (componentNode && componentStart > 0) {
595
- return {
596
- startLine: componentStart,
597
- endLine: componentEnd,
598
- componentStart,
599
- componentEnd
600
- };
601
- }
602
- return null;
603
- }
604
- function scoreElementMatch(node, context, fileContent) {
605
- let score = 0;
606
- const opening = node.openingElement;
607
- if (t__namespace.isJSXIdentifier(opening.name)) {
608
- if (opening.name.name === context.tagName) {
609
- score += 50;
610
- } else {
611
- return 0;
612
- }
613
- } else if (t__namespace.isJSXMemberExpression(opening.name)) {
614
- const fullName = getJSXMemberName(opening.name);
615
- if (fullName === context.tagName || fullName.endsWith(`.${context.tagName}`)) {
616
- score += 50;
617
- } else {
618
- return 0;
619
- }
620
- }
621
- if (context.className) {
622
- const classAttr = opening.attributes.find(
623
- (attr) => t__namespace.isJSXAttribute(attr) && t__namespace.isJSXIdentifier(attr.name) && attr.name.name === "className"
624
- );
625
- if (classAttr && t__namespace.isJSXAttribute(classAttr)) {
626
- const classValue = getAttributeValue(classAttr);
627
- if (classValue && context.className.split(/\s+/).some((c) => classValue.includes(c))) {
628
- score += 20;
629
- }
630
- }
631
- }
632
- if (context.textContent && node.loc) {
633
- const elementCode = fileContent.split("\n").slice(node.loc.start.line - 1, node.loc.end.line).join("\n");
634
- const normalizedContent = context.textContent.toLowerCase().trim();
635
- const normalizedElement = elementCode.toLowerCase();
636
- if (normalizedElement.includes(normalizedContent)) {
637
- score += 30;
638
- }
639
- }
640
- if (context.props) {
641
- for (const [key, value] of Object.entries(context.props)) {
642
- if (key.startsWith("_")) continue;
643
- const attr = opening.attributes.find(
644
- (a) => t__namespace.isJSXAttribute(a) && t__namespace.isJSXIdentifier(a.name) && a.name.name === key
645
- );
646
- if (attr) {
647
- score += 5;
648
- if (typeof value === "string" && t__namespace.isJSXAttribute(attr)) {
649
- const attrValue = getAttributeValue(attr);
650
- if (attrValue === value) score += 10;
651
- }
652
- }
653
- }
654
- }
655
- return score;
656
- }
657
- function getJSXMemberName(node) {
658
- if (t__namespace.isJSXIdentifier(node.object)) {
659
- return `${node.object.name}.${node.property.name}`;
660
- }
661
- if (t__namespace.isJSXMemberExpression(node.object)) {
662
- return `${getJSXMemberName(node.object)}.${node.property.name}`;
663
- }
664
- return node.property.name;
665
- }
666
- function getAttributeValue(attr) {
667
- if (!attr.value) return null;
668
- if (t__namespace.isStringLiteral(attr.value)) return attr.value.value;
669
- if (t__namespace.isJSXExpressionContainer(attr.value) && t__namespace.isStringLiteral(attr.value.expression)) {
670
- return attr.value.expression.value;
671
- }
672
- return null;
673
- }
674
- async function handleRead(req) {
675
- const devModeError = validateDevMode();
676
- if (devModeError) return devModeError;
677
- const { searchParams } = new URL(req.url);
678
- let filePath = searchParams.get("path") || "";
679
- let lineNumber = parseInt(searchParams.get("line") || "1");
680
- const debugStack = searchParams.get("debugStack") || "";
681
- const tagName = searchParams.get("tagName") || "";
682
- const nthOfType = parseInt(searchParams.get("nthOfType") || "0");
683
- const textContent = searchParams.get("textContent") || "";
684
- const className = searchParams.get("className") || "";
685
- const elementContext = tagName ? {
686
- tagName,
687
- nthOfType: nthOfType > 0 ? nthOfType : void 0,
688
- textContent: textContent || void 0,
689
- className: className || void 0
690
- } : void 0;
691
- const parentFilePath = searchParams.get("parentFilePath") || "";
692
- const parentLine = parseInt(searchParams.get("parentLine") || "0");
693
- const parentComponentName = searchParams.get("parentComponentName") || "";
694
- const parentDebugStack = searchParams.get("parentDebugStack") || "";
695
- const childKey = searchParams.get("childKey") || "";
696
- const projectRoot = process.cwd();
697
- if (debugStack) {
698
- const compiledPos = parseDebugStack(debugStack);
699
- if (compiledPos) {
700
- const originalPos = await resolveOriginalPosition(
701
- compiledPos,
702
- projectRoot
703
- );
704
- if (originalPos) {
705
- filePath = originalPos.source;
706
- lineNumber = originalPos.line;
707
- }
708
- }
709
- }
710
- const normalizedPath = normalizePath(filePath);
711
- const absolutePath = await resolveFilePath(projectRoot, normalizedPath);
712
- if (!absolutePath) {
713
- return server.NextResponse.json(
714
- { success: false, error: "File not found" },
715
- { status: 404 }
716
- );
717
- }
718
- const content = await fs.readFile(absolutePath, "utf-8");
719
- const ast = parseFile(content);
720
- if (!ast) {
721
- return server.NextResponse.json(
722
- { success: false, error: "Failed to parse file" },
723
- { status: 400 }
724
- );
725
- }
726
- const componentName = extractComponentName(ast);
727
- if (!componentName) {
728
- return server.NextResponse.json({
729
- success: true,
730
- content,
731
- lineStart: 1,
732
- lineEnd: content.split("\n").length
733
- });
734
- }
735
- const target = findTargetElement(ast, content, {
736
- componentName,
737
- lineNumber,
738
- elementContext
739
- });
740
- if (!target) {
741
- return server.NextResponse.json({
742
- success: true,
743
- content,
744
- lineStart: 1,
745
- lineEnd: content.split("\n").length
746
- });
747
- }
748
- const lines = content.split("\n");
749
- const componentLines = lines.slice(
750
- target.componentStart - 1,
751
- target.componentEnd
752
- );
753
- const preview = componentLines.join("\n");
754
- let parentInstance = null;
755
- if (parentDebugStack) {
756
- try {
757
- let resolvedParentPath = parentFilePath;
758
- let resolvedParentLine = parentLine;
759
- let resolvedParentComponentName = parentComponentName;
760
- if (!resolvedParentComponentName && parentDebugStack) {
761
- resolvedParentComponentName = extractComponentNameFromStack(parentDebugStack) || "";
762
- }
763
- if (parentDebugStack) {
764
- const compiledPos = parseDebugStack(parentDebugStack);
765
- if (compiledPos) {
766
- const originalPos = await resolveOriginalPosition(
767
- compiledPos,
768
- projectRoot
769
- );
770
- if (originalPos) {
771
- resolvedParentPath = originalPos.source;
772
- resolvedParentLine = originalPos.line;
773
- }
774
- }
775
- }
776
- const normalizedParentPath = normalizePath(resolvedParentPath);
777
- const absoluteParentPath = await resolveFilePath(
778
- projectRoot,
779
- normalizedParentPath
780
- );
781
- if (absoluteParentPath && resolvedParentComponentName) {
782
- const parentContent = await fs.readFile(absoluteParentPath, "utf-8");
783
- const parentAst = parseFile(parentContent);
784
- if (parentAst) {
785
- let nthOfType2 = void 0;
786
- if (childKey) {
787
- const keyAsNumber = parseInt(childKey, 10);
788
- if (!isNaN(keyAsNumber)) {
789
- nthOfType2 = keyAsNumber + 1;
790
- }
791
- }
792
- const parentTarget = findTargetElement(parentAst, parentContent, {
793
- componentName: resolvedParentComponentName,
794
- lineNumber: 0,
795
- // Don't use line number - rely on element context to find correct instance
796
- elementContext: {
797
- tagName: componentName,
798
- // Search for child component usage
799
- nthOfType: nthOfType2,
800
- // Find specific instance if key is numeric
801
- textContent: textContent || void 0
802
- // Use text content to match the specific instance
803
- }
804
- });
805
- if (parentTarget) {
806
- const parentLines = parentContent.split("\n");
807
- const parentComponentLines = parentLines.slice(
808
- parentTarget.componentStart - 1,
809
- parentTarget.componentEnd
810
- );
811
- parentInstance = {
812
- filePath: resolvedParentPath,
813
- content: parentComponentLines.join("\n"),
814
- lineStart: parentTarget.componentStart,
815
- lineEnd: parentTarget.componentEnd,
816
- usageLineStart: parentTarget.startLine,
817
- usageLineEnd: parentTarget.endLine,
818
- componentName: resolvedParentComponentName
819
- };
820
- }
821
- }
822
- }
823
- } catch (error) {
824
- console.error("Error resolving parent instance:", error);
825
- }
826
- }
827
- return server.NextResponse.json({
828
- success: true,
829
- content: preview,
830
- lineStart: target.componentStart,
831
- lineEnd: target.componentEnd,
832
- targetStartLine: target.startLine,
833
- targetEndLine: target.endLine,
834
- componentName,
835
- // Return the actual component name parsed from code
836
- parentInstance
837
- // Optional: where this component is used
838
- });
839
- }
840
- async function handleUndo(req) {
841
- const devModeError = validateDevMode();
842
- if (devModeError) return devModeError;
843
- try {
844
- const body = await req.json();
845
- const { filePath, content } = body;
846
- if (!filePath || typeof content !== "string") {
847
- return server.NextResponse.json(
848
- {
849
- success: false,
850
- error: "Invalid request: filePath and content required"
851
- },
852
- { status: 400 }
853
- );
854
- }
855
- const projectRoot = process.cwd();
856
- const normalizedPath = normalizePath(filePath);
857
- const absolutePath = await resolveFilePath(projectRoot, normalizedPath);
858
- if (!absolutePath) {
859
- return server.NextResponse.json(
860
- { success: false, error: `File not found: ${normalizedPath}` },
861
- { status: 404 }
862
- );
863
- }
864
- if (!isPathSecure(absolutePath, projectRoot)) {
865
- return server.NextResponse.json(
866
- { success: false, error: "Access denied: File outside project root" },
867
- { status: 403 }
868
- );
869
- }
870
- await fs.writeFile(absolutePath, content, "utf-8");
871
- console.log(`✅ Undo: Restored ${normalizedPath}`);
872
- return server.NextResponse.json({ success: true });
873
- } catch (error) {
874
- console.error("Undo error:", error);
875
- return server.NextResponse.json(
876
- { success: false, error: String(error) },
877
- { status: 500 }
878
- );
879
- }
880
- }
881
- async function handleResolve(req) {
882
- const devModeError = validateDevMode();
883
- if (devModeError) return devModeError;
884
- try {
885
- const body = await req.json();
886
- const debugStack = body == null ? void 0 : body.debugStack;
887
- if (!debugStack || typeof debugStack !== "string") {
888
- return server.NextResponse.json(
889
- { success: false, error: "Missing debugStack" },
890
- { status: 400 }
891
- );
892
- }
893
- const compiledFrames = parseDebugStackFrames(debugStack);
894
- if (compiledFrames.length === 0) {
895
- const compiledPos = parseDebugStack(debugStack);
896
- if (!compiledPos) {
897
- console.error("Could not parse debug stack:", debugStack);
898
- return server.NextResponse.json(
899
- { success: false, error: "Could not parse stack" },
900
- { status: 422 }
901
- );
902
- }
903
- const originalPos = await resolveOriginalPosition(
904
- compiledPos,
905
- process.cwd()
906
- );
907
- if (!originalPos) {
908
- return server.NextResponse.json(
909
- { success: false, error: "Source map lookup failed" },
910
- { status: 404 }
911
- );
912
- }
913
- return server.NextResponse.json({
914
- success: true,
915
- filePath: originalPos.source,
916
- lineNumber: originalPos.line,
917
- columnNumber: originalPos.column ?? 0
918
- });
919
- }
920
- const resolvedFrames = [];
921
- for (const frame of compiledFrames) {
922
- const originalPos = await resolveOriginalPosition(frame, process.cwd());
923
- if (originalPos) {
924
- resolvedFrames.push({
925
- filePath: originalPos.source,
926
- lineNumber: originalPos.line,
927
- columnNumber: originalPos.column ?? 0
928
- });
929
- }
930
- }
931
- if (resolvedFrames.length === 0) {
932
- return server.NextResponse.json(
933
- { success: false, error: "Source map lookup failed for all frames" },
934
- { status: 404 }
935
- );
936
- }
937
- console.log("Resolved frames:", resolvedFrames);
938
- return server.NextResponse.json({
939
- success: true,
940
- filePath: resolvedFrames[0].filePath,
941
- lineNumber: resolvedFrames[0].lineNumber,
942
- columnNumber: resolvedFrames[0].columnNumber,
943
- frames: resolvedFrames
944
- // [componentDefinition, parentInstance]
945
- });
946
- } catch (error) {
947
- console.error("Source resolve error:", error);
948
- return server.NextResponse.json(
949
- { success: false, error: "Internal error" },
950
- { status: 500 }
951
- );
952
- }
953
- }
954
- async function handleAbsolutePath(req) {
955
- const devModeError = validateDevMode();
956
- if (devModeError) return devModeError;
957
- const { searchParams } = new URL(req.url);
958
- const filePath = searchParams.get("path") || "";
959
- if (!filePath) {
960
- return server.NextResponse.json(
961
- { success: false, error: "Missing path" },
962
- { status: 400 }
963
- );
964
- }
965
- const projectRoot = process.cwd();
966
- const normalizedPath = normalizePath(filePath);
967
- const absolutePath = await resolveFilePath(projectRoot, normalizedPath);
968
- if (!absolutePath) {
969
- return server.NextResponse.json(
970
- { success: false, error: "File not found" },
971
- { status: 404 }
972
- );
973
- }
974
- return server.NextResponse.json({
975
- success: true,
976
- absolutePath
977
- });
978
- }
979
- async function handleValidateSession(req) {
980
- const devModeError = validateDevMode();
981
- if (devModeError) return devModeError;
982
- try {
983
- const body = await req.json();
984
- const { filePath, lastKnownHash, lastKnownSize } = body;
985
- if (!filePath || !lastKnownHash || lastKnownSize === void 0) {
986
- return server.NextResponse.json(
987
- { success: false, error: "Missing required fields" },
988
- { status: 400 }
989
- );
990
- }
991
- const projectRoot = process.cwd();
992
- const normalizedPath = normalizePath(filePath);
993
- const absolutePath = await resolveFilePath(projectRoot, normalizedPath);
994
- if (!absolutePath) {
995
- return server.NextResponse.json(
996
- { success: false, error: "File not found" },
997
- { status: 404 }
998
- );
999
- }
1000
- if (!isPathSecure(absolutePath, projectRoot)) {
1001
- return server.NextResponse.json(
1002
- { success: false, error: "Access denied" },
1003
- { status: 403 }
1004
- );
1005
- }
1006
- const content = await fs.readFile(absolutePath, "utf-8");
1007
- const hash = crypto.createHash("sha256").update(content).digest("hex");
1008
- const stats = await fs.stat(absolutePath);
1009
- const isValid = hash === lastKnownHash && content.length === lastKnownSize;
1010
- console.log(`[validate-session] ${filePath}:`);
1011
- console.log(` Hash match: ${hash === lastKnownHash}`);
1012
- console.log(` Size match: ${content.length === lastKnownSize}`);
1013
- console.log(` Is valid: ${isValid}`);
1014
- return server.NextResponse.json({
1015
- success: true,
1016
- isValid,
1017
- currentHash: hash,
1018
- currentSize: content.length,
1019
- lastModifiedTime: stats.mtimeMs
1020
- });
1021
- } catch (error) {
1022
- console.error("Validation error:", error);
1023
- return server.NextResponse.json(
1024
- { success: false, error: String(error) },
1025
- { status: 500 }
1026
- );
1027
- }
1028
- }
1029
- class AIEditorAgent {
1030
- constructor(session, projectRoot) {
1031
- this.session = session;
1032
- this.projectRoot = projectRoot;
1033
- }
1034
- /**
1035
- * Create a new agent instance
1036
- */
1037
- static async create(config) {
1038
- const sessionOptions = {
1039
- model: "claude-sonnet-4-5-20250929",
1040
- // Enable auto-apply for edits without permission prompts
1041
- permissionMode: "acceptEdits",
1042
- env: {
1043
- ...process.env,
1044
- ANTHROPIC_API_KEY: config.apiKey,
1045
- // Set working directory
1046
- PWD: config.projectRoot
1047
- },
1048
- // Explicitly allow core development tools
1049
- allowedTools: config.allowedTools || ["Read", "Edit", "Glob", "Grep"],
1050
- disallowedTools: config.disallowedTools || []
1051
- };
1052
- let session;
1053
- if (config.sessionId) {
1054
- session = claudeAgentSdk.unstable_v2_resumeSession(config.sessionId, sessionOptions);
1055
- } else {
1056
- session = claudeAgentSdk.unstable_v2_createSession(sessionOptions);
1057
- }
1058
- return new AIEditorAgent(session, config.projectRoot);
1059
- }
1060
- /**
1061
- * Send a message to the agent and stream responses
1062
- */
1063
- async *sendMessage(message, componentContext) {
1064
- let fullMessage = `<response_style>
1065
- KEEP RESPONSES EXTREMELY BRIEF AND STATUS-LIKE.
1066
- - Use terse status messages: "Reading file.tsx", "Changing color", "Done"
1067
- - NO conversational language (avoid: "I'll", "Let me", "Sure", "Great", "I can see")
1068
- - NO explanations unless explicitly asked
1069
- - State ONLY what you're doing, nothing more
1070
- - Format: Action + target (e.g., "Updating StatsCard.tsx:24")
1071
- </response_style>
1072
-
1073
- `;
1074
- if (componentContext) {
1075
- fullMessage += `[Component: ${componentContext.componentName} at ${componentContext.filePath}:${componentContext.lineNumber}]
1076
-
1077
- `;
1078
- }
1079
- fullMessage += message;
1080
- await this.session.send(fullMessage);
1081
- for await (const event of this.session.stream()) {
1082
- yield event;
1083
- }
1084
- }
1085
- /**
1086
- * Get the session ID
1087
- */
1088
- getSessionId() {
1089
- return this.session.sessionId;
1090
- }
1091
- /**
1092
- * Close the session
1093
- */
1094
- close() {
1095
- this.session.close();
1096
- }
1097
- /**
1098
- * Async disposal support
1099
- */
1100
- async [Symbol.asyncDispose]() {
1101
- await this.session[Symbol.asyncDispose]();
1102
- }
1103
- }
1104
- class AgentSessionStore {
1105
- // 5 minutes
1106
- constructor() {
1107
- this.sessions = /* @__PURE__ */ new Map();
1108
- this.SESSION_TIMEOUT = 1e3 * 60 * 30;
1109
- this.CLEANUP_INTERVAL = 1e3 * 60 * 5;
1110
- this.startCleanupTimer();
1111
- }
1112
- /**
1113
- * Create or resume a session
1114
- */
1115
- async createSession(config) {
1116
- const sessionId = config.sessionId || this.generateSessionId();
1117
- const existing = this.sessions.get(sessionId);
1118
- if (existing) {
1119
- existing.lastActive = Date.now();
1120
- existing.threadId = config.threadId;
1121
- return existing;
1122
- }
1123
- const agent = await AIEditorAgent.create({
1124
- apiKey: config.apiKey,
1125
- projectRoot: config.projectRoot,
1126
- sessionId: config.sessionId,
1127
- allowedTools: config.allowedTools,
1128
- disallowedTools: config.disallowedTools
1129
- });
1130
- const session = {
1131
- sessionId,
1132
- threadId: config.threadId,
1133
- agent,
1134
- createdAt: Date.now(),
1135
- lastActive: Date.now(),
1136
- isLocked: false
1137
- };
1138
- this.sessions.set(sessionId, session);
1139
- return session;
1140
- }
1141
- /**
1142
- * Get a session by ID
1143
- */
1144
- getSession(sessionId) {
1145
- const session = this.sessions.get(sessionId);
1146
- if (session) {
1147
- session.lastActive = Date.now();
1148
- }
1149
- return session;
1150
- }
1151
- /**
1152
- * Acquire a lock on a session to prevent concurrent edits
1153
- * Returns true if lock was acquired, false if already locked
1154
- */
1155
- acquireLock(sessionId) {
1156
- const session = this.sessions.get(sessionId);
1157
- if (!session) {
1158
- throw new Error(`Session ${sessionId} not found`);
1159
- }
1160
- if (session.isLocked) {
1161
- return false;
1162
- }
1163
- session.isLocked = true;
1164
- session.lastActive = Date.now();
1165
- return true;
1166
- }
1167
- /**
1168
- * Release a lock on a session
1169
- */
1170
- releaseLock(sessionId) {
1171
- const session = this.sessions.get(sessionId);
1172
- if (session) {
1173
- session.isLocked = false;
1174
- session.lastActive = Date.now();
1175
- }
1176
- }
1177
- /**
1178
- * Check if any session is currently locked (to prevent concurrent edits)
1179
- */
1180
- hasActiveLock() {
1181
- for (const session of this.sessions.values()) {
1182
- if (session.isLocked) {
1183
- return true;
1184
- }
1185
- }
1186
- return false;
1187
- }
1188
- /**
1189
- * Get all active sessions for a thread
1190
- */
1191
- getSessionsByThread(threadId) {
1192
- const sessions = [];
1193
- for (const session of this.sessions.values()) {
1194
- if (session.threadId === threadId) {
1195
- sessions.push(session);
1196
- }
1197
- }
1198
- return sessions;
1199
- }
1200
- /**
1201
- * Delete a session
1202
- */
1203
- deleteSession(sessionId) {
1204
- const session = this.sessions.get(sessionId);
1205
- if (session) {
1206
- session.agent.close();
1207
- this.sessions.delete(sessionId);
1208
- }
1209
- }
1210
- /**
1211
- * Delete all sessions for a thread
1212
- */
1213
- deleteSessionsByThread(threadId) {
1214
- for (const [sessionId, session] of this.sessions.entries()) {
1215
- if (session.threadId === threadId) {
1216
- session.agent.close();
1217
- this.sessions.delete(sessionId);
1218
- }
1219
- }
1220
- }
1221
- /**
1222
- * Get all active sessions
1223
- */
1224
- getAllSessions() {
1225
- return Array.from(this.sessions.values());
1226
- }
1227
- /**
1228
- * Clean up expired sessions
1229
- */
1230
- cleanupExpiredSessions() {
1231
- const now = Date.now();
1232
- const expiredSessions = [];
1233
- for (const [sessionId, session] of this.sessions.entries()) {
1234
- const inactiveTime = now - session.lastActive;
1235
- if (inactiveTime > this.SESSION_TIMEOUT && !session.isLocked) {
1236
- expiredSessions.push(sessionId);
1237
- }
1238
- }
1239
- for (const sessionId of expiredSessions) {
1240
- console.log(
1241
- `[AgentSessionStore] Cleaning up expired session: ${sessionId}`
1242
- );
1243
- this.deleteSession(sessionId);
1244
- }
1245
- if (expiredSessions.length > 0) {
1246
- console.log(
1247
- `[AgentSessionStore] Cleaned up ${expiredSessions.length} expired sessions`
1248
- );
1249
- }
1250
- }
1251
- /**
1252
- * Start periodic cleanup timer
1253
- */
1254
- startCleanupTimer() {
1255
- setInterval(() => {
1256
- this.cleanupExpiredSessions();
1257
- }, this.CLEANUP_INTERVAL);
1258
- }
1259
- /**
1260
- * Generate a unique session ID
1261
- */
1262
- generateSessionId() {
1263
- return `session-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
1264
- }
1265
- /**
1266
- * Get statistics about the session store
1267
- */
1268
- getStats() {
1269
- return {
1270
- totalSessions: this.sessions.size,
1271
- lockedSessions: Array.from(this.sessions.values()).filter(
1272
- (s) => s.isLocked
1273
- ).length,
1274
- sessions: Array.from(this.sessions.values()).map((s) => ({
1275
- sessionId: s.sessionId,
1276
- threadId: s.threadId,
1277
- isLocked: s.isLocked,
1278
- ageMinutes: Math.floor((Date.now() - s.createdAt) / 1e3 / 60),
1279
- inactiveMinutes: Math.floor((Date.now() - s.lastActive) / 1e3 / 60)
1280
- }))
1281
- };
1282
- }
1283
- }
1284
- let sessionStore = null;
1285
- function getSessionStore() {
1286
- if (!sessionStore) {
1287
- sessionStore = new AgentSessionStore();
1288
- }
1289
- return sessionStore;
1290
- }
1291
- async function handleChat(req) {
1292
- const devModeError = validateDevMode();
1293
- if (devModeError) return devModeError;
1294
- try {
1295
- const body = await req.json();
1296
- const { sessionId, threadId, message, componentContext } = body;
1297
- if (!threadId || !message) {
1298
- return server.NextResponse.json(
1299
- { error: "threadId and message are required" },
1300
- { status: 400 }
1301
- );
1302
- }
1303
- const apiKey = process.env.ANTHROPIC_API_KEY;
1304
- if (!apiKey) {
1305
- return server.NextResponse.json(
1306
- { error: "ANTHROPIC_API_KEY not configured" },
1307
- { status: 500 }
1308
- );
1309
- }
1310
- const sessionStore2 = getSessionStore();
1311
- const projectRoot = process.cwd();
1312
- const session = await sessionStore2.createSession({
1313
- sessionId,
1314
- threadId,
1315
- apiKey,
1316
- projectRoot
1317
- });
1318
- if (!sessionStore2.acquireLock(session.sessionId)) {
1319
- return server.NextResponse.json(
1320
- {
1321
- error: "Another operation is in progress. Please wait for it to complete."
1322
- },
1323
- { status: 409 }
1324
- );
1325
- }
1326
- const encoder = new TextEncoder();
1327
- const stream = new ReadableStream({
1328
- async start(controller) {
1329
- try {
1330
- controller.enqueue(
1331
- encoder.encode(
1332
- `data: ${JSON.stringify({ type: "connected", sessionId: session.sessionId })}
1333
-
1334
- `
1335
- )
1336
- );
1337
- for await (const event of session.agent.sendMessage(
1338
- message,
1339
- componentContext
1340
- )) {
1341
- console.log("[AGENT EVENT]", event.type, JSON.stringify(event, null, 2));
1342
- controller.enqueue(
1343
- encoder.encode(`data: ${JSON.stringify(event)}
1344
-
1345
- `)
1346
- );
1347
- }
1348
- controller.enqueue(
1349
- encoder.encode(`data: ${JSON.stringify({ type: "done" })}
1350
-
1351
- `)
1352
- );
1353
- controller.close();
1354
- } catch (error) {
1355
- console.error("[handleChat] Error:", error);
1356
- controller.enqueue(
1357
- encoder.encode(
1358
- `data: ${JSON.stringify({ type: "error", error: error.message || String(error) })}
1359
-
1360
- `
1361
- )
1362
- );
1363
- controller.close();
1364
- } finally {
1365
- sessionStore2.releaseLock(session.sessionId);
1366
- }
1367
- }
1368
- });
1369
- return new Response(stream, {
1370
- headers: {
1371
- "Content-Type": "text/event-stream",
1372
- "Cache-Control": "no-cache",
1373
- Connection: "keep-alive"
1374
- }
1375
- });
1376
- } catch (error) {
1377
- console.error("[handleChat] Request error:", error);
1378
- return server.NextResponse.json(
1379
- { error: String(error) },
1380
- { status: 500 }
1381
- );
1382
- }
1383
- }
1384
- async function handleConfig() {
1385
- const enabled = process.env.NEXT_PUBLIC_AI_EDITOR_ENABLED === "true" || process.env.VITE_AI_EDITOR_ENABLED === "true" || process.env.REACT_APP_AI_EDITOR_ENABLED === "true";
1386
- return server.NextResponse.json({
1387
- enabled,
1388
- // Include NODE_ENV for debugging
1389
- nodeEnv: process.env.NODE_ENV
1390
- });
1391
- }
1392
- async function handleAIEditorRequest(req, context) {
1393
- const { path: path2 } = await context.params;
1394
- const endpoint = path2[0];
1395
- const method = req.method;
1396
- switch (endpoint) {
1397
- case "read":
1398
- if (method === "GET") return handleRead(req);
1399
- break;
1400
- case "undo":
1401
- if (method === "POST") return handleUndo(req);
1402
- break;
1403
- case "resolve":
1404
- if (method === "POST") return handleResolve(req);
1405
- break;
1406
- case "absolute-path":
1407
- if (method === "GET") return handleAbsolutePath(req);
1408
- break;
1409
- case "validate-session":
1410
- if (method === "POST") return handleValidateSession(req);
1411
- break;
1412
- case "chat":
1413
- if (method === "POST") return handleChat(req);
1414
- break;
1415
- case "config":
1416
- if (method === "GET") return handleConfig();
1417
- break;
1418
- }
1419
- return server.NextResponse.json(
1420
- { error: `Unknown endpoint: ${endpoint}` },
1421
- { status: 404 }
1422
- );
1423
- }
1424
- const STORAGE_DIR = ".ai-editor";
1425
- const STORAGE_FILE = "comments.json";
1426
- function getProjectRoot() {
1427
- return process.cwd();
1428
- }
1429
- function getStoragePath() {
1430
- return path.join(getProjectRoot(), STORAGE_DIR, STORAGE_FILE);
1431
- }
1432
- async function ensureStorageDir() {
1433
- const dir = path.join(getProjectRoot(), STORAGE_DIR);
1434
- if (!fs$1.existsSync(dir)) {
1435
- await fs.mkdir(dir, { recursive: true });
1436
- }
1437
- }
1438
- async function handleCommentsRequest(request) {
1439
- if (process.env.NODE_ENV !== "development") {
1440
- return server.NextResponse.json(
1441
- { error: "Comments API only available in development" },
1442
- { status: 403 }
1443
- );
1444
- }
1445
- try {
1446
- if (request.method === "GET") {
1447
- const storagePath = getStoragePath();
1448
- if (!fs$1.existsSync(storagePath)) {
1449
- return server.NextResponse.json({ comments: [] });
1450
- }
1451
- const data = await fs.readFile(storagePath, "utf-8");
1452
- const comments = JSON.parse(data);
1453
- return server.NextResponse.json({ comments });
1454
- }
1455
- if (request.method === "POST") {
1456
- const body = await request.json();
1457
- const { action } = body;
1458
- if (action === "save") {
1459
- const { comments } = body;
1460
- await ensureStorageDir();
1461
- const storagePath = getStoragePath();
1462
- await fs.writeFile(storagePath, JSON.stringify(comments, null, 2), "utf-8");
1463
- return server.NextResponse.json({ success: true });
1464
- }
1465
- if (action === "clear") {
1466
- await ensureStorageDir();
1467
- const storagePath = getStoragePath();
1468
- await fs.writeFile(storagePath, JSON.stringify([]), "utf-8");
1469
- return server.NextResponse.json({ success: true });
1470
- }
1471
- return server.NextResponse.json(
1472
- { error: "Invalid action" },
1473
- { status: 400 }
1474
- );
1475
- }
1476
- return server.NextResponse.json(
1477
- { error: "Method not allowed" },
1478
- { status: 405 }
1479
- );
1480
- } catch (error) {
1481
- console.error("Comment storage error:", error);
1482
- return server.NextResponse.json(
1483
- { error: "Internal server error" },
1484
- { status: 500 }
1485
- );
1486
- }
1487
- }
1488
- exports.extractComponentName = extractComponentName;
1489
- exports.extractComponentNameFromStack = extractComponentNameFromStack;
1490
- exports.fileExists = fileExists$1;
1491
- exports.findTargetElement = findTargetElement;
1492
- exports.getAttributeValue = getAttributeValue;
1493
- exports.getJSXMemberName = getJSXMemberName;
1494
- exports.getOriginalPositionFromDebugStack = getOriginalPositionFromDebugStack;
1495
- exports.handleAIEditorRequest = handleAIEditorRequest;
1496
- exports.handleAbsolutePath = handleAbsolutePath;
1497
- exports.handleCommentsRequest = handleCommentsRequest;
1498
- exports.handleRead = handleRead;
1499
- exports.handleResolve = handleResolve;
1500
- exports.handleUndo = handleUndo;
1501
- exports.handleValidateSession = handleValidateSession;
1502
- exports.isPathSecure = isPathSecure;
1503
- exports.normalizePath = normalizePath;
1504
- exports.parseDebugStack = parseDebugStack;
1505
- exports.parseDebugStackFrames = parseDebugStackFrames;
1506
- exports.parseFile = parseFile;
1507
- exports.resolveFilePath = resolveFilePath;
1508
- exports.resolveOriginalPosition = resolveOriginalPosition;
1509
- exports.scoreElementMatch = scoreElementMatch;
1510
- exports.validateDevMode = validateDevMode;
1511
- exports.validateGeneratedCode = validateGeneratedCode;
1512
- //# sourceMappingURL=comments-2HX-AAwu.cjs.map