orkestrate 0.1.11 → 0.1.13
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 +289 -67
- package/dist/cli.js.map +1 -1
- package/dist/mcp-entry.js +36 -7
- package/dist/mcp-entry.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -137,6 +137,14 @@ function getActiveWorkspace() {
|
|
|
137
137
|
function getConfigPath() {
|
|
138
138
|
return config.path;
|
|
139
139
|
}
|
|
140
|
+
function setGithubTokens(tokens) {
|
|
141
|
+
const creds = getCredentials();
|
|
142
|
+
if (!creds) return;
|
|
143
|
+
creds.githubAccessToken = tokens.accessToken;
|
|
144
|
+
creds.githubRefreshToken = tokens.refreshToken;
|
|
145
|
+
creds.githubExpiresAt = tokens.expiresAt;
|
|
146
|
+
setCredentials(creds);
|
|
147
|
+
}
|
|
140
148
|
var config;
|
|
141
149
|
var init_config = __esm({
|
|
142
150
|
"src/lib/config.ts"() {
|
|
@@ -156,7 +164,9 @@ var init_config = __esm({
|
|
|
156
164
|
|
|
157
165
|
// src/lib/auth.ts
|
|
158
166
|
import { createHash, randomBytes } from "crypto";
|
|
159
|
-
import {
|
|
167
|
+
import {
|
|
168
|
+
createServer
|
|
169
|
+
} from "http";
|
|
160
170
|
function randomToken(bytes = 32) {
|
|
161
171
|
return randomBytes(bytes).toString("base64url");
|
|
162
172
|
}
|
|
@@ -225,10 +235,15 @@ function waitForCallback(port) {
|
|
|
225
235
|
clearTimeout(timeoutHandle);
|
|
226
236
|
reject(new Error(`Could not start local server: ${err.message}`));
|
|
227
237
|
});
|
|
228
|
-
timeoutHandle = setTimeout(
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
238
|
+
timeoutHandle = setTimeout(
|
|
239
|
+
() => {
|
|
240
|
+
server.close();
|
|
241
|
+
reject(
|
|
242
|
+
new Error("Authentication timed out (5 minutes). Please try again.")
|
|
243
|
+
);
|
|
244
|
+
},
|
|
245
|
+
5 * 60 * 1e3
|
|
246
|
+
);
|
|
232
247
|
timeoutHandle.unref();
|
|
233
248
|
});
|
|
234
249
|
}
|
|
@@ -249,8 +264,61 @@ async function exchangeCodeForTokens(serverUrl, code, clientId, codeVerifier, re
|
|
|
249
264
|
const text = await res.text();
|
|
250
265
|
throw new Error(`Token exchange failed (${res.status}): ${text}`);
|
|
251
266
|
}
|
|
267
|
+
const data = await res.json();
|
|
268
|
+
if (process.env.DEBUG) {
|
|
269
|
+
console.error(
|
|
270
|
+
`[DEBUG] Orkestrate Token: ${data.access_token?.slice(0, 5)}...`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
return data;
|
|
274
|
+
}
|
|
275
|
+
async function startGithubDeviceFlow(serverUrl, accessToken) {
|
|
276
|
+
const res = await fetch(`${serverUrl}/api/oauth/github/auth-url`, {
|
|
277
|
+
method: "POST",
|
|
278
|
+
headers: {
|
|
279
|
+
Authorization: `Bearer ${accessToken}`,
|
|
280
|
+
"Content-Type": "application/json"
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
if (!res.ok) {
|
|
284
|
+
const text = await res.text();
|
|
285
|
+
throw new Error(
|
|
286
|
+
`Failed to start GitHub device flow (${res.status}): ${text}`
|
|
287
|
+
);
|
|
288
|
+
}
|
|
252
289
|
return await res.json();
|
|
253
290
|
}
|
|
291
|
+
async function pollGithubToken(serverUrl, accessToken, userId, deviceCode, intervalSeconds) {
|
|
292
|
+
const pollInterval = (intervalSeconds + 1) * 1e3;
|
|
293
|
+
while (true) {
|
|
294
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
295
|
+
const res = await fetch(`${serverUrl}/api/oauth/github/token`, {
|
|
296
|
+
method: "POST",
|
|
297
|
+
headers: {
|
|
298
|
+
Authorization: `Bearer ${accessToken}`,
|
|
299
|
+
"Content-Type": "application/json"
|
|
300
|
+
},
|
|
301
|
+
body: JSON.stringify({ device_code: deviceCode, user_id: userId })
|
|
302
|
+
});
|
|
303
|
+
const data = await res.json();
|
|
304
|
+
if (data.error === "authorization_pending" || data.error === "slow_down") {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
if (data.error) {
|
|
308
|
+
throw new Error(
|
|
309
|
+
`GitHub authorization failed: ${data.error_description || data.error}`
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
if (!data.access_token) {
|
|
313
|
+
throw new Error("GitHub returned no access token");
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
access_token: data.access_token,
|
|
317
|
+
refresh_token: data.refresh_token,
|
|
318
|
+
expires_in: data.expires_in ?? 3600
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
}
|
|
254
322
|
async function refreshAccessToken() {
|
|
255
323
|
const creds = getCredentials();
|
|
256
324
|
if (!creds?.refreshToken) return null;
|
|
@@ -274,7 +342,10 @@ async function refreshAccessToken() {
|
|
|
274
342
|
refreshToken: tokens.refresh_token,
|
|
275
343
|
expiresAt: now + tokens.expires_in,
|
|
276
344
|
userId: creds.userId,
|
|
277
|
-
scope: tokens.scope
|
|
345
|
+
scope: tokens.scope,
|
|
346
|
+
githubAccessToken: creds.githubAccessToken,
|
|
347
|
+
githubRefreshToken: creds.githubRefreshToken,
|
|
348
|
+
githubExpiresAt: creds.githubExpiresAt
|
|
278
349
|
};
|
|
279
350
|
setCredentials(newCreds);
|
|
280
351
|
return newCreds;
|
|
@@ -303,14 +374,16 @@ async function performLogin() {
|
|
|
303
374
|
authUrl.searchParams.set("redirect_uri", redirectUri);
|
|
304
375
|
authUrl.searchParams.set("code_challenge", codeChallenge);
|
|
305
376
|
authUrl.searchParams.set("code_challenge_method", "S256");
|
|
306
|
-
authUrl.searchParams.set("scope", "mcp:read mcp:write");
|
|
377
|
+
authUrl.searchParams.set("scope", "openid profile email mcp:read mcp:write");
|
|
307
378
|
authUrl.searchParams.set("state", state);
|
|
308
379
|
const callbackPromise = waitForCallback(port);
|
|
309
380
|
const { default: openBrowser } = await import("open");
|
|
310
381
|
await openBrowser(authUrl.toString());
|
|
311
382
|
const { code, state: returnedState } = await callbackPromise;
|
|
312
383
|
if (returnedState !== state) {
|
|
313
|
-
throw new Error(
|
|
384
|
+
throw new Error(
|
|
385
|
+
"Orkestrate OAuth state mismatch \u2014 possible CSRF attack. Aborting."
|
|
386
|
+
);
|
|
314
387
|
}
|
|
315
388
|
const tokens = await exchangeCodeForTokens(
|
|
316
389
|
serverUrl,
|
|
@@ -319,21 +392,66 @@ async function performLogin() {
|
|
|
319
392
|
codeVerifier,
|
|
320
393
|
redirectUri
|
|
321
394
|
);
|
|
322
|
-
|
|
395
|
+
let userId = "";
|
|
396
|
+
try {
|
|
397
|
+
const meRes = await fetch(`${serverUrl}/api/auth/me`, {
|
|
398
|
+
headers: { Authorization: `Bearer ${tokens.access_token}` }
|
|
399
|
+
});
|
|
400
|
+
if (meRes.ok) {
|
|
401
|
+
const me = await meRes.json();
|
|
402
|
+
userId = me.id || "";
|
|
403
|
+
}
|
|
404
|
+
} catch {
|
|
405
|
+
}
|
|
323
406
|
const credentials = {
|
|
324
407
|
clientId,
|
|
325
408
|
accessToken: tokens.access_token,
|
|
326
409
|
refreshToken: tokens.refresh_token,
|
|
327
|
-
expiresAt: now + tokens.expires_in,
|
|
328
|
-
userId
|
|
329
|
-
// Will be resolved on first API call
|
|
410
|
+
expiresAt: Math.floor(Date.now() / 1e3) + tokens.expires_in,
|
|
411
|
+
userId,
|
|
330
412
|
scope: tokens.scope
|
|
331
413
|
};
|
|
332
414
|
setCredentials(credentials);
|
|
415
|
+
let githubConnected = false;
|
|
416
|
+
try {
|
|
417
|
+
const deviceData = await startGithubDeviceFlow(
|
|
418
|
+
serverUrl,
|
|
419
|
+
tokens.access_token
|
|
420
|
+
);
|
|
421
|
+
console.error();
|
|
422
|
+
console.error(" GitHub Device Authorization");
|
|
423
|
+
console.error();
|
|
424
|
+
console.error(` 1. Open: ${deviceData.verification_uri}`);
|
|
425
|
+
console.error(` 2. Enter: ${deviceData.user_code}`);
|
|
426
|
+
console.error();
|
|
427
|
+
console.error(" Waiting for authorization... (press Ctrl+C to cancel)");
|
|
428
|
+
const githubTokens = await pollGithubToken(
|
|
429
|
+
serverUrl,
|
|
430
|
+
tokens.access_token,
|
|
431
|
+
userId,
|
|
432
|
+
deviceData.device_code,
|
|
433
|
+
deviceData.interval
|
|
434
|
+
);
|
|
435
|
+
setGithubTokens({
|
|
436
|
+
accessToken: githubTokens.access_token,
|
|
437
|
+
refreshToken: githubTokens.refresh_token,
|
|
438
|
+
expiresAt: Math.floor(Date.now() / 1e3) + (githubTokens.expires_in ?? 3600)
|
|
439
|
+
});
|
|
440
|
+
githubConnected = true;
|
|
441
|
+
} catch (err) {
|
|
442
|
+
console.error(
|
|
443
|
+
`[Login] GitHub connection failed: ${err instanceof Error ? err.message : String(err)}`
|
|
444
|
+
);
|
|
445
|
+
console.error("[Login] Workspace creation requires GitHub access.");
|
|
446
|
+
console.error(
|
|
447
|
+
"[Login] Re-run `orkestrate login --github` to connect GitHub later."
|
|
448
|
+
);
|
|
449
|
+
}
|
|
333
450
|
return {
|
|
334
451
|
clientId,
|
|
335
452
|
userId: credentials.userId,
|
|
336
|
-
accessToken:
|
|
453
|
+
accessToken: credentials.accessToken,
|
|
454
|
+
githubConnected
|
|
337
455
|
};
|
|
338
456
|
}
|
|
339
457
|
function buildSuccessPage() {
|
|
@@ -379,6 +497,7 @@ function buildSuccessPage() {
|
|
|
379
497
|
</html>`;
|
|
380
498
|
}
|
|
381
499
|
function buildErrorPage(message) {
|
|
500
|
+
const escaped = message.replace(/</g, "<").replace(/>/g, ">");
|
|
382
501
|
return `<!DOCTYPE html>
|
|
383
502
|
<html lang="en">
|
|
384
503
|
<head>
|
|
@@ -412,7 +531,7 @@ function buildErrorPage(message) {
|
|
|
412
531
|
<div class="card">
|
|
413
532
|
<div class="icon">\u2717</div>
|
|
414
533
|
<h1>Authentication Failed</h1>
|
|
415
|
-
<p>${
|
|
534
|
+
<p>${escaped}</p>
|
|
416
535
|
</div>
|
|
417
536
|
</body>
|
|
418
537
|
</html>`;
|
|
@@ -434,22 +553,37 @@ async function loginCommand() {
|
|
|
434
553
|
if (existing?.accessToken) {
|
|
435
554
|
ui.dim("Refreshing existing session...");
|
|
436
555
|
}
|
|
437
|
-
ui.info("Opening browser for authentication...");
|
|
438
|
-
ui.dim("If the browser doesn't open, check your terminal for the URL.");
|
|
556
|
+
ui.info("Opening browser for Orkestrate authentication...");
|
|
439
557
|
ui.blank();
|
|
440
558
|
try {
|
|
441
559
|
const result = await performLogin();
|
|
442
560
|
ui.blank();
|
|
443
|
-
ui.success("
|
|
561
|
+
ui.success("Logged in to Orkestrate!");
|
|
562
|
+
if (result.githubConnected) {
|
|
563
|
+
ui.success("GitHub connected.");
|
|
564
|
+
} else {
|
|
565
|
+
ui.warn(
|
|
566
|
+
"GitHub not connected \u2014 workspace creation will require GitHub access."
|
|
567
|
+
);
|
|
568
|
+
}
|
|
444
569
|
ui.blank();
|
|
445
570
|
ui.info("Next steps:");
|
|
446
|
-
ui.line(
|
|
447
|
-
|
|
448
|
-
|
|
571
|
+
ui.line(
|
|
572
|
+
" 1. orkestrate init \u2014 link your project to a workspace"
|
|
573
|
+
);
|
|
574
|
+
ui.line(
|
|
575
|
+
" 2. orkestrate connect <tool> \u2014 configure your AI tool (claude, opencode, etc.)"
|
|
576
|
+
);
|
|
577
|
+
ui.line(
|
|
578
|
+
" 3. Run your AI tool \u2014 your agent starts and joins the workspace"
|
|
579
|
+
);
|
|
580
|
+
ui.line(" 4. In your AI tool, call: join_workspace <workspace_id>");
|
|
449
581
|
ui.blank();
|
|
450
582
|
ui.dim(`Credentials stored at: ${getConfigPath()}`);
|
|
451
583
|
} catch (err) {
|
|
452
|
-
ui.error(
|
|
584
|
+
ui.error(
|
|
585
|
+
`Login failed: ${err instanceof Error ? err.message : String(err)}`
|
|
586
|
+
);
|
|
453
587
|
process.exit(1);
|
|
454
588
|
}
|
|
455
589
|
}
|
|
@@ -559,12 +693,17 @@ function resolveMcpBridge() {
|
|
|
559
693
|
function configureClaudeCode(bridge) {
|
|
560
694
|
if (!isCommandAvailable("claude")) return { success: false, message: "Claude Code CLI not found." };
|
|
561
695
|
try {
|
|
562
|
-
|
|
696
|
+
try {
|
|
697
|
+
execSync("claude mcp remove Orkestrate", { stdio: "pipe" });
|
|
698
|
+
} catch {
|
|
699
|
+
}
|
|
700
|
+
const commandToRun = bridge.command;
|
|
701
|
+
const argsToRun = bridge.args.join(" ");
|
|
563
702
|
execSync(
|
|
564
|
-
`claude mcp add --transport stdio --scope project Orkestrate
|
|
703
|
+
`claude mcp add --transport stdio --scope project Orkestrate ${commandToRun} ${argsToRun}`,
|
|
565
704
|
{ stdio: "pipe", encoding: "utf-8" }
|
|
566
705
|
);
|
|
567
|
-
return { success: true, message: "MCP added to Claude Code
|
|
706
|
+
return { success: true, message: "MCP added to Claude Code." };
|
|
568
707
|
} catch (err) {
|
|
569
708
|
return { success: false, message: `Claude config failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
570
709
|
}
|
|
@@ -661,62 +800,106 @@ async function connectCommand(toolName) {
|
|
|
661
800
|
ui.error("Not authenticated. Run `orkestrate login` first.");
|
|
662
801
|
process.exit(1);
|
|
663
802
|
}
|
|
664
|
-
const validTools = getToolNames();
|
|
665
803
|
if (!toolName) {
|
|
666
|
-
ui.header("
|
|
804
|
+
ui.header("Connect Orkestrate MCP");
|
|
667
805
|
const detected = detectTools();
|
|
668
806
|
const found = detected.filter((t) => t.detected);
|
|
669
|
-
if (found.length
|
|
670
|
-
ui.
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
for (const name of validTools) {
|
|
674
|
-
ui.line(` \u2022 ${name}`);
|
|
807
|
+
if (found.length > 0) {
|
|
808
|
+
ui.info("Detected AI tools:");
|
|
809
|
+
for (const tool of found) {
|
|
810
|
+
ui.success(` ${tool.displayName}`);
|
|
675
811
|
}
|
|
676
812
|
ui.blank();
|
|
677
|
-
ui.info("Usage: orkestrate connect <tool>");
|
|
678
|
-
return;
|
|
679
813
|
}
|
|
680
|
-
|
|
681
|
-
if (tool2.detected) {
|
|
682
|
-
ui.success(`${tool2.displayName} \u2014 detected`);
|
|
683
|
-
} else {
|
|
684
|
-
ui.dim(`${tool2.displayName} \u2014 not found`);
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
ui.blank();
|
|
688
|
-
ui.info("Run `orkestrate connect <tool>` to configure. Example:");
|
|
689
|
-
ui.line(` orkestrate connect ${found[0].name}`);
|
|
814
|
+
displayGenericInstructions();
|
|
690
815
|
return;
|
|
691
816
|
}
|
|
692
|
-
const
|
|
693
|
-
|
|
694
|
-
|
|
817
|
+
const normalized = toolName.toLowerCase().trim();
|
|
818
|
+
const isAutoConfig = SUPPORTED_AUTO_CONFIG.includes(normalized);
|
|
819
|
+
if (!isAutoConfig) {
|
|
820
|
+
ui.header(`Connect ${normalized} to Orkestrate`);
|
|
695
821
|
ui.blank();
|
|
696
|
-
ui.info("
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
822
|
+
ui.info("Orkestrate MCP endpoint:");
|
|
823
|
+
ui.line(` ${getServerUrl()}/api/mcp`);
|
|
824
|
+
ui.blank();
|
|
825
|
+
displayGenericInstructions();
|
|
826
|
+
ui.blank();
|
|
827
|
+
ui.info(
|
|
828
|
+
`To configure ${normalized} with Orkestrate MCP, add it as a stdio MCP server.`
|
|
829
|
+
);
|
|
830
|
+
ui.dim(
|
|
831
|
+
`Restart ${normalized} after configuring MCP for changes to take effect.`
|
|
832
|
+
);
|
|
833
|
+
return;
|
|
701
834
|
}
|
|
702
|
-
ui.info(`Configuring MCP for ${toolName}...`);
|
|
703
|
-
const result = await configureTool(
|
|
835
|
+
ui.info(`Configuring Orkestrate MCP for ${toolName}...`);
|
|
836
|
+
const result = await configureTool(normalized);
|
|
704
837
|
if (result.success) {
|
|
705
838
|
ui.success(result.message);
|
|
706
839
|
ui.blank();
|
|
707
|
-
ui.info("Your AI tool
|
|
840
|
+
ui.info("Your AI tool is now connected to Orkestrate.");
|
|
708
841
|
ui.dim("Restart your tool if it's currently running.");
|
|
709
842
|
} else {
|
|
710
843
|
ui.error(result.message);
|
|
711
844
|
process.exit(1);
|
|
712
845
|
}
|
|
713
846
|
}
|
|
847
|
+
function displayGenericInstructions() {
|
|
848
|
+
const mcpUrl = `${getServerUrl()}/api/mcp`;
|
|
849
|
+
const bridgeCommand = "orkestrate";
|
|
850
|
+
const bridgeArgs = "mcp";
|
|
851
|
+
ui.info("Generic MCP Setup (for any tool that supports stdio MCP):");
|
|
852
|
+
ui.blank();
|
|
853
|
+
ui.line(" Add Orkestrate as an MCP server with:");
|
|
854
|
+
ui.blank();
|
|
855
|
+
ui.line(` Command: ${bridgeCommand}`);
|
|
856
|
+
ui.line(` Args: ${bridgeArgs}`);
|
|
857
|
+
ui.blank();
|
|
858
|
+
ui.dim(" Tool-specific setup:");
|
|
859
|
+
ui.blank();
|
|
860
|
+
ui.line(" Claude Code:");
|
|
861
|
+
ui.line(
|
|
862
|
+
` claude mcp add --transport stdio Orkestrate ${bridgeCommand} ${bridgeArgs}`
|
|
863
|
+
);
|
|
864
|
+
ui.blank();
|
|
865
|
+
ui.line(" Cursor:");
|
|
866
|
+
ui.line(" Settings \u2192 MCP \u2192 Add new server:");
|
|
867
|
+
ui.line(` Name: Orkestrate`);
|
|
868
|
+
ui.line(` Command: ${bridgeCommand}`);
|
|
869
|
+
ui.line(` Args: ${bridgeArgs}`);
|
|
870
|
+
ui.blank();
|
|
871
|
+
ui.line(" Windsurf:");
|
|
872
|
+
ui.line(" Settings \u2192 MCP \u2192 Add server:");
|
|
873
|
+
ui.line(` Command: ${bridgeCommand}`);
|
|
874
|
+
ui.line(` Args: ${bridgeArgs}`);
|
|
875
|
+
ui.blank();
|
|
876
|
+
ui.line(" OpenCode:");
|
|
877
|
+
ui.line(" Add to opencode.json mcp servers:");
|
|
878
|
+
ui.blank();
|
|
879
|
+
ui.line(" Codex:");
|
|
880
|
+
ui.line(` Add to ~/.codex/config.toml:`);
|
|
881
|
+
ui.line(` [mcp_servers.Orkestrate]`);
|
|
882
|
+
ui.line(` command = "${bridgeCommand}"`);
|
|
883
|
+
ui.line(` args = ["${bridgeArgs}"]`);
|
|
884
|
+
ui.blank();
|
|
885
|
+
ui.dim(
|
|
886
|
+
" Not sure if your tool supports MCP? Check its docs for 'MCP server'."
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
var SUPPORTED_AUTO_CONFIG;
|
|
714
890
|
var init_connect = __esm({
|
|
715
891
|
"src/commands/connect.ts"() {
|
|
716
892
|
"use strict";
|
|
717
893
|
init_config();
|
|
718
894
|
init_detect();
|
|
719
895
|
init_ui();
|
|
896
|
+
SUPPORTED_AUTO_CONFIG = [
|
|
897
|
+
"claude",
|
|
898
|
+
"opencode",
|
|
899
|
+
"cursor",
|
|
900
|
+
"windsurf",
|
|
901
|
+
"codex"
|
|
902
|
+
];
|
|
720
903
|
}
|
|
721
904
|
});
|
|
722
905
|
|
|
@@ -726,6 +909,7 @@ __export(api_exports, {
|
|
|
726
909
|
ApiError: () => ApiError,
|
|
727
910
|
checkHealth: () => checkHealth,
|
|
728
911
|
createWorkspace: () => createWorkspace,
|
|
912
|
+
getMe: () => getMe,
|
|
729
913
|
getTeamStatus: () => getTeamStatus,
|
|
730
914
|
listWorkspaces: () => listWorkspaces,
|
|
731
915
|
switchWorkspace: () => switchWorkspace
|
|
@@ -747,7 +931,7 @@ async function request(method, path, body) {
|
|
|
747
931
|
const maskedToken = token.length > 10 ? `${token.slice(0, 5)}...${token.slice(-5)}` : "***";
|
|
748
932
|
if (process.env.DEBUG) {
|
|
749
933
|
console.error(`[DEBUG] API Request: ${method} ${serverUrl}${path}`);
|
|
750
|
-
console.error(`[DEBUG] Token: ${maskedToken}`);
|
|
934
|
+
console.error(`[DEBUG] Token: ${maskedToken} (len: ${token.length})`);
|
|
751
935
|
}
|
|
752
936
|
const res = await fetch(`${serverUrl}${path}`, {
|
|
753
937
|
method,
|
|
@@ -764,6 +948,10 @@ async function request(method, path, body) {
|
|
|
764
948
|
}
|
|
765
949
|
return await res.json();
|
|
766
950
|
}
|
|
951
|
+
async function getMe() {
|
|
952
|
+
const data = await request("GET", "/api/auth/me");
|
|
953
|
+
return data.user;
|
|
954
|
+
}
|
|
767
955
|
async function listWorkspaces() {
|
|
768
956
|
const data = await request("GET", "/api/workspaces");
|
|
769
957
|
return data.workspaces || [];
|
|
@@ -1165,7 +1353,12 @@ async function initCommand() {
|
|
|
1165
1353
|
}
|
|
1166
1354
|
}
|
|
1167
1355
|
} catch (err) {
|
|
1168
|
-
|
|
1356
|
+
if (err instanceof Error && err.message.includes("401")) {
|
|
1357
|
+
ui.warn("Authentication failed (401). Your session may have expired.");
|
|
1358
|
+
ui.info("Please run `orkestrate login` to refresh your session.");
|
|
1359
|
+
} else {
|
|
1360
|
+
ui.dim(`Could not fetch workspaces: ${err instanceof Error ? err.message : String(err)}`);
|
|
1361
|
+
}
|
|
1169
1362
|
}
|
|
1170
1363
|
ui.blank();
|
|
1171
1364
|
const tools = detectTools(cwd);
|
|
@@ -1204,7 +1397,7 @@ async function initCommand() {
|
|
|
1204
1397
|
writeFileSync2(configFile, JSON.stringify(projectConfig, null, 2) + "\n", "utf-8");
|
|
1205
1398
|
ui.blank();
|
|
1206
1399
|
ui.success(`Created .orkestrate.json`);
|
|
1207
|
-
ui.dim("
|
|
1400
|
+
ui.dim("This file identifies your project workspace. It is gitignored by default.");
|
|
1208
1401
|
}
|
|
1209
1402
|
} else {
|
|
1210
1403
|
try {
|
|
@@ -1254,8 +1447,12 @@ async function mcpCommand() {
|
|
|
1254
1447
|
const mcpUrl = `${serverUrl}/api/mcp`;
|
|
1255
1448
|
process.stdin.setEncoding("utf-8");
|
|
1256
1449
|
let buffer = "";
|
|
1450
|
+
process.stderr.write(`[Orkestrate-MCP] Starting bridge to ${mcpUrl}
|
|
1451
|
+
`);
|
|
1257
1452
|
process.stdin.on("data", async (chunk) => {
|
|
1258
1453
|
const rawChunk = String(chunk);
|
|
1454
|
+
if (process.env.DEBUG) process.stderr.write(`[Orkestrate-MCP] Received chunk: ${rawChunk}
|
|
1455
|
+
`);
|
|
1259
1456
|
buffer += rawChunk;
|
|
1260
1457
|
let lineEndIndex;
|
|
1261
1458
|
while ((lineEndIndex = buffer.indexOf("\n")) >= 0) {
|
|
@@ -1264,17 +1461,18 @@ async function mcpCommand() {
|
|
|
1264
1461
|
if (!line) continue;
|
|
1265
1462
|
if (line.includes("}{")) {
|
|
1266
1463
|
const parts = line.split("}{");
|
|
1267
|
-
processLine(parts[0] + "}", mcpUrl);
|
|
1464
|
+
await processLine(parts[0] + "}", mcpUrl);
|
|
1268
1465
|
for (let i = 1; i < parts.length - 1; i++) {
|
|
1269
|
-
processLine("{" + parts[i] + "}", mcpUrl);
|
|
1466
|
+
await processLine("{" + parts[i] + "}", mcpUrl);
|
|
1270
1467
|
}
|
|
1271
|
-
processLine("{" + parts[parts.length - 1], mcpUrl);
|
|
1468
|
+
await processLine("{" + parts[parts.length - 1], mcpUrl);
|
|
1272
1469
|
} else {
|
|
1273
|
-
processLine(line, mcpUrl);
|
|
1470
|
+
await processLine(line, mcpUrl);
|
|
1274
1471
|
}
|
|
1275
1472
|
}
|
|
1276
1473
|
});
|
|
1277
|
-
process.stdin.on("end", () => {
|
|
1474
|
+
process.stdin.on("end", async () => {
|
|
1475
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
1278
1476
|
process.exit(0);
|
|
1279
1477
|
});
|
|
1280
1478
|
await new Promise(() => {
|
|
@@ -1286,10 +1484,14 @@ async function mcpCommand() {
|
|
|
1286
1484
|
}
|
|
1287
1485
|
}
|
|
1288
1486
|
async function processLine(line, mcpUrl) {
|
|
1487
|
+
if (process.env.DEBUG) process.stderr.write(`[Orkestrate-MCP] Processing line: ${line}
|
|
1488
|
+
`);
|
|
1289
1489
|
let payload;
|
|
1290
1490
|
try {
|
|
1291
1491
|
payload = JSON.parse(line);
|
|
1292
1492
|
} catch {
|
|
1493
|
+
if (process.env.DEBUG) process.stderr.write(`[Orkestrate-MCP] JSON Parse failed for: ${line}
|
|
1494
|
+
`);
|
|
1293
1495
|
return;
|
|
1294
1496
|
}
|
|
1295
1497
|
const isNotification = !Object.prototype.hasOwnProperty.call(payload, "id");
|
|
@@ -1310,6 +1512,21 @@ async function processLine(line, mcpUrl) {
|
|
|
1310
1512
|
});
|
|
1311
1513
|
if (isNotification) return;
|
|
1312
1514
|
const responseBody = await res.text();
|
|
1515
|
+
if (!res.ok) {
|
|
1516
|
+
process.stderr.write(`[Orkestrate-MCP] Backend error (${res.status}): ${responseBody}
|
|
1517
|
+
`);
|
|
1518
|
+
if (!isNotification) {
|
|
1519
|
+
process.stdout.write(JSON.stringify({
|
|
1520
|
+
jsonrpc: "2.0",
|
|
1521
|
+
id: requestId,
|
|
1522
|
+
error: {
|
|
1523
|
+
code: -32603,
|
|
1524
|
+
message: `Orkestrate Cloud Error (${res.status}): ${responseBody || "Unauthorized"}. Please try 'orkestrate login'.`
|
|
1525
|
+
}
|
|
1526
|
+
}) + "\n");
|
|
1527
|
+
}
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1313
1530
|
if (responseBody) {
|
|
1314
1531
|
process.stdout.write(responseBody + "\n");
|
|
1315
1532
|
}
|
|
@@ -1348,9 +1565,14 @@ async function whoamiCommand() {
|
|
|
1348
1565
|
ui.blank();
|
|
1349
1566
|
if (creds?.accessToken) {
|
|
1350
1567
|
ui.success("Authenticated");
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1568
|
+
try {
|
|
1569
|
+
const { getMe: getMe2 } = await Promise.resolve().then(() => (init_api(), api_exports));
|
|
1570
|
+
const user = await getMe2();
|
|
1571
|
+
ui.kv("User", user.email);
|
|
1572
|
+
ui.kv("User ID", user.id);
|
|
1573
|
+
} catch {
|
|
1574
|
+
ui.kv("Client ID", creds.clientId);
|
|
1575
|
+
ui.dim("Could not fetch user info from server.");
|
|
1354
1576
|
}
|
|
1355
1577
|
const expiresIn = creds.expiresAt - Math.floor(Date.now() / 1e3);
|
|
1356
1578
|
if (expiresIn > 0) {
|
|
@@ -1391,7 +1613,7 @@ var init_whoami = __esm({
|
|
|
1391
1613
|
init_ui();
|
|
1392
1614
|
import { Command } from "commander";
|
|
1393
1615
|
var program = new Command();
|
|
1394
|
-
program.name("orkestrate").description("The coordination layer for autonomous AI coding agents").version("0.1.
|
|
1616
|
+
program.name("orkestrate").description("The coordination layer for autonomous AI coding agents").version("0.1.12").hook("preAction", () => {
|
|
1395
1617
|
});
|
|
1396
1618
|
program.command("login").description("Authenticate with Orkestrate via browser OAuth").action(async () => {
|
|
1397
1619
|
const { loginCommand: loginCommand2 } = await Promise.resolve().then(() => (init_login(), login_exports));
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/ui.ts","../src/lib/config.ts","../src/lib/auth.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/lib/detect.ts","../src/commands/connect.ts","../src/lib/api.ts","../src/commands/status.ts","../src/commands/workspace.ts","../src/lib/git.ts","../src/commands/init.ts","../src/commands/mcp.ts","../src/commands/whoami.ts","../src/cli.ts"],"sourcesContent":["/**\n * Orkestrate CLI — Terminal UI Helpers\n *\n * Pretty output formatting for the terminal.\n */\n\nimport pc from \"picocolors\";\n\nexport const ui = {\n // Status icons\n success: (msg: string) => console.log(` ${pc.green(\"✓\")} ${msg}`),\n error: (msg: string) => console.log(` ${pc.red(\"✗\")} ${msg}`),\n info: (msg: string) => console.log(` ${pc.blue(\"→\")} ${msg}`),\n warn: (msg: string) => console.log(` ${pc.yellow(\"!\")} ${msg}`),\n dim: (msg: string) => console.log(` ${pc.dim(msg)}`),\n\n // Headers\n header: (msg: string) => {\n console.log();\n console.log(` ${pc.bold(pc.white(msg))}`);\n console.log();\n },\n\n // Blank line\n blank: () => console.log(),\n\n // Indented line\n line: (msg: string) => console.log(` ${msg}`),\n\n // Key-value pair\n kv: (key: string, value: string) => {\n console.log(` ${pc.dim(key + \":\")} ${value}`);\n },\n\n // Table\n table: (headers: string[], rows: string[][]) => {\n const colWidths = headers.map((h, i) => {\n const maxContent = Math.max(h.length, ...rows.map((r) => (r[i] || \"\").length));\n return Math.min(maxContent, 40);\n });\n\n const separator = \"─\";\n const pad = (s: string, w: number) => s.padEnd(w).slice(0, w);\n\n // Top border\n console.log(\n ` ┌${colWidths.map((w) => separator.repeat(w + 2)).join(\"┬\")}┐`,\n );\n\n // Header row\n console.log(\n ` │${headers.map((h, i) => ` ${pc.bold(pad(h, colWidths[i]))} `).join(\"│\")}│`,\n );\n\n // Header separator\n console.log(\n ` ├${colWidths.map((w) => separator.repeat(w + 2)).join(\"┼\")}┤`,\n );\n\n // Data rows\n for (const row of rows) {\n console.log(\n ` │${row.map((c, i) => ` ${pad(c || \"\", colWidths[i])} `).join(\"│\")}│`,\n );\n }\n\n // Bottom border\n console.log(\n ` └${colWidths.map((w) => separator.repeat(w + 2)).join(\"┴\")}┘`,\n );\n },\n\n // Colored status badge\n statusBadge: (status: string): string => {\n switch (status) {\n case \"active\":\n return pc.green(\"● active\");\n case \"idle\":\n return pc.dim(\"○ idle\");\n case \"blocked\":\n return pc.red(\"■ blocked\");\n case \"planning\":\n return pc.blue(\"◆ planning\");\n case \"handoff\":\n return pc.yellow(\"⇄ handoff\");\n case \"done\":\n return pc.dim(\"✓ done\");\n default:\n return pc.dim(status);\n }\n },\n\n // Interactive prompts\n confirm: async (question: string, defaultYes = true): Promise<boolean> => {\n const { createInterface } = await import(\"node:readline/promises\");\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n const suffix = defaultYes ? \"[Y/n]\" : \"[y/N]\";\n const answer = await rl.question(` ${pc.bold(pc.white(question))} ${pc.dim(suffix)} `);\n rl.close();\n if (!answer) return defaultYes;\n return answer.toLowerCase().startsWith(\"y\");\n },\n\n input: async (question: string, defaultValue?: string): Promise<string> => {\n const { createInterface } = await import(\"node:readline/promises\");\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n const suffix = defaultValue ? pc.dim(` (${defaultValue})`) : \"\";\n const answer = await rl.question(` ${pc.bold(pc.white(question))}${suffix} `);\n rl.close();\n return answer || defaultValue || \"\";\n },\n\n // Banner\n banner: () => {\n console.log();\n console.log(pc.bold(pc.cyan(\" ⬡ orkestrate\")));\n console.log(pc.dim(\" the coordination layer for AI coding agents\"));\n console.log();\n },\n};\n","/**\n * Orkestrate CLI — Configuration Management\n *\n * Stores credentials and preferences in the user's home directory.\n * Uses the `conf` package for cross-platform config storage.\n */\n\nimport Conf from \"conf\";\n\nexport interface StoredCredentials {\n clientId: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number; // epoch seconds\n userId: string;\n scope: string;\n}\n\nexport interface CliConfig {\n credentials: StoredCredentials | null;\n activeWorkspaceId: string | null;\n activeWorkspaceName: string | null;\n serverUrl: string;\n}\n\nconst config = new Conf<CliConfig>({\n projectName: \"orkestrate\",\n projectSuffix: \"\",\n defaults: {\n credentials: null,\n activeWorkspaceId: null,\n activeWorkspaceName: null,\n serverUrl: \"https://orkestrate.space\",\n },\n});\n\nexport function getConfig(): CliConfig {\n return {\n credentials: config.get(\"credentials\"),\n activeWorkspaceId: config.get(\"activeWorkspaceId\"),\n activeWorkspaceName: config.get(\"activeWorkspaceName\"),\n serverUrl: config.get(\"serverUrl\"),\n };\n}\n\nexport function getServerUrl(): string {\n return config.get(\"serverUrl\");\n}\n\nexport function setCredentials(creds: StoredCredentials): void {\n config.set(\"credentials\", creds);\n}\n\nexport function getCredentials(): StoredCredentials | null {\n return config.get(\"credentials\");\n}\n\nexport function clearCredentials(): void {\n config.set(\"credentials\", null);\n}\n\nexport function setActiveWorkspace(id: string, name: string): void {\n config.set(\"activeWorkspaceId\", id);\n config.set(\"activeWorkspaceName\", name);\n}\n\nexport function getActiveWorkspace(): { id: string | null; name: string | null } {\n return {\n id: config.get(\"activeWorkspaceId\"),\n name: config.get(\"activeWorkspaceName\"),\n };\n}\n\nexport function setServerUrl(url: string): void {\n config.set(\"serverUrl\", url);\n}\n\nexport function clearAll(): void {\n config.clear();\n}\n\nexport function getConfigPath(): string {\n return config.path;\n}\n","/**\n * Orkestrate CLI — OAuth Authentication\n *\n * Implements the full OAuth 2.0 + PKCE flow:\n * 1. Dynamic client registration\n * 2. Open browser for consent\n * 3. Local HTTP callback server\n * 4. Token exchange\n * 5. Credential storage\n */\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport {\n getServerUrl,\n setCredentials,\n getCredentials,\n type StoredCredentials,\n} from \"./config.js\";\n\nfunction randomToken(bytes = 32): string {\n return randomBytes(bytes).toString(\"base64url\");\n}\n\nfunction pkceS256(verifier: string): string {\n return createHash(\"sha256\").update(verifier).digest(\"base64url\");\n}\n\ninterface TokenResponse {\n token_type: string;\n access_token: string;\n expires_in: number;\n refresh_token: string;\n scope: string;\n}\n\n/**\n * Step 1: Register this CLI instance as an OAuth client.\n */\nasync function registerClient(\n serverUrl: string,\n redirectUri: string,\n): Promise<{ clientId: string }> {\n const res = await fetch(`${serverUrl}/api/oauth/register`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n client_name: \"Orkestrate CLI\",\n redirect_uris: [redirectUri],\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\",\n }),\n });\n\n if (!res.ok) {\n const body = await res.text();\n throw new Error(`Client registration failed (${res.status}): ${body}`);\n }\n\n const data = (await res.json()) as { client_id: string };\n return { clientId: data.client_id };\n}\n\n/**\n * Step 2 & 3: Open browser and wait for the OAuth callback.\n */\nfunction waitForCallback(\n port: number,\n): Promise<{ code: string; state: string }> {\n return new Promise((resolve, reject) => {\n let timeoutHandle: ReturnType<typeof setTimeout>;\n\n function cleanup() {\n clearTimeout(timeoutHandle);\n server.close();\n }\n\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url || \"/\", `http://localhost:${port}`);\n\n if (url.pathname !== \"/callback\") {\n res.writeHead(404);\n res.end(\"Not found\");\n return;\n }\n\n const code = url.searchParams.get(\"code\");\n const error = url.searchParams.get(\"error\");\n const state = url.searchParams.get(\"state\") || \"\";\n\n if (error) {\n const description = url.searchParams.get(\"error_description\") || error;\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(buildErrorPage(description));\n cleanup();\n reject(new Error(`OAuth error: ${description}`));\n return;\n }\n\n if (!code) {\n res.writeHead(400, { \"Content-Type\": \"text/html\" });\n res.end(buildErrorPage(\"No authorization code received.\"));\n cleanup();\n reject(new Error(\"No authorization code received\"));\n return;\n }\n\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(buildSuccessPage());\n cleanup();\n resolve({ code, state });\n });\n\n server.listen(port, \"127.0.0.1\", () => {\n // Server ready\n });\n\n server.on(\"error\", (err: Error) => {\n clearTimeout(timeoutHandle);\n reject(new Error(`Could not start local server: ${err.message}`));\n });\n\n // Timeout after 5 minutes — unref so it doesn't block process exit\n timeoutHandle = setTimeout(() => {\n server.close();\n reject(new Error(\"Authentication timed out (5 minutes). Please try again.\"));\n }, 5 * 60 * 1000);\n timeoutHandle.unref();\n });\n}\n\n/**\n * Step 4: Exchange authorization code for tokens.\n */\nasync function exchangeCodeForTokens(\n serverUrl: string,\n code: string,\n clientId: string,\n codeVerifier: string,\n redirectUri: string,\n): Promise<TokenResponse> {\n const body = new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n code_verifier: codeVerifier,\n client_id: clientId,\n redirect_uri: redirectUri,\n });\n\n const res = await fetch(`${serverUrl}/api/oauth/token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Token exchange failed (${res.status}): ${text}`);\n }\n\n return (await res.json()) as TokenResponse;\n}\n\n/**\n * Refresh an expired access token.\n */\nexport async function refreshAccessToken(): Promise<StoredCredentials | null> {\n const creds = getCredentials();\n if (!creds?.refreshToken) return null;\n\n const serverUrl = getServerUrl();\n const body = new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: creds.refreshToken,\n client_id: creds.clientId,\n });\n\n const res = await fetch(`${serverUrl}/api/oauth/token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) return null;\n\n const tokens = (await res.json()) as TokenResponse;\n const now = Math.floor(Date.now() / 1000);\n\n const newCreds: StoredCredentials = {\n clientId: creds.clientId,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: now + tokens.expires_in,\n userId: creds.userId,\n scope: tokens.scope,\n };\n\n setCredentials(newCreds);\n return newCreds;\n}\n\n/**\n * Get a valid access token, refreshing if needed.\n */\nexport async function getValidToken(): Promise<string | null> {\n const creds = getCredentials();\n if (!creds) return null;\n\n const now = Math.floor(Date.now() / 1000);\n\n // Refresh if expired or expiring within 60 seconds\n if (creds.expiresAt <= now + 60) {\n const refreshed = await refreshAccessToken();\n return refreshed?.accessToken || null;\n }\n\n return creds.accessToken;\n}\n\n/**\n * Run the full OAuth login flow.\n */\nexport async function performLogin(): Promise<{\n clientId: string;\n userId: string;\n accessToken: string;\n}> {\n const serverUrl = getServerUrl();\n const port = 19274; // \"ork\" on a phone keypad, roughly\n const redirectUri = `http://127.0.0.1:${port}/callback`;\n\n // Step 1: Register client\n const { clientId } = await registerClient(serverUrl, redirectUri);\n\n // Step 2: Prepare PKCE\n const codeVerifier = randomToken(48);\n const codeChallenge = pkceS256(codeVerifier);\n const state = randomToken(16);\n\n // Step 3: Build authorization URL\n const authUrl = new URL(`${serverUrl}/api/oauth/authorize`);\n authUrl.searchParams.set(\"response_type\", \"code\");\n authUrl.searchParams.set(\"client_id\", clientId);\n authUrl.searchParams.set(\"redirect_uri\", redirectUri);\n authUrl.searchParams.set(\"code_challenge\", codeChallenge);\n authUrl.searchParams.set(\"code_challenge_method\", \"S256\");\n authUrl.searchParams.set(\"scope\", \"mcp:read mcp:write\");\n authUrl.searchParams.set(\"state\", state);\n\n // Step 4: Start callback server + open browser\n const callbackPromise = waitForCallback(port);\n\n // Dynamic import to handle ESM-only `open` package\n const { default: openBrowser } = await import(\"open\");\n await openBrowser(authUrl.toString());\n\n // Step 5: Wait for callback\n const { code, state: returnedState } = await callbackPromise;\n\n if (returnedState !== state) {\n throw new Error(\"OAuth state mismatch — possible CSRF attack. Aborting.\");\n }\n\n // Step 6: Exchange code for tokens\n const tokens = await exchangeCodeForTokens(\n serverUrl,\n code,\n clientId,\n codeVerifier,\n redirectUri,\n );\n\n const now = Math.floor(Date.now() / 1000);\n\n // We don't get user_id from the token response directly.\n // We'll extract it from the MCP endpoint or store a placeholder.\n // For now, use clientId as a proxy until first API call resolves it.\n const credentials: StoredCredentials = {\n clientId,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: now + tokens.expires_in,\n userId: \"\", // Will be resolved on first API call\n scope: tokens.scope,\n };\n\n setCredentials(credentials);\n\n return {\n clientId,\n userId: credentials.userId,\n accessToken: tokens.access_token,\n };\n}\n\n// --- HTML pages for the local callback server ---\n\nfunction buildSuccessPage(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>Orkestrate — Authenticated</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .card {\n text-align: center;\n padding: 3rem;\n border: 1px solid #262626;\n border-radius: 12px;\n background: #111;\n max-width: 420px;\n }\n .icon { font-size: 3rem; margin-bottom: 1rem; }\n h1 { font-size: 1.5rem; margin-bottom: 0.5rem; color: #fff; }\n p { color: #a3a3a3; line-height: 1.6; }\n .hint { margin-top: 1.5rem; font-size: 0.85rem; color: #525252; }\n </style>\n</head>\n<body>\n <div class=\"card\">\n <div class=\"icon\">✓</div>\n <h1>Authenticated</h1>\n <p>You're now logged in to Orkestrate. You can close this tab and return to your terminal.</p>\n <p class=\"hint\">This window will close automatically.</p>\n </div>\n <script>setTimeout(() => window.close(), 3000);</script>\n</body>\n</html>`;\n}\n\nfunction buildErrorPage(message: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>Orkestrate — Error</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .card {\n text-align: center;\n padding: 3rem;\n border: 1px solid #371717;\n border-radius: 12px;\n background: #1a0a0a;\n max-width: 420px;\n }\n .icon { font-size: 3rem; margin-bottom: 1rem; }\n h1 { font-size: 1.5rem; margin-bottom: 0.5rem; color: #fca5a5; }\n p { color: #a3a3a3; line-height: 1.6; }\n </style>\n</head>\n<body>\n <div class=\"card\">\n <div class=\"icon\">✗</div>\n <h1>Authentication Failed</h1>\n <p>${message}</p>\n </div>\n</body>\n</html>`;\n}\n","/**\n * orkestrate login\n *\n * Authenticate with Orkestrate via OAuth browser flow.\n */\n\nimport { performLogin } from \"../lib/auth.js\";\nimport { getCredentials, getConfigPath } from \"../lib/config.js\";\nimport { listWorkspaces } from \"../lib/api.js\";\nimport { setActiveWorkspace } from \"../lib/config.js\";\nimport { ui } from \"../lib/ui.js\";\n\nexport async function loginCommand(): Promise<void> {\n // Check if already logged in (optional info, not a block)\n const existing = getCredentials();\n if (existing?.accessToken) {\n ui.dim(\"Refreshing existing session...\");\n }\n\n ui.info(\"Opening browser for authentication...\");\n ui.dim(\"If the browser doesn't open, check your terminal for the URL.\");\n ui.blank();\n\n try {\n const result = await performLogin();\n ui.blank();\n\n ui.success(\"Authenticated successfully!\");\n ui.blank();\n ui.info(\"Next steps:\");\n ui.line(\" 1. Run `orkestrate init` in your project folder\");\n ui.line(\" 2. Select/Create a workspace\");\n ui.line(\" 3. Connect your AI tools\");\n ui.blank();\n ui.dim(`Credentials stored at: ${getConfigPath()}`);\n } catch (err) {\n ui.error(`Login failed: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n","/**\n * orkestrate logout\n *\n * Clear stored credentials.\n */\n\nimport { clearCredentials, getCredentials, getConfigPath } from \"../lib/config.js\";\nimport { ui } from \"../lib/ui.js\";\n\nexport function logoutCommand(): void {\n const existing = getCredentials();\n\n if (!existing?.accessToken) {\n ui.dim(\"Not currently logged in.\");\n return;\n }\n\n clearCredentials();\n ui.success(\"Logged out. Credentials cleared.\");\n ui.dim(`Config: ${getConfigPath()}`);\n}\n","/**\n * Orkestrate CLI — Tool Detection & MCP Configuration\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport { getServerUrl } from \"./config.js\";\n\nexport type ToolName = \"claude\" | \"opencode\" | \"cursor\" | \"windsurf\" | \"codex\";\n\nexport interface DetectedTool {\n name: ToolName;\n displayName: string;\n detected: boolean;\n configPath?: string;\n}\n\n/**\n * Detect which AI coding tools are available on this system.\n */\nexport function detectTools(projectDir: string = process.cwd()): DetectedTool[] {\n const tools: DetectedTool[] = [];\n\n // Claude Code\n tools.push({\n name: \"claude\",\n displayName: \"Claude Code\",\n detected: isCommandAvailable(\"claude\"),\n });\n\n // OpenCode\n const opencodeConfig = join(projectDir, \"opencode.json\");\n tools.push({\n name: \"opencode\",\n displayName: \"OpenCode\",\n detected: existsSync(opencodeConfig) || isCommandAvailable(\"opencode\"),\n configPath: opencodeConfig,\n });\n\n // Cursor\n const cursorConfig = join(projectDir, \".cursor\", \"mcp.json\");\n tools.push({\n name: \"cursor\",\n displayName: \"Cursor\",\n detected: existsSync(join(projectDir, \".cursor\")) || existsSync(cursorConfig),\n configPath: cursorConfig,\n });\n\n // Windsurf\n const windsurfConfig = join(projectDir, \".windsurf\", \"mcp.json\");\n tools.push({\n name: \"windsurf\",\n displayName: \"Windsurf\",\n detected: existsSync(join(projectDir, \".windsurf\")) || existsSync(windsurfConfig),\n configPath: windsurfConfig,\n });\n\n // Codex\n const codexDir = join(homedir(), \".codex\");\n tools.push({\n name: \"codex\",\n displayName: \"Codex CLI\",\n detected: isCommandAvailable(\"codex\") || existsSync(codexDir),\n });\n\n return tools;\n}\n\n/**\n * Configure MCP for a specific tool.\n */\nexport async function configureTool(\n tool: ToolName,\n projectDir: string = process.cwd(),\n): Promise<{ success: boolean; message: string }> {\n const bridge = resolveMcpBridge();\n const mcpUrl = `${getServerUrl()}/api/mcp`;\n\n switch (tool) {\n case \"claude\":\n return configureClaudeCode(bridge);\n case \"opencode\":\n return configureOpenCode(join(projectDir, \"opencode.json\"), bridge);\n case \"cursor\":\n return configureMcpServersJson(\"Cursor\", join(projectDir, \".cursor\", \"mcp.json\"), bridge);\n case \"windsurf\":\n return configureMcpServersJson(\"Windsurf\", join(projectDir, \".windsurf\", \"mcp.json\"), bridge);\n case \"codex\":\n return configureCodex(bridge);\n default:\n return { success: false, message: `Unknown tool: ${tool}` };\n }\n}\n\n/**\n * Resolves the global command to run the Orkestrate MCP bridge.\n */\nfunction resolveMcpBridge(): { command: string, args: string[] } {\n return {\n command: \"orkestrate\",\n args: [\"mcp\"]\n };\n}\n\n// ──────────────────────────────────────────────\n// Tool Specific Configs (Global Command standard)\n// ──────────────────────────────────────────────\n\nfunction configureClaudeCode(bridge: { command: string, args: string[] }): { success: boolean; message: string } {\n if (!isCommandAvailable(\"claude\")) return { success: false, message: \"Claude Code CLI not found.\" };\n\n try {\n // We use the raw command string Claude expects\n const bridgeCmd = `${bridge.command} ${bridge.args.join(\" \")}`;\n execSync(\n `claude mcp add --transport stdio --scope project Orkestrate \"${bridgeCmd}\"`,\n { stdio: \"pipe\", encoding: \"utf-8\" },\n );\n return { success: true, message: \"MCP added to Claude Code using global command.\" };\n } catch (err) {\n return { success: false, message: `Claude config failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n}\n\nfunction configureOpenCode(configPath: string, bridge: { command: string, args: string[] }): { success: boolean; message: string } {\n try {\n let config = existsSync(configPath) ? JSON.parse(readFileSync(configPath, \"utf-8\")) : {};\n if (!config.mcp || typeof config.mcp !== \"object\") config.mcp = {};\n\n config.mcp[\"Orkestrate\"] = {\n type: \"local\",\n command: [bridge.command, ...bridge.args],\n enabled: true\n };\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n return { success: true, message: `Configured OpenCode at ${configPath}` };\n } catch (err) {\n return { success: false, message: `OpenCode config failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n}\n\nfunction configureMcpServersJson(displayName: string, configPath: string, bridge: { command: string, args: string[] }): { success: boolean; message: string } {\n try {\n const dir = join(configPath, \"..\");\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n\n let config = existsSync(configPath) ? JSON.parse(readFileSync(configPath, \"utf-8\")) : {};\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") config.mcpServers = {};\n\n config.mcpServers[\"Orkestrate\"] = {\n command: bridge.command,\n args: bridge.args\n };\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n return { success: true, message: `Configured ${displayName} at ${configPath}` };\n } catch (err) {\n return { success: false, message: `${displayName} config failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n}\n\nfunction configureCodex(bridge: { command: string, args: string[] }): { success: boolean; message: string } {\n const home = homedir();\n const codexDir = join(home, \".codex\");\n const configPath = join(codexDir, \"config.toml\");\n\n try {\n if (!existsSync(codexDir)) mkdirSync(codexDir, { recursive: true });\n\n let content = existsSync(configPath) ? readFileSync(configPath, \"utf-8\") : \"[mcp_servers]\\n\";\n const proxySection = `[mcp_servers.Orkestrate]\\ncommand = \"${bridge.command}\"\\nargs = [${bridge.args.map(a => `\"${a}\"`).join(\", \")}]\\n`;\n\n const sectionRegex = /\\[mcp_servers\\.Orkestrate\\]\\s*\\n(?:(?!\\[)[^\\n]*\\n?)*/;\n if (sectionRegex.test(content)) {\n content = content.replace(sectionRegex, proxySection);\n } else {\n const mcpServersIdx = content.indexOf(\"[mcp_servers]\");\n if (mcpServersIdx !== -1) {\n const lineEnd = content.indexOf(\"\\n\", mcpServersIdx);\n const insertPos = lineEnd !== -1 ? lineEnd + 1 : content.length;\n content = content.slice(0, insertPos) + \"\\n\" + proxySection + content.slice(insertPos);\n } else {\n content = content.trimEnd() + \"\\n\\n[mcp_servers]\\n\\n\" + proxySection;\n }\n }\n\n writeFileSync(configPath, content, \"utf-8\");\n return { success: true, message: `Configured Codex.` };\n } catch (err) {\n return { success: false, message: `Codex config failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n}\n\nfunction isCommandAvailable(command: string): boolean {\n try {\n const isWindows = process.platform === \"win32\";\n const checkCmd = isWindows ? `where ${command}` : `which ${command}`;\n execSync(checkCmd, { stdio: \"pipe\" });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function getToolNames(): ToolName[] {\n return [\"claude\", \"opencode\", \"cursor\", \"windsurf\", \"codex\"];\n}\n","/**\n * orkestrate connect <tool>\n *\n * Auto-configure MCP endpoint for a specific AI coding tool.\n */\n\nimport { getCredentials } from \"../lib/config.js\";\nimport {\n configureTool,\n detectTools,\n getToolNames,\n type ToolName,\n} from \"../lib/detect.js\";\nimport { ui } from \"../lib/ui.js\";\n\nexport async function connectCommand(toolName?: string): Promise<void> {\n // Require authentication\n const creds = getCredentials();\n if (!creds?.accessToken) {\n ui.error(\"Not authenticated. Run `orkestrate login` first.\");\n process.exit(1);\n }\n\n const validTools = getToolNames();\n\n // If no tool specified, detect and list available tools\n if (!toolName) {\n ui.header(\"Detected Tools\");\n\n const detected = detectTools();\n const found = detected.filter((t) => t.detected);\n\n if (found.length === 0) {\n ui.dim(\"No supported AI coding tools detected in this environment.\");\n ui.blank();\n ui.info(\"Supported tools:\");\n for (const name of validTools) {\n ui.line(` • ${name}`);\n }\n ui.blank();\n ui.info(\"Usage: orkestrate connect <tool>\");\n return;\n }\n\n for (const tool of detected) {\n if (tool.detected) {\n ui.success(`${tool.displayName} — detected`);\n } else {\n ui.dim(`${tool.displayName} — not found`);\n }\n }\n\n ui.blank();\n ui.info(\"Run `orkestrate connect <tool>` to configure. Example:\");\n ui.line(` orkestrate connect ${found[0].name}`);\n return;\n }\n\n // Validate tool name\n const tool = toolName.toLowerCase() as ToolName;\n if (!validTools.includes(tool)) {\n ui.error(`Unknown tool: ${toolName}`);\n ui.blank();\n ui.info(\"Supported tools:\");\n for (const name of validTools) {\n ui.line(` • ${name}`);\n }\n process.exit(1);\n }\n\n // Configure\n ui.info(`Configuring MCP for ${toolName}...`);\n\n const result = await configureTool(tool);\n\n if (result.success) {\n ui.success(result.message);\n ui.blank();\n ui.info(\"Your AI tool can now connect to Orkestrate.\");\n ui.dim(\"Restart your tool if it's currently running.\");\n } else {\n ui.error(result.message);\n process.exit(1);\n }\n}\n","/**\n * Orkestrate CLI — API Client\n *\n * Authenticated HTTP client for the Orkestrate web API.\n * All requests use the stored OAuth bearer token.\n */\n\nimport { getServerUrl } from \"./config.js\";\nimport { getValidToken } from \"./auth.js\";\n\nexport class ApiError extends Error {\n constructor(\n public status: number,\n message: string,\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\nasync function authHeaders(): Promise<Record<string, string>> {\n const token = await getValidToken();\n if (!token) {\n throw new ApiError(401, \"Not authenticated. Run `orkestrate login` first.\");\n }\n return {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n };\n}\n\nasync function request<T>(\n method: string,\n path: string,\n body?: unknown,\n): Promise<T> {\n const serverUrl = getServerUrl();\n const headers = await authHeaders();\n\n // Debug (masked token)\n const token = headers[\"Authorization\"]?.split(\" \")[1] || \"\";\n const maskedToken = token.length > 10 ? `${token.slice(0, 5)}...${token.slice(-5)}` : \"***\";\n \n if (process.env.DEBUG) {\n console.error(`[DEBUG] API Request: ${method} ${serverUrl}${path}`);\n console.error(`[DEBUG] Token: ${maskedToken}`);\n }\n\n const res = await fetch(`${serverUrl}${path}`, {\n method,\n headers: {\n ...headers,\n \"Accept\": \"application/json\",\n \"User-Agent\": \"Orkestrate-CLI-v1\",\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!res.ok) {\n const text = await res.text();\n // If it's a 401, maybe we should clear credentials? \n // Not yet, let's just log it first.\n throw new ApiError(res.status, `API error (${res.status}): ${text}`);\n }\n\n return (await res.json()) as T;\n}\n\n// --- Workspace API ---\n\nexport interface Workspace {\n id: string;\n name: string;\n ownerId: string;\n repoUrl: string | null;\n defaultBranch: string | null;\n isActive: boolean;\n createdAt: string;\n}\n\nexport async function listWorkspaces(): Promise<Workspace[]> {\n const data = await request<{ workspaces: Workspace[] }>(\"GET\", \"/api/workspaces\");\n return data.workspaces || [];\n}\n\nexport async function switchWorkspace(workspaceId: string): Promise<void> {\n await request(\"POST\", \"/api/workspaces\", {\n action: \"switch\",\n workspaceId,\n });\n}\n\nexport async function createWorkspace(\n name: string,\n repoUrl: string,\n defaultBranch: string,\n): Promise<Workspace> {\n const data = await request<{ workspace: Workspace }>(\"POST\", \"/api/workspaces\", {\n action: \"create\",\n name,\n repoUrl,\n defaultBranch,\n });\n return data.workspace;\n}\n\n// --- Agent Status API ---\n\nexport interface AgentState {\n scopedAgentId: string;\n agentId: string;\n toolName: string | null;\n status: string;\n objective: string;\n claimedPaths: string[];\n plan: string[];\n notes: string;\n updatedAt: string;\n}\n\nexport async function getTeamStatus(): Promise<{\n agents: AgentState[];\n stateHash: string;\n}> {\n // Use the MCP endpoint with a read_team_state RPC call\n const serverUrl = getServerUrl();\n const token = await getValidToken();\n if (!token) {\n throw new ApiError(401, \"Not authenticated. Run `orkestrate login` first.\");\n }\n\n const res = await fetch(`${serverUrl}/api/mcp`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"tools/call\",\n params: {\n name: \"read_team_state\",\n arguments: {},\n },\n }),\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new ApiError(res.status, `MCP error (${res.status}): ${text}`);\n }\n\n const rpcResult = (await res.json()) as any;\n\n // Parse the MCP response to extract team state\n if (rpcResult.error) {\n throw new ApiError(400, rpcResult.error.message || \"MCP call failed\");\n }\n\n const content = rpcResult.result?.content || [];\n const textContent = content\n .filter((c: { type: string }) => c.type === \"text\")\n .map((c: { text: string }) => c.text)\n .join(\"\\n\");\n\n try {\n const parsed = JSON.parse(textContent);\n return {\n agents: parsed.agents || parsed.states || [],\n stateHash: parsed.stateHash || \"\",\n };\n } catch {\n return { agents: [], stateHash: \"\" };\n }\n}\n\n// --- Health Check ---\n\nexport async function checkHealth(): Promise<boolean> {\n const serverUrl = getServerUrl();\n try {\n const res = await fetch(`${serverUrl}/api/health`, { method: \"GET\" });\n return res.ok;\n } catch {\n return false;\n }\n}\n","/**\n * orkestrate status\n *\n * Display current team coordination state in the terminal.\n */\n\nimport { getCredentials, getActiveWorkspace } from \"../lib/config.js\";\nimport { getTeamStatus, listWorkspaces, checkHealth } from \"../lib/api.js\";\nimport { ui } from \"../lib/ui.js\";\n\nexport async function statusCommand(): Promise<void> {\n const creds = getCredentials();\n if (!creds?.accessToken) {\n ui.error(\"Not authenticated. Run `orkestrate login` first.\");\n process.exit(1);\n }\n\n // Check server health\n const healthy = await checkHealth();\n if (!healthy) {\n ui.error(\"Cannot reach Orkestrate server. Check your connection.\");\n process.exit(1);\n }\n\n const workspace = getActiveWorkspace();\n\n ui.header(\"Orkestrate Status\");\n\n // Show workspace info\n if (workspace.name) {\n ui.kv(\"Workspace\", workspace.name);\n }\n if (workspace.id) {\n ui.kv(\"ID\", workspace.id);\n }\n ui.blank();\n\n try {\n const { agents, stateHash } = await getTeamStatus();\n\n if (agents.length === 0) {\n ui.dim(\"No active agents in this workspace.\");\n ui.blank();\n ui.info(\"Connect an agent with `orkestrate connect <tool>` to get started.\");\n return;\n }\n\n // Build table\n const rows = agents.map((agent) => [\n agent.agentId || agent.scopedAgentId,\n agent.toolName || \"—\",\n agent.status,\n truncate(agent.objective, 35),\n ]);\n\n ui.table(\n [\"Agent\", \"Tool\", \"Status\", \"Objective\"],\n rows,\n );\n\n // Show claimed paths summary\n const agentsWithClaims = agents.filter(\n (a) => a.claimedPaths && a.claimedPaths.length > 0,\n );\n if (agentsWithClaims.length > 0) {\n ui.blank();\n ui.line(pc_bold(\"Active Scope Claims:\"));\n for (const agent of agentsWithClaims) {\n ui.line(` ${agent.agentId}: ${agent.claimedPaths.join(\", \")}`);\n }\n }\n\n ui.blank();\n ui.dim(`State hash: ${stateHash}`);\n ui.dim(`${agents.length} agent(s) connected`);\n } catch (err) {\n ui.error(\n `Failed to fetch status: ${err instanceof Error ? err.message : String(err)}`,\n );\n process.exit(1);\n }\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s;\n return s.slice(0, max - 1) + \"…\";\n}\n\n// Inline bold since we don't want to import picocolors at top level just for one use\nfunction pc_bold(s: string): string {\n return `\\x1b[1m${s}\\x1b[22m`;\n}\n","/**\n * orkestrate workspace [list|switch|create]\n *\n * Manage workspaces from the CLI.\n */\n\nimport { getCredentials, setActiveWorkspace, getActiveWorkspace } from \"../lib/config.js\";\nimport {\n listWorkspaces,\n switchWorkspace as apiSwitchWorkspace,\n createWorkspace as apiCreateWorkspace,\n} from \"../lib/api.js\";\nimport { ui } from \"../lib/ui.js\";\n\nexport async function workspaceCommand(\n action?: string,\n nameOrId?: string,\n extra?: string,\n): Promise<void> {\n const creds = getCredentials();\n if (!creds?.accessToken) {\n ui.error(\"Not authenticated. Run `orkestrate login` first.\");\n process.exit(1);\n }\n\n const subcommand = (action || \"list\").toLowerCase();\n\n switch (subcommand) {\n case \"list\":\n case \"ls\":\n return workspaceList();\n\n case \"switch\":\n case \"use\":\n if (!nameOrId) {\n ui.error(\"Usage: orkestrate workspace switch <workspace-id-or-name>\");\n process.exit(1);\n }\n return workspaceSwitch(nameOrId);\n\n case \"create\":\n case \"new\":\n if (!nameOrId) {\n ui.error(\"Usage: orkestrate workspace create <name> <repo-url> [branch]\");\n process.exit(1);\n }\n return workspaceCreate(nameOrId, extra);\n\n default:\n ui.error(`Unknown subcommand: ${action}`);\n ui.blank();\n ui.info(\"Available subcommands:\");\n ui.line(\" list — Show all workspaces\");\n ui.line(\" switch — Switch active workspace\");\n ui.line(\" create — Create a new workspace\");\n process.exit(1);\n }\n}\n\nasync function workspaceList(): Promise<void> {\n ui.header(\"Workspaces\");\n\n try {\n const workspaces = await listWorkspaces();\n const active = getActiveWorkspace();\n\n if (workspaces.length === 0) {\n ui.dim(\"No workspaces found.\");\n ui.info(\"Create one at orkestrate.space or run `orkestrate workspace create`.\");\n return;\n }\n\n for (const ws of workspaces) {\n const isActive = ws.id === active.id || ws.isActive;\n const marker = isActive ? \" ← active\" : \"\";\n const name = ws.name || \"Unnamed\";\n\n if (isActive) {\n ui.success(`${name} (${ws.id})${marker}`);\n } else {\n ui.line(` ${name} (${ws.id})`);\n }\n\n if (ws.repoUrl) {\n ui.dim(` repo: ${ws.repoUrl}`);\n }\n }\n\n ui.blank();\n ui.dim(`${workspaces.length} workspace(s)`);\n } catch (err) {\n ui.error(`Failed to list workspaces: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n\nasync function workspaceSwitch(nameOrId: string): Promise<void> {\n try {\n const workspaces = await listWorkspaces();\n\n // Find by exact ID or name match\n const target = workspaces.find(\n (ws) =>\n ws.id === nameOrId ||\n ws.name.toLowerCase() === nameOrId.toLowerCase(),\n );\n\n if (!target) {\n ui.error(`Workspace not found: ${nameOrId}`);\n ui.blank();\n ui.info(\"Available workspaces:\");\n for (const ws of workspaces) {\n ui.line(` ${ws.name} (${ws.id})`);\n }\n process.exit(1);\n }\n\n await apiSwitchWorkspace(target.id);\n setActiveWorkspace(target.id, target.name);\n ui.success(`Switched to workspace: ${target.name}`);\n } catch (err) {\n ui.error(`Failed to switch workspace: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n\nasync function workspaceCreate(name: string, repoUrl?: string): Promise<void> {\n if (!repoUrl) {\n ui.error(\"Repository URL is required.\");\n ui.info(\"Usage: orkestrate workspace create <name> <repo-url>\");\n process.exit(1);\n }\n\n try {\n const workspace = await apiCreateWorkspace(name, repoUrl, \"main\");\n setActiveWorkspace(workspace.id, workspace.name || name);\n ui.success(`Created workspace: ${workspace.name || name}`);\n ui.kv(\"ID\", workspace.id);\n ui.kv(\"Repo\", repoUrl);\n } catch (err) {\n ui.error(`Failed to create workspace: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n","/**\n * Orkestrate CLI — Git Context Detection\n *\n * Reads git metadata from the current working directory.\n */\n\nimport { execSync } from \"node:child_process\";\n\nexport interface GitContext {\n remote: string;\n repoRoot: string;\n branch: string;\n headSha: string;\n dirty: boolean;\n collectedAt: string;\n}\n\nfunction git(cmd: string, cwd: string): string {\n try {\n return execSync(`git ${cmd}`, {\n cwd,\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim();\n } catch {\n return \"\";\n }\n}\n\nexport function detectGitContext(cwd: string = process.cwd()): GitContext | null {\n const repoRoot = git(\"rev-parse --show-toplevel\", cwd);\n if (!repoRoot) return null;\n\n const remote = git(\"remote get-url origin\", cwd);\n const branch = git(\"rev-parse --abbrev-ref HEAD\", cwd);\n const headSha = git(\"rev-parse HEAD\", cwd);\n const status = git(\"status --porcelain\", cwd);\n\n return {\n remote: remote || \"\",\n repoRoot,\n branch: branch || \"unknown\",\n headSha: headSha || \"\",\n dirty: status.length > 0,\n collectedAt: new Date().toISOString(),\n };\n}\n","/**\n * orkestrate init\n *\n * Initialize Orkestrate in the current project directory.\n * Detects git context and binds to the matching workspace.\n */\n\nimport { existsSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getCredentials, getActiveWorkspace, setActiveWorkspace } from \"../lib/config.js\";\nimport { detectGitContext } from \"../lib/git.js\";\nimport { listWorkspaces } from \"../lib/api.js\";\nimport { detectTools } from \"../lib/detect.js\";\nimport { ui } from \"../lib/ui.js\";\n\nexport async function initCommand(): Promise<void> {\n const creds = getCredentials();\n if (!creds?.accessToken) {\n ui.error(\"Not authenticated. Run `orkestrate login` first.\");\n process.exit(1);\n }\n\n const cwd = process.cwd();\n\n ui.header(\"Initializing Orkestrate\");\n\n // Step 1: Detect git context\n const git = detectGitContext(cwd);\n if (git) {\n ui.success(`Git repository detected`);\n ui.kv(\"Remote\", git.remote || \"(no remote)\");\n ui.kv(\"Branch\", git.branch);\n ui.kv(\"HEAD\", git.headSha.slice(0, 8));\n ui.kv(\"Dirty\", git.dirty ? \"yes\" : \"clean\");\n } else {\n ui.warn(\"No git repository detected in current directory.\");\n ui.dim(\"Orkestrate works best with a git repository.\");\n }\n\n ui.blank();\n\n // Step 2: Match to workspace\n try {\n const workspaces = await listWorkspaces();\n let matched = false;\n\n if (git?.remote && workspaces.length > 0) {\n // Try to match by repo URL\n const normalizedRemote = normalizeGitUrl(git.remote);\n const match = workspaces.find((ws) => {\n if (!ws.repoUrl) return false;\n return normalizeGitUrl(ws.repoUrl) === normalizedRemote;\n });\n\n if (match) {\n setActiveWorkspace(match.id, match.name);\n ui.success(`Matched to workspace: ${match.name}`);\n ui.kv(\"Workspace ID\", match.id);\n matched = true;\n }\n }\n\n if (!matched) {\n if (git?.remote) {\n const create = await ui.confirm(`No matching workspace found for this repository. Create one?`);\n if (create) {\n const name = await ui.input(\"Workspace name\", git.remote.split(\"/\").pop()?.replace(/\\.git$/, \"\"));\n try {\n const { createWorkspace } = await import(\"../lib/api.js\");\n const workspace = await createWorkspace(name, git.remote, git.branch || \"main\");\n setActiveWorkspace(workspace.id, workspace.name);\n ui.success(`Created and matched to workspace: ${workspace.name}`);\n ui.kv(\"Workspace ID\", workspace.id);\n matched = true;\n } catch (err) {\n ui.error(`Failed to create workspace: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n }\n\n if (!matched) {\n const active = getActiveWorkspace();\n if (active.id) {\n ui.info(`Using current active workspace: ${active.name || active.id}`);\n } else if (workspaces.length > 0) {\n ui.info(\"Available workspaces:\");\n for (const ws of workspaces.slice(0, 5)) {\n ui.line(` • ${ws.name} (${ws.id})`);\n }\n const wsId = await ui.input(\"Enter workspace ID to link (or leave blank)\");\n if (wsId) {\n const selected = workspaces.find(w => w.id === wsId || w.name === wsId);\n if (selected) {\n setActiveWorkspace(selected.id, selected.name);\n ui.success(`Linked to workspace: ${selected.name}`);\n matched = true;\n }\n }\n }\n }\n }\n } catch (err) {\n ui.dim(`Could not fetch workspaces: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n ui.blank();\n\n // Step 3: Detect available tools\n const tools = detectTools(cwd);\n const found = tools.filter((t) => t.detected);\n\n if (found.length > 0) {\n ui.info(\"Detected AI tools:\");\n for (const tool of found) {\n ui.line(` • ${tool.displayName}`);\n }\n ui.blank();\n const connect = await ui.confirm(`Would you like to connect ${found[0].displayName} now?`);\n if (connect) {\n const { configureTool } = await import(\"../lib/detect.js\");\n const res = await configureTool(found[0].name, cwd);\n if (res.success) {\n ui.success(res.message);\n } else {\n ui.error(res.message);\n }\n } else {\n ui.info(`You can connect later with \\`orkestrate connect ${found[0].name}\\``);\n }\n } else {\n ui.dim(\"No AI coding tools detected. Install one and run `orkestrate connect <tool>`.\");\n }\n\n // Step 4: Write .orkestrate.json (project marker)\n const configFile = join(cwd, \".orkestrate.json\");\n const activeWs = getActiveWorkspace();\n \n if (!existsSync(configFile)) {\n if (activeWs.id) {\n const projectConfig = {\n $schema: \"https://orkestrate.space/schema/project.json\",\n workspaceId: activeWs.id,\n server: \"https://orkestrate.space\",\n initialized: new Date().toISOString(),\n };\n\n writeFileSync(configFile, JSON.stringify(projectConfig, null, 2) + \"\\n\", \"utf-8\");\n ui.blank();\n ui.success(`Created .orkestrate.json`);\n ui.dim(\"Add this file to your repository so collaborators can auto-detect the workspace.\");\n }\n } else {\n // Sync existing config if it has a different WS ID\n try {\n const { readFileSync } = await import(\"node:fs\");\n const existing = JSON.parse(readFileSync(configFile, \"utf-8\"));\n if (activeWs.id && existing.workspaceId !== activeWs.id) {\n existing.workspaceId = activeWs.id;\n writeFileSync(configFile, JSON.stringify(existing, null, 2) + \"\\n\", \"utf-8\");\n ui.success(`Updated .orkestrate.json with workspace ID ${activeWs.id}`);\n }\n } catch {}\n }\n\n ui.blank();\n}\n\n/**\n * Normalize a git remote URL for comparison.\n */\nfunction normalizeGitUrl(url: string): string {\n let normalized = url.trim().toLowerCase();\n normalized = normalized.replace(/\\.git$/, \"\");\n \n const sshMatch = normalized.match(/^git@([^:]+):(.+)$/);\n if (sshMatch) {\n normalized = `${sshMatch[1]}/${sshMatch[2]}`;\n }\n \n normalized = normalized.replace(/^https?:\\/\\//, \"\");\n normalized = normalized.replace(/^ssh:\\/\\//, \"\");\n normalized = normalized.replace(/\\/$/, \"\");\n return normalized;\n}\n","\nimport { getServerUrl } from \"../lib/config.js\";\nimport { getValidToken } from \"../lib/auth.js\";\n\n/**\n * Orkestrate MCP Proxy\n * \n * Acts as a local MCP server (stdio) that forwards all requests to the \n * Orkestrate cloud MCP endpoint (HTTP), injecting the local auth token.\n */\nexport async function mcpCommand() {\n try {\n const serverUrl = getServerUrl();\n const mcpUrl = `${serverUrl}/api/mcp`;\n\n process.stdin.setEncoding(\"utf-8\");\n let buffer = \"\";\n \n process.stdin.on(\"data\", async (chunk) => {\n const rawChunk = String(chunk);\n buffer += rawChunk;\n \n let lineEndIndex;\n while ((lineEndIndex = buffer.indexOf(\"\\n\")) >= 0) {\n let line = buffer.slice(0, lineEndIndex).trim();\n buffer = buffer.slice(lineEndIndex + 1);\n \n if (!line) continue;\n \n // Handle back-to-back JSON objects missing newlines\n if (line.includes(\"}{\")) {\n const parts = line.split(\"}{\");\n processLine(parts[0] + \"}\", mcpUrl);\n for (let i = 1; i < parts.length - 1; i++) {\n processLine(\"{\" + parts[i] + \"}\", mcpUrl);\n }\n processLine(\"{\" + parts[parts.length - 1], mcpUrl);\n } else {\n processLine(line, mcpUrl);\n }\n }\n });\n\n process.stdin.on(\"end\", () => {\n process.exit(0);\n });\n\n // Stay alive\n await new Promise(() => {});\n } catch (err) {\n process.stderr.write(`[Orkestrate] Fatal error: ${err}\\n`);\n process.exit(1);\n }\n}\n\nasync function processLine(line: string, mcpUrl: string) {\n let payload: any;\n try {\n payload = JSON.parse(line);\n } catch { return; }\n\n const isNotification = !Object.prototype.hasOwnProperty.call(payload, \"id\");\n const requestId = payload.id;\n\n try {\n const token = await getValidToken();\n \n if (!token) {\n throw new Error(\"NOT_LOGGED_IN: Please run 'orkestrate login' to authenticate.\");\n }\n\n const res = await fetch(mcpUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${token}`,\n \"User-Agent\": \"Orkestrate-CLI-Proxy\"\n },\n body: line\n });\n\n // Notifications MUST NOT be responded to on stdout\n if (isNotification) return;\n\n const responseBody = await res.text();\n if (responseBody) {\n process.stdout.write(responseBody + \"\\n\");\n }\n } catch (err) {\n if (isNotification) return;\n\n process.stdout.write(JSON.stringify({\n jsonrpc: \"2.0\",\n id: requestId,\n error: {\n code: -32603,\n message: err instanceof Error ? err.message : String(err)\n }\n }) + \"\\n\");\n }\n}\n","/**\n * orkestrate whoami\n *\n * Show current authentication and configuration state.\n */\n\nimport { getCredentials, getActiveWorkspace, getServerUrl, getConfigPath } from \"../lib/config.js\";\nimport { checkHealth } from \"../lib/api.js\";\nimport { ui } from \"../lib/ui.js\";\n\nexport async function whoamiCommand(): Promise<void> {\n ui.header(\"Orkestrate Configuration\");\n\n const creds = getCredentials();\n const workspace = getActiveWorkspace();\n const serverUrl = getServerUrl();\n\n ui.kv(\"Server\", serverUrl);\n ui.kv(\"Config\", getConfigPath());\n ui.blank();\n\n if (creds?.accessToken) {\n ui.success(\"Authenticated\");\n ui.kv(\"Client ID\", creds.clientId);\n if (creds.userId) {\n ui.kv(\"User ID\", creds.userId);\n }\n\n const expiresIn = creds.expiresAt - Math.floor(Date.now() / 1000);\n if (expiresIn > 0) {\n const minutes = Math.floor(expiresIn / 60);\n ui.kv(\"Token expires\", `in ${minutes} minute(s)`);\n } else {\n ui.warn(\"Access token expired — will auto-refresh on next API call.\");\n }\n } else {\n ui.error(\"Not authenticated. Run `orkestrate login`.\");\n }\n\n ui.blank();\n\n if (workspace.id) {\n ui.kv(\"Active workspace\", workspace.name || \"—\");\n ui.kv(\"Workspace ID\", workspace.id);\n } else {\n ui.dim(\"No active workspace set.\");\n }\n\n ui.blank();\n\n // Server health check\n ui.info(\"Checking server health...\");\n const healthy = await checkHealth();\n if (healthy) {\n ui.success(\"Server is reachable\");\n } else {\n ui.error(\"Server is unreachable\");\n }\n}\n","/**\n * Orkestrate CLI\n *\n * The coordination layer for autonomous AI coding agents.\n * https://orkestrate.space\n */\n\nimport { Command } from \"commander\";\nimport { ui } from \"./lib/ui.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"orkestrate\")\n .description(\"The coordination layer for autonomous AI coding agents\")\n .version(\"0.1.0\")\n .hook(\"preAction\", () => {\n // Show banner on all commands\n });\n\n// --- login ---\nprogram\n .command(\"login\")\n .description(\"Authenticate with Orkestrate via browser OAuth\")\n .action(async () => {\n const { loginCommand } = await import(\"./commands/login.js\");\n await loginCommand();\n });\n\n// --- logout ---\nprogram\n .command(\"logout\")\n .description(\"Clear stored credentials\")\n .action(async () => {\n const { logoutCommand } = await import(\"./commands/logout.js\");\n logoutCommand();\n });\n\n// --- connect ---\nprogram\n .command(\"connect [tool]\")\n .description(\"Configure MCP endpoint for an AI coding tool (claude, opencode, cursor, windsurf, codex)\")\n .action(async (tool?: string) => {\n const { connectCommand } = await import(\"./commands/connect.js\");\n await connectCommand(tool);\n });\n\n// --- status ---\nprogram\n .command(\"status\")\n .alias(\"s\")\n .description(\"Show current team coordination state\")\n .action(async () => {\n const { statusCommand } = await import(\"./commands/status.js\");\n await statusCommand();\n });\n\n// --- workspace ---\nprogram\n .command(\"workspace [action] [name] [extra]\")\n .alias(\"ws\")\n .description(\"Manage workspaces (list, switch, create)\")\n .action(async (action?: string, name?: string, extra?: string) => {\n const { workspaceCommand } = await import(\"./commands/workspace.js\");\n await workspaceCommand(action, name, extra);\n });\n\n// --- init ---\nprogram\n .command(\"init\")\n .description(\"Initialize Orkestrate in the current project\")\n .action(async () => {\n const { initCommand } = await import(\"./commands/init.js\");\n await initCommand();\n });\n\n// --- mcp ---\nprogram\n .command(\"mcp\")\n .description(\"Run as a local MCP server (stdio bridge to Orkestrate Cloud)\")\n .action(async () => {\n try {\n const { mcpCommand } = await import(\"./commands/mcp.js\");\n await mcpCommand();\n } catch (err) {\n process.stderr.write(`[Orkestrate-MCP] ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n }\n });\n\n// --- whoami ---\nprogram\n .command(\"whoami\")\n .description(\"Show current authentication and configuration\")\n .action(async () => {\n const { whoamiCommand } = await import(\"./commands/whoami.js\");\n await whoamiCommand();\n });\n\n// --- Default: show banner + help ---\nprogram.action(() => {\n ui.banner();\n program.help();\n});\n\n// Run\nprogram.parseAsync(process.argv).catch((err) => {\n ui.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n});\n"],"mappings":";;;;;;;;;;;;AAMA,OAAO,QAAQ;AANf,IAQa;AARb;AAAA;AAAA;AAQO,IAAM,KAAK;AAAA;AAAA,MAEhB,SAAS,CAAC,QAAgB,QAAQ,IAAI,KAAK,GAAG,MAAM,QAAG,CAAC,IAAI,GAAG,EAAE;AAAA,MACjE,OAAO,CAAC,QAAgB,QAAQ,IAAI,KAAK,GAAG,IAAI,QAAG,CAAC,IAAI,GAAG,EAAE;AAAA,MAC7D,MAAM,CAAC,QAAgB,QAAQ,IAAI,KAAK,GAAG,KAAK,QAAG,CAAC,IAAI,GAAG,EAAE;AAAA,MAC7D,MAAM,CAAC,QAAgB,QAAQ,IAAI,KAAK,GAAG,OAAO,GAAG,CAAC,IAAI,GAAG,EAAE;AAAA,MAC/D,KAAK,CAAC,QAAgB,QAAQ,IAAI,KAAK,GAAG,IAAI,GAAG,CAAC,EAAE;AAAA;AAAA,MAGpD,QAAQ,CAAC,QAAgB;AACvB,gBAAQ,IAAI;AACZ,gBAAQ,IAAI,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC,EAAE;AACzC,gBAAQ,IAAI;AAAA,MACd;AAAA;AAAA,MAGA,OAAO,MAAM,QAAQ,IAAI;AAAA;AAAA,MAGzB,MAAM,CAAC,QAAgB,QAAQ,IAAI,KAAK,GAAG,EAAE;AAAA;AAAA,MAG7C,IAAI,CAAC,KAAa,UAAkB;AAClC,gBAAQ,IAAI,KAAK,GAAG,IAAI,MAAM,GAAG,CAAC,IAAI,KAAK,EAAE;AAAA,MAC/C;AAAA;AAAA,MAGA,OAAO,CAAC,SAAmB,SAAqB;AAC9C,cAAM,YAAY,QAAQ,IAAI,CAAC,GAAG,MAAM;AACtC,gBAAM,aAAa,KAAK,IAAI,EAAE,QAAQ,GAAG,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,MAAM,CAAC;AAC7E,iBAAO,KAAK,IAAI,YAAY,EAAE;AAAA,QAChC,CAAC;AAED,cAAM,YAAY;AAClB,cAAM,MAAM,CAAC,GAAW,MAAc,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC;AAG5D,gBAAQ;AAAA,UACN,WAAM,UAAU,IAAI,CAAC,MAAM,UAAU,OAAO,IAAI,CAAC,CAAC,EAAE,KAAK,QAAG,CAAC;AAAA,QAC/D;AAGA,gBAAQ;AAAA,UACN,WAAM,QAAQ,IAAI,CAAC,GAAG,MAAM,IAAI,GAAG,KAAK,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,QAAG,CAAC;AAAA,QAC7E;AAGA,gBAAQ;AAAA,UACN,WAAM,UAAU,IAAI,CAAC,MAAM,UAAU,OAAO,IAAI,CAAC,CAAC,EAAE,KAAK,QAAG,CAAC;AAAA,QAC/D;AAGA,mBAAW,OAAO,MAAM;AACtB,kBAAQ;AAAA,YACN,WAAM,IAAI,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,KAAK,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,QAAG,CAAC;AAAA,UACtE;AAAA,QACF;AAGA,gBAAQ;AAAA,UACN,WAAM,UAAU,IAAI,CAAC,MAAM,UAAU,OAAO,IAAI,CAAC,CAAC,EAAE,KAAK,QAAG,CAAC;AAAA,QAC/D;AAAA,MACF;AAAA;AAAA,MAGA,aAAa,CAAC,WAA2B;AACvC,gBAAQ,QAAQ;AAAA,UACd,KAAK;AACH,mBAAO,GAAG,MAAM,eAAU;AAAA,UAC5B,KAAK;AACH,mBAAO,GAAG,IAAI,aAAQ;AAAA,UACxB,KAAK;AACH,mBAAO,GAAG,IAAI,gBAAW;AAAA,UAC3B,KAAK;AACH,mBAAO,GAAG,KAAK,iBAAY;AAAA,UAC7B,KAAK;AACH,mBAAO,GAAG,OAAO,gBAAW;AAAA,UAC9B,KAAK;AACH,mBAAO,GAAG,IAAI,aAAQ;AAAA,UACxB;AACE,mBAAO,GAAG,IAAI,MAAM;AAAA,QACxB;AAAA,MACF;AAAA;AAAA,MAGA,SAAS,OAAO,UAAkB,aAAa,SAA2B;AACxE,cAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,mBAAwB;AACjE,cAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAC3E,cAAM,SAAS,aAAa,UAAU;AACtC,cAAM,SAAS,MAAM,GAAG,SAAS,KAAK,GAAG,KAAK,GAAG,MAAM,QAAQ,CAAC,CAAC,IAAI,GAAG,IAAI,MAAM,CAAC,GAAG;AACtF,WAAG,MAAM;AACT,YAAI,CAAC,OAAQ,QAAO;AACpB,eAAO,OAAO,YAAY,EAAE,WAAW,GAAG;AAAA,MAC5C;AAAA,MAEA,OAAO,OAAO,UAAkB,iBAA2C;AACzE,cAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,mBAAwB;AACjE,cAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAC3E,cAAM,SAAS,eAAe,GAAG,IAAI,KAAK,YAAY,GAAG,IAAI;AAC7D,cAAM,SAAS,MAAM,GAAG,SAAS,KAAK,GAAG,KAAK,GAAG,MAAM,QAAQ,CAAC,CAAC,GAAG,MAAM,GAAG;AAC7E,WAAG,MAAM;AACT,eAAO,UAAU,gBAAgB;AAAA,MACnC;AAAA;AAAA,MAGA,QAAQ,MAAM;AACZ,gBAAQ,IAAI;AACZ,gBAAQ,IAAI,GAAG,KAAK,GAAG,KAAK,qBAAgB,CAAC,CAAC;AAC9C,gBAAQ,IAAI,GAAG,IAAI,+CAA+C,CAAC;AACnE,gBAAQ,IAAI;AAAA,MACd;AAAA,IACF;AAAA;AAAA;;;AChHA,OAAO,UAAU;AAsCV,SAAS,eAAuB;AACrC,SAAO,OAAO,IAAI,WAAW;AAC/B;AAEO,SAAS,eAAe,OAAgC;AAC7D,SAAO,IAAI,eAAe,KAAK;AACjC;AAEO,SAAS,iBAA2C;AACzD,SAAO,OAAO,IAAI,aAAa;AACjC;AAEO,SAAS,mBAAyB;AACvC,SAAO,IAAI,eAAe,IAAI;AAChC;AAEO,SAAS,mBAAmB,IAAY,MAAoB;AACjE,SAAO,IAAI,qBAAqB,EAAE;AAClC,SAAO,IAAI,uBAAuB,IAAI;AACxC;AAEO,SAAS,qBAAiE;AAC/E,SAAO;AAAA,IACL,IAAI,OAAO,IAAI,mBAAmB;AAAA,IAClC,MAAM,OAAO,IAAI,qBAAqB;AAAA,EACxC;AACF;AAUO,SAAS,gBAAwB;AACtC,SAAO,OAAO;AAChB;AAnFA,IAyBM;AAzBN;AAAA;AAAA;AAyBA,IAAM,SAAS,IAAI,KAAgB;AAAA,MACjC,aAAa;AAAA,MACb,eAAe;AAAA,MACf,UAAU;AAAA,QACR,aAAa;AAAA,QACb,mBAAmB;AAAA,QACnB,qBAAqB;AAAA,QACrB,WAAW;AAAA,MACb;AAAA,IACF,CAAC;AAAA;AAAA;;;ACvBD,SAAS,YAAY,mBAAmB;AACxC,SAAS,oBAA+D;AAQxE,SAAS,YAAY,QAAQ,IAAY;AACvC,SAAO,YAAY,KAAK,EAAE,SAAS,WAAW;AAChD;AAEA,SAAS,SAAS,UAA0B;AAC1C,SAAO,WAAW,QAAQ,EAAE,OAAO,QAAQ,EAAE,OAAO,WAAW;AACjE;AAaA,eAAe,eACb,WACA,aAC+B;AAC/B,QAAM,MAAM,MAAM,MAAM,GAAG,SAAS,uBAAuB;AAAA,IACzD,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU;AAAA,MACnB,aAAa;AAAA,MACb,eAAe,CAAC,WAAW;AAAA,MAC3B,aAAa,CAAC,sBAAsB,eAAe;AAAA,MACnD,gBAAgB,CAAC,MAAM;AAAA,MACvB,4BAA4B;AAAA,IAC9B,CAAC;AAAA,EACH,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAM,IAAI,MAAM,+BAA+B,IAAI,MAAM,MAAM,IAAI,EAAE;AAAA,EACvE;AAEA,QAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,SAAO,EAAE,UAAU,KAAK,UAAU;AACpC;AAKA,SAAS,gBACP,MAC0C;AAC1C,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI;AAEJ,aAAS,UAAU;AACjB,mBAAa,aAAa;AAC1B,aAAO,MAAM;AAAA,IACf;AAEA,UAAM,SAAS,aAAa,CAAC,KAAsB,QAAwB;AACzE,YAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,oBAAoB,IAAI,EAAE;AAE9D,UAAI,IAAI,aAAa,aAAa;AAChC,YAAI,UAAU,GAAG;AACjB,YAAI,IAAI,WAAW;AACnB;AAAA,MACF;AAEA,YAAM,OAAO,IAAI,aAAa,IAAI,MAAM;AACxC,YAAM,QAAQ,IAAI,aAAa,IAAI,OAAO;AAC1C,YAAM,QAAQ,IAAI,aAAa,IAAI,OAAO,KAAK;AAE/C,UAAI,OAAO;AACT,cAAM,cAAc,IAAI,aAAa,IAAI,mBAAmB,KAAK;AACjE,YAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,YAAI,IAAI,eAAe,WAAW,CAAC;AACnC,gBAAQ;AACR,eAAO,IAAI,MAAM,gBAAgB,WAAW,EAAE,CAAC;AAC/C;AAAA,MACF;AAEA,UAAI,CAAC,MAAM;AACT,YAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,YAAI,IAAI,eAAe,iCAAiC,CAAC;AACzD,gBAAQ;AACR,eAAO,IAAI,MAAM,gCAAgC,CAAC;AAClD;AAAA,MACF;AAEA,UAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,UAAI,IAAI,iBAAiB,CAAC;AAC1B,cAAQ;AACR,cAAQ,EAAE,MAAM,MAAM,CAAC;AAAA,IACzB,CAAC;AAED,WAAO,OAAO,MAAM,aAAa,MAAM;AAAA,IAEvC,CAAC;AAED,WAAO,GAAG,SAAS,CAAC,QAAe;AACjC,mBAAa,aAAa;AAC1B,aAAO,IAAI,MAAM,iCAAiC,IAAI,OAAO,EAAE,CAAC;AAAA,IAClE,CAAC;AAGD,oBAAgB,WAAW,MAAM;AAC/B,aAAO,MAAM;AACb,aAAO,IAAI,MAAM,yDAAyD,CAAC;AAAA,IAC7E,GAAG,IAAI,KAAK,GAAI;AAChB,kBAAc,MAAM;AAAA,EACtB,CAAC;AACH;AAKA,eAAe,sBACb,WACA,MACA,UACA,cACA,aACwB;AACxB,QAAM,OAAO,IAAI,gBAAgB;AAAA,IAC/B,YAAY;AAAA,IACZ;AAAA,IACA,eAAe;AAAA,IACf,WAAW;AAAA,IACX,cAAc;AAAA,EAChB,CAAC;AAED,QAAM,MAAM,MAAM,MAAM,GAAG,SAAS,oBAAoB;AAAA,IACtD,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,IAC/D,MAAM,KAAK,SAAS;AAAA,EACtB,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAM,IAAI,MAAM,0BAA0B,IAAI,MAAM,MAAM,IAAI,EAAE;AAAA,EAClE;AAEA,SAAQ,MAAM,IAAI,KAAK;AACzB;AAKA,eAAsB,qBAAwD;AAC5E,QAAM,QAAQ,eAAe;AAC7B,MAAI,CAAC,OAAO,aAAc,QAAO;AAEjC,QAAM,YAAY,aAAa;AAC/B,QAAM,OAAO,IAAI,gBAAgB;AAAA,IAC/B,YAAY;AAAA,IACZ,eAAe,MAAM;AAAA,IACrB,WAAW,MAAM;AAAA,EACnB,CAAC;AAED,QAAM,MAAM,MAAM,MAAM,GAAG,SAAS,oBAAoB;AAAA,IACtD,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,IAC/D,MAAM,KAAK,SAAS;AAAA,EACtB,CAAC;AAED,MAAI,CAAC,IAAI,GAAI,QAAO;AAEpB,QAAM,SAAU,MAAM,IAAI,KAAK;AAC/B,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAExC,QAAM,WAA8B;AAAA,IAClC,UAAU,MAAM;AAAA,IAChB,aAAa,OAAO;AAAA,IACpB,cAAc,OAAO;AAAA,IACrB,WAAW,MAAM,OAAO;AAAA,IACxB,QAAQ,MAAM;AAAA,IACd,OAAO,OAAO;AAAA,EAChB;AAEA,iBAAe,QAAQ;AACvB,SAAO;AACT;AAKA,eAAsB,gBAAwC;AAC5D,QAAM,QAAQ,eAAe;AAC7B,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAGxC,MAAI,MAAM,aAAa,MAAM,IAAI;AAC/B,UAAM,YAAY,MAAM,mBAAmB;AAC3C,WAAO,WAAW,eAAe;AAAA,EACnC;AAEA,SAAO,MAAM;AACf;AAKA,eAAsB,eAInB;AACD,QAAM,YAAY,aAAa;AAC/B,QAAM,OAAO;AACb,QAAM,cAAc,oBAAoB,IAAI;AAG5C,QAAM,EAAE,SAAS,IAAI,MAAM,eAAe,WAAW,WAAW;AAGhE,QAAM,eAAe,YAAY,EAAE;AACnC,QAAM,gBAAgB,SAAS,YAAY;AAC3C,QAAM,QAAQ,YAAY,EAAE;AAG5B,QAAM,UAAU,IAAI,IAAI,GAAG,SAAS,sBAAsB;AAC1D,UAAQ,aAAa,IAAI,iBAAiB,MAAM;AAChD,UAAQ,aAAa,IAAI,aAAa,QAAQ;AAC9C,UAAQ,aAAa,IAAI,gBAAgB,WAAW;AACpD,UAAQ,aAAa,IAAI,kBAAkB,aAAa;AACxD,UAAQ,aAAa,IAAI,yBAAyB,MAAM;AACxD,UAAQ,aAAa,IAAI,SAAS,oBAAoB;AACtD,UAAQ,aAAa,IAAI,SAAS,KAAK;AAGvC,QAAM,kBAAkB,gBAAgB,IAAI;AAG5C,QAAM,EAAE,SAAS,YAAY,IAAI,MAAM,OAAO,MAAM;AACpD,QAAM,YAAY,QAAQ,SAAS,CAAC;AAGpC,QAAM,EAAE,MAAM,OAAO,cAAc,IAAI,MAAM;AAE7C,MAAI,kBAAkB,OAAO;AAC3B,UAAM,IAAI,MAAM,6DAAwD;AAAA,EAC1E;AAGA,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAKxC,QAAM,cAAiC;AAAA,IACrC;AAAA,IACA,aAAa,OAAO;AAAA,IACpB,cAAc,OAAO;AAAA,IACrB,WAAW,MAAM,OAAO;AAAA,IACxB,QAAQ;AAAA;AAAA,IACR,OAAO,OAAO;AAAA,EAChB;AAEA,iBAAe,WAAW;AAE1B,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,YAAY;AAAA,IACpB,aAAa,OAAO;AAAA,EACtB;AACF;AAIA,SAAS,mBAA2B;AAClC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwCT;AAEA,SAAS,eAAe,SAAyB;AAC/C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAiCA,OAAO;AAAA;AAAA;AAAA;AAIhB;AA3XA;AAAA;AAAA;AAaA;AAAA;AAAA;;;ACbA;AAAA;AAAA;AAAA;AAYA,eAAsB,eAA8B;AAElD,QAAM,WAAW,eAAe;AAChC,MAAI,UAAU,aAAa;AACzB,OAAG,IAAI,gCAAgC;AAAA,EACzC;AAEA,KAAG,KAAK,uCAAuC;AAC/C,KAAG,IAAI,+DAA+D;AACtE,KAAG,MAAM;AAET,MAAI;AACF,UAAM,SAAS,MAAM,aAAa;AAClC,OAAG,MAAM;AAET,OAAG,QAAQ,6BAA6B;AACxC,OAAG,MAAM;AACT,OAAG,KAAK,aAAa;AACrB,OAAG,KAAK,mDAAmD;AAC3D,OAAG,KAAK,gCAAgC;AACxC,OAAG,KAAK,4BAA4B;AACpC,OAAG,MAAM;AACT,OAAG,IAAI,0BAA0B,cAAc,CAAC,EAAE;AAAA,EACpD,SAAS,KAAK;AACZ,OAAG,MAAM,iBAAiB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAC5E,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAvCA;AAAA;AAAA;AAMA;AACA;AAGA;AAAA;AAAA;;;ACVA;AAAA;AAAA;AAAA;AASO,SAAS,gBAAsB;AACpC,QAAM,WAAW,eAAe;AAEhC,MAAI,CAAC,UAAU,aAAa;AAC1B,OAAG,IAAI,0BAA0B;AACjC;AAAA,EACF;AAEA,mBAAiB;AACjB,KAAG,QAAQ,kCAAkC;AAC7C,KAAG,IAAI,WAAW,cAAc,CAAC,EAAE;AACrC;AApBA;AAAA;AAAA;AAMA;AACA;AAAA;AAAA;;;ACPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,gBAAgB;AAelB,SAAS,YAAY,aAAqB,QAAQ,IAAI,GAAmB;AAC9E,QAAM,QAAwB,CAAC;AAG/B,QAAM,KAAK;AAAA,IACT,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU,mBAAmB,QAAQ;AAAA,EACvC,CAAC;AAGD,QAAM,iBAAiB,KAAK,YAAY,eAAe;AACvD,QAAM,KAAK;AAAA,IACT,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU,WAAW,cAAc,KAAK,mBAAmB,UAAU;AAAA,IACrE,YAAY;AAAA,EACd,CAAC;AAGD,QAAM,eAAe,KAAK,YAAY,WAAW,UAAU;AAC3D,QAAM,KAAK;AAAA,IACT,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU,WAAW,KAAK,YAAY,SAAS,CAAC,KAAK,WAAW,YAAY;AAAA,IAC5E,YAAY;AAAA,EACd,CAAC;AAGD,QAAM,iBAAiB,KAAK,YAAY,aAAa,UAAU;AAC/D,QAAM,KAAK;AAAA,IACT,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU,WAAW,KAAK,YAAY,WAAW,CAAC,KAAK,WAAW,cAAc;AAAA,IAChF,YAAY;AAAA,EACd,CAAC;AAGD,QAAM,WAAW,KAAK,QAAQ,GAAG,QAAQ;AACzC,QAAM,KAAK;AAAA,IACT,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU,mBAAmB,OAAO,KAAK,WAAW,QAAQ;AAAA,EAC9D,CAAC;AAED,SAAO;AACT;AAKA,eAAsB,cACpB,MACA,aAAqB,QAAQ,IAAI,GACe;AAChD,QAAM,SAAS,iBAAiB;AAChC,QAAM,SAAS,GAAG,aAAa,CAAC;AAEhC,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,oBAAoB,MAAM;AAAA,IACnC,KAAK;AACH,aAAO,kBAAkB,KAAK,YAAY,eAAe,GAAG,MAAM;AAAA,IACpE,KAAK;AACH,aAAO,wBAAwB,UAAU,KAAK,YAAY,WAAW,UAAU,GAAG,MAAM;AAAA,IAC1F,KAAK;AACH,aAAO,wBAAwB,YAAY,KAAK,YAAY,aAAa,UAAU,GAAG,MAAM;AAAA,IAC9F,KAAK;AACH,aAAO,eAAe,MAAM;AAAA,IAC9B;AACE,aAAO,EAAE,SAAS,OAAO,SAAS,iBAAiB,IAAI,GAAG;AAAA,EAC9D;AACF;AAKA,SAAS,mBAAwD;AAC/D,SAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM,CAAC,KAAK;AAAA,EACd;AACF;AAMA,SAAS,oBAAoB,QAAoF;AAC/G,MAAI,CAAC,mBAAmB,QAAQ,EAAG,QAAO,EAAE,SAAS,OAAO,SAAS,6BAA6B;AAElG,MAAI;AAEF,UAAM,YAAY,GAAG,OAAO,OAAO,IAAI,OAAO,KAAK,KAAK,GAAG,CAAC;AAC5D;AAAA,MACE,gEAAgE,SAAS;AAAA,MACzE,EAAE,OAAO,QAAQ,UAAU,QAAQ;AAAA,IACrC;AACA,WAAO,EAAE,SAAS,MAAM,SAAS,iDAAiD;AAAA,EACpF,SAAS,KAAK;AACZ,WAAO,EAAE,SAAS,OAAO,SAAS,yBAAyB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG;AAAA,EAChH;AACF;AAEA,SAAS,kBAAkB,YAAoB,QAAoF;AACjI,MAAI;AACF,QAAIA,UAAS,WAAW,UAAU,IAAI,KAAK,MAAM,aAAa,YAAY,OAAO,CAAC,IAAI,CAAC;AACvF,QAAI,CAACA,QAAO,OAAO,OAAOA,QAAO,QAAQ,SAAU,CAAAA,QAAO,MAAM,CAAC;AAEjE,IAAAA,QAAO,IAAI,YAAY,IAAI;AAAA,MACzB,MAAM;AAAA,MACN,SAAS,CAAC,OAAO,SAAS,GAAG,OAAO,IAAI;AAAA,MACxC,SAAS;AAAA,IACX;AAEA,kBAAc,YAAY,KAAK,UAAUA,SAAQ,MAAM,CAAC,IAAI,MAAM,OAAO;AACzE,WAAO,EAAE,SAAS,MAAM,SAAS,0BAA0B,UAAU,GAAG;AAAA,EAC1E,SAAS,KAAK;AACZ,WAAO,EAAE,SAAS,OAAO,SAAS,2BAA2B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG;AAAA,EAClH;AACF;AAEA,SAAS,wBAAwB,aAAqB,YAAoB,QAAoF;AAC5J,MAAI;AACF,UAAM,MAAM,KAAK,YAAY,IAAI;AACjC,QAAI,CAAC,WAAW,GAAG,EAAG,WAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAExD,QAAIA,UAAS,WAAW,UAAU,IAAI,KAAK,MAAM,aAAa,YAAY,OAAO,CAAC,IAAI,CAAC;AACvF,QAAI,CAACA,QAAO,cAAc,OAAOA,QAAO,eAAe,SAAU,CAAAA,QAAO,aAAa,CAAC;AAEtF,IAAAA,QAAO,WAAW,YAAY,IAAI;AAAA,MAChC,SAAS,OAAO;AAAA,MAChB,MAAM,OAAO;AAAA,IACf;AAEA,kBAAc,YAAY,KAAK,UAAUA,SAAQ,MAAM,CAAC,IAAI,MAAM,OAAO;AACzE,WAAO,EAAE,SAAS,MAAM,SAAS,cAAc,WAAW,OAAO,UAAU,GAAG;AAAA,EAChF,SAAS,KAAK;AACZ,WAAO,EAAE,SAAS,OAAO,SAAS,GAAG,WAAW,mBAAmB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG;AAAA,EACxH;AACF;AAEA,SAAS,eAAe,QAAoF;AAC1G,QAAM,OAAO,QAAQ;AACrB,QAAM,WAAW,KAAK,MAAM,QAAQ;AACpC,QAAM,aAAa,KAAK,UAAU,aAAa;AAE/C,MAAI;AACF,QAAI,CAAC,WAAW,QAAQ,EAAG,WAAU,UAAU,EAAE,WAAW,KAAK,CAAC;AAElE,QAAI,UAAU,WAAW,UAAU,IAAI,aAAa,YAAY,OAAO,IAAI;AAC3E,UAAM,eAAe;AAAA,aAAwC,OAAO,OAAO;AAAA,UAAc,OAAO,KAAK,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA;AAElI,UAAM,eAAe;AACrB,QAAI,aAAa,KAAK,OAAO,GAAG;AAC9B,gBAAU,QAAQ,QAAQ,cAAc,YAAY;AAAA,IACtD,OAAO;AACL,YAAM,gBAAgB,QAAQ,QAAQ,eAAe;AACrD,UAAI,kBAAkB,IAAI;AACxB,cAAM,UAAU,QAAQ,QAAQ,MAAM,aAAa;AACnD,cAAM,YAAY,YAAY,KAAK,UAAU,IAAI,QAAQ;AACzD,kBAAU,QAAQ,MAAM,GAAG,SAAS,IAAI,OAAO,eAAe,QAAQ,MAAM,SAAS;AAAA,MACvF,OAAO;AACL,kBAAU,QAAQ,QAAQ,IAAI,0BAA0B;AAAA,MAC1D;AAAA,IACF;AAEA,kBAAc,YAAY,SAAS,OAAO;AAC1C,WAAO,EAAE,SAAS,MAAM,SAAS,oBAAoB;AAAA,EACvD,SAAS,KAAK;AACZ,WAAO,EAAE,SAAS,OAAO,SAAS,wBAAwB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG;AAAA,EAC/G;AACF;AAEA,SAAS,mBAAmB,SAA0B;AACpD,MAAI;AACF,UAAM,YAAY,QAAQ,aAAa;AACvC,UAAM,WAAW,YAAY,SAAS,OAAO,KAAK,SAAS,OAAO;AAClE,aAAS,UAAU,EAAE,OAAO,OAAO,CAAC;AACpC,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,eAA2B;AACzC,SAAO,CAAC,UAAU,YAAY,UAAU,YAAY,OAAO;AAC7D;AAjNA;AAAA;AAAA;AAQA;AAAA;AAAA;;;ACRA;AAAA;AAAA;AAAA;AAeA,eAAsB,eAAe,UAAkC;AAErE,QAAM,QAAQ,eAAe;AAC7B,MAAI,CAAC,OAAO,aAAa;AACvB,OAAG,MAAM,kDAAkD;AAC3D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,aAAa,aAAa;AAGhC,MAAI,CAAC,UAAU;AACb,OAAG,OAAO,gBAAgB;AAE1B,UAAM,WAAW,YAAY;AAC7B,UAAM,QAAQ,SAAS,OAAO,CAAC,MAAM,EAAE,QAAQ;AAE/C,QAAI,MAAM,WAAW,GAAG;AACtB,SAAG,IAAI,4DAA4D;AACnE,SAAG,MAAM;AACT,SAAG,KAAK,kBAAkB;AAC1B,iBAAW,QAAQ,YAAY;AAC7B,WAAG,KAAK,YAAO,IAAI,EAAE;AAAA,MACvB;AACA,SAAG,MAAM;AACT,SAAG,KAAK,kCAAkC;AAC1C;AAAA,IACF;AAEA,eAAWC,SAAQ,UAAU;AAC3B,UAAIA,MAAK,UAAU;AACjB,WAAG,QAAQ,GAAGA,MAAK,WAAW,kBAAa;AAAA,MAC7C,OAAO;AACL,WAAG,IAAI,GAAGA,MAAK,WAAW,mBAAc;AAAA,MAC1C;AAAA,IACF;AAEA,OAAG,MAAM;AACT,OAAG,KAAK,wDAAwD;AAChE,OAAG,KAAK,wBAAwB,MAAM,CAAC,EAAE,IAAI,EAAE;AAC/C;AAAA,EACF;AAGA,QAAM,OAAO,SAAS,YAAY;AAClC,MAAI,CAAC,WAAW,SAAS,IAAI,GAAG;AAC9B,OAAG,MAAM,iBAAiB,QAAQ,EAAE;AACpC,OAAG,MAAM;AACT,OAAG,KAAK,kBAAkB;AAC1B,eAAW,QAAQ,YAAY;AAC7B,SAAG,KAAK,YAAO,IAAI,EAAE;AAAA,IACvB;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,KAAG,KAAK,uBAAuB,QAAQ,KAAK;AAE5C,QAAM,SAAS,MAAM,cAAc,IAAI;AAEvC,MAAI,OAAO,SAAS;AAClB,OAAG,QAAQ,OAAO,OAAO;AACzB,OAAG,MAAM;AACT,OAAG,KAAK,6CAA6C;AACrD,OAAG,IAAI,8CAA8C;AAAA,EACvD,OAAO;AACL,OAAG,MAAM,OAAO,OAAO;AACvB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AApFA;AAAA;AAAA;AAMA;AACA;AAMA;AAAA;AAAA;;;ACbA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBA,eAAe,cAA+C;AAC5D,QAAM,QAAQ,MAAM,cAAc;AAClC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,SAAS,KAAK,kDAAkD;AAAA,EAC5E;AACA,SAAO;AAAA,IACL,eAAe,UAAU,KAAK;AAAA,IAC9B,gBAAgB;AAAA,EAClB;AACF;AAEA,eAAe,QACb,QACA,MACA,MACY;AACZ,QAAM,YAAY,aAAa;AAC/B,QAAM,UAAU,MAAM,YAAY;AAGlC,QAAM,QAAQ,QAAQ,eAAe,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK;AACzD,QAAM,cAAc,MAAM,SAAS,KAAK,GAAG,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,MAAM,MAAM,EAAE,CAAC,KAAK;AAEtF,MAAI,QAAQ,IAAI,OAAO;AACrB,YAAQ,MAAM,wBAAwB,MAAM,IAAI,SAAS,GAAG,IAAI,EAAE;AAClE,YAAQ,MAAM,kBAAkB,WAAW,EAAE;AAAA,EAC/C;AAEA,QAAM,MAAM,MAAM,MAAM,GAAG,SAAS,GAAG,IAAI,IAAI;AAAA,IAC7C;AAAA,IACA,SAAS;AAAA,MACP,GAAG;AAAA,MACH,UAAU;AAAA,MACV,cAAc;AAAA,IAChB;AAAA,IACA,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,EACtC,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAO,MAAM,IAAI,KAAK;AAG5B,UAAM,IAAI,SAAS,IAAI,QAAQ,cAAc,IAAI,MAAM,MAAM,IAAI,EAAE;AAAA,EACrE;AAEA,SAAQ,MAAM,IAAI,KAAK;AACzB;AAcA,eAAsB,iBAAuC;AAC3D,QAAM,OAAO,MAAM,QAAqC,OAAO,iBAAiB;AAChF,SAAO,KAAK,cAAc,CAAC;AAC7B;AAEA,eAAsB,gBAAgB,aAAoC;AACxE,QAAM,QAAQ,QAAQ,mBAAmB;AAAA,IACvC,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,gBACpB,MACA,SACA,eACoB;AACpB,QAAM,OAAO,MAAM,QAAkC,QAAQ,mBAAmB;AAAA,IAC9E,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,SAAO,KAAK;AACd;AAgBA,eAAsB,gBAGnB;AAED,QAAM,YAAY,aAAa;AAC/B,QAAM,QAAQ,MAAM,cAAc;AAClC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,SAAS,KAAK,kDAAkD;AAAA,EAC5E;AAEA,QAAM,MAAM,MAAM,MAAM,GAAG,SAAS,YAAY;AAAA,IAC9C,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACnB,SAAS;AAAA,MACT,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,WAAW,CAAC;AAAA,MACd;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAM,IAAI,SAAS,IAAI,QAAQ,cAAc,IAAI,MAAM,MAAM,IAAI,EAAE;AAAA,EACrE;AAEA,QAAM,YAAa,MAAM,IAAI,KAAK;AAGlC,MAAI,UAAU,OAAO;AACnB,UAAM,IAAI,SAAS,KAAK,UAAU,MAAM,WAAW,iBAAiB;AAAA,EACtE;AAEA,QAAM,UAAU,UAAU,QAAQ,WAAW,CAAC;AAC9C,QAAM,cAAc,QACjB,OAAO,CAAC,MAAwB,EAAE,SAAS,MAAM,EACjD,IAAI,CAAC,MAAwB,EAAE,IAAI,EACnC,KAAK,IAAI;AAEZ,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,WAAW;AACrC,WAAO;AAAA,MACL,QAAQ,OAAO,UAAU,OAAO,UAAU,CAAC;AAAA,MAC3C,WAAW,OAAO,aAAa;AAAA,IACjC;AAAA,EACF,QAAQ;AACN,WAAO,EAAE,QAAQ,CAAC,GAAG,WAAW,GAAG;AAAA,EACrC;AACF;AAIA,eAAsB,cAAgC;AACpD,QAAM,YAAY,aAAa;AAC/B,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,GAAG,SAAS,eAAe,EAAE,QAAQ,MAAM,CAAC;AACpE,WAAO,IAAI;AAAA,EACb,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AA3LA,IAUa;AAVb;AAAA;AAAA;AAOA;AACA;AAEO,IAAM,WAAN,cAAuB,MAAM;AAAA,MAClC,YACS,QACP,SACA;AACA,cAAM,OAAO;AAHN;AAIP,aAAK,OAAO;AAAA,MACd;AAAA,IACF;AAAA;AAAA;;;AClBA;AAAA;AAAA;AAAA;AAUA,eAAsB,gBAA+B;AACnD,QAAM,QAAQ,eAAe;AAC7B,MAAI,CAAC,OAAO,aAAa;AACvB,OAAG,MAAM,kDAAkD;AAC3D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,UAAU,MAAM,YAAY;AAClC,MAAI,CAAC,SAAS;AACZ,OAAG,MAAM,wDAAwD;AACjE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,YAAY,mBAAmB;AAErC,KAAG,OAAO,mBAAmB;AAG7B,MAAI,UAAU,MAAM;AAClB,OAAG,GAAG,aAAa,UAAU,IAAI;AAAA,EACnC;AACA,MAAI,UAAU,IAAI;AAChB,OAAG,GAAG,MAAM,UAAU,EAAE;AAAA,EAC1B;AACA,KAAG,MAAM;AAET,MAAI;AACF,UAAM,EAAE,QAAQ,UAAU,IAAI,MAAM,cAAc;AAElD,QAAI,OAAO,WAAW,GAAG;AACvB,SAAG,IAAI,qCAAqC;AAC5C,SAAG,MAAM;AACT,SAAG,KAAK,mEAAmE;AAC3E;AAAA,IACF;AAGA,UAAM,OAAO,OAAO,IAAI,CAAC,UAAU;AAAA,MACjC,MAAM,WAAW,MAAM;AAAA,MACvB,MAAM,YAAY;AAAA,MAClB,MAAM;AAAA,MACN,SAAS,MAAM,WAAW,EAAE;AAAA,IAC9B,CAAC;AAED,OAAG;AAAA,MACD,CAAC,SAAS,QAAQ,UAAU,WAAW;AAAA,MACvC;AAAA,IACF;AAGA,UAAM,mBAAmB,OAAO;AAAA,MAC9B,CAAC,MAAM,EAAE,gBAAgB,EAAE,aAAa,SAAS;AAAA,IACnD;AACA,QAAI,iBAAiB,SAAS,GAAG;AAC/B,SAAG,MAAM;AACT,SAAG,KAAK,QAAQ,sBAAsB,CAAC;AACvC,iBAAW,SAAS,kBAAkB;AACpC,WAAG,KAAK,KAAK,MAAM,OAAO,KAAK,MAAM,aAAa,KAAK,IAAI,CAAC,EAAE;AAAA,MAChE;AAAA,IACF;AAEA,OAAG,MAAM;AACT,OAAG,IAAI,eAAe,SAAS,EAAE;AACjC,OAAG,IAAI,GAAG,OAAO,MAAM,qBAAqB;AAAA,EAC9C,SAAS,KAAK;AACZ,OAAG;AAAA,MACD,2BAA2B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC7E;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,SAAS,SAAS,GAAW,KAAqB;AAChD,MAAI,EAAE,UAAU,IAAK,QAAO;AAC5B,SAAO,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI;AAC/B;AAGA,SAAS,QAAQ,GAAmB;AAClC,SAAO,UAAU,CAAC;AACpB;AA3FA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AAAA;;;ACRA;AAAA;AAAA;AAAA;AAcA,eAAsB,iBACpB,QACA,UACA,OACe;AACf,QAAM,QAAQ,eAAe;AAC7B,MAAI,CAAC,OAAO,aAAa;AACvB,OAAG,MAAM,kDAAkD;AAC3D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,cAAc,UAAU,QAAQ,YAAY;AAElD,UAAQ,YAAY;AAAA,IAClB,KAAK;AAAA,IACL,KAAK;AACH,aAAO,cAAc;AAAA,IAEvB,KAAK;AAAA,IACL,KAAK;AACH,UAAI,CAAC,UAAU;AACb,WAAG,MAAM,2DAA2D;AACpE,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,aAAO,gBAAgB,QAAQ;AAAA,IAEjC,KAAK;AAAA,IACL,KAAK;AACH,UAAI,CAAC,UAAU;AACb,WAAG,MAAM,+DAA+D;AACxE,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,aAAO,gBAAgB,UAAU,KAAK;AAAA,IAExC;AACE,SAAG,MAAM,uBAAuB,MAAM,EAAE;AACxC,SAAG,MAAM;AACT,SAAG,KAAK,wBAAwB;AAChC,SAAG,KAAK,uCAAkC;AAC1C,SAAG,KAAK,2CAAsC;AAC9C,SAAG,KAAK,0CAAqC;AAC7C,cAAQ,KAAK,CAAC;AAAA,EAClB;AACF;AAEA,eAAe,gBAA+B;AAC5C,KAAG,OAAO,YAAY;AAEtB,MAAI;AACF,UAAM,aAAa,MAAM,eAAe;AACxC,UAAM,SAAS,mBAAmB;AAElC,QAAI,WAAW,WAAW,GAAG;AAC3B,SAAG,IAAI,sBAAsB;AAC7B,SAAG,KAAK,sEAAsE;AAC9E;AAAA,IACF;AAEA,eAAW,MAAM,YAAY;AAC3B,YAAM,WAAW,GAAG,OAAO,OAAO,MAAM,GAAG;AAC3C,YAAM,SAAS,WAAW,mBAAc;AACxC,YAAM,OAAO,GAAG,QAAQ;AAExB,UAAI,UAAU;AACZ,WAAG,QAAQ,GAAG,IAAI,KAAK,GAAG,EAAE,IAAI,MAAM,EAAE;AAAA,MAC1C,OAAO;AACL,WAAG,KAAK,KAAK,IAAI,KAAK,GAAG,EAAE,GAAG;AAAA,MAChC;AAEA,UAAI,GAAG,SAAS;AACd,WAAG,IAAI,aAAa,GAAG,OAAO,EAAE;AAAA,MAClC;AAAA,IACF;AAEA,OAAG,MAAM;AACT,OAAG,IAAI,GAAG,WAAW,MAAM,eAAe;AAAA,EAC5C,SAAS,KAAK;AACZ,OAAG,MAAM,8BAA8B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AACzF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAe,gBAAgB,UAAiC;AAC9D,MAAI;AACF,UAAM,aAAa,MAAM,eAAe;AAGxC,UAAM,SAAS,WAAW;AAAA,MACxB,CAAC,OACC,GAAG,OAAO,YACV,GAAG,KAAK,YAAY,MAAM,SAAS,YAAY;AAAA,IACnD;AAEA,QAAI,CAAC,QAAQ;AACX,SAAG,MAAM,wBAAwB,QAAQ,EAAE;AAC3C,SAAG,MAAM;AACT,SAAG,KAAK,uBAAuB;AAC/B,iBAAW,MAAM,YAAY;AAC3B,WAAG,KAAK,KAAK,GAAG,IAAI,KAAK,GAAG,EAAE,GAAG;AAAA,MACnC;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,gBAAmB,OAAO,EAAE;AAClC,uBAAmB,OAAO,IAAI,OAAO,IAAI;AACzC,OAAG,QAAQ,0BAA0B,OAAO,IAAI,EAAE;AAAA,EACpD,SAAS,KAAK;AACZ,OAAG,MAAM,+BAA+B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAC1F,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAe,gBAAgB,MAAc,SAAiC;AAC5E,MAAI,CAAC,SAAS;AACZ,OAAG,MAAM,6BAA6B;AACtC,OAAG,KAAK,sDAAsD;AAC9D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI;AACF,UAAM,YAAY,MAAM,gBAAmB,MAAM,SAAS,MAAM;AAChE,uBAAmB,UAAU,IAAI,UAAU,QAAQ,IAAI;AACvD,OAAG,QAAQ,sBAAsB,UAAU,QAAQ,IAAI,EAAE;AACzD,OAAG,GAAG,MAAM,UAAU,EAAE;AACxB,OAAG,GAAG,QAAQ,OAAO;AAAA,EACvB,SAAS,KAAK;AACZ,OAAG,MAAM,+BAA+B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAC1F,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AA/IA;AAAA;AAAA;AAMA;AACA;AAKA;AAAA;AAAA;;;ACNA,SAAS,YAAAC,iBAAgB;AAWzB,SAAS,IAAI,KAAa,KAAqB;AAC7C,MAAI;AACF,WAAOA,UAAS,OAAO,GAAG,IAAI;AAAA,MAC5B;AAAA,MACA,UAAU;AAAA,MACV,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,IAChC,CAAC,EAAE,KAAK;AAAA,EACV,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,iBAAiB,MAAc,QAAQ,IAAI,GAAsB;AAC/E,QAAM,WAAW,IAAI,6BAA6B,GAAG;AACrD,MAAI,CAAC,SAAU,QAAO;AAEtB,QAAM,SAAS,IAAI,yBAAyB,GAAG;AAC/C,QAAM,SAAS,IAAI,+BAA+B,GAAG;AACrD,QAAM,UAAU,IAAI,kBAAkB,GAAG;AACzC,QAAM,SAAS,IAAI,sBAAsB,GAAG;AAE5C,SAAO;AAAA,IACL,QAAQ,UAAU;AAAA,IAClB;AAAA,IACA,QAAQ,UAAU;AAAA,IAClB,SAAS,WAAW;AAAA,IACpB,OAAO,OAAO,SAAS;AAAA,IACvB,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,EACtC;AACF;AA9CA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAOA,SAAS,cAAAC,aAAY,iBAAAC,sBAAqB;AAC1C,SAAS,QAAAC,aAAY;AAOrB,eAAsB,cAA6B;AACjD,QAAM,QAAQ,eAAe;AAC7B,MAAI,CAAC,OAAO,aAAa;AACvB,OAAG,MAAM,kDAAkD;AAC3D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,MAAM,QAAQ,IAAI;AAExB,KAAG,OAAO,yBAAyB;AAGnC,QAAMC,OAAM,iBAAiB,GAAG;AAChC,MAAIA,MAAK;AACP,OAAG,QAAQ,yBAAyB;AACpC,OAAG,GAAG,UAAUA,KAAI,UAAU,aAAa;AAC3C,OAAG,GAAG,UAAUA,KAAI,MAAM;AAC1B,OAAG,GAAG,QAAQA,KAAI,QAAQ,MAAM,GAAG,CAAC,CAAC;AACrC,OAAG,GAAG,SAASA,KAAI,QAAQ,QAAQ,OAAO;AAAA,EAC5C,OAAO;AACL,OAAG,KAAK,kDAAkD;AAC1D,OAAG,IAAI,8CAA8C;AAAA,EACvD;AAEA,KAAG,MAAM;AAGT,MAAI;AACF,UAAM,aAAa,MAAM,eAAe;AACxC,QAAI,UAAU;AAEd,QAAIA,MAAK,UAAU,WAAW,SAAS,GAAG;AAExC,YAAM,mBAAmB,gBAAgBA,KAAI,MAAM;AACnD,YAAM,QAAQ,WAAW,KAAK,CAAC,OAAO;AACpC,YAAI,CAAC,GAAG,QAAS,QAAO;AACxB,eAAO,gBAAgB,GAAG,OAAO,MAAM;AAAA,MACzC,CAAC;AAED,UAAI,OAAO;AACT,2BAAmB,MAAM,IAAI,MAAM,IAAI;AACvC,WAAG,QAAQ,yBAAyB,MAAM,IAAI,EAAE;AAChD,WAAG,GAAG,gBAAgB,MAAM,EAAE;AAC9B,kBAAU;AAAA,MACZ;AAAA,IACF;AAEA,QAAI,CAAC,SAAS;AACZ,UAAIA,MAAK,QAAQ;AACf,cAAM,SAAS,MAAM,GAAG,QAAQ,8DAA8D;AAC9F,YAAI,QAAQ;AACV,gBAAM,OAAO,MAAM,GAAG,MAAM,kBAAkBA,KAAI,OAAO,MAAM,GAAG,EAAE,IAAI,GAAG,QAAQ,UAAU,EAAE,CAAC;AAChG,cAAI;AACF,kBAAM,EAAE,iBAAAC,iBAAgB,IAAI,MAAM;AAClC,kBAAM,YAAY,MAAMA,iBAAgB,MAAMD,KAAI,QAAQA,KAAI,UAAU,MAAM;AAC9E,+BAAmB,UAAU,IAAI,UAAU,IAAI;AAC/C,eAAG,QAAQ,qCAAqC,UAAU,IAAI,EAAE;AAChE,eAAG,GAAG,gBAAgB,UAAU,EAAE;AAClC,sBAAU;AAAA,UACZ,SAAS,KAAK;AACZ,eAAG,MAAM,+BAA+B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,UAC5F;AAAA,QACF;AAAA,MACF;AAEA,UAAI,CAAC,SAAS;AACZ,cAAM,SAAS,mBAAmB;AAClC,YAAI,OAAO,IAAI;AACb,aAAG,KAAK,mCAAmC,OAAO,QAAQ,OAAO,EAAE,EAAE;AAAA,QACvE,WAAW,WAAW,SAAS,GAAG;AAChC,aAAG,KAAK,uBAAuB;AAC/B,qBAAW,MAAM,WAAW,MAAM,GAAG,CAAC,GAAG;AACvC,eAAG,KAAK,YAAO,GAAG,IAAI,KAAK,GAAG,EAAE,GAAG;AAAA,UACrC;AACA,gBAAM,OAAO,MAAM,GAAG,MAAM,6CAA6C;AACzE,cAAI,MAAM;AACP,kBAAM,WAAW,WAAW,KAAK,OAAK,EAAE,OAAO,QAAQ,EAAE,SAAS,IAAI;AACtE,gBAAI,UAAU;AACV,iCAAmB,SAAS,IAAI,SAAS,IAAI;AAC7C,iBAAG,QAAQ,wBAAwB,SAAS,IAAI,EAAE;AAClD,wBAAU;AAAA,YACd;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,KAAK;AACZ,OAAG,IAAI,+BAA+B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,EAC1F;AAEA,KAAG,MAAM;AAGT,QAAM,QAAQ,YAAY,GAAG;AAC7B,QAAM,QAAQ,MAAM,OAAO,CAAC,MAAM,EAAE,QAAQ;AAE5C,MAAI,MAAM,SAAS,GAAG;AACpB,OAAG,KAAK,oBAAoB;AAC5B,eAAW,QAAQ,OAAO;AACxB,SAAG,KAAK,YAAO,KAAK,WAAW,EAAE;AAAA,IACnC;AACA,OAAG,MAAM;AACT,UAAM,UAAU,MAAM,GAAG,QAAQ,6BAA6B,MAAM,CAAC,EAAE,WAAW,OAAO;AACzF,QAAI,SAAS;AACT,YAAM,EAAE,eAAAE,eAAc,IAAI,MAAM;AAChC,YAAM,MAAM,MAAMA,eAAc,MAAM,CAAC,EAAE,MAAM,GAAG;AAClD,UAAI,IAAI,SAAS;AACb,WAAG,QAAQ,IAAI,OAAO;AAAA,MAC1B,OAAO;AACH,WAAG,MAAM,IAAI,OAAO;AAAA,MACxB;AAAA,IACJ,OAAO;AACH,SAAG,KAAK,mDAAmD,MAAM,CAAC,EAAE,IAAI,IAAI;AAAA,IAChF;AAAA,EACF,OAAO;AACL,OAAG,IAAI,+EAA+E;AAAA,EACxF;AAGA,QAAM,aAAaH,MAAK,KAAK,kBAAkB;AAC/C,QAAM,WAAW,mBAAmB;AAEpC,MAAI,CAACF,YAAW,UAAU,GAAG;AAC3B,QAAI,SAAS,IAAI;AACb,YAAM,gBAAgB;AAAA,QACpB,SAAS;AAAA,QACT,aAAa,SAAS;AAAA,QACtB,QAAQ;AAAA,QACR,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC;AAEA,MAAAC,eAAc,YAAY,KAAK,UAAU,eAAe,MAAM,CAAC,IAAI,MAAM,OAAO;AAChF,SAAG,MAAM;AACT,SAAG,QAAQ,0BAA0B;AACrC,SAAG,IAAI,kFAAkF;AAAA,IAC7F;AAAA,EACF,OAAO;AAEL,QAAI;AACA,YAAM,EAAE,cAAAK,cAAa,IAAI,MAAM,OAAO,IAAS;AAC/C,YAAM,WAAW,KAAK,MAAMA,cAAa,YAAY,OAAO,CAAC;AAC7D,UAAI,SAAS,MAAM,SAAS,gBAAgB,SAAS,IAAI;AACrD,iBAAS,cAAc,SAAS;AAChC,QAAAL,eAAc,YAAY,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI,MAAM,OAAO;AAC3E,WAAG,QAAQ,8CAA8C,SAAS,EAAE,EAAE;AAAA,MAC1E;AAAA,IACJ,QAAQ;AAAA,IAAC;AAAA,EACX;AAEA,KAAG,MAAM;AACX;AAKA,SAAS,gBAAgB,KAAqB;AAC5C,MAAI,aAAa,IAAI,KAAK,EAAE,YAAY;AACxC,eAAa,WAAW,QAAQ,UAAU,EAAE;AAE5C,QAAM,WAAW,WAAW,MAAM,oBAAoB;AACtD,MAAI,UAAU;AACZ,iBAAa,GAAG,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC;AAAA,EAC5C;AAEA,eAAa,WAAW,QAAQ,gBAAgB,EAAE;AAClD,eAAa,WAAW,QAAQ,aAAa,EAAE;AAC/C,eAAa,WAAW,QAAQ,OAAO,EAAE;AACzC,SAAO;AACT;AAvLA;AAAA;AAAA;AASA;AACA;AACA;AACA;AACA;AAAA;AAAA;;;ACbA;AAAA;AAAA;AAAA;AAUA,eAAsB,aAAa;AACjC,MAAI;AACF,UAAM,YAAY,aAAa;AAC/B,UAAM,SAAS,GAAG,SAAS;AAE3B,YAAQ,MAAM,YAAY,OAAO;AACjC,QAAI,SAAS;AAEb,YAAQ,MAAM,GAAG,QAAQ,OAAO,UAAU;AACxC,YAAM,WAAW,OAAO,KAAK;AAC7B,gBAAU;AAEV,UAAI;AACJ,cAAQ,eAAe,OAAO,QAAQ,IAAI,MAAM,GAAG;AACjD,YAAI,OAAO,OAAO,MAAM,GAAG,YAAY,EAAE,KAAK;AAC9C,iBAAS,OAAO,MAAM,eAAe,CAAC;AAEtC,YAAI,CAAC,KAAM;AAGX,YAAI,KAAK,SAAS,IAAI,GAAG;AACtB,gBAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,sBAAY,MAAM,CAAC,IAAI,KAAK,MAAM;AAClC,mBAAS,IAAI,GAAG,IAAI,MAAM,SAAS,GAAG,KAAK;AACzC,wBAAY,MAAM,MAAM,CAAC,IAAI,KAAK,MAAM;AAAA,UAC1C;AACA,sBAAY,MAAM,MAAM,MAAM,SAAS,CAAC,GAAG,MAAM;AAAA,QACpD,OAAO;AACJ,sBAAY,MAAM,MAAM;AAAA,QAC3B;AAAA,MACF;AAAA,IACF,CAAC;AAED,YAAQ,MAAM,GAAG,OAAO,MAAM;AAC5B,cAAQ,KAAK,CAAC;AAAA,IAChB,CAAC;AAGD,UAAM,IAAI,QAAQ,MAAM;AAAA,IAAC,CAAC;AAAA,EAC5B,SAAS,KAAK;AACZ,YAAQ,OAAO,MAAM,6BAA6B,GAAG;AAAA,CAAI;AACzD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAe,YAAY,MAAc,QAAgB;AACrD,MAAI;AACJ,MAAI;AACA,cAAU,KAAK,MAAM,IAAI;AAAA,EAC7B,QAAQ;AAAE;AAAA,EAAQ;AAElB,QAAM,iBAAiB,CAAC,OAAO,UAAU,eAAe,KAAK,SAAS,IAAI;AAC1E,QAAM,YAAY,QAAQ;AAE1B,MAAI;AACA,UAAM,QAAQ,MAAM,cAAc;AAElC,QAAI,CAAC,OAAO;AACT,YAAM,IAAI,MAAM,+DAA+D;AAAA,IAClF;AAEA,UAAM,MAAM,MAAM,MAAM,QAAQ;AAAA,MAC5B,QAAQ;AAAA,MACR,SAAS;AAAA,QACL,gBAAgB;AAAA,QAChB,iBAAiB,UAAU,KAAK;AAAA,QAChC,cAAc;AAAA,MAClB;AAAA,MACA,MAAM;AAAA,IACV,CAAC;AAGD,QAAI,eAAgB;AAEpB,UAAM,eAAe,MAAM,IAAI,KAAK;AACpC,QAAI,cAAc;AACd,cAAQ,OAAO,MAAM,eAAe,IAAI;AAAA,IAC5C;AAAA,EACJ,SAAS,KAAK;AACV,QAAI,eAAgB;AAEpB,YAAQ,OAAO,MAAM,KAAK,UAAU;AAAA,MAChC,SAAS;AAAA,MACT,IAAI;AAAA,MACJ,OAAO;AAAA,QACH,MAAM;AAAA,QACN,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MAC5D;AAAA,IACJ,CAAC,IAAI,IAAI;AAAA,EACb;AACJ;AApGA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;;;ACFA;AAAA;AAAA;AAAA;AAUA,eAAsB,gBAA+B;AACnD,KAAG,OAAO,0BAA0B;AAEpC,QAAM,QAAQ,eAAe;AAC7B,QAAM,YAAY,mBAAmB;AACrC,QAAM,YAAY,aAAa;AAE/B,KAAG,GAAG,UAAU,SAAS;AACzB,KAAG,GAAG,UAAU,cAAc,CAAC;AAC/B,KAAG,MAAM;AAET,MAAI,OAAO,aAAa;AACtB,OAAG,QAAQ,eAAe;AAC1B,OAAG,GAAG,aAAa,MAAM,QAAQ;AACjC,QAAI,MAAM,QAAQ;AAChB,SAAG,GAAG,WAAW,MAAM,MAAM;AAAA,IAC/B;AAEA,UAAM,YAAY,MAAM,YAAY,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAChE,QAAI,YAAY,GAAG;AACjB,YAAM,UAAU,KAAK,MAAM,YAAY,EAAE;AACzC,SAAG,GAAG,iBAAiB,MAAM,OAAO,YAAY;AAAA,IAClD,OAAO;AACL,SAAG,KAAK,iEAA4D;AAAA,IACtE;AAAA,EACF,OAAO;AACL,OAAG,MAAM,4CAA4C;AAAA,EACvD;AAEA,KAAG,MAAM;AAET,MAAI,UAAU,IAAI;AAChB,OAAG,GAAG,oBAAoB,UAAU,QAAQ,QAAG;AAC/C,OAAG,GAAG,gBAAgB,UAAU,EAAE;AAAA,EACpC,OAAO;AACL,OAAG,IAAI,0BAA0B;AAAA,EACnC;AAEA,KAAG,MAAM;AAGT,KAAG,KAAK,2BAA2B;AACnC,QAAM,UAAU,MAAM,YAAY;AAClC,MAAI,SAAS;AACX,OAAG,QAAQ,qBAAqB;AAAA,EAClC,OAAO;AACL,OAAG,MAAM,uBAAuB;AAAA,EAClC;AACF;AA1DA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AAAA;;;ACAA;AADA,SAAS,eAAe;AAGxB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,YAAY,EACjB,YAAY,wDAAwD,EACpE,QAAQ,OAAO,EACf,KAAK,aAAa,MAAM;AAEzB,CAAC;AAGH,QACG,QAAQ,OAAO,EACf,YAAY,gDAAgD,EAC5D,OAAO,YAAY;AAClB,QAAM,EAAE,cAAAM,cAAa,IAAI,MAAM;AAC/B,QAAMA,cAAa;AACrB,CAAC;AAGH,QACG,QAAQ,QAAQ,EAChB,YAAY,0BAA0B,EACtC,OAAO,YAAY;AAClB,QAAM,EAAE,eAAAC,eAAc,IAAI,MAAM;AAChC,EAAAA,eAAc;AAChB,CAAC;AAGH,QACG,QAAQ,gBAAgB,EACxB,YAAY,0FAA0F,EACtG,OAAO,OAAO,SAAkB;AAC/B,QAAM,EAAE,gBAAAC,gBAAe,IAAI,MAAM;AACjC,QAAMA,gBAAe,IAAI;AAC3B,CAAC;AAGH,QACG,QAAQ,QAAQ,EAChB,MAAM,GAAG,EACT,YAAY,sCAAsC,EAClD,OAAO,YAAY;AAClB,QAAM,EAAE,eAAAC,eAAc,IAAI,MAAM;AAChC,QAAMA,eAAc;AACtB,CAAC;AAGH,QACG,QAAQ,mCAAmC,EAC3C,MAAM,IAAI,EACV,YAAY,0CAA0C,EACtD,OAAO,OAAO,QAAiB,MAAe,UAAmB;AAChE,QAAM,EAAE,kBAAAC,kBAAiB,IAAI,MAAM;AACnC,QAAMA,kBAAiB,QAAQ,MAAM,KAAK;AAC5C,CAAC;AAGH,QACG,QAAQ,MAAM,EACd,YAAY,8CAA8C,EAC1D,OAAO,YAAY;AAClB,QAAM,EAAE,aAAAC,aAAY,IAAI,MAAM;AAC9B,QAAMA,aAAY;AACpB,CAAC;AAGH,QACG,QAAQ,KAAK,EACb,YAAY,8DAA8D,EAC1E,OAAO,YAAY;AAClB,MAAI;AACF,UAAM,EAAE,YAAAC,YAAW,IAAI,MAAM;AAC7B,UAAMA,YAAW;AAAA,EACnB,SAAS,KAAK;AACZ,YAAQ,OAAO,MAAM,oBAAoB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AAC7F,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAGH,QACG,QAAQ,QAAQ,EAChB,YAAY,+CAA+C,EAC3D,OAAO,YAAY;AAClB,QAAM,EAAE,eAAAC,eAAc,IAAI,MAAM;AAChC,QAAMA,eAAc;AACtB,CAAC;AAGH,QAAQ,OAAO,MAAM;AACnB,KAAG,OAAO;AACV,UAAQ,KAAK;AACf,CAAC;AAGD,QAAQ,WAAW,QAAQ,IAAI,EAAE,MAAM,CAAC,QAAQ;AAC9C,KAAG,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AACzD,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["config","tool","execSync","existsSync","writeFileSync","join","git","createWorkspace","configureTool","readFileSync","loginCommand","logoutCommand","connectCommand","statusCommand","workspaceCommand","initCommand","mcpCommand","whoamiCommand"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/ui.ts","../src/lib/config.ts","../src/lib/auth.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/lib/detect.ts","../src/commands/connect.ts","../src/lib/api.ts","../src/commands/status.ts","../src/commands/workspace.ts","../src/lib/git.ts","../src/commands/init.ts","../src/commands/mcp.ts","../src/commands/whoami.ts","../src/cli.ts"],"sourcesContent":["/**\n * Orkestrate CLI — Terminal UI Helpers\n *\n * Pretty output formatting for the terminal.\n */\n\nimport pc from \"picocolors\";\n\nexport const ui = {\n // Status icons\n success: (msg: string) => console.log(` ${pc.green(\"✓\")} ${msg}`),\n error: (msg: string) => console.log(` ${pc.red(\"✗\")} ${msg}`),\n info: (msg: string) => console.log(` ${pc.blue(\"→\")} ${msg}`),\n warn: (msg: string) => console.log(` ${pc.yellow(\"!\")} ${msg}`),\n dim: (msg: string) => console.log(` ${pc.dim(msg)}`),\n\n // Headers\n header: (msg: string) => {\n console.log();\n console.log(` ${pc.bold(pc.white(msg))}`);\n console.log();\n },\n\n // Blank line\n blank: () => console.log(),\n\n // Indented line\n line: (msg: string) => console.log(` ${msg}`),\n\n // Key-value pair\n kv: (key: string, value: string) => {\n console.log(` ${pc.dim(key + \":\")} ${value}`);\n },\n\n // Table\n table: (headers: string[], rows: string[][]) => {\n const colWidths = headers.map((h, i) => {\n const maxContent = Math.max(h.length, ...rows.map((r) => (r[i] || \"\").length));\n return Math.min(maxContent, 40);\n });\n\n const separator = \"─\";\n const pad = (s: string, w: number) => s.padEnd(w).slice(0, w);\n\n // Top border\n console.log(\n ` ┌${colWidths.map((w) => separator.repeat(w + 2)).join(\"┬\")}┐`,\n );\n\n // Header row\n console.log(\n ` │${headers.map((h, i) => ` ${pc.bold(pad(h, colWidths[i]))} `).join(\"│\")}│`,\n );\n\n // Header separator\n console.log(\n ` ├${colWidths.map((w) => separator.repeat(w + 2)).join(\"┼\")}┤`,\n );\n\n // Data rows\n for (const row of rows) {\n console.log(\n ` │${row.map((c, i) => ` ${pad(c || \"\", colWidths[i])} `).join(\"│\")}│`,\n );\n }\n\n // Bottom border\n console.log(\n ` └${colWidths.map((w) => separator.repeat(w + 2)).join(\"┴\")}┘`,\n );\n },\n\n // Colored status badge\n statusBadge: (status: string): string => {\n switch (status) {\n case \"active\":\n return pc.green(\"● active\");\n case \"idle\":\n return pc.dim(\"○ idle\");\n case \"blocked\":\n return pc.red(\"■ blocked\");\n case \"planning\":\n return pc.blue(\"◆ planning\");\n case \"handoff\":\n return pc.yellow(\"⇄ handoff\");\n case \"done\":\n return pc.dim(\"✓ done\");\n default:\n return pc.dim(status);\n }\n },\n\n // Interactive prompts\n confirm: async (question: string, defaultYes = true): Promise<boolean> => {\n const { createInterface } = await import(\"node:readline/promises\");\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n const suffix = defaultYes ? \"[Y/n]\" : \"[y/N]\";\n const answer = await rl.question(` ${pc.bold(pc.white(question))} ${pc.dim(suffix)} `);\n rl.close();\n if (!answer) return defaultYes;\n return answer.toLowerCase().startsWith(\"y\");\n },\n\n input: async (question: string, defaultValue?: string): Promise<string> => {\n const { createInterface } = await import(\"node:readline/promises\");\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n const suffix = defaultValue ? pc.dim(` (${defaultValue})`) : \"\";\n const answer = await rl.question(` ${pc.bold(pc.white(question))}${suffix} `);\n rl.close();\n return answer || defaultValue || \"\";\n },\n\n // Banner\n banner: () => {\n console.log();\n console.log(pc.bold(pc.cyan(\" ⬡ orkestrate\")));\n console.log(pc.dim(\" the coordination layer for AI coding agents\"));\n console.log();\n },\n};\n","/**\n * Orkestrate CLI — Configuration Management\n *\n * Stores credentials and preferences in the user's home directory.\n * Uses the `conf` package for cross-platform config storage.\n */\n\nimport Conf from \"conf\";\n\nexport interface StoredCredentials {\n clientId: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number; // epoch seconds\n userId: string;\n scope: string;\n githubAccessToken?: string;\n githubRefreshToken?: string;\n githubExpiresAt?: number; // epoch seconds\n}\n\nexport interface CliConfig {\n credentials: StoredCredentials | null;\n activeWorkspaceId: string | null;\n activeWorkspaceName: string | null;\n serverUrl: string;\n}\n\nconst config = new Conf<CliConfig>({\n projectName: \"orkestrate\",\n projectSuffix: \"\",\n defaults: {\n credentials: null,\n activeWorkspaceId: null,\n activeWorkspaceName: null,\n serverUrl: \"https://orkestrate.space\",\n },\n});\n\nexport function getConfig(): CliConfig {\n return {\n credentials: config.get(\"credentials\"),\n activeWorkspaceId: config.get(\"activeWorkspaceId\"),\n activeWorkspaceName: config.get(\"activeWorkspaceName\"),\n serverUrl: config.get(\"serverUrl\"),\n };\n}\n\nexport function getServerUrl(): string {\n return config.get(\"serverUrl\");\n}\n\nexport function setCredentials(creds: StoredCredentials): void {\n config.set(\"credentials\", creds);\n}\n\nexport function getCredentials(): StoredCredentials | null {\n return config.get(\"credentials\");\n}\n\nexport function clearCredentials(): void {\n config.set(\"credentials\", null);\n}\n\nexport function setActiveWorkspace(id: string, name: string): void {\n config.set(\"activeWorkspaceId\", id);\n config.set(\"activeWorkspaceName\", name);\n}\n\nexport function getActiveWorkspace(): {\n id: string | null;\n name: string | null;\n} {\n return {\n id: config.get(\"activeWorkspaceId\"),\n name: config.get(\"activeWorkspaceName\"),\n };\n}\n\nexport function setServerUrl(url: string): void {\n config.set(\"serverUrl\", url);\n}\n\nexport function clearAll(): void {\n config.clear();\n}\n\nexport function getConfigPath(): string {\n return config.path;\n}\n\n// --- GitHub Token Management ---\n\nexport interface GithubTokens {\n accessToken: string;\n refreshToken?: string;\n expiresAt: number; // epoch seconds\n}\n\nexport function setGithubTokens(tokens: GithubTokens): void {\n const creds = getCredentials();\n if (!creds) return;\n\n creds.githubAccessToken = tokens.accessToken;\n creds.githubRefreshToken = tokens.refreshToken;\n creds.githubExpiresAt = tokens.expiresAt;\n\n setCredentials(creds);\n}\n\nexport function getGithubTokens(): GithubTokens | null {\n const creds = getCredentials();\n if (!creds?.githubAccessToken || !creds.githubExpiresAt) return null;\n\n return {\n accessToken: creds.githubAccessToken,\n refreshToken: creds.githubRefreshToken,\n expiresAt: creds.githubExpiresAt,\n };\n}\n\nexport function getValidGithubToken(): string | null {\n const tokens = getGithubTokens();\n if (!tokens) return null;\n\n const now = Math.floor(Date.now() / 1000);\n\n // Consider expired if within 60 seconds of expiry\n if (tokens.expiresAt <= now + 60) return null;\n\n return tokens.accessToken;\n}\n\nexport function hasGithubToken(): boolean {\n return getValidGithubToken() !== null;\n}\n","/**\n * Orkestrate CLI — OAuth Authentication\n *\n * Implements OAuth 2.0 + PKCE flow with two providers:\n * 1. Orkestrate OAuth — identity (openid, profile, email, mcp scopes)\n * 2. GitHub OAuth — repo access (required for workspace creation)\n *\n * Flow:\n * 1. Orkestrate OAuth → Orkestrate identity tokens\n * 2. GitHub OAuth (via Orkestrate proxy) → GitHub access tokens\n * 3. Both stored locally in ~/.config/orkestrate/\n */\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport {\n createServer,\n type IncomingMessage,\n type ServerResponse,\n} from \"node:http\";\nimport {\n getServerUrl,\n setCredentials,\n getCredentials,\n setGithubTokens,\n type StoredCredentials,\n} from \"./config.js\";\n\n// ─── PKCE Helpers ──────────────────────────────────────────────────────────────\n\nfunction randomToken(bytes = 32): string {\n return randomBytes(bytes).toString(\"base64url\");\n}\n\nfunction pkceS256(verifier: string): string {\n return createHash(\"sha256\").update(verifier).digest(\"base64url\");\n}\n\n// ─── Token Types ───────────────────────────────────────────────────────────────\n\ninterface TokenResponse {\n token_type: string;\n access_token: string;\n expires_in: number;\n refresh_token: string;\n scope: string;\n id_token?: string;\n}\n\n// ─── Dynamic Client Registration ───────────────────────────────────────────────\n\nasync function registerClient(\n serverUrl: string,\n redirectUri: string,\n): Promise<{ clientId: string }> {\n const res = await fetch(`${serverUrl}/api/oauth/register`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n client_name: \"Orkestrate CLI\",\n redirect_uris: [redirectUri],\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\",\n }),\n });\n\n if (!res.ok) {\n const body = await res.text();\n throw new Error(`Client registration failed (${res.status}): ${body}`);\n }\n\n const data = (await res.json()) as { client_id: string };\n return { clientId: data.client_id };\n}\n\n// ─── Callback Server ───────────────────────────────────────────────────────────\n\nfunction waitForCallback(\n port: number,\n): Promise<{ code: string; state: string }> {\n return new Promise((resolve, reject) => {\n let timeoutHandle: ReturnType<typeof setTimeout>;\n\n function cleanup() {\n clearTimeout(timeoutHandle);\n server.close();\n }\n\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url || \"/\", `http://localhost:${port}`);\n\n if (url.pathname !== \"/callback\") {\n res.writeHead(404);\n res.end(\"Not found\");\n return;\n }\n\n const code = url.searchParams.get(\"code\");\n const error = url.searchParams.get(\"error\");\n const state = url.searchParams.get(\"state\") || \"\";\n\n if (error) {\n const description = url.searchParams.get(\"error_description\") || error;\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(buildErrorPage(description));\n cleanup();\n reject(new Error(`OAuth error: ${description}`));\n return;\n }\n\n if (!code) {\n res.writeHead(400, { \"Content-Type\": \"text/html\" });\n res.end(buildErrorPage(\"No authorization code received.\"));\n cleanup();\n reject(new Error(\"No authorization code received\"));\n return;\n }\n\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(buildSuccessPage());\n cleanup();\n resolve({ code, state });\n });\n\n server.listen(port, \"127.0.0.1\", () => {\n // ready\n });\n\n server.on(\"error\", (err: Error) => {\n clearTimeout(timeoutHandle);\n reject(new Error(`Could not start local server: ${err.message}`));\n });\n\n // 5-minute timeout — unref so it doesn't block process exit\n timeoutHandle = setTimeout(\n () => {\n server.close();\n reject(\n new Error(\"Authentication timed out (5 minutes). Please try again.\"),\n );\n },\n 5 * 60 * 1000,\n );\n timeoutHandle.unref();\n });\n}\n\n// ─── Token Exchange ────────────────────────────────────────────────────────────\n\nasync function exchangeCodeForTokens(\n serverUrl: string,\n code: string,\n clientId: string,\n codeVerifier: string,\n redirectUri: string,\n): Promise<TokenResponse> {\n const body = new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n code_verifier: codeVerifier,\n client_id: clientId,\n redirect_uri: redirectUri,\n });\n\n const res = await fetch(`${serverUrl}/api/oauth/token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Token exchange failed (${res.status}): ${text}`);\n }\n\n const data = (await res.json()) as TokenResponse;\n if (process.env.DEBUG) {\n console.error(\n `[DEBUG] Orkestrate Token: ${data.access_token?.slice(0, 5)}...`,\n );\n }\n return data;\n}\n\n// ─── GitHub OAuth (proxied through Orkestrate backend, device flow) ────────────\n\ninterface GithubDeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n expires_in: number;\n interval: number;\n}\n\ninterface GithubTokenPollResponse {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n error?: string;\n error_description?: string;\n}\n\n/**\n * Start GitHub's Device Flow via Orkestrate proxy.\n * Returns device code + user code for the user to enter at verification_uri.\n */\nasync function startGithubDeviceFlow(\n serverUrl: string,\n accessToken: string,\n): Promise<GithubDeviceCodeResponse> {\n const res = await fetch(`${serverUrl}/api/oauth/github/auth-url`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(\n `Failed to start GitHub device flow (${res.status}): ${text}`,\n );\n }\n\n return (await res.json()) as GithubDeviceCodeResponse;\n}\n\n/**\n * Poll Orkestrate (which proxies to GitHub) for the GitHub token.\n * Returns null while authorization is still pending.\n * Throws on error or expired code.\n */\nasync function pollGithubToken(\n serverUrl: string,\n accessToken: string,\n userId: string,\n deviceCode: string,\n intervalSeconds: number,\n): Promise<{\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n}> {\n // Add a small buffer to the interval to avoid hitting rate limits\n const pollInterval = (intervalSeconds + 1) * 1000;\n\n while (true) {\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n\n const res = await fetch(`${serverUrl}/api/oauth/github/token`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ device_code: deviceCode, user_id: userId }),\n });\n\n const data = (await res.json()) as GithubTokenPollResponse;\n\n // Still pending — keep polling\n if (data.error === \"authorization_pending\" || data.error === \"slow_down\") {\n continue;\n }\n\n if (data.error) {\n throw new Error(\n `GitHub authorization failed: ${data.error_description || data.error}`,\n );\n }\n\n if (!data.access_token) {\n throw new Error(\"GitHub returned no access token\");\n }\n\n return {\n access_token: data.access_token,\n refresh_token: data.refresh_token,\n expires_in: data.expires_in ?? 3600,\n };\n }\n}\n\n// ─── Token Refresh ─────────────────────────────────────────────────────────────\n\n/**\n * Refresh the Orkestrate access token using the stored refresh token.\n */\nexport async function refreshAccessToken(): Promise<StoredCredentials | null> {\n const creds = getCredentials();\n if (!creds?.refreshToken) return null;\n\n const serverUrl = getServerUrl();\n const body = new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: creds.refreshToken,\n client_id: creds.clientId,\n });\n\n const res = await fetch(`${serverUrl}/api/oauth/token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) return null;\n\n const tokens = (await res.json()) as TokenResponse;\n const now = Math.floor(Date.now() / 1000);\n\n const newCreds: StoredCredentials = {\n clientId: creds.clientId,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: now + tokens.expires_in,\n userId: creds.userId,\n scope: tokens.scope,\n githubAccessToken: creds.githubAccessToken,\n githubRefreshToken: creds.githubRefreshToken,\n githubExpiresAt: creds.githubExpiresAt,\n };\n\n setCredentials(newCreds);\n return newCreds;\n}\n\n/**\n * Get a valid (non-expired) Orkestrate access token.\n * Automatically refreshes if within 60 seconds of expiry.\n */\nexport async function getValidToken(): Promise<string | null> {\n const creds = getCredentials();\n if (!creds) return null;\n\n const now = Math.floor(Date.now() / 1000);\n\n if (creds.expiresAt <= now + 60) {\n const refreshed = await refreshAccessToken();\n return refreshed?.accessToken || null;\n }\n\n return creds.accessToken;\n}\n\n// ─── Main Login Flow ──────────────────────────────────────────────────────────\n\n/**\n * Run the full Orkestrate + GitHub OAuth login flow.\n *\n * Phase 1: Orkestrate OAuth → identity (stored locally)\n * Phase 2: GitHub OAuth → repo access (proxied through Orkestrate backend)\n *\n * GitHub is best-effort — if it fails, login still succeeds but\n * workspace creation won't work until GitHub is re-connected.\n */\nexport async function performLogin(): Promise<{\n clientId: string;\n userId: string;\n accessToken: string;\n githubConnected: boolean;\n}> {\n const serverUrl = getServerUrl();\n const port = 19274; // \"ork\" on phone keypad, roughly\n const redirectUri = `http://127.0.0.1:${port}/callback`;\n\n // ── Phase 1: Orkestrate OAuth ──────────────────────────────────────────────\n\n const { clientId } = await registerClient(serverUrl, redirectUri);\n\n const codeVerifier = randomToken(48);\n const codeChallenge = pkceS256(codeVerifier);\n const state = randomToken(16);\n\n const authUrl = new URL(`${serverUrl}/api/oauth/authorize`);\n authUrl.searchParams.set(\"response_type\", \"code\");\n authUrl.searchParams.set(\"client_id\", clientId);\n authUrl.searchParams.set(\"redirect_uri\", redirectUri);\n authUrl.searchParams.set(\"code_challenge\", codeChallenge);\n authUrl.searchParams.set(\"code_challenge_method\", \"S256\");\n authUrl.searchParams.set(\"scope\", \"openid profile email mcp:read mcp:write\");\n authUrl.searchParams.set(\"state\", state);\n\n const callbackPromise = waitForCallback(port);\n\n const { default: openBrowser } = await import(\"open\");\n await openBrowser(authUrl.toString());\n\n const { code, state: returnedState } = await callbackPromise;\n\n if (returnedState !== state) {\n throw new Error(\n \"Orkestrate OAuth state mismatch — possible CSRF attack. Aborting.\",\n );\n }\n\n const tokens = await exchangeCodeForTokens(\n serverUrl,\n code,\n clientId,\n codeVerifier,\n redirectUri,\n );\n\n // Resolve userId\n let userId = \"\";\n try {\n const meRes = await fetch(`${serverUrl}/api/auth/me`, {\n headers: { Authorization: `Bearer ${tokens.access_token}` },\n });\n if (meRes.ok) {\n const me = (await meRes.json()) as { id?: string };\n userId = me.id || \"\";\n }\n } catch {\n // Non-fatal\n }\n\n const credentials: StoredCredentials = {\n clientId,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: Math.floor(Date.now() / 1000) + tokens.expires_in,\n userId,\n scope: tokens.scope,\n };\n\n setCredentials(credentials);\n\n // ── Phase 2: GitHub OAuth (Device Flow) ───────────────────────────────────\n\n let githubConnected = false;\n\n try {\n // Start GitHub device flow via Orkestrate proxy\n const deviceData = await startGithubDeviceFlow(\n serverUrl,\n tokens.access_token,\n );\n\n // Display user code and instructions\n console.error();\n console.error(\" GitHub Device Authorization\");\n console.error();\n console.error(` 1. Open: ${deviceData.verification_uri}`);\n console.error(` 2. Enter: ${deviceData.user_code}`);\n console.error();\n console.error(\" Waiting for authorization... (press Ctrl+C to cancel)\");\n\n // Poll until user completes GitHub authorization\n const githubTokens = await pollGithubToken(\n serverUrl,\n tokens.access_token,\n userId,\n deviceData.device_code,\n deviceData.interval,\n );\n\n setGithubTokens({\n accessToken: githubTokens.access_token,\n refreshToken: githubTokens.refresh_token,\n expiresAt:\n Math.floor(Date.now() / 1000) + (githubTokens.expires_in ?? 3600),\n });\n\n githubConnected = true;\n } catch (err) {\n // Best-effort — warn but don't fail the login\n console.error(\n `[Login] GitHub connection failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n console.error(\"[Login] Workspace creation requires GitHub access.\");\n console.error(\n \"[Login] Re-run \\`orkestrate login --github\\` to connect GitHub later.\",\n );\n }\n\n return {\n clientId,\n userId: credentials.userId,\n accessToken: credentials.accessToken,\n githubConnected,\n };\n}\n\n// ─── HTML Pages ───────────────────────────────────────────────────────────────\n\nfunction buildSuccessPage(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>Orkestrate — Authenticated</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .card {\n text-align: center;\n padding: 3rem;\n border: 1px solid #262626;\n border-radius: 12px;\n background: #111;\n max-width: 420px;\n }\n .icon { font-size: 3rem; margin-bottom: 1rem; }\n h1 { font-size: 1.5rem; margin-bottom: 0.5rem; color: #fff; }\n p { color: #a3a3a3; line-height: 1.6; }\n .hint { margin-top: 1.5rem; font-size: 0.85rem; color: #525252; }\n </style>\n</head>\n<body>\n <div class=\"card\">\n <div class=\"icon\">✓</div>\n <h1>Authenticated</h1>\n <p>You're now logged in to Orkestrate. You can close this tab and return to your terminal.</p>\n <p class=\"hint\">This window will close automatically.</p>\n </div>\n <script>setTimeout(() => window.close(), 3000);</script>\n</body>\n</html>`;\n}\n\nfunction buildErrorPage(message: string): string {\n const escaped = message.replace(/</g, \"<\").replace(/>/g, \">\");\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>Orkestrate — Error</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .card {\n text-align: center;\n padding: 3rem;\n border: 1px solid #371717;\n border-radius: 12px;\n background: #1a0a0a;\n max-width: 420px;\n }\n .icon { font-size: 3rem; margin-bottom: 1rem; }\n h1 { font-size: 1.5rem; margin-bottom: 0.5rem; color: #fca5a5; }\n p { color: #a3a3a3; line-height: 1.6; }\n </style>\n</head>\n<body>\n <div class=\"card\">\n <div class=\"icon\">✗</div>\n <h1>Authentication Failed</h1>\n <p>${escaped}</p>\n </div>\n</body>\n</html>`;\n}\n","/**\n * orkestrate login\n *\n * Authenticate with Orkestrate via Orkestrate OAuth + GitHub OAuth.\n * Both are required: Orkestrate for identity, GitHub for workspace creation.\n */\n\nimport { performLogin } from \"../lib/auth.js\";\nimport { getCredentials, getConfigPath } from \"../lib/config.js\";\nimport { ui } from \"../lib/ui.js\";\n\nexport async function loginCommand(): Promise<void> {\n const existing = getCredentials();\n if (existing?.accessToken) {\n ui.dim(\"Refreshing existing session...\");\n }\n\n ui.info(\"Opening browser for Orkestrate authentication...\");\n ui.blank();\n\n try {\n const result = await performLogin();\n ui.blank();\n\n ui.success(\"Logged in to Orkestrate!\");\n\n if (result.githubConnected) {\n ui.success(\"GitHub connected.\");\n } else {\n ui.warn(\n \"GitHub not connected — workspace creation will require GitHub access.\",\n );\n }\n\n ui.blank();\n ui.info(\"Next steps:\");\n ui.line(\n \" 1. orkestrate init — link your project to a workspace\",\n );\n ui.line(\n \" 2. orkestrate connect <tool> — configure your AI tool (claude, opencode, etc.)\",\n );\n ui.line(\n \" 3. Run your AI tool — your agent starts and joins the workspace\",\n );\n ui.line(\" 4. In your AI tool, call: join_workspace <workspace_id>\");\n ui.blank();\n ui.dim(`Credentials stored at: ${getConfigPath()}`);\n } catch (err) {\n ui.error(\n `Login failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n process.exit(1);\n }\n}\n","/**\n * orkestrate logout\n *\n * Clear stored credentials.\n */\n\nimport { clearCredentials, getCredentials, getConfigPath } from \"../lib/config.js\";\nimport { ui } from \"../lib/ui.js\";\n\nexport function logoutCommand(): void {\n const existing = getCredentials();\n\n if (!existing?.accessToken) {\n ui.dim(\"Not currently logged in.\");\n return;\n }\n\n clearCredentials();\n ui.success(\"Logged out. Credentials cleared.\");\n ui.dim(`Config: ${getConfigPath()}`);\n}\n","/**\n * Orkestrate CLI — Tool Detection & MCP Configuration\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport { getServerUrl } from \"./config.js\";\n\nexport type ToolName = \"claude\" | \"opencode\" | \"cursor\" | \"windsurf\" | \"codex\";\n\nexport interface DetectedTool {\n name: ToolName;\n displayName: string;\n detected: boolean;\n configPath?: string;\n}\n\n/**\n * Detect which AI coding tools are available on this system.\n */\nexport function detectTools(projectDir: string = process.cwd()): DetectedTool[] {\n const tools: DetectedTool[] = [];\n\n // Claude Code\n tools.push({\n name: \"claude\",\n displayName: \"Claude Code\",\n detected: isCommandAvailable(\"claude\"),\n });\n\n // OpenCode\n const opencodeConfig = join(projectDir, \"opencode.json\");\n tools.push({\n name: \"opencode\",\n displayName: \"OpenCode\",\n detected: existsSync(opencodeConfig) || isCommandAvailable(\"opencode\"),\n configPath: opencodeConfig,\n });\n\n // Cursor\n const cursorConfig = join(projectDir, \".cursor\", \"mcp.json\");\n tools.push({\n name: \"cursor\",\n displayName: \"Cursor\",\n detected: existsSync(join(projectDir, \".cursor\")) || existsSync(cursorConfig),\n configPath: cursorConfig,\n });\n\n // Windsurf\n const windsurfConfig = join(projectDir, \".windsurf\", \"mcp.json\");\n tools.push({\n name: \"windsurf\",\n displayName: \"Windsurf\",\n detected: existsSync(join(projectDir, \".windsurf\")) || existsSync(windsurfConfig),\n configPath: windsurfConfig,\n });\n\n // Codex\n const codexDir = join(homedir(), \".codex\");\n tools.push({\n name: \"codex\",\n displayName: \"Codex CLI\",\n detected: isCommandAvailable(\"codex\") || existsSync(codexDir),\n });\n\n return tools;\n}\n\n/**\n * Configure MCP for a specific tool.\n */\nexport async function configureTool(\n tool: ToolName,\n projectDir: string = process.cwd(),\n): Promise<{ success: boolean; message: string }> {\n const bridge = resolveMcpBridge();\n const mcpUrl = `${getServerUrl()}/api/mcp`;\n\n switch (tool) {\n case \"claude\":\n return configureClaudeCode(bridge);\n case \"opencode\":\n return configureOpenCode(join(projectDir, \"opencode.json\"), bridge);\n case \"cursor\":\n return configureMcpServersJson(\"Cursor\", join(projectDir, \".cursor\", \"mcp.json\"), bridge);\n case \"windsurf\":\n return configureMcpServersJson(\"Windsurf\", join(projectDir, \".windsurf\", \"mcp.json\"), bridge);\n case \"codex\":\n return configureCodex(bridge);\n default:\n return { success: false, message: `Unknown tool: ${tool}` };\n }\n}\n\n/**\n * Resolves the global command to run the Orkestrate MCP bridge.\n */\nfunction resolveMcpBridge(): { command: string, args: string[] } {\n return {\n command: \"orkestrate\",\n args: [\"mcp\"]\n };\n}\n\n// ──────────────────────────────────────────────\n// Tool Specific Configs (Global Command standard)\n// ──────────────────────────────────────────────\n\nfunction configureClaudeCode(bridge: { command: string, args: string[] }): { success: boolean; message: string } {\n if (!isCommandAvailable(\"claude\")) return { success: false, message: \"Claude Code CLI not found.\" };\n\n try {\n // Attempt to remove existing first (idempotency)\n try {\n execSync(\"claude mcp remove Orkestrate\", { stdio: \"pipe\" });\n } catch { /* ignore if not exists */ }\n\n // Claude expects: claude mcp add <name> <command> [args...]\n // We pass the command and args as separate tokens\n const commandToRun = bridge.command;\n const argsToRun = bridge.args.join(\" \");\n \n execSync(\n `claude mcp add --transport stdio --scope project Orkestrate ${commandToRun} ${argsToRun}`,\n { stdio: \"pipe\", encoding: \"utf-8\" },\n );\n return { success: true, message: \"MCP added to Claude Code.\" };\n } catch (err) {\n return { success: false, message: `Claude config failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n}\n\nfunction configureOpenCode(configPath: string, bridge: { command: string, args: string[] }): { success: boolean; message: string } {\n try {\n let config = existsSync(configPath) ? JSON.parse(readFileSync(configPath, \"utf-8\")) : {};\n if (!config.mcp || typeof config.mcp !== \"object\") config.mcp = {};\n\n config.mcp[\"Orkestrate\"] = {\n type: \"local\",\n command: [bridge.command, ...bridge.args],\n enabled: true\n };\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n return { success: true, message: `Configured OpenCode at ${configPath}` };\n } catch (err) {\n return { success: false, message: `OpenCode config failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n}\n\nfunction configureMcpServersJson(displayName: string, configPath: string, bridge: { command: string, args: string[] }): { success: boolean; message: string } {\n try {\n const dir = join(configPath, \"..\");\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n\n let config = existsSync(configPath) ? JSON.parse(readFileSync(configPath, \"utf-8\")) : {};\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") config.mcpServers = {};\n\n config.mcpServers[\"Orkestrate\"] = {\n command: bridge.command,\n args: bridge.args\n };\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n return { success: true, message: `Configured ${displayName} at ${configPath}` };\n } catch (err) {\n return { success: false, message: `${displayName} config failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n}\n\nfunction configureCodex(bridge: { command: string, args: string[] }): { success: boolean; message: string } {\n const home = homedir();\n const codexDir = join(home, \".codex\");\n const configPath = join(codexDir, \"config.toml\");\n\n try {\n if (!existsSync(codexDir)) mkdirSync(codexDir, { recursive: true });\n\n let content = existsSync(configPath) ? readFileSync(configPath, \"utf-8\") : \"[mcp_servers]\\n\";\n const proxySection = `[mcp_servers.Orkestrate]\\ncommand = \"${bridge.command}\"\\nargs = [${bridge.args.map(a => `\"${a}\"`).join(\", \")}]\\n`;\n\n const sectionRegex = /\\[mcp_servers\\.Orkestrate\\]\\s*\\n(?:(?!\\[)[^\\n]*\\n?)*/;\n if (sectionRegex.test(content)) {\n content = content.replace(sectionRegex, proxySection);\n } else {\n const mcpServersIdx = content.indexOf(\"[mcp_servers]\");\n if (mcpServersIdx !== -1) {\n const lineEnd = content.indexOf(\"\\n\", mcpServersIdx);\n const insertPos = lineEnd !== -1 ? lineEnd + 1 : content.length;\n content = content.slice(0, insertPos) + \"\\n\" + proxySection + content.slice(insertPos);\n } else {\n content = content.trimEnd() + \"\\n\\n[mcp_servers]\\n\\n\" + proxySection;\n }\n }\n\n writeFileSync(configPath, content, \"utf-8\");\n return { success: true, message: `Configured Codex.` };\n } catch (err) {\n return { success: false, message: `Codex config failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n}\n\nfunction isCommandAvailable(command: string): boolean {\n try {\n const isWindows = process.platform === \"win32\";\n const checkCmd = isWindows ? `where ${command}` : `which ${command}`;\n execSync(checkCmd, { stdio: \"pipe\" });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function getToolNames(): ToolName[] {\n return [\"claude\", \"opencode\", \"cursor\", \"windsurf\", \"codex\"];\n}\n","/**\n * orkestrate connect [tool]\n *\n * Configure Orkestrate MCP for any AI coding tool.\n *\n * With a tool name: auto-configure supported tools (claude, opencode, etc.)\n * Without a tool name: show detected tools + generic MCP setup instructions\n */\n\nimport { getCredentials, getServerUrl } from \"../lib/config.js\";\nimport { configureTool, detectTools, type ToolName } from \"../lib/detect.js\";\nimport { ui } from \"../lib/ui.js\";\n\nconst SUPPORTED_AUTO_CONFIG: ToolName[] = [\n \"claude\",\n \"opencode\",\n \"cursor\",\n \"windsurf\",\n \"codex\",\n];\n\nexport async function connectCommand(toolName?: string): Promise<void> {\n const creds = getCredentials();\n if (!creds?.accessToken) {\n ui.error(\"Not authenticated. Run `orkestrate login` first.\");\n process.exit(1);\n }\n\n // ── No tool specified: show detection + generic instructions ───────────────\n if (!toolName) {\n ui.header(\"Connect Orkestrate MCP\");\n\n const detected = detectTools();\n const found = detected.filter((t) => t.detected);\n\n if (found.length > 0) {\n ui.info(\"Detected AI tools:\");\n for (const tool of found) {\n ui.success(` ${tool.displayName}`);\n }\n ui.blank();\n }\n\n displayGenericInstructions();\n return;\n }\n\n // ── Generic MCP tool (not in auto-config list) ────────────────────────────\n const normalized = toolName.toLowerCase().trim();\n const isAutoConfig = SUPPORTED_AUTO_CONFIG.includes(normalized as ToolName);\n\n if (!isAutoConfig) {\n ui.header(`Connect ${normalized} to Orkestrate`);\n ui.blank();\n ui.info(\"Orkestrate MCP endpoint:\");\n ui.line(` ${getServerUrl()}/api/mcp`);\n ui.blank();\n\n displayGenericInstructions();\n\n ui.blank();\n ui.info(\n `To configure ${normalized} with Orkestrate MCP, add it as a stdio MCP server.`,\n );\n ui.dim(\n `Restart ${normalized} after configuring MCP for changes to take effect.`,\n );\n return;\n }\n\n // ── Auto-configure supported tool ──────────────────────────────────────────\n ui.info(`Configuring Orkestrate MCP for ${toolName}...`);\n\n const result = await configureTool(normalized as ToolName);\n\n if (result.success) {\n ui.success(result.message);\n ui.blank();\n ui.info(\"Your AI tool is now connected to Orkestrate.\");\n ui.dim(\"Restart your tool if it's currently running.\");\n } else {\n ui.error(result.message);\n process.exit(1);\n }\n}\n\nfunction displayGenericInstructions(): void {\n const mcpUrl = `${getServerUrl()}/api/mcp`;\n const bridgeCommand = \"orkestrate\";\n const bridgeArgs = \"mcp\";\n\n ui.info(\"Generic MCP Setup (for any tool that supports stdio MCP):\");\n ui.blank();\n\n ui.line(\" Add Orkestrate as an MCP server with:\");\n ui.blank();\n ui.line(` Command: ${bridgeCommand}`);\n ui.line(` Args: ${bridgeArgs}`);\n ui.blank();\n\n ui.dim(\" Tool-specific setup:\");\n\n ui.blank();\n ui.line(\" Claude Code:\");\n ui.line(\n ` claude mcp add --transport stdio Orkestrate ${bridgeCommand} ${bridgeArgs}`,\n );\n\n ui.blank();\n ui.line(\" Cursor:\");\n ui.line(\" Settings → MCP → Add new server:\");\n ui.line(` Name: Orkestrate`);\n ui.line(` Command: ${bridgeCommand}`);\n ui.line(` Args: ${bridgeArgs}`);\n\n ui.blank();\n ui.line(\" Windsurf:\");\n ui.line(\" Settings → MCP → Add server:\");\n ui.line(` Command: ${bridgeCommand}`);\n ui.line(` Args: ${bridgeArgs}`);\n\n ui.blank();\n ui.line(\" OpenCode:\");\n ui.line(\" Add to opencode.json mcp servers:\");\n\n ui.blank();\n ui.line(\" Codex:\");\n ui.line(` Add to ~/.codex/config.toml:`);\n ui.line(` [mcp_servers.Orkestrate]`);\n ui.line(` command = \"${bridgeCommand}\"`);\n ui.line(` args = [\"${bridgeArgs}\"]`);\n\n ui.blank();\n ui.dim(\n \" Not sure if your tool supports MCP? Check its docs for 'MCP server'.\",\n );\n}\n","/**\n * Orkestrate CLI — API Client\n *\n * Authenticated HTTP client for the Orkestrate web API.\n * All requests use the stored OAuth bearer token.\n */\n\nimport { getServerUrl } from \"./config.js\";\nimport { getValidToken } from \"./auth.js\";\n\nexport class ApiError extends Error {\n constructor(\n public status: number,\n message: string,\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\nasync function authHeaders(): Promise<Record<string, string>> {\n const token = await getValidToken();\n if (!token) {\n throw new ApiError(401, \"Not authenticated. Run `orkestrate login` first.\");\n }\n return {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n };\n}\n\nasync function request<T>(\n method: string,\n path: string,\n body?: unknown,\n): Promise<T> {\n const serverUrl = getServerUrl();\n const headers = await authHeaders();\n\n // Debug (masked token)\n const token = headers[\"Authorization\"]?.split(\" \")[1] || \"\";\n const maskedToken = token.length > 10 ? `${token.slice(0, 5)}...${token.slice(-5)}` : \"***\";\n \n if (process.env.DEBUG) {\n console.error(`[DEBUG] API Request: ${method} ${serverUrl}${path}`);\n console.error(`[DEBUG] Token: ${maskedToken} (len: ${token.length})`);\n }\n\n const res = await fetch(`${serverUrl}${path}`, {\n method,\n headers: {\n ...headers,\n \"Accept\": \"application/json\",\n \"User-Agent\": \"Orkestrate-CLI-v1\",\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new ApiError(res.status, `API error (${res.status}): ${text}`);\n }\n\n return (await res.json()) as T;\n}\n\n// --- User API ---\n\nexport interface UserInfo {\n id: string;\n email: string;\n}\n\nexport async function getMe(): Promise<UserInfo> {\n const data = await request<{ user: UserInfo }>(\"GET\", \"/api/auth/me\");\n return data.user;\n}\n\n// --- Workspace API ---\n\nexport interface Workspace {\n id: string;\n name: string;\n ownerId: string;\n repoUrl: string | null;\n defaultBranch: string | null;\n isActive: boolean;\n createdAt: string;\n}\n\nexport async function listWorkspaces(): Promise<Workspace[]> {\n const data = await request<{ workspaces: Workspace[] }>(\"GET\", \"/api/workspaces\");\n return data.workspaces || [];\n}\n\nexport async function switchWorkspace(workspaceId: string): Promise<void> {\n await request(\"POST\", \"/api/workspaces\", {\n action: \"switch\",\n workspaceId,\n });\n}\n\nexport async function createWorkspace(\n name: string,\n repoUrl: string,\n defaultBranch: string,\n): Promise<Workspace> {\n const data = await request<{ workspace: Workspace }>(\"POST\", \"/api/workspaces\", {\n action: \"create\",\n name,\n repoUrl,\n defaultBranch,\n });\n return data.workspace;\n}\n\n// --- Agent Status API ---\n\nexport interface AgentState {\n scopedAgentId: string;\n agentId: string;\n toolName: string | null;\n status: string;\n objective: string;\n claimedPaths: string[];\n plan: string[];\n notes: string;\n updatedAt: string;\n}\n\nexport async function getTeamStatus(): Promise<{\n agents: AgentState[];\n stateHash: string;\n}> {\n // Use the MCP endpoint with a read_team_state RPC call\n const serverUrl = getServerUrl();\n const token = await getValidToken();\n if (!token) {\n throw new ApiError(401, \"Not authenticated. Run `orkestrate login` first.\");\n }\n\n const res = await fetch(`${serverUrl}/api/mcp`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"tools/call\",\n params: {\n name: \"read_team_state\",\n arguments: {},\n },\n }),\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new ApiError(res.status, `MCP error (${res.status}): ${text}`);\n }\n\n const rpcResult = (await res.json()) as any;\n\n // Parse the MCP response to extract team state\n if (rpcResult.error) {\n throw new ApiError(400, rpcResult.error.message || \"MCP call failed\");\n }\n\n const content = rpcResult.result?.content || [];\n const textContent = content\n .filter((c: { type: string }) => c.type === \"text\")\n .map((c: { text: string }) => c.text)\n .join(\"\\n\");\n\n try {\n const parsed = JSON.parse(textContent);\n return {\n agents: parsed.agents || parsed.states || [],\n stateHash: parsed.stateHash || \"\",\n };\n } catch {\n return { agents: [], stateHash: \"\" };\n }\n}\n\n// --- Health Check ---\n\nexport async function checkHealth(): Promise<boolean> {\n const serverUrl = getServerUrl();\n try {\n const res = await fetch(`${serverUrl}/api/health`, { method: \"GET\" });\n return res.ok;\n } catch {\n return false;\n }\n}\n","/**\n * orkestrate status\n *\n * Display current team coordination state in the terminal.\n */\n\nimport { getCredentials, getActiveWorkspace } from \"../lib/config.js\";\nimport { getTeamStatus, listWorkspaces, checkHealth } from \"../lib/api.js\";\nimport { ui } from \"../lib/ui.js\";\n\nexport async function statusCommand(): Promise<void> {\n const creds = getCredentials();\n if (!creds?.accessToken) {\n ui.error(\"Not authenticated. Run `orkestrate login` first.\");\n process.exit(1);\n }\n\n // Check server health\n const healthy = await checkHealth();\n if (!healthy) {\n ui.error(\"Cannot reach Orkestrate server. Check your connection.\");\n process.exit(1);\n }\n\n const workspace = getActiveWorkspace();\n\n ui.header(\"Orkestrate Status\");\n\n // Show workspace info\n if (workspace.name) {\n ui.kv(\"Workspace\", workspace.name);\n }\n if (workspace.id) {\n ui.kv(\"ID\", workspace.id);\n }\n ui.blank();\n\n try {\n const { agents, stateHash } = await getTeamStatus();\n\n if (agents.length === 0) {\n ui.dim(\"No active agents in this workspace.\");\n ui.blank();\n ui.info(\"Connect an agent with `orkestrate connect <tool>` to get started.\");\n return;\n }\n\n // Build table\n const rows = agents.map((agent) => [\n agent.agentId || agent.scopedAgentId,\n agent.toolName || \"—\",\n agent.status,\n truncate(agent.objective, 35),\n ]);\n\n ui.table(\n [\"Agent\", \"Tool\", \"Status\", \"Objective\"],\n rows,\n );\n\n // Show claimed paths summary\n const agentsWithClaims = agents.filter(\n (a) => a.claimedPaths && a.claimedPaths.length > 0,\n );\n if (agentsWithClaims.length > 0) {\n ui.blank();\n ui.line(pc_bold(\"Active Scope Claims:\"));\n for (const agent of agentsWithClaims) {\n ui.line(` ${agent.agentId}: ${agent.claimedPaths.join(\", \")}`);\n }\n }\n\n ui.blank();\n ui.dim(`State hash: ${stateHash}`);\n ui.dim(`${agents.length} agent(s) connected`);\n } catch (err) {\n ui.error(\n `Failed to fetch status: ${err instanceof Error ? err.message : String(err)}`,\n );\n process.exit(1);\n }\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s;\n return s.slice(0, max - 1) + \"…\";\n}\n\n// Inline bold since we don't want to import picocolors at top level just for one use\nfunction pc_bold(s: string): string {\n return `\\x1b[1m${s}\\x1b[22m`;\n}\n","/**\n * orkestrate workspace [list|switch|create]\n *\n * Manage workspaces from the CLI.\n */\n\nimport { getCredentials, setActiveWorkspace, getActiveWorkspace } from \"../lib/config.js\";\nimport {\n listWorkspaces,\n switchWorkspace as apiSwitchWorkspace,\n createWorkspace as apiCreateWorkspace,\n} from \"../lib/api.js\";\nimport { ui } from \"../lib/ui.js\";\n\nexport async function workspaceCommand(\n action?: string,\n nameOrId?: string,\n extra?: string,\n): Promise<void> {\n const creds = getCredentials();\n if (!creds?.accessToken) {\n ui.error(\"Not authenticated. Run `orkestrate login` first.\");\n process.exit(1);\n }\n\n const subcommand = (action || \"list\").toLowerCase();\n\n switch (subcommand) {\n case \"list\":\n case \"ls\":\n return workspaceList();\n\n case \"switch\":\n case \"use\":\n if (!nameOrId) {\n ui.error(\"Usage: orkestrate workspace switch <workspace-id-or-name>\");\n process.exit(1);\n }\n return workspaceSwitch(nameOrId);\n\n case \"create\":\n case \"new\":\n if (!nameOrId) {\n ui.error(\"Usage: orkestrate workspace create <name> <repo-url> [branch]\");\n process.exit(1);\n }\n return workspaceCreate(nameOrId, extra);\n\n default:\n ui.error(`Unknown subcommand: ${action}`);\n ui.blank();\n ui.info(\"Available subcommands:\");\n ui.line(\" list — Show all workspaces\");\n ui.line(\" switch — Switch active workspace\");\n ui.line(\" create — Create a new workspace\");\n process.exit(1);\n }\n}\n\nasync function workspaceList(): Promise<void> {\n ui.header(\"Workspaces\");\n\n try {\n const workspaces = await listWorkspaces();\n const active = getActiveWorkspace();\n\n if (workspaces.length === 0) {\n ui.dim(\"No workspaces found.\");\n ui.info(\"Create one at orkestrate.space or run `orkestrate workspace create`.\");\n return;\n }\n\n for (const ws of workspaces) {\n const isActive = ws.id === active.id || ws.isActive;\n const marker = isActive ? \" ← active\" : \"\";\n const name = ws.name || \"Unnamed\";\n\n if (isActive) {\n ui.success(`${name} (${ws.id})${marker}`);\n } else {\n ui.line(` ${name} (${ws.id})`);\n }\n\n if (ws.repoUrl) {\n ui.dim(` repo: ${ws.repoUrl}`);\n }\n }\n\n ui.blank();\n ui.dim(`${workspaces.length} workspace(s)`);\n } catch (err) {\n ui.error(`Failed to list workspaces: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n\nasync function workspaceSwitch(nameOrId: string): Promise<void> {\n try {\n const workspaces = await listWorkspaces();\n\n // Find by exact ID or name match\n const target = workspaces.find(\n (ws) =>\n ws.id === nameOrId ||\n ws.name.toLowerCase() === nameOrId.toLowerCase(),\n );\n\n if (!target) {\n ui.error(`Workspace not found: ${nameOrId}`);\n ui.blank();\n ui.info(\"Available workspaces:\");\n for (const ws of workspaces) {\n ui.line(` ${ws.name} (${ws.id})`);\n }\n process.exit(1);\n }\n\n await apiSwitchWorkspace(target.id);\n setActiveWorkspace(target.id, target.name);\n ui.success(`Switched to workspace: ${target.name}`);\n } catch (err) {\n ui.error(`Failed to switch workspace: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n\nasync function workspaceCreate(name: string, repoUrl?: string): Promise<void> {\n if (!repoUrl) {\n ui.error(\"Repository URL is required.\");\n ui.info(\"Usage: orkestrate workspace create <name> <repo-url>\");\n process.exit(1);\n }\n\n try {\n const workspace = await apiCreateWorkspace(name, repoUrl, \"main\");\n setActiveWorkspace(workspace.id, workspace.name || name);\n ui.success(`Created workspace: ${workspace.name || name}`);\n ui.kv(\"ID\", workspace.id);\n ui.kv(\"Repo\", repoUrl);\n } catch (err) {\n ui.error(`Failed to create workspace: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n","/**\n * Orkestrate CLI — Git Context Detection\n *\n * Reads git metadata from the current working directory.\n */\n\nimport { execSync } from \"node:child_process\";\n\nexport interface GitContext {\n remote: string;\n repoRoot: string;\n branch: string;\n headSha: string;\n dirty: boolean;\n collectedAt: string;\n}\n\nfunction git(cmd: string, cwd: string): string {\n try {\n return execSync(`git ${cmd}`, {\n cwd,\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim();\n } catch {\n return \"\";\n }\n}\n\nexport function detectGitContext(cwd: string = process.cwd()): GitContext | null {\n const repoRoot = git(\"rev-parse --show-toplevel\", cwd);\n if (!repoRoot) return null;\n\n const remote = git(\"remote get-url origin\", cwd);\n const branch = git(\"rev-parse --abbrev-ref HEAD\", cwd);\n const headSha = git(\"rev-parse HEAD\", cwd);\n const status = git(\"status --porcelain\", cwd);\n\n return {\n remote: remote || \"\",\n repoRoot,\n branch: branch || \"unknown\",\n headSha: headSha || \"\",\n dirty: status.length > 0,\n collectedAt: new Date().toISOString(),\n };\n}\n","/**\n * orkestrate init\n *\n * Initialize Orkestrate in the current project directory.\n * Detects git context and binds to the matching workspace.\n */\n\nimport { existsSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getCredentials, getActiveWorkspace, setActiveWorkspace } from \"../lib/config.js\";\nimport { detectGitContext } from \"../lib/git.js\";\nimport { listWorkspaces } from \"../lib/api.js\";\nimport { detectTools } from \"../lib/detect.js\";\nimport { ui } from \"../lib/ui.js\";\n\nexport async function initCommand(): Promise<void> {\n const creds = getCredentials();\n if (!creds?.accessToken) {\n ui.error(\"Not authenticated. Run `orkestrate login` first.\");\n process.exit(1);\n }\n\n const cwd = process.cwd();\n\n ui.header(\"Initializing Orkestrate\");\n\n // Step 1: Detect git context\n const git = detectGitContext(cwd);\n if (git) {\n ui.success(`Git repository detected`);\n ui.kv(\"Remote\", git.remote || \"(no remote)\");\n ui.kv(\"Branch\", git.branch);\n ui.kv(\"HEAD\", git.headSha.slice(0, 8));\n ui.kv(\"Dirty\", git.dirty ? \"yes\" : \"clean\");\n } else {\n ui.warn(\"No git repository detected in current directory.\");\n ui.dim(\"Orkestrate works best with a git repository.\");\n }\n\n ui.blank();\n\n // Step 2: Match to workspace\n try {\n const workspaces = await listWorkspaces();\n let matched = false;\n\n if (git?.remote && workspaces.length > 0) {\n // Try to match by repo URL\n const normalizedRemote = normalizeGitUrl(git.remote);\n const match = workspaces.find((ws) => {\n if (!ws.repoUrl) return false;\n return normalizeGitUrl(ws.repoUrl) === normalizedRemote;\n });\n\n if (match) {\n setActiveWorkspace(match.id, match.name);\n ui.success(`Matched to workspace: ${match.name}`);\n ui.kv(\"Workspace ID\", match.id);\n matched = true;\n }\n }\n\n if (!matched) {\n if (git?.remote) {\n const create = await ui.confirm(`No matching workspace found for this repository. Create one?`);\n if (create) {\n const name = await ui.input(\"Workspace name\", git.remote.split(\"/\").pop()?.replace(/\\.git$/, \"\"));\n try {\n const { createWorkspace } = await import(\"../lib/api.js\");\n const workspace = await createWorkspace(name, git.remote, git.branch || \"main\");\n setActiveWorkspace(workspace.id, workspace.name);\n ui.success(`Created and matched to workspace: ${workspace.name}`);\n ui.kv(\"Workspace ID\", workspace.id);\n matched = true;\n } catch (err) {\n ui.error(`Failed to create workspace: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n }\n\n if (!matched) {\n const active = getActiveWorkspace();\n if (active.id) {\n ui.info(`Using current active workspace: ${active.name || active.id}`);\n } else if (workspaces.length > 0) {\n ui.info(\"Available workspaces:\");\n for (const ws of workspaces.slice(0, 5)) {\n ui.line(` • ${ws.name} (${ws.id})`);\n }\n const wsId = await ui.input(\"Enter workspace ID to link (or leave blank)\");\n if (wsId) {\n const selected = workspaces.find(w => w.id === wsId || w.name === wsId);\n if (selected) {\n setActiveWorkspace(selected.id, selected.name);\n ui.success(`Linked to workspace: ${selected.name}`);\n matched = true;\n }\n }\n }\n }\n }\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"401\")) {\n ui.warn(\"Authentication failed (401). Your session may have expired.\");\n ui.info(\"Please run `orkestrate login` to refresh your session.\");\n } else {\n ui.dim(`Could not fetch workspaces: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n ui.blank();\n\n // Step 3: Detect available tools\n const tools = detectTools(cwd);\n const found = tools.filter((t) => t.detected);\n\n if (found.length > 0) {\n ui.info(\"Detected AI tools:\");\n for (const tool of found) {\n ui.line(` • ${tool.displayName}`);\n }\n ui.blank();\n const connect = await ui.confirm(`Would you like to connect ${found[0].displayName} now?`);\n if (connect) {\n const { configureTool } = await import(\"../lib/detect.js\");\n const res = await configureTool(found[0].name, cwd);\n if (res.success) {\n ui.success(res.message);\n } else {\n ui.error(res.message);\n }\n } else {\n ui.info(`You can connect later with \\`orkestrate connect ${found[0].name}\\``);\n }\n } else {\n ui.dim(\"No AI coding tools detected. Install one and run `orkestrate connect <tool>`.\");\n }\n\n // Step 4: Write .orkestrate.json (project marker)\n const configFile = join(cwd, \".orkestrate.json\");\n const activeWs = getActiveWorkspace();\n \n if (!existsSync(configFile)) {\n if (activeWs.id) {\n const projectConfig = {\n $schema: \"https://orkestrate.space/schema/project.json\",\n workspaceId: activeWs.id,\n server: \"https://orkestrate.space\",\n initialized: new Date().toISOString(),\n };\n\n writeFileSync(configFile, JSON.stringify(projectConfig, null, 2) + \"\\n\", \"utf-8\");\n ui.blank();\n ui.success(`Created .orkestrate.json`);\n ui.dim(\"This file identifies your project workspace. It is gitignored by default.\");\n }\n } else {\n // Sync existing config if it has a different WS ID\n try {\n const { readFileSync } = await import(\"node:fs\");\n const existing = JSON.parse(readFileSync(configFile, \"utf-8\"));\n if (activeWs.id && existing.workspaceId !== activeWs.id) {\n existing.workspaceId = activeWs.id;\n writeFileSync(configFile, JSON.stringify(existing, null, 2) + \"\\n\", \"utf-8\");\n ui.success(`Updated .orkestrate.json with workspace ID ${activeWs.id}`);\n }\n } catch {}\n }\n\n ui.blank();\n}\n\n/**\n * Normalize a git remote URL for comparison.\n */\nfunction normalizeGitUrl(url: string): string {\n let normalized = url.trim().toLowerCase();\n normalized = normalized.replace(/\\.git$/, \"\");\n \n const sshMatch = normalized.match(/^git@([^:]+):(.+)$/);\n if (sshMatch) {\n normalized = `${sshMatch[1]}/${sshMatch[2]}`;\n }\n \n normalized = normalized.replace(/^https?:\\/\\//, \"\");\n normalized = normalized.replace(/^ssh:\\/\\//, \"\");\n normalized = normalized.replace(/\\/$/, \"\");\n return normalized;\n}\n","\nimport { getServerUrl } from \"../lib/config.js\";\nimport { getValidToken } from \"../lib/auth.js\";\n\n/**\n * Orkestrate MCP Proxy\n * \n * Acts as a local MCP server (stdio) that forwards all requests to the \n * Orkestrate cloud MCP endpoint (HTTP), injecting the local auth token.\n */\nexport async function mcpCommand() {\n try {\n const serverUrl = getServerUrl();\n const mcpUrl = `${serverUrl}/api/mcp`;\n\n process.stdin.setEncoding(\"utf-8\");\n let buffer = \"\";\n\n process.stderr.write(`[Orkestrate-MCP] Starting bridge to ${mcpUrl}\\n`);\n\n process.stdin.on(\"data\", async (chunk) => {\n const rawChunk = String(chunk);\n if (process.env.DEBUG) process.stderr.write(`[Orkestrate-MCP] Received chunk: ${rawChunk}\\n`);\n buffer += rawChunk;\n \n let lineEndIndex;\n while ((lineEndIndex = buffer.indexOf(\"\\n\")) >= 0) {\n let line = buffer.slice(0, lineEndIndex).trim();\n buffer = buffer.slice(lineEndIndex + 1);\n \n if (!line) continue;\n \n // Handle back-to-back JSON objects missing newlines\n if (line.includes(\"}{\")) {\n const parts = line.split(\"}{\");\n await processLine(parts[0] + \"}\", mcpUrl);\n for (let i = 1; i < parts.length - 1; i++) {\n await processLine(\"{\" + parts[i] + \"}\", mcpUrl);\n }\n await processLine(\"{\" + parts[parts.length - 1], mcpUrl);\n } else {\n await processLine(line, mcpUrl);\n }\n }\n });\n\n process.stdin.on(\"end\", async () => {\n // Small delay to ensure last processing finishes\n await new Promise(r => setTimeout(r, 100));\n process.exit(0);\n });\n\n // Stay alive\n await new Promise(() => {});\n } catch (err) {\n process.stderr.write(`[Orkestrate] Fatal error: ${err}\\n`);\n process.exit(1);\n }\n}\n\nasync function processLine(line: string, mcpUrl: string) {\n if (process.env.DEBUG) process.stderr.write(`[Orkestrate-MCP] Processing line: ${line}\\n`);\n let payload: any;\n try {\n payload = JSON.parse(line);\n } catch { \n if (process.env.DEBUG) process.stderr.write(`[Orkestrate-MCP] JSON Parse failed for: ${line}\\n`);\n return; \n }\n\n const isNotification = !Object.prototype.hasOwnProperty.call(payload, \"id\");\n const requestId = payload.id;\n\n try {\n const token = await getValidToken();\n \n if (!token) {\n throw new Error(\"NOT_LOGGED_IN: Please run 'orkestrate login' to authenticate.\");\n }\n\n const res = await fetch(mcpUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${token}`,\n \"User-Agent\": \"Orkestrate-CLI-Proxy\"\n },\n body: line\n });\n\n // Notifications MUST NOT be responded to on stdout\n if (isNotification) return;\n\n const responseBody = await res.text();\n if (!res.ok) {\n process.stderr.write(`[Orkestrate-MCP] Backend error (${res.status}): ${responseBody}\\n`);\n if (!isNotification) {\n process.stdout.write(JSON.stringify({\n jsonrpc: \"2.0\",\n id: requestId,\n error: {\n code: -32603,\n message: `Orkestrate Cloud Error (${res.status}): ${responseBody || \"Unauthorized\"}. Please try 'orkestrate login'.`\n }\n }) + \"\\n\");\n }\n return;\n }\n \n if (responseBody) {\n process.stdout.write(responseBody + \"\\n\");\n }\n } catch (err) {\n if (isNotification) return;\n\n process.stdout.write(JSON.stringify({\n jsonrpc: \"2.0\",\n id: requestId,\n error: {\n code: -32603,\n message: err instanceof Error ? err.message : String(err)\n }\n }) + \"\\n\");\n }\n}\n","/**\n * orkestrate whoami\n *\n * Show current authentication and configuration state.\n */\n\nimport { getCredentials, getActiveWorkspace, getServerUrl, getConfigPath } from \"../lib/config.js\";\nimport { checkHealth } from \"../lib/api.js\";\nimport { ui } from \"../lib/ui.js\";\n\nexport async function whoamiCommand(): Promise<void> {\n ui.header(\"Orkestrate Configuration\");\n\n const creds = getCredentials();\n const workspace = getActiveWorkspace();\n const serverUrl = getServerUrl();\n\n ui.kv(\"Server\", serverUrl);\n ui.kv(\"Config\", getConfigPath());\n ui.blank();\n\n if (creds?.accessToken) {\n ui.success(\"Authenticated\");\n \n try {\n const { getMe } = await import(\"../lib/api.js\");\n const user = await getMe();\n ui.kv(\"User\", user.email);\n ui.kv(\"User ID\", user.id);\n } catch {\n ui.kv(\"Client ID\", creds.clientId);\n ui.dim(\"Could not fetch user info from server.\");\n }\n\n const expiresIn = creds.expiresAt - Math.floor(Date.now() / 1000);\n if (expiresIn > 0) {\n const minutes = Math.floor(expiresIn / 60);\n ui.kv(\"Token expires\", `in ${minutes} minute(s)`);\n } else {\n ui.warn(\"Access token expired — will auto-refresh on next API call.\");\n }\n } else {\n ui.error(\"Not authenticated. Run `orkestrate login`.\");\n }\n\n ui.blank();\n\n if (workspace.id) {\n ui.kv(\"Active workspace\", workspace.name || \"—\");\n ui.kv(\"Workspace ID\", workspace.id);\n } else {\n ui.dim(\"No active workspace set.\");\n }\n\n ui.blank();\n\n // Server health check\n ui.info(\"Checking server health...\");\n const healthy = await checkHealth();\n if (healthy) {\n ui.success(\"Server is reachable\");\n } else {\n ui.error(\"Server is unreachable\");\n }\n}\n","/**\n * Orkestrate CLI\n *\n * The coordination layer for autonomous AI coding agents.\n * https://orkestrate.space\n */\n\nimport { Command } from \"commander\";\nimport { ui } from \"./lib/ui.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"orkestrate\")\n .description(\"The coordination layer for autonomous AI coding agents\")\n .version(\"0.1.12\")\n .hook(\"preAction\", () => {\n // Show banner on all commands\n });\n\n// --- login ---\nprogram\n .command(\"login\")\n .description(\"Authenticate with Orkestrate via browser OAuth\")\n .action(async () => {\n const { loginCommand } = await import(\"./commands/login.js\");\n await loginCommand();\n });\n\n// --- logout ---\nprogram\n .command(\"logout\")\n .description(\"Clear stored credentials\")\n .action(async () => {\n const { logoutCommand } = await import(\"./commands/logout.js\");\n logoutCommand();\n });\n\n// --- connect ---\nprogram\n .command(\"connect [tool]\")\n .description(\"Configure MCP endpoint for an AI coding tool (claude, opencode, cursor, windsurf, codex)\")\n .action(async (tool?: string) => {\n const { connectCommand } = await import(\"./commands/connect.js\");\n await connectCommand(tool);\n });\n\n// --- status ---\nprogram\n .command(\"status\")\n .alias(\"s\")\n .description(\"Show current team coordination state\")\n .action(async () => {\n const { statusCommand } = await import(\"./commands/status.js\");\n await statusCommand();\n });\n\n// --- workspace ---\nprogram\n .command(\"workspace [action] [name] [extra]\")\n .alias(\"ws\")\n .description(\"Manage workspaces (list, switch, create)\")\n .action(async (action?: string, name?: string, extra?: string) => {\n const { workspaceCommand } = await import(\"./commands/workspace.js\");\n await workspaceCommand(action, name, extra);\n });\n\n// --- init ---\nprogram\n .command(\"init\")\n .description(\"Initialize Orkestrate in the current project\")\n .action(async () => {\n const { initCommand } = await import(\"./commands/init.js\");\n await initCommand();\n });\n\n// --- mcp ---\nprogram\n .command(\"mcp\")\n .description(\"Run as a local MCP server (stdio bridge to Orkestrate Cloud)\")\n .action(async () => {\n try {\n const { mcpCommand } = await import(\"./commands/mcp.js\");\n await mcpCommand();\n } catch (err) {\n process.stderr.write(`[Orkestrate-MCP] ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n }\n });\n\n// --- whoami ---\nprogram\n .command(\"whoami\")\n .description(\"Show current authentication and configuration\")\n .action(async () => {\n const { whoamiCommand } = await import(\"./commands/whoami.js\");\n await whoamiCommand();\n });\n\n// --- Default: show banner + help ---\nprogram.action(() => {\n ui.banner();\n program.help();\n});\n\n// Run\nprogram.parseAsync(process.argv).catch((err) => {\n ui.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n});\n"],"mappings":"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","names":["config","execSync","existsSync","writeFileSync","join","git","createWorkspace","configureTool","readFileSync","getMe","loginCommand","logoutCommand","connectCommand","statusCommand","workspaceCommand","initCommand","mcpCommand","whoamiCommand"]}
|
package/dist/mcp-entry.js
CHANGED
|
@@ -24,7 +24,9 @@ function getCredentials() {
|
|
|
24
24
|
|
|
25
25
|
// src/lib/auth.ts
|
|
26
26
|
import { createHash, randomBytes } from "crypto";
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
createServer
|
|
29
|
+
} from "http";
|
|
28
30
|
async function refreshAccessToken() {
|
|
29
31
|
const creds = getCredentials();
|
|
30
32
|
if (!creds?.refreshToken) return null;
|
|
@@ -48,7 +50,10 @@ async function refreshAccessToken() {
|
|
|
48
50
|
refreshToken: tokens.refresh_token,
|
|
49
51
|
expiresAt: now + tokens.expires_in,
|
|
50
52
|
userId: creds.userId,
|
|
51
|
-
scope: tokens.scope
|
|
53
|
+
scope: tokens.scope,
|
|
54
|
+
githubAccessToken: creds.githubAccessToken,
|
|
55
|
+
githubRefreshToken: creds.githubRefreshToken,
|
|
56
|
+
githubExpiresAt: creds.githubExpiresAt
|
|
52
57
|
};
|
|
53
58
|
setCredentials(newCreds);
|
|
54
59
|
return newCreds;
|
|
@@ -71,8 +76,12 @@ async function mcpCommand() {
|
|
|
71
76
|
const mcpUrl = `${serverUrl}/api/mcp`;
|
|
72
77
|
process.stdin.setEncoding("utf-8");
|
|
73
78
|
let buffer = "";
|
|
79
|
+
process.stderr.write(`[Orkestrate-MCP] Starting bridge to ${mcpUrl}
|
|
80
|
+
`);
|
|
74
81
|
process.stdin.on("data", async (chunk) => {
|
|
75
82
|
const rawChunk = String(chunk);
|
|
83
|
+
if (process.env.DEBUG) process.stderr.write(`[Orkestrate-MCP] Received chunk: ${rawChunk}
|
|
84
|
+
`);
|
|
76
85
|
buffer += rawChunk;
|
|
77
86
|
let lineEndIndex;
|
|
78
87
|
while ((lineEndIndex = buffer.indexOf("\n")) >= 0) {
|
|
@@ -81,17 +90,18 @@ async function mcpCommand() {
|
|
|
81
90
|
if (!line) continue;
|
|
82
91
|
if (line.includes("}{")) {
|
|
83
92
|
const parts = line.split("}{");
|
|
84
|
-
processLine(parts[0] + "}", mcpUrl);
|
|
93
|
+
await processLine(parts[0] + "}", mcpUrl);
|
|
85
94
|
for (let i = 1; i < parts.length - 1; i++) {
|
|
86
|
-
processLine("{" + parts[i] + "}", mcpUrl);
|
|
95
|
+
await processLine("{" + parts[i] + "}", mcpUrl);
|
|
87
96
|
}
|
|
88
|
-
processLine("{" + parts[parts.length - 1], mcpUrl);
|
|
97
|
+
await processLine("{" + parts[parts.length - 1], mcpUrl);
|
|
89
98
|
} else {
|
|
90
|
-
processLine(line, mcpUrl);
|
|
99
|
+
await processLine(line, mcpUrl);
|
|
91
100
|
}
|
|
92
101
|
}
|
|
93
102
|
});
|
|
94
|
-
process.stdin.on("end", () => {
|
|
103
|
+
process.stdin.on("end", async () => {
|
|
104
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
95
105
|
process.exit(0);
|
|
96
106
|
});
|
|
97
107
|
await new Promise(() => {
|
|
@@ -103,10 +113,14 @@ async function mcpCommand() {
|
|
|
103
113
|
}
|
|
104
114
|
}
|
|
105
115
|
async function processLine(line, mcpUrl) {
|
|
116
|
+
if (process.env.DEBUG) process.stderr.write(`[Orkestrate-MCP] Processing line: ${line}
|
|
117
|
+
`);
|
|
106
118
|
let payload;
|
|
107
119
|
try {
|
|
108
120
|
payload = JSON.parse(line);
|
|
109
121
|
} catch {
|
|
122
|
+
if (process.env.DEBUG) process.stderr.write(`[Orkestrate-MCP] JSON Parse failed for: ${line}
|
|
123
|
+
`);
|
|
110
124
|
return;
|
|
111
125
|
}
|
|
112
126
|
const isNotification = !Object.prototype.hasOwnProperty.call(payload, "id");
|
|
@@ -127,6 +141,21 @@ async function processLine(line, mcpUrl) {
|
|
|
127
141
|
});
|
|
128
142
|
if (isNotification) return;
|
|
129
143
|
const responseBody = await res.text();
|
|
144
|
+
if (!res.ok) {
|
|
145
|
+
process.stderr.write(`[Orkestrate-MCP] Backend error (${res.status}): ${responseBody}
|
|
146
|
+
`);
|
|
147
|
+
if (!isNotification) {
|
|
148
|
+
process.stdout.write(JSON.stringify({
|
|
149
|
+
jsonrpc: "2.0",
|
|
150
|
+
id: requestId,
|
|
151
|
+
error: {
|
|
152
|
+
code: -32603,
|
|
153
|
+
message: `Orkestrate Cloud Error (${res.status}): ${responseBody || "Unauthorized"}. Please try 'orkestrate login'.`
|
|
154
|
+
}
|
|
155
|
+
}) + "\n");
|
|
156
|
+
}
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
130
159
|
if (responseBody) {
|
|
131
160
|
process.stdout.write(responseBody + "\n");
|
|
132
161
|
}
|
package/dist/mcp-entry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/config.ts","../src/lib/auth.ts","../src/commands/mcp.ts","../src/mcp-entry.ts"],"sourcesContent":["/**\n * Orkestrate CLI — Configuration Management\n *\n * Stores credentials and preferences in the user's home directory.\n * Uses the `conf` package for cross-platform config storage.\n */\n\nimport Conf from \"conf\";\n\nexport interface StoredCredentials {\n clientId: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number; // epoch seconds\n userId: string;\n scope: string;\n}\n\nexport interface CliConfig {\n credentials: StoredCredentials | null;\n activeWorkspaceId: string | null;\n activeWorkspaceName: string | null;\n serverUrl: string;\n}\n\nconst config = new Conf<CliConfig>({\n projectName: \"orkestrate\",\n projectSuffix: \"\",\n defaults: {\n credentials: null,\n activeWorkspaceId: null,\n activeWorkspaceName: null,\n serverUrl: \"https://orkestrate.space\",\n },\n});\n\nexport function getConfig(): CliConfig {\n return {\n credentials: config.get(\"credentials\"),\n activeWorkspaceId: config.get(\"activeWorkspaceId\"),\n activeWorkspaceName: config.get(\"activeWorkspaceName\"),\n serverUrl: config.get(\"serverUrl\"),\n };\n}\n\nexport function getServerUrl(): string {\n return config.get(\"serverUrl\");\n}\n\nexport function setCredentials(creds: StoredCredentials): void {\n config.set(\"credentials\", creds);\n}\n\nexport function getCredentials(): StoredCredentials | null {\n return config.get(\"credentials\");\n}\n\nexport function clearCredentials(): void {\n config.set(\"credentials\", null);\n}\n\nexport function setActiveWorkspace(id: string, name: string): void {\n config.set(\"activeWorkspaceId\", id);\n config.set(\"activeWorkspaceName\", name);\n}\n\nexport function getActiveWorkspace(): { id: string | null; name: string | null } {\n return {\n id: config.get(\"activeWorkspaceId\"),\n name: config.get(\"activeWorkspaceName\"),\n };\n}\n\nexport function setServerUrl(url: string): void {\n config.set(\"serverUrl\", url);\n}\n\nexport function clearAll(): void {\n config.clear();\n}\n\nexport function getConfigPath(): string {\n return config.path;\n}\n","/**\n * Orkestrate CLI — OAuth Authentication\n *\n * Implements the full OAuth 2.0 + PKCE flow:\n * 1. Dynamic client registration\n * 2. Open browser for consent\n * 3. Local HTTP callback server\n * 4. Token exchange\n * 5. Credential storage\n */\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport {\n getServerUrl,\n setCredentials,\n getCredentials,\n type StoredCredentials,\n} from \"./config.js\";\n\nfunction randomToken(bytes = 32): string {\n return randomBytes(bytes).toString(\"base64url\");\n}\n\nfunction pkceS256(verifier: string): string {\n return createHash(\"sha256\").update(verifier).digest(\"base64url\");\n}\n\ninterface TokenResponse {\n token_type: string;\n access_token: string;\n expires_in: number;\n refresh_token: string;\n scope: string;\n}\n\n/**\n * Step 1: Register this CLI instance as an OAuth client.\n */\nasync function registerClient(\n serverUrl: string,\n redirectUri: string,\n): Promise<{ clientId: string }> {\n const res = await fetch(`${serverUrl}/api/oauth/register`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n client_name: \"Orkestrate CLI\",\n redirect_uris: [redirectUri],\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\",\n }),\n });\n\n if (!res.ok) {\n const body = await res.text();\n throw new Error(`Client registration failed (${res.status}): ${body}`);\n }\n\n const data = (await res.json()) as { client_id: string };\n return { clientId: data.client_id };\n}\n\n/**\n * Step 2 & 3: Open browser and wait for the OAuth callback.\n */\nfunction waitForCallback(\n port: number,\n): Promise<{ code: string; state: string }> {\n return new Promise((resolve, reject) => {\n let timeoutHandle: ReturnType<typeof setTimeout>;\n\n function cleanup() {\n clearTimeout(timeoutHandle);\n server.close();\n }\n\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url || \"/\", `http://localhost:${port}`);\n\n if (url.pathname !== \"/callback\") {\n res.writeHead(404);\n res.end(\"Not found\");\n return;\n }\n\n const code = url.searchParams.get(\"code\");\n const error = url.searchParams.get(\"error\");\n const state = url.searchParams.get(\"state\") || \"\";\n\n if (error) {\n const description = url.searchParams.get(\"error_description\") || error;\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(buildErrorPage(description));\n cleanup();\n reject(new Error(`OAuth error: ${description}`));\n return;\n }\n\n if (!code) {\n res.writeHead(400, { \"Content-Type\": \"text/html\" });\n res.end(buildErrorPage(\"No authorization code received.\"));\n cleanup();\n reject(new Error(\"No authorization code received\"));\n return;\n }\n\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(buildSuccessPage());\n cleanup();\n resolve({ code, state });\n });\n\n server.listen(port, \"127.0.0.1\", () => {\n // Server ready\n });\n\n server.on(\"error\", (err: Error) => {\n clearTimeout(timeoutHandle);\n reject(new Error(`Could not start local server: ${err.message}`));\n });\n\n // Timeout after 5 minutes — unref so it doesn't block process exit\n timeoutHandle = setTimeout(() => {\n server.close();\n reject(new Error(\"Authentication timed out (5 minutes). Please try again.\"));\n }, 5 * 60 * 1000);\n timeoutHandle.unref();\n });\n}\n\n/**\n * Step 4: Exchange authorization code for tokens.\n */\nasync function exchangeCodeForTokens(\n serverUrl: string,\n code: string,\n clientId: string,\n codeVerifier: string,\n redirectUri: string,\n): Promise<TokenResponse> {\n const body = new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n code_verifier: codeVerifier,\n client_id: clientId,\n redirect_uri: redirectUri,\n });\n\n const res = await fetch(`${serverUrl}/api/oauth/token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Token exchange failed (${res.status}): ${text}`);\n }\n\n return (await res.json()) as TokenResponse;\n}\n\n/**\n * Refresh an expired access token.\n */\nexport async function refreshAccessToken(): Promise<StoredCredentials | null> {\n const creds = getCredentials();\n if (!creds?.refreshToken) return null;\n\n const serverUrl = getServerUrl();\n const body = new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: creds.refreshToken,\n client_id: creds.clientId,\n });\n\n const res = await fetch(`${serverUrl}/api/oauth/token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) return null;\n\n const tokens = (await res.json()) as TokenResponse;\n const now = Math.floor(Date.now() / 1000);\n\n const newCreds: StoredCredentials = {\n clientId: creds.clientId,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: now + tokens.expires_in,\n userId: creds.userId,\n scope: tokens.scope,\n };\n\n setCredentials(newCreds);\n return newCreds;\n}\n\n/**\n * Get a valid access token, refreshing if needed.\n */\nexport async function getValidToken(): Promise<string | null> {\n const creds = getCredentials();\n if (!creds) return null;\n\n const now = Math.floor(Date.now() / 1000);\n\n // Refresh if expired or expiring within 60 seconds\n if (creds.expiresAt <= now + 60) {\n const refreshed = await refreshAccessToken();\n return refreshed?.accessToken || null;\n }\n\n return creds.accessToken;\n}\n\n/**\n * Run the full OAuth login flow.\n */\nexport async function performLogin(): Promise<{\n clientId: string;\n userId: string;\n accessToken: string;\n}> {\n const serverUrl = getServerUrl();\n const port = 19274; // \"ork\" on a phone keypad, roughly\n const redirectUri = `http://127.0.0.1:${port}/callback`;\n\n // Step 1: Register client\n const { clientId } = await registerClient(serverUrl, redirectUri);\n\n // Step 2: Prepare PKCE\n const codeVerifier = randomToken(48);\n const codeChallenge = pkceS256(codeVerifier);\n const state = randomToken(16);\n\n // Step 3: Build authorization URL\n const authUrl = new URL(`${serverUrl}/api/oauth/authorize`);\n authUrl.searchParams.set(\"response_type\", \"code\");\n authUrl.searchParams.set(\"client_id\", clientId);\n authUrl.searchParams.set(\"redirect_uri\", redirectUri);\n authUrl.searchParams.set(\"code_challenge\", codeChallenge);\n authUrl.searchParams.set(\"code_challenge_method\", \"S256\");\n authUrl.searchParams.set(\"scope\", \"mcp:read mcp:write\");\n authUrl.searchParams.set(\"state\", state);\n\n // Step 4: Start callback server + open browser\n const callbackPromise = waitForCallback(port);\n\n // Dynamic import to handle ESM-only `open` package\n const { default: openBrowser } = await import(\"open\");\n await openBrowser(authUrl.toString());\n\n // Step 5: Wait for callback\n const { code, state: returnedState } = await callbackPromise;\n\n if (returnedState !== state) {\n throw new Error(\"OAuth state mismatch — possible CSRF attack. Aborting.\");\n }\n\n // Step 6: Exchange code for tokens\n const tokens = await exchangeCodeForTokens(\n serverUrl,\n code,\n clientId,\n codeVerifier,\n redirectUri,\n );\n\n const now = Math.floor(Date.now() / 1000);\n\n // We don't get user_id from the token response directly.\n // We'll extract it from the MCP endpoint or store a placeholder.\n // For now, use clientId as a proxy until first API call resolves it.\n const credentials: StoredCredentials = {\n clientId,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: now + tokens.expires_in,\n userId: \"\", // Will be resolved on first API call\n scope: tokens.scope,\n };\n\n setCredentials(credentials);\n\n return {\n clientId,\n userId: credentials.userId,\n accessToken: tokens.access_token,\n };\n}\n\n// --- HTML pages for the local callback server ---\n\nfunction buildSuccessPage(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>Orkestrate — Authenticated</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .card {\n text-align: center;\n padding: 3rem;\n border: 1px solid #262626;\n border-radius: 12px;\n background: #111;\n max-width: 420px;\n }\n .icon { font-size: 3rem; margin-bottom: 1rem; }\n h1 { font-size: 1.5rem; margin-bottom: 0.5rem; color: #fff; }\n p { color: #a3a3a3; line-height: 1.6; }\n .hint { margin-top: 1.5rem; font-size: 0.85rem; color: #525252; }\n </style>\n</head>\n<body>\n <div class=\"card\">\n <div class=\"icon\">✓</div>\n <h1>Authenticated</h1>\n <p>You're now logged in to Orkestrate. You can close this tab and return to your terminal.</p>\n <p class=\"hint\">This window will close automatically.</p>\n </div>\n <script>setTimeout(() => window.close(), 3000);</script>\n</body>\n</html>`;\n}\n\nfunction buildErrorPage(message: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>Orkestrate — Error</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .card {\n text-align: center;\n padding: 3rem;\n border: 1px solid #371717;\n border-radius: 12px;\n background: #1a0a0a;\n max-width: 420px;\n }\n .icon { font-size: 3rem; margin-bottom: 1rem; }\n h1 { font-size: 1.5rem; margin-bottom: 0.5rem; color: #fca5a5; }\n p { color: #a3a3a3; line-height: 1.6; }\n </style>\n</head>\n<body>\n <div class=\"card\">\n <div class=\"icon\">✗</div>\n <h1>Authentication Failed</h1>\n <p>${message}</p>\n </div>\n</body>\n</html>`;\n}\n","\nimport { getServerUrl } from \"../lib/config.js\";\nimport { getValidToken } from \"../lib/auth.js\";\n\n/**\n * Orkestrate MCP Proxy\n * \n * Acts as a local MCP server (stdio) that forwards all requests to the \n * Orkestrate cloud MCP endpoint (HTTP), injecting the local auth token.\n */\nexport async function mcpCommand() {\n try {\n const serverUrl = getServerUrl();\n const mcpUrl = `${serverUrl}/api/mcp`;\n\n process.stdin.setEncoding(\"utf-8\");\n let buffer = \"\";\n \n process.stdin.on(\"data\", async (chunk) => {\n const rawChunk = String(chunk);\n buffer += rawChunk;\n \n let lineEndIndex;\n while ((lineEndIndex = buffer.indexOf(\"\\n\")) >= 0) {\n let line = buffer.slice(0, lineEndIndex).trim();\n buffer = buffer.slice(lineEndIndex + 1);\n \n if (!line) continue;\n \n // Handle back-to-back JSON objects missing newlines\n if (line.includes(\"}{\")) {\n const parts = line.split(\"}{\");\n processLine(parts[0] + \"}\", mcpUrl);\n for (let i = 1; i < parts.length - 1; i++) {\n processLine(\"{\" + parts[i] + \"}\", mcpUrl);\n }\n processLine(\"{\" + parts[parts.length - 1], mcpUrl);\n } else {\n processLine(line, mcpUrl);\n }\n }\n });\n\n process.stdin.on(\"end\", () => {\n process.exit(0);\n });\n\n // Stay alive\n await new Promise(() => {});\n } catch (err) {\n process.stderr.write(`[Orkestrate] Fatal error: ${err}\\n`);\n process.exit(1);\n }\n}\n\nasync function processLine(line: string, mcpUrl: string) {\n let payload: any;\n try {\n payload = JSON.parse(line);\n } catch { return; }\n\n const isNotification = !Object.prototype.hasOwnProperty.call(payload, \"id\");\n const requestId = payload.id;\n\n try {\n const token = await getValidToken();\n \n if (!token) {\n throw new Error(\"NOT_LOGGED_IN: Please run 'orkestrate login' to authenticate.\");\n }\n\n const res = await fetch(mcpUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${token}`,\n \"User-Agent\": \"Orkestrate-CLI-Proxy\"\n },\n body: line\n });\n\n // Notifications MUST NOT be responded to on stdout\n if (isNotification) return;\n\n const responseBody = await res.text();\n if (responseBody) {\n process.stdout.write(responseBody + \"\\n\");\n }\n } catch (err) {\n if (isNotification) return;\n\n process.stdout.write(JSON.stringify({\n jsonrpc: \"2.0\",\n id: requestId,\n error: {\n code: -32603,\n message: err instanceof Error ? err.message : String(err)\n }\n }) + \"\\n\");\n }\n}\n","\nimport { mcpCommand } from \"./commands/mcp.js\";\n\n// Standalone MCP bridge entry point. \n// DO NOT PRINT TO STDOUT ANY NON-JSON DATA.\nmcpCommand().catch(err => {\n process.stderr.write(`[Orkestrate-MCP] Fatal: ${err}\\n`);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/config.ts","../src/lib/auth.ts","../src/commands/mcp.ts","../src/mcp-entry.ts"],"sourcesContent":["/**\n * Orkestrate CLI — Configuration Management\n *\n * Stores credentials and preferences in the user's home directory.\n * Uses the `conf` package for cross-platform config storage.\n */\n\nimport Conf from \"conf\";\n\nexport interface StoredCredentials {\n clientId: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number; // epoch seconds\n userId: string;\n scope: string;\n githubAccessToken?: string;\n githubRefreshToken?: string;\n githubExpiresAt?: number; // epoch seconds\n}\n\nexport interface CliConfig {\n credentials: StoredCredentials | null;\n activeWorkspaceId: string | null;\n activeWorkspaceName: string | null;\n serverUrl: string;\n}\n\nconst config = new Conf<CliConfig>({\n projectName: \"orkestrate\",\n projectSuffix: \"\",\n defaults: {\n credentials: null,\n activeWorkspaceId: null,\n activeWorkspaceName: null,\n serverUrl: \"https://orkestrate.space\",\n },\n});\n\nexport function getConfig(): CliConfig {\n return {\n credentials: config.get(\"credentials\"),\n activeWorkspaceId: config.get(\"activeWorkspaceId\"),\n activeWorkspaceName: config.get(\"activeWorkspaceName\"),\n serverUrl: config.get(\"serverUrl\"),\n };\n}\n\nexport function getServerUrl(): string {\n return config.get(\"serverUrl\");\n}\n\nexport function setCredentials(creds: StoredCredentials): void {\n config.set(\"credentials\", creds);\n}\n\nexport function getCredentials(): StoredCredentials | null {\n return config.get(\"credentials\");\n}\n\nexport function clearCredentials(): void {\n config.set(\"credentials\", null);\n}\n\nexport function setActiveWorkspace(id: string, name: string): void {\n config.set(\"activeWorkspaceId\", id);\n config.set(\"activeWorkspaceName\", name);\n}\n\nexport function getActiveWorkspace(): {\n id: string | null;\n name: string | null;\n} {\n return {\n id: config.get(\"activeWorkspaceId\"),\n name: config.get(\"activeWorkspaceName\"),\n };\n}\n\nexport function setServerUrl(url: string): void {\n config.set(\"serverUrl\", url);\n}\n\nexport function clearAll(): void {\n config.clear();\n}\n\nexport function getConfigPath(): string {\n return config.path;\n}\n\n// --- GitHub Token Management ---\n\nexport interface GithubTokens {\n accessToken: string;\n refreshToken?: string;\n expiresAt: number; // epoch seconds\n}\n\nexport function setGithubTokens(tokens: GithubTokens): void {\n const creds = getCredentials();\n if (!creds) return;\n\n creds.githubAccessToken = tokens.accessToken;\n creds.githubRefreshToken = tokens.refreshToken;\n creds.githubExpiresAt = tokens.expiresAt;\n\n setCredentials(creds);\n}\n\nexport function getGithubTokens(): GithubTokens | null {\n const creds = getCredentials();\n if (!creds?.githubAccessToken || !creds.githubExpiresAt) return null;\n\n return {\n accessToken: creds.githubAccessToken,\n refreshToken: creds.githubRefreshToken,\n expiresAt: creds.githubExpiresAt,\n };\n}\n\nexport function getValidGithubToken(): string | null {\n const tokens = getGithubTokens();\n if (!tokens) return null;\n\n const now = Math.floor(Date.now() / 1000);\n\n // Consider expired if within 60 seconds of expiry\n if (tokens.expiresAt <= now + 60) return null;\n\n return tokens.accessToken;\n}\n\nexport function hasGithubToken(): boolean {\n return getValidGithubToken() !== null;\n}\n","/**\n * Orkestrate CLI — OAuth Authentication\n *\n * Implements OAuth 2.0 + PKCE flow with two providers:\n * 1. Orkestrate OAuth — identity (openid, profile, email, mcp scopes)\n * 2. GitHub OAuth — repo access (required for workspace creation)\n *\n * Flow:\n * 1. Orkestrate OAuth → Orkestrate identity tokens\n * 2. GitHub OAuth (via Orkestrate proxy) → GitHub access tokens\n * 3. Both stored locally in ~/.config/orkestrate/\n */\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport {\n createServer,\n type IncomingMessage,\n type ServerResponse,\n} from \"node:http\";\nimport {\n getServerUrl,\n setCredentials,\n getCredentials,\n setGithubTokens,\n type StoredCredentials,\n} from \"./config.js\";\n\n// ─── PKCE Helpers ──────────────────────────────────────────────────────────────\n\nfunction randomToken(bytes = 32): string {\n return randomBytes(bytes).toString(\"base64url\");\n}\n\nfunction pkceS256(verifier: string): string {\n return createHash(\"sha256\").update(verifier).digest(\"base64url\");\n}\n\n// ─── Token Types ───────────────────────────────────────────────────────────────\n\ninterface TokenResponse {\n token_type: string;\n access_token: string;\n expires_in: number;\n refresh_token: string;\n scope: string;\n id_token?: string;\n}\n\n// ─── Dynamic Client Registration ───────────────────────────────────────────────\n\nasync function registerClient(\n serverUrl: string,\n redirectUri: string,\n): Promise<{ clientId: string }> {\n const res = await fetch(`${serverUrl}/api/oauth/register`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n client_name: \"Orkestrate CLI\",\n redirect_uris: [redirectUri],\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\",\n }),\n });\n\n if (!res.ok) {\n const body = await res.text();\n throw new Error(`Client registration failed (${res.status}): ${body}`);\n }\n\n const data = (await res.json()) as { client_id: string };\n return { clientId: data.client_id };\n}\n\n// ─── Callback Server ───────────────────────────────────────────────────────────\n\nfunction waitForCallback(\n port: number,\n): Promise<{ code: string; state: string }> {\n return new Promise((resolve, reject) => {\n let timeoutHandle: ReturnType<typeof setTimeout>;\n\n function cleanup() {\n clearTimeout(timeoutHandle);\n server.close();\n }\n\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url || \"/\", `http://localhost:${port}`);\n\n if (url.pathname !== \"/callback\") {\n res.writeHead(404);\n res.end(\"Not found\");\n return;\n }\n\n const code = url.searchParams.get(\"code\");\n const error = url.searchParams.get(\"error\");\n const state = url.searchParams.get(\"state\") || \"\";\n\n if (error) {\n const description = url.searchParams.get(\"error_description\") || error;\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(buildErrorPage(description));\n cleanup();\n reject(new Error(`OAuth error: ${description}`));\n return;\n }\n\n if (!code) {\n res.writeHead(400, { \"Content-Type\": \"text/html\" });\n res.end(buildErrorPage(\"No authorization code received.\"));\n cleanup();\n reject(new Error(\"No authorization code received\"));\n return;\n }\n\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(buildSuccessPage());\n cleanup();\n resolve({ code, state });\n });\n\n server.listen(port, \"127.0.0.1\", () => {\n // ready\n });\n\n server.on(\"error\", (err: Error) => {\n clearTimeout(timeoutHandle);\n reject(new Error(`Could not start local server: ${err.message}`));\n });\n\n // 5-minute timeout — unref so it doesn't block process exit\n timeoutHandle = setTimeout(\n () => {\n server.close();\n reject(\n new Error(\"Authentication timed out (5 minutes). Please try again.\"),\n );\n },\n 5 * 60 * 1000,\n );\n timeoutHandle.unref();\n });\n}\n\n// ─── Token Exchange ────────────────────────────────────────────────────────────\n\nasync function exchangeCodeForTokens(\n serverUrl: string,\n code: string,\n clientId: string,\n codeVerifier: string,\n redirectUri: string,\n): Promise<TokenResponse> {\n const body = new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n code_verifier: codeVerifier,\n client_id: clientId,\n redirect_uri: redirectUri,\n });\n\n const res = await fetch(`${serverUrl}/api/oauth/token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Token exchange failed (${res.status}): ${text}`);\n }\n\n const data = (await res.json()) as TokenResponse;\n if (process.env.DEBUG) {\n console.error(\n `[DEBUG] Orkestrate Token: ${data.access_token?.slice(0, 5)}...`,\n );\n }\n return data;\n}\n\n// ─── GitHub OAuth (proxied through Orkestrate backend, device flow) ────────────\n\ninterface GithubDeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n expires_in: number;\n interval: number;\n}\n\ninterface GithubTokenPollResponse {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n error?: string;\n error_description?: string;\n}\n\n/**\n * Start GitHub's Device Flow via Orkestrate proxy.\n * Returns device code + user code for the user to enter at verification_uri.\n */\nasync function startGithubDeviceFlow(\n serverUrl: string,\n accessToken: string,\n): Promise<GithubDeviceCodeResponse> {\n const res = await fetch(`${serverUrl}/api/oauth/github/auth-url`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(\n `Failed to start GitHub device flow (${res.status}): ${text}`,\n );\n }\n\n return (await res.json()) as GithubDeviceCodeResponse;\n}\n\n/**\n * Poll Orkestrate (which proxies to GitHub) for the GitHub token.\n * Returns null while authorization is still pending.\n * Throws on error or expired code.\n */\nasync function pollGithubToken(\n serverUrl: string,\n accessToken: string,\n userId: string,\n deviceCode: string,\n intervalSeconds: number,\n): Promise<{\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n}> {\n // Add a small buffer to the interval to avoid hitting rate limits\n const pollInterval = (intervalSeconds + 1) * 1000;\n\n while (true) {\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n\n const res = await fetch(`${serverUrl}/api/oauth/github/token`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ device_code: deviceCode, user_id: userId }),\n });\n\n const data = (await res.json()) as GithubTokenPollResponse;\n\n // Still pending — keep polling\n if (data.error === \"authorization_pending\" || data.error === \"slow_down\") {\n continue;\n }\n\n if (data.error) {\n throw new Error(\n `GitHub authorization failed: ${data.error_description || data.error}`,\n );\n }\n\n if (!data.access_token) {\n throw new Error(\"GitHub returned no access token\");\n }\n\n return {\n access_token: data.access_token,\n refresh_token: data.refresh_token,\n expires_in: data.expires_in ?? 3600,\n };\n }\n}\n\n// ─── Token Refresh ─────────────────────────────────────────────────────────────\n\n/**\n * Refresh the Orkestrate access token using the stored refresh token.\n */\nexport async function refreshAccessToken(): Promise<StoredCredentials | null> {\n const creds = getCredentials();\n if (!creds?.refreshToken) return null;\n\n const serverUrl = getServerUrl();\n const body = new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: creds.refreshToken,\n client_id: creds.clientId,\n });\n\n const res = await fetch(`${serverUrl}/api/oauth/token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) return null;\n\n const tokens = (await res.json()) as TokenResponse;\n const now = Math.floor(Date.now() / 1000);\n\n const newCreds: StoredCredentials = {\n clientId: creds.clientId,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: now + tokens.expires_in,\n userId: creds.userId,\n scope: tokens.scope,\n githubAccessToken: creds.githubAccessToken,\n githubRefreshToken: creds.githubRefreshToken,\n githubExpiresAt: creds.githubExpiresAt,\n };\n\n setCredentials(newCreds);\n return newCreds;\n}\n\n/**\n * Get a valid (non-expired) Orkestrate access token.\n * Automatically refreshes if within 60 seconds of expiry.\n */\nexport async function getValidToken(): Promise<string | null> {\n const creds = getCredentials();\n if (!creds) return null;\n\n const now = Math.floor(Date.now() / 1000);\n\n if (creds.expiresAt <= now + 60) {\n const refreshed = await refreshAccessToken();\n return refreshed?.accessToken || null;\n }\n\n return creds.accessToken;\n}\n\n// ─── Main Login Flow ──────────────────────────────────────────────────────────\n\n/**\n * Run the full Orkestrate + GitHub OAuth login flow.\n *\n * Phase 1: Orkestrate OAuth → identity (stored locally)\n * Phase 2: GitHub OAuth → repo access (proxied through Orkestrate backend)\n *\n * GitHub is best-effort — if it fails, login still succeeds but\n * workspace creation won't work until GitHub is re-connected.\n */\nexport async function performLogin(): Promise<{\n clientId: string;\n userId: string;\n accessToken: string;\n githubConnected: boolean;\n}> {\n const serverUrl = getServerUrl();\n const port = 19274; // \"ork\" on phone keypad, roughly\n const redirectUri = `http://127.0.0.1:${port}/callback`;\n\n // ── Phase 1: Orkestrate OAuth ──────────────────────────────────────────────\n\n const { clientId } = await registerClient(serverUrl, redirectUri);\n\n const codeVerifier = randomToken(48);\n const codeChallenge = pkceS256(codeVerifier);\n const state = randomToken(16);\n\n const authUrl = new URL(`${serverUrl}/api/oauth/authorize`);\n authUrl.searchParams.set(\"response_type\", \"code\");\n authUrl.searchParams.set(\"client_id\", clientId);\n authUrl.searchParams.set(\"redirect_uri\", redirectUri);\n authUrl.searchParams.set(\"code_challenge\", codeChallenge);\n authUrl.searchParams.set(\"code_challenge_method\", \"S256\");\n authUrl.searchParams.set(\"scope\", \"openid profile email mcp:read mcp:write\");\n authUrl.searchParams.set(\"state\", state);\n\n const callbackPromise = waitForCallback(port);\n\n const { default: openBrowser } = await import(\"open\");\n await openBrowser(authUrl.toString());\n\n const { code, state: returnedState } = await callbackPromise;\n\n if (returnedState !== state) {\n throw new Error(\n \"Orkestrate OAuth state mismatch — possible CSRF attack. Aborting.\",\n );\n }\n\n const tokens = await exchangeCodeForTokens(\n serverUrl,\n code,\n clientId,\n codeVerifier,\n redirectUri,\n );\n\n // Resolve userId\n let userId = \"\";\n try {\n const meRes = await fetch(`${serverUrl}/api/auth/me`, {\n headers: { Authorization: `Bearer ${tokens.access_token}` },\n });\n if (meRes.ok) {\n const me = (await meRes.json()) as { id?: string };\n userId = me.id || \"\";\n }\n } catch {\n // Non-fatal\n }\n\n const credentials: StoredCredentials = {\n clientId,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: Math.floor(Date.now() / 1000) + tokens.expires_in,\n userId,\n scope: tokens.scope,\n };\n\n setCredentials(credentials);\n\n // ── Phase 2: GitHub OAuth (Device Flow) ───────────────────────────────────\n\n let githubConnected = false;\n\n try {\n // Start GitHub device flow via Orkestrate proxy\n const deviceData = await startGithubDeviceFlow(\n serverUrl,\n tokens.access_token,\n );\n\n // Display user code and instructions\n console.error();\n console.error(\" GitHub Device Authorization\");\n console.error();\n console.error(` 1. Open: ${deviceData.verification_uri}`);\n console.error(` 2. Enter: ${deviceData.user_code}`);\n console.error();\n console.error(\" Waiting for authorization... (press Ctrl+C to cancel)\");\n\n // Poll until user completes GitHub authorization\n const githubTokens = await pollGithubToken(\n serverUrl,\n tokens.access_token,\n userId,\n deviceData.device_code,\n deviceData.interval,\n );\n\n setGithubTokens({\n accessToken: githubTokens.access_token,\n refreshToken: githubTokens.refresh_token,\n expiresAt:\n Math.floor(Date.now() / 1000) + (githubTokens.expires_in ?? 3600),\n });\n\n githubConnected = true;\n } catch (err) {\n // Best-effort — warn but don't fail the login\n console.error(\n `[Login] GitHub connection failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n console.error(\"[Login] Workspace creation requires GitHub access.\");\n console.error(\n \"[Login] Re-run \\`orkestrate login --github\\` to connect GitHub later.\",\n );\n }\n\n return {\n clientId,\n userId: credentials.userId,\n accessToken: credentials.accessToken,\n githubConnected,\n };\n}\n\n// ─── HTML Pages ───────────────────────────────────────────────────────────────\n\nfunction buildSuccessPage(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>Orkestrate — Authenticated</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .card {\n text-align: center;\n padding: 3rem;\n border: 1px solid #262626;\n border-radius: 12px;\n background: #111;\n max-width: 420px;\n }\n .icon { font-size: 3rem; margin-bottom: 1rem; }\n h1 { font-size: 1.5rem; margin-bottom: 0.5rem; color: #fff; }\n p { color: #a3a3a3; line-height: 1.6; }\n .hint { margin-top: 1.5rem; font-size: 0.85rem; color: #525252; }\n </style>\n</head>\n<body>\n <div class=\"card\">\n <div class=\"icon\">✓</div>\n <h1>Authenticated</h1>\n <p>You're now logged in to Orkestrate. You can close this tab and return to your terminal.</p>\n <p class=\"hint\">This window will close automatically.</p>\n </div>\n <script>setTimeout(() => window.close(), 3000);</script>\n</body>\n</html>`;\n}\n\nfunction buildErrorPage(message: string): string {\n const escaped = message.replace(/</g, \"<\").replace(/>/g, \">\");\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>Orkestrate — Error</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .card {\n text-align: center;\n padding: 3rem;\n border: 1px solid #371717;\n border-radius: 12px;\n background: #1a0a0a;\n max-width: 420px;\n }\n .icon { font-size: 3rem; margin-bottom: 1rem; }\n h1 { font-size: 1.5rem; margin-bottom: 0.5rem; color: #fca5a5; }\n p { color: #a3a3a3; line-height: 1.6; }\n </style>\n</head>\n<body>\n <div class=\"card\">\n <div class=\"icon\">✗</div>\n <h1>Authentication Failed</h1>\n <p>${escaped}</p>\n </div>\n</body>\n</html>`;\n}\n","\nimport { getServerUrl } from \"../lib/config.js\";\nimport { getValidToken } from \"../lib/auth.js\";\n\n/**\n * Orkestrate MCP Proxy\n * \n * Acts as a local MCP server (stdio) that forwards all requests to the \n * Orkestrate cloud MCP endpoint (HTTP), injecting the local auth token.\n */\nexport async function mcpCommand() {\n try {\n const serverUrl = getServerUrl();\n const mcpUrl = `${serverUrl}/api/mcp`;\n\n process.stdin.setEncoding(\"utf-8\");\n let buffer = \"\";\n\n process.stderr.write(`[Orkestrate-MCP] Starting bridge to ${mcpUrl}\\n`);\n\n process.stdin.on(\"data\", async (chunk) => {\n const rawChunk = String(chunk);\n if (process.env.DEBUG) process.stderr.write(`[Orkestrate-MCP] Received chunk: ${rawChunk}\\n`);\n buffer += rawChunk;\n \n let lineEndIndex;\n while ((lineEndIndex = buffer.indexOf(\"\\n\")) >= 0) {\n let line = buffer.slice(0, lineEndIndex).trim();\n buffer = buffer.slice(lineEndIndex + 1);\n \n if (!line) continue;\n \n // Handle back-to-back JSON objects missing newlines\n if (line.includes(\"}{\")) {\n const parts = line.split(\"}{\");\n await processLine(parts[0] + \"}\", mcpUrl);\n for (let i = 1; i < parts.length - 1; i++) {\n await processLine(\"{\" + parts[i] + \"}\", mcpUrl);\n }\n await processLine(\"{\" + parts[parts.length - 1], mcpUrl);\n } else {\n await processLine(line, mcpUrl);\n }\n }\n });\n\n process.stdin.on(\"end\", async () => {\n // Small delay to ensure last processing finishes\n await new Promise(r => setTimeout(r, 100));\n process.exit(0);\n });\n\n // Stay alive\n await new Promise(() => {});\n } catch (err) {\n process.stderr.write(`[Orkestrate] Fatal error: ${err}\\n`);\n process.exit(1);\n }\n}\n\nasync function processLine(line: string, mcpUrl: string) {\n if (process.env.DEBUG) process.stderr.write(`[Orkestrate-MCP] Processing line: ${line}\\n`);\n let payload: any;\n try {\n payload = JSON.parse(line);\n } catch { \n if (process.env.DEBUG) process.stderr.write(`[Orkestrate-MCP] JSON Parse failed for: ${line}\\n`);\n return; \n }\n\n const isNotification = !Object.prototype.hasOwnProperty.call(payload, \"id\");\n const requestId = payload.id;\n\n try {\n const token = await getValidToken();\n \n if (!token) {\n throw new Error(\"NOT_LOGGED_IN: Please run 'orkestrate login' to authenticate.\");\n }\n\n const res = await fetch(mcpUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${token}`,\n \"User-Agent\": \"Orkestrate-CLI-Proxy\"\n },\n body: line\n });\n\n // Notifications MUST NOT be responded to on stdout\n if (isNotification) return;\n\n const responseBody = await res.text();\n if (!res.ok) {\n process.stderr.write(`[Orkestrate-MCP] Backend error (${res.status}): ${responseBody}\\n`);\n if (!isNotification) {\n process.stdout.write(JSON.stringify({\n jsonrpc: \"2.0\",\n id: requestId,\n error: {\n code: -32603,\n message: `Orkestrate Cloud Error (${res.status}): ${responseBody || \"Unauthorized\"}. Please try 'orkestrate login'.`\n }\n }) + \"\\n\");\n }\n return;\n }\n \n if (responseBody) {\n process.stdout.write(responseBody + \"\\n\");\n }\n } catch (err) {\n if (isNotification) return;\n\n process.stdout.write(JSON.stringify({\n jsonrpc: \"2.0\",\n id: requestId,\n error: {\n code: -32603,\n message: err instanceof Error ? err.message : String(err)\n }\n }) + \"\\n\");\n }\n}\n","\nimport { mcpCommand } from \"./commands/mcp.js\";\n\n// Standalone MCP bridge entry point. \n// DO NOT PRINT TO STDOUT ANY NON-JSON DATA.\nmcpCommand().catch(err => {\n process.stderr.write(`[Orkestrate-MCP] Fatal: ${err}\\n`);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
|