@aident-ai/cli 0.3.1 → 0.3.2-rc.ci.37567087135.1
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/README.md +10 -0
- package/dist/cli.mjs +313 -84
- package/dist/dsh.mjs +947 -906
- package/package.json +2 -2
package/dist/dsh.mjs
CHANGED
|
@@ -2542,552 +2542,6 @@ function readLine(prompt, options = {}) {
|
|
|
2542
2542
|
});
|
|
2543
2543
|
}
|
|
2544
2544
|
|
|
2545
|
-
// src/auth.ts
|
|
2546
|
-
var CLIENT_NAME = "aident-cli";
|
|
2547
|
-
var LOOPBACK_HOST = "127.0.0.1";
|
|
2548
|
-
var LOGIN_OPEN_TIMEOUT_MS = 90 * 1000;
|
|
2549
|
-
var LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS = 30 * 60 * 1000;
|
|
2550
|
-
var LOGIN_OPENED_MESSAGE = `User opened the Aident login window. They have ${LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS / 60000} minutes to finish; if it fails, run \`aident login --oob\`, share the URL, and ask for the verification code.`;
|
|
2551
|
-
async function login(options) {
|
|
2552
|
-
const baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
2553
|
-
const writeInfo = options.format === "json" ? logErr : logInfo;
|
|
2554
|
-
if (options.oob)
|
|
2555
|
-
return loginOob(baseUrl, writeInfo, options.format === "json" ? process.stderr : process.stdout, options.ref);
|
|
2556
|
-
try {
|
|
2557
|
-
return await loginLoopback(baseUrl, writeInfo, options.ref);
|
|
2558
|
-
} catch (err) {
|
|
2559
|
-
logErr(`Loopback OAuth failed (${err instanceof Error ? err.message : String(err)}). Falling back to OOB flow.`);
|
|
2560
|
-
return loginOob(baseUrl, writeInfo, options.format === "json" ? process.stderr : process.stdout, options.ref);
|
|
2561
|
-
}
|
|
2562
|
-
}
|
|
2563
|
-
async function refreshToken(creds) {
|
|
2564
|
-
if (!creds.refresh_token || !creds.client_id)
|
|
2565
|
-
return null;
|
|
2566
|
-
const baseUrl = creds.base_url.replace(/\/+$/, "");
|
|
2567
|
-
const body = new URLSearchParams({
|
|
2568
|
-
grant_type: "refresh_token",
|
|
2569
|
-
client_id: creds.client_id,
|
|
2570
|
-
refresh_token: creds.refresh_token
|
|
2571
|
-
});
|
|
2572
|
-
const res = await fetch(`${baseUrl}/api/mcp/oauth/token`, {
|
|
2573
|
-
method: "POST",
|
|
2574
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
2575
|
-
body
|
|
2576
|
-
});
|
|
2577
|
-
if (!res.ok)
|
|
2578
|
-
return null;
|
|
2579
|
-
const tok = await res.json();
|
|
2580
|
-
return updateCredsFromToken(creds, tok);
|
|
2581
|
-
}
|
|
2582
|
-
async function logout(creds) {
|
|
2583
|
-
const baseUrl = creds.base_url.replace(/\/+$/, "");
|
|
2584
|
-
await fetch(`${baseUrl}/api/mcp/oauth/revoke`, {
|
|
2585
|
-
method: "POST",
|
|
2586
|
-
headers: {
|
|
2587
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
2588
|
-
Authorization: `Bearer ${creds.access_token}`
|
|
2589
|
-
},
|
|
2590
|
-
body: new URLSearchParams({ token: creds.access_token })
|
|
2591
|
-
}).catch(() => {
|
|
2592
|
-
return;
|
|
2593
|
-
});
|
|
2594
|
-
}
|
|
2595
|
-
async function loginLoopback(baseUrl, writeInfo, ref) {
|
|
2596
|
-
const verifier = base64UrlEncode(randomBytes(48));
|
|
2597
|
-
const challenge = base64UrlEncode(createHash("sha256").update(verifier).digest());
|
|
2598
|
-
const state = base64UrlEncode(randomBytes(16));
|
|
2599
|
-
const { server, port, codePromise, setExpectedOpenRedirectUrl } = await startCallbackServer(state, writeInfo);
|
|
2600
|
-
const redirectUri = `http://${LOOPBACK_HOST}:${port}/callback`;
|
|
2601
|
-
const clientId = await registerClient(baseUrl, [redirectUri]);
|
|
2602
|
-
const authorizeUrl = new URL(`${baseUrl}/api/mcp/oauth/authorize`);
|
|
2603
|
-
authorizeUrl.searchParams.set("response_type", "code");
|
|
2604
|
-
authorizeUrl.searchParams.set("client_id", clientId);
|
|
2605
|
-
authorizeUrl.searchParams.set("redirect_uri", redirectUri);
|
|
2606
|
-
authorizeUrl.searchParams.set("redirect_uri_exact", base64UrlEncode(Buffer.from(redirectUri, "utf8")));
|
|
2607
|
-
authorizeUrl.searchParams.set("code_challenge", challenge);
|
|
2608
|
-
authorizeUrl.searchParams.set("code_challenge_method", "S256");
|
|
2609
|
-
authorizeUrl.searchParams.set("state", state);
|
|
2610
|
-
if (ref)
|
|
2611
|
-
authorizeUrl.searchParams.set("via", ref);
|
|
2612
|
-
const authorizeUrlString = authorizeUrl.toString();
|
|
2613
|
-
setExpectedOpenRedirectUrl(authorizeUrlString);
|
|
2614
|
-
const loginOpenUrl = buildLoginOpenUrl(port, state, authorizeUrlString);
|
|
2615
|
-
writeInfo(`Opening browser for Aident login...`);
|
|
2616
|
-
writeInfo(`If the browser does not open, visit: ${authorizeUrlString}`);
|
|
2617
|
-
openExternalUrl(shouldUseLoopbackBrowserHandoff() ? loginOpenUrl : authorizeUrlString);
|
|
2618
|
-
let code;
|
|
2619
|
-
try {
|
|
2620
|
-
code = await codePromise;
|
|
2621
|
-
} finally {
|
|
2622
|
-
closeServer(server);
|
|
2623
|
-
}
|
|
2624
|
-
const tok = await exchangeCode(baseUrl, clientId, code, redirectUri, verifier);
|
|
2625
|
-
return buildCreds(baseUrl, clientId, tok);
|
|
2626
|
-
}
|
|
2627
|
-
async function loginOob(baseUrl, writeInfo, promptOutput, ref) {
|
|
2628
|
-
const redirectUri = `${baseUrl}/mcp/oob`;
|
|
2629
|
-
const verifier = base64UrlEncode(randomBytes(48));
|
|
2630
|
-
const challenge = base64UrlEncode(createHash("sha256").update(verifier).digest());
|
|
2631
|
-
const state = base64UrlEncode(randomBytes(16));
|
|
2632
|
-
let clientId = "";
|
|
2633
|
-
let valueToExchange = "";
|
|
2634
|
-
try {
|
|
2635
|
-
clientId = await registerClient(baseUrl, [redirectUri]);
|
|
2636
|
-
const authorizeUrl = new URL(`${baseUrl}/api/mcp/oauth/authorize`);
|
|
2637
|
-
authorizeUrl.searchParams.set("response_type", "code");
|
|
2638
|
-
authorizeUrl.searchParams.set("client_id", clientId);
|
|
2639
|
-
authorizeUrl.searchParams.set("redirect_uri", redirectUri);
|
|
2640
|
-
authorizeUrl.searchParams.set("code_challenge", challenge);
|
|
2641
|
-
authorizeUrl.searchParams.set("code_challenge_method", "S256");
|
|
2642
|
-
authorizeUrl.searchParams.set("state", state);
|
|
2643
|
-
if (ref)
|
|
2644
|
-
authorizeUrl.searchParams.set("via", ref);
|
|
2645
|
-
const authorizeUrlString = authorizeUrl.toString();
|
|
2646
|
-
writeInfo(`Opening browser for Aident login...`);
|
|
2647
|
-
writeInfo(`If the browser does not open, visit: ${authorizeUrlString}`);
|
|
2648
|
-
openExternalUrl(authorizeUrlString);
|
|
2649
|
-
writeInfo("After approving, paste the 8-digit verification code shown on the Aident page below.");
|
|
2650
|
-
const pastedInput = await readLine("Paste 8-digit code here: ", {
|
|
2651
|
-
output: promptOutput,
|
|
2652
|
-
timeoutMs: LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS,
|
|
2653
|
-
timeoutMessage: `Verification code not received within ${LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS / 1000}s; aborting.`
|
|
2654
|
-
});
|
|
2655
|
-
valueToExchange = normalizeOobLoginInput(pastedInput);
|
|
2656
|
-
if (!valueToExchange)
|
|
2657
|
-
throw new Error("No verification code provided");
|
|
2658
|
-
if (!/^\d{8}$/.test(valueToExchange) && !looksLikeAccessToken(valueToExchange)) {
|
|
2659
|
-
throw new Error("Pasted value is not a valid 8-digit verification code. Please retry the login.");
|
|
2660
|
-
}
|
|
2661
|
-
const tok = await exchangeCode(baseUrl, clientId, valueToExchange, redirectUri, verifier);
|
|
2662
|
-
return buildCreds(baseUrl, clientId, tok);
|
|
2663
|
-
} catch (err) {
|
|
2664
|
-
if (err instanceof OAuthRejectedError) {
|
|
2665
|
-
if (!looksLikeAccessToken(valueToExchange)) {
|
|
2666
|
-
throw new Error("Pasted verification code was rejected by the server. Please retry the login.");
|
|
2667
|
-
}
|
|
2668
|
-
logErr(`Server rejected the pasted value as an authorization code. Treating it as a raw access token. Note: token refresh is unavailable in this mode — when the token expires you'll need to run \`aident login\` again.`);
|
|
2669
|
-
return { base_url: baseUrl, client_id: clientId, access_token: valueToExchange };
|
|
2670
|
-
}
|
|
2671
|
-
throw err;
|
|
2672
|
-
}
|
|
2673
|
-
}
|
|
2674
|
-
function normalizeVerificationCodeInput(value) {
|
|
2675
|
-
return value.trim().replace(/[\s-]+/g, "");
|
|
2676
|
-
}
|
|
2677
|
-
function normalizeOobLoginInput(value) {
|
|
2678
|
-
const verificationCode = normalizeVerificationCodeInput(value);
|
|
2679
|
-
if (/^\d{8}$/.test(verificationCode))
|
|
2680
|
-
return verificationCode;
|
|
2681
|
-
return value.trim().replace(/\s+/g, "");
|
|
2682
|
-
}
|
|
2683
|
-
function looksLikeAccessToken(value) {
|
|
2684
|
-
if (value.length < 20)
|
|
2685
|
-
return false;
|
|
2686
|
-
if (/\s/.test(value))
|
|
2687
|
-
return false;
|
|
2688
|
-
return /^[A-Za-z0-9._-]+$/.test(value);
|
|
2689
|
-
}
|
|
2690
|
-
async function registerClient(baseUrl, redirectUris) {
|
|
2691
|
-
const res = await fetch(`${baseUrl}/api/mcp/oauth/register`, {
|
|
2692
|
-
method: "POST",
|
|
2693
|
-
headers: { "Content-Type": "application/json" },
|
|
2694
|
-
body: JSON.stringify({
|
|
2695
|
-
client_name: CLIENT_NAME,
|
|
2696
|
-
redirect_uris: redirectUris,
|
|
2697
|
-
grant_types: ["authorization_code", "refresh_token"],
|
|
2698
|
-
response_types: ["code"],
|
|
2699
|
-
token_endpoint_auth_method: "none"
|
|
2700
|
-
})
|
|
2701
|
-
});
|
|
2702
|
-
if (!res.ok) {
|
|
2703
|
-
const text = await res.text().catch(() => "");
|
|
2704
|
-
throw new Error(`Failed to register OAuth client (HTTP ${res.status}): ${text}`);
|
|
2705
|
-
}
|
|
2706
|
-
const json = await res.json();
|
|
2707
|
-
if (!json.client_id)
|
|
2708
|
-
throw new Error("OAuth registration response missing client_id");
|
|
2709
|
-
return json.client_id;
|
|
2710
|
-
}
|
|
2711
|
-
|
|
2712
|
-
class OAuthRejectedError extends Error {
|
|
2713
|
-
status;
|
|
2714
|
-
constructor(message, status) {
|
|
2715
|
-
super(message);
|
|
2716
|
-
this.status = status;
|
|
2717
|
-
this.name = "OAuthRejectedError";
|
|
2718
|
-
}
|
|
2719
|
-
}
|
|
2720
|
-
async function exchangeCode(baseUrl, clientId, code, redirectUri, verifier) {
|
|
2721
|
-
const body = new URLSearchParams({
|
|
2722
|
-
grant_type: "authorization_code",
|
|
2723
|
-
client_id: clientId,
|
|
2724
|
-
code,
|
|
2725
|
-
redirect_uri: redirectUri,
|
|
2726
|
-
code_verifier: verifier
|
|
2727
|
-
});
|
|
2728
|
-
const res = await fetch(`${baseUrl}/api/mcp/oauth/token`, {
|
|
2729
|
-
method: "POST",
|
|
2730
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
2731
|
-
body
|
|
2732
|
-
});
|
|
2733
|
-
if (!res.ok) {
|
|
2734
|
-
const text = await res.text().catch(() => "");
|
|
2735
|
-
if (res.status >= 400 && res.status < 500) {
|
|
2736
|
-
throw new OAuthRejectedError(`Token exchange rejected (HTTP ${res.status}): ${text}`, res.status);
|
|
2737
|
-
}
|
|
2738
|
-
throw new Error(`Token exchange failed (HTTP ${res.status}): ${text}`);
|
|
2739
|
-
}
|
|
2740
|
-
return await res.json();
|
|
2741
|
-
}
|
|
2742
|
-
function buildCreds(baseUrl, clientId, tok) {
|
|
2743
|
-
const expiresAt = tok.expires_in ? new Date(Date.now() + tok.expires_in * 1000).toISOString() : undefined;
|
|
2744
|
-
return {
|
|
2745
|
-
base_url: baseUrl,
|
|
2746
|
-
client_id: clientId,
|
|
2747
|
-
access_token: tok.access_token,
|
|
2748
|
-
refresh_token: tok.refresh_token,
|
|
2749
|
-
expires_at: expiresAt
|
|
2750
|
-
};
|
|
2751
|
-
}
|
|
2752
|
-
function updateCredsFromToken(creds, tok) {
|
|
2753
|
-
const expiresAt = tok.expires_in ? new Date(Date.now() + tok.expires_in * 1000).toISOString() : creds.expires_at;
|
|
2754
|
-
return {
|
|
2755
|
-
...creds,
|
|
2756
|
-
access_token: tok.access_token,
|
|
2757
|
-
refresh_token: tok.refresh_token ?? creds.refresh_token,
|
|
2758
|
-
expires_at: expiresAt
|
|
2759
|
-
};
|
|
2760
|
-
}
|
|
2761
|
-
function startCallbackServer(expectedState, writeInfo = logInfo) {
|
|
2762
|
-
return new Promise((resolve, reject) => {
|
|
2763
|
-
let codeResolver = () => {
|
|
2764
|
-
return;
|
|
2765
|
-
};
|
|
2766
|
-
let codeRejecter = () => {
|
|
2767
|
-
return;
|
|
2768
|
-
};
|
|
2769
|
-
let opened = false;
|
|
2770
|
-
let expectedOpenRedirectUrl = "";
|
|
2771
|
-
let completeTimeout;
|
|
2772
|
-
const codePromise = new Promise((res, rej) => {
|
|
2773
|
-
codeResolver = res;
|
|
2774
|
-
codeRejecter = rej;
|
|
2775
|
-
});
|
|
2776
|
-
const scheduleCompleteTimeout = (timeoutMs, message) => {
|
|
2777
|
-
if (completeTimeout)
|
|
2778
|
-
clearTimeout(completeTimeout);
|
|
2779
|
-
completeTimeout = setTimeout(() => codeRejecter(new Error(message)), timeoutMs);
|
|
2780
|
-
};
|
|
2781
|
-
const openTimeout = setTimeout(() => {
|
|
2782
|
-
if (!opened) {
|
|
2783
|
-
writeInfo(`Login window open signal not received within ${LOGIN_OPEN_TIMEOUT_MS / 1000}s; still waiting for login to finish.`);
|
|
2784
|
-
}
|
|
2785
|
-
}, LOGIN_OPEN_TIMEOUT_MS);
|
|
2786
|
-
scheduleCompleteTimeout(LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS, `Authorization callback not received within ${LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS / 1000}s; aborting.`);
|
|
2787
|
-
codePromise.then(() => {
|
|
2788
|
-
clearTimeout(openTimeout);
|
|
2789
|
-
if (completeTimeout)
|
|
2790
|
-
clearTimeout(completeTimeout);
|
|
2791
|
-
}, () => {
|
|
2792
|
-
clearTimeout(openTimeout);
|
|
2793
|
-
if (completeTimeout)
|
|
2794
|
-
clearTimeout(completeTimeout);
|
|
2795
|
-
});
|
|
2796
|
-
const markOpened = () => {
|
|
2797
|
-
if (opened)
|
|
2798
|
-
return;
|
|
2799
|
-
opened = true;
|
|
2800
|
-
clearTimeout(openTimeout);
|
|
2801
|
-
writeInfo(LOGIN_OPENED_MESSAGE);
|
|
2802
|
-
const timeoutMs = LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS;
|
|
2803
|
-
scheduleCompleteTimeout(timeoutMs, `Login page opened but did not complete within ${timeoutMs / 1000}s; aborting.`);
|
|
2804
|
-
};
|
|
2805
|
-
const server = createServer((req, res) => {
|
|
2806
|
-
runLocalCallbackHandler(req, res, () => {
|
|
2807
|
-
if (!req.url) {
|
|
2808
|
-
res.writeHead(400);
|
|
2809
|
-
res.end("Bad request");
|
|
2810
|
-
return;
|
|
2811
|
-
}
|
|
2812
|
-
const url = new URL(req.url, `http://${LOOPBACK_HOST}`);
|
|
2813
|
-
if (handleOpenRedirect(url, res, expectedState, expectedOpenRedirectUrl, markOpened))
|
|
2814
|
-
return;
|
|
2815
|
-
if (url.pathname !== "/callback") {
|
|
2816
|
-
res.writeHead(404);
|
|
2817
|
-
res.end("Not found");
|
|
2818
|
-
return;
|
|
2819
|
-
}
|
|
2820
|
-
const code = url.searchParams.get("code");
|
|
2821
|
-
const state = url.searchParams.get("state");
|
|
2822
|
-
const error = url.searchParams.get("error");
|
|
2823
|
-
if (error) {
|
|
2824
|
-
res.writeHead(400, { "Content-Type": "text/html" });
|
|
2825
|
-
res.end(`<html><body><h2>Authentication error</h2><p>${escapeHtml(error)}</p></body></html>`);
|
|
2826
|
-
codeRejecter(new Error(`OAuth error: ${error}`));
|
|
2827
|
-
return;
|
|
2828
|
-
}
|
|
2829
|
-
if (!code || state !== expectedState) {
|
|
2830
|
-
res.writeHead(400, { "Content-Type": "text/html" });
|
|
2831
|
-
res.end("<html><body><h2>Invalid callback</h2></body></html>");
|
|
2832
|
-
codeRejecter(new Error("Invalid callback (missing code or bad state)"));
|
|
2833
|
-
return;
|
|
2834
|
-
}
|
|
2835
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
2836
|
-
res.end(`<html><body style="font-family:system-ui;padding:40px;text-align:center"><h2>You're signed in.</h2><p>You can close this window and return to the terminal.</p></body></html>`);
|
|
2837
|
-
codeResolver(code);
|
|
2838
|
-
}, codeRejecter);
|
|
2839
|
-
});
|
|
2840
|
-
server.once("error", reject);
|
|
2841
|
-
server.listen(0, LOOPBACK_HOST, () => {
|
|
2842
|
-
const addr = server.address();
|
|
2843
|
-
resolve({
|
|
2844
|
-
server,
|
|
2845
|
-
port: addr.port,
|
|
2846
|
-
codePromise,
|
|
2847
|
-
setExpectedOpenRedirectUrl: (url) => {
|
|
2848
|
-
expectedOpenRedirectUrl = url;
|
|
2849
|
-
}
|
|
2850
|
-
});
|
|
2851
|
-
});
|
|
2852
|
-
});
|
|
2853
|
-
}
|
|
2854
|
-
function handleOpenRedirect(url, res, expectedState, expectedOpenRedirectUrl, onOpened) {
|
|
2855
|
-
if (url.pathname !== "/open")
|
|
2856
|
-
return false;
|
|
2857
|
-
if (url.searchParams.get("state") !== expectedState) {
|
|
2858
|
-
res.writeHead(400);
|
|
2859
|
-
res.end("Bad request");
|
|
2860
|
-
return true;
|
|
2861
|
-
}
|
|
2862
|
-
const nextUrl = url.searchParams.get("next");
|
|
2863
|
-
if (!expectedOpenRedirectUrl || !nextUrl || nextUrl !== expectedOpenRedirectUrl) {
|
|
2864
|
-
res.writeHead(400);
|
|
2865
|
-
res.end("Bad request");
|
|
2866
|
-
return true;
|
|
2867
|
-
}
|
|
2868
|
-
try {
|
|
2869
|
-
onOpened();
|
|
2870
|
-
} catch {
|
|
2871
|
-
res.writeHead(500);
|
|
2872
|
-
res.end("Internal callback error");
|
|
2873
|
-
return true;
|
|
2874
|
-
}
|
|
2875
|
-
res.writeHead(302, { Location: nextUrl });
|
|
2876
|
-
res.end();
|
|
2877
|
-
return true;
|
|
2878
|
-
}
|
|
2879
|
-
function runLocalCallbackHandler(req, res, handle, onAuthCallbackError) {
|
|
2880
|
-
try {
|
|
2881
|
-
handle();
|
|
2882
|
-
} catch (err) {
|
|
2883
|
-
if (!res.writableEnded) {
|
|
2884
|
-
if (!res.headersSent)
|
|
2885
|
-
res.writeHead(500);
|
|
2886
|
-
res.end("Internal callback error");
|
|
2887
|
-
}
|
|
2888
|
-
if (isAuthCallbackRequest(req.url))
|
|
2889
|
-
onAuthCallbackError?.(toError(err));
|
|
2890
|
-
}
|
|
2891
|
-
}
|
|
2892
|
-
function isAuthCallbackRequest(url) {
|
|
2893
|
-
if (!url)
|
|
2894
|
-
return false;
|
|
2895
|
-
try {
|
|
2896
|
-
return new URL(url, `http://${LOOPBACK_HOST}`).pathname === "/callback";
|
|
2897
|
-
} catch {
|
|
2898
|
-
return false;
|
|
2899
|
-
}
|
|
2900
|
-
}
|
|
2901
|
-
function toError(err) {
|
|
2902
|
-
return err instanceof Error ? err : new Error(String(err));
|
|
2903
|
-
}
|
|
2904
|
-
function closeServer(server) {
|
|
2905
|
-
server.close();
|
|
2906
|
-
server.closeIdleConnections?.();
|
|
2907
|
-
server.closeAllConnections?.();
|
|
2908
|
-
}
|
|
2909
|
-
function buildLoginOpenUrl(port, state, authorizeUrl) {
|
|
2910
|
-
const url = new URL(`http://${LOOPBACK_HOST}:${port}/open`);
|
|
2911
|
-
url.searchParams.set("state", state);
|
|
2912
|
-
url.searchParams.set("next", authorizeUrl);
|
|
2913
|
-
return url.toString();
|
|
2914
|
-
}
|
|
2915
|
-
function shouldUseLoopbackBrowserHandoff(env = process.env) {
|
|
2916
|
-
return !isRemoteSessionEnvironment(env);
|
|
2917
|
-
}
|
|
2918
|
-
function isRemoteSessionEnvironment(env = process.env) {
|
|
2919
|
-
return Boolean(env.SSH_CONNECTION || env.SSH_TTY || env.CODESPACES || env.REMOTE_CONTAINERS || env.DEVCONTAINER);
|
|
2920
|
-
}
|
|
2921
|
-
function base64UrlEncode(buf) {
|
|
2922
|
-
return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
2923
|
-
}
|
|
2924
|
-
function escapeHtml(s) {
|
|
2925
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
2926
|
-
}
|
|
2927
|
-
|
|
2928
|
-
// src/catalogCache.ts
|
|
2929
|
-
import crypto from "node:crypto";
|
|
2930
|
-
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
2931
|
-
import { join as join2 } from "node:path";
|
|
2932
|
-
|
|
2933
|
-
// src/config.ts
|
|
2934
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2935
|
-
import { homedir } from "node:os";
|
|
2936
|
-
import { dirname, join } from "node:path";
|
|
2937
|
-
|
|
2938
|
-
// src/packages.ts
|
|
2939
|
-
var CLI_PACKAGES = ["loadout", "playbook", "intern"];
|
|
2940
|
-
var DEFAULT_CLI_PACKAGES = ["loadout"];
|
|
2941
|
-
function parseCliPackage(value) {
|
|
2942
|
-
if (typeof value !== "string")
|
|
2943
|
-
throw new Error(`Unsupported Aident package: ${String(value)}`);
|
|
2944
|
-
const normalized = value.trim().toLowerCase();
|
|
2945
|
-
if (!CLI_PACKAGES.includes(normalized))
|
|
2946
|
-
throw new Error(`Unsupported Aident package: ${value}`);
|
|
2947
|
-
return normalized;
|
|
2948
|
-
}
|
|
2949
|
-
function normalizeCliPackages(value) {
|
|
2950
|
-
const rawPackages = value === undefined || value === null || value === "" ? [] : Array.isArray(value) ? value : String(value).split(/[,\s]+/);
|
|
2951
|
-
const packages = ["loadout"];
|
|
2952
|
-
for (const rawPackage of rawPackages) {
|
|
2953
|
-
if (rawPackage === undefined || rawPackage === null || rawPackage === "")
|
|
2954
|
-
continue;
|
|
2955
|
-
const cliPackage = parseCliPackage(rawPackage);
|
|
2956
|
-
if (!packages.includes(cliPackage))
|
|
2957
|
-
packages.push(cliPackage);
|
|
2958
|
-
}
|
|
2959
|
-
return packages;
|
|
2960
|
-
}
|
|
2961
|
-
function formatCliPackages(packages) {
|
|
2962
|
-
return packages.join(",");
|
|
2963
|
-
}
|
|
2964
|
-
|
|
2965
|
-
// ../web/shared/env/loadoutHostPairs.json
|
|
2966
|
-
var loadoutHostPairs_default = [
|
|
2967
|
-
{
|
|
2968
|
-
appHost: "app.aident.ai",
|
|
2969
|
-
loadoutHost: "loadout.aident.ai"
|
|
2970
|
-
},
|
|
2971
|
-
{
|
|
2972
|
-
appHost: "staging.app.aident.ai",
|
|
2973
|
-
loadoutHost: "staging.loadout.aident.ai"
|
|
2974
|
-
},
|
|
2975
|
-
{
|
|
2976
|
-
appHost: "rc.app.aident.ai",
|
|
2977
|
-
loadoutHost: "rc.loadout.aident.ai"
|
|
2978
|
-
}
|
|
2979
|
-
];
|
|
2980
|
-
|
|
2981
|
-
// ../web/shared/env/loadoutHosts.ts
|
|
2982
|
-
var LOADOUT_PRODUCTION_HOST = "loadout.aident.ai";
|
|
2983
|
-
var LOADOUT_STAGING_HOST = "staging.loadout.aident.ai";
|
|
2984
|
-
var LOADOUT_PREVIEW_HOST = "rc.loadout.aident.ai";
|
|
2985
|
-
var LOADOUT_CUSTOM_HOSTS = [LOADOUT_PRODUCTION_HOST, LOADOUT_STAGING_HOST, LOADOUT_PREVIEW_HOST];
|
|
2986
|
-
var LOADOUT_HOST_BY_AIDENT_APP_HOST = Object.fromEntries(loadoutHostPairs_default.map(({ appHost, loadoutHost }) => [appHost, loadoutHost]));
|
|
2987
|
-
var AIDENT_PUBLIC_HOSTS = new Set(["aident.ai", "www.aident.ai"]);
|
|
2988
|
-
function getLoadoutHostname(host) {
|
|
2989
|
-
return (host ?? "").split(":")[0]?.toLowerCase() ?? "";
|
|
2990
|
-
}
|
|
2991
|
-
function isLoadoutCustomHost(host) {
|
|
2992
|
-
const hostname = getLoadoutHostname(host);
|
|
2993
|
-
return LOADOUT_CUSTOM_HOSTS.some((candidate) => candidate === hostname) || /^pr-\d+-loadout\.prebuilt\.aident\.ai$/.test(hostname);
|
|
2994
|
-
}
|
|
2995
|
-
function isTrustedAidentHttpsUrl(value) {
|
|
2996
|
-
try {
|
|
2997
|
-
const url = value instanceof URL ? value : new URL(value);
|
|
2998
|
-
const hostname = url.hostname.toLowerCase();
|
|
2999
|
-
return url.protocol === "https:" && url.port === "" && url.username === "" && url.password === "" && (hostname === "aident.ai" || hostname.endsWith(".aident.ai"));
|
|
3000
|
-
} catch {
|
|
3001
|
-
return false;
|
|
3002
|
-
}
|
|
3003
|
-
}
|
|
3004
|
-
function getLoadoutHostForAidentAppHost(host) {
|
|
3005
|
-
const hostname = getLoadoutHostname(host);
|
|
3006
|
-
return LOADOUT_HOST_BY_AIDENT_APP_HOST[hostname] ?? null;
|
|
3007
|
-
}
|
|
3008
|
-
function getCanonicalLoadoutHost(host) {
|
|
3009
|
-
const hostname = getLoadoutHostname(host);
|
|
3010
|
-
return getLoadoutHostForAidentAppHost(hostname) ?? (isLoadoutCustomHost(hostname) ? hostname : null);
|
|
3011
|
-
}
|
|
3012
|
-
function getLoadoutHostForLegacyAidentHost(host) {
|
|
3013
|
-
const hostname = getLoadoutHostname(host);
|
|
3014
|
-
return AIDENT_PUBLIC_HOSTS.has(hostname) ? LOADOUT_PRODUCTION_HOST : getCanonicalLoadoutHost(hostname);
|
|
3015
|
-
}
|
|
3016
|
-
|
|
3017
|
-
// src/config.ts
|
|
3018
|
-
function getAidentDir(home = process.env.HOME || process.env.USERPROFILE || homedir()) {
|
|
3019
|
-
return join(home, ".aident");
|
|
3020
|
-
}
|
|
3021
|
-
function getConfigFile() {
|
|
3022
|
-
return join(getAidentDir(), "config.json");
|
|
3023
|
-
}
|
|
3024
|
-
function getConfigFileForHome(home) {
|
|
3025
|
-
return join(getAidentDir(home), "config.json");
|
|
3026
|
-
}
|
|
3027
|
-
var DEFAULT_BASE_URL = "https://loadout.aident.ai"?.trim() || "https://loadout.aident.ai";
|
|
3028
|
-
var CONFIG_KEYS = ["baseUrl", "packages"];
|
|
3029
|
-
async function readConfig(configFile = getConfigFile()) {
|
|
3030
|
-
try {
|
|
3031
|
-
const text = await readFile(configFile, "utf-8");
|
|
3032
|
-
const parsed = JSON.parse(text);
|
|
3033
|
-
if (!parsed || typeof parsed !== "object")
|
|
3034
|
-
return {};
|
|
3035
|
-
if (typeof parsed.baseUrl === "string")
|
|
3036
|
-
parsed.baseUrl = normalizeBaseUrl(parsed.baseUrl);
|
|
3037
|
-
return parsed;
|
|
3038
|
-
} catch {
|
|
3039
|
-
return {};
|
|
3040
|
-
}
|
|
3041
|
-
}
|
|
3042
|
-
async function writeConfig(config, configFile = getConfigFile()) {
|
|
3043
|
-
await mkdir(dirname(configFile), { recursive: true, mode: 448 });
|
|
3044
|
-
await writeFile(configFile, JSON.stringify(config, null, 2) + `
|
|
3045
|
-
`, { mode: 420 });
|
|
3046
|
-
}
|
|
3047
|
-
async function setConfigValue(key, value, configFile = getConfigFile()) {
|
|
3048
|
-
const config = await readConfig(configFile);
|
|
3049
|
-
config[key] = value;
|
|
3050
|
-
await writeConfig(config, configFile);
|
|
3051
|
-
}
|
|
3052
|
-
async function unsetConfigValue(key) {
|
|
3053
|
-
const config = await readConfig();
|
|
3054
|
-
delete config[key];
|
|
3055
|
-
await writeConfig(config);
|
|
3056
|
-
}
|
|
3057
|
-
async function resolveDefaultBaseUrl() {
|
|
3058
|
-
const env = process.env.AIDENT_BASE_URL?.trim();
|
|
3059
|
-
if (env)
|
|
3060
|
-
return normalizeBaseUrl(env);
|
|
3061
|
-
const config = await readConfig();
|
|
3062
|
-
if (typeof config.baseUrl === "string" && config.baseUrl.trim() !== "") {
|
|
3063
|
-
return normalizeBaseUrl(config.baseUrl);
|
|
3064
|
-
}
|
|
3065
|
-
return DEFAULT_BASE_URL;
|
|
3066
|
-
}
|
|
3067
|
-
async function resolveDefaultPackages() {
|
|
3068
|
-
const env = process.env.AIDENT_PACKAGES?.trim() || process.env.AIDENT_PACKAGE?.trim();
|
|
3069
|
-
if (env)
|
|
3070
|
-
return normalizeCliPackages(env);
|
|
3071
|
-
const config = await readConfig();
|
|
3072
|
-
return normalizeCliPackages(config.packages ?? DEFAULT_CLI_PACKAGES);
|
|
3073
|
-
}
|
|
3074
|
-
async function resolveOriginClientName() {
|
|
3075
|
-
const config = await readConfig();
|
|
3076
|
-
return typeof config.originClientName === "string" && config.originClientName.trim() ? config.originClientName.trim() : null;
|
|
3077
|
-
}
|
|
3078
|
-
function isKnownConfigKey(key) {
|
|
3079
|
-
return CONFIG_KEYS.includes(key);
|
|
3080
|
-
}
|
|
3081
|
-
function normalizeBaseUrl(url) {
|
|
3082
|
-
let trimmed = url.trim();
|
|
3083
|
-
if (!/^https?:\/\//i.test(trimmed))
|
|
3084
|
-
trimmed = `https://${trimmed}`;
|
|
3085
|
-
const normalized = trimmed.replace(/\/+$/, "");
|
|
3086
|
-
const officialOrigin = /^https:\/\/([^/?#:@]+)$/i.exec(normalized);
|
|
3087
|
-
const loadoutHost = getLoadoutHostForLegacyAidentHost(officialOrigin?.[1]);
|
|
3088
|
-
return loadoutHost ? `https://${loadoutHost}` : normalized;
|
|
3089
|
-
}
|
|
3090
|
-
|
|
3091
2545
|
// ../../node_modules/zod/v3/helpers/util.js
|
|
3092
2546
|
var util;
|
|
3093
2547
|
(function(util) {
|
|
@@ -6498,407 +5952,967 @@ class ZodEffects extends ZodType {
|
|
|
6498
5952
|
path: ctx.path,
|
|
6499
5953
|
parent: ctx
|
|
6500
5954
|
});
|
|
6501
|
-
if (result.status === "aborted")
|
|
5955
|
+
if (result.status === "aborted")
|
|
5956
|
+
return INVALID;
|
|
5957
|
+
if (result.status === "dirty")
|
|
5958
|
+
return DIRTY(result.value);
|
|
5959
|
+
if (status.value === "dirty")
|
|
5960
|
+
return DIRTY(result.value);
|
|
5961
|
+
return result;
|
|
5962
|
+
}
|
|
5963
|
+
}
|
|
5964
|
+
if (effect.type === "refinement") {
|
|
5965
|
+
const executeRefinement = (acc) => {
|
|
5966
|
+
const result = effect.refinement(acc, checkCtx);
|
|
5967
|
+
if (ctx.common.async) {
|
|
5968
|
+
return Promise.resolve(result);
|
|
5969
|
+
}
|
|
5970
|
+
if (result instanceof Promise) {
|
|
5971
|
+
throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead.");
|
|
5972
|
+
}
|
|
5973
|
+
return acc;
|
|
5974
|
+
};
|
|
5975
|
+
if (ctx.common.async === false) {
|
|
5976
|
+
const inner = this._def.schema._parseSync({
|
|
5977
|
+
data: ctx.data,
|
|
5978
|
+
path: ctx.path,
|
|
5979
|
+
parent: ctx
|
|
5980
|
+
});
|
|
5981
|
+
if (inner.status === "aborted")
|
|
5982
|
+
return INVALID;
|
|
5983
|
+
if (inner.status === "dirty")
|
|
5984
|
+
status.dirty();
|
|
5985
|
+
executeRefinement(inner.value);
|
|
5986
|
+
return { status: status.value, value: inner.value };
|
|
5987
|
+
} else {
|
|
5988
|
+
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((inner) => {
|
|
5989
|
+
if (inner.status === "aborted")
|
|
5990
|
+
return INVALID;
|
|
5991
|
+
if (inner.status === "dirty")
|
|
5992
|
+
status.dirty();
|
|
5993
|
+
return executeRefinement(inner.value).then(() => {
|
|
5994
|
+
return { status: status.value, value: inner.value };
|
|
5995
|
+
});
|
|
5996
|
+
});
|
|
5997
|
+
}
|
|
5998
|
+
}
|
|
5999
|
+
if (effect.type === "transform") {
|
|
6000
|
+
if (ctx.common.async === false) {
|
|
6001
|
+
const base = this._def.schema._parseSync({
|
|
6002
|
+
data: ctx.data,
|
|
6003
|
+
path: ctx.path,
|
|
6004
|
+
parent: ctx
|
|
6005
|
+
});
|
|
6006
|
+
if (!isValid(base))
|
|
6007
|
+
return INVALID;
|
|
6008
|
+
const result = effect.transform(base.value, checkCtx);
|
|
6009
|
+
if (result instanceof Promise) {
|
|
6010
|
+
throw new Error(`Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.`);
|
|
6011
|
+
}
|
|
6012
|
+
return { status: status.value, value: result };
|
|
6013
|
+
} else {
|
|
6014
|
+
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((base) => {
|
|
6015
|
+
if (!isValid(base))
|
|
6016
|
+
return INVALID;
|
|
6017
|
+
return Promise.resolve(effect.transform(base.value, checkCtx)).then((result) => ({
|
|
6018
|
+
status: status.value,
|
|
6019
|
+
value: result
|
|
6020
|
+
}));
|
|
6021
|
+
});
|
|
6022
|
+
}
|
|
6023
|
+
}
|
|
6024
|
+
util.assertNever(effect);
|
|
6025
|
+
}
|
|
6026
|
+
}
|
|
6027
|
+
ZodEffects.create = (schema, effect, params) => {
|
|
6028
|
+
return new ZodEffects({
|
|
6029
|
+
schema,
|
|
6030
|
+
typeName: ZodFirstPartyTypeKind.ZodEffects,
|
|
6031
|
+
effect,
|
|
6032
|
+
...processCreateParams(params)
|
|
6033
|
+
});
|
|
6034
|
+
};
|
|
6035
|
+
ZodEffects.createWithPreprocess = (preprocess, schema, params) => {
|
|
6036
|
+
return new ZodEffects({
|
|
6037
|
+
schema,
|
|
6038
|
+
effect: { type: "preprocess", transform: preprocess },
|
|
6039
|
+
typeName: ZodFirstPartyTypeKind.ZodEffects,
|
|
6040
|
+
...processCreateParams(params)
|
|
6041
|
+
});
|
|
6042
|
+
};
|
|
6043
|
+
class ZodOptional extends ZodType {
|
|
6044
|
+
_parse(input) {
|
|
6045
|
+
const parsedType = this._getType(input);
|
|
6046
|
+
if (parsedType === ZodParsedType.undefined) {
|
|
6047
|
+
return OK(undefined);
|
|
6048
|
+
}
|
|
6049
|
+
return this._def.innerType._parse(input);
|
|
6050
|
+
}
|
|
6051
|
+
unwrap() {
|
|
6052
|
+
return this._def.innerType;
|
|
6053
|
+
}
|
|
6054
|
+
}
|
|
6055
|
+
ZodOptional.create = (type, params) => {
|
|
6056
|
+
return new ZodOptional({
|
|
6057
|
+
innerType: type,
|
|
6058
|
+
typeName: ZodFirstPartyTypeKind.ZodOptional,
|
|
6059
|
+
...processCreateParams(params)
|
|
6060
|
+
});
|
|
6061
|
+
};
|
|
6062
|
+
|
|
6063
|
+
class ZodNullable extends ZodType {
|
|
6064
|
+
_parse(input) {
|
|
6065
|
+
const parsedType = this._getType(input);
|
|
6066
|
+
if (parsedType === ZodParsedType.null) {
|
|
6067
|
+
return OK(null);
|
|
6068
|
+
}
|
|
6069
|
+
return this._def.innerType._parse(input);
|
|
6070
|
+
}
|
|
6071
|
+
unwrap() {
|
|
6072
|
+
return this._def.innerType;
|
|
6073
|
+
}
|
|
6074
|
+
}
|
|
6075
|
+
ZodNullable.create = (type, params) => {
|
|
6076
|
+
return new ZodNullable({
|
|
6077
|
+
innerType: type,
|
|
6078
|
+
typeName: ZodFirstPartyTypeKind.ZodNullable,
|
|
6079
|
+
...processCreateParams(params)
|
|
6080
|
+
});
|
|
6081
|
+
};
|
|
6082
|
+
|
|
6083
|
+
class ZodDefault extends ZodType {
|
|
6084
|
+
_parse(input) {
|
|
6085
|
+
const { ctx } = this._processInputParams(input);
|
|
6086
|
+
let data = ctx.data;
|
|
6087
|
+
if (ctx.parsedType === ZodParsedType.undefined) {
|
|
6088
|
+
data = this._def.defaultValue();
|
|
6089
|
+
}
|
|
6090
|
+
return this._def.innerType._parse({
|
|
6091
|
+
data,
|
|
6092
|
+
path: ctx.path,
|
|
6093
|
+
parent: ctx
|
|
6094
|
+
});
|
|
6095
|
+
}
|
|
6096
|
+
removeDefault() {
|
|
6097
|
+
return this._def.innerType;
|
|
6098
|
+
}
|
|
6099
|
+
}
|
|
6100
|
+
ZodDefault.create = (type, params) => {
|
|
6101
|
+
return new ZodDefault({
|
|
6102
|
+
innerType: type,
|
|
6103
|
+
typeName: ZodFirstPartyTypeKind.ZodDefault,
|
|
6104
|
+
defaultValue: typeof params.default === "function" ? params.default : () => params.default,
|
|
6105
|
+
...processCreateParams(params)
|
|
6106
|
+
});
|
|
6107
|
+
};
|
|
6108
|
+
|
|
6109
|
+
class ZodCatch extends ZodType {
|
|
6110
|
+
_parse(input) {
|
|
6111
|
+
const { ctx } = this._processInputParams(input);
|
|
6112
|
+
const newCtx = {
|
|
6113
|
+
...ctx,
|
|
6114
|
+
common: {
|
|
6115
|
+
...ctx.common,
|
|
6116
|
+
issues: []
|
|
6117
|
+
}
|
|
6118
|
+
};
|
|
6119
|
+
const result = this._def.innerType._parse({
|
|
6120
|
+
data: newCtx.data,
|
|
6121
|
+
path: newCtx.path,
|
|
6122
|
+
parent: {
|
|
6123
|
+
...newCtx
|
|
6124
|
+
}
|
|
6125
|
+
});
|
|
6126
|
+
if (isAsync(result)) {
|
|
6127
|
+
return result.then((result) => {
|
|
6128
|
+
return {
|
|
6129
|
+
status: "valid",
|
|
6130
|
+
value: result.status === "valid" ? result.value : this._def.catchValue({
|
|
6131
|
+
get error() {
|
|
6132
|
+
return new ZodError(newCtx.common.issues);
|
|
6133
|
+
},
|
|
6134
|
+
input: newCtx.data
|
|
6135
|
+
})
|
|
6136
|
+
};
|
|
6137
|
+
});
|
|
6138
|
+
} else {
|
|
6139
|
+
return {
|
|
6140
|
+
status: "valid",
|
|
6141
|
+
value: result.status === "valid" ? result.value : this._def.catchValue({
|
|
6142
|
+
get error() {
|
|
6143
|
+
return new ZodError(newCtx.common.issues);
|
|
6144
|
+
},
|
|
6145
|
+
input: newCtx.data
|
|
6146
|
+
})
|
|
6147
|
+
};
|
|
6148
|
+
}
|
|
6149
|
+
}
|
|
6150
|
+
removeCatch() {
|
|
6151
|
+
return this._def.innerType;
|
|
6152
|
+
}
|
|
6153
|
+
}
|
|
6154
|
+
ZodCatch.create = (type, params) => {
|
|
6155
|
+
return new ZodCatch({
|
|
6156
|
+
innerType: type,
|
|
6157
|
+
typeName: ZodFirstPartyTypeKind.ZodCatch,
|
|
6158
|
+
catchValue: typeof params.catch === "function" ? params.catch : () => params.catch,
|
|
6159
|
+
...processCreateParams(params)
|
|
6160
|
+
});
|
|
6161
|
+
};
|
|
6162
|
+
|
|
6163
|
+
class ZodNaN extends ZodType {
|
|
6164
|
+
_parse(input) {
|
|
6165
|
+
const parsedType = this._getType(input);
|
|
6166
|
+
if (parsedType !== ZodParsedType.nan) {
|
|
6167
|
+
const ctx = this._getOrReturnCtx(input);
|
|
6168
|
+
addIssueToContext(ctx, {
|
|
6169
|
+
code: ZodIssueCode.invalid_type,
|
|
6170
|
+
expected: ZodParsedType.nan,
|
|
6171
|
+
received: ctx.parsedType
|
|
6172
|
+
});
|
|
6173
|
+
return INVALID;
|
|
6174
|
+
}
|
|
6175
|
+
return { status: "valid", value: input.data };
|
|
6176
|
+
}
|
|
6177
|
+
}
|
|
6178
|
+
ZodNaN.create = (params) => {
|
|
6179
|
+
return new ZodNaN({
|
|
6180
|
+
typeName: ZodFirstPartyTypeKind.ZodNaN,
|
|
6181
|
+
...processCreateParams(params)
|
|
6182
|
+
});
|
|
6183
|
+
};
|
|
6184
|
+
var BRAND = Symbol("zod_brand");
|
|
6185
|
+
|
|
6186
|
+
class ZodBranded extends ZodType {
|
|
6187
|
+
_parse(input) {
|
|
6188
|
+
const { ctx } = this._processInputParams(input);
|
|
6189
|
+
const data = ctx.data;
|
|
6190
|
+
return this._def.type._parse({
|
|
6191
|
+
data,
|
|
6192
|
+
path: ctx.path,
|
|
6193
|
+
parent: ctx
|
|
6194
|
+
});
|
|
6195
|
+
}
|
|
6196
|
+
unwrap() {
|
|
6197
|
+
return this._def.type;
|
|
6198
|
+
}
|
|
6199
|
+
}
|
|
6200
|
+
|
|
6201
|
+
class ZodPipeline extends ZodType {
|
|
6202
|
+
_parse(input) {
|
|
6203
|
+
const { status, ctx } = this._processInputParams(input);
|
|
6204
|
+
if (ctx.common.async) {
|
|
6205
|
+
const handleAsync = async () => {
|
|
6206
|
+
const inResult = await this._def.in._parseAsync({
|
|
6207
|
+
data: ctx.data,
|
|
6208
|
+
path: ctx.path,
|
|
6209
|
+
parent: ctx
|
|
6210
|
+
});
|
|
6211
|
+
if (inResult.status === "aborted")
|
|
6502
6212
|
return INVALID;
|
|
6503
|
-
if (
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
const result = effect.refinement(acc, checkCtx);
|
|
6513
|
-
if (ctx.common.async) {
|
|
6514
|
-
return Promise.resolve(result);
|
|
6515
|
-
}
|
|
6516
|
-
if (result instanceof Promise) {
|
|
6517
|
-
throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead.");
|
|
6213
|
+
if (inResult.status === "dirty") {
|
|
6214
|
+
status.dirty();
|
|
6215
|
+
return DIRTY(inResult.value);
|
|
6216
|
+
} else {
|
|
6217
|
+
return this._def.out._parseAsync({
|
|
6218
|
+
data: inResult.value,
|
|
6219
|
+
path: ctx.path,
|
|
6220
|
+
parent: ctx
|
|
6221
|
+
});
|
|
6518
6222
|
}
|
|
6519
|
-
return acc;
|
|
6520
6223
|
};
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6224
|
+
return handleAsync();
|
|
6225
|
+
} else {
|
|
6226
|
+
const inResult = this._def.in._parseSync({
|
|
6227
|
+
data: ctx.data,
|
|
6228
|
+
path: ctx.path,
|
|
6229
|
+
parent: ctx
|
|
6230
|
+
});
|
|
6231
|
+
if (inResult.status === "aborted")
|
|
6232
|
+
return INVALID;
|
|
6233
|
+
if (inResult.status === "dirty") {
|
|
6234
|
+
status.dirty();
|
|
6235
|
+
return {
|
|
6236
|
+
status: "dirty",
|
|
6237
|
+
value: inResult.value
|
|
6238
|
+
};
|
|
6239
|
+
} else {
|
|
6240
|
+
return this._def.out._parseSync({
|
|
6241
|
+
data: inResult.value,
|
|
6524
6242
|
path: ctx.path,
|
|
6525
6243
|
parent: ctx
|
|
6526
6244
|
});
|
|
6527
|
-
if (inner.status === "aborted")
|
|
6528
|
-
return INVALID;
|
|
6529
|
-
if (inner.status === "dirty")
|
|
6530
|
-
status.dirty();
|
|
6531
|
-
executeRefinement(inner.value);
|
|
6532
|
-
return { status: status.value, value: inner.value };
|
|
6533
|
-
} else {
|
|
6534
|
-
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((inner) => {
|
|
6535
|
-
if (inner.status === "aborted")
|
|
6536
|
-
return INVALID;
|
|
6537
|
-
if (inner.status === "dirty")
|
|
6538
|
-
status.dirty();
|
|
6539
|
-
return executeRefinement(inner.value).then(() => {
|
|
6540
|
-
return { status: status.value, value: inner.value };
|
|
6541
|
-
});
|
|
6542
|
-
});
|
|
6543
6245
|
}
|
|
6544
6246
|
}
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6247
|
+
}
|
|
6248
|
+
static create(a, b) {
|
|
6249
|
+
return new ZodPipeline({
|
|
6250
|
+
in: a,
|
|
6251
|
+
out: b,
|
|
6252
|
+
typeName: ZodFirstPartyTypeKind.ZodPipeline
|
|
6253
|
+
});
|
|
6254
|
+
}
|
|
6255
|
+
}
|
|
6256
|
+
|
|
6257
|
+
class ZodReadonly extends ZodType {
|
|
6258
|
+
_parse(input) {
|
|
6259
|
+
const result = this._def.innerType._parse(input);
|
|
6260
|
+
const freeze = (data) => {
|
|
6261
|
+
if (isValid(data)) {
|
|
6262
|
+
data.value = Object.freeze(data.value);
|
|
6263
|
+
}
|
|
6264
|
+
return data;
|
|
6265
|
+
};
|
|
6266
|
+
return isAsync(result) ? result.then((data) => freeze(data)) : freeze(result);
|
|
6267
|
+
}
|
|
6268
|
+
unwrap() {
|
|
6269
|
+
return this._def.innerType;
|
|
6270
|
+
}
|
|
6271
|
+
}
|
|
6272
|
+
ZodReadonly.create = (type, params) => {
|
|
6273
|
+
return new ZodReadonly({
|
|
6274
|
+
innerType: type,
|
|
6275
|
+
typeName: ZodFirstPartyTypeKind.ZodReadonly,
|
|
6276
|
+
...processCreateParams(params)
|
|
6277
|
+
});
|
|
6278
|
+
};
|
|
6279
|
+
var late = {
|
|
6280
|
+
object: ZodObject.lazycreate
|
|
6281
|
+
};
|
|
6282
|
+
var ZodFirstPartyTypeKind;
|
|
6283
|
+
(function(ZodFirstPartyTypeKind) {
|
|
6284
|
+
ZodFirstPartyTypeKind["ZodString"] = "ZodString";
|
|
6285
|
+
ZodFirstPartyTypeKind["ZodNumber"] = "ZodNumber";
|
|
6286
|
+
ZodFirstPartyTypeKind["ZodNaN"] = "ZodNaN";
|
|
6287
|
+
ZodFirstPartyTypeKind["ZodBigInt"] = "ZodBigInt";
|
|
6288
|
+
ZodFirstPartyTypeKind["ZodBoolean"] = "ZodBoolean";
|
|
6289
|
+
ZodFirstPartyTypeKind["ZodDate"] = "ZodDate";
|
|
6290
|
+
ZodFirstPartyTypeKind["ZodSymbol"] = "ZodSymbol";
|
|
6291
|
+
ZodFirstPartyTypeKind["ZodUndefined"] = "ZodUndefined";
|
|
6292
|
+
ZodFirstPartyTypeKind["ZodNull"] = "ZodNull";
|
|
6293
|
+
ZodFirstPartyTypeKind["ZodAny"] = "ZodAny";
|
|
6294
|
+
ZodFirstPartyTypeKind["ZodUnknown"] = "ZodUnknown";
|
|
6295
|
+
ZodFirstPartyTypeKind["ZodNever"] = "ZodNever";
|
|
6296
|
+
ZodFirstPartyTypeKind["ZodVoid"] = "ZodVoid";
|
|
6297
|
+
ZodFirstPartyTypeKind["ZodArray"] = "ZodArray";
|
|
6298
|
+
ZodFirstPartyTypeKind["ZodObject"] = "ZodObject";
|
|
6299
|
+
ZodFirstPartyTypeKind["ZodUnion"] = "ZodUnion";
|
|
6300
|
+
ZodFirstPartyTypeKind["ZodDiscriminatedUnion"] = "ZodDiscriminatedUnion";
|
|
6301
|
+
ZodFirstPartyTypeKind["ZodIntersection"] = "ZodIntersection";
|
|
6302
|
+
ZodFirstPartyTypeKind["ZodTuple"] = "ZodTuple";
|
|
6303
|
+
ZodFirstPartyTypeKind["ZodRecord"] = "ZodRecord";
|
|
6304
|
+
ZodFirstPartyTypeKind["ZodMap"] = "ZodMap";
|
|
6305
|
+
ZodFirstPartyTypeKind["ZodSet"] = "ZodSet";
|
|
6306
|
+
ZodFirstPartyTypeKind["ZodFunction"] = "ZodFunction";
|
|
6307
|
+
ZodFirstPartyTypeKind["ZodLazy"] = "ZodLazy";
|
|
6308
|
+
ZodFirstPartyTypeKind["ZodLiteral"] = "ZodLiteral";
|
|
6309
|
+
ZodFirstPartyTypeKind["ZodEnum"] = "ZodEnum";
|
|
6310
|
+
ZodFirstPartyTypeKind["ZodEffects"] = "ZodEffects";
|
|
6311
|
+
ZodFirstPartyTypeKind["ZodNativeEnum"] = "ZodNativeEnum";
|
|
6312
|
+
ZodFirstPartyTypeKind["ZodOptional"] = "ZodOptional";
|
|
6313
|
+
ZodFirstPartyTypeKind["ZodNullable"] = "ZodNullable";
|
|
6314
|
+
ZodFirstPartyTypeKind["ZodDefault"] = "ZodDefault";
|
|
6315
|
+
ZodFirstPartyTypeKind["ZodCatch"] = "ZodCatch";
|
|
6316
|
+
ZodFirstPartyTypeKind["ZodPromise"] = "ZodPromise";
|
|
6317
|
+
ZodFirstPartyTypeKind["ZodBranded"] = "ZodBranded";
|
|
6318
|
+
ZodFirstPartyTypeKind["ZodPipeline"] = "ZodPipeline";
|
|
6319
|
+
ZodFirstPartyTypeKind["ZodReadonly"] = "ZodReadonly";
|
|
6320
|
+
})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
|
|
6321
|
+
var stringType = ZodString.create;
|
|
6322
|
+
var numberType = ZodNumber.create;
|
|
6323
|
+
var nanType = ZodNaN.create;
|
|
6324
|
+
var bigIntType = ZodBigInt.create;
|
|
6325
|
+
var booleanType = ZodBoolean.create;
|
|
6326
|
+
var dateType = ZodDate.create;
|
|
6327
|
+
var symbolType = ZodSymbol.create;
|
|
6328
|
+
var undefinedType = ZodUndefined.create;
|
|
6329
|
+
var nullType = ZodNull.create;
|
|
6330
|
+
var anyType = ZodAny.create;
|
|
6331
|
+
var unknownType = ZodUnknown.create;
|
|
6332
|
+
var neverType = ZodNever.create;
|
|
6333
|
+
var voidType = ZodVoid.create;
|
|
6334
|
+
var arrayType = ZodArray.create;
|
|
6335
|
+
var objectType = ZodObject.create;
|
|
6336
|
+
var strictObjectType = ZodObject.strictCreate;
|
|
6337
|
+
var unionType = ZodUnion.create;
|
|
6338
|
+
var discriminatedUnionType = ZodDiscriminatedUnion.create;
|
|
6339
|
+
var intersectionType = ZodIntersection.create;
|
|
6340
|
+
var tupleType = ZodTuple.create;
|
|
6341
|
+
var recordType = ZodRecord.create;
|
|
6342
|
+
var mapType = ZodMap.create;
|
|
6343
|
+
var setType = ZodSet.create;
|
|
6344
|
+
var functionType = ZodFunction.create;
|
|
6345
|
+
var lazyType = ZodLazy.create;
|
|
6346
|
+
var literalType = ZodLiteral.create;
|
|
6347
|
+
var enumType = ZodEnum.create;
|
|
6348
|
+
var nativeEnumType = ZodNativeEnum.create;
|
|
6349
|
+
var promiseType = ZodPromise.create;
|
|
6350
|
+
var effectsType = ZodEffects.create;
|
|
6351
|
+
var optionalType = ZodOptional.create;
|
|
6352
|
+
var nullableType = ZodNullable.create;
|
|
6353
|
+
var preprocessType = ZodEffects.createWithPreprocess;
|
|
6354
|
+
var pipelineType = ZodPipeline.create;
|
|
6355
|
+
var NEVER = INVALID;
|
|
6356
|
+
// ../web/shared/loadout/LoadoutDesktopSession.ts
|
|
6357
|
+
var LOADOUT_DESKTOP_SESSION_PATH = "/api/loadout/desktop/session";
|
|
6358
|
+
var LOADOUT_DESKTOP_SESSION_SCOPE = "desktop:session";
|
|
6359
|
+
var LOADOUT_DESKTOP_CLIENT_ID = "aident_desktop_v1";
|
|
6360
|
+
var LoadoutDesktopSessionResponseSchema = objectType({
|
|
6361
|
+
success: literalType(true),
|
|
6362
|
+
userId: stringType().uuid(),
|
|
6363
|
+
unchanged: literalType(true).optional()
|
|
6364
|
+
});
|
|
6365
|
+
|
|
6366
|
+
// src/auth.ts
|
|
6367
|
+
var CLIENT_NAME = "aident-cli";
|
|
6368
|
+
var LOOPBACK_HOST = "127.0.0.1";
|
|
6369
|
+
var LOGIN_OPEN_TIMEOUT_MS = 90 * 1000;
|
|
6370
|
+
var LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS = 30 * 60 * 1000;
|
|
6371
|
+
var LOGIN_OPENED_MESSAGE = `User opened the Aident login window. They have ${LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS / 60000} minutes to finish; if it fails, run \`aident login --oob\`, share the URL, and ask for the verification code.`;
|
|
6372
|
+
async function login(options) {
|
|
6373
|
+
const baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
6374
|
+
const writeInfo = options.format === "json" ? logErr : logInfo;
|
|
6375
|
+
if (options.oob)
|
|
6376
|
+
return loginOob(baseUrl, writeInfo, options.format === "json" ? process.stderr : process.stdout, options.ref);
|
|
6377
|
+
try {
|
|
6378
|
+
return await loginLoopback(baseUrl, writeInfo, options.ref);
|
|
6379
|
+
} catch (err) {
|
|
6380
|
+
logErr(`Loopback OAuth failed (${err instanceof Error ? err.message : String(err)}). Falling back to OOB flow.`);
|
|
6381
|
+
return loginOob(baseUrl, writeInfo, options.format === "json" ? process.stderr : process.stdout, options.ref);
|
|
6382
|
+
}
|
|
6383
|
+
}
|
|
6384
|
+
async function refreshToken(creds) {
|
|
6385
|
+
if (!creds.refresh_token || !creds.client_id)
|
|
6386
|
+
return null;
|
|
6387
|
+
const baseUrl = creds.base_url.replace(/\/+$/, "");
|
|
6388
|
+
const body = new URLSearchParams({
|
|
6389
|
+
grant_type: "refresh_token",
|
|
6390
|
+
client_id: creds.client_id,
|
|
6391
|
+
refresh_token: creds.refresh_token
|
|
6392
|
+
});
|
|
6393
|
+
const res = await fetch(`${baseUrl}/api/mcp/oauth/token`, {
|
|
6394
|
+
method: "POST",
|
|
6395
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
6396
|
+
body
|
|
6397
|
+
});
|
|
6398
|
+
if (!res.ok)
|
|
6399
|
+
return null;
|
|
6400
|
+
const tok = await res.json();
|
|
6401
|
+
return updateCredsFromToken(creds, tok);
|
|
6402
|
+
}
|
|
6403
|
+
async function logout(creds) {
|
|
6404
|
+
const baseUrl = creds.base_url.replace(/\/+$/, "");
|
|
6405
|
+
await fetch(`${baseUrl}/api/mcp/oauth/revoke`, {
|
|
6406
|
+
method: "POST",
|
|
6407
|
+
headers: {
|
|
6408
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
6409
|
+
Authorization: `Bearer ${creds.access_token}`
|
|
6410
|
+
},
|
|
6411
|
+
body: new URLSearchParams({ token: creds.access_token })
|
|
6412
|
+
}).catch(() => {
|
|
6413
|
+
return;
|
|
6414
|
+
});
|
|
6415
|
+
}
|
|
6416
|
+
async function loginLoopback(baseUrl, writeInfo, ref) {
|
|
6417
|
+
const verifier = base64UrlEncode(randomBytes(48));
|
|
6418
|
+
const challenge = base64UrlEncode(createHash("sha256").update(verifier).digest());
|
|
6419
|
+
const state = base64UrlEncode(randomBytes(16));
|
|
6420
|
+
const { server, port, codePromise, setExpectedOpenRedirectUrl } = await startCallbackServer(state, writeInfo);
|
|
6421
|
+
const redirectUri = `http://${LOOPBACK_HOST}:${port}/callback`;
|
|
6422
|
+
const { clientId, scope } = await genRegisterLoginClient(baseUrl, [redirectUri], true);
|
|
6423
|
+
const authorizeUrl = new URL(`${baseUrl}/api/mcp/oauth/authorize`);
|
|
6424
|
+
authorizeUrl.searchParams.set("response_type", "code");
|
|
6425
|
+
authorizeUrl.searchParams.set("client_id", clientId);
|
|
6426
|
+
authorizeUrl.searchParams.set("redirect_uri", redirectUri);
|
|
6427
|
+
authorizeUrl.searchParams.set("redirect_uri_exact", base64UrlEncode(Buffer.from(redirectUri, "utf8")));
|
|
6428
|
+
authorizeUrl.searchParams.set("code_challenge", challenge);
|
|
6429
|
+
authorizeUrl.searchParams.set("code_challenge_method", "S256");
|
|
6430
|
+
authorizeUrl.searchParams.set("state", state);
|
|
6431
|
+
if (scope)
|
|
6432
|
+
authorizeUrl.searchParams.set("scope", scope);
|
|
6433
|
+
if (ref)
|
|
6434
|
+
authorizeUrl.searchParams.set("via", ref);
|
|
6435
|
+
const authorizeUrlString = authorizeUrl.toString();
|
|
6436
|
+
setExpectedOpenRedirectUrl(authorizeUrlString);
|
|
6437
|
+
const loginOpenUrl = buildLoginOpenUrl(port, state, authorizeUrlString);
|
|
6438
|
+
writeInfo(`Opening browser for Aident login...`);
|
|
6439
|
+
writeInfo(`If the browser does not open, visit: ${authorizeUrlString}`);
|
|
6440
|
+
openExternalUrl(shouldUseLoopbackBrowserHandoff() ? loginOpenUrl : authorizeUrlString);
|
|
6441
|
+
let code;
|
|
6442
|
+
try {
|
|
6443
|
+
code = await codePromise;
|
|
6444
|
+
} finally {
|
|
6445
|
+
closeServer(server);
|
|
6446
|
+
}
|
|
6447
|
+
const tok = await exchangeCode(baseUrl, clientId, code, redirectUri, verifier);
|
|
6448
|
+
return buildCreds(baseUrl, clientId, tok);
|
|
6449
|
+
}
|
|
6450
|
+
async function loginOob(baseUrl, writeInfo, promptOutput, ref) {
|
|
6451
|
+
const redirectUri = `${baseUrl}/mcp/oob`;
|
|
6452
|
+
const verifier = base64UrlEncode(randomBytes(48));
|
|
6453
|
+
const challenge = base64UrlEncode(createHash("sha256").update(verifier).digest());
|
|
6454
|
+
const state = base64UrlEncode(randomBytes(16));
|
|
6455
|
+
let clientId = "";
|
|
6456
|
+
let valueToExchange = "";
|
|
6457
|
+
try {
|
|
6458
|
+
({ clientId } = await genRegisterLoginClient(baseUrl, [redirectUri]));
|
|
6459
|
+
const authorizeUrl = new URL(`${baseUrl}/api/mcp/oauth/authorize`);
|
|
6460
|
+
authorizeUrl.searchParams.set("response_type", "code");
|
|
6461
|
+
authorizeUrl.searchParams.set("client_id", clientId);
|
|
6462
|
+
authorizeUrl.searchParams.set("redirect_uri", redirectUri);
|
|
6463
|
+
authorizeUrl.searchParams.set("code_challenge", challenge);
|
|
6464
|
+
authorizeUrl.searchParams.set("code_challenge_method", "S256");
|
|
6465
|
+
authorizeUrl.searchParams.set("state", state);
|
|
6466
|
+
if (ref)
|
|
6467
|
+
authorizeUrl.searchParams.set("via", ref);
|
|
6468
|
+
const authorizeUrlString = authorizeUrl.toString();
|
|
6469
|
+
writeInfo(`Opening browser for Aident login...`);
|
|
6470
|
+
writeInfo(`If the browser does not open, visit: ${authorizeUrlString}`);
|
|
6471
|
+
openExternalUrl(authorizeUrlString);
|
|
6472
|
+
writeInfo("After approving, paste the 8-digit verification code shown on the Aident page below.");
|
|
6473
|
+
const pastedInput = await readLine("Paste 8-digit code here: ", {
|
|
6474
|
+
output: promptOutput,
|
|
6475
|
+
timeoutMs: LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS,
|
|
6476
|
+
timeoutMessage: `Verification code not received within ${LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS / 1000}s; aborting.`
|
|
6477
|
+
});
|
|
6478
|
+
valueToExchange = normalizeOobLoginInput(pastedInput);
|
|
6479
|
+
if (!valueToExchange)
|
|
6480
|
+
throw new Error("No verification code provided");
|
|
6481
|
+
if (!/^\d{8}$/.test(valueToExchange) && !looksLikeAccessToken(valueToExchange)) {
|
|
6482
|
+
throw new Error("Pasted value is not a valid 8-digit verification code. Please retry the login.");
|
|
6483
|
+
}
|
|
6484
|
+
const tok = await exchangeCode(baseUrl, clientId, valueToExchange, redirectUri, verifier);
|
|
6485
|
+
return buildCreds(baseUrl, clientId, tok);
|
|
6486
|
+
} catch (err) {
|
|
6487
|
+
if (err instanceof OAuthRejectedError) {
|
|
6488
|
+
if (!looksLikeAccessToken(valueToExchange)) {
|
|
6489
|
+
throw new Error("Pasted verification code was rejected by the server. Please retry the login.");
|
|
6568
6490
|
}
|
|
6491
|
+
logErr(`Server rejected the pasted value as an authorization code. Treating it as a raw access token. Note: token refresh is unavailable in this mode — when the token expires you'll need to run \`aident login\` again.`);
|
|
6492
|
+
return { base_url: baseUrl, client_id: clientId, access_token: valueToExchange };
|
|
6569
6493
|
}
|
|
6570
|
-
|
|
6494
|
+
throw err;
|
|
6571
6495
|
}
|
|
6572
6496
|
}
|
|
6573
|
-
|
|
6574
|
-
return
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6497
|
+
function normalizeVerificationCodeInput(value) {
|
|
6498
|
+
return value.trim().replace(/[\s-]+/g, "");
|
|
6499
|
+
}
|
|
6500
|
+
function normalizeOobLoginInput(value) {
|
|
6501
|
+
const verificationCode = normalizeVerificationCodeInput(value);
|
|
6502
|
+
if (/^\d{8}$/.test(verificationCode))
|
|
6503
|
+
return verificationCode;
|
|
6504
|
+
return value.trim().replace(/\s+/g, "");
|
|
6505
|
+
}
|
|
6506
|
+
function looksLikeAccessToken(value) {
|
|
6507
|
+
if (value.length < 20)
|
|
6508
|
+
return false;
|
|
6509
|
+
if (/\s/.test(value))
|
|
6510
|
+
return false;
|
|
6511
|
+
return /^[A-Za-z0-9._-]+$/.test(value);
|
|
6512
|
+
}
|
|
6513
|
+
async function genRegisterLoginClient(baseUrl, redirectUris, desktop = false) {
|
|
6514
|
+
const res = await fetch(`${baseUrl}/api/mcp/oauth/register`, {
|
|
6515
|
+
method: "POST",
|
|
6516
|
+
headers: { "Content-Type": "application/json" },
|
|
6517
|
+
body: JSON.stringify({
|
|
6518
|
+
client_name: CLIENT_NAME,
|
|
6519
|
+
redirect_uris: redirectUris,
|
|
6520
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
6521
|
+
response_types: ["code"],
|
|
6522
|
+
token_endpoint_auth_method: "none"
|
|
6523
|
+
})
|
|
6587
6524
|
});
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
const parsedType = this._getType(input);
|
|
6592
|
-
if (parsedType === ZodParsedType.undefined) {
|
|
6593
|
-
return OK(undefined);
|
|
6594
|
-
}
|
|
6595
|
-
return this._def.innerType._parse(input);
|
|
6596
|
-
}
|
|
6597
|
-
unwrap() {
|
|
6598
|
-
return this._def.innerType;
|
|
6525
|
+
if (!res.ok) {
|
|
6526
|
+
const text = await res.text().catch(() => "");
|
|
6527
|
+
throw new Error(`Failed to register OAuth client (HTTP ${res.status}): ${text}`);
|
|
6599
6528
|
}
|
|
6529
|
+
const json = await res.json();
|
|
6530
|
+
if (!json.client_id)
|
|
6531
|
+
throw new Error("OAuth registration response missing client_id");
|
|
6532
|
+
if (desktop && json.desktop_client_id === LOADOUT_DESKTOP_CLIENT_ID)
|
|
6533
|
+
return { clientId: LOADOUT_DESKTOP_CLIENT_ID, scope: LOADOUT_DESKTOP_SESSION_SCOPE };
|
|
6534
|
+
return { clientId: json.client_id };
|
|
6600
6535
|
}
|
|
6601
|
-
ZodOptional.create = (type, params) => {
|
|
6602
|
-
return new ZodOptional({
|
|
6603
|
-
innerType: type,
|
|
6604
|
-
typeName: ZodFirstPartyTypeKind.ZodOptional,
|
|
6605
|
-
...processCreateParams(params)
|
|
6606
|
-
});
|
|
6607
|
-
};
|
|
6608
6536
|
|
|
6609
|
-
class
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
return this._def.innerType._parse(input);
|
|
6616
|
-
}
|
|
6617
|
-
unwrap() {
|
|
6618
|
-
return this._def.innerType;
|
|
6537
|
+
class OAuthRejectedError extends Error {
|
|
6538
|
+
status;
|
|
6539
|
+
constructor(message, status) {
|
|
6540
|
+
super(message);
|
|
6541
|
+
this.status = status;
|
|
6542
|
+
this.name = "OAuthRejectedError";
|
|
6619
6543
|
}
|
|
6620
6544
|
}
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6545
|
+
async function exchangeCode(baseUrl, clientId, code, redirectUri, verifier) {
|
|
6546
|
+
const body = new URLSearchParams({
|
|
6547
|
+
grant_type: "authorization_code",
|
|
6548
|
+
client_id: clientId,
|
|
6549
|
+
code,
|
|
6550
|
+
redirect_uri: redirectUri,
|
|
6551
|
+
code_verifier: verifier
|
|
6626
6552
|
});
|
|
6627
|
-
}
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
|
|
6553
|
+
const res = await fetch(`${baseUrl}/api/mcp/oauth/token`, {
|
|
6554
|
+
method: "POST",
|
|
6555
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
6556
|
+
body
|
|
6557
|
+
});
|
|
6558
|
+
if (!res.ok) {
|
|
6559
|
+
const text = await res.text().catch(() => "");
|
|
6560
|
+
if (res.status >= 400 && res.status < 500) {
|
|
6561
|
+
throw new OAuthRejectedError(`Token exchange rejected (HTTP ${res.status}): ${text}`, res.status);
|
|
6635
6562
|
}
|
|
6636
|
-
|
|
6637
|
-
data,
|
|
6638
|
-
path: ctx.path,
|
|
6639
|
-
parent: ctx
|
|
6640
|
-
});
|
|
6641
|
-
}
|
|
6642
|
-
removeDefault() {
|
|
6643
|
-
return this._def.innerType;
|
|
6563
|
+
throw new Error(`Token exchange failed (HTTP ${res.status}): ${text}`);
|
|
6644
6564
|
}
|
|
6565
|
+
return await res.json();
|
|
6645
6566
|
}
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6567
|
+
function buildCreds(baseUrl, clientId, tok) {
|
|
6568
|
+
const expiresAt = tok.expires_in ? new Date(Date.now() + tok.expires_in * 1000).toISOString() : undefined;
|
|
6569
|
+
return {
|
|
6570
|
+
base_url: baseUrl,
|
|
6571
|
+
client_id: clientId,
|
|
6572
|
+
access_token: tok.access_token,
|
|
6573
|
+
refresh_token: tok.refresh_token,
|
|
6574
|
+
expires_at: expiresAt
|
|
6575
|
+
};
|
|
6576
|
+
}
|
|
6577
|
+
function updateCredsFromToken(creds, tok) {
|
|
6578
|
+
const expiresAt = tok.expires_in ? new Date(Date.now() + tok.expires_in * 1000).toISOString() : creds.expires_at;
|
|
6579
|
+
return {
|
|
6580
|
+
...creds,
|
|
6581
|
+
access_token: tok.access_token,
|
|
6582
|
+
refresh_token: tok.refresh_token ?? creds.refresh_token,
|
|
6583
|
+
expires_at: expiresAt
|
|
6584
|
+
};
|
|
6585
|
+
}
|
|
6586
|
+
function startCallbackServer(expectedState, writeInfo = logInfo) {
|
|
6587
|
+
return new Promise((resolve, reject) => {
|
|
6588
|
+
let codeResolver = () => {
|
|
6589
|
+
return;
|
|
6664
6590
|
};
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6591
|
+
let codeRejecter = () => {
|
|
6592
|
+
return;
|
|
6593
|
+
};
|
|
6594
|
+
let opened = false;
|
|
6595
|
+
let expectedOpenRedirectUrl = "";
|
|
6596
|
+
let completeTimeout;
|
|
6597
|
+
const codePromise = new Promise((res, rej) => {
|
|
6598
|
+
codeResolver = res;
|
|
6599
|
+
codeRejecter = rej;
|
|
6600
|
+
});
|
|
6601
|
+
const scheduleCompleteTimeout = (timeoutMs, message) => {
|
|
6602
|
+
if (completeTimeout)
|
|
6603
|
+
clearTimeout(completeTimeout);
|
|
6604
|
+
completeTimeout = setTimeout(() => codeRejecter(new Error(message)), timeoutMs);
|
|
6605
|
+
};
|
|
6606
|
+
const openTimeout = setTimeout(() => {
|
|
6607
|
+
if (!opened) {
|
|
6608
|
+
writeInfo(`Login window open signal not received within ${LOGIN_OPEN_TIMEOUT_MS / 1000}s; still waiting for login to finish.`);
|
|
6670
6609
|
}
|
|
6610
|
+
}, LOGIN_OPEN_TIMEOUT_MS);
|
|
6611
|
+
scheduleCompleteTimeout(LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS, `Authorization callback not received within ${LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS / 1000}s; aborting.`);
|
|
6612
|
+
codePromise.then(() => {
|
|
6613
|
+
clearTimeout(openTimeout);
|
|
6614
|
+
if (completeTimeout)
|
|
6615
|
+
clearTimeout(completeTimeout);
|
|
6616
|
+
}, () => {
|
|
6617
|
+
clearTimeout(openTimeout);
|
|
6618
|
+
if (completeTimeout)
|
|
6619
|
+
clearTimeout(completeTimeout);
|
|
6671
6620
|
});
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
return
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6621
|
+
const markOpened = () => {
|
|
6622
|
+
if (opened)
|
|
6623
|
+
return;
|
|
6624
|
+
opened = true;
|
|
6625
|
+
clearTimeout(openTimeout);
|
|
6626
|
+
writeInfo(LOGIN_OPENED_MESSAGE);
|
|
6627
|
+
const timeoutMs = LOGIN_COMPLETE_TIMEOUT_AFTER_OPENED_MS;
|
|
6628
|
+
scheduleCompleteTimeout(timeoutMs, `Login page opened but did not complete within ${timeoutMs / 1000}s; aborting.`);
|
|
6629
|
+
};
|
|
6630
|
+
const server = createServer((req, res) => {
|
|
6631
|
+
runLocalCallbackHandler(req, res, () => {
|
|
6632
|
+
if (!req.url) {
|
|
6633
|
+
res.writeHead(400);
|
|
6634
|
+
res.end("Bad request");
|
|
6635
|
+
return;
|
|
6636
|
+
}
|
|
6637
|
+
const url = new URL(req.url, `http://${LOOPBACK_HOST}`);
|
|
6638
|
+
if (handleOpenRedirect(url, res, expectedState, expectedOpenRedirectUrl, markOpened))
|
|
6639
|
+
return;
|
|
6640
|
+
if (url.pathname !== "/callback") {
|
|
6641
|
+
res.writeHead(404);
|
|
6642
|
+
res.end("Not found");
|
|
6643
|
+
return;
|
|
6644
|
+
}
|
|
6645
|
+
const code = url.searchParams.get("code");
|
|
6646
|
+
const state = url.searchParams.get("state");
|
|
6647
|
+
const error = url.searchParams.get("error");
|
|
6648
|
+
if (error) {
|
|
6649
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
6650
|
+
res.end(`<html><body><h2>Authentication error</h2><p>${escapeHtml(error)}</p></body></html>`);
|
|
6651
|
+
codeRejecter(new Error(`OAuth error: ${error}`));
|
|
6652
|
+
return;
|
|
6653
|
+
}
|
|
6654
|
+
if (!code || state !== expectedState) {
|
|
6655
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
6656
|
+
res.end("<html><body><h2>Invalid callback</h2></body></html>");
|
|
6657
|
+
codeRejecter(new Error("Invalid callback (missing code or bad state)"));
|
|
6658
|
+
return;
|
|
6659
|
+
}
|
|
6660
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
6661
|
+
res.end(`<html><body style="font-family:system-ui;padding:40px;text-align:center"><h2>You're signed in.</h2><p>You can close this window and return to the terminal.</p></body></html>`);
|
|
6662
|
+
codeResolver(code);
|
|
6663
|
+
}, codeRejecter);
|
|
6664
|
+
});
|
|
6665
|
+
server.once("error", reject);
|
|
6666
|
+
server.listen(0, LOOPBACK_HOST, () => {
|
|
6667
|
+
const addr = server.address();
|
|
6668
|
+
resolve({
|
|
6669
|
+
server,
|
|
6670
|
+
port: addr.port,
|
|
6671
|
+
codePromise,
|
|
6672
|
+
setExpectedOpenRedirectUrl: (url) => {
|
|
6673
|
+
expectedOpenRedirectUrl = url;
|
|
6674
|
+
}
|
|
6683
6675
|
});
|
|
6684
|
-
}
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
}
|
|
6676
|
+
});
|
|
6677
|
+
});
|
|
6678
|
+
}
|
|
6679
|
+
function handleOpenRedirect(url, res, expectedState, expectedOpenRedirectUrl, onOpened) {
|
|
6680
|
+
if (url.pathname !== "/open")
|
|
6681
|
+
return false;
|
|
6682
|
+
if (url.searchParams.get("state") !== expectedState) {
|
|
6683
|
+
res.writeHead(400);
|
|
6684
|
+
res.end("Bad request");
|
|
6685
|
+
return true;
|
|
6695
6686
|
}
|
|
6696
|
-
|
|
6697
|
-
|
|
6687
|
+
const nextUrl = url.searchParams.get("next");
|
|
6688
|
+
if (!expectedOpenRedirectUrl || !nextUrl || nextUrl !== expectedOpenRedirectUrl) {
|
|
6689
|
+
res.writeHead(400);
|
|
6690
|
+
res.end("Bad request");
|
|
6691
|
+
return true;
|
|
6692
|
+
}
|
|
6693
|
+
try {
|
|
6694
|
+
onOpened();
|
|
6695
|
+
} catch {
|
|
6696
|
+
res.writeHead(500);
|
|
6697
|
+
res.end("Internal callback error");
|
|
6698
|
+
return true;
|
|
6698
6699
|
}
|
|
6700
|
+
res.writeHead(302, { Location: nextUrl });
|
|
6701
|
+
res.end();
|
|
6702
|
+
return true;
|
|
6699
6703
|
}
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
class ZodNaN extends ZodType {
|
|
6710
|
-
_parse(input) {
|
|
6711
|
-
const parsedType = this._getType(input);
|
|
6712
|
-
if (parsedType !== ZodParsedType.nan) {
|
|
6713
|
-
const ctx = this._getOrReturnCtx(input);
|
|
6714
|
-
addIssueToContext(ctx, {
|
|
6715
|
-
code: ZodIssueCode.invalid_type,
|
|
6716
|
-
expected: ZodParsedType.nan,
|
|
6717
|
-
received: ctx.parsedType
|
|
6718
|
-
});
|
|
6719
|
-
return INVALID;
|
|
6704
|
+
function runLocalCallbackHandler(req, res, handle, onAuthCallbackError) {
|
|
6705
|
+
try {
|
|
6706
|
+
handle();
|
|
6707
|
+
} catch (err) {
|
|
6708
|
+
if (!res.writableEnded) {
|
|
6709
|
+
if (!res.headersSent)
|
|
6710
|
+
res.writeHead(500);
|
|
6711
|
+
res.end("Internal callback error");
|
|
6720
6712
|
}
|
|
6721
|
-
|
|
6713
|
+
if (isAuthCallbackRequest(req.url))
|
|
6714
|
+
onAuthCallbackError?.(toError(err));
|
|
6722
6715
|
}
|
|
6723
6716
|
}
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
}
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
class ZodBranded extends ZodType {
|
|
6733
|
-
_parse(input) {
|
|
6734
|
-
const { ctx } = this._processInputParams(input);
|
|
6735
|
-
const data = ctx.data;
|
|
6736
|
-
return this._def.type._parse({
|
|
6737
|
-
data,
|
|
6738
|
-
path: ctx.path,
|
|
6739
|
-
parent: ctx
|
|
6740
|
-
});
|
|
6741
|
-
}
|
|
6742
|
-
unwrap() {
|
|
6743
|
-
return this._def.type;
|
|
6717
|
+
function isAuthCallbackRequest(url) {
|
|
6718
|
+
if (!url)
|
|
6719
|
+
return false;
|
|
6720
|
+
try {
|
|
6721
|
+
return new URL(url, `http://${LOOPBACK_HOST}`).pathname === "/callback";
|
|
6722
|
+
} catch {
|
|
6723
|
+
return false;
|
|
6744
6724
|
}
|
|
6745
6725
|
}
|
|
6726
|
+
function toError(err) {
|
|
6727
|
+
return err instanceof Error ? err : new Error(String(err));
|
|
6728
|
+
}
|
|
6729
|
+
function closeServer(server) {
|
|
6730
|
+
server.close();
|
|
6731
|
+
server.closeIdleConnections?.();
|
|
6732
|
+
server.closeAllConnections?.();
|
|
6733
|
+
}
|
|
6734
|
+
function buildLoginOpenUrl(port, state, authorizeUrl) {
|
|
6735
|
+
const url = new URL(`http://${LOOPBACK_HOST}:${port}/open`);
|
|
6736
|
+
url.searchParams.set("state", state);
|
|
6737
|
+
url.searchParams.set("next", authorizeUrl);
|
|
6738
|
+
return url.toString();
|
|
6739
|
+
}
|
|
6740
|
+
function shouldUseLoopbackBrowserHandoff(env = process.env) {
|
|
6741
|
+
return !isRemoteSessionEnvironment(env);
|
|
6742
|
+
}
|
|
6743
|
+
function isRemoteSessionEnvironment(env = process.env) {
|
|
6744
|
+
return Boolean(env.SSH_CONNECTION || env.SSH_TTY || env.CODESPACES || env.REMOTE_CONTAINERS || env.DEVCONTAINER);
|
|
6745
|
+
}
|
|
6746
|
+
function base64UrlEncode(buf) {
|
|
6747
|
+
return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
6748
|
+
}
|
|
6749
|
+
function escapeHtml(s) {
|
|
6750
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
6751
|
+
}
|
|
6746
6752
|
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
if (inResult.status === "aborted")
|
|
6778
|
-
return INVALID;
|
|
6779
|
-
if (inResult.status === "dirty") {
|
|
6780
|
-
status.dirty();
|
|
6781
|
-
return {
|
|
6782
|
-
status: "dirty",
|
|
6783
|
-
value: inResult.value
|
|
6784
|
-
};
|
|
6785
|
-
} else {
|
|
6786
|
-
return this._def.out._parseSync({
|
|
6787
|
-
data: inResult.value,
|
|
6788
|
-
path: ctx.path,
|
|
6789
|
-
parent: ctx
|
|
6790
|
-
});
|
|
6791
|
-
}
|
|
6792
|
-
}
|
|
6753
|
+
// src/catalogCache.ts
|
|
6754
|
+
import crypto from "node:crypto";
|
|
6755
|
+
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
6756
|
+
import { join as join2 } from "node:path";
|
|
6757
|
+
|
|
6758
|
+
// src/config.ts
|
|
6759
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
6760
|
+
import { homedir } from "node:os";
|
|
6761
|
+
import { dirname, join } from "node:path";
|
|
6762
|
+
|
|
6763
|
+
// src/packages.ts
|
|
6764
|
+
var CLI_PACKAGES = ["loadout", "playbook", "intern"];
|
|
6765
|
+
var DEFAULT_CLI_PACKAGES = ["loadout"];
|
|
6766
|
+
function parseCliPackage(value) {
|
|
6767
|
+
if (typeof value !== "string")
|
|
6768
|
+
throw new Error(`Unsupported Aident package: ${String(value)}`);
|
|
6769
|
+
const normalized = value.trim().toLowerCase();
|
|
6770
|
+
if (!CLI_PACKAGES.includes(normalized))
|
|
6771
|
+
throw new Error(`Unsupported Aident package: ${value}`);
|
|
6772
|
+
return normalized;
|
|
6773
|
+
}
|
|
6774
|
+
function normalizeCliPackages(value) {
|
|
6775
|
+
const rawPackages = value === undefined || value === null || value === "" ? [] : Array.isArray(value) ? value : String(value).split(/[,\s]+/);
|
|
6776
|
+
const packages = ["loadout"];
|
|
6777
|
+
for (const rawPackage of rawPackages) {
|
|
6778
|
+
if (rawPackage === undefined || rawPackage === null || rawPackage === "")
|
|
6779
|
+
continue;
|
|
6780
|
+
const cliPackage = parseCliPackage(rawPackage);
|
|
6781
|
+
if (!packages.includes(cliPackage))
|
|
6782
|
+
packages.push(cliPackage);
|
|
6793
6783
|
}
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6784
|
+
return packages;
|
|
6785
|
+
}
|
|
6786
|
+
function formatCliPackages(packages) {
|
|
6787
|
+
return packages.join(",");
|
|
6788
|
+
}
|
|
6789
|
+
|
|
6790
|
+
// ../web/shared/env/loadoutHostPairs.json
|
|
6791
|
+
var loadoutHostPairs_default = [
|
|
6792
|
+
{
|
|
6793
|
+
appHost: "app.aident.ai",
|
|
6794
|
+
loadoutHost: "loadout.aident.ai"
|
|
6795
|
+
},
|
|
6796
|
+
{
|
|
6797
|
+
appHost: "staging.app.aident.ai",
|
|
6798
|
+
loadoutHost: "staging.loadout.aident.ai"
|
|
6799
|
+
},
|
|
6800
|
+
{
|
|
6801
|
+
appHost: "rc.app.aident.ai",
|
|
6802
|
+
loadoutHost: "rc.loadout.aident.ai"
|
|
6803
|
+
}
|
|
6804
|
+
];
|
|
6805
|
+
|
|
6806
|
+
// ../web/shared/env/loadoutHosts.ts
|
|
6807
|
+
var LOADOUT_PRODUCTION_HOST = "loadout.aident.ai";
|
|
6808
|
+
var LOADOUT_STAGING_HOST = "staging.loadout.aident.ai";
|
|
6809
|
+
var LOADOUT_PREVIEW_HOST = "rc.loadout.aident.ai";
|
|
6810
|
+
var LOADOUT_CUSTOM_HOSTS = [LOADOUT_PRODUCTION_HOST, LOADOUT_STAGING_HOST, LOADOUT_PREVIEW_HOST];
|
|
6811
|
+
var LOADOUT_HOST_BY_AIDENT_APP_HOST = Object.fromEntries(loadoutHostPairs_default.map(({ appHost, loadoutHost }) => [appHost, loadoutHost]));
|
|
6812
|
+
var AIDENT_PUBLIC_HOSTS = new Set(["aident.ai", "www.aident.ai"]);
|
|
6813
|
+
function getLoadoutHostname(host) {
|
|
6814
|
+
return (host ?? "").split(":")[0]?.toLowerCase() ?? "";
|
|
6815
|
+
}
|
|
6816
|
+
function isLoadoutCustomHost(host) {
|
|
6817
|
+
const hostname = getLoadoutHostname(host);
|
|
6818
|
+
return LOADOUT_CUSTOM_HOSTS.some((candidate) => candidate === hostname) || /^pr-\d+-loadout\.prebuilt\.aident\.ai$/.test(hostname);
|
|
6819
|
+
}
|
|
6820
|
+
function isTrustedAidentHttpsUrl(value) {
|
|
6821
|
+
try {
|
|
6822
|
+
const url = value instanceof URL ? value : new URL(value);
|
|
6823
|
+
const hostname = url.hostname.toLowerCase();
|
|
6824
|
+
return url.protocol === "https:" && url.port === "" && url.username === "" && url.password === "" && (hostname === "aident.ai" || hostname.endsWith(".aident.ai"));
|
|
6825
|
+
} catch {
|
|
6826
|
+
return false;
|
|
6800
6827
|
}
|
|
6801
6828
|
}
|
|
6829
|
+
function getLoadoutHostForAidentAppHost(host) {
|
|
6830
|
+
const hostname = getLoadoutHostname(host);
|
|
6831
|
+
return LOADOUT_HOST_BY_AIDENT_APP_HOST[hostname] ?? null;
|
|
6832
|
+
}
|
|
6833
|
+
function getCanonicalLoadoutHost(host) {
|
|
6834
|
+
const hostname = getLoadoutHostname(host);
|
|
6835
|
+
return getLoadoutHostForAidentAppHost(hostname) ?? (isLoadoutCustomHost(hostname) ? hostname : null);
|
|
6836
|
+
}
|
|
6837
|
+
function getLoadoutHostForLegacyAidentHost(host) {
|
|
6838
|
+
const hostname = getLoadoutHostname(host);
|
|
6839
|
+
return AIDENT_PUBLIC_HOSTS.has(hostname) ? LOADOUT_PRODUCTION_HOST : getCanonicalLoadoutHost(hostname);
|
|
6840
|
+
}
|
|
6802
6841
|
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6842
|
+
// src/config.ts
|
|
6843
|
+
function getAidentDir(home = process.env.HOME || process.env.USERPROFILE || homedir()) {
|
|
6844
|
+
return join(home, ".aident");
|
|
6845
|
+
}
|
|
6846
|
+
function getConfigFile() {
|
|
6847
|
+
return join(getAidentDir(), "config.json");
|
|
6848
|
+
}
|
|
6849
|
+
function getConfigFileForHome(home) {
|
|
6850
|
+
return join(getAidentDir(home), "config.json");
|
|
6851
|
+
}
|
|
6852
|
+
var DEFAULT_BASE_URL = "https://rc.loadout.aident.ai"?.trim() || "https://loadout.aident.ai";
|
|
6853
|
+
var CONFIG_KEYS = ["baseUrl", "packages"];
|
|
6854
|
+
async function readConfig(configFile = getConfigFile()) {
|
|
6855
|
+
try {
|
|
6856
|
+
const text = await readFile(configFile, "utf-8");
|
|
6857
|
+
const parsed = JSON.parse(text);
|
|
6858
|
+
if (!parsed || typeof parsed !== "object")
|
|
6859
|
+
return {};
|
|
6860
|
+
if (typeof parsed.baseUrl === "string")
|
|
6861
|
+
parsed.baseUrl = normalizeBaseUrl(parsed.baseUrl);
|
|
6862
|
+
return parsed;
|
|
6863
|
+
} catch {
|
|
6864
|
+
return {};
|
|
6813
6865
|
}
|
|
6814
|
-
|
|
6815
|
-
|
|
6866
|
+
}
|
|
6867
|
+
async function writeConfig(config, configFile = getConfigFile()) {
|
|
6868
|
+
await mkdir(dirname(configFile), { recursive: true, mode: 448 });
|
|
6869
|
+
await writeFile(configFile, JSON.stringify(config, null, 2) + `
|
|
6870
|
+
`, { mode: 420 });
|
|
6871
|
+
}
|
|
6872
|
+
async function setConfigValue(key, value, configFile = getConfigFile()) {
|
|
6873
|
+
const config = await readConfig(configFile);
|
|
6874
|
+
config[key] = value;
|
|
6875
|
+
await writeConfig(config, configFile);
|
|
6876
|
+
}
|
|
6877
|
+
async function unsetConfigValue(key) {
|
|
6878
|
+
const config = await readConfig();
|
|
6879
|
+
delete config[key];
|
|
6880
|
+
await writeConfig(config);
|
|
6881
|
+
}
|
|
6882
|
+
async function resolveDefaultBaseUrl() {
|
|
6883
|
+
const env = process.env.AIDENT_BASE_URL?.trim();
|
|
6884
|
+
if (env)
|
|
6885
|
+
return normalizeBaseUrl(env);
|
|
6886
|
+
const config = await readConfig();
|
|
6887
|
+
if (typeof config.baseUrl === "string" && config.baseUrl.trim() !== "") {
|
|
6888
|
+
return normalizeBaseUrl(config.baseUrl);
|
|
6816
6889
|
}
|
|
6890
|
+
return DEFAULT_BASE_URL;
|
|
6817
6891
|
}
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
}
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
ZodFirstPartyTypeKind["ZodVoid"] = "ZodVoid";
|
|
6843
|
-
ZodFirstPartyTypeKind["ZodArray"] = "ZodArray";
|
|
6844
|
-
ZodFirstPartyTypeKind["ZodObject"] = "ZodObject";
|
|
6845
|
-
ZodFirstPartyTypeKind["ZodUnion"] = "ZodUnion";
|
|
6846
|
-
ZodFirstPartyTypeKind["ZodDiscriminatedUnion"] = "ZodDiscriminatedUnion";
|
|
6847
|
-
ZodFirstPartyTypeKind["ZodIntersection"] = "ZodIntersection";
|
|
6848
|
-
ZodFirstPartyTypeKind["ZodTuple"] = "ZodTuple";
|
|
6849
|
-
ZodFirstPartyTypeKind["ZodRecord"] = "ZodRecord";
|
|
6850
|
-
ZodFirstPartyTypeKind["ZodMap"] = "ZodMap";
|
|
6851
|
-
ZodFirstPartyTypeKind["ZodSet"] = "ZodSet";
|
|
6852
|
-
ZodFirstPartyTypeKind["ZodFunction"] = "ZodFunction";
|
|
6853
|
-
ZodFirstPartyTypeKind["ZodLazy"] = "ZodLazy";
|
|
6854
|
-
ZodFirstPartyTypeKind["ZodLiteral"] = "ZodLiteral";
|
|
6855
|
-
ZodFirstPartyTypeKind["ZodEnum"] = "ZodEnum";
|
|
6856
|
-
ZodFirstPartyTypeKind["ZodEffects"] = "ZodEffects";
|
|
6857
|
-
ZodFirstPartyTypeKind["ZodNativeEnum"] = "ZodNativeEnum";
|
|
6858
|
-
ZodFirstPartyTypeKind["ZodOptional"] = "ZodOptional";
|
|
6859
|
-
ZodFirstPartyTypeKind["ZodNullable"] = "ZodNullable";
|
|
6860
|
-
ZodFirstPartyTypeKind["ZodDefault"] = "ZodDefault";
|
|
6861
|
-
ZodFirstPartyTypeKind["ZodCatch"] = "ZodCatch";
|
|
6862
|
-
ZodFirstPartyTypeKind["ZodPromise"] = "ZodPromise";
|
|
6863
|
-
ZodFirstPartyTypeKind["ZodBranded"] = "ZodBranded";
|
|
6864
|
-
ZodFirstPartyTypeKind["ZodPipeline"] = "ZodPipeline";
|
|
6865
|
-
ZodFirstPartyTypeKind["ZodReadonly"] = "ZodReadonly";
|
|
6866
|
-
})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
|
|
6867
|
-
var stringType = ZodString.create;
|
|
6868
|
-
var numberType = ZodNumber.create;
|
|
6869
|
-
var nanType = ZodNaN.create;
|
|
6870
|
-
var bigIntType = ZodBigInt.create;
|
|
6871
|
-
var booleanType = ZodBoolean.create;
|
|
6872
|
-
var dateType = ZodDate.create;
|
|
6873
|
-
var symbolType = ZodSymbol.create;
|
|
6874
|
-
var undefinedType = ZodUndefined.create;
|
|
6875
|
-
var nullType = ZodNull.create;
|
|
6876
|
-
var anyType = ZodAny.create;
|
|
6877
|
-
var unknownType = ZodUnknown.create;
|
|
6878
|
-
var neverType = ZodNever.create;
|
|
6879
|
-
var voidType = ZodVoid.create;
|
|
6880
|
-
var arrayType = ZodArray.create;
|
|
6881
|
-
var objectType = ZodObject.create;
|
|
6882
|
-
var strictObjectType = ZodObject.strictCreate;
|
|
6883
|
-
var unionType = ZodUnion.create;
|
|
6884
|
-
var discriminatedUnionType = ZodDiscriminatedUnion.create;
|
|
6885
|
-
var intersectionType = ZodIntersection.create;
|
|
6886
|
-
var tupleType = ZodTuple.create;
|
|
6887
|
-
var recordType = ZodRecord.create;
|
|
6888
|
-
var mapType = ZodMap.create;
|
|
6889
|
-
var setType = ZodSet.create;
|
|
6890
|
-
var functionType = ZodFunction.create;
|
|
6891
|
-
var lazyType = ZodLazy.create;
|
|
6892
|
-
var literalType = ZodLiteral.create;
|
|
6893
|
-
var enumType = ZodEnum.create;
|
|
6894
|
-
var nativeEnumType = ZodNativeEnum.create;
|
|
6895
|
-
var promiseType = ZodPromise.create;
|
|
6896
|
-
var effectsType = ZodEffects.create;
|
|
6897
|
-
var optionalType = ZodOptional.create;
|
|
6898
|
-
var nullableType = ZodNullable.create;
|
|
6899
|
-
var preprocessType = ZodEffects.createWithPreprocess;
|
|
6900
|
-
var pipelineType = ZodPipeline.create;
|
|
6901
|
-
var NEVER = INVALID;
|
|
6892
|
+
async function resolveDefaultPackages() {
|
|
6893
|
+
const env = process.env.AIDENT_PACKAGES?.trim() || process.env.AIDENT_PACKAGE?.trim();
|
|
6894
|
+
if (env)
|
|
6895
|
+
return normalizeCliPackages(env);
|
|
6896
|
+
const config = await readConfig();
|
|
6897
|
+
return normalizeCliPackages(config.packages ?? DEFAULT_CLI_PACKAGES);
|
|
6898
|
+
}
|
|
6899
|
+
async function resolveOriginClientName() {
|
|
6900
|
+
const config = await readConfig();
|
|
6901
|
+
return typeof config.originClientName === "string" && config.originClientName.trim() ? config.originClientName.trim() : null;
|
|
6902
|
+
}
|
|
6903
|
+
function isKnownConfigKey(key) {
|
|
6904
|
+
return CONFIG_KEYS.includes(key);
|
|
6905
|
+
}
|
|
6906
|
+
function normalizeBaseUrl(url) {
|
|
6907
|
+
let trimmed = url.trim();
|
|
6908
|
+
if (!/^https?:\/\//i.test(trimmed))
|
|
6909
|
+
trimmed = `https://${trimmed}`;
|
|
6910
|
+
const normalized = trimmed.replace(/\/+$/, "");
|
|
6911
|
+
const officialOrigin = /^https:\/\/([^/?#:@]+)$/i.exec(normalized);
|
|
6912
|
+
const loadoutHost = getLoadoutHostForLegacyAidentHost(officialOrigin?.[1]);
|
|
6913
|
+
return loadoutHost ? `https://${loadoutHost}` : normalized;
|
|
6914
|
+
}
|
|
6915
|
+
|
|
6902
6916
|
// ../web/shared/loadout/AidentSemver.ts
|
|
6903
6917
|
var AIDENT_SEMVER_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
6904
6918
|
var AidentSemverSchema = stringType().regex(AIDENT_SEMVER_RE);
|
|
@@ -7128,7 +7142,7 @@ function serializeLoadoutSkillPackage(skillPackage) {
|
|
|
7128
7142
|
}
|
|
7129
7143
|
|
|
7130
7144
|
// src/version.ts
|
|
7131
|
-
var VERSION = "0.3.1";
|
|
7145
|
+
var VERSION = "0.3.2-rc.ci.37567087135.1";
|
|
7132
7146
|
var DESKTOP_VERSION = process.env.AIDENT_DESKTOP_VERSION?.trim() || undefined;
|
|
7133
7147
|
var DESKTOP_CHANNEL = parseDesktopChannel(process.env.AIDENT_DESKTOP_CHANNEL);
|
|
7134
7148
|
function parseDesktopChannel(value) {
|
|
@@ -8494,6 +8508,15 @@ var KNOWN_CLEAN_LOADOUT_SKILL_REQUIRED_FILE_GIT_BLOB_SHA1 = {
|
|
|
8494
8508
|
"references/mcp.md": "4b59cce600b87e1ae2c7cbda8b61f79cd5776fc4",
|
|
8495
8509
|
"references/troubleshooting.md": "f819915c8829b028630ef1f8f29ae9433a072ca8"
|
|
8496
8510
|
}
|
|
8511
|
+
],
|
|
8512
|
+
"0.4.20": [
|
|
8513
|
+
{
|
|
8514
|
+
"SKILL.md": "bb6101455a28b865cbba127c9c9805b04372b561",
|
|
8515
|
+
"references/api.md": "240b913e8c85492f2441326033db91747c54863e",
|
|
8516
|
+
"references/loadout.md": "89e8370f3f70a6f0531151397b73ebd9da270c37",
|
|
8517
|
+
"references/mcp.md": "4b59cce600b87e1ae2c7cbda8b61f79cd5776fc4",
|
|
8518
|
+
"references/troubleshooting.md": "f819915c8829b028630ef1f8f29ae9433a072ca8"
|
|
8519
|
+
}
|
|
8497
8520
|
]
|
|
8498
8521
|
};
|
|
8499
8522
|
async function fetchLoadoutSkillMetadata(baseUrl, signal) {
|
|
@@ -8859,6 +8882,24 @@ class CliClient {
|
|
|
8859
8882
|
async execOperation(packageName, operationId, args, options = {}) {
|
|
8860
8883
|
return this.fetchJson("POST", this.operationPath(packageName, operationId), args, this.takeCatalogTimingHeaders(), options);
|
|
8861
8884
|
}
|
|
8885
|
+
async genDesktopSession(currentUserId) {
|
|
8886
|
+
const response = await fetch(`${this.baseUrl}${LOADOUT_DESKTOP_SESSION_PATH}`, {
|
|
8887
|
+
method: "POST",
|
|
8888
|
+
headers: { Authorization: `Bearer ${this.creds.access_token}`, "Content-Type": "application/json" },
|
|
8889
|
+
body: JSON.stringify({ currentUserId }),
|
|
8890
|
+
redirect: "error",
|
|
8891
|
+
signal: AbortSignal.timeout(20000)
|
|
8892
|
+
});
|
|
8893
|
+
if (!response.ok)
|
|
8894
|
+
return { status: response.status, body: { authenticated: false, cookies: [] } };
|
|
8895
|
+
const { userId, unchanged } = LoadoutDesktopSessionResponseSchema.parse(await response.json());
|
|
8896
|
+
const cookies = response.headers.getSetCookie();
|
|
8897
|
+
if (unchanged && userId === currentUserId)
|
|
8898
|
+
return { status: response.status, body: { authenticated: true, userId, unchanged, cookies: [] } };
|
|
8899
|
+
if (cookies.length === 0)
|
|
8900
|
+
throw new Error("Desktop sign-in exchange returned no session");
|
|
8901
|
+
return { status: response.status, body: { authenticated: true, userId, cookies } };
|
|
8902
|
+
}
|
|
8862
8903
|
takeCatalogTimingHeaders() {
|
|
8863
8904
|
if (this.catalogDurationMs === null)
|
|
8864
8905
|
return;
|