next-ai-editor 0.1.2 → 0.2.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 (67) hide show
  1. package/dist/AIEditorProvider-CKA2K_g2.js +1428 -0
  2. package/dist/AIEditorProvider-CKA2K_g2.js.map +1 -0
  3. package/dist/AIEditorProvider-C_zRSAuV.cjs +1427 -0
  4. package/dist/AIEditorProvider-C_zRSAuV.cjs.map +1 -0
  5. package/dist/client/AIEditorProvider.d.ts +1 -33
  6. package/dist/client/AIEditorProvider.d.ts.map +1 -1
  7. package/dist/client/components/ChatPanel.d.ts +18 -0
  8. package/dist/client/components/ChatPanel.d.ts.map +1 -0
  9. package/dist/client/components/ControlPill.d.ts +8 -0
  10. package/dist/client/components/ControlPill.d.ts.map +1 -0
  11. package/dist/client/components/MessageItem.d.ts +7 -0
  12. package/dist/client/components/MessageItem.d.ts.map +1 -0
  13. package/dist/client/components/MessageList.d.ts +7 -0
  14. package/dist/client/components/MessageList.d.ts.map +1 -0
  15. package/dist/client/components/TaskHistoryPanel.d.ts +10 -0
  16. package/dist/client/components/TaskHistoryPanel.d.ts.map +1 -0
  17. package/dist/client/components/index.d.ts +11 -0
  18. package/dist/client/components/index.d.ts.map +1 -0
  19. package/dist/client/hooks/index.d.ts +3 -0
  20. package/dist/client/hooks/index.d.ts.map +1 -0
  21. package/dist/client/hooks/useChatStream.d.ts +66 -0
  22. package/dist/client/hooks/useChatStream.d.ts.map +1 -0
  23. package/dist/client/hooks/useHotReload.d.ts +10 -0
  24. package/dist/client/hooks/useHotReload.d.ts.map +1 -0
  25. package/dist/client/index.d.ts +3 -0
  26. package/dist/client/index.d.ts.map +1 -1
  27. package/dist/client.cjs +7 -1
  28. package/dist/client.cjs.map +1 -1
  29. package/dist/client.js +8 -2
  30. package/dist/client.js.map +1 -1
  31. package/dist/{index-3OMXRwpD.js → comments-D3m0RsOO.js} +505 -26
  32. package/dist/comments-D3m0RsOO.js.map +1 -0
  33. package/dist/{index-9QODCOgD.cjs → comments-Daur80r4.cjs} +492 -13
  34. package/dist/comments-Daur80r4.cjs.map +1 -0
  35. package/dist/index.cjs +34 -26
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.js +22 -14
  38. package/dist/index.js.map +1 -1
  39. package/dist/next-ai-editor.css +880 -0
  40. package/dist/server/agent/sdk-client.d.ts +54 -0
  41. package/dist/server/agent/sdk-client.d.ts.map +1 -0
  42. package/dist/server/agent/session-store.d.ts +101 -0
  43. package/dist/server/agent/session-store.d.ts.map +1 -0
  44. package/dist/server/handlers/chat.d.ts +6 -0
  45. package/dist/server/handlers/chat.d.ts.map +1 -0
  46. package/dist/server/handlers/comments.d.ts +10 -0
  47. package/dist/server/handlers/comments.d.ts.map +1 -0
  48. package/dist/server/handlers/index.d.ts +2 -1
  49. package/dist/server/handlers/index.d.ts.map +1 -1
  50. package/dist/server/handlers/read.d.ts.map +1 -1
  51. package/dist/server/index.d.ts +1 -0
  52. package/dist/server/index.d.ts.map +1 -1
  53. package/dist/server/utils/ast.d.ts.map +1 -1
  54. package/dist/server/utils/source-map.d.ts +5 -0
  55. package/dist/server/utils/source-map.d.ts.map +1 -1
  56. package/dist/server.cjs +27 -25
  57. package/dist/server.cjs.map +1 -1
  58. package/dist/server.js +14 -12
  59. package/dist/shared/comment-types.d.ts +140 -0
  60. package/dist/shared/comment-types.d.ts.map +1 -0
  61. package/package.json +13 -4
  62. package/dist/AIEditorProvider-CFFnEtEB.js +0 -2170
  63. package/dist/AIEditorProvider-CFFnEtEB.js.map +0 -1
  64. package/dist/AIEditorProvider-CmiACRfw.cjs +0 -2169
  65. package/dist/AIEditorProvider-CmiACRfw.cjs.map +0 -1
  66. package/dist/index-3OMXRwpD.js.map +0 -1
  67. package/dist/index-9QODCOgD.cjs.map +0 -1
