zephex 2.1.1 → 2.1.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 +49 -285
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -195,16 +195,13 @@ var require_picocolors = __commonJS((exports, module) => {
|
|
|
195
195
|
});
|
|
196
196
|
|
|
197
197
|
// src/cli.ts
|
|
198
|
-
import { fileURLToPath as
|
|
198
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
199
199
|
import { resolve, dirname } from "path";
|
|
200
200
|
|
|
201
201
|
// src/commands/setup.ts
|
|
202
|
-
import http from "node:http";
|
|
203
|
-
import crypto from "node:crypto";
|
|
204
202
|
import fs7 from "node:fs";
|
|
205
203
|
import path3 from "node:path";
|
|
206
204
|
import os3 from "node:os";
|
|
207
|
-
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
208
205
|
import { spawnSync } from "node:child_process";
|
|
209
206
|
|
|
210
207
|
// node_modules/.bun/@clack+prompts@0.9.1/node_modules/@clack/prompts/dist/index.mjs
|
|
@@ -1423,38 +1420,10 @@ async function runSkills(argv) {
|
|
|
1423
1420
|
}
|
|
1424
1421
|
|
|
1425
1422
|
// src/commands/setup.ts
|
|
1426
|
-
var
|
|
1427
|
-
function getCliVersion() {
|
|
1428
|
-
if (CACHED_CLI_VERSION !== null)
|
|
1429
|
-
return CACHED_CLI_VERSION;
|
|
1430
|
-
try {
|
|
1431
|
-
const here = fileURLToPath2(import.meta.url);
|
|
1432
|
-
let dir = path3.dirname(here);
|
|
1433
|
-
for (let depth = 0;depth < 6; depth++) {
|
|
1434
|
-
const candidate = path3.join(dir, "package.json");
|
|
1435
|
-
if (fs7.existsSync(candidate)) {
|
|
1436
|
-
const json = JSON.parse(fs7.readFileSync(candidate, "utf8"));
|
|
1437
|
-
if (json.name === "zephex" && typeof json.version === "string") {
|
|
1438
|
-
CACHED_CLI_VERSION = json.version;
|
|
1439
|
-
return CACHED_CLI_VERSION;
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
const parent = path3.dirname(dir);
|
|
1443
|
-
if (parent === dir)
|
|
1444
|
-
break;
|
|
1445
|
-
dir = parent;
|
|
1446
|
-
}
|
|
1447
|
-
} catch {}
|
|
1448
|
-
CACHED_CLI_VERSION = "unknown";
|
|
1449
|
-
return CACHED_CLI_VERSION;
|
|
1450
|
-
}
|
|
1451
|
-
var DEFAULT_AUTH0_CLI_CLIENT_ID = process.env.AUTH0_CLI_CLIENT_ID ?? "AUTH0_CLI_CLIENT_ID_NOT_SET";
|
|
1452
|
-
var DEFAULT_AUTH0_DOMAIN = "zephex.us.auth0.com";
|
|
1453
|
-
var DEFAULT_AUTH0_AUDIENCE = "https://zephex.dev/mcp";
|
|
1423
|
+
var DEFAULT_AUTH0_CLI_CLIENT_ID = process.env.AUTH0_CLI_CLIENT_ID ?? "2JrCMEKyOdY1YDZxInqTamSGNSCX9DaS";
|
|
1454
1424
|
var ZEPHEX_API_BASE = "https://zephex.dev";
|
|
1455
1425
|
var ZEPHEX_MCP_URL = "https://zephex.dev/mcp";
|
|
1456
1426
|
var DASHBOARD_KEYS_URL = "https://zephex.dev/dashboard/keys";
|
|
1457
|
-
var CALLBACK_PORTS = [52748, 52749, 52750];
|
|
1458
1427
|
function parseFlags2(argv) {
|
|
1459
1428
|
let mode = null;
|
|
1460
1429
|
let editor = null;
|
|
@@ -1577,257 +1546,55 @@ function prettyPath2(absPath) {
|
|
|
1577
1546
|
}
|
|
1578
1547
|
return absPath;
|
|
1579
1548
|
}
|
|
1580
|
-
function
|
|
1581
|
-
|
|
1582
|
-
}
|
|
1583
|
-
function base64urlDecode(input) {
|
|
1584
|
-
const pad = input.length % 4 === 0 ? "" : "=".repeat(4 - input.length % 4);
|
|
1585
|
-
const normalized = input.replace(/-/g, "+").replace(/_/g, "/") + pad;
|
|
1586
|
-
return Buffer.from(normalized, "base64");
|
|
1587
|
-
}
|
|
1588
|
-
function generatePkce() {
|
|
1589
|
-
const verifier = base64url(crypto.randomBytes(32));
|
|
1590
|
-
const challenge = base64url(crypto.createHash("sha256").update(verifier).digest());
|
|
1591
|
-
return { verifier, challenge };
|
|
1592
|
-
}
|
|
1593
|
-
function decodeJwtEmail(token) {
|
|
1594
|
-
try {
|
|
1595
|
-
const parts = token.split(".");
|
|
1596
|
-
if (parts.length < 2)
|
|
1597
|
-
return null;
|
|
1598
|
-
const payloadStr = base64urlDecode(parts[1] ?? "").toString("utf8");
|
|
1599
|
-
const payload = JSON.parse(payloadStr);
|
|
1600
|
-
const email = payload["email"];
|
|
1601
|
-
if (typeof email === "string" && email.length > 0)
|
|
1602
|
-
return email;
|
|
1603
|
-
return null;
|
|
1604
|
-
} catch {
|
|
1605
|
-
return null;
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
var SUCCESS_HTML = `<!DOCTYPE html>
|
|
1609
|
-
<html>
|
|
1610
|
-
<head>
|
|
1611
|
-
<title>Zephex Connected</title>
|
|
1612
|
-
<style>
|
|
1613
|
-
body { background: #0f0f13; color: #e0e0e0; font-family: ui-sans-serif, system-ui, sans-serif;
|
|
1614
|
-
display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
|
|
1615
|
-
.box { text-align: center; }
|
|
1616
|
-
.check { font-size: 48px; color: #7c3aed; margin-bottom: 16px; }
|
|
1617
|
-
h1 { font-size: 24px; margin: 0 0 8px; }
|
|
1618
|
-
p { color: #888; margin: 0; }
|
|
1619
|
-
</style>
|
|
1620
|
-
</head>
|
|
1621
|
-
<body>
|
|
1622
|
-
<div class="box">
|
|
1623
|
-
<div class="check">✓</div>
|
|
1624
|
-
<h1>You're connected to Zephex</h1>
|
|
1625
|
-
<p>You can close this tab and return to your terminal.</p>
|
|
1626
|
-
</div>
|
|
1627
|
-
</body>
|
|
1628
|
-
</html>`;
|
|
1629
|
-
function errorHtml(message) {
|
|
1630
|
-
return `<!DOCTYPE html>
|
|
1631
|
-
<html>
|
|
1632
|
-
<head>
|
|
1633
|
-
<title>Zephex — Login failed</title>
|
|
1634
|
-
<style>
|
|
1635
|
-
body { background: #0f0f13; color: #e0e0e0; font-family: ui-sans-serif, system-ui, sans-serif;
|
|
1636
|
-
display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
|
|
1637
|
-
.box { text-align: center; max-width: 480px; padding: 0 24px; }
|
|
1638
|
-
.x { font-size: 48px; color: #dc2626; margin-bottom: 16px; }
|
|
1639
|
-
h1 { font-size: 24px; margin: 0 0 8px; }
|
|
1640
|
-
p { color: #888; margin: 0; }
|
|
1641
|
-
</style>
|
|
1642
|
-
</head>
|
|
1643
|
-
<body>
|
|
1644
|
-
<div class="box">
|
|
1645
|
-
<div class="x">✕</div>
|
|
1646
|
-
<h1>Login failed</h1>
|
|
1647
|
-
<p>${escapeHtml(message)}</p>
|
|
1648
|
-
</div>
|
|
1649
|
-
</body>
|
|
1650
|
-
</html>`;
|
|
1651
|
-
}
|
|
1652
|
-
async function startCallbackServer(expectedState) {
|
|
1653
|
-
let lastErr = null;
|
|
1654
|
-
for (const port of CALLBACK_PORTS) {
|
|
1655
|
-
try {
|
|
1656
|
-
const server = http.createServer();
|
|
1657
|
-
await new Promise((resolve, reject) => {
|
|
1658
|
-
const onError = (err) => {
|
|
1659
|
-
server.removeListener("listening", onListen);
|
|
1660
|
-
reject(err);
|
|
1661
|
-
};
|
|
1662
|
-
const onListen = () => {
|
|
1663
|
-
server.removeListener("error", onError);
|
|
1664
|
-
resolve();
|
|
1665
|
-
};
|
|
1666
|
-
server.once("error", onError);
|
|
1667
|
-
server.once("listening", onListen);
|
|
1668
|
-
server.listen(port, "127.0.0.1");
|
|
1669
|
-
});
|
|
1670
|
-
const result = new Promise((resolve, reject) => {
|
|
1671
|
-
server.on("request", (req, res) => {
|
|
1672
|
-
if (!req.url) {
|
|
1673
|
-
res.writeHead(400).end();
|
|
1674
|
-
return;
|
|
1675
|
-
}
|
|
1676
|
-
const reqUrl = new URL(req.url, `http://127.0.0.1:${port}`);
|
|
1677
|
-
if (reqUrl.pathname !== "/callback") {
|
|
1678
|
-
res.writeHead(404, { "Content-Type": "text/plain" }).end("Not found");
|
|
1679
|
-
return;
|
|
1680
|
-
}
|
|
1681
|
-
const code = reqUrl.searchParams.get("code");
|
|
1682
|
-
const state = reqUrl.searchParams.get("state");
|
|
1683
|
-
const errParam = reqUrl.searchParams.get("error");
|
|
1684
|
-
const errDesc = reqUrl.searchParams.get("error_description");
|
|
1685
|
-
if (errParam) {
|
|
1686
|
-
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" }).end(errorHtml(errDesc ?? errParam));
|
|
1687
|
-
reject(new Error(`Auth0 returned error: ${errParam}${errDesc ? ` (${errDesc})` : ""}`));
|
|
1688
|
-
return;
|
|
1689
|
-
}
|
|
1690
|
-
if (!code || !state) {
|
|
1691
|
-
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" }).end(errorHtml("Missing authorization code or state."));
|
|
1692
|
-
reject(new Error("Missing code or state on callback"));
|
|
1693
|
-
return;
|
|
1694
|
-
}
|
|
1695
|
-
if (state !== expectedState) {
|
|
1696
|
-
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" }).end(errorHtml("Invalid state — possible CSRF."));
|
|
1697
|
-
reject(new Error("OAuth state mismatch — possible CSRF; aborting"));
|
|
1698
|
-
return;
|
|
1699
|
-
}
|
|
1700
|
-
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }).end(SUCCESS_HTML);
|
|
1701
|
-
resolve({ code, state });
|
|
1702
|
-
});
|
|
1703
|
-
});
|
|
1704
|
-
return {
|
|
1705
|
-
port,
|
|
1706
|
-
waitForCallback: () => result,
|
|
1707
|
-
close: () => {
|
|
1708
|
-
server.close();
|
|
1709
|
-
}
|
|
1710
|
-
};
|
|
1711
|
-
} catch (err) {
|
|
1712
|
-
const e2 = err;
|
|
1713
|
-
lastErr = e2 instanceof Error ? e2 : new Error(String(e2));
|
|
1714
|
-
if (e2?.code !== "EADDRINUSE") {
|
|
1715
|
-
throw lastErr;
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
}
|
|
1719
|
-
throw new Error(`Could not bind any local callback port (${CALLBACK_PORTS.join(", ")}). ${lastErr?.message ?? ""}`.trim());
|
|
1720
|
-
}
|
|
1721
|
-
function escapeHtml(value) {
|
|
1722
|
-
return value.replace(/[&<>"']/g, (ch) => {
|
|
1723
|
-
switch (ch) {
|
|
1724
|
-
case "&":
|
|
1725
|
-
return "&";
|
|
1726
|
-
case "<":
|
|
1727
|
-
return "<";
|
|
1728
|
-
case ">":
|
|
1729
|
-
return ">";
|
|
1730
|
-
case '"':
|
|
1731
|
-
return """;
|
|
1732
|
-
case "'":
|
|
1733
|
-
return "'";
|
|
1734
|
-
default:
|
|
1735
|
-
return ch;
|
|
1736
|
-
}
|
|
1737
|
-
});
|
|
1738
|
-
}
|
|
1739
|
-
async function exchangeCodeForToken(params) {
|
|
1740
|
-
const resp = await fetch(`https://${params.domain}/oauth/token`, {
|
|
1549
|
+
async function loginAndGetApiKey(editor) {
|
|
1550
|
+
const sessionResp = await fetch(`${ZEPHEX_API_BASE}/api/cli/session`, {
|
|
1741
1551
|
method: "POST",
|
|
1742
|
-
headers: { "Content-Type": "application/json" }
|
|
1743
|
-
body: JSON.stringify({
|
|
1744
|
-
grant_type: "authorization_code",
|
|
1745
|
-
client_id: params.clientId,
|
|
1746
|
-
code_verifier: params.verifier,
|
|
1747
|
-
code: params.code,
|
|
1748
|
-
redirect_uri: params.redirectUri
|
|
1749
|
-
})
|
|
1552
|
+
headers: { "Content-Type": "application/json" }
|
|
1750
1553
|
});
|
|
1751
|
-
if (!
|
|
1752
|
-
|
|
1753
|
-
throw new Error(`Token exchange failed (${resp.status}): ${text || resp.statusText}`);
|
|
1754
|
-
}
|
|
1755
|
-
const json = await resp.json();
|
|
1756
|
-
if (!json.access_token || typeof json.access_token !== "string") {
|
|
1757
|
-
throw new Error("Token response missing access_token");
|
|
1554
|
+
if (!sessionResp.ok) {
|
|
1555
|
+
throw new Error("Failed to start auth session. Is zephex.dev reachable?");
|
|
1758
1556
|
}
|
|
1759
|
-
|
|
1760
|
-
}
|
|
1761
|
-
|
|
1762
|
-
const clientId = process.env["AUTH0_CLI_CLIENT_ID"] || DEFAULT_AUTH0_CLI_CLIENT_ID;
|
|
1763
|
-
const domain = process.env["AUTH0_DOMAIN"] || DEFAULT_AUTH0_DOMAIN;
|
|
1764
|
-
const audience = process.env["AUTH0_AUDIENCE"] || DEFAULT_AUTH0_AUDIENCE;
|
|
1765
|
-
const { verifier, challenge } = generatePkce();
|
|
1766
|
-
const state = base64url(crypto.randomBytes(16));
|
|
1767
|
-
const callback = await startCallbackServer(state);
|
|
1557
|
+
const { session_id } = await sessionResp.json();
|
|
1558
|
+
const authUrl = `${ZEPHEX_API_BASE}/cli/auth?session=${encodeURIComponent(session_id)}`;
|
|
1559
|
+
ye("Opening zephex.dev in your browser...", "Sign in");
|
|
1768
1560
|
try {
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
async function provisionCliKey(accessToken, editor) {
|
|
1803
|
-
const cliVersion = getCliVersion();
|
|
1804
|
-
const resp = await fetch(`${ZEPHEX_API_BASE}/api/cli/create-key`, {
|
|
1805
|
-
method: "POST",
|
|
1806
|
-
headers: {
|
|
1807
|
-
"Content-Type": "application/json",
|
|
1808
|
-
Authorization: `Bearer ${accessToken}`,
|
|
1809
|
-
"X-Zephex-CLI-Version": cliVersion,
|
|
1810
|
-
"X-Zephex-Editor": editor,
|
|
1811
|
-
"User-Agent": `zephex-cli/${cliVersion} (${process.platform}; node-${process.versions.node})`
|
|
1812
|
-
},
|
|
1813
|
-
body: JSON.stringify({ editor })
|
|
1814
|
-
});
|
|
1815
|
-
if (!resp.ok) {
|
|
1816
|
-
let detail = "";
|
|
1817
|
-
try {
|
|
1818
|
-
const body = await resp.json();
|
|
1819
|
-
if (body && typeof body.error === "string")
|
|
1820
|
-
detail = body.error;
|
|
1821
|
-
} catch {
|
|
1822
|
-
detail = await resp.text().catch(() => "");
|
|
1561
|
+
await open_default(authUrl);
|
|
1562
|
+
} catch {
|
|
1563
|
+
v2.message(`If your browser didn't open, paste this URL:
|
|
1564
|
+
${authUrl}`);
|
|
1565
|
+
}
|
|
1566
|
+
const sp = L2();
|
|
1567
|
+
sp.start("Waiting for you to sign in...");
|
|
1568
|
+
const POLL_INTERVAL = 2000;
|
|
1569
|
+
const TIMEOUT = 5 * 60 * 1000;
|
|
1570
|
+
const start = Date.now();
|
|
1571
|
+
try {
|
|
1572
|
+
while (Date.now() - start < TIMEOUT) {
|
|
1573
|
+
await new Promise((r2) => setTimeout(r2, POLL_INTERVAL));
|
|
1574
|
+
const pollResp = await fetch(`${ZEPHEX_API_BASE}/api/cli/poll?session=${encodeURIComponent(session_id)}`);
|
|
1575
|
+
if (pollResp.status === 410) {
|
|
1576
|
+
throw new Error("Session expired. Please try again.");
|
|
1577
|
+
}
|
|
1578
|
+
if (!pollResp.ok && pollResp.status !== 200) {
|
|
1579
|
+
continue;
|
|
1580
|
+
}
|
|
1581
|
+
const data = await pollResp.json();
|
|
1582
|
+
if (data.status === "complete" && data.key && data.name) {
|
|
1583
|
+
sp.stop("Signed in");
|
|
1584
|
+
return {
|
|
1585
|
+
keyInfo: { key: data.key, name: data.name, created: new Date().toISOString() },
|
|
1586
|
+
email: data.email ?? null
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1589
|
+
if (data.status === "error") {
|
|
1590
|
+
throw new Error(data.error || "Authentication failed on server");
|
|
1591
|
+
}
|
|
1823
1592
|
}
|
|
1824
|
-
throw new Error(
|
|
1825
|
-
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
throw new Error("create-key returned an unexpected response shape");
|
|
1593
|
+
throw new Error("Timed out waiting for sign-in (5 minutes). Please try again.");
|
|
1594
|
+
} catch (err) {
|
|
1595
|
+
sp.stop("Sign-in failed");
|
|
1596
|
+
throw err;
|
|
1829
1597
|
}
|
|
1830
|
-
return { key: json.key, name: json.name, created: json.created };
|
|
1831
1598
|
}
|
|
1832
1599
|
function readJsonFile(filePath) {
|
|
1833
1600
|
if (!fs7.existsSync(filePath))
|
|
@@ -2161,14 +1928,11 @@ async function runSetup(argv) {
|
|
|
2161
1928
|
return;
|
|
2162
1929
|
}
|
|
2163
1930
|
const resolvedClientId = process.env["AUTH0_CLI_CLIENT_ID"] || DEFAULT_AUTH0_CLI_CLIENT_ID;
|
|
2164
|
-
if (!resolvedClientId
|
|
1931
|
+
if (!resolvedClientId) {
|
|
2165
1932
|
process.stderr.write(`
|
|
2166
1933
|
Error: AUTH0_CLI_CLIENT_ID is not configured.
|
|
2167
|
-
` +
|
|
2168
|
-
` + `
|
|
2169
|
-
` + ` • Application type: Native
|
|
2170
|
-
` + ` • Allowed Callback URLs: http://localhost:52748/callback, http://localhost:52749/callback, http://localhost:52750/callback
|
|
2171
|
-
` + ` • Token Endpoint Auth Method: None
|
|
1934
|
+
` + `This should not happen with the published package. Report this at:
|
|
1935
|
+
` + ` https://github.com/zephex/mcp-proxy/issues
|
|
2172
1936
|
|
|
2173
1937
|
`);
|
|
2174
1938
|
process.exit(1);
|
|
@@ -2557,7 +2321,7 @@ if (subcommand === "skills") {
|
|
|
2557
2321
|
process.exit(0);
|
|
2558
2322
|
}
|
|
2559
2323
|
var { spawn } = await import("node:child_process");
|
|
2560
|
-
var __filename2 =
|
|
2324
|
+
var __filename2 = fileURLToPath2(import.meta.url);
|
|
2561
2325
|
var __dirname3 = dirname(__filename2);
|
|
2562
2326
|
var serverPath = resolve(__dirname3, "tools/server.js");
|
|
2563
2327
|
var child = spawn(process.execPath, [serverPath], {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zephex",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "Zephex MCP — codebase intelligence tools for AI coding agents. stdio server that runs locally, reads your project files, and proxies AI calls to the Zephex backend.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cli.js",
|