openmagic 0.36.1 → 0.36.3
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/cli.js +191 -31
- package/dist/cli.js.map +1 -1
- package/dist/toolbar/index.global.js +1 -1
- package/dist/toolbar/index.global.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1532,13 +1532,21 @@ async function chatClaudeCode(messages, context, onChunk, onDone, onError) {
|
|
|
1532
1532
|
"--output-format",
|
|
1533
1533
|
"stream-json",
|
|
1534
1534
|
"--verbose",
|
|
1535
|
+
"--include-partial-messages",
|
|
1535
1536
|
"--max-turns",
|
|
1536
|
-
"
|
|
1537
|
-
// Single turn — OpenMagic manages its own retry loop
|
|
1537
|
+
"5"
|
|
1538
1538
|
],
|
|
1539
1539
|
{
|
|
1540
1540
|
stdio: ["pipe", "pipe", "pipe"],
|
|
1541
|
-
cwd: process.cwd()
|
|
1541
|
+
cwd: process.cwd(),
|
|
1542
|
+
env: {
|
|
1543
|
+
...process.env,
|
|
1544
|
+
// Generous timeouts — Claude may read files and think between turns
|
|
1545
|
+
CLAUDE_STREAM_IDLE_TIMEOUT_MS: "300000",
|
|
1546
|
+
// 5 min idle timeout between chunks
|
|
1547
|
+
API_TIMEOUT_MS: "600000"
|
|
1548
|
+
// 10 min overall API timeout
|
|
1549
|
+
}
|
|
1542
1550
|
}
|
|
1543
1551
|
);
|
|
1544
1552
|
proc.stdin.write(`${SYSTEM_PROMPT}
|
|
@@ -1546,6 +1554,7 @@ async function chatClaudeCode(messages, context, onChunk, onDone, onError) {
|
|
|
1546
1554
|
${fullPrompt}`);
|
|
1547
1555
|
proc.stdin.end();
|
|
1548
1556
|
let fullContent = "";
|
|
1557
|
+
let resultContent = "";
|
|
1549
1558
|
let buffer = "";
|
|
1550
1559
|
let errOutput = "";
|
|
1551
1560
|
proc.stdout.on("data", (data) => {
|
|
@@ -1556,6 +1565,12 @@ ${fullPrompt}`);
|
|
|
1556
1565
|
if (!line.trim()) continue;
|
|
1557
1566
|
try {
|
|
1558
1567
|
const event = JSON.parse(line);
|
|
1568
|
+
if (event.type === "result") {
|
|
1569
|
+
if (typeof event.result === "string") {
|
|
1570
|
+
resultContent = event.result;
|
|
1571
|
+
}
|
|
1572
|
+
continue;
|
|
1573
|
+
}
|
|
1559
1574
|
const text = extractText(event);
|
|
1560
1575
|
if (text) {
|
|
1561
1576
|
fullContent += text;
|
|
@@ -1581,20 +1596,22 @@ ${fullPrompt}`);
|
|
|
1581
1596
|
if (buffer.trim()) {
|
|
1582
1597
|
try {
|
|
1583
1598
|
const event = JSON.parse(buffer);
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1599
|
+
if (event.type === "result" && typeof event.result === "string") {
|
|
1600
|
+
resultContent = event.result;
|
|
1601
|
+
} else {
|
|
1602
|
+
const text = extractText(event);
|
|
1603
|
+
if (text) fullContent += text;
|
|
1588
1604
|
}
|
|
1589
1605
|
} catch {
|
|
1590
1606
|
}
|
|
1591
1607
|
}
|
|
1592
|
-
|
|
1593
|
-
|
|
1608
|
+
const finalContent = resultContent || fullContent;
|
|
1609
|
+
if (code === 0 || finalContent) {
|
|
1610
|
+
onDone({ content: finalContent });
|
|
1594
1611
|
} else {
|
|
1595
1612
|
const err = errOutput.trim();
|
|
1596
1613
|
if (err.includes("not authenticated") || err.includes("login")) {
|
|
1597
|
-
onError("Claude CLI is not authenticated. Run `claude
|
|
1614
|
+
onError("Claude CLI is not authenticated. Run `claude` in your terminal to log in.");
|
|
1598
1615
|
} else if (err.includes("ENOENT") || err.includes("not found")) {
|
|
1599
1616
|
onError("Claude CLI not found. Install it with: npm install -g @anthropic-ai/claude-code");
|
|
1600
1617
|
} else {
|
|
@@ -1630,16 +1647,35 @@ async function chatCodexCli(messages, context, onChunk, onDone, onError) {
|
|
|
1630
1647
|
const fullPrompt = `${SYSTEM_PROMPT}
|
|
1631
1648
|
|
|
1632
1649
|
${buildUserMessage(userPrompt, contextParts)}`;
|
|
1633
|
-
const proc = spawn2(
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1650
|
+
const proc = spawn2(
|
|
1651
|
+
"codex",
|
|
1652
|
+
["exec", "--full-auto", "--json", "--skip-git-repo-check", "-"],
|
|
1653
|
+
{
|
|
1654
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1655
|
+
cwd: process.cwd()
|
|
1656
|
+
}
|
|
1657
|
+
);
|
|
1658
|
+
proc.stdin.write(fullPrompt);
|
|
1659
|
+
proc.stdin.end();
|
|
1637
1660
|
let fullContent = "";
|
|
1661
|
+
let buffer = "";
|
|
1638
1662
|
let errOutput = "";
|
|
1639
1663
|
proc.stdout.on("data", (data) => {
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1664
|
+
buffer += data.toString();
|
|
1665
|
+
const lines = buffer.split("\n");
|
|
1666
|
+
buffer = lines.pop() || "";
|
|
1667
|
+
for (const line of lines) {
|
|
1668
|
+
if (!line.trim()) continue;
|
|
1669
|
+
try {
|
|
1670
|
+
const event = JSON.parse(line);
|
|
1671
|
+
const text = extractCodexText(event);
|
|
1672
|
+
if (text) {
|
|
1673
|
+
fullContent += text;
|
|
1674
|
+
onChunk(text);
|
|
1675
|
+
}
|
|
1676
|
+
} catch {
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1643
1679
|
});
|
|
1644
1680
|
proc.stderr.on("data", (data) => {
|
|
1645
1681
|
errOutput += data.toString();
|
|
@@ -1652,7 +1688,15 @@ ${buildUserMessage(userPrompt, contextParts)}`;
|
|
|
1652
1688
|
}
|
|
1653
1689
|
});
|
|
1654
1690
|
proc.on("close", (code) => {
|
|
1655
|
-
if (
|
|
1691
|
+
if (buffer.trim()) {
|
|
1692
|
+
try {
|
|
1693
|
+
const event = JSON.parse(buffer);
|
|
1694
|
+
const text = extractCodexText(event);
|
|
1695
|
+
if (text) fullContent += text;
|
|
1696
|
+
} catch {
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
if (code === 0 || fullContent.trim()) {
|
|
1656
1700
|
onDone({ content: fullContent });
|
|
1657
1701
|
} else {
|
|
1658
1702
|
const err = errOutput.trim();
|
|
@@ -1664,6 +1708,18 @@ ${buildUserMessage(userPrompt, contextParts)}`;
|
|
|
1664
1708
|
}
|
|
1665
1709
|
});
|
|
1666
1710
|
}
|
|
1711
|
+
function extractCodexText(event) {
|
|
1712
|
+
if (event.type === "item.completed" || event.type === "item.updated" || event.type === "item.started") {
|
|
1713
|
+
const item = event.item;
|
|
1714
|
+
if (item?.type === "agent_message" && typeof item.text === "string") {
|
|
1715
|
+
return item.text;
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
if (event.type === "error" && typeof event.message === "string") {
|
|
1719
|
+
return void 0;
|
|
1720
|
+
}
|
|
1721
|
+
return void 0;
|
|
1722
|
+
}
|
|
1667
1723
|
|
|
1668
1724
|
// src/llm/gemini-cli.ts
|
|
1669
1725
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -1674,18 +1730,55 @@ async function chatGeminiCli(messages, context, onChunk, onDone, onError) {
|
|
|
1674
1730
|
const fullPrompt = `${SYSTEM_PROMPT}
|
|
1675
1731
|
|
|
1676
1732
|
${buildUserMessage(userPrompt, contextParts)}`;
|
|
1677
|
-
const proc = spawn3(
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1733
|
+
const proc = spawn3(
|
|
1734
|
+
"gemini",
|
|
1735
|
+
[
|
|
1736
|
+
"-p",
|
|
1737
|
+
userPrompt,
|
|
1738
|
+
"--output-format",
|
|
1739
|
+
"stream-json",
|
|
1740
|
+
"--yolo"
|
|
1741
|
+
],
|
|
1742
|
+
{
|
|
1743
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1744
|
+
cwd: process.cwd()
|
|
1745
|
+
}
|
|
1746
|
+
);
|
|
1747
|
+
proc.stdin.write(`${SYSTEM_PROMPT}
|
|
1748
|
+
|
|
1749
|
+
${buildUserMessage("", contextParts)}`);
|
|
1682
1750
|
proc.stdin.end();
|
|
1683
1751
|
let fullContent = "";
|
|
1752
|
+
let resultContent = "";
|
|
1753
|
+
let buffer = "";
|
|
1684
1754
|
let errOutput = "";
|
|
1685
1755
|
proc.stdout.on("data", (data) => {
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1756
|
+
buffer += data.toString();
|
|
1757
|
+
const lines = buffer.split("\n");
|
|
1758
|
+
buffer = lines.pop() || "";
|
|
1759
|
+
for (const line of lines) {
|
|
1760
|
+
if (!line.trim()) continue;
|
|
1761
|
+
try {
|
|
1762
|
+
const event = JSON.parse(line);
|
|
1763
|
+
if (event.type === "result") {
|
|
1764
|
+
if (typeof event.result === "string") {
|
|
1765
|
+
resultContent = event.result;
|
|
1766
|
+
}
|
|
1767
|
+
continue;
|
|
1768
|
+
}
|
|
1769
|
+
const text = extractGeminiText(event);
|
|
1770
|
+
if (text) {
|
|
1771
|
+
fullContent += text;
|
|
1772
|
+
onChunk(text);
|
|
1773
|
+
}
|
|
1774
|
+
} catch {
|
|
1775
|
+
const trimmed = line.trim();
|
|
1776
|
+
if (trimmed) {
|
|
1777
|
+
fullContent += trimmed + "\n";
|
|
1778
|
+
onChunk(trimmed + "\n");
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1689
1782
|
});
|
|
1690
1783
|
proc.stderr.on("data", (data) => {
|
|
1691
1784
|
errOutput += data.toString();
|
|
@@ -1698,18 +1791,48 @@ ${buildUserMessage(userPrompt, contextParts)}`;
|
|
|
1698
1791
|
}
|
|
1699
1792
|
});
|
|
1700
1793
|
proc.on("close", (code) => {
|
|
1701
|
-
if (
|
|
1702
|
-
|
|
1794
|
+
if (buffer.trim()) {
|
|
1795
|
+
try {
|
|
1796
|
+
const event = JSON.parse(buffer);
|
|
1797
|
+
if (event.type === "result" && typeof event.result === "string") {
|
|
1798
|
+
resultContent = event.result;
|
|
1799
|
+
} else {
|
|
1800
|
+
const text = extractGeminiText(event);
|
|
1801
|
+
if (text) fullContent += text;
|
|
1802
|
+
}
|
|
1803
|
+
} catch {
|
|
1804
|
+
const trimmed = buffer.trim();
|
|
1805
|
+
if (trimmed) fullContent += trimmed;
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
const finalContent = resultContent || fullContent;
|
|
1809
|
+
if (code === 0 || finalContent.trim()) {
|
|
1810
|
+
onDone({ content: finalContent });
|
|
1703
1811
|
} else {
|
|
1704
1812
|
const err = errOutput.trim();
|
|
1705
|
-
if (err.includes("auth") || err.includes("
|
|
1706
|
-
onError("Gemini CLI requires
|
|
1813
|
+
if (err.includes("auth") || err.includes("GEMINI_API_KEY") || err.includes("credentials") || err.includes("login")) {
|
|
1814
|
+
onError("Gemini CLI requires authentication. Set GEMINI_API_KEY in your environment, or run `gemini` interactively to log in with Google.");
|
|
1707
1815
|
} else {
|
|
1708
1816
|
onError(err.slice(0, 500) || `Gemini CLI exited with code ${code}`);
|
|
1709
1817
|
}
|
|
1710
1818
|
}
|
|
1711
1819
|
});
|
|
1712
1820
|
}
|
|
1821
|
+
function extractGeminiText(event) {
|
|
1822
|
+
if (event.type === "assistant" || event.type === "message") {
|
|
1823
|
+
const content = event.content ?? event.message?.content;
|
|
1824
|
+
if (Array.isArray(content)) {
|
|
1825
|
+
return content.filter((b) => b.type === "text" && b.text).map((b) => b.text).join("");
|
|
1826
|
+
}
|
|
1827
|
+
if (typeof content === "string") return content;
|
|
1828
|
+
if (typeof event.text === "string") return event.text;
|
|
1829
|
+
}
|
|
1830
|
+
if (event.type === "content_block_delta") {
|
|
1831
|
+
const delta = event.delta;
|
|
1832
|
+
if (typeof delta?.text === "string") return delta.text;
|
|
1833
|
+
}
|
|
1834
|
+
return void 0;
|
|
1835
|
+
}
|
|
1713
1836
|
|
|
1714
1837
|
// src/llm/proxy.ts
|
|
1715
1838
|
var OPENAI_COMPATIBLE_PROVIDERS = /* @__PURE__ */ new Set([
|
|
@@ -2863,12 +2986,49 @@ program.name("openmagic").description("AI-powered coding toolbar for any web app
|
|
|
2863
2986
|
});
|
|
2864
2987
|
}
|
|
2865
2988
|
});
|
|
2989
|
+
let shuttingDown = false;
|
|
2866
2990
|
const shutdown = () => {
|
|
2991
|
+
if (shuttingDown) return;
|
|
2992
|
+
shuttingDown = true;
|
|
2867
2993
|
console.log("");
|
|
2868
2994
|
console.log(chalk.dim(" Shutting down OpenMagic..."));
|
|
2869
2995
|
cleanupBackups();
|
|
2870
2996
|
proxyServer.close();
|
|
2871
|
-
|
|
2997
|
+
for (const cp of childProcesses) {
|
|
2998
|
+
try {
|
|
2999
|
+
cp.kill("SIGTERM");
|
|
3000
|
+
} catch {
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
const forceExit = setTimeout(() => {
|
|
3004
|
+
for (const cp of childProcesses) {
|
|
3005
|
+
try {
|
|
3006
|
+
cp.kill("SIGKILL");
|
|
3007
|
+
} catch {
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
process.exit(0);
|
|
3011
|
+
}, 2e3);
|
|
3012
|
+
forceExit.unref();
|
|
3013
|
+
const allDead = childProcesses.every((cp) => cp.killed || cp.exitCode !== null);
|
|
3014
|
+
if (allDead) {
|
|
3015
|
+
clearTimeout(forceExit);
|
|
3016
|
+
process.exit(0);
|
|
3017
|
+
}
|
|
3018
|
+
let remaining = childProcesses.filter((cp) => !cp.killed && cp.exitCode === null).length;
|
|
3019
|
+
if (remaining === 0) {
|
|
3020
|
+
clearTimeout(forceExit);
|
|
3021
|
+
process.exit(0);
|
|
3022
|
+
}
|
|
3023
|
+
for (const cp of childProcesses) {
|
|
3024
|
+
cp.once("exit", () => {
|
|
3025
|
+
remaining--;
|
|
3026
|
+
if (remaining <= 0) {
|
|
3027
|
+
clearTimeout(forceExit);
|
|
3028
|
+
process.exit(0);
|
|
3029
|
+
}
|
|
3030
|
+
});
|
|
3031
|
+
}
|
|
2872
3032
|
};
|
|
2873
3033
|
process.on("SIGINT", shutdown);
|
|
2874
3034
|
process.on("SIGTERM", shutdown);
|