@@ -10,6 +10,8 @@ const t = require("@babel/types");
10
10
  const sourceMap = require("@jridgewell/source-map");
11
11
  const pathUtils = require("./path-utils-DYzEWUGy.cjs");
12
12
  const crypto = require("crypto");
13
+ const claudeAgentSdk = require("@anthropic-ai/claude-agent-sdk");
14
+ const fs$1 = require("fs");
13
15
  function _interopNamespaceDefault(e) {
14
16
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
15
17
  if (e) {
@@ -107,6 +109,11 @@ function extractComponentName(ast) {
107
109
  if (t__namespace.isIdentifier(declarator.id)) {
108
110
  componentName = declarator.id.name;
109
111
  }
112
+ } else if (path2.node.specifiers && path2.node.specifiers.length > 0) {
113
+ const specifier = path2.node.specifiers[0];
114
+ if (t__namespace.isExportSpecifier(specifier) && t__namespace.isIdentifier(specifier.exported)) {
115
+ componentName = specifier.exported.name;
116
+ }
110
117
  }
111
118
  }
112
119
  });
@@ -258,16 +265,34 @@ function findTargetElement(ast, fileContent, options) {
258
265
  componentEnd
259
266
  };
260
267
  }
261
- if ((elementContext == null ? void 0 : elementContext.nthOfType) && elementContext.tagName) {
268
+ if (elementContext == null ? void 0 : elementContext.tagName) {
262
269
  const allOfTag = allElementsByTag.get(elementContext.tagName);
263
- if (allOfTag && allOfTag.length >= elementContext.nthOfType) {
264
- const target = allOfTag[elementContext.nthOfType - 1];
265
- return {
266
- startLine: target.startLine,
267
- endLine: target.endLine,
268
- componentStart,
269
- componentEnd
270
- };
270
+ if (allOfTag && allOfTag.length > 0) {
271
+ if (elementContext.textContent || elementContext.className) {
272
+ for (const elem of allOfTag) {
273
+ if (t__namespace.isJSXElement(elem.node)) {
274
+ elem.score = scoreElementMatch(elem.node, elementContext, fileContent);
275
+ }
276
+ }
277
+ allOfTag.sort((a, b) => b.score - a.score);
278
+ if (allOfTag[0].score > 50) {
279
+ return {
280
+ startLine: allOfTag[0].startLine,
281
+ endLine: allOfTag[0].endLine,
282
+ componentStart,
283
+ componentEnd
284
+ };
285
+ }
286
+ }
287
+ if (elementContext.nthOfType && allOfTag.length >= elementContext.nthOfType) {
288
+ const target = allOfTag[elementContext.nthOfType - 1];
289
+ return {
290
+ startLine: target.startLine,
291
+ endLine: target.endLine,
292
+ componentStart,
293
+ componentEnd
294
+ };
295
+ }
271
296
  }
272
297
  }
273
298
  const nearbyElements = [];
@@ -714,6 +739,30 @@ function parseDebugStack(stack) {
714
739
  );
715
740
  return null;
716
741
  }
742
+ function extractComponentNameFromStack(stack) {
743
+ if (!stack) return null;
744
+ const stackStr = typeof stack === "string" ? stack : stack.stack || String(stack);
745
+ const frames = stackStr.split("\n");
746
+ const skipPatterns = [
747
+ "node_modules",
748
+ "SegmentViewNode",
749
+ "LayoutRouter",
750
+ "ErrorBoundary",
751
+ "fakeJSXCallSite",
752
+ "react_stack_bottom_frame"
753
+ ];
754
+ for (const frame of frames) {
755
+ if (skipPatterns.some((p) => frame.includes(p))) continue;
756
+ const match = frame.match(/at\s+(\w+)\s+\(/);
757
+ if (match && match[1]) {
758
+ const componentName = match[1];
759
+ if (componentName !== "Object" && componentName !== "anonymous") {
760
+ return componentName;
761
+ }
762
+ }
763
+ }
764
+ return null;
765
+ }
717
766
  function parseDebugStackFrames(stack) {
718
767
  if (!stack) return [];
719
768
  const stackStr = typeof stack === "string" ? stack : stack.stack || String(stack);
@@ -1014,7 +1063,10 @@ async function handleRead(req) {
1014
1063
  let resolvedParentPath = parentFilePath;
1015
1064
  let resolvedParentLine = parentLine;
1016
1065
  let resolvedParentComponentName = parentComponentName;
1017
- if (resolvedParentComponentName && parentDebugStack) {
1066
+ if (!resolvedParentComponentName && parentDebugStack) {
1067
+ resolvedParentComponentName = extractComponentNameFromStack(parentDebugStack) || "";
1068
+ }
1069
+ if (parentDebugStack) {
1018
1070
  const compiledPos = parseDebugStack(parentDebugStack);
1019
1071
  if (compiledPos) {
1020
1072
  const originalPos = await resolveOriginalPosition(
@@ -1046,12 +1098,14 @@ async function handleRead(req) {
1046
1098
  const parentTarget = findTargetElement(parentAst, parentContent, {
1047
1099
  componentName: resolvedParentComponentName,
1048
1100
  lineNumber: 0,
1049
- // Don't use line number - rely on nthOfType to find correct instance
1101
+ // Don't use line number - rely on element context to find correct instance
1050
1102
  elementContext: {
1051
1103
  tagName: componentName,
1052
1104
  // Search for child component usage
1053
- nthOfType: nthOfType2
1105
+ nthOfType: nthOfType2,
1054
1106
  // Find specific instance if key is numeric
1107
+ textContent: textContent || void 0
1108
+ // Use text content to match the specific instance
1055
1109
  }
1056
1110
  });
1057
1111
  if (parentTarget) {
@@ -1073,6 +1127,7 @@ async function handleRead(req) {
1073
1127
  }
1074
1128
  }
1075
1129
  } catch (error) {
1130
+ console.error("Error resolving parent instance:", error);
1076
1131
  }
1077
1132
  }
1078
1133
  return server.NextResponse.json({
@@ -1480,6 +1535,361 @@ Generate 6-8 initial suggestions:`;
1480
1535
  return null;
1481
1536
  }
1482
1537
  }
1538
+ class AIEditorAgent {
1539
+ constructor(session, projectRoot) {
1540
+ this.session = session;
1541
+ this.projectRoot = projectRoot;
1542
+ }
1543
+ /**
1544
+ * Create a new agent instance
1545
+ */
1546
+ static async create(config) {
1547
+ const sessionOptions = {
1548
+ model: "claude-sonnet-4-5-20250929",
1549
+ // Enable auto-apply for edits without permission prompts
1550
+ permissionMode: "acceptEdits",
1551
+ env: {
1552
+ ...process.env,
1553
+ ANTHROPIC_API_KEY: config.apiKey,
1554
+ // Set working directory
1555
+ PWD: config.projectRoot
1556
+ },
1557
+ // Explicitly allow core development tools
1558
+ allowedTools: config.allowedTools || ["Read", "Edit", "Glob", "Grep"],
1559
+ disallowedTools: config.disallowedTools || []
1560
+ };
1561
+ let session;
1562
+ if (config.sessionId) {
1563
+ session = claudeAgentSdk.unstable_v2_resumeSession(config.sessionId, sessionOptions);
1564
+ } else {
1565
+ session = claudeAgentSdk.unstable_v2_createSession(sessionOptions);
1566
+ }
1567
+ return new AIEditorAgent(session, config.projectRoot);
1568
+ }
1569
+ /**
1570
+ * Send a message to the agent and stream responses
1571
+ */
1572
+ async *sendMessage(message, componentContext) {
1573
+ let fullMessage = `<response_style>
1574
+ KEEP RESPONSES EXTREMELY BRIEF AND STATUS-LIKE.
1575
+ - Use terse status messages: "Reading file.tsx", "Changing color", "Done"
1576
+ - NO conversational language (avoid: "I'll", "Let me", "Sure", "Great", "I can see")
1577
+ - NO explanations unless explicitly asked
1578
+ - State ONLY what you're doing, nothing more
1579
+ - Format: Action + target (e.g., "Updating StatsCard.tsx:24")
1580
+ </response_style>
1581
+
1582
+ `;
1583
+ if (componentContext) {
1584
+ fullMessage += `[Component: ${componentContext.componentName} at ${componentContext.filePath}:${componentContext.lineNumber}]
1585
+
1586
+ `;
1587
+ }
1588
+ fullMessage += message;
1589
+ await this.session.send(fullMessage);
1590
+ for await (const event of this.session.stream()) {
1591
+ yield event;
1592
+ }
1593
+ }
1594
+ /**
1595
+ * Get the session ID
1596
+ */
1597
+ getSessionId() {
1598
+ return this.session.sessionId;
1599
+ }
1600
+ /**
1601
+ * Close the session
1602
+ */
1603
+ close() {
1604
+ this.session.close();
1605
+ }
1606
+ /**
1607
+ * Async disposal support
1608
+ */
1609
+ async [Symbol.asyncDispose]() {
1610
+ await this.session[Symbol.asyncDispose]();
1611
+ }
1612
+ }
1613
+ class AgentSessionStore {
1614
+ // 5 minutes
1615
+ constructor() {
1616
+ this.sessions = /* @__PURE__ */ new Map();
1617
+ this.SESSION_TIMEOUT = 1e3 * 60 * 30;
1618
+ this.CLEANUP_INTERVAL = 1e3 * 60 * 5;
1619
+ this.startCleanupTimer();
1620
+ }
1621
+ /**
1622
+ * Create or resume a session
1623
+ */
1624
+ async createSession(config) {
1625
+ const sessionId = config.sessionId || this.generateSessionId();
1626
+ const existing = this.sessions.get(sessionId);
1627
+ if (existing) {
1628
+ existing.lastActive = Date.now();
1629
+ existing.threadId = config.threadId;
1630
+ return existing;
1631
+ }
1632
+ const agent = await AIEditorAgent.create({
1633
+ apiKey: config.apiKey,
1634
+ projectRoot: config.projectRoot,
1635
+ sessionId: config.sessionId,
1636
+ allowedTools: config.allowedTools,
1637
+ disallowedTools: config.disallowedTools
1638
+ });
1639
+ const session = {
1640
+ sessionId,
1641
+ threadId: config.threadId,
1642
+ agent,
1643
+ createdAt: Date.now(),
1644
+ lastActive: Date.now(),
1645
+ isLocked: false
1646
+ };
1647
+ this.sessions.set(sessionId, session);
1648
+ return session;
1649
+ }
1650
+ /**
1651
+ * Get a session by ID
1652
+ */
1653
+ getSession(sessionId) {
1654
+ const session = this.sessions.get(sessionId);
1655
+ if (session) {
1656
+ session.lastActive = Date.now();
1657
+ }
1658
+ return session;
1659
+ }
1660
+ /**
1661
+ * Acquire a lock on a session to prevent concurrent edits
1662
+ * Returns true if lock was acquired, false if already locked
1663
+ */
1664
+ acquireLock(sessionId) {
1665
+ const session = this.sessions.get(sessionId);
1666
+ if (!session) {
1667
+ throw new Error(`Session ${sessionId} not found`);
1668
+ }
1669
+ if (session.isLocked) {
1670
+ return false;
1671
+ }
1672
+ session.isLocked = true;
1673
+ session.lastActive = Date.now();
1674
+ return true;
1675
+ }
1676
+ /**
1677
+ * Release a lock on a session
1678
+ */
1679
+ releaseLock(sessionId) {
1680
+ const session = this.sessions.get(sessionId);
1681
+ if (session) {
1682
+ session.isLocked = false;
1683
+ session.lastActive = Date.now();
1684
+ }
1685
+ }
1686
+ /**
1687
+ * Check if any session is currently locked (to prevent concurrent edits)
1688
+ */
1689
+ hasActiveLock() {
1690
+ for (const session of this.sessions.values()) {
1691
+ if (session.isLocked) {
1692
+ return true;
1693
+ }
1694
+ }
1695
+ return false;
1696
+ }
1697
+ /**
1698
+ * Get all active sessions for a thread
1699
+ */
1700
+ getSessionsByThread(threadId) {
1701
+ const sessions = [];
1702
+ for (const session of this.sessions.values()) {
1703
+ if (session.threadId === threadId) {
1704
+ sessions.push(session);
1705
+ }
1706
+ }
1707
+ return sessions;
1708
+ }
1709
+ /**
1710
+ * Delete a session
1711
+ */
1712
+ deleteSession(sessionId) {
1713
+ const session = this.sessions.get(sessionId);
1714
+ if (session) {
1715
+ session.agent.close();
1716
+ this.sessions.delete(sessionId);
1717
+ }
1718
+ }
1719
+ /**
1720
+ * Delete all sessions for a thread
1721
+ */
1722
+ deleteSessionsByThread(threadId) {
1723
+ for (const [sessionId, session] of this.sessions.entries()) {
1724
+ if (session.threadId === threadId) {
1725
+ session.agent.close();
1726
+ this.sessions.delete(sessionId);
1727
+ }
1728
+ }
1729
+ }
1730
+ /**
1731
+ * Get all active sessions
1732
+ */
1733
+ getAllSessions() {
1734
+ return Array.from(this.sessions.values());
1735
+ }
1736
+ /**
1737
+ * Clean up expired sessions
1738
+ */
1739
+ cleanupExpiredSessions() {
1740
+ const now = Date.now();
1741
+ const expiredSessions = [];
1742
+ for (const [sessionId, session] of this.sessions.entries()) {
1743
+ const inactiveTime = now - session.lastActive;
1744
+ if (inactiveTime > this.SESSION_TIMEOUT && !session.isLocked) {
1745
+ expiredSessions.push(sessionId);
1746
+ }
1747
+ }
1748
+ for (const sessionId of expiredSessions) {
1749
+ console.log(
1750
+ `[AgentSessionStore] Cleaning up expired session: ${sessionId}`
1751
+ );
1752
+ this.deleteSession(sessionId);
1753
+ }
1754
+ if (expiredSessions.length > 0) {
1755
+ console.log(
1756
+ `[AgentSessionStore] Cleaned up ${expiredSessions.length} expired sessions`
1757
+ );
1758
+ }
1759
+ }
1760
+ /**
1761
+ * Start periodic cleanup timer
1762
+ */
1763
+ startCleanupTimer() {
1764
+ setInterval(() => {
1765
+ this.cleanupExpiredSessions();
1766
+ }, this.CLEANUP_INTERVAL);
1767
+ }
1768
+ /**
1769
+ * Generate a unique session ID
1770
+ */
1771
+ generateSessionId() {
1772
+ return `session-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
1773
+ }
1774
+ /**
1775
+ * Get statistics about the session store
1776
+ */
1777
+ getStats() {
1778
+ return {
1779
+ totalSessions: this.sessions.size,
1780
+ lockedSessions: Array.from(this.sessions.values()).filter(
1781
+ (s) => s.isLocked
1782
+ ).length,
1783
+ sessions: Array.from(this.sessions.values()).map((s) => ({
1784
+ sessionId: s.sessionId,
1785
+ threadId: s.threadId,
1786
+ isLocked: s.isLocked,
1787
+ ageMinutes: Math.floor((Date.now() - s.createdAt) / 1e3 / 60),
1788
+ inactiveMinutes: Math.floor((Date.now() - s.lastActive) / 1e3 / 60)
1789
+ }))
1790
+ };
1791
+ }
1792
+ }
1793
+ let sessionStore = null;
1794
+ function getSessionStore() {
1795
+ if (!sessionStore) {
1796
+ sessionStore = new AgentSessionStore();
1797
+ }
1798
+ return sessionStore;
1799
+ }
1800
+ async function handleChat(req) {
1801
+ const devModeError = validateDevMode();
1802
+ if (devModeError) return devModeError;
1803
+ try {
1804
+ const body = await req.json();
1805
+ const { sessionId, threadId, message, componentContext } = body;
1806
+ if (!threadId || !message) {
1807
+ return server.NextResponse.json(
1808
+ { error: "threadId and message are required" },
1809
+ { status: 400 }
1810
+ );
1811
+ }
1812
+ const apiKey = process.env.ANTHROPIC_API_KEY;
1813
+ if (!apiKey) {
1814
+ return server.NextResponse.json(
1815
+ { error: "ANTHROPIC_API_KEY not configured" },
1816
+ { status: 500 }
1817
+ );
1818
+ }
1819
+ const sessionStore2 = getSessionStore();
1820
+ const projectRoot = process.cwd();
1821
+ const session = await sessionStore2.createSession({
1822
+ sessionId,
1823
+ threadId,
1824
+ apiKey,
1825
+ projectRoot
1826
+ });
1827
+ if (!sessionStore2.acquireLock(session.sessionId)) {
1828
+ return server.NextResponse.json(
1829
+ {
1830
+ error: "Another operation is in progress. Please wait for it to complete."
1831
+ },
1832
+ { status: 409 }
1833
+ );
1834
+ }
1835
+ const encoder = new TextEncoder();
1836
+ const stream = new ReadableStream({
1837
+ async start(controller) {
1838
+ try {
1839
+ controller.enqueue(
1840
+ encoder.encode(
1841
+ `data: ${JSON.stringify({ type: "connected", sessionId: session.sessionId })}
1842
+
1843
+ `
1844
+ )
1845
+ );
1846
+ for await (const event of session.agent.sendMessage(
1847
+ message,
1848
+ componentContext
1849
+ )) {
1850
+ console.log("[AGENT EVENT]", event.type, JSON.stringify(event, null, 2));
1851
+ controller.enqueue(
1852
+ encoder.encode(`data: ${JSON.stringify(event)}
1853
+
1854
+ `)
1855
+ );
1856
+ }
1857
+ controller.enqueue(
1858
+ encoder.encode(`data: ${JSON.stringify({ type: "done" })}
1859
+
1860
+ `)
1861
+ );
1862
+ controller.close();
1863
+ } catch (error) {
1864
+ console.error("[handleChat] Error:", error);
1865
+ controller.enqueue(
1866
+ encoder.encode(
1867
+ `data: ${JSON.stringify({ type: "error", error: error.message || String(error) })}
1868
+
1869
+ `
1870
+ )
1871
+ );
1872
+ controller.close();
1873
+ } finally {
1874
+ sessionStore2.releaseLock(session.sessionId);
1875
+ }
1876
+ }
1877
+ });
1878
+ return new Response(stream, {
1879
+ headers: {
1880
+ "Content-Type": "text/event-stream",
1881
+ "Cache-Control": "no-cache",
1882
+ Connection: "keep-alive"
1883
+ }
1884
+ });
1885
+ } catch (error) {
1886
+ console.error("[handleChat] Request error:", error);
1887
+ return server.NextResponse.json(
1888
+ { error: String(error) },
1889
+ { status: 500 }
1890
+ );
1891
+ }
1892
+ }
1483
1893
  async function handleAIEditorRequest(req, context) {
1484
1894
  const { path: path2 } = await context.params;
1485
1895
  const endpoint = path2[0];
@@ -1506,13 +1916,81 @@ async function handleAIEditorRequest(req, context) {
1506
1916
  case "suggestions":
1507
1917
  if (method === "GET") return handleSuggestions(req);
1508
1918
  break;
1919
+ case "chat":
1920
+ if (method === "POST") return handleChat(req);
1921
+ break;
1509
1922
  }
1510
1923
  return server.NextResponse.json(
1511
1924
  { error: `Unknown endpoint: ${endpoint}` },
1512
1925
  { status: 404 }
1513
1926
  );
1514
1927
  }
1928
+ const STORAGE_DIR = ".ai-editor";
1929
+ const STORAGE_FILE = "comments.json";
1930
+ function getProjectRoot() {
1931
+ return process.cwd();
1932
+ }
1933
+ function getStoragePath() {
1934
+ return path.join(getProjectRoot(), STORAGE_DIR, STORAGE_FILE);
1935
+ }
1936
+ async function ensureStorageDir() {
1937
+ const dir = path.join(getProjectRoot(), STORAGE_DIR);
1938
+ if (!fs$1.existsSync(dir)) {
1939
+ await fs.mkdir(dir, { recursive: true });
1940
+ }
1941
+ }
1942
+ async function handleCommentsRequest(request) {
1943
+ if (process.env.NODE_ENV !== "development") {
1944
+ return server.NextResponse.json(
1945
+ { error: "Comments API only available in development" },
1946
+ { status: 403 }
1947
+ );
1948
+ }
1949
+ try {
1950
+ if (request.method === "GET") {
1951
+ const storagePath = getStoragePath();
1952
+ if (!fs$1.existsSync(storagePath)) {
1953
+ return server.NextResponse.json({ comments: [] });
1954
+ }
1955
+ const data = await fs.readFile(storagePath, "utf-8");
1956
+ const comments = JSON.parse(data);
1957
+ return server.NextResponse.json({ comments });
1958
+ }
1959
+ if (request.method === "POST") {
1960
+ const body = await request.json();
1961
+ const { action } = body;
1962
+ if (action === "save") {
1963
+ const { comments } = body;
1964
+ await ensureStorageDir();
1965
+ const storagePath = getStoragePath();
1966
+ await fs.writeFile(storagePath, JSON.stringify(comments, null, 2), "utf-8");
1967
+ return server.NextResponse.json({ success: true });
1968
+ }
1969
+ if (action === "clear") {
1970
+ await ensureStorageDir();
1971
+ const storagePath = getStoragePath();
1972
+ await fs.writeFile(storagePath, JSON.stringify([]), "utf-8");
1973
+ return server.NextResponse.json({ success: true });
1974
+ }
1975
+ return server.NextResponse.json(
1976
+ { error: "Invalid action" },
1977
+ { status: 400 }
1978
+ );
1979
+ }
1980
+ return server.NextResponse.json(
1981
+ { error: "Method not allowed" },
1982
+ { status: 405 }
1983
+ );
1984
+ } catch (error) {
1985
+ console.error("Comment storage error:", error);
1986
+ return server.NextResponse.json(
1987
+ { error: "Internal server error" },
1988
+ { status: 500 }
1989
+ );
1990
+ }
1991
+ }
1515
1992
  exports.extractComponentName = extractComponentName;
1993
+ exports.extractComponentNameFromStack = extractComponentNameFromStack;
1516
1994
  exports.fileExists = fileExists$1;
1517
1995
  exports.findTargetElement = findTargetElement;
1518
1996
  exports.getAttributeValue = getAttributeValue;
@@ -1520,6 +1998,7 @@ exports.getJSXMemberName = getJSXMemberName;
1520
1998
  exports.getOriginalPositionFromDebugStack = getOriginalPositionFromDebugStack;
1521
1999
  exports.handleAIEditorRequest = handleAIEditorRequest;
1522
2000
  exports.handleAbsolutePath = handleAbsolutePath;
2001
+ exports.handleCommentsRequest = handleCommentsRequest;
1523
2002
  exports.handleEdit = handleEdit;
1524
2003
  exports.handleRead = handleRead;
1525
2004
  exports.handleResolve = handleResolve;
@@ -1536,4 +2015,4 @@ exports.resolveOriginalPosition = resolveOriginalPosition;
1536
2015
  exports.scoreElementMatch = scoreElementMatch;
1537
2016
  exports.validateDevMode = validateDevMode;
1538
2017
  exports.validateGeneratedCode = validateGeneratedCode;
1539
- //# sourceMappingURL=index-9QODCOgD.cjs.map
2018
+ //# sourceMappingURL=comments-Daur80r4.cjs.map