next-ai-editor 1.0.1 → 1.1.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.
package/dist/index.cjs CHANGED
@@ -1008,13 +1008,6 @@ function MessageList({
1008
1008
  ] });
1009
1009
  }
1010
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
1011
  if (typeof window !== "undefined") {
1019
1012
  const hostname = window.location.hostname;
1020
1013
  if (hostname === "localhost" || hostname === "127.0.0.1") {
@@ -1371,7 +1364,7 @@ const createLucideIcon = (iconName, iconNode) => {
1371
1364
  * This source code is licensed under the ISC license.
1372
1365
  * See the LICENSE file in the root directory of this source tree.
1373
1366
  */
1374
- const __iconNode$4 = [
1367
+ const __iconNode$a = [
1375
1368
  [
1376
1369
  "path",
1377
1370
  {
@@ -1382,14 +1375,22 @@ const __iconNode$4 = [
1382
1375
  ["path", { d: "m3.3 7 8.7 5 8.7-5", key: "g66t2b" }],
1383
1376
  ["path", { d: "M12 22V12", key: "d0xqtd" }]
1384
1377
  ];
1385
- const Box = createLucideIcon("box", __iconNode$4);
1378
+ const Box = createLucideIcon("box", __iconNode$a);
1386
1379
  /**
1387
1380
  * @license lucide-react v0.562.0 - ISC
1388
1381
  *
1389
1382
  * This source code is licensed under the ISC license.
1390
1383
  * See the LICENSE file in the root directory of this source tree.
1391
1384
  */
1392
- const __iconNode$3 = [
1385
+ const __iconNode$9 = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
1386
+ const Check = createLucideIcon("check", __iconNode$9);
1387
+ /**
1388
+ * @license lucide-react v0.562.0 - ISC
1389
+ *
1390
+ * This source code is licensed under the ISC license.
1391
+ * See the LICENSE file in the root directory of this source tree.
1392
+ */
1393
+ const __iconNode$8 = [
1393
1394
  [
1394
1395
  "path",
1395
1396
  {
@@ -1401,14 +1402,68 @@ const __iconNode$3 = [
1401
1402
  ["path", { d: "M10 12.5 8 15l2 2.5", key: "1tg20x" }],
1402
1403
  ["path", { d: "m14 12.5 2 2.5-2 2.5", key: "yinavb" }]
1403
1404
  ];
1404
- const FileCode = createLucideIcon("file-code", __iconNode$3);
1405
+ const FileCode = createLucideIcon("file-code", __iconNode$8);
1405
1406
  /**
1406
1407
  * @license lucide-react v0.562.0 - ISC
1407
1408
  *
1408
1409
  * This source code is licensed under the ISC license.
1409
1410
  * See the LICENSE file in the root directory of this source tree.
1410
1411
  */
1411
- const __iconNode$2 = [
1412
+ const __iconNode$7 = [
1413
+ [
1414
+ "path",
1415
+ {
1416
+ 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",
1417
+ key: "1oefj6"
1418
+ }
1419
+ ],
1420
+ ["path", { d: "M14 2v5a1 1 0 0 0 1 1h5", key: "wfsgrz" }],
1421
+ ["path", { d: "M10 9H8", key: "b1mrlr" }],
1422
+ ["path", { d: "M16 13H8", key: "t4e002" }],
1423
+ ["path", { d: "M16 17H8", key: "z1uh3a" }]
1424
+ ];
1425
+ const FileText = createLucideIcon("file-text", __iconNode$7);
1426
+ /**
1427
+ * @license lucide-react v0.562.0 - ISC
1428
+ *
1429
+ * This source code is licensed under the ISC license.
1430
+ * See the LICENSE file in the root directory of this source tree.
1431
+ */
1432
+ const __iconNode$6 = [
1433
+ ["line", { x1: "6", x2: "6", y1: "3", y2: "15", key: "17qcm7" }],
1434
+ ["circle", { cx: "18", cy: "6", r: "3", key: "1h7g24" }],
1435
+ ["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
1436
+ ["path", { d: "M18 9a9 9 0 0 1-9 9", key: "n2h4wq" }]
1437
+ ];
1438
+ const GitBranch = createLucideIcon("git-branch", __iconNode$6);
1439
+ /**
1440
+ * @license lucide-react v0.562.0 - ISC
1441
+ *
1442
+ * This source code is licensed under the ISC license.
1443
+ * See the LICENSE file in the root directory of this source tree.
1444
+ */
1445
+ const __iconNode$5 = [
1446
+ ["circle", { cx: "18", cy: "18", r: "3", key: "1xkwt0" }],
1447
+ ["circle", { cx: "6", cy: "6", r: "3", key: "1lh9wr" }],
1448
+ ["path", { d: "M13 6h3a2 2 0 0 1 2 2v7", key: "1yeb86" }],
1449
+ ["line", { x1: "6", x2: "6", y1: "9", y2: "21", key: "rroup" }]
1450
+ ];
1451
+ const GitPullRequest = createLucideIcon("git-pull-request", __iconNode$5);
1452
+ /**
1453
+ * @license lucide-react v0.562.0 - ISC
1454
+ *
1455
+ * This source code is licensed under the ISC license.
1456
+ * See the LICENSE file in the root directory of this source tree.
1457
+ */
1458
+ const __iconNode$4 = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
1459
+ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$4);
1460
+ /**
1461
+ * @license lucide-react v0.562.0 - ISC
1462
+ *
1463
+ * This source code is licensed under the ISC license.
1464
+ * See the LICENSE file in the root directory of this source tree.
1465
+ */
1466
+ const __iconNode$3 = [
1412
1467
  [
1413
1468
  "path",
1414
1469
  {
@@ -1418,7 +1473,26 @@ const __iconNode$2 = [
1418
1473
  ],
1419
1474
  ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
1420
1475
  ];
1421
- const Pencil = createLucideIcon("pencil", __iconNode$2);
1476
+ const Pencil = createLucideIcon("pencil", __iconNode$3);
1477
+ /**
1478
+ * @license lucide-react v0.562.0 - ISC
1479
+ *
1480
+ * This source code is licensed under the ISC license.
1481
+ * See the LICENSE file in the root directory of this source tree.
1482
+ */
1483
+ const __iconNode$2 = [
1484
+ [
1485
+ "path",
1486
+ {
1487
+ d: "M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",
1488
+ key: "1s2grr"
1489
+ }
1490
+ ],
1491
+ ["path", { d: "M20 2v4", key: "1rf3ol" }],
1492
+ ["path", { d: "M22 4h-4", key: "gwowj6" }],
1493
+ ["circle", { cx: "4", cy: "20", r: "2", key: "6kqj1y" }]
1494
+ ];
1495
+ const Sparkles = createLucideIcon("sparkles", __iconNode$2);
1422
1496
  /**
1423
1497
  * @license lucide-react v0.562.0 - ISC
1424
1498
  *
@@ -1442,6 +1516,263 @@ const __iconNode = [
1442
1516
  ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
1443
1517
  ];
1444
1518
  const X = createLucideIcon("x", __iconNode);
1519
+ function usePRStatus() {
1520
+ const [status, setStatus] = react.useState(null);
1521
+ const [isLoading, setIsLoading] = react.useState(true);
1522
+ const [error, setError] = react.useState(null);
1523
+ const fetchStatus = react.useCallback(async () => {
1524
+ try {
1525
+ setIsLoading(true);
1526
+ setError(null);
1527
+ const response = await fetch(buildServiceUrl("api/pr/status"));
1528
+ if (!response.ok) {
1529
+ throw new Error("Failed to fetch PR status");
1530
+ }
1531
+ const data = await response.json();
1532
+ setStatus(data);
1533
+ } catch (err) {
1534
+ setError(err instanceof Error ? err.message : "Unknown error");
1535
+ setStatus(null);
1536
+ } finally {
1537
+ setIsLoading(false);
1538
+ }
1539
+ }, []);
1540
+ react.useEffect(() => {
1541
+ fetchStatus();
1542
+ }, [fetchStatus]);
1543
+ return {
1544
+ status,
1545
+ isLoading,
1546
+ error,
1547
+ refresh: fetchStatus
1548
+ };
1549
+ }
1550
+ function useCreatePR() {
1551
+ const [isCreating, setIsCreating] = react.useState(false);
1552
+ const [isGenerating, setIsGenerating] = react.useState(false);
1553
+ const generateContent = react.useCallback(async () => {
1554
+ setIsGenerating(true);
1555
+ try {
1556
+ const response = await fetch(buildServiceUrl("api/pr/generate-description"), {
1557
+ method: "POST",
1558
+ headers: { "Content-Type": "application/json" },
1559
+ body: JSON.stringify({})
1560
+ });
1561
+ if (!response.ok) {
1562
+ throw new Error("Failed to generate PR content");
1563
+ }
1564
+ const data = await response.json();
1565
+ return {
1566
+ title: data.title || "",
1567
+ description: data.description || ""
1568
+ };
1569
+ } catch (err) {
1570
+ console.error("Error generating PR content:", err);
1571
+ return { title: "", description: "" };
1572
+ } finally {
1573
+ setIsGenerating(false);
1574
+ }
1575
+ }, []);
1576
+ const createPR = react.useCallback(async (input) => {
1577
+ setIsCreating(true);
1578
+ try {
1579
+ const response = await fetch(buildServiceUrl("api/pr/create"), {
1580
+ method: "POST",
1581
+ headers: { "Content-Type": "application/json" },
1582
+ body: JSON.stringify(input)
1583
+ });
1584
+ const data = await response.json();
1585
+ if (!response.ok) {
1586
+ return {
1587
+ success: false,
1588
+ error: data.error || "Failed to create PR",
1589
+ branchName: data.branchName,
1590
+ partialSuccess: data.partialSuccess
1591
+ };
1592
+ }
1593
+ return {
1594
+ success: true,
1595
+ prUrl: data.prUrl,
1596
+ prNumber: data.prNumber,
1597
+ branchName: data.branchName
1598
+ };
1599
+ } catch (err) {
1600
+ return {
1601
+ success: false,
1602
+ error: err instanceof Error ? err.message : "Failed to create PR"
1603
+ };
1604
+ } finally {
1605
+ setIsCreating(false);
1606
+ }
1607
+ }, []);
1608
+ return {
1609
+ createPR,
1610
+ generateContent,
1611
+ isCreating,
1612
+ isGenerating
1613
+ };
1614
+ }
1615
+ function PRBlock({ onCancel, onSuccess }) {
1616
+ const [title, setTitle] = react.useState("");
1617
+ const [description, setDescription] = react.useState("");
1618
+ const [error, setError] = react.useState(null);
1619
+ const [result, setResult] = react.useState(null);
1620
+ const [blockState, setBlockState] = react.useState("generating");
1621
+ const hasGenerated = react.useRef(false);
1622
+ const { status } = usePRStatus();
1623
+ const { createPR, generateContent, isGenerating } = useCreatePR();
1624
+ react.useEffect(() => {
1625
+ if (!hasGenerated.current) {
1626
+ hasGenerated.current = true;
1627
+ generateContent().then((content) => {
1628
+ setTitle(content.title);
1629
+ setDescription(content.description);
1630
+ setBlockState("form");
1631
+ });
1632
+ }
1633
+ }, [generateContent]);
1634
+ const handleRegenerate = react.useCallback(async () => {
1635
+ setError(null);
1636
+ const content = await generateContent();
1637
+ setTitle(content.title);
1638
+ setDescription(content.description);
1639
+ }, [generateContent]);
1640
+ const handleSubmit = react.useCallback(async () => {
1641
+ if (!title.trim()) {
1642
+ setError("Title is required");
1643
+ return;
1644
+ }
1645
+ setError(null);
1646
+ setBlockState("creating");
1647
+ const prResult = await createPR({ title: title.trim(), description });
1648
+ if (prResult.success) {
1649
+ setResult(prResult);
1650
+ setBlockState("success");
1651
+ onSuccess == null ? void 0 : onSuccess(prResult);
1652
+ } else {
1653
+ setError(prResult.error || "Failed to create PR");
1654
+ setBlockState("form");
1655
+ }
1656
+ }, [title, description, createPR, onSuccess]);
1657
+ if (blockState === "success" && result) {
1658
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pr-block pr-block-success", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-block-success-content", children: [
1659
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pr-block-success-icon", children: /* @__PURE__ */ jsxRuntime.jsx(Check, { size: 16 }) }),
1660
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-block-success-text", children: [
1661
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pr-block-success-title", children: "PR Created" }),
1662
+ /* @__PURE__ */ jsxRuntime.jsxs(
1663
+ "a",
1664
+ {
1665
+ href: result.prUrl,
1666
+ target: "_blank",
1667
+ rel: "noopener noreferrer",
1668
+ className: "pr-block-success-link",
1669
+ children: [
1670
+ "#",
1671
+ result.prNumber
1672
+ ]
1673
+ }
1674
+ ),
1675
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pr-block-success-branch", children: [
1676
+ "on ",
1677
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: result.branchName })
1678
+ ] })
1679
+ ] })
1680
+ ] }) });
1681
+ }
1682
+ if (blockState === "generating") {
1683
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pr-block pr-block-generating", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-block-loading", children: [
1684
+ /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 16, className: "pr-block-spinner" }),
1685
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Generating PR details..." })
1686
+ ] }) });
1687
+ }
1688
+ const isDisabled = blockState === "creating" || isGenerating;
1689
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-block", children: [
1690
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-block-header", children: [
1691
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pr-block-title", children: "Create Pull Request" }),
1692
+ /* @__PURE__ */ jsxRuntime.jsx(
1693
+ "button",
1694
+ {
1695
+ className: "pr-block-cancel",
1696
+ onClick: onCancel,
1697
+ disabled: blockState === "creating",
1698
+ title: "Cancel",
1699
+ children: /* @__PURE__ */ jsxRuntime.jsx(X, { size: 14 })
1700
+ }
1701
+ )
1702
+ ] }),
1703
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-block-content", children: [
1704
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pr-block-error", children: error }),
1705
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-block-field", children: [
1706
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "pr-block-title", children: "Title" }),
1707
+ /* @__PURE__ */ jsxRuntime.jsx(
1708
+ "input",
1709
+ {
1710
+ id: "pr-block-title",
1711
+ type: "text",
1712
+ value: title,
1713
+ onChange: (e) => setTitle(e.target.value),
1714
+ placeholder: "PR title...",
1715
+ disabled: isDisabled
1716
+ }
1717
+ )
1718
+ ] }),
1719
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-block-field", children: [
1720
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-block-field-header", children: [
1721
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "pr-block-description", children: "Description" }),
1722
+ /* @__PURE__ */ jsxRuntime.jsxs(
1723
+ "button",
1724
+ {
1725
+ className: "pr-block-regenerate",
1726
+ onClick: handleRegenerate,
1727
+ disabled: isDisabled,
1728
+ children: [
1729
+ isGenerating ? /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 12, className: "pr-block-spinner" }) : /* @__PURE__ */ jsxRuntime.jsx(Sparkles, { size: 12 }),
1730
+ "Regen"
1731
+ ]
1732
+ }
1733
+ )
1734
+ ] }),
1735
+ /* @__PURE__ */ jsxRuntime.jsx(
1736
+ "textarea",
1737
+ {
1738
+ id: "pr-block-description",
1739
+ value: description,
1740
+ onChange: (e) => setDescription(e.target.value),
1741
+ placeholder: "Describe your changes...",
1742
+ disabled: isDisabled,
1743
+ rows: 3
1744
+ }
1745
+ )
1746
+ ] }),
1747
+ status && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-block-info", children: [
1748
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1749
+ /* @__PURE__ */ jsxRuntime.jsx(FileText, { size: 12 }),
1750
+ status.changedFiles.length,
1751
+ " files"
1752
+ ] }),
1753
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1754
+ /* @__PURE__ */ jsxRuntime.jsx(GitBranch, { size: 12 }),
1755
+ status.baseBranch
1756
+ ] })
1757
+ ] })
1758
+ ] }),
1759
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pr-block-footer", children: /* @__PURE__ */ jsxRuntime.jsx(
1760
+ "button",
1761
+ {
1762
+ className: "pr-block-submit",
1763
+ onClick: handleSubmit,
1764
+ disabled: isDisabled || !title.trim(),
1765
+ children: blockState === "creating" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1766
+ /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 14, className: "pr-block-spinner" }),
1767
+ "Creating..."
1768
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1769
+ /* @__PURE__ */ jsxRuntime.jsx(GitPullRequest, { size: 14 }),
1770
+ "Create PR"
1771
+ ] })
1772
+ }
1773
+ ) })
1774
+ ] });
1775
+ }
1445
1776
  function ChatPanel({
1446
1777
  isExpanded,
1447
1778
  onToggle,
@@ -1456,9 +1787,19 @@ function ChatPanel({
1456
1787
  const textareaRef = react.useRef(null);
1457
1788
  const [contextRanges, setContextRanges] = react.useState([]);
1458
1789
  const [isMessagesCollapsed, setMessagesCollapsed] = react.useState(false);
1790
+ const [showPRBlock, setShowPRBlock] = react.useState(false);
1459
1791
  const { messages, isStreaming, sendMessage, startedToolIds, completedToolIds, todos } = useChatStream({
1460
1792
  threadId
1461
1793
  });
1794
+ const { status: prStatus, isLoading: prLoading, refresh: refreshPRStatus } = usePRStatus();
1795
+ const hasChanges = (prStatus == null ? void 0 : prStatus.hasChanges) ?? false;
1796
+ const prevIsStreaming = react.useRef(isStreaming);
1797
+ react.useEffect(() => {
1798
+ if (prevIsStreaming.current && !isStreaming) {
1799
+ refreshPRStatus();
1800
+ }
1801
+ prevIsStreaming.current = isStreaming;
1802
+ }, [isStreaming, refreshPRStatus]);
1462
1803
  react.useEffect(() => {
1463
1804
  if (attachedContext) {
1464
1805
  setContextRanges((prev) => [...prev, {
@@ -1541,11 +1882,15 @@ function ChatPanel({
1541
1882
  }
1542
1883
  return count;
1543
1884
  }, [commentMessages]);
1885
+ const handlePRCancel = react.useCallback(() => {
1886
+ setShowPRBlock(false);
1887
+ }, []);
1888
+ const prButtonTitle = prLoading ? "Checking for changes..." : hasChanges ? `Create PR (${prStatus == null ? void 0 : prStatus.changedFiles.length} files)` : "No changes to commit";
1544
1889
  if (!isExpanded) {
1545
1890
  return null;
1546
1891
  }
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: [
1892
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `chat-panel ai-editor-ui ${theme} ${commentMessages.length === 0 && !showPRBlock ? "empty" : ""}`, children: [
1893
+ (commentMessages.length > 0 || showPRBlock) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `chat-panel-messages-container ${isMessagesCollapsed ? "collapsed" : "expanded"}`, children: [
1549
1894
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "chat-panel-messages-header", children: /* @__PURE__ */ jsxRuntime.jsxs(
1550
1895
  "div",
1551
1896
  {
@@ -1561,18 +1906,21 @@ function ChatPanel({
1561
1906
  ]
1562
1907
  }
1563
1908
  ) }),
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
- ) })
1909
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "chat-panel-messages", children: [
1910
+ /* @__PURE__ */ jsxRuntime.jsx(
1911
+ MessageList,
1912
+ {
1913
+ messages: commentMessages,
1914
+ isStreaming,
1915
+ startedToolIds,
1916
+ completedToolIds,
1917
+ todos
1918
+ }
1919
+ ),
1920
+ showPRBlock && /* @__PURE__ */ jsxRuntime.jsx(PRBlock, { onCancel: handlePRCancel })
1921
+ ] })
1574
1922
  ] }),
1575
- commentMessages.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "chat-panel-empty-content", children: /* @__PURE__ */ jsxRuntime.jsx(
1923
+ commentMessages.length === 0 && !showPRBlock && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "chat-panel-empty-content", children: /* @__PURE__ */ jsxRuntime.jsx(
1576
1924
  MessageList,
1577
1925
  {
1578
1926
  messages: [],
@@ -1649,6 +1997,16 @@ function ChatPanel({
1649
1997
  title: "Select Text",
1650
1998
  children: /* @__PURE__ */ jsxRuntime.jsx(Type, { size: 16 })
1651
1999
  }
2000
+ ),
2001
+ /* @__PURE__ */ jsxRuntime.jsx(
2002
+ "button",
2003
+ {
2004
+ className: `tool-button ${showPRBlock ? "active" : ""}`,
2005
+ onClick: () => setShowPRBlock(!showPRBlock),
2006
+ disabled: !hasChanges || prLoading,
2007
+ title: prButtonTitle,
2008
+ children: /* @__PURE__ */ jsxRuntime.jsx(GitPullRequest, { size: 16 })
2009
+ }
1652
2010
  )
1653
2011
  ] }),
1654
2012
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2110,9 +2468,162 @@ function EditorOverlay({ theme, onComponentSelect }) {
2110
2468
  }
2111
2469
  );
2112
2470
  }
2471
+ function PRView({ onClose, onSuccess }) {
2472
+ const [title, setTitle] = react.useState("");
2473
+ const [description, setDescription] = react.useState("");
2474
+ const [error, setError] = react.useState(null);
2475
+ const [result, setResult] = react.useState(null);
2476
+ const hasGenerated = react.useRef(false);
2477
+ const { status } = usePRStatus();
2478
+ const { createPR, generateContent, isCreating, isGenerating } = useCreatePR();
2479
+ react.useEffect(() => {
2480
+ if (!hasGenerated.current && !isGenerating) {
2481
+ hasGenerated.current = true;
2482
+ generateContent().then((content) => {
2483
+ setTitle(content.title);
2484
+ setDescription(content.description);
2485
+ });
2486
+ }
2487
+ }, [isGenerating, generateContent]);
2488
+ react.useEffect(() => {
2489
+ if (result == null ? void 0 : result.success) {
2490
+ const timer = setTimeout(() => {
2491
+ onClose();
2492
+ }, 2e3);
2493
+ return () => clearTimeout(timer);
2494
+ }
2495
+ }, [result == null ? void 0 : result.success, onClose]);
2496
+ const handleRegenerate = react.useCallback(async () => {
2497
+ setError(null);
2498
+ const content = await generateContent();
2499
+ setTitle(content.title);
2500
+ setDescription(content.description);
2501
+ }, [generateContent]);
2502
+ const handleSubmit = react.useCallback(async () => {
2503
+ if (!title.trim()) {
2504
+ setError("Title is required");
2505
+ return;
2506
+ }
2507
+ setError(null);
2508
+ const prResult = await createPR({ title: title.trim(), description });
2509
+ if (prResult.success) {
2510
+ setResult(prResult);
2511
+ onSuccess == null ? void 0 : onSuccess(prResult);
2512
+ } else {
2513
+ setError(prResult.error || "Failed to create PR");
2514
+ }
2515
+ }, [title, description, createPR, onSuccess]);
2516
+ if (result == null ? void 0 : result.success) {
2517
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pr-view", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-view-success", children: [
2518
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pr-view-success-icon", children: /* @__PURE__ */ jsxRuntime.jsx(Check, { size: 32 }) }),
2519
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { children: "PR Created!" }),
2520
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
2521
+ /* @__PURE__ */ jsxRuntime.jsxs("a", { href: result.prUrl, target: "_blank", rel: "noopener noreferrer", children: [
2522
+ "#",
2523
+ result.prNumber
2524
+ ] }),
2525
+ " ",
2526
+ "on ",
2527
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: result.branchName })
2528
+ ] })
2529
+ ] }) });
2530
+ }
2531
+ if (isGenerating && !title) {
2532
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pr-view", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-view-loading", children: [
2533
+ /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 24, className: "pr-view-spinner" }),
2534
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Generating PR details..." })
2535
+ ] }) });
2536
+ }
2537
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-view", children: [
2538
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-view-content", children: [
2539
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pr-view-error", children: error }),
2540
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-view-field", children: [
2541
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "pr-title", children: "Title" }),
2542
+ /* @__PURE__ */ jsxRuntime.jsx(
2543
+ "input",
2544
+ {
2545
+ id: "pr-title",
2546
+ type: "text",
2547
+ value: title,
2548
+ onChange: (e) => setTitle(e.target.value),
2549
+ placeholder: "PR title...",
2550
+ disabled: isCreating || isGenerating
2551
+ }
2552
+ )
2553
+ ] }),
2554
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-view-field", children: [
2555
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-view-field-header", children: [
2556
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "pr-description", children: "Description" }),
2557
+ /* @__PURE__ */ jsxRuntime.jsxs(
2558
+ "button",
2559
+ {
2560
+ className: "pr-view-regenerate",
2561
+ onClick: handleRegenerate,
2562
+ disabled: isGenerating || isCreating,
2563
+ children: [
2564
+ isGenerating ? /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 12, className: "pr-view-spinner" }) : /* @__PURE__ */ jsxRuntime.jsx(Sparkles, { size: 12 }),
2565
+ "Regenerate"
2566
+ ]
2567
+ }
2568
+ )
2569
+ ] }),
2570
+ /* @__PURE__ */ jsxRuntime.jsx(
2571
+ "textarea",
2572
+ {
2573
+ id: "pr-description",
2574
+ value: description,
2575
+ onChange: (e) => setDescription(e.target.value),
2576
+ placeholder: "Describe your changes...",
2577
+ disabled: isCreating || isGenerating
2578
+ }
2579
+ )
2580
+ ] }),
2581
+ status && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-view-info", children: [
2582
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2583
+ /* @__PURE__ */ jsxRuntime.jsx(FileText, { size: 12 }),
2584
+ status.changedFiles.length,
2585
+ " files"
2586
+ ] }),
2587
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2588
+ /* @__PURE__ */ jsxRuntime.jsx(GitBranch, { size: 12 }),
2589
+ status.baseBranch
2590
+ ] })
2591
+ ] })
2592
+ ] }),
2593
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pr-view-footer", children: [
2594
+ /* @__PURE__ */ jsxRuntime.jsx(
2595
+ "button",
2596
+ {
2597
+ className: "pr-view-btn pr-view-btn-secondary",
2598
+ onClick: onClose,
2599
+ disabled: isCreating,
2600
+ children: "Cancel"
2601
+ }
2602
+ ),
2603
+ /* @__PURE__ */ jsxRuntime.jsx(
2604
+ "button",
2605
+ {
2606
+ className: "pr-view-btn pr-view-btn-primary",
2607
+ onClick: handleSubmit,
2608
+ disabled: isCreating || !title.trim(),
2609
+ children: isCreating ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2610
+ /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 14, className: "pr-view-spinner" }),
2611
+ "Creating..."
2612
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2613
+ /* @__PURE__ */ jsxRuntime.jsx(GitPullRequest, { size: 14 }),
2614
+ "Create PR"
2615
+ ] })
2616
+ }
2617
+ )
2618
+ ] })
2619
+ ] });
2620
+ }
2113
2621
  exports.AIEditorProvider = AIEditorProvider;
2114
2622
  exports.ChatPanel = ChatPanel;
2115
2623
  exports.ControlPill = ControlPill;
2624
+ exports.PRView = PRView;
2116
2625
  exports.buildServiceUrl = buildServiceUrl;
2117
2626
  exports.getServiceUrl = getServiceUrl;
2627
+ exports.useCreatePR = useCreatePR;
2628
+ exports.usePRStatus = usePRStatus;
2118
2629
  //# sourceMappingURL=index.cjs.map