@braid-cloud/cli 0.1.17 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -0
- package/dist/index.js +1316 -1032
- package/dist/index.js.map +1 -1
- package/dist/manage-ui/assets/{index-DvWPfYXk.css → index-BBmBYWoe.css} +1 -1
- package/dist/manage-ui/index.html +2 -2
- package/package.json +5 -2
- /package/dist/manage-ui/assets/{index-m-nUswBP.js → index-RfQhJisb.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -18,10 +18,28 @@ var init_esm_shims = __esm({
|
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
+
// src/lib/automation-headers.ts
|
|
22
|
+
import process3 from "process";
|
|
23
|
+
var VERCEL_AUTOMATION_BYPASS_SECRET, mergeAutomationHeaders;
|
|
24
|
+
var init_automation_headers = __esm({
|
|
25
|
+
"src/lib/automation-headers.ts"() {
|
|
26
|
+
"use strict";
|
|
27
|
+
init_esm_shims();
|
|
28
|
+
VERCEL_AUTOMATION_BYPASS_SECRET = process3.env.VERCEL_AUTOMATION_BYPASS_SECRET;
|
|
29
|
+
mergeAutomationHeaders = (headers) => {
|
|
30
|
+
const merged = new Headers(headers);
|
|
31
|
+
if (VERCEL_AUTOMATION_BYPASS_SECRET) {
|
|
32
|
+
merged.set("x-vercel-protection-bypass", VERCEL_AUTOMATION_BYPASS_SECRET);
|
|
33
|
+
}
|
|
34
|
+
return merged.entries().next().done ? void 0 : merged;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
21
39
|
// src/lib/braid-workspace.ts
|
|
22
40
|
import { existsSync, readFileSync } from "fs";
|
|
23
41
|
import { dirname as dirname3, join as join2 } from "path";
|
|
24
|
-
import
|
|
42
|
+
import process4 from "process";
|
|
25
43
|
function readPackageName(packagePath) {
|
|
26
44
|
if (!existsSync(packagePath)) {
|
|
27
45
|
return void 0;
|
|
@@ -38,7 +56,7 @@ function readPackageName(packagePath) {
|
|
|
38
56
|
function isBraidWorkspaceRoot(directory) {
|
|
39
57
|
return readPackageName(join2(directory, "package.json")) === BRAID_WORKSPACE_NAME;
|
|
40
58
|
}
|
|
41
|
-
function findBraidWorkspaceRoot(startDir =
|
|
59
|
+
function findBraidWorkspaceRoot(startDir = process4.cwd()) {
|
|
42
60
|
let currentDir = startDir;
|
|
43
61
|
while (true) {
|
|
44
62
|
if (isBraidWorkspaceRoot(currentDir)) {
|
|
@@ -108,9 +126,9 @@ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
|
108
126
|
import { mkdir as mkdir2, readFile, writeFile as writeFile2 } from "fs/promises";
|
|
109
127
|
import { homedir as homedir2 } from "os";
|
|
110
128
|
import { dirname as dirname4, join as join3, parse } from "path";
|
|
111
|
-
import
|
|
129
|
+
import process5 from "process";
|
|
112
130
|
import { Data as Data2, Effect as Effect3, pipe as pipe3 } from "effect";
|
|
113
|
-
var CONFIG_DIR, CONFIG_FILE, PROJECT_CONFIG_FILENAME, USER_CONFIG_FILENAME, CONVEX_CLOUD_SUFFIX_REGEX, LOCAL_CONVEX_PORT_REGEX, LOCAL_SERVER_ENV_FILES, LOOPBACK_HOSTS, NEWLINE_REGEX, TRAILING_SLASHES, ConfigReadError, ConfigWriteError, findConfigFile, findProjectConfigFile, findUserConfigFile, stripQuotes, parseDotenv, normalizeBaseUrl, resolveConvexSiteUrl, resolveLocalServerUrlFromEnv, resolveLocalServerUrlFromFiles, resolveLocalServerUrl, loadProjectConfig, loadUserConfig, resolveUserConfigWritePath, resolveProjectConfigWritePath, saveUserConfig, saveProjectConfig, isValidServerUrl, resolveServerUrlFromConfig, applyConfigSource, applyEnvOverrides, createDefaultMergedConfig, loadMergedConfig, loadConfig, saveConfig, getApiKey, setApiKey, getServerUrl, clearApiKey, getDemoContext, setDemoContext, clearDemoContext, loadConfigAsync, loadProjectConfigAsync, loadUserConfigAsync, loadMergedConfigAsync, findProjectConfigFileAsync, findUserConfigFileAsync, saveConfigAsync, saveUserConfigAsync, saveProjectConfigAsync, getApiKeyAsync, setApiKeyAsync, persistApiKeyAsync, getServerUrlAsync, clearApiKeyAsync, getDemoContextAsync, setDemoContextAsync, clearDemoContextAsync;
|
|
131
|
+
var CONFIG_DIR, CONFIG_FILE, PROJECT_CONFIG_FILENAME, USER_CONFIG_FILENAME, CONVEX_CLOUD_SUFFIX_REGEX, LOCAL_CONVEX_PORT_REGEX, LOCAL_SERVER_ENV_FILES, LOOPBACK_HOSTS, NEWLINE_REGEX, TRAILING_SLASHES, ConfigReadError, ConfigWriteError, findConfigFile, findProjectConfigFile, findUserConfigFile, stripQuotes, parseDotenv, normalizeBaseUrl, resolveConvexSiteUrl, resolveLocalServerUrlFromEnv, resolveLocalServerUrlFromFiles, resolveLocalServerUrl, loadProjectConfig, loadUserConfig, resolveUserConfigWritePath, resolveProjectConfigWritePath, saveUserConfig, saveProjectConfig, isValidServerUrl, resolveServerUrlFromConfig, applyConfigSource, applyGlobalConfigSource, applyEnvOverrides, createDefaultMergedConfig, loadMergedConfig, loadConfig, saveConfig, getApiKey, setApiKey, getServerUrl, clearApiKey, getDemoContext, setDemoContext, clearDemoContext, loadConfigAsync, loadProjectConfigAsync, loadUserConfigAsync, loadMergedConfigAsync, findProjectConfigFileAsync, findUserConfigFileAsync, saveConfigAsync, saveUserConfigAsync, saveProjectConfigAsync, getApiKeyAsync, setApiKeyAsync, persistApiKeyAsync, getServerUrlAsync, clearApiKeyAsync, getDemoContextAsync, setDemoContextAsync, clearDemoContextAsync;
|
|
114
132
|
var init_config = __esm({
|
|
115
133
|
"src/lib/config.ts"() {
|
|
116
134
|
"use strict";
|
|
@@ -133,7 +151,7 @@ var init_config = __esm({
|
|
|
133
151
|
};
|
|
134
152
|
ConfigWriteError = class extends Data2.TaggedError("ConfigWriteError") {
|
|
135
153
|
};
|
|
136
|
-
findConfigFile = (filename, startDir =
|
|
154
|
+
findConfigFile = (filename, startDir = process5.cwd()) => {
|
|
137
155
|
let currentDir = startDir;
|
|
138
156
|
while (true) {
|
|
139
157
|
const configPath = join3(currentDir, filename);
|
|
@@ -147,8 +165,8 @@ var init_config = __esm({
|
|
|
147
165
|
currentDir = parsed.dir;
|
|
148
166
|
}
|
|
149
167
|
};
|
|
150
|
-
findProjectConfigFile = (startDir =
|
|
151
|
-
findUserConfigFile = (startDir =
|
|
168
|
+
findProjectConfigFile = (startDir = process5.cwd()) => findConfigFile(PROJECT_CONFIG_FILENAME, startDir);
|
|
169
|
+
findUserConfigFile = (startDir = process5.cwd()) => findConfigFile(USER_CONFIG_FILENAME, startDir);
|
|
152
170
|
stripQuotes = (value) => {
|
|
153
171
|
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
154
172
|
return value.slice(1, -1);
|
|
@@ -207,7 +225,7 @@ var init_config = __esm({
|
|
|
207
225
|
}
|
|
208
226
|
return void 0;
|
|
209
227
|
};
|
|
210
|
-
resolveLocalServerUrlFromFiles = (startDir =
|
|
228
|
+
resolveLocalServerUrlFromFiles = (startDir = process5.cwd()) => {
|
|
211
229
|
const workspaceRoot = findBraidWorkspaceRoot(startDir);
|
|
212
230
|
if (!workspaceRoot) {
|
|
213
231
|
return void 0;
|
|
@@ -226,7 +244,7 @@ var init_config = __esm({
|
|
|
226
244
|
}
|
|
227
245
|
return void 0;
|
|
228
246
|
};
|
|
229
|
-
resolveLocalServerUrl = (startDir =
|
|
247
|
+
resolveLocalServerUrl = (startDir = process5.cwd()) => resolveLocalServerUrlFromEnv(process5.env) ?? resolveLocalServerUrlFromFiles(startDir);
|
|
230
248
|
loadProjectConfig = () => Effect3.tryPromise({
|
|
231
249
|
try: async () => {
|
|
232
250
|
const configPath = await findProjectConfigFile();
|
|
@@ -249,9 +267,9 @@ var init_config = __esm({
|
|
|
249
267
|
},
|
|
250
268
|
catch: () => void 0
|
|
251
269
|
}).pipe(Effect3.orElseSucceed(() => void 0));
|
|
252
|
-
resolveUserConfigWritePath = (startDir =
|
|
253
|
-
resolveProjectConfigWritePath = (startDir =
|
|
254
|
-
saveUserConfig = (config, startDir =
|
|
270
|
+
resolveUserConfigWritePath = (startDir = process5.cwd()) => findUserConfigFile(startDir) ?? join3(startDir, USER_CONFIG_FILENAME);
|
|
271
|
+
resolveProjectConfigWritePath = (startDir = process5.cwd()) => findProjectConfigFile(startDir) ?? join3(startDir, PROJECT_CONFIG_FILENAME);
|
|
272
|
+
saveUserConfig = (config, startDir = process5.cwd()) => {
|
|
255
273
|
const targetPath = resolveUserConfigWritePath(startDir);
|
|
256
274
|
return pipe3(
|
|
257
275
|
Effect3.tryPromise({
|
|
@@ -267,7 +285,7 @@ var init_config = __esm({
|
|
|
267
285
|
})
|
|
268
286
|
);
|
|
269
287
|
};
|
|
270
|
-
saveProjectConfig = (config, startDir =
|
|
288
|
+
saveProjectConfig = (config, startDir = process5.cwd()) => {
|
|
271
289
|
const targetPath = resolveProjectConfigWritePath(startDir);
|
|
272
290
|
return pipe3(
|
|
273
291
|
Effect3.tryPromise({
|
|
@@ -343,11 +361,17 @@ var init_config = __esm({
|
|
|
343
361
|
merged.token = config.token;
|
|
344
362
|
}
|
|
345
363
|
};
|
|
364
|
+
applyGlobalConfigSource = (merged, config) => {
|
|
365
|
+
const serverUrl = resolveServerUrlFromConfig(config);
|
|
366
|
+
if (serverUrl) {
|
|
367
|
+
merged.serverUrl = serverUrl;
|
|
368
|
+
}
|
|
369
|
+
};
|
|
346
370
|
applyEnvOverrides = (merged) => {
|
|
347
|
-
if (
|
|
348
|
-
merged.token =
|
|
371
|
+
if (process5.env.BRAID_API_KEY) {
|
|
372
|
+
merged.token = process5.env.BRAID_API_KEY;
|
|
349
373
|
}
|
|
350
|
-
const envServerUrl =
|
|
374
|
+
const envServerUrl = process5.env.BRAID_SKILLS_SERVER_URL ?? process5.env.BRAID_SERVER_URL;
|
|
351
375
|
if (envServerUrl && isValidServerUrl(envServerUrl)) {
|
|
352
376
|
merged.serverUrl = envServerUrl;
|
|
353
377
|
}
|
|
@@ -367,6 +391,7 @@ var init_config = __esm({
|
|
|
367
391
|
}),
|
|
368
392
|
Effect3.map(({ projectConfig, userConfig, globalConfig }) => {
|
|
369
393
|
const merged = createDefaultMergedConfig();
|
|
394
|
+
applyGlobalConfigSource(merged, globalConfig);
|
|
370
395
|
applyConfigSource(merged, projectConfig);
|
|
371
396
|
applyConfigSource(merged, userConfig);
|
|
372
397
|
applyEnvOverrides(merged);
|
|
@@ -402,7 +427,7 @@ var init_config = __esm({
|
|
|
402
427
|
})
|
|
403
428
|
);
|
|
404
429
|
getApiKey = () => pipe3(
|
|
405
|
-
Effect3.succeed(
|
|
430
|
+
Effect3.succeed(process5.env.BRAID_API_KEY),
|
|
406
431
|
Effect3.flatMap(
|
|
407
432
|
(envKey) => envKey ? Effect3.succeed(envKey) : pipe3(
|
|
408
433
|
loadUserConfig(),
|
|
@@ -420,7 +445,7 @@ var init_config = __esm({
|
|
|
420
445
|
Effect3.flatMap((config) => saveConfig({ ...config, apiKey }))
|
|
421
446
|
);
|
|
422
447
|
getServerUrl = () => pipe3(
|
|
423
|
-
Effect3.succeed(
|
|
448
|
+
Effect3.succeed(process5.env.BRAID_SERVER_URL),
|
|
424
449
|
Effect3.flatMap(
|
|
425
450
|
(envUrl) => envUrl ? Effect3.succeed(envUrl) : pipe3(
|
|
426
451
|
loadUserConfig(),
|
|
@@ -478,8 +503,13 @@ var init_config = __esm({
|
|
|
478
503
|
saveProjectConfigAsync = (config, startDir) => Effect3.runPromise(saveProjectConfig(config, startDir));
|
|
479
504
|
getApiKeyAsync = () => Effect3.runPromise(getApiKey());
|
|
480
505
|
setApiKeyAsync = (apiKey) => Effect3.runPromise(setApiKey(apiKey));
|
|
481
|
-
persistApiKeyAsync = async (apiKey) => {
|
|
482
|
-
await
|
|
506
|
+
persistApiKeyAsync = async (apiKey, serverUrl) => {
|
|
507
|
+
const config = await loadConfigAsync();
|
|
508
|
+
await saveConfigAsync({
|
|
509
|
+
...config,
|
|
510
|
+
apiKey,
|
|
511
|
+
...serverUrl ? { serverUrl } : {}
|
|
512
|
+
});
|
|
483
513
|
const existingUserConfig = await loadUserConfigAsync();
|
|
484
514
|
if (existingUserConfig?.token) {
|
|
485
515
|
await saveUserConfigAsync({ ...existingUserConfig, token: apiKey });
|
|
@@ -493,88 +523,226 @@ var init_config = __esm({
|
|
|
493
523
|
}
|
|
494
524
|
});
|
|
495
525
|
|
|
496
|
-
// src/lib/
|
|
497
|
-
import {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
526
|
+
// src/lib/device-auth.ts
|
|
527
|
+
import { execFile } from "child_process";
|
|
528
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
529
|
+
import { hostname, platform } from "os";
|
|
530
|
+
import { join as join4 } from "path";
|
|
531
|
+
import process6 from "process";
|
|
532
|
+
function resolveAuthWebBaseUrl(serverUrl) {
|
|
533
|
+
const canonicalBaseUrl = resolveCanonicalAuthWebBaseUrl(serverUrl);
|
|
534
|
+
try {
|
|
535
|
+
const url = new URL(canonicalBaseUrl);
|
|
536
|
+
const localAuthBaseUrl = resolveLocalAuthWebBaseUrl();
|
|
537
|
+
if (localAuthBaseUrl && (DEFAULT_BRAID_AUTH_HOSTS.has(url.hostname) || isLoopbackHost(url.hostname))) {
|
|
538
|
+
return localAuthBaseUrl;
|
|
539
|
+
}
|
|
540
|
+
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
541
|
+
} catch {
|
|
542
|
+
return canonicalBaseUrl;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
function buildAuthVerificationUrlFromBaseUrl(authBaseUrl, userCode) {
|
|
546
|
+
return `${authBaseUrl.replace(TRAILING_SLASHES2, "")}/cli/authorize?user_code=${encodeURIComponent(userCode)}`;
|
|
547
|
+
}
|
|
548
|
+
async function fetchAuthConfigFromBaseUrl(authBaseUrl) {
|
|
549
|
+
const headers = mergeAutomationHeaders();
|
|
550
|
+
const authConfigUrl = `${authBaseUrl}/api/cli/auth-config`;
|
|
551
|
+
const response = headers ? await fetch(authConfigUrl, { headers }) : await fetch(authConfigUrl);
|
|
552
|
+
if (!response.ok) {
|
|
553
|
+
const body = await response.text();
|
|
554
|
+
throw new Error(
|
|
555
|
+
`Failed to fetch auth config (${response.status}): ${body}`
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
return {
|
|
559
|
+
...await response.json(),
|
|
560
|
+
verificationBaseUrl: authBaseUrl
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
async function fetchAuthConfig(serverUrl) {
|
|
564
|
+
const authBaseUrl = resolveAuthWebBaseUrl(serverUrl).replace(
|
|
565
|
+
TRAILING_SLASHES2,
|
|
566
|
+
""
|
|
567
|
+
);
|
|
568
|
+
const canonicalAuthBaseUrl = resolveCanonicalAuthWebBaseUrl(
|
|
569
|
+
serverUrl
|
|
570
|
+
).replace(TRAILING_SLASHES2, "");
|
|
571
|
+
try {
|
|
572
|
+
return await fetchAuthConfigFromBaseUrl(authBaseUrl);
|
|
573
|
+
} catch (error) {
|
|
574
|
+
if (authBaseUrl !== canonicalAuthBaseUrl && isHostedBraidAuthServer(serverUrl)) {
|
|
575
|
+
return fetchAuthConfigFromBaseUrl(canonicalAuthBaseUrl);
|
|
576
|
+
}
|
|
577
|
+
throw error;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
async function initiateDeviceAuth(convexSiteUrl, deviceInfo) {
|
|
581
|
+
const url = `${convexSiteUrl.replace(TRAILING_SLASHES2, "")}/api/cli/device/authorize`;
|
|
582
|
+
const response = await fetch(url, {
|
|
583
|
+
method: "POST",
|
|
584
|
+
headers: mergeAutomationHeaders({
|
|
585
|
+
"Content-Type": "application/json"
|
|
586
|
+
}),
|
|
587
|
+
body: JSON.stringify(deviceInfo)
|
|
588
|
+
});
|
|
589
|
+
if (!response.ok) {
|
|
590
|
+
const body = await response.text();
|
|
591
|
+
throw new Error(
|
|
592
|
+
`Failed to initiate device authorization (${response.status}): ${body}`
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
return response.json();
|
|
596
|
+
}
|
|
597
|
+
async function pollForSession(convexSiteUrl, deviceCode, interval, expiresIn, timeoutSeconds) {
|
|
598
|
+
const tokenUrl = `${convexSiteUrl.replace(TRAILING_SLASHES2, "")}/api/cli/device/token`;
|
|
599
|
+
const deadline = Date.now() + Math.min(expiresIn, timeoutSeconds) * 1e3;
|
|
600
|
+
let currentInterval = interval;
|
|
601
|
+
while (Date.now() < deadline) {
|
|
602
|
+
await sleep(currentInterval * 1e3);
|
|
603
|
+
const response = await fetch(tokenUrl, {
|
|
604
|
+
method: "POST",
|
|
605
|
+
headers: mergeAutomationHeaders({
|
|
606
|
+
"Content-Type": "application/json"
|
|
607
|
+
}),
|
|
608
|
+
body: JSON.stringify({ device_code: deviceCode })
|
|
609
|
+
});
|
|
610
|
+
if (response.ok) {
|
|
611
|
+
const result = await response.json();
|
|
612
|
+
return {
|
|
613
|
+
sessionToken: result.session_token,
|
|
614
|
+
expiresAt: result.expires_at,
|
|
615
|
+
user: result.user
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
let errorCode;
|
|
619
|
+
try {
|
|
620
|
+
const errorBody = await response.json();
|
|
621
|
+
errorCode = errorBody.error;
|
|
622
|
+
} catch {
|
|
623
|
+
throw new Error(`Device auth polling error: HTTP ${response.status}`);
|
|
624
|
+
}
|
|
625
|
+
if (errorCode === "authorization_pending") {
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
if (errorCode === "slow_down") {
|
|
629
|
+
currentInterval += 5;
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
if (errorCode === "expired_token") {
|
|
633
|
+
throw new DeviceAuthExpiredError();
|
|
634
|
+
}
|
|
635
|
+
if (errorCode === "access_denied") {
|
|
636
|
+
throw new DeviceAuthDeniedError();
|
|
637
|
+
}
|
|
638
|
+
throw new Error(
|
|
639
|
+
`Device auth polling error: ${errorCode ?? `HTTP ${response.status}`}`
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
throw new DeviceAuthTimeoutError();
|
|
643
|
+
}
|
|
644
|
+
async function fetchSessionInfo(convexSiteUrl, sessionToken) {
|
|
645
|
+
const url = `${convexSiteUrl.replace(TRAILING_SLASHES2, "")}/api/cli/sessions/me`;
|
|
646
|
+
const response = await fetch(url, {
|
|
647
|
+
method: "GET",
|
|
648
|
+
headers: mergeAutomationHeaders({
|
|
649
|
+
Authorization: `Bearer ${sessionToken}`
|
|
650
|
+
})
|
|
651
|
+
});
|
|
652
|
+
if (response.status === 404) {
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
if (!response.ok) {
|
|
656
|
+
const body = await response.text();
|
|
657
|
+
throw new Error(
|
|
658
|
+
`Failed to fetch session info (${response.status}): ${body}`
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
return response.json();
|
|
662
|
+
}
|
|
663
|
+
async function revokeSession(convexSiteUrl, sessionToken) {
|
|
664
|
+
const url = `${convexSiteUrl.replace(TRAILING_SLASHES2, "")}/api/cli/sessions/me`;
|
|
665
|
+
const response = await fetch(url, {
|
|
666
|
+
method: "DELETE",
|
|
667
|
+
headers: mergeAutomationHeaders({
|
|
668
|
+
Authorization: `Bearer ${sessionToken}`
|
|
669
|
+
})
|
|
670
|
+
});
|
|
671
|
+
if (response.status === 404) {
|
|
672
|
+
return false;
|
|
673
|
+
}
|
|
674
|
+
if (!response.ok) {
|
|
675
|
+
const body = await response.text();
|
|
676
|
+
throw new Error(`Failed to revoke session (${response.status}): ${body}`);
|
|
677
|
+
}
|
|
678
|
+
return true;
|
|
679
|
+
}
|
|
680
|
+
function openBrowser(url) {
|
|
681
|
+
if (process6.env.BRAID_DISABLE_BROWSER_OPEN === "1" || process6.env.BRAID_DISABLE_BROWSER_OPEN === "true") {
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
const currentPlatform = platform();
|
|
685
|
+
if (currentPlatform === "darwin") {
|
|
686
|
+
execFile("open", [url], noop);
|
|
687
|
+
} else if (currentPlatform === "win32") {
|
|
688
|
+
execFile("cmd", ["/c", "start", "", url], noop);
|
|
689
|
+
} else {
|
|
690
|
+
execFile("xdg-open", [url], noop);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
function getDeviceInfo() {
|
|
694
|
+
return {
|
|
695
|
+
deviceName: hostname(),
|
|
696
|
+
deviceOs: platform(),
|
|
697
|
+
deviceHostname: hostname()
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
var TRAILING_SLASHES2, LEGACY_BRAID_AUTH_HOSTS, BRAID_APP_HOST, DEFAULT_BRAID_AUTH_HOSTS, LOOPBACK_HOSTS2, LOCAL_AUTH_ENV_FILES, LOCAL_AUTH_ENV_KEYS, NEWLINE_REGEX2, DeviceAuthTimeoutError, DeviceAuthDeniedError, DeviceAuthExpiredError, sleep, normalizeBaseUrl2, normalizeLoopbackBaseUrl, isLoopbackHost, isLoopbackUrl, stripQuotes2, parseDotenv2, resolveLocalAuthWebBaseUrlFromEnv, resolveLocalAuthWebBaseUrlFromFiles, resolveLocalAuthWebBaseUrl, normalizeServerBaseUrl, resolveCanonicalAuthWebBaseUrl, isHostedBraidAuthServer, noop;
|
|
701
|
+
var init_device_auth = __esm({
|
|
702
|
+
"src/lib/device-auth.ts"() {
|
|
501
703
|
"use strict";
|
|
502
704
|
init_esm_shims();
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
705
|
+
init_automation_headers();
|
|
706
|
+
init_braid_workspace();
|
|
707
|
+
TRAILING_SLASHES2 = /\/+$/;
|
|
708
|
+
LEGACY_BRAID_AUTH_HOSTS = /* @__PURE__ */ new Set([
|
|
709
|
+
"api.braid.cloud",
|
|
710
|
+
"braid.cloud",
|
|
711
|
+
"www.braid.cloud"
|
|
712
|
+
]);
|
|
713
|
+
BRAID_APP_HOST = "app.braid.cloud";
|
|
714
|
+
DEFAULT_BRAID_AUTH_HOSTS = /* @__PURE__ */ new Set([
|
|
715
|
+
...LEGACY_BRAID_AUTH_HOSTS,
|
|
716
|
+
BRAID_APP_HOST
|
|
717
|
+
]);
|
|
718
|
+
LOOPBACK_HOSTS2 = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "localhost"]);
|
|
719
|
+
LOCAL_AUTH_ENV_FILES = [
|
|
720
|
+
["apps", "web", ".env.local"],
|
|
721
|
+
["apps", "convex", ".env.local"]
|
|
722
|
+
];
|
|
723
|
+
LOCAL_AUTH_ENV_KEYS = ["APP_URL", "SITE_URL"];
|
|
724
|
+
NEWLINE_REGEX2 = /\r?\n/;
|
|
725
|
+
DeviceAuthTimeoutError = class extends Error {
|
|
726
|
+
constructor() {
|
|
727
|
+
super("Device authorization timed out");
|
|
728
|
+
this.name = "DeviceAuthTimeoutError";
|
|
522
729
|
}
|
|
523
730
|
};
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
NetworkError = class extends Data3.TaggedError("NetworkError") {
|
|
529
|
-
};
|
|
530
|
-
resolveApiKey = (optionsApiKey) => {
|
|
531
|
-
if (optionsApiKey) {
|
|
532
|
-
return Effect4.succeed(optionsApiKey);
|
|
731
|
+
DeviceAuthDeniedError = class extends Error {
|
|
732
|
+
constructor() {
|
|
733
|
+
super("Device authorization was denied");
|
|
734
|
+
this.name = "DeviceAuthDeniedError";
|
|
533
735
|
}
|
|
534
|
-
return pipe4(
|
|
535
|
-
Effect4.tryPromise({
|
|
536
|
-
try: () => getApiKeyAsync(),
|
|
537
|
-
catch: () => new NetworkError({ message: "Failed to read config" })
|
|
538
|
-
}),
|
|
539
|
-
Effect4.flatMap(
|
|
540
|
-
(key) => key ? Effect4.succeed(key) : Effect4.fail(
|
|
541
|
-
new AuthenticationError({
|
|
542
|
-
message: 'No API key configured. Run "braid auth" to authenticate.'
|
|
543
|
-
})
|
|
544
|
-
)
|
|
545
|
-
)
|
|
546
|
-
);
|
|
547
736
|
};
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
new NetworkError({
|
|
553
|
-
message: `Untrusted server URL '${optionsServerUrl}'. Set ${ALLOW_UNTRUSTED_SERVER_ENV}=true to override.`
|
|
554
|
-
})
|
|
555
|
-
);
|
|
556
|
-
}
|
|
557
|
-
return Effect4.succeed(optionsServerUrl);
|
|
737
|
+
DeviceAuthExpiredError = class extends Error {
|
|
738
|
+
constructor() {
|
|
739
|
+
super("Device authorization code has expired");
|
|
740
|
+
this.name = "DeviceAuthExpiredError";
|
|
558
741
|
}
|
|
559
|
-
return pipe4(
|
|
560
|
-
Effect4.tryPromise({
|
|
561
|
-
try: () => getServerUrlAsync(),
|
|
562
|
-
catch: () => new NetworkError({ message: "Failed to read config" })
|
|
563
|
-
}),
|
|
564
|
-
Effect4.flatMap((serverUrl) => {
|
|
565
|
-
if (isTruthy(process.env[ALLOW_UNTRUSTED_SERVER_ENV]) || isTrustedApiServerUrl(serverUrl)) {
|
|
566
|
-
return Effect4.succeed(serverUrl);
|
|
567
|
-
}
|
|
568
|
-
return Effect4.fail(
|
|
569
|
-
new NetworkError({
|
|
570
|
-
message: `Untrusted server URL '${serverUrl}'. Set ${ALLOW_UNTRUSTED_SERVER_ENV}=true to override.`
|
|
571
|
-
})
|
|
572
|
-
);
|
|
573
|
-
})
|
|
574
|
-
);
|
|
575
742
|
};
|
|
576
|
-
|
|
577
|
-
|
|
743
|
+
sleep = (ms) => new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
744
|
+
normalizeBaseUrl2 = (rawUrl) => {
|
|
745
|
+
const trimmed = rawUrl.replace(TRAILING_SLASHES2, "");
|
|
578
746
|
try {
|
|
579
747
|
const url = new URL(trimmed);
|
|
580
748
|
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
@@ -582,13 +750,295 @@ var init_api = __esm({
|
|
|
582
750
|
return trimmed;
|
|
583
751
|
}
|
|
584
752
|
};
|
|
753
|
+
normalizeLoopbackBaseUrl = (rawUrl) => {
|
|
754
|
+
const normalized = normalizeBaseUrl2(rawUrl);
|
|
755
|
+
try {
|
|
756
|
+
const url = new URL(normalized);
|
|
757
|
+
if (isLoopbackHost(url.hostname)) {
|
|
758
|
+
url.hostname = "localhost";
|
|
759
|
+
}
|
|
760
|
+
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
761
|
+
} catch {
|
|
762
|
+
return normalized;
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
isLoopbackHost = (hostname2) => LOOPBACK_HOSTS2.has(hostname2);
|
|
766
|
+
isLoopbackUrl = (rawUrl) => {
|
|
767
|
+
try {
|
|
768
|
+
return isLoopbackHost(new URL(rawUrl).hostname);
|
|
769
|
+
} catch {
|
|
770
|
+
return false;
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
stripQuotes2 = (value) => {
|
|
774
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
775
|
+
return value.slice(1, -1);
|
|
776
|
+
}
|
|
777
|
+
return value;
|
|
778
|
+
};
|
|
779
|
+
parseDotenv2 = (content) => {
|
|
780
|
+
const result = {};
|
|
781
|
+
for (const rawLine of content.split(NEWLINE_REGEX2)) {
|
|
782
|
+
const line = rawLine.trim();
|
|
783
|
+
if (!line || line.startsWith("#")) {
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
const separatorIndex = line.indexOf("=");
|
|
787
|
+
if (separatorIndex <= 0) {
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
const key = line.slice(0, separatorIndex).trim();
|
|
791
|
+
const value = line.slice(separatorIndex + 1).trim();
|
|
792
|
+
result[key] = stripQuotes2(value);
|
|
793
|
+
}
|
|
794
|
+
return result;
|
|
795
|
+
};
|
|
796
|
+
resolveLocalAuthWebBaseUrlFromEnv = (env) => {
|
|
797
|
+
for (const key of LOCAL_AUTH_ENV_KEYS) {
|
|
798
|
+
const value = env[key];
|
|
799
|
+
if (value && isLoopbackUrl(value)) {
|
|
800
|
+
return normalizeLoopbackBaseUrl(value);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
return void 0;
|
|
804
|
+
};
|
|
805
|
+
resolveLocalAuthWebBaseUrlFromFiles = () => {
|
|
806
|
+
const workspaceRoot = findBraidWorkspaceRoot();
|
|
807
|
+
if (!workspaceRoot) {
|
|
808
|
+
return void 0;
|
|
809
|
+
}
|
|
810
|
+
for (const envFile of LOCAL_AUTH_ENV_FILES) {
|
|
811
|
+
const envPath = join4(workspaceRoot, ...envFile);
|
|
812
|
+
if (!existsSync3(envPath)) {
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
const localAppUrl = resolveLocalAuthWebBaseUrlFromEnv(
|
|
816
|
+
parseDotenv2(readFileSync3(envPath, "utf8"))
|
|
817
|
+
);
|
|
818
|
+
if (localAppUrl) {
|
|
819
|
+
return localAppUrl;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
return void 0;
|
|
823
|
+
};
|
|
824
|
+
resolveLocalAuthWebBaseUrl = () => resolveLocalAuthWebBaseUrlFromEnv(process6.env) ?? resolveLocalAuthWebBaseUrlFromFiles();
|
|
825
|
+
normalizeServerBaseUrl = (serverUrl) => {
|
|
826
|
+
const trimmed = normalizeBaseUrl2(serverUrl);
|
|
827
|
+
try {
|
|
828
|
+
const url = new URL(trimmed);
|
|
829
|
+
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
830
|
+
} catch {
|
|
831
|
+
return trimmed;
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
resolveCanonicalAuthWebBaseUrl = (serverUrl) => {
|
|
835
|
+
const normalized = normalizeServerBaseUrl(serverUrl);
|
|
836
|
+
try {
|
|
837
|
+
const url = new URL(normalized);
|
|
838
|
+
if (LEGACY_BRAID_AUTH_HOSTS.has(url.hostname)) {
|
|
839
|
+
url.hostname = BRAID_APP_HOST;
|
|
840
|
+
url.pathname = "/";
|
|
841
|
+
}
|
|
842
|
+
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
843
|
+
} catch {
|
|
844
|
+
return normalized;
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
isHostedBraidAuthServer = (serverUrl) => {
|
|
848
|
+
try {
|
|
849
|
+
return DEFAULT_BRAID_AUTH_HOSTS.has(
|
|
850
|
+
new URL(normalizeServerBaseUrl(serverUrl)).hostname
|
|
851
|
+
);
|
|
852
|
+
} catch {
|
|
853
|
+
return false;
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
noop = () => {
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
});
|
|
860
|
+
|
|
861
|
+
// src/lib/api.ts
|
|
862
|
+
import { Data as Data3, Effect as Effect4, pipe as pipe4 } from "effect";
|
|
863
|
+
var TRAILING_SLASH_REGEX, ALLOW_UNTRUSTED_SERVER_ENV, SESSION_TOKEN_PREFIX, isTruthy, isLocalHost, isConvexSiteHost, isTrustedApiServerUrl, isSessionApiServerUrl, REAUTH_REQUIRED_MESSAGE, RAW_AUTH_ERROR_PATTERN, normalizeAuthenticationErrorMessage, ApiError, AuthenticationError, NetworkError, resolveApiKey, resolveServerUrl, resolveApiRequestServerUrl, normalizeApiServerBaseUrl, readJsonResponseAsync, readJsonResponse, getApiErrorResponse, isAuthenticationErrorResponse, parseResponse, buildApiUrl, buildExportUrl, executeApiRequest, parseScopeOptionsResponse, fetchScopeOptions, buildLibraryOptionsUrl, fetchLibraryOptions, fetchSkills, runLifecycleCommand, DEFAULT_PUBLIC_SERVER_URL, NotFoundError, RateLimitedError, handlePublicApiResponse, fetchPublicMetadata, fetchPublicExport, fetchPublicMetadataAsync, fetchPublicExportAsync, validateApiKey, fetchSkillsAsync, validateApiKeyAsync, fetchScopeOptionsAsync, fetchLibraryOptionsAsync, runLifecycleCommandAsync;
|
|
864
|
+
var init_api = __esm({
|
|
865
|
+
"src/lib/api.ts"() {
|
|
866
|
+
"use strict";
|
|
867
|
+
init_esm_shims();
|
|
868
|
+
init_automation_headers();
|
|
869
|
+
init_config();
|
|
870
|
+
init_device_auth();
|
|
871
|
+
TRAILING_SLASH_REGEX = /\/$/;
|
|
872
|
+
ALLOW_UNTRUSTED_SERVER_ENV = "BRAID_ALLOW_UNTRUSTED_SERVER_URL";
|
|
873
|
+
SESSION_TOKEN_PREFIX = "brs_";
|
|
874
|
+
isTruthy = (value) => value === "1" || value === "true" || value === "yes";
|
|
875
|
+
isLocalHost = (hostname2) => hostname2 === "localhost" || hostname2 === "127.0.0.1" || hostname2 === "::1";
|
|
876
|
+
isConvexSiteHost = (hostname2) => hostname2.endsWith(".convex.site");
|
|
877
|
+
isTrustedApiServerUrl = (serverUrl) => {
|
|
878
|
+
try {
|
|
879
|
+
const parsed = new URL(serverUrl);
|
|
880
|
+
const hostname2 = parsed.hostname;
|
|
881
|
+
const isBraidHost = hostname2 === "braid.cloud" || hostname2.endsWith(".braid.cloud");
|
|
882
|
+
const isConvexSite = isConvexSiteHost(hostname2);
|
|
883
|
+
if (parsed.protocol === "https:" && (isBraidHost || isConvexSite)) {
|
|
884
|
+
return true;
|
|
885
|
+
}
|
|
886
|
+
if (parsed.protocol === "http:" && isLocalHost(hostname2)) {
|
|
887
|
+
return true;
|
|
888
|
+
}
|
|
889
|
+
return false;
|
|
890
|
+
} catch {
|
|
891
|
+
return false;
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
isSessionApiServerUrl = (serverUrl) => {
|
|
895
|
+
try {
|
|
896
|
+
const hostname2 = new URL(serverUrl).hostname;
|
|
897
|
+
return isConvexSiteHost(hostname2) || isLocalHost(hostname2);
|
|
898
|
+
} catch {
|
|
899
|
+
return false;
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
REAUTH_REQUIRED_MESSAGE = "Invalid or expired API key. Run 'braid auth' to re-authenticate.";
|
|
903
|
+
RAW_AUTH_ERROR_PATTERN = /invalid authentication token|authentication token expired|token expired|not authenticated/i;
|
|
904
|
+
normalizeAuthenticationErrorMessage = (message) => {
|
|
905
|
+
if (!message || RAW_AUTH_ERROR_PATTERN.test(message)) {
|
|
906
|
+
return REAUTH_REQUIRED_MESSAGE;
|
|
907
|
+
}
|
|
908
|
+
return message;
|
|
909
|
+
};
|
|
910
|
+
ApiError = class extends Data3.TaggedError("ApiError") {
|
|
911
|
+
};
|
|
912
|
+
AuthenticationError = class extends Data3.TaggedError("AuthenticationError") {
|
|
913
|
+
};
|
|
914
|
+
NetworkError = class extends Data3.TaggedError("NetworkError") {
|
|
915
|
+
};
|
|
916
|
+
resolveApiKey = (optionsApiKey) => {
|
|
917
|
+
if (optionsApiKey) {
|
|
918
|
+
return Effect4.succeed(optionsApiKey);
|
|
919
|
+
}
|
|
920
|
+
return pipe4(
|
|
921
|
+
Effect4.tryPromise({
|
|
922
|
+
try: () => getApiKeyAsync(),
|
|
923
|
+
catch: () => new NetworkError({ message: "Failed to read config" })
|
|
924
|
+
}),
|
|
925
|
+
Effect4.flatMap(
|
|
926
|
+
(key) => key ? Effect4.succeed(key) : Effect4.fail(
|
|
927
|
+
new AuthenticationError({
|
|
928
|
+
message: 'No API key configured. Run "braid auth" to authenticate.'
|
|
929
|
+
})
|
|
930
|
+
)
|
|
931
|
+
)
|
|
932
|
+
);
|
|
933
|
+
};
|
|
934
|
+
resolveServerUrl = (optionsServerUrl) => {
|
|
935
|
+
if (optionsServerUrl) {
|
|
936
|
+
if (!(isTruthy(process.env[ALLOW_UNTRUSTED_SERVER_ENV]) || isTrustedApiServerUrl(optionsServerUrl))) {
|
|
937
|
+
return Effect4.fail(
|
|
938
|
+
new NetworkError({
|
|
939
|
+
message: `Untrusted server URL '${optionsServerUrl}'. Set ${ALLOW_UNTRUSTED_SERVER_ENV}=true to override.`
|
|
940
|
+
})
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
return Effect4.succeed(optionsServerUrl);
|
|
944
|
+
}
|
|
945
|
+
return pipe4(
|
|
946
|
+
Effect4.tryPromise({
|
|
947
|
+
try: () => getServerUrlAsync(),
|
|
948
|
+
catch: () => new NetworkError({ message: "Failed to read config" })
|
|
949
|
+
}),
|
|
950
|
+
Effect4.flatMap((serverUrl) => {
|
|
951
|
+
if (isTruthy(process.env[ALLOW_UNTRUSTED_SERVER_ENV]) || isTrustedApiServerUrl(serverUrl)) {
|
|
952
|
+
return Effect4.succeed(serverUrl);
|
|
953
|
+
}
|
|
954
|
+
return Effect4.fail(
|
|
955
|
+
new NetworkError({
|
|
956
|
+
message: `Untrusted server URL '${serverUrl}'. Set ${ALLOW_UNTRUSTED_SERVER_ENV}=true to override.`
|
|
957
|
+
})
|
|
958
|
+
);
|
|
959
|
+
})
|
|
960
|
+
);
|
|
961
|
+
};
|
|
962
|
+
resolveApiRequestServerUrl = (serverUrl, apiKey) => {
|
|
963
|
+
if (!apiKey?.startsWith(SESSION_TOKEN_PREFIX)) {
|
|
964
|
+
return Effect4.succeed(serverUrl);
|
|
965
|
+
}
|
|
966
|
+
if (isSessionApiServerUrl(serverUrl)) {
|
|
967
|
+
return Effect4.succeed(serverUrl);
|
|
968
|
+
}
|
|
969
|
+
return pipe4(
|
|
970
|
+
Effect4.tryPromise({
|
|
971
|
+
try: async () => {
|
|
972
|
+
const authConfig = await fetchAuthConfig(serverUrl);
|
|
973
|
+
return authConfig.convexSiteUrl.replace(TRAILING_SLASH_REGEX, "");
|
|
974
|
+
},
|
|
975
|
+
catch: (cause) => new NetworkError({
|
|
976
|
+
message: `Failed to resolve session API server for ${serverUrl}`,
|
|
977
|
+
cause
|
|
978
|
+
})
|
|
979
|
+
}),
|
|
980
|
+
Effect4.flatMap((resolvedServerUrl) => {
|
|
981
|
+
if (isTruthy(process.env[ALLOW_UNTRUSTED_SERVER_ENV]) || isTrustedApiServerUrl(resolvedServerUrl)) {
|
|
982
|
+
return Effect4.succeed(resolvedServerUrl);
|
|
983
|
+
}
|
|
984
|
+
return Effect4.fail(
|
|
985
|
+
new NetworkError({
|
|
986
|
+
message: `Untrusted server URL '${resolvedServerUrl}'. Set ${ALLOW_UNTRUSTED_SERVER_ENV}=true to override.`
|
|
987
|
+
})
|
|
988
|
+
);
|
|
989
|
+
})
|
|
990
|
+
);
|
|
991
|
+
};
|
|
992
|
+
normalizeApiServerBaseUrl = (serverUrl) => {
|
|
993
|
+
const trimmed = serverUrl.replace(TRAILING_SLASH_REGEX, "");
|
|
994
|
+
try {
|
|
995
|
+
const url = new URL(trimmed);
|
|
996
|
+
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
997
|
+
} catch {
|
|
998
|
+
return trimmed;
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
readJsonResponseAsync = async (response) => {
|
|
1002
|
+
const raw = await response.text();
|
|
1003
|
+
if (raw.trim().length === 0) {
|
|
1004
|
+
if (response.ok) {
|
|
1005
|
+
throw new Error("Empty API response");
|
|
1006
|
+
}
|
|
1007
|
+
return null;
|
|
1008
|
+
}
|
|
1009
|
+
try {
|
|
1010
|
+
return JSON.parse(raw);
|
|
1011
|
+
} catch (error) {
|
|
1012
|
+
if (!response.ok) {
|
|
1013
|
+
return null;
|
|
1014
|
+
}
|
|
1015
|
+
throw error;
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
1018
|
+
readJsonResponse = (response) => Effect4.tryPromise({
|
|
1019
|
+
try: () => readJsonResponseAsync(response),
|
|
1020
|
+
catch: () => new NetworkError({ message: "Failed to parse API response" })
|
|
1021
|
+
});
|
|
1022
|
+
getApiErrorResponse = (json) => {
|
|
1023
|
+
if (typeof json !== "object" || json === null || Array.isArray(json)) {
|
|
1024
|
+
return {};
|
|
1025
|
+
}
|
|
1026
|
+
return json;
|
|
1027
|
+
};
|
|
1028
|
+
isAuthenticationErrorResponse = (response, json) => {
|
|
1029
|
+
if (response.status === 401) {
|
|
1030
|
+
return true;
|
|
1031
|
+
}
|
|
1032
|
+
const errorResponse = getApiErrorResponse(json);
|
|
1033
|
+
return RAW_AUTH_ERROR_PATTERN.test(errorResponse.error ?? "");
|
|
1034
|
+
};
|
|
585
1035
|
parseResponse = (response, json) => {
|
|
586
1036
|
if (!response.ok) {
|
|
587
|
-
const errorResponse = json;
|
|
588
|
-
if (response
|
|
1037
|
+
const errorResponse = getApiErrorResponse(json);
|
|
1038
|
+
if (isAuthenticationErrorResponse(response, json)) {
|
|
589
1039
|
return Effect4.fail(
|
|
590
1040
|
new AuthenticationError({
|
|
591
|
-
message: errorResponse.error
|
|
1041
|
+
message: normalizeAuthenticationErrorMessage(errorResponse.error)
|
|
592
1042
|
})
|
|
593
1043
|
);
|
|
594
1044
|
}
|
|
@@ -647,10 +1097,10 @@ var init_api = __esm({
|
|
|
647
1097
|
Effect4.tryPromise({
|
|
648
1098
|
try: () => fetch(url.toString(), {
|
|
649
1099
|
method: "GET",
|
|
650
|
-
headers: {
|
|
1100
|
+
headers: mergeAutomationHeaders({
|
|
651
1101
|
"Content-Type": "application/json",
|
|
652
1102
|
...apiKey ? { Authorization: `Bearer ${apiKey}` } : {}
|
|
653
|
-
}
|
|
1103
|
+
})
|
|
654
1104
|
}),
|
|
655
1105
|
catch: (e) => new NetworkError({
|
|
656
1106
|
message: `Failed to connect to ${serverUrl}`,
|
|
@@ -660,7 +1110,7 @@ var init_api = __esm({
|
|
|
660
1110
|
Effect4.flatMap(
|
|
661
1111
|
(response) => pipe4(
|
|
662
1112
|
Effect4.tryPromise({
|
|
663
|
-
try: () => response
|
|
1113
|
+
try: () => readJsonResponseAsync(response),
|
|
664
1114
|
catch: () => new NetworkError({ message: "Failed to parse API response" })
|
|
665
1115
|
}),
|
|
666
1116
|
Effect4.flatMap((json) => parseResponse(response, json))
|
|
@@ -669,11 +1119,11 @@ var init_api = __esm({
|
|
|
669
1119
|
);
|
|
670
1120
|
parseScopeOptionsResponse = (response, json) => {
|
|
671
1121
|
if (!response.ok) {
|
|
672
|
-
const errorResponse = json;
|
|
673
|
-
if (response
|
|
1122
|
+
const errorResponse = getApiErrorResponse(json);
|
|
1123
|
+
if (isAuthenticationErrorResponse(response, json)) {
|
|
674
1124
|
return Effect4.fail(
|
|
675
1125
|
new AuthenticationError({
|
|
676
|
-
message: errorResponse.error
|
|
1126
|
+
message: normalizeAuthenticationErrorMessage(errorResponse.error)
|
|
677
1127
|
})
|
|
678
1128
|
);
|
|
679
1129
|
}
|
|
@@ -692,33 +1142,37 @@ var init_api = __esm({
|
|
|
692
1142
|
apiKey: resolveApiKey(options.apiKey),
|
|
693
1143
|
serverUrl: resolveServerUrl(options.serverUrl)
|
|
694
1144
|
}),
|
|
695
|
-
Effect4.flatMap(
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
Effect4.
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
headers: {
|
|
702
|
-
Authorization: `Bearer ${apiKey}`,
|
|
703
|
-
"Content-Type": "application/json"
|
|
704
|
-
}
|
|
705
|
-
}),
|
|
706
|
-
catch: (e) => new NetworkError({
|
|
707
|
-
message: `Failed to connect to ${serverUrl}`,
|
|
708
|
-
cause: e
|
|
709
|
-
})
|
|
710
|
-
}),
|
|
711
|
-
Effect4.flatMap(
|
|
712
|
-
(response) => pipe4(
|
|
1145
|
+
Effect4.flatMap(
|
|
1146
|
+
({ apiKey, serverUrl }) => pipe4(
|
|
1147
|
+
resolveApiRequestServerUrl(serverUrl, apiKey),
|
|
1148
|
+
Effect4.flatMap((apiServerUrl) => {
|
|
1149
|
+
const url = buildApiUrl(apiServerUrl, "/api/skills/scope-options");
|
|
1150
|
+
return pipe4(
|
|
713
1151
|
Effect4.tryPromise({
|
|
714
|
-
try: () =>
|
|
715
|
-
|
|
1152
|
+
try: () => fetch(url.toString(), {
|
|
1153
|
+
method: "GET",
|
|
1154
|
+
headers: mergeAutomationHeaders({
|
|
1155
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1156
|
+
"Content-Type": "application/json"
|
|
1157
|
+
})
|
|
1158
|
+
}),
|
|
1159
|
+
catch: (e) => new NetworkError({
|
|
1160
|
+
message: `Failed to connect to ${apiServerUrl}`,
|
|
1161
|
+
cause: e
|
|
1162
|
+
})
|
|
716
1163
|
}),
|
|
717
|
-
Effect4.flatMap(
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
1164
|
+
Effect4.flatMap(
|
|
1165
|
+
(response) => pipe4(
|
|
1166
|
+
readJsonResponse(response),
|
|
1167
|
+
Effect4.flatMap(
|
|
1168
|
+
(json) => parseScopeOptionsResponse(response, json)
|
|
1169
|
+
)
|
|
1170
|
+
)
|
|
1171
|
+
)
|
|
1172
|
+
);
|
|
1173
|
+
})
|
|
1174
|
+
)
|
|
1175
|
+
)
|
|
722
1176
|
);
|
|
723
1177
|
buildLibraryOptionsUrl = (serverUrl, options) => {
|
|
724
1178
|
const url = buildApiUrl(serverUrl, "/api/skills/library-options");
|
|
@@ -752,41 +1206,57 @@ var init_api = __esm({
|
|
|
752
1206
|
}),
|
|
753
1207
|
Effect4.flatMap(
|
|
754
1208
|
({ apiKey, serverUrl }) => pipe4(
|
|
755
|
-
|
|
756
|
-
try: () => fetch(buildLibraryOptionsUrl(serverUrl, options).toString(), {
|
|
757
|
-
method: "GET",
|
|
758
|
-
headers: {
|
|
759
|
-
Authorization: `Bearer ${apiKey}`,
|
|
760
|
-
"Content-Type": "application/json"
|
|
761
|
-
}
|
|
762
|
-
}),
|
|
763
|
-
catch: (e) => new NetworkError({
|
|
764
|
-
message: `Failed to connect to ${serverUrl}`,
|
|
765
|
-
cause: e
|
|
766
|
-
})
|
|
767
|
-
}),
|
|
1209
|
+
resolveApiRequestServerUrl(serverUrl, apiKey),
|
|
768
1210
|
Effect4.flatMap(
|
|
769
|
-
(
|
|
1211
|
+
(apiServerUrl) => pipe4(
|
|
770
1212
|
Effect4.tryPromise({
|
|
771
|
-
try: () =>
|
|
772
|
-
|
|
1213
|
+
try: () => fetch(
|
|
1214
|
+
buildLibraryOptionsUrl(apiServerUrl, options).toString(),
|
|
1215
|
+
{
|
|
1216
|
+
method: "GET",
|
|
1217
|
+
headers: mergeAutomationHeaders({
|
|
1218
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1219
|
+
"Content-Type": "application/json"
|
|
1220
|
+
})
|
|
1221
|
+
}
|
|
1222
|
+
),
|
|
1223
|
+
catch: (e) => new NetworkError({
|
|
1224
|
+
message: `Failed to connect to ${apiServerUrl}`,
|
|
1225
|
+
cause: e
|
|
1226
|
+
})
|
|
773
1227
|
}),
|
|
774
|
-
Effect4.flatMap(
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
1228
|
+
Effect4.flatMap(
|
|
1229
|
+
(response) => pipe4(
|
|
1230
|
+
readJsonResponse(response),
|
|
1231
|
+
Effect4.flatMap(
|
|
1232
|
+
(json) => {
|
|
1233
|
+
if (!response.ok) {
|
|
1234
|
+
return pipe4(
|
|
1235
|
+
parseResponse(response, json),
|
|
1236
|
+
Effect4.flatMap(
|
|
1237
|
+
() => Effect4.fail(
|
|
1238
|
+
new ApiError({
|
|
1239
|
+
message: "API request failed",
|
|
1240
|
+
code: "UNKNOWN_ERROR",
|
|
1241
|
+
status: response.status
|
|
1242
|
+
})
|
|
1243
|
+
)
|
|
1244
|
+
),
|
|
1245
|
+
Effect4.catchTag(
|
|
1246
|
+
"AuthenticationError",
|
|
1247
|
+
(error) => Effect4.fail(error)
|
|
1248
|
+
),
|
|
1249
|
+
Effect4.catchTag(
|
|
1250
|
+
"ApiError",
|
|
1251
|
+
(error) => Effect4.fail(error)
|
|
1252
|
+
)
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
return Effect4.succeed(json);
|
|
1256
|
+
}
|
|
1257
|
+
)
|
|
1258
|
+
)
|
|
1259
|
+
)
|
|
790
1260
|
)
|
|
791
1261
|
)
|
|
792
1262
|
)
|
|
@@ -797,10 +1267,15 @@ var init_api = __esm({
|
|
|
797
1267
|
apiKey: options.demo ? Effect4.succeed(options.apiKey) : resolveApiKey(options.apiKey),
|
|
798
1268
|
serverUrl: resolveServerUrl(options.serverUrl)
|
|
799
1269
|
}),
|
|
800
|
-
Effect4.flatMap(
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
1270
|
+
Effect4.flatMap(
|
|
1271
|
+
({ apiKey, serverUrl }) => pipe4(
|
|
1272
|
+
resolveApiRequestServerUrl(serverUrl, apiKey),
|
|
1273
|
+
Effect4.flatMap((apiServerUrl) => {
|
|
1274
|
+
const url = buildExportUrl(apiServerUrl, options);
|
|
1275
|
+
return executeApiRequest(url, apiKey, apiServerUrl);
|
|
1276
|
+
})
|
|
1277
|
+
)
|
|
1278
|
+
)
|
|
804
1279
|
);
|
|
805
1280
|
runLifecycleCommand = (request, options = {}) => pipe4(
|
|
806
1281
|
Effect4.all({
|
|
@@ -808,45 +1283,56 @@ var init_api = __esm({
|
|
|
808
1283
|
serverUrl: resolveServerUrl(options.serverUrl)
|
|
809
1284
|
}),
|
|
810
1285
|
Effect4.flatMap(
|
|
811
|
-
({ apiKey, serverUrl }) =>
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
{
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
1286
|
+
({ apiKey, serverUrl }) => pipe4(
|
|
1287
|
+
resolveApiRequestServerUrl(serverUrl, apiKey),
|
|
1288
|
+
Effect4.flatMap(
|
|
1289
|
+
(apiServerUrl) => Effect4.tryPromise({
|
|
1290
|
+
try: async () => {
|
|
1291
|
+
const response = await fetch(
|
|
1292
|
+
buildApiUrl(apiServerUrl, "/api/lifecycle").toString(),
|
|
1293
|
+
{
|
|
1294
|
+
method: "POST",
|
|
1295
|
+
headers: mergeAutomationHeaders({
|
|
1296
|
+
"Content-Type": "application/json",
|
|
1297
|
+
...apiKey ? { Authorization: `Bearer ${apiKey}` } : {}
|
|
1298
|
+
}),
|
|
1299
|
+
body: JSON.stringify({ ...request, demo: options.demo })
|
|
1300
|
+
}
|
|
1301
|
+
);
|
|
1302
|
+
const json = await readJsonResponseAsync(response).catch(() => {
|
|
1303
|
+
throw new NetworkError({
|
|
1304
|
+
message: "Failed to parse API response"
|
|
1305
|
+
});
|
|
1306
|
+
});
|
|
1307
|
+
if (!response.ok) {
|
|
1308
|
+
const errorResponse = getApiErrorResponse(json);
|
|
1309
|
+
if (isAuthenticationErrorResponse(response, json)) {
|
|
1310
|
+
throw new AuthenticationError({
|
|
1311
|
+
message: normalizeAuthenticationErrorMessage(
|
|
1312
|
+
errorResponse.error
|
|
1313
|
+
)
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
throw new ApiError({
|
|
1317
|
+
message: errorResponse.error || "API request failed",
|
|
1318
|
+
code: errorResponse.code || "UNKNOWN_ERROR",
|
|
1319
|
+
status: response.status
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
return json;
|
|
1323
|
+
},
|
|
1324
|
+
catch: (error) => {
|
|
1325
|
+
if (error instanceof ApiError || error instanceof AuthenticationError || error instanceof NetworkError) {
|
|
1326
|
+
return error;
|
|
1327
|
+
}
|
|
1328
|
+
return new NetworkError({
|
|
1329
|
+
message: `Failed to connect to ${apiServerUrl}`,
|
|
1330
|
+
cause: error
|
|
830
1331
|
});
|
|
831
1332
|
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
status: response.status
|
|
836
|
-
});
|
|
837
|
-
}
|
|
838
|
-
return json;
|
|
839
|
-
},
|
|
840
|
-
catch: (error) => {
|
|
841
|
-
if (error instanceof ApiError || error instanceof AuthenticationError || error instanceof NetworkError) {
|
|
842
|
-
return error;
|
|
843
|
-
}
|
|
844
|
-
return new NetworkError({
|
|
845
|
-
message: `Failed to connect to ${serverUrl}`,
|
|
846
|
-
cause: error
|
|
847
|
-
});
|
|
848
|
-
}
|
|
849
|
-
})
|
|
1333
|
+
})
|
|
1334
|
+
)
|
|
1335
|
+
)
|
|
850
1336
|
)
|
|
851
1337
|
);
|
|
852
1338
|
DEFAULT_PUBLIC_SERVER_URL = "https://braid.cloud";
|
|
@@ -873,7 +1359,7 @@ var init_api = __esm({
|
|
|
873
1359
|
})
|
|
874
1360
|
);
|
|
875
1361
|
}
|
|
876
|
-
const errorResponse = json;
|
|
1362
|
+
const errorResponse = getApiErrorResponse(json);
|
|
877
1363
|
return Effect4.fail(
|
|
878
1364
|
new ApiError({
|
|
879
1365
|
message: errorResponse.error || "API request failed",
|
|
@@ -893,7 +1379,10 @@ var init_api = __esm({
|
|
|
893
1379
|
}
|
|
894
1380
|
return pipe4(
|
|
895
1381
|
Effect4.tryPromise({
|
|
896
|
-
try: () => fetch(url.toString(), {
|
|
1382
|
+
try: () => fetch(url.toString(), {
|
|
1383
|
+
method: "GET",
|
|
1384
|
+
headers: mergeAutomationHeaders()
|
|
1385
|
+
}),
|
|
897
1386
|
catch: (e) => new NetworkError({
|
|
898
1387
|
message: `Failed to connect to ${baseUrl}`,
|
|
899
1388
|
cause: e
|
|
@@ -901,10 +1390,7 @@ var init_api = __esm({
|
|
|
901
1390
|
}),
|
|
902
1391
|
Effect4.flatMap(
|
|
903
1392
|
(response) => pipe4(
|
|
904
|
-
|
|
905
|
-
try: () => response.json(),
|
|
906
|
-
catch: () => new NetworkError({ message: "Failed to parse API response" })
|
|
907
|
-
}),
|
|
1393
|
+
readJsonResponse(response),
|
|
908
1394
|
Effect4.flatMap(
|
|
909
1395
|
(json) => handlePublicApiResponse(response, json)
|
|
910
1396
|
)
|
|
@@ -926,7 +1412,10 @@ var init_api = __esm({
|
|
|
926
1412
|
}
|
|
927
1413
|
return pipe4(
|
|
928
1414
|
Effect4.tryPromise({
|
|
929
|
-
try: () => fetch(url.toString(), {
|
|
1415
|
+
try: () => fetch(url.toString(), {
|
|
1416
|
+
method: "GET",
|
|
1417
|
+
headers: mergeAutomationHeaders()
|
|
1418
|
+
}),
|
|
930
1419
|
catch: (e) => new NetworkError({
|
|
931
1420
|
message: `Failed to connect to ${baseUrl}`,
|
|
932
1421
|
cause: e
|
|
@@ -934,10 +1423,7 @@ var init_api = __esm({
|
|
|
934
1423
|
}),
|
|
935
1424
|
Effect4.flatMap(
|
|
936
1425
|
(response) => pipe4(
|
|
937
|
-
|
|
938
|
-
try: () => response.json(),
|
|
939
|
-
catch: () => new NetworkError({ message: "Failed to parse API response" })
|
|
940
|
-
}),
|
|
1426
|
+
readJsonResponse(response),
|
|
941
1427
|
Effect4.flatMap(
|
|
942
1428
|
(json) => handlePublicApiResponse(response, json)
|
|
943
1429
|
)
|
|
@@ -969,10 +1455,10 @@ var init_api = __esm({
|
|
|
969
1455
|
url.searchParams.set("profile", "default");
|
|
970
1456
|
const response = await fetch(url.toString(), {
|
|
971
1457
|
method: "GET",
|
|
972
|
-
headers: {
|
|
1458
|
+
headers: mergeAutomationHeaders({
|
|
973
1459
|
Authorization: `Bearer ${apiKey}`,
|
|
974
1460
|
"Content-Type": "application/json"
|
|
975
|
-
}
|
|
1461
|
+
})
|
|
976
1462
|
});
|
|
977
1463
|
return response.status !== 401;
|
|
978
1464
|
},
|
|
@@ -992,7 +1478,7 @@ var init_api = __esm({
|
|
|
992
1478
|
});
|
|
993
1479
|
|
|
994
1480
|
// src/lib/tui.ts
|
|
995
|
-
import
|
|
1481
|
+
import process7 from "process";
|
|
996
1482
|
import {
|
|
997
1483
|
cancel as clackCancel,
|
|
998
1484
|
confirm as clackConfirm,
|
|
@@ -1017,19 +1503,19 @@ function spinner() {
|
|
|
1017
1503
|
return {
|
|
1018
1504
|
start: (message) => {
|
|
1019
1505
|
if (message) {
|
|
1020
|
-
|
|
1506
|
+
process7.stdout.write(`${message}
|
|
1021
1507
|
`);
|
|
1022
1508
|
}
|
|
1023
1509
|
},
|
|
1024
1510
|
stop: (message) => {
|
|
1025
1511
|
if (message) {
|
|
1026
|
-
|
|
1512
|
+
process7.stdout.write(`${message}
|
|
1027
1513
|
`);
|
|
1028
1514
|
}
|
|
1029
1515
|
},
|
|
1030
1516
|
message: (message) => {
|
|
1031
1517
|
if (message) {
|
|
1032
|
-
|
|
1518
|
+
process7.stdout.write(`${message}
|
|
1033
1519
|
`);
|
|
1034
1520
|
}
|
|
1035
1521
|
}
|
|
@@ -1039,7 +1525,7 @@ function intro(message) {
|
|
|
1039
1525
|
if (isTTY) {
|
|
1040
1526
|
clackIntro(message);
|
|
1041
1527
|
} else {
|
|
1042
|
-
|
|
1528
|
+
process7.stdout.write(`
|
|
1043
1529
|
${message}
|
|
1044
1530
|
`);
|
|
1045
1531
|
}
|
|
@@ -1048,7 +1534,7 @@ function outro(message) {
|
|
|
1048
1534
|
if (isTTY) {
|
|
1049
1535
|
clackOutro(message);
|
|
1050
1536
|
} else {
|
|
1051
|
-
|
|
1537
|
+
process7.stdout.write(`${message}
|
|
1052
1538
|
|
|
1053
1539
|
`);
|
|
1054
1540
|
}
|
|
@@ -1058,7 +1544,7 @@ var init_tui = __esm({
|
|
|
1058
1544
|
"src/lib/tui.ts"() {
|
|
1059
1545
|
"use strict";
|
|
1060
1546
|
init_esm_shims();
|
|
1061
|
-
isTTY = Boolean(
|
|
1547
|
+
isTTY = Boolean(process7.stdout.isTTY);
|
|
1062
1548
|
cancel = clackCancel;
|
|
1063
1549
|
confirm = clackConfirm;
|
|
1064
1550
|
isCancel = clackIsCancel;
|
|
@@ -1168,10 +1654,10 @@ var scope_exports = {};
|
|
|
1168
1654
|
__export(scope_exports, {
|
|
1169
1655
|
scopeCommand: () => scopeCommand
|
|
1170
1656
|
});
|
|
1171
|
-
import
|
|
1657
|
+
import process9 from "process";
|
|
1172
1658
|
function exitCancelled(message) {
|
|
1173
1659
|
cancel(message);
|
|
1174
|
-
|
|
1660
|
+
process9.exit(0);
|
|
1175
1661
|
}
|
|
1176
1662
|
async function selectTargetFile(options) {
|
|
1177
1663
|
if (options.file) {
|
|
@@ -1523,7 +2009,7 @@ async function scopeCommand(options) {
|
|
|
1523
2009
|
} catch (error) {
|
|
1524
2010
|
loadSpinner.stop("Failed to load scope options");
|
|
1525
2011
|
log.error(error instanceof Error ? error.message : String(error));
|
|
1526
|
-
|
|
2012
|
+
process9.exit(1);
|
|
1527
2013
|
}
|
|
1528
2014
|
}
|
|
1529
2015
|
var init_scope = __esm({
|
|
@@ -1562,7 +2048,7 @@ __export(lockfile_exports, {
|
|
|
1562
2048
|
});
|
|
1563
2049
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
1564
2050
|
import { join as join6 } from "path";
|
|
1565
|
-
import { Data as
|
|
2051
|
+
import { Data as Data5, Effect as Effect6, pipe as pipe6 } from "effect";
|
|
1566
2052
|
var LOCKFILE_FILENAME, LOCKFILE_VERSION, MARKETPLACE_KEY_REGEX, ORG_KEY_REGEX, LockfileReadError, LockfileWriteError, LockfileVersionError, LockfileCorruptError, getLockfilePath, emptyLockfile, readLockfile, writeLockfile, resolveLocked, upsertLockfileEntry, removeLockfileEntry, buildLockfileKey, parseLockfileKey, readLockfileAsync, writeLockfileAsync, upsertLockfileEntryAsync, removeLockfileEntryAsync;
|
|
1567
2053
|
var init_lockfile = __esm({
|
|
1568
2054
|
"src/lib/lockfile.ts"() {
|
|
@@ -1572,13 +2058,13 @@ var init_lockfile = __esm({
|
|
|
1572
2058
|
LOCKFILE_VERSION = 1;
|
|
1573
2059
|
MARKETPLACE_KEY_REGEX = /^@([a-z0-9-]+)\/([a-z0-9-]+)@(\d+)$/;
|
|
1574
2060
|
ORG_KEY_REGEX = /^([a-z0-9-]+)\/([a-z0-9-]+)@(\d+)$/;
|
|
1575
|
-
LockfileReadError = class extends
|
|
2061
|
+
LockfileReadError = class extends Data5.TaggedError("LockfileReadError") {
|
|
1576
2062
|
};
|
|
1577
|
-
LockfileWriteError = class extends
|
|
2063
|
+
LockfileWriteError = class extends Data5.TaggedError("LockfileWriteError") {
|
|
1578
2064
|
};
|
|
1579
|
-
LockfileVersionError = class extends
|
|
2065
|
+
LockfileVersionError = class extends Data5.TaggedError("LockfileVersionError") {
|
|
1580
2066
|
};
|
|
1581
|
-
LockfileCorruptError = class extends
|
|
2067
|
+
LockfileCorruptError = class extends Data5.TaggedError("LockfileCorruptError") {
|
|
1582
2068
|
};
|
|
1583
2069
|
getLockfilePath = (dir) => join6(dir, LOCKFILE_FILENAME);
|
|
1584
2070
|
emptyLockfile = () => ({
|
|
@@ -1587,27 +2073,27 @@ var init_lockfile = __esm({
|
|
|
1587
2073
|
});
|
|
1588
2074
|
readLockfile = (dir) => {
|
|
1589
2075
|
const lockfilePath = getLockfilePath(dir);
|
|
1590
|
-
return
|
|
1591
|
-
|
|
2076
|
+
return pipe6(
|
|
2077
|
+
Effect6.tryPromise({
|
|
1592
2078
|
try: () => readFile3(lockfilePath, "utf-8"),
|
|
1593
2079
|
catch: () => new LockfileReadError({ path: lockfilePath, cause: "not found" })
|
|
1594
2080
|
}),
|
|
1595
|
-
|
|
2081
|
+
Effect6.catchTag(
|
|
1596
2082
|
"LockfileReadError",
|
|
1597
|
-
() =>
|
|
2083
|
+
() => Effect6.succeed(null)
|
|
1598
2084
|
),
|
|
1599
|
-
|
|
2085
|
+
Effect6.flatMap((content) => {
|
|
1600
2086
|
if (content === null) {
|
|
1601
|
-
return
|
|
2087
|
+
return Effect6.succeed(null);
|
|
1602
2088
|
}
|
|
1603
|
-
return
|
|
1604
|
-
|
|
2089
|
+
return pipe6(
|
|
2090
|
+
Effect6.try({
|
|
1605
2091
|
try: () => JSON.parse(content),
|
|
1606
2092
|
catch: (cause) => new LockfileCorruptError({ path: lockfilePath, cause })
|
|
1607
2093
|
}),
|
|
1608
|
-
|
|
2094
|
+
Effect6.flatMap((parsed) => {
|
|
1609
2095
|
if (parsed.lockfileVersion !== LOCKFILE_VERSION) {
|
|
1610
|
-
return
|
|
2096
|
+
return Effect6.fail(
|
|
1611
2097
|
new LockfileVersionError({
|
|
1612
2098
|
path: lockfilePath,
|
|
1613
2099
|
expected: LOCKFILE_VERSION,
|
|
@@ -1615,7 +2101,7 @@ var init_lockfile = __esm({
|
|
|
1615
2101
|
})
|
|
1616
2102
|
);
|
|
1617
2103
|
}
|
|
1618
|
-
return
|
|
2104
|
+
return Effect6.succeed(parsed);
|
|
1619
2105
|
})
|
|
1620
2106
|
);
|
|
1621
2107
|
})
|
|
@@ -1623,7 +2109,7 @@ var init_lockfile = __esm({
|
|
|
1623
2109
|
};
|
|
1624
2110
|
writeLockfile = (dir, lockfile) => {
|
|
1625
2111
|
const lockfilePath = getLockfilePath(dir);
|
|
1626
|
-
return
|
|
2112
|
+
return Effect6.tryPromise({
|
|
1627
2113
|
try: () => writeFile4(
|
|
1628
2114
|
lockfilePath,
|
|
1629
2115
|
`${JSON.stringify(lockfile, null, 2)}
|
|
@@ -1640,26 +2126,26 @@ var init_lockfile = __esm({
|
|
|
1640
2126
|
}
|
|
1641
2127
|
return entry;
|
|
1642
2128
|
};
|
|
1643
|
-
upsertLockfileEntry = (dir, key, entry) =>
|
|
2129
|
+
upsertLockfileEntry = (dir, key, entry) => pipe6(
|
|
1644
2130
|
readLockfile(dir),
|
|
1645
|
-
|
|
1646
|
-
|
|
2131
|
+
Effect6.map((existing) => existing ?? emptyLockfile()),
|
|
2132
|
+
Effect6.map((lockfile) => ({
|
|
1647
2133
|
...lockfile,
|
|
1648
2134
|
resolved: {
|
|
1649
2135
|
...lockfile.resolved,
|
|
1650
2136
|
[key]: entry
|
|
1651
2137
|
}
|
|
1652
2138
|
})),
|
|
1653
|
-
|
|
2139
|
+
Effect6.flatMap((lockfile) => writeLockfile(dir, lockfile))
|
|
1654
2140
|
);
|
|
1655
|
-
removeLockfileEntry = (dir, key) =>
|
|
2141
|
+
removeLockfileEntry = (dir, key) => pipe6(
|
|
1656
2142
|
readLockfile(dir),
|
|
1657
|
-
|
|
1658
|
-
|
|
2143
|
+
Effect6.map((existing) => existing ?? emptyLockfile()),
|
|
2144
|
+
Effect6.map((lockfile) => {
|
|
1659
2145
|
const { [key]: _removed, ...rest } = lockfile.resolved;
|
|
1660
2146
|
return { ...lockfile, resolved: rest };
|
|
1661
2147
|
}),
|
|
1662
|
-
|
|
2148
|
+
Effect6.flatMap((lockfile) => writeLockfile(dir, lockfile))
|
|
1663
2149
|
);
|
|
1664
2150
|
buildLockfileKey = (source, handle, slug, version) => {
|
|
1665
2151
|
const prefix = source === "marketplace" ? `@${handle}` : handle;
|
|
@@ -1686,10 +2172,10 @@ var init_lockfile = __esm({
|
|
|
1686
2172
|
}
|
|
1687
2173
|
return null;
|
|
1688
2174
|
};
|
|
1689
|
-
readLockfileAsync = (dir) =>
|
|
1690
|
-
writeLockfileAsync = (dir, lockfile) =>
|
|
1691
|
-
upsertLockfileEntryAsync = (dir, key, entry) =>
|
|
1692
|
-
removeLockfileEntryAsync = (dir, key) =>
|
|
2175
|
+
readLockfileAsync = (dir) => Effect6.runPromise(readLockfile(dir));
|
|
2176
|
+
writeLockfileAsync = (dir, lockfile) => Effect6.runPromise(writeLockfile(dir, lockfile));
|
|
2177
|
+
upsertLockfileEntryAsync = (dir, key, entry) => Effect6.runPromise(upsertLockfileEntry(dir, key, entry));
|
|
2178
|
+
removeLockfileEntryAsync = (dir, key) => Effect6.runPromise(removeLockfileEntry(dir, key));
|
|
1693
2179
|
}
|
|
1694
2180
|
});
|
|
1695
2181
|
|
|
@@ -2274,25 +2760,260 @@ var resolveHookConfigPath = (agent, options) => {
|
|
|
2274
2760
|
|
|
2275
2761
|
// src/commands/agents.ts
|
|
2276
2762
|
init_api();
|
|
2763
|
+
|
|
2764
|
+
// src/lib/command-output.ts
|
|
2765
|
+
init_esm_shims();
|
|
2766
|
+
init_api();
|
|
2767
|
+
import process8 from "process";
|
|
2768
|
+
|
|
2769
|
+
// src/lib/marketplace-api.ts
|
|
2770
|
+
init_esm_shims();
|
|
2771
|
+
init_automation_headers();
|
|
2772
|
+
init_config();
|
|
2773
|
+
init_device_auth();
|
|
2774
|
+
import { Data as Data4, Effect as Effect5, pipe as pipe5 } from "effect";
|
|
2775
|
+
var TRAILING_SLASH_REGEX2 = /\/$/;
|
|
2776
|
+
var SESSION_TOKEN_PREFIX2 = "brs_";
|
|
2777
|
+
var MarketplaceApiError = class extends Data4.TaggedError("MarketplaceApiError") {
|
|
2778
|
+
};
|
|
2779
|
+
var isLocalHost2 = (hostname2) => hostname2 === "localhost" || hostname2 === "127.0.0.1" || hostname2 === "::1";
|
|
2780
|
+
var isConvexSiteHost2 = (hostname2) => hostname2.endsWith(".convex.site");
|
|
2781
|
+
var isSessionApiServerUrl2 = (serverUrl) => {
|
|
2782
|
+
try {
|
|
2783
|
+
const hostname2 = new URL(serverUrl).hostname;
|
|
2784
|
+
return isConvexSiteHost2(hostname2) || isLocalHost2(hostname2);
|
|
2785
|
+
} catch {
|
|
2786
|
+
return false;
|
|
2787
|
+
}
|
|
2788
|
+
};
|
|
2789
|
+
var resolveApiKey2 = (provided) => {
|
|
2790
|
+
if (provided) {
|
|
2791
|
+
return Effect5.succeed(provided);
|
|
2792
|
+
}
|
|
2793
|
+
return pipe5(
|
|
2794
|
+
Effect5.tryPromise({
|
|
2795
|
+
try: () => getApiKeyAsync(),
|
|
2796
|
+
catch: () => new MarketplaceApiError({
|
|
2797
|
+
message: "Failed to load API key",
|
|
2798
|
+
status: 500,
|
|
2799
|
+
code: "CONFIG_ERROR"
|
|
2800
|
+
})
|
|
2801
|
+
}),
|
|
2802
|
+
Effect5.flatMap(
|
|
2803
|
+
(token) => token ? Effect5.succeed(token) : Effect5.fail(
|
|
2804
|
+
new MarketplaceApiError({
|
|
2805
|
+
message: "Not signed in. Run 'braid auth'.",
|
|
2806
|
+
status: 401,
|
|
2807
|
+
code: "AUTH_REQUIRED"
|
|
2808
|
+
})
|
|
2809
|
+
)
|
|
2810
|
+
)
|
|
2811
|
+
);
|
|
2812
|
+
};
|
|
2813
|
+
var resolveServer = (provided) => {
|
|
2814
|
+
if (provided) {
|
|
2815
|
+
return Effect5.succeed(provided.replace(TRAILING_SLASH_REGEX2, ""));
|
|
2816
|
+
}
|
|
2817
|
+
return pipe5(
|
|
2818
|
+
Effect5.tryPromise({
|
|
2819
|
+
try: () => getServerUrlAsync(),
|
|
2820
|
+
catch: () => new MarketplaceApiError({
|
|
2821
|
+
message: "Failed to load server URL",
|
|
2822
|
+
status: 500,
|
|
2823
|
+
code: "CONFIG_ERROR"
|
|
2824
|
+
})
|
|
2825
|
+
}),
|
|
2826
|
+
Effect5.map((server) => server.replace(TRAILING_SLASH_REGEX2, ""))
|
|
2827
|
+
);
|
|
2828
|
+
};
|
|
2829
|
+
var resolveRequestServer = (server, apiKey) => {
|
|
2830
|
+
if (!apiKey.startsWith(SESSION_TOKEN_PREFIX2) || isSessionApiServerUrl2(server)) {
|
|
2831
|
+
return Effect5.succeed(server);
|
|
2832
|
+
}
|
|
2833
|
+
return Effect5.tryPromise({
|
|
2834
|
+
try: async () => {
|
|
2835
|
+
const authConfig = await fetchAuthConfig(server);
|
|
2836
|
+
return authConfig.convexSiteUrl.replace(TRAILING_SLASH_REGEX2, "");
|
|
2837
|
+
},
|
|
2838
|
+
catch: () => new MarketplaceApiError({
|
|
2839
|
+
message: `Failed to resolve marketplace API server for ${server}`,
|
|
2840
|
+
status: 500,
|
|
2841
|
+
code: "CONFIG_ERROR"
|
|
2842
|
+
})
|
|
2843
|
+
});
|
|
2844
|
+
};
|
|
2845
|
+
var requestJson = (url, options, requestOptions = {}) => pipe5(
|
|
2846
|
+
Effect5.tryPromise({
|
|
2847
|
+
try: () => fetch(url, options),
|
|
2848
|
+
catch: () => new MarketplaceApiError({
|
|
2849
|
+
message: "Network error",
|
|
2850
|
+
status: 503,
|
|
2851
|
+
code: "NETWORK_ERROR"
|
|
2852
|
+
})
|
|
2853
|
+
}),
|
|
2854
|
+
Effect5.flatMap(
|
|
2855
|
+
(response) => Effect5.tryPromise({
|
|
2856
|
+
try: async () => {
|
|
2857
|
+
const payload = await response.json().catch(() => null);
|
|
2858
|
+
if (!response.ok) {
|
|
2859
|
+
const normalizedMessage = requestOptions.normalizeErrorMessage?.({
|
|
2860
|
+
payload,
|
|
2861
|
+
response,
|
|
2862
|
+
url
|
|
2863
|
+
});
|
|
2864
|
+
throw new MarketplaceApiError({
|
|
2865
|
+
message: normalizedMessage ?? (response.status === 404 ? requestOptions.notFoundMessage : void 0) ?? payload?.error ?? payload?.message ?? `Request failed (HTTP ${response.status} from ${new URL(url).origin})`,
|
|
2866
|
+
status: response.status,
|
|
2867
|
+
code: payload?.code ?? "REQUEST_ERROR"
|
|
2868
|
+
});
|
|
2869
|
+
}
|
|
2870
|
+
return payload;
|
|
2871
|
+
},
|
|
2872
|
+
catch: (error) => error instanceof MarketplaceApiError ? error : new MarketplaceApiError({
|
|
2873
|
+
message: "Invalid response",
|
|
2874
|
+
status: 500,
|
|
2875
|
+
code: "PARSE_ERROR"
|
|
2876
|
+
})
|
|
2877
|
+
})
|
|
2878
|
+
)
|
|
2879
|
+
);
|
|
2880
|
+
var fetchMarketplaceLibrary = (options) => pipe5(
|
|
2881
|
+
Effect5.all({
|
|
2882
|
+
server: resolveServer(options.server),
|
|
2883
|
+
apiKey: resolveApiKey2(options.apiKey)
|
|
2884
|
+
}),
|
|
2885
|
+
Effect5.flatMap(
|
|
2886
|
+
({ server, apiKey }) => Effect5.all({
|
|
2887
|
+
apiKey: Effect5.succeed(apiKey),
|
|
2888
|
+
server: resolveRequestServer(server, apiKey)
|
|
2889
|
+
})
|
|
2890
|
+
),
|
|
2891
|
+
Effect5.flatMap(
|
|
2892
|
+
({ server, apiKey }) => requestJson(
|
|
2893
|
+
`${server}/api/marketplace/library`,
|
|
2894
|
+
{
|
|
2895
|
+
method: "GET",
|
|
2896
|
+
headers: mergeAutomationHeaders({
|
|
2897
|
+
Authorization: `Bearer ${apiKey}`
|
|
2898
|
+
})
|
|
2899
|
+
}
|
|
2900
|
+
)
|
|
2901
|
+
),
|
|
2902
|
+
Effect5.map((response) => response.items)
|
|
2903
|
+
);
|
|
2904
|
+
var fetchMarketplaceInstallManifest = (slug, options) => pipe5(
|
|
2905
|
+
Effect5.all({
|
|
2906
|
+
server: resolveServer(options.server),
|
|
2907
|
+
apiKey: resolveApiKey2(options.apiKey)
|
|
2908
|
+
}),
|
|
2909
|
+
Effect5.flatMap(
|
|
2910
|
+
({ server, apiKey }) => Effect5.all({
|
|
2911
|
+
apiKey: Effect5.succeed(apiKey),
|
|
2912
|
+
server: resolveRequestServer(server, apiKey)
|
|
2913
|
+
})
|
|
2914
|
+
),
|
|
2915
|
+
Effect5.flatMap(
|
|
2916
|
+
({ server, apiKey }) => requestJson(
|
|
2917
|
+
`${server}/api/marketplace/install-manifest/${encodeURIComponent(slug)}`,
|
|
2918
|
+
{
|
|
2919
|
+
method: "GET",
|
|
2920
|
+
headers: mergeAutomationHeaders({
|
|
2921
|
+
Authorization: `Bearer ${apiKey}`
|
|
2922
|
+
})
|
|
2923
|
+
},
|
|
2924
|
+
{
|
|
2925
|
+
normalizeErrorMessage: ({ payload }) => payload?.error === "Not entitled" ? "Pack not found or no longer available in your library." : void 0,
|
|
2926
|
+
notFoundMessage: "Pack not found or no longer available in your library."
|
|
2927
|
+
}
|
|
2928
|
+
)
|
|
2929
|
+
)
|
|
2930
|
+
);
|
|
2931
|
+
var fetchMarketplaceLibraryAsync = (options) => Effect5.runPromise(fetchMarketplaceLibrary(options));
|
|
2932
|
+
var fetchMarketplaceInstallManifestAsync = (slug, options) => Effect5.runPromise(fetchMarketplaceInstallManifest(slug, options));
|
|
2933
|
+
|
|
2934
|
+
// src/lib/command-output.ts
|
|
2277
2935
|
init_tui();
|
|
2278
|
-
var
|
|
2279
|
-
|
|
2280
|
-
|
|
2936
|
+
var CommandValidationError = class extends Error {
|
|
2937
|
+
code = "CLI_VALIDATION_ERROR";
|
|
2938
|
+
constructor(message) {
|
|
2939
|
+
super(message);
|
|
2940
|
+
this.name = "CommandValidationError";
|
|
2281
2941
|
}
|
|
2282
|
-
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
2283
|
-
return values.length > 0 ? values : void 0;
|
|
2284
2942
|
};
|
|
2285
2943
|
var writeJson = (value) => {
|
|
2286
|
-
|
|
2944
|
+
process8.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
2287
2945
|
`);
|
|
2288
2946
|
};
|
|
2947
|
+
var toJsonErrorOutput = (error) => {
|
|
2948
|
+
if (error instanceof ApiError) {
|
|
2949
|
+
return {
|
|
2950
|
+
error: error.message,
|
|
2951
|
+
code: error.code,
|
|
2952
|
+
status: error.status
|
|
2953
|
+
};
|
|
2954
|
+
}
|
|
2955
|
+
if (error instanceof AuthenticationError) {
|
|
2956
|
+
return {
|
|
2957
|
+
error: error.message,
|
|
2958
|
+
code: "AUTH_REQUIRED",
|
|
2959
|
+
status: 401
|
|
2960
|
+
};
|
|
2961
|
+
}
|
|
2962
|
+
if (error instanceof NetworkError) {
|
|
2963
|
+
return {
|
|
2964
|
+
error: error.message,
|
|
2965
|
+
code: "NETWORK_ERROR",
|
|
2966
|
+
status: 503
|
|
2967
|
+
};
|
|
2968
|
+
}
|
|
2969
|
+
if (error instanceof MarketplaceApiError) {
|
|
2970
|
+
return {
|
|
2971
|
+
error: error.message,
|
|
2972
|
+
code: error.code,
|
|
2973
|
+
status: error.status
|
|
2974
|
+
};
|
|
2975
|
+
}
|
|
2976
|
+
if (error instanceof CommandValidationError || error instanceof SyntaxError) {
|
|
2977
|
+
return {
|
|
2978
|
+
error: error.message,
|
|
2979
|
+
code: "CLI_VALIDATION_ERROR",
|
|
2980
|
+
status: 400
|
|
2981
|
+
};
|
|
2982
|
+
}
|
|
2983
|
+
if (error instanceof Error) {
|
|
2984
|
+
return {
|
|
2985
|
+
error: error.message,
|
|
2986
|
+
code: "CLI_ERROR",
|
|
2987
|
+
status: 500
|
|
2988
|
+
};
|
|
2989
|
+
}
|
|
2990
|
+
return {
|
|
2991
|
+
error: String(error),
|
|
2992
|
+
code: "CLI_ERROR",
|
|
2993
|
+
status: 500
|
|
2994
|
+
};
|
|
2995
|
+
};
|
|
2289
2996
|
var fail = (message) => {
|
|
2290
|
-
throw new
|
|
2997
|
+
throw new CommandValidationError(message);
|
|
2291
2998
|
};
|
|
2292
|
-
var
|
|
2999
|
+
var exitCommandError = (error, options) => {
|
|
3000
|
+
if (options?.json) {
|
|
3001
|
+
writeJson(toJsonErrorOutput(error));
|
|
3002
|
+
process8.exit(1);
|
|
3003
|
+
}
|
|
2293
3004
|
const message = error instanceof Error ? error.message : String(error);
|
|
2294
3005
|
log.error(message);
|
|
2295
|
-
|
|
3006
|
+
process8.exit(1);
|
|
3007
|
+
};
|
|
3008
|
+
|
|
3009
|
+
// src/commands/agents.ts
|
|
3010
|
+
init_tui();
|
|
3011
|
+
var parseCsv = (input) => {
|
|
3012
|
+
if (!input) {
|
|
3013
|
+
return void 0;
|
|
3014
|
+
}
|
|
3015
|
+
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
3016
|
+
return values.length > 0 ? values : void 0;
|
|
2296
3017
|
};
|
|
2297
3018
|
var run = (command, args, options) => {
|
|
2298
3019
|
const apiOptions = {
|
|
@@ -2397,7 +3118,7 @@ async function agentsListCommand(options) {
|
|
|
2397
3118
|
log.success("sub-agents list completed");
|
|
2398
3119
|
writeJson(result);
|
|
2399
3120
|
} catch (error) {
|
|
2400
|
-
|
|
3121
|
+
exitCommandError(error, { json: options.json });
|
|
2401
3122
|
}
|
|
2402
3123
|
}
|
|
2403
3124
|
async function agentsGetCommand(options) {
|
|
@@ -2411,7 +3132,7 @@ async function agentsGetCommand(options) {
|
|
|
2411
3132
|
log.success("sub-agents get completed");
|
|
2412
3133
|
writeJson(result);
|
|
2413
3134
|
} catch (error) {
|
|
2414
|
-
|
|
3135
|
+
exitCommandError(error, { json: options.json });
|
|
2415
3136
|
}
|
|
2416
3137
|
}
|
|
2417
3138
|
async function agentsCreateCommand(options) {
|
|
@@ -2439,7 +3160,7 @@ async function agentsCreateCommand(options) {
|
|
|
2439
3160
|
}
|
|
2440
3161
|
log.success("sub-agents create completed");
|
|
2441
3162
|
} catch (error) {
|
|
2442
|
-
|
|
3163
|
+
exitCommandError(error, { json: options.json });
|
|
2443
3164
|
}
|
|
2444
3165
|
}
|
|
2445
3166
|
async function agentsUpdateCommand(options) {
|
|
@@ -2464,7 +3185,7 @@ async function agentsUpdateCommand(options) {
|
|
|
2464
3185
|
}
|
|
2465
3186
|
log.success("sub-agents update completed");
|
|
2466
3187
|
} catch (error) {
|
|
2467
|
-
|
|
3188
|
+
exitCommandError(error, { json: options.json });
|
|
2468
3189
|
}
|
|
2469
3190
|
}
|
|
2470
3191
|
async function agentsRemoveCommand(options) {
|
|
@@ -2480,7 +3201,7 @@ async function agentsRemoveCommand(options) {
|
|
|
2480
3201
|
}
|
|
2481
3202
|
log.success("sub-agents remove completed");
|
|
2482
3203
|
} catch (error) {
|
|
2483
|
-
|
|
3204
|
+
exitCommandError(error, { json: options.json });
|
|
2484
3205
|
}
|
|
2485
3206
|
}
|
|
2486
3207
|
async function agentsInstallCommand(options) {
|
|
@@ -2504,366 +3225,58 @@ async function agentsInstallCommand(options) {
|
|
|
2504
3225
|
const result = await writeAgentsForPlatformAsync(
|
|
2505
3226
|
target,
|
|
2506
3227
|
[spec],
|
|
2507
|
-
installPath
|
|
2508
|
-
);
|
|
2509
|
-
summary.push({
|
|
2510
|
-
platform: target.id,
|
|
2511
|
-
installPath,
|
|
2512
|
-
written: result.written.length,
|
|
2513
|
-
warnings: result.warnings,
|
|
2514
|
-
errors: result.errors
|
|
2515
|
-
});
|
|
2516
|
-
}
|
|
2517
|
-
if (options.json) {
|
|
2518
|
-
writeJson(summary);
|
|
2519
|
-
return;
|
|
2520
|
-
}
|
|
2521
|
-
for (const item of summary) {
|
|
2522
|
-
log.info(
|
|
2523
|
-
`${item.platform}: ${item.written} file(s) written${item.installPath ? ` to ${item.installPath}` : ""}`
|
|
2524
|
-
);
|
|
2525
|
-
for (const warning of item.warnings) {
|
|
2526
|
-
log.warn(` warning: ${warning}`);
|
|
2527
|
-
}
|
|
2528
|
-
for (const error of item.errors) {
|
|
2529
|
-
log.error(` error (${error.agent}): ${error.error}`);
|
|
2530
|
-
}
|
|
2531
|
-
}
|
|
2532
|
-
log.success("sub-agents install completed");
|
|
2533
|
-
} catch (error) {
|
|
2534
|
-
exitWithError(error);
|
|
2535
|
-
}
|
|
2536
|
-
}
|
|
2537
|
-
|
|
2538
|
-
// src/commands/auth.ts
|
|
2539
|
-
init_esm_shims();
|
|
2540
|
-
init_api();
|
|
2541
|
-
init_config();
|
|
2542
|
-
import process8 from "process";
|
|
2543
|
-
|
|
2544
|
-
// src/lib/device-auth.ts
|
|
2545
|
-
init_esm_shims();
|
|
2546
|
-
init_braid_workspace();
|
|
2547
|
-
import { execFile } from "child_process";
|
|
2548
|
-
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
2549
|
-
import { hostname, platform } from "os";
|
|
2550
|
-
import { join as join4 } from "path";
|
|
2551
|
-
import process6 from "process";
|
|
2552
|
-
var TRAILING_SLASHES2 = /\/+$/;
|
|
2553
|
-
var LEGACY_BRAID_AUTH_HOSTS = /* @__PURE__ */ new Set([
|
|
2554
|
-
"api.braid.cloud",
|
|
2555
|
-
"braid.cloud",
|
|
2556
|
-
"www.braid.cloud"
|
|
2557
|
-
]);
|
|
2558
|
-
var BRAID_APP_HOST = "app.braid.cloud";
|
|
2559
|
-
var DEFAULT_BRAID_AUTH_HOSTS = /* @__PURE__ */ new Set([
|
|
2560
|
-
...LEGACY_BRAID_AUTH_HOSTS,
|
|
2561
|
-
BRAID_APP_HOST
|
|
2562
|
-
]);
|
|
2563
|
-
var LOOPBACK_HOSTS2 = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "localhost"]);
|
|
2564
|
-
var LOCAL_AUTH_ENV_FILES = [
|
|
2565
|
-
["apps", "web", ".env.local"],
|
|
2566
|
-
["apps", "convex", ".env.local"]
|
|
2567
|
-
];
|
|
2568
|
-
var LOCAL_AUTH_ENV_KEYS = ["APP_URL", "SITE_URL"];
|
|
2569
|
-
var NEWLINE_REGEX2 = /\r?\n/;
|
|
2570
|
-
var DeviceAuthTimeoutError = class extends Error {
|
|
2571
|
-
constructor() {
|
|
2572
|
-
super("Device authorization timed out");
|
|
2573
|
-
this.name = "DeviceAuthTimeoutError";
|
|
2574
|
-
}
|
|
2575
|
-
};
|
|
2576
|
-
var DeviceAuthDeniedError = class extends Error {
|
|
2577
|
-
constructor() {
|
|
2578
|
-
super("Device authorization was denied");
|
|
2579
|
-
this.name = "DeviceAuthDeniedError";
|
|
2580
|
-
}
|
|
2581
|
-
};
|
|
2582
|
-
var DeviceAuthExpiredError = class extends Error {
|
|
2583
|
-
constructor() {
|
|
2584
|
-
super("Device authorization code has expired");
|
|
2585
|
-
this.name = "DeviceAuthExpiredError";
|
|
2586
|
-
}
|
|
2587
|
-
};
|
|
2588
|
-
var sleep = (ms) => new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
2589
|
-
var normalizeBaseUrl2 = (rawUrl) => {
|
|
2590
|
-
const trimmed = rawUrl.replace(TRAILING_SLASHES2, "");
|
|
2591
|
-
try {
|
|
2592
|
-
const url = new URL(trimmed);
|
|
2593
|
-
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
2594
|
-
} catch {
|
|
2595
|
-
return trimmed;
|
|
2596
|
-
}
|
|
2597
|
-
};
|
|
2598
|
-
var normalizeLoopbackBaseUrl = (rawUrl) => {
|
|
2599
|
-
const normalized = normalizeBaseUrl2(rawUrl);
|
|
2600
|
-
try {
|
|
2601
|
-
const url = new URL(normalized);
|
|
2602
|
-
if (isLoopbackHost(url.hostname)) {
|
|
2603
|
-
url.hostname = "localhost";
|
|
2604
|
-
}
|
|
2605
|
-
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
2606
|
-
} catch {
|
|
2607
|
-
return normalized;
|
|
2608
|
-
}
|
|
2609
|
-
};
|
|
2610
|
-
var isLoopbackHost = (hostname2) => LOOPBACK_HOSTS2.has(hostname2);
|
|
2611
|
-
var isLoopbackUrl = (rawUrl) => {
|
|
2612
|
-
try {
|
|
2613
|
-
return isLoopbackHost(new URL(rawUrl).hostname);
|
|
2614
|
-
} catch {
|
|
2615
|
-
return false;
|
|
2616
|
-
}
|
|
2617
|
-
};
|
|
2618
|
-
var stripQuotes2 = (value) => {
|
|
2619
|
-
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
2620
|
-
return value.slice(1, -1);
|
|
2621
|
-
}
|
|
2622
|
-
return value;
|
|
2623
|
-
};
|
|
2624
|
-
var parseDotenv2 = (content) => {
|
|
2625
|
-
const result = {};
|
|
2626
|
-
for (const rawLine of content.split(NEWLINE_REGEX2)) {
|
|
2627
|
-
const line = rawLine.trim();
|
|
2628
|
-
if (!line || line.startsWith("#")) {
|
|
2629
|
-
continue;
|
|
2630
|
-
}
|
|
2631
|
-
const separatorIndex = line.indexOf("=");
|
|
2632
|
-
if (separatorIndex <= 0) {
|
|
2633
|
-
continue;
|
|
2634
|
-
}
|
|
2635
|
-
const key = line.slice(0, separatorIndex).trim();
|
|
2636
|
-
const value = line.slice(separatorIndex + 1).trim();
|
|
2637
|
-
result[key] = stripQuotes2(value);
|
|
2638
|
-
}
|
|
2639
|
-
return result;
|
|
2640
|
-
};
|
|
2641
|
-
var resolveLocalAuthWebBaseUrlFromEnv = (env) => {
|
|
2642
|
-
for (const key of LOCAL_AUTH_ENV_KEYS) {
|
|
2643
|
-
const value = env[key];
|
|
2644
|
-
if (value && isLoopbackUrl(value)) {
|
|
2645
|
-
return normalizeLoopbackBaseUrl(value);
|
|
2646
|
-
}
|
|
2647
|
-
}
|
|
2648
|
-
return void 0;
|
|
2649
|
-
};
|
|
2650
|
-
var resolveLocalAuthWebBaseUrlFromFiles = () => {
|
|
2651
|
-
const workspaceRoot = findBraidWorkspaceRoot();
|
|
2652
|
-
if (!workspaceRoot) {
|
|
2653
|
-
return void 0;
|
|
2654
|
-
}
|
|
2655
|
-
for (const envFile of LOCAL_AUTH_ENV_FILES) {
|
|
2656
|
-
const envPath = join4(workspaceRoot, ...envFile);
|
|
2657
|
-
if (!existsSync3(envPath)) {
|
|
2658
|
-
continue;
|
|
2659
|
-
}
|
|
2660
|
-
const localAppUrl = resolveLocalAuthWebBaseUrlFromEnv(
|
|
2661
|
-
parseDotenv2(readFileSync3(envPath, "utf8"))
|
|
2662
|
-
);
|
|
2663
|
-
if (localAppUrl) {
|
|
2664
|
-
return localAppUrl;
|
|
2665
|
-
}
|
|
2666
|
-
}
|
|
2667
|
-
return void 0;
|
|
2668
|
-
};
|
|
2669
|
-
var resolveLocalAuthWebBaseUrl = () => resolveLocalAuthWebBaseUrlFromEnv(process6.env) ?? resolveLocalAuthWebBaseUrlFromFiles();
|
|
2670
|
-
var normalizeServerBaseUrl = (serverUrl) => {
|
|
2671
|
-
const trimmed = normalizeBaseUrl2(serverUrl);
|
|
2672
|
-
try {
|
|
2673
|
-
const url = new URL(trimmed);
|
|
2674
|
-
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
2675
|
-
} catch {
|
|
2676
|
-
return trimmed;
|
|
2677
|
-
}
|
|
2678
|
-
};
|
|
2679
|
-
var resolveCanonicalAuthWebBaseUrl = (serverUrl) => {
|
|
2680
|
-
const normalized = normalizeServerBaseUrl(serverUrl);
|
|
2681
|
-
try {
|
|
2682
|
-
const url = new URL(normalized);
|
|
2683
|
-
if (LEGACY_BRAID_AUTH_HOSTS.has(url.hostname)) {
|
|
2684
|
-
url.hostname = BRAID_APP_HOST;
|
|
2685
|
-
url.pathname = "/";
|
|
2686
|
-
}
|
|
2687
|
-
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
2688
|
-
} catch {
|
|
2689
|
-
return normalized;
|
|
2690
|
-
}
|
|
2691
|
-
};
|
|
2692
|
-
var isHostedBraidAuthServer = (serverUrl) => {
|
|
2693
|
-
try {
|
|
2694
|
-
return DEFAULT_BRAID_AUTH_HOSTS.has(
|
|
2695
|
-
new URL(normalizeServerBaseUrl(serverUrl)).hostname
|
|
2696
|
-
);
|
|
2697
|
-
} catch {
|
|
2698
|
-
return false;
|
|
2699
|
-
}
|
|
2700
|
-
};
|
|
2701
|
-
function resolveAuthWebBaseUrl(serverUrl) {
|
|
2702
|
-
const canonicalBaseUrl = resolveCanonicalAuthWebBaseUrl(serverUrl);
|
|
2703
|
-
try {
|
|
2704
|
-
const url = new URL(canonicalBaseUrl);
|
|
2705
|
-
const localAuthBaseUrl = resolveLocalAuthWebBaseUrl();
|
|
2706
|
-
if (localAuthBaseUrl && (DEFAULT_BRAID_AUTH_HOSTS.has(url.hostname) || isLoopbackHost(url.hostname))) {
|
|
2707
|
-
return localAuthBaseUrl;
|
|
2708
|
-
}
|
|
2709
|
-
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
2710
|
-
} catch {
|
|
2711
|
-
return canonicalBaseUrl;
|
|
2712
|
-
}
|
|
2713
|
-
}
|
|
2714
|
-
function buildAuthVerificationUrlFromBaseUrl(authBaseUrl, userCode) {
|
|
2715
|
-
return `${authBaseUrl.replace(TRAILING_SLASHES2, "")}/cli/authorize?user_code=${encodeURIComponent(userCode)}`;
|
|
2716
|
-
}
|
|
2717
|
-
async function fetchAuthConfigFromBaseUrl(authBaseUrl) {
|
|
2718
|
-
const response = await fetch(`${authBaseUrl}/api/cli/auth-config`);
|
|
2719
|
-
if (!response.ok) {
|
|
2720
|
-
const body = await response.text();
|
|
2721
|
-
throw new Error(
|
|
2722
|
-
`Failed to fetch auth config (${response.status}): ${body}`
|
|
2723
|
-
);
|
|
2724
|
-
}
|
|
2725
|
-
return {
|
|
2726
|
-
...await response.json(),
|
|
2727
|
-
verificationBaseUrl: authBaseUrl
|
|
2728
|
-
};
|
|
2729
|
-
}
|
|
2730
|
-
async function fetchAuthConfig(serverUrl) {
|
|
2731
|
-
const authBaseUrl = resolveAuthWebBaseUrl(serverUrl).replace(
|
|
2732
|
-
TRAILING_SLASHES2,
|
|
2733
|
-
""
|
|
2734
|
-
);
|
|
2735
|
-
const canonicalAuthBaseUrl = resolveCanonicalAuthWebBaseUrl(
|
|
2736
|
-
serverUrl
|
|
2737
|
-
).replace(TRAILING_SLASHES2, "");
|
|
2738
|
-
try {
|
|
2739
|
-
return await fetchAuthConfigFromBaseUrl(authBaseUrl);
|
|
2740
|
-
} catch (error) {
|
|
2741
|
-
if (authBaseUrl !== canonicalAuthBaseUrl && isHostedBraidAuthServer(serverUrl)) {
|
|
2742
|
-
return fetchAuthConfigFromBaseUrl(canonicalAuthBaseUrl);
|
|
2743
|
-
}
|
|
2744
|
-
throw error;
|
|
2745
|
-
}
|
|
2746
|
-
}
|
|
2747
|
-
async function initiateDeviceAuth(convexSiteUrl, deviceInfo) {
|
|
2748
|
-
const url = `${convexSiteUrl.replace(TRAILING_SLASHES2, "")}/api/cli/device/authorize`;
|
|
2749
|
-
const response = await fetch(url, {
|
|
2750
|
-
method: "POST",
|
|
2751
|
-
headers: { "Content-Type": "application/json" },
|
|
2752
|
-
body: JSON.stringify(deviceInfo)
|
|
2753
|
-
});
|
|
2754
|
-
if (!response.ok) {
|
|
2755
|
-
const body = await response.text();
|
|
2756
|
-
throw new Error(
|
|
2757
|
-
`Failed to initiate device authorization (${response.status}): ${body}`
|
|
2758
|
-
);
|
|
2759
|
-
}
|
|
2760
|
-
return response.json();
|
|
2761
|
-
}
|
|
2762
|
-
async function pollForSession(convexSiteUrl, deviceCode, interval, expiresIn, timeoutSeconds) {
|
|
2763
|
-
const tokenUrl = `${convexSiteUrl.replace(TRAILING_SLASHES2, "")}/api/cli/device/token`;
|
|
2764
|
-
const deadline = Date.now() + Math.min(expiresIn, timeoutSeconds) * 1e3;
|
|
2765
|
-
let currentInterval = interval;
|
|
2766
|
-
while (Date.now() < deadline) {
|
|
2767
|
-
await sleep(currentInterval * 1e3);
|
|
2768
|
-
const response = await fetch(tokenUrl, {
|
|
2769
|
-
method: "POST",
|
|
2770
|
-
headers: { "Content-Type": "application/json" },
|
|
2771
|
-
body: JSON.stringify({ device_code: deviceCode })
|
|
2772
|
-
});
|
|
2773
|
-
if (response.ok) {
|
|
2774
|
-
const result = await response.json();
|
|
2775
|
-
return {
|
|
2776
|
-
sessionToken: result.session_token,
|
|
2777
|
-
expiresAt: result.expires_at,
|
|
2778
|
-
user: result.user
|
|
2779
|
-
};
|
|
2780
|
-
}
|
|
2781
|
-
let errorCode;
|
|
2782
|
-
try {
|
|
2783
|
-
const errorBody = await response.json();
|
|
2784
|
-
errorCode = errorBody.error;
|
|
2785
|
-
} catch {
|
|
2786
|
-
throw new Error(`Device auth polling error: HTTP ${response.status}`);
|
|
2787
|
-
}
|
|
2788
|
-
if (errorCode === "authorization_pending") {
|
|
2789
|
-
continue;
|
|
2790
|
-
}
|
|
2791
|
-
if (errorCode === "slow_down") {
|
|
2792
|
-
currentInterval += 5;
|
|
2793
|
-
continue;
|
|
2794
|
-
}
|
|
2795
|
-
if (errorCode === "expired_token") {
|
|
2796
|
-
throw new DeviceAuthExpiredError();
|
|
2797
|
-
}
|
|
2798
|
-
if (errorCode === "access_denied") {
|
|
2799
|
-
throw new DeviceAuthDeniedError();
|
|
2800
|
-
}
|
|
2801
|
-
throw new Error(
|
|
2802
|
-
`Device auth polling error: ${errorCode ?? `HTTP ${response.status}`}`
|
|
2803
|
-
);
|
|
2804
|
-
}
|
|
2805
|
-
throw new DeviceAuthTimeoutError();
|
|
2806
|
-
}
|
|
2807
|
-
async function fetchSessionInfo(convexSiteUrl, sessionToken) {
|
|
2808
|
-
const url = `${convexSiteUrl.replace(TRAILING_SLASHES2, "")}/api/cli/sessions/me`;
|
|
2809
|
-
const response = await fetch(url, {
|
|
2810
|
-
method: "GET",
|
|
2811
|
-
headers: {
|
|
2812
|
-
Authorization: `Bearer ${sessionToken}`
|
|
2813
|
-
}
|
|
2814
|
-
});
|
|
2815
|
-
if (response.status === 404) {
|
|
2816
|
-
return null;
|
|
2817
|
-
}
|
|
2818
|
-
if (!response.ok) {
|
|
2819
|
-
const body = await response.text();
|
|
2820
|
-
throw new Error(
|
|
2821
|
-
`Failed to fetch session info (${response.status}): ${body}`
|
|
2822
|
-
);
|
|
2823
|
-
}
|
|
2824
|
-
return response.json();
|
|
2825
|
-
}
|
|
2826
|
-
async function revokeSession(convexSiteUrl, sessionToken) {
|
|
2827
|
-
const url = `${convexSiteUrl.replace(TRAILING_SLASHES2, "")}/api/cli/sessions/me`;
|
|
2828
|
-
const response = await fetch(url, {
|
|
2829
|
-
method: "DELETE",
|
|
2830
|
-
headers: {
|
|
2831
|
-
Authorization: `Bearer ${sessionToken}`
|
|
3228
|
+
installPath
|
|
3229
|
+
);
|
|
3230
|
+
summary.push({
|
|
3231
|
+
platform: target.id,
|
|
3232
|
+
installPath,
|
|
3233
|
+
written: result.written.length,
|
|
3234
|
+
warnings: result.warnings,
|
|
3235
|
+
errors: result.errors
|
|
3236
|
+
});
|
|
2832
3237
|
}
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
}
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
}
|
|
2850
|
-
|
|
2851
|
-
} else {
|
|
2852
|
-
execFile("xdg-open", [url], noop);
|
|
3238
|
+
if (options.json) {
|
|
3239
|
+
writeJson(summary);
|
|
3240
|
+
return;
|
|
3241
|
+
}
|
|
3242
|
+
for (const item of summary) {
|
|
3243
|
+
log.info(
|
|
3244
|
+
`${item.platform}: ${item.written} file(s) written${item.installPath ? ` to ${item.installPath}` : ""}`
|
|
3245
|
+
);
|
|
3246
|
+
for (const warning of item.warnings) {
|
|
3247
|
+
log.warn(` warning: ${warning}`);
|
|
3248
|
+
}
|
|
3249
|
+
for (const error of item.errors) {
|
|
3250
|
+
log.error(` error (${error.agent}): ${error.error}`);
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
log.success("sub-agents install completed");
|
|
3254
|
+
} catch (error) {
|
|
3255
|
+
exitCommandError(error, { json: options.json });
|
|
2853
3256
|
}
|
|
2854
3257
|
}
|
|
2855
|
-
function getDeviceInfo() {
|
|
2856
|
-
return {
|
|
2857
|
-
deviceName: hostname(),
|
|
2858
|
-
deviceOs: platform(),
|
|
2859
|
-
deviceHostname: hostname()
|
|
2860
|
-
};
|
|
2861
|
-
}
|
|
2862
3258
|
|
|
2863
3259
|
// src/commands/auth.ts
|
|
3260
|
+
init_esm_shims();
|
|
3261
|
+
init_api();
|
|
3262
|
+
init_config();
|
|
3263
|
+
init_device_auth();
|
|
2864
3264
|
init_tui();
|
|
2865
|
-
|
|
3265
|
+
import process10 from "process";
|
|
3266
|
+
var SESSION_TOKEN_PREFIX3 = "brs_";
|
|
3267
|
+
var LOOPBACK_HOSTS3 = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "localhost"]);
|
|
2866
3268
|
var DEFAULT_TIMEOUT_SECONDS = 300;
|
|
3269
|
+
var resolvePersistedCliServerUrl = (serverUrl, convexSiteUrl) => {
|
|
3270
|
+
try {
|
|
3271
|
+
const convexUrl = new URL(convexSiteUrl);
|
|
3272
|
+
if (LOOPBACK_HOSTS3.has(convexUrl.hostname)) {
|
|
3273
|
+
return convexSiteUrl;
|
|
3274
|
+
}
|
|
3275
|
+
} catch {
|
|
3276
|
+
return serverUrl;
|
|
3277
|
+
}
|
|
3278
|
+
return serverUrl;
|
|
3279
|
+
};
|
|
2867
3280
|
async function configureDefaultScopeAsync(serverUrl) {
|
|
2868
3281
|
const shouldConfigureScope = await confirm({
|
|
2869
3282
|
message: "Configure organization and scope defaults now?",
|
|
@@ -2898,9 +3311,9 @@ async function manualTokenFlow(apiKey, serverUrl, options) {
|
|
|
2898
3311
|
log.error(
|
|
2899
3312
|
"The API key could not be validated. Please check your key and try again."
|
|
2900
3313
|
);
|
|
2901
|
-
|
|
3314
|
+
process10.exit(1);
|
|
2902
3315
|
}
|
|
2903
|
-
await persistApiKeyAsync(apiKey);
|
|
3316
|
+
await persistApiKeyAsync(apiKey, serverUrl);
|
|
2904
3317
|
stopAuthSpinner("API key validated and saved");
|
|
2905
3318
|
if (options.scope !== false) {
|
|
2906
3319
|
await configureDefaultScopeAsync(serverUrl);
|
|
@@ -2913,7 +3326,7 @@ async function manualTokenFlow(apiKey, serverUrl, options) {
|
|
|
2913
3326
|
stopAuthSpinner("Validation failed");
|
|
2914
3327
|
const message = error instanceof Error ? error.message : String(error);
|
|
2915
3328
|
log.error(`Failed to validate API key: ${message}`);
|
|
2916
|
-
|
|
3329
|
+
process10.exit(1);
|
|
2917
3330
|
}
|
|
2918
3331
|
}
|
|
2919
3332
|
function handlePollingError(error) {
|
|
@@ -2927,7 +3340,7 @@ function handlePollingError(error) {
|
|
|
2927
3340
|
const message = error instanceof Error ? error.message : String(error);
|
|
2928
3341
|
log.error(`Authentication failed: ${message}`);
|
|
2929
3342
|
}
|
|
2930
|
-
|
|
3343
|
+
process10.exit(1);
|
|
2931
3344
|
}
|
|
2932
3345
|
async function deviceFlow(serverUrl, timeoutSeconds, options) {
|
|
2933
3346
|
const configSpinner = spinner();
|
|
@@ -2940,7 +3353,7 @@ async function deviceFlow(serverUrl, timeoutSeconds, options) {
|
|
|
2940
3353
|
configSpinner.stop("Failed to fetch auth configuration");
|
|
2941
3354
|
const message = error instanceof Error ? error.message : String(error);
|
|
2942
3355
|
log.error(`Could not connect to server: ${message}`);
|
|
2943
|
-
|
|
3356
|
+
process10.exit(1);
|
|
2944
3357
|
}
|
|
2945
3358
|
const deviceSpinner = spinner();
|
|
2946
3359
|
deviceSpinner.start("Initiating device authorization...");
|
|
@@ -2955,7 +3368,7 @@ async function deviceFlow(serverUrl, timeoutSeconds, options) {
|
|
|
2955
3368
|
deviceSpinner.stop("Failed to initiate device authorization");
|
|
2956
3369
|
const message = error instanceof Error ? error.message : String(error);
|
|
2957
3370
|
log.error(`Device authorization failed: ${message}`);
|
|
2958
|
-
|
|
3371
|
+
process10.exit(1);
|
|
2959
3372
|
}
|
|
2960
3373
|
const verificationUrl = buildAuthVerificationUrlFromBaseUrl(
|
|
2961
3374
|
authConfig.verificationBaseUrl,
|
|
@@ -2989,9 +3402,13 @@ async function deviceFlow(serverUrl, timeoutSeconds, options) {
|
|
|
2989
3402
|
pollSpinner.stop("Authentication failed");
|
|
2990
3403
|
handlePollingError(error);
|
|
2991
3404
|
}
|
|
2992
|
-
|
|
3405
|
+
const persistedServerUrl = resolvePersistedCliServerUrl(
|
|
3406
|
+
serverUrl,
|
|
3407
|
+
authConfig.convexSiteUrl
|
|
3408
|
+
);
|
|
3409
|
+
await persistApiKeyAsync(session.sessionToken, persistedServerUrl);
|
|
2993
3410
|
if (options.scope !== false) {
|
|
2994
|
-
await configureDefaultScopeAsync(
|
|
3411
|
+
await configureDefaultScopeAsync(persistedServerUrl);
|
|
2995
3412
|
}
|
|
2996
3413
|
log.success(`Session saved to ${CONFIG_FILE}`);
|
|
2997
3414
|
outro(
|
|
@@ -3019,12 +3436,12 @@ async function authCommand(options) {
|
|
|
3019
3436
|
const timeoutSeconds = options.timeout ? Number.parseInt(options.timeout, 10) : DEFAULT_TIMEOUT_SECONDS;
|
|
3020
3437
|
if (Number.isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
|
|
3021
3438
|
log.error("Invalid timeout value. Must be a positive number of seconds.");
|
|
3022
|
-
|
|
3439
|
+
process10.exit(1);
|
|
3023
3440
|
}
|
|
3024
3441
|
await deviceFlow(serverUrl, timeoutSeconds, options);
|
|
3025
3442
|
}
|
|
3026
3443
|
async function displayTokenSource(masked) {
|
|
3027
|
-
if (
|
|
3444
|
+
if (process10.env.BRAID_API_KEY) {
|
|
3028
3445
|
log.info(`Authenticated with key: ${masked}`);
|
|
3029
3446
|
log.info("Source: BRAID_API_KEY environment variable");
|
|
3030
3447
|
return;
|
|
@@ -3105,7 +3522,7 @@ async function authStatusCommand() {
|
|
|
3105
3522
|
);
|
|
3106
3523
|
return;
|
|
3107
3524
|
}
|
|
3108
|
-
if (config.token.startsWith(
|
|
3525
|
+
if (config.token.startsWith(SESSION_TOKEN_PREFIX3)) {
|
|
3109
3526
|
await displaySessionInfo(config.token);
|
|
3110
3527
|
await displayProjectConfig();
|
|
3111
3528
|
displayResolvedSettings(config);
|
|
@@ -3128,7 +3545,7 @@ async function revokeSessionIfActive(token) {
|
|
|
3128
3545
|
async function authLogoutCommand() {
|
|
3129
3546
|
const config = await loadMergedConfigAsync();
|
|
3130
3547
|
const { clearApiKeyAsync: clearApiKeyAsync2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
3131
|
-
if (config.token?.startsWith(
|
|
3548
|
+
if (config.token?.startsWith(SESSION_TOKEN_PREFIX3)) {
|
|
3132
3549
|
await revokeSessionIfActive(config.token);
|
|
3133
3550
|
}
|
|
3134
3551
|
await clearApiKeyAsync2();
|
|
@@ -3140,7 +3557,6 @@ init_esm_shims();
|
|
|
3140
3557
|
init_api();
|
|
3141
3558
|
init_config();
|
|
3142
3559
|
init_tui();
|
|
3143
|
-
import process9 from "process";
|
|
3144
3560
|
var parseCsv2 = (input) => {
|
|
3145
3561
|
if (!input) {
|
|
3146
3562
|
return void 0;
|
|
@@ -3148,15 +3564,6 @@ var parseCsv2 = (input) => {
|
|
|
3148
3564
|
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
3149
3565
|
return values.length > 0 ? values : void 0;
|
|
3150
3566
|
};
|
|
3151
|
-
var writeJson2 = (value) => {
|
|
3152
|
-
process9.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
3153
|
-
`);
|
|
3154
|
-
};
|
|
3155
|
-
var exitWithError2 = (error) => {
|
|
3156
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
3157
|
-
log.error(message);
|
|
3158
|
-
process9.exit(1);
|
|
3159
|
-
};
|
|
3160
3567
|
var applyCommonOptions = (base, options) => ({
|
|
3161
3568
|
...base,
|
|
3162
3569
|
...options.server ? { serverUrl: options.server } : {},
|
|
@@ -3183,7 +3590,7 @@ async function projectsListCommand(options) {
|
|
|
3183
3590
|
applyCommonOptions({}, options)
|
|
3184
3591
|
);
|
|
3185
3592
|
if (options.json) {
|
|
3186
|
-
|
|
3593
|
+
writeJson(result);
|
|
3187
3594
|
return;
|
|
3188
3595
|
}
|
|
3189
3596
|
log.info("Personal projects:");
|
|
@@ -3205,7 +3612,7 @@ Organization: ${orgProjects.orgName} (${orgProjects.orgId})`);
|
|
|
3205
3612
|
}
|
|
3206
3613
|
}
|
|
3207
3614
|
} catch (error) {
|
|
3208
|
-
|
|
3615
|
+
exitCommandError(error, { json: options.json });
|
|
3209
3616
|
}
|
|
3210
3617
|
}
|
|
3211
3618
|
var buildRulesRequest = async (options) => {
|
|
@@ -3226,7 +3633,7 @@ async function rulesListCommand(options) {
|
|
|
3226
3633
|
await buildRulesRequest(options)
|
|
3227
3634
|
);
|
|
3228
3635
|
if (options.json) {
|
|
3229
|
-
|
|
3636
|
+
writeJson(result);
|
|
3230
3637
|
return;
|
|
3231
3638
|
}
|
|
3232
3639
|
if (result.rules.length === 0) {
|
|
@@ -3237,7 +3644,7 @@ async function rulesListCommand(options) {
|
|
|
3237
3644
|
log.info(`${rule.id} ${rule.title}`);
|
|
3238
3645
|
}
|
|
3239
3646
|
} catch (error) {
|
|
3240
|
-
|
|
3647
|
+
exitCommandError(error, { json: options.json });
|
|
3241
3648
|
}
|
|
3242
3649
|
}
|
|
3243
3650
|
var buildSkillsRequest = async (options) => {
|
|
@@ -3257,7 +3664,7 @@ async function skillsListCommand(options) {
|
|
|
3257
3664
|
try {
|
|
3258
3665
|
const result = await fetchSkillsAsync(await buildSkillsRequest(options));
|
|
3259
3666
|
if (options.json) {
|
|
3260
|
-
|
|
3667
|
+
writeJson(result);
|
|
3261
3668
|
return;
|
|
3262
3669
|
}
|
|
3263
3670
|
if (result.skills.length === 0) {
|
|
@@ -3268,7 +3675,7 @@ async function skillsListCommand(options) {
|
|
|
3268
3675
|
log.info(`${skill.name}`);
|
|
3269
3676
|
}
|
|
3270
3677
|
} catch (error) {
|
|
3271
|
-
|
|
3678
|
+
exitCommandError(error, { json: options.json });
|
|
3272
3679
|
}
|
|
3273
3680
|
}
|
|
3274
3681
|
|
|
@@ -3415,11 +3822,11 @@ init_lockfile();
|
|
|
3415
3822
|
init_esm_shims();
|
|
3416
3823
|
import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
3417
3824
|
import { dirname as dirname6, join as join7 } from "path";
|
|
3418
|
-
import { Data as
|
|
3825
|
+
import { Data as Data6, Effect as Effect7, pipe as pipe7 } from "effect";
|
|
3419
3826
|
var METADATA_FILENAME2 = ".braid-metadata.json";
|
|
3420
|
-
var MetadataReadError = class extends
|
|
3827
|
+
var MetadataReadError = class extends Data6.TaggedError("MetadataReadError") {
|
|
3421
3828
|
};
|
|
3422
|
-
var MetadataWriteError = class extends
|
|
3829
|
+
var MetadataWriteError = class extends Data6.TaggedError("MetadataWriteError") {
|
|
3423
3830
|
};
|
|
3424
3831
|
var normalizeInstalledSkill = (skill) => ({
|
|
3425
3832
|
kind: skill.kind ?? "skill",
|
|
@@ -3435,18 +3842,18 @@ var normalizeMetadata = (metadata) => ({
|
|
|
3435
3842
|
var getMetadataPath = (skillsDir) => join7(dirname6(skillsDir), METADATA_FILENAME2);
|
|
3436
3843
|
var readMetadata = (skillsDir) => {
|
|
3437
3844
|
const metadataPath = getMetadataPath(skillsDir);
|
|
3438
|
-
return
|
|
3439
|
-
|
|
3845
|
+
return pipe7(
|
|
3846
|
+
Effect7.tryPromise({
|
|
3440
3847
|
try: () => readFile4(metadataPath, "utf-8"),
|
|
3441
3848
|
catch: (e) => new MetadataReadError({ path: metadataPath, cause: e })
|
|
3442
3849
|
}),
|
|
3443
|
-
|
|
3444
|
-
(content) =>
|
|
3850
|
+
Effect7.flatMap(
|
|
3851
|
+
(content) => Effect7.try({
|
|
3445
3852
|
try: () => normalizeMetadata(JSON.parse(content)),
|
|
3446
3853
|
catch: () => normalizeMetadata(void 0)
|
|
3447
3854
|
})
|
|
3448
3855
|
),
|
|
3449
|
-
|
|
3856
|
+
Effect7.orElseSucceed(() => normalizeMetadata(void 0))
|
|
3450
3857
|
);
|
|
3451
3858
|
};
|
|
3452
3859
|
var readRawJson = async (path2) => {
|
|
@@ -3463,7 +3870,7 @@ var readRawJson = async (path2) => {
|
|
|
3463
3870
|
};
|
|
3464
3871
|
var writeMetadata = (skillsDir, metadata) => {
|
|
3465
3872
|
const metadataPath = getMetadataPath(skillsDir);
|
|
3466
|
-
return
|
|
3873
|
+
return Effect7.tryPromise({
|
|
3467
3874
|
try: async () => {
|
|
3468
3875
|
const existing = await readRawJson(metadataPath);
|
|
3469
3876
|
const merged = { ...existing, skills: metadata.skills };
|
|
@@ -3472,9 +3879,9 @@ var writeMetadata = (skillsDir, metadata) => {
|
|
|
3472
3879
|
catch: (e) => new MetadataWriteError({ path: metadataPath, cause: e })
|
|
3473
3880
|
});
|
|
3474
3881
|
};
|
|
3475
|
-
var updateMetadata = (skillsDir, newSkills) =>
|
|
3882
|
+
var updateMetadata = (skillsDir, newSkills) => pipe7(
|
|
3476
3883
|
readMetadata(skillsDir),
|
|
3477
|
-
|
|
3884
|
+
Effect7.map((existing) => {
|
|
3478
3885
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3479
3886
|
const updatedSkills = [...existing.skills];
|
|
3480
3887
|
for (const skill of newSkills) {
|
|
@@ -3497,35 +3904,35 @@ var updateMetadata = (skillsDir, newSkills) => pipe6(
|
|
|
3497
3904
|
}
|
|
3498
3905
|
return { skills: updatedSkills };
|
|
3499
3906
|
}),
|
|
3500
|
-
|
|
3907
|
+
Effect7.flatMap((metadata) => writeMetadata(skillsDir, metadata))
|
|
3501
3908
|
);
|
|
3502
|
-
var removeFromMetadata = (skillsDir, skillName) =>
|
|
3909
|
+
var removeFromMetadata = (skillsDir, skillName) => pipe7(
|
|
3503
3910
|
readMetadata(skillsDir),
|
|
3504
|
-
|
|
3911
|
+
Effect7.map((metadata) => ({
|
|
3505
3912
|
skills: metadata.skills.filter((s) => s.name !== skillName)
|
|
3506
3913
|
})),
|
|
3507
|
-
|
|
3914
|
+
Effect7.flatMap((metadata) => writeMetadata(skillsDir, metadata))
|
|
3508
3915
|
);
|
|
3509
|
-
var readMetadataAsync = (skillsDir) =>
|
|
3510
|
-
var updateMetadataAsync = (skillsDir, newSkills) =>
|
|
3511
|
-
var removeFromMetadataAsync = (skillsDir, skillName) =>
|
|
3916
|
+
var readMetadataAsync = (skillsDir) => Effect7.runPromise(readMetadata(skillsDir));
|
|
3917
|
+
var updateMetadataAsync = (skillsDir, newSkills) => Effect7.runPromise(updateMetadata(skillsDir, newSkills));
|
|
3918
|
+
var removeFromMetadataAsync = (skillsDir, skillName) => Effect7.runPromise(removeFromMetadata(skillsDir, skillName));
|
|
3512
3919
|
|
|
3513
3920
|
// src/lib/rule-writer.ts
|
|
3514
3921
|
init_esm_shims();
|
|
3515
3922
|
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile6 } from "fs/promises";
|
|
3516
3923
|
import { dirname as dirname7, resolve as resolve3, sep as sep2 } from "path";
|
|
3517
|
-
import { Data as
|
|
3518
|
-
var RuleWriteError = class extends
|
|
3924
|
+
import { Data as Data7, Effect as Effect8, pipe as pipe8 } from "effect";
|
|
3925
|
+
var RuleWriteError = class extends Data7.TaggedError("RuleWriteError") {
|
|
3519
3926
|
};
|
|
3520
|
-
var createDirectory = (dir) =>
|
|
3927
|
+
var createDirectory = (dir) => Effect8.tryPromise({
|
|
3521
3928
|
try: () => mkdir4(dir, { recursive: true }),
|
|
3522
3929
|
catch: (e) => new RuleWriteError({ path: dir, operation: "mkdir", cause: e })
|
|
3523
3930
|
});
|
|
3524
|
-
var writeTextFile = (fullPath, content) =>
|
|
3931
|
+
var writeTextFile = (fullPath, content) => Effect8.tryPromise({
|
|
3525
3932
|
try: () => writeFile6(fullPath, content, "utf-8"),
|
|
3526
3933
|
catch: (e) => new RuleWriteError({ path: fullPath, operation: "write", cause: e })
|
|
3527
3934
|
});
|
|
3528
|
-
var readTextFile = (fullPath) =>
|
|
3935
|
+
var readTextFile = (fullPath) => Effect8.tryPromise({
|
|
3529
3936
|
try: () => readFile5(fullPath, "utf-8"),
|
|
3530
3937
|
catch: (e) => new RuleWriteError({ path: fullPath, operation: "read", cause: e })
|
|
3531
3938
|
});
|
|
@@ -3533,7 +3940,7 @@ var assertRulePathWithinBase = (basePath, ruleName) => {
|
|
|
3533
3940
|
const resolvedBase = resolve3(basePath);
|
|
3534
3941
|
const resolvedFull = resolve3(basePath, ruleName);
|
|
3535
3942
|
if (resolvedFull !== resolvedBase && !resolvedFull.startsWith(resolvedBase + sep2)) {
|
|
3536
|
-
return
|
|
3943
|
+
return Effect8.fail(
|
|
3537
3944
|
new RuleWriteError({
|
|
3538
3945
|
path: ruleName,
|
|
3539
3946
|
operation: "write",
|
|
@@ -3543,7 +3950,7 @@ var assertRulePathWithinBase = (basePath, ruleName) => {
|
|
|
3543
3950
|
})
|
|
3544
3951
|
);
|
|
3545
3952
|
}
|
|
3546
|
-
return
|
|
3953
|
+
return Effect8.succeed(resolvedFull);
|
|
3547
3954
|
};
|
|
3548
3955
|
var BRAID_SECTION_START = "<!-- braid:rules:start -->";
|
|
3549
3956
|
var BRAID_SECTION_END = "<!-- braid:rules:end -->";
|
|
@@ -3576,30 +3983,30 @@ function buildAppendContent(rules2) {
|
|
|
3576
3983
|
lines.push(BRAID_SECTION_END);
|
|
3577
3984
|
return lines.join("\n");
|
|
3578
3985
|
}
|
|
3579
|
-
var writeMdcRules = (basePath, rules2) =>
|
|
3986
|
+
var writeMdcRules = (basePath, rules2) => pipe8(
|
|
3580
3987
|
createDirectory(basePath),
|
|
3581
|
-
|
|
3582
|
-
() =>
|
|
3988
|
+
Effect8.flatMap(
|
|
3989
|
+
() => Effect8.forEach(
|
|
3583
3990
|
rules2,
|
|
3584
|
-
(rule) =>
|
|
3991
|
+
(rule) => pipe8(
|
|
3585
3992
|
assertRulePathWithinBase(basePath, `${rule.name}.mdc`),
|
|
3586
|
-
|
|
3993
|
+
Effect8.flatMap(
|
|
3587
3994
|
(filePath) => writeTextFile(filePath, buildMdcContent(rule))
|
|
3588
3995
|
)
|
|
3589
3996
|
),
|
|
3590
3997
|
{ concurrency: "unbounded" }
|
|
3591
3998
|
)
|
|
3592
3999
|
),
|
|
3593
|
-
|
|
4000
|
+
Effect8.asVoid
|
|
3594
4001
|
);
|
|
3595
|
-
var writeMarkdownDirRules = (basePath, rules2) =>
|
|
4002
|
+
var writeMarkdownDirRules = (basePath, rules2) => pipe8(
|
|
3596
4003
|
createDirectory(basePath),
|
|
3597
|
-
|
|
3598
|
-
() =>
|
|
4004
|
+
Effect8.flatMap(
|
|
4005
|
+
() => Effect8.forEach(
|
|
3599
4006
|
rules2,
|
|
3600
|
-
(rule) =>
|
|
4007
|
+
(rule) => pipe8(
|
|
3601
4008
|
assertRulePathWithinBase(basePath, `${rule.name}.md`),
|
|
3602
|
-
|
|
4009
|
+
Effect8.flatMap(
|
|
3603
4010
|
(filePath) => writeTextFile(filePath, `# ${rule.title}
|
|
3604
4011
|
|
|
3605
4012
|
${rule.content}`)
|
|
@@ -3608,17 +4015,17 @@ ${rule.content}`)
|
|
|
3608
4015
|
{ concurrency: "unbounded" }
|
|
3609
4016
|
)
|
|
3610
4017
|
),
|
|
3611
|
-
|
|
4018
|
+
Effect8.asVoid
|
|
3612
4019
|
);
|
|
3613
|
-
var writeAppendSingleRules = (filePath, rules2) =>
|
|
4020
|
+
var writeAppendSingleRules = (filePath, rules2) => pipe8(
|
|
3614
4021
|
createDirectory(dirname7(filePath)),
|
|
3615
|
-
|
|
3616
|
-
() =>
|
|
4022
|
+
Effect8.flatMap(
|
|
4023
|
+
() => pipe8(
|
|
3617
4024
|
readTextFile(filePath),
|
|
3618
|
-
|
|
4025
|
+
Effect8.orElseSucceed(() => "")
|
|
3619
4026
|
)
|
|
3620
4027
|
),
|
|
3621
|
-
|
|
4028
|
+
Effect8.flatMap((existing) => {
|
|
3622
4029
|
const braidContent = buildAppendContent(rules2);
|
|
3623
4030
|
const startIdx = existing.indexOf(BRAID_SECTION_START);
|
|
3624
4031
|
const endIdx = existing.indexOf(BRAID_SECTION_END);
|
|
@@ -3642,21 +4049,21 @@ var writeRulesForFormat = (basePath, rules2, format) => {
|
|
|
3642
4049
|
case "append-single":
|
|
3643
4050
|
return writeAppendSingleRules(basePath, rules2);
|
|
3644
4051
|
default:
|
|
3645
|
-
return
|
|
4052
|
+
return Effect8.void;
|
|
3646
4053
|
}
|
|
3647
4054
|
};
|
|
3648
4055
|
var writeRulesForAgent = (agent, rules2, rulesPath) => {
|
|
3649
4056
|
if (!agent.ruleFormat || rules2.length === 0) {
|
|
3650
|
-
return
|
|
4057
|
+
return Effect8.succeed({ written: 0, errors: [] });
|
|
3651
4058
|
}
|
|
3652
|
-
return
|
|
4059
|
+
return pipe8(
|
|
3653
4060
|
writeRulesForFormat(rulesPath, rules2, agent.ruleFormat),
|
|
3654
|
-
|
|
4061
|
+
Effect8.map(() => ({
|
|
3655
4062
|
written: rules2.length,
|
|
3656
4063
|
errors: []
|
|
3657
4064
|
})),
|
|
3658
|
-
|
|
3659
|
-
(error) =>
|
|
4065
|
+
Effect8.catch(
|
|
4066
|
+
(error) => Effect8.succeed({
|
|
3660
4067
|
written: 0,
|
|
3661
4068
|
errors: [
|
|
3662
4069
|
{
|
|
@@ -3668,29 +4075,29 @@ var writeRulesForAgent = (agent, rules2, rulesPath) => {
|
|
|
3668
4075
|
)
|
|
3669
4076
|
);
|
|
3670
4077
|
};
|
|
3671
|
-
var writeRulesForAgentAsync = (agent, rules2, rulesPath) =>
|
|
4078
|
+
var writeRulesForAgentAsync = (agent, rules2, rulesPath) => Effect8.runPromise(writeRulesForAgent(agent, rules2, rulesPath));
|
|
3672
4079
|
|
|
3673
4080
|
// src/lib/skill-writer.ts
|
|
3674
4081
|
init_esm_shims();
|
|
3675
4082
|
import { createHash as createHash2 } from "crypto";
|
|
3676
4083
|
import { chmod, mkdir as mkdir5, rm as rm2, symlink, writeFile as writeFile7 } from "fs/promises";
|
|
3677
4084
|
import { dirname as dirname8, join as join8, resolve as resolve4, sep as sep3 } from "path";
|
|
3678
|
-
import { Data as
|
|
3679
|
-
var WriteError = class extends
|
|
4085
|
+
import { Data as Data8, Effect as Effect9, pipe as pipe9 } from "effect";
|
|
4086
|
+
var WriteError = class extends Data8.TaggedError("WriteError") {
|
|
3680
4087
|
};
|
|
3681
|
-
var createDirectory2 = (dir, fullPath) =>
|
|
4088
|
+
var createDirectory2 = (dir, fullPath) => Effect9.tryPromise({
|
|
3682
4089
|
try: () => mkdir5(dir, { recursive: true }),
|
|
3683
4090
|
catch: (e) => new WriteError({ path: fullPath, operation: "mkdir", cause: e })
|
|
3684
4091
|
});
|
|
3685
|
-
var writeTextFile2 = (fullPath, content) =>
|
|
4092
|
+
var writeTextFile2 = (fullPath, content) => Effect9.tryPromise({
|
|
3686
4093
|
try: () => writeFile7(fullPath, content, "utf-8"),
|
|
3687
4094
|
catch: (e) => new WriteError({ path: fullPath, operation: "write", cause: e })
|
|
3688
4095
|
});
|
|
3689
|
-
var writeBinaryFile = (fullPath, content) =>
|
|
4096
|
+
var writeBinaryFile = (fullPath, content) => Effect9.tryPromise({
|
|
3690
4097
|
try: () => writeFile7(fullPath, content),
|
|
3691
4098
|
catch: (e) => new WriteError({ path: fullPath, operation: "write", cause: e })
|
|
3692
4099
|
});
|
|
3693
|
-
var makeExecutable = (fullPath) =>
|
|
4100
|
+
var makeExecutable = (fullPath) => Effect9.tryPromise({
|
|
3694
4101
|
try: () => chmod(fullPath, 493),
|
|
3695
4102
|
catch: (e) => new WriteError({ path: fullPath, operation: "chmod", cause: e })
|
|
3696
4103
|
});
|
|
@@ -3698,7 +4105,7 @@ var assertWithinBase2 = (basePath, untrustedPath) => {
|
|
|
3698
4105
|
const resolvedBase = resolve4(basePath);
|
|
3699
4106
|
const resolvedFull = resolve4(basePath, untrustedPath);
|
|
3700
4107
|
if (resolvedFull !== resolvedBase && !resolvedFull.startsWith(resolvedBase + sep3)) {
|
|
3701
|
-
return
|
|
4108
|
+
return Effect9.fail(
|
|
3702
4109
|
new WriteError({
|
|
3703
4110
|
path: untrustedPath,
|
|
3704
4111
|
operation: "write",
|
|
@@ -3708,7 +4115,7 @@ var assertWithinBase2 = (basePath, untrustedPath) => {
|
|
|
3708
4115
|
})
|
|
3709
4116
|
);
|
|
3710
4117
|
}
|
|
3711
|
-
return
|
|
4118
|
+
return Effect9.succeed(resolvedFull);
|
|
3712
4119
|
};
|
|
3713
4120
|
var COMPATIBILITY_REGEX = /^compatibility:\s*.+$/m;
|
|
3714
4121
|
var rewriteCompatibility = (content, agentId) => {
|
|
@@ -3751,22 +4158,22 @@ var isScriptFile = (path2) => {
|
|
|
3751
4158
|
return inScriptsDir && scriptExtensions.some((ext) => lowerPath.endsWith(ext));
|
|
3752
4159
|
};
|
|
3753
4160
|
var writeFileContent = (fullPath, file, agentId) => isBinaryFile(file.path) ? writeBinaryFile(fullPath, decodeFileContentBinary(file)) : writeTextFile2(fullPath, decodeFileContent(file, agentId));
|
|
3754
|
-
var setExecutableIfScript = (fullPath, file, agentId) => isScriptFile(file.path) && decodeFileContent(file, agentId).startsWith("#!") ? makeExecutable(fullPath) :
|
|
3755
|
-
var writeSkillFile = (basePath, file, agentId) =>
|
|
4161
|
+
var setExecutableIfScript = (fullPath, file, agentId) => isScriptFile(file.path) && decodeFileContent(file, agentId).startsWith("#!") ? makeExecutable(fullPath) : Effect9.void;
|
|
4162
|
+
var writeSkillFile = (basePath, file, agentId) => pipe9(
|
|
3756
4163
|
assertWithinBase2(basePath, file.path),
|
|
3757
|
-
|
|
4164
|
+
Effect9.flatMap((fullPath) => {
|
|
3758
4165
|
const dir = dirname8(fullPath);
|
|
3759
|
-
return
|
|
4166
|
+
return pipe9(
|
|
3760
4167
|
createDirectory2(dir, fullPath),
|
|
3761
|
-
|
|
3762
|
-
|
|
4168
|
+
Effect9.flatMap(() => writeFileContent(fullPath, file, agentId)),
|
|
4169
|
+
Effect9.flatMap(() => setExecutableIfScript(fullPath, file, agentId))
|
|
3763
4170
|
);
|
|
3764
4171
|
})
|
|
3765
4172
|
);
|
|
3766
|
-
var writeSkillAtPath = (skillPath, skill, agentId) =>
|
|
4173
|
+
var writeSkillAtPath = (skillPath, skill, agentId) => pipe9(
|
|
3767
4174
|
createDirectory2(skillPath, skillPath),
|
|
3768
|
-
|
|
3769
|
-
() =>
|
|
4175
|
+
Effect9.flatMap(
|
|
4176
|
+
() => Effect9.forEach(
|
|
3770
4177
|
skill.files,
|
|
3771
4178
|
(file) => writeSkillFile(skillPath, file, agentId),
|
|
3772
4179
|
{
|
|
@@ -3774,16 +4181,16 @@ var writeSkillAtPath = (skillPath, skill, agentId) => pipe8(
|
|
|
3774
4181
|
}
|
|
3775
4182
|
)
|
|
3776
4183
|
),
|
|
3777
|
-
|
|
4184
|
+
Effect9.map(() => void 0)
|
|
3778
4185
|
);
|
|
3779
|
-
var writeSkill = (basePath, skill, agentId) =>
|
|
4186
|
+
var writeSkill = (basePath, skill, agentId) => pipe9(
|
|
3780
4187
|
assertWithinBase2(basePath, skill.name),
|
|
3781
|
-
|
|
4188
|
+
Effect9.flatMap((skillDir) => writeSkillAtPath(skillDir, skill, agentId))
|
|
3782
4189
|
);
|
|
3783
|
-
var writeSkillSymlink = (basePath, skill, agentId, options) =>
|
|
4190
|
+
var writeSkillSymlink = (basePath, skill, agentId, options) => pipe9(
|
|
3784
4191
|
assertWithinBase2(basePath, skill.name),
|
|
3785
|
-
|
|
3786
|
-
(installPath) =>
|
|
4192
|
+
Effect9.flatMap(
|
|
4193
|
+
(installPath) => Effect9.tryPromise({
|
|
3787
4194
|
try: async () => {
|
|
3788
4195
|
if (!options.storeRoot) {
|
|
3789
4196
|
throw new Error("storeRoot is required for shared-store installs");
|
|
@@ -3793,7 +4200,7 @@ var writeSkillSymlink = (basePath, skill, agentId, options) => pipe8(
|
|
|
3793
4200
|
skill,
|
|
3794
4201
|
agentId
|
|
3795
4202
|
);
|
|
3796
|
-
await
|
|
4203
|
+
await Effect9.runPromise(
|
|
3797
4204
|
writeSkillAtPath(storedBundlePath, skill, agentId)
|
|
3798
4205
|
);
|
|
3799
4206
|
const destinationPath = await resolveManagedBundlePathAsync(
|
|
@@ -3820,14 +4227,14 @@ var writeSkillSymlink = (basePath, skill, agentId, options) => pipe8(
|
|
|
3820
4227
|
);
|
|
3821
4228
|
var hashSkill = (skill, agentId) => createHash2("sha256").update(JSON.stringify({ agentId, skill })).digest("hex").slice(0, 16);
|
|
3822
4229
|
var resolveStorePath = (storeRoot, skill, agentId) => join8(storeRoot, `${skill.name}-${hashSkill(skill, agentId)}`);
|
|
3823
|
-
var writeSkills = (basePath, skills2, agentId, options = {}) =>
|
|
3824
|
-
|
|
4230
|
+
var writeSkills = (basePath, skills2, agentId, options = {}) => pipe9(
|
|
4231
|
+
Effect9.forEach(
|
|
3825
4232
|
skills2,
|
|
3826
|
-
(skill) =>
|
|
4233
|
+
(skill) => pipe9(
|
|
3827
4234
|
options.storeRoot ? writeSkillSymlink(basePath, skill, agentId, options) : writeSkill(basePath, skill, agentId),
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
(error) =>
|
|
4235
|
+
Effect9.map(() => ({ success: true, skill: skill.name })),
|
|
4236
|
+
Effect9.catch(
|
|
4237
|
+
(error) => Effect9.succeed({
|
|
3831
4238
|
success: false,
|
|
3832
4239
|
skill: skill.name,
|
|
3833
4240
|
error: error.cause instanceof Error ? error.cause.message : String(error.cause)
|
|
@@ -3836,14 +4243,14 @@ var writeSkills = (basePath, skills2, agentId, options = {}) => pipe8(
|
|
|
3836
4243
|
),
|
|
3837
4244
|
{ concurrency: "unbounded" }
|
|
3838
4245
|
),
|
|
3839
|
-
|
|
4246
|
+
Effect9.map((results) => ({
|
|
3840
4247
|
written: results.filter((r) => r.success).map((r) => r.skill),
|
|
3841
4248
|
errors: results.filter(
|
|
3842
4249
|
(r) => !r.success
|
|
3843
4250
|
).map((r) => ({ skill: r.skill, error: r.error }))
|
|
3844
4251
|
}))
|
|
3845
4252
|
);
|
|
3846
|
-
var writeSkillsAsync = (basePath, skills2, agentId, options) =>
|
|
4253
|
+
var writeSkillsAsync = (basePath, skills2, agentId, options) => Effect9.runPromise(writeSkills(basePath, skills2, agentId, options));
|
|
3847
4254
|
|
|
3848
4255
|
// src/commands/install.ts
|
|
3849
4256
|
init_tui();
|
|
@@ -4293,6 +4700,7 @@ async function writeLockfileAfterInstall(handle, slug, version, contentHash, rul
|
|
|
4293
4700
|
}
|
|
4294
4701
|
}
|
|
4295
4702
|
async function publicInstallCommand(source, options) {
|
|
4703
|
+
const config = await loadMergedConfigAsync();
|
|
4296
4704
|
const parsed = parsePublicSource(source);
|
|
4297
4705
|
if (!parsed) {
|
|
4298
4706
|
log.error(`Invalid public source: ${source}`);
|
|
@@ -4316,6 +4724,7 @@ async function publicInstallCommand(source, options) {
|
|
|
4316
4724
|
log.info(`Using locked version: v${version}`);
|
|
4317
4725
|
}
|
|
4318
4726
|
const versionSuffix = version !== void 0 ? `@${version}` : "";
|
|
4727
|
+
const serverUrl = options.server ?? config.serverUrl;
|
|
4319
4728
|
intro(`Installing from @${handle}/${slug}${versionSuffix}`);
|
|
4320
4729
|
const installSpinner = spinner();
|
|
4321
4730
|
installSpinner.start("Fetching public content...");
|
|
@@ -4325,7 +4734,10 @@ async function publicInstallCommand(source, options) {
|
|
|
4325
4734
|
slug,
|
|
4326
4735
|
version,
|
|
4327
4736
|
lockedRuleIds,
|
|
4328
|
-
|
|
4737
|
+
{
|
|
4738
|
+
...options,
|
|
4739
|
+
server: serverUrl
|
|
4740
|
+
},
|
|
4329
4741
|
installSpinner
|
|
4330
4742
|
);
|
|
4331
4743
|
installSpinner.stop(`Downloaded ${summarizeContent(response)}`);
|
|
@@ -4333,11 +4745,13 @@ async function publicInstallCommand(source, options) {
|
|
|
4333
4745
|
log.warn("No content to install.");
|
|
4334
4746
|
process.exit(0);
|
|
4335
4747
|
}
|
|
4336
|
-
const serverUrl = options.server ?? "https://braid.cloud";
|
|
4337
4748
|
const { totalWritten, totalErrors } = await installToSelectedAgents(
|
|
4338
4749
|
response,
|
|
4339
4750
|
serverUrl,
|
|
4340
|
-
|
|
4751
|
+
{
|
|
4752
|
+
...options,
|
|
4753
|
+
server: serverUrl
|
|
4754
|
+
},
|
|
4341
4755
|
installSpinner
|
|
4342
4756
|
);
|
|
4343
4757
|
if (totalWritten > 0 && version !== void 0) {
|
|
@@ -4534,7 +4948,8 @@ async function listCommand(options) {
|
|
|
4534
4948
|
|
|
4535
4949
|
// src/commands/manage.ts
|
|
4536
4950
|
init_esm_shims();
|
|
4537
|
-
|
|
4951
|
+
init_device_auth();
|
|
4952
|
+
import process11 from "process";
|
|
4538
4953
|
|
|
4539
4954
|
// src/lib/manage-server.ts
|
|
4540
4955
|
init_esm_shims();
|
|
@@ -4544,6 +4959,7 @@ import { createServer } from "http";
|
|
|
4544
4959
|
import { isAbsolute, relative as relative2, resolve as resolve6 } from "path";
|
|
4545
4960
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4546
4961
|
init_config();
|
|
4962
|
+
init_device_auth();
|
|
4547
4963
|
|
|
4548
4964
|
// src/lib/manage-actions.ts
|
|
4549
4965
|
init_esm_shims();
|
|
@@ -4554,8 +4970,8 @@ import { basename as basename2, dirname as dirname10, join as join11, relative }
|
|
|
4554
4970
|
init_esm_shims();
|
|
4555
4971
|
import { mkdir as mkdir6, readFile as readFile6, rm as rm3, writeFile as writeFile8 } from "fs/promises";
|
|
4556
4972
|
import { dirname as dirname9, join as join9 } from "path";
|
|
4557
|
-
import { Data as
|
|
4558
|
-
var HookConfigWriteError = class extends
|
|
4973
|
+
import { Data as Data9, Effect as Effect10 } from "effect";
|
|
4974
|
+
var HookConfigWriteError = class extends Data9.TaggedError("HookConfigWriteError") {
|
|
4559
4975
|
};
|
|
4560
4976
|
var HOOK_METADATA_FILENAME = ".braid-metadata.json";
|
|
4561
4977
|
function stableStringify(value) {
|
|
@@ -4880,7 +5296,7 @@ async function ensureMarketplaceHookBundleFile(settingsPath, sourceSlug) {
|
|
|
4880
5296
|
});
|
|
4881
5297
|
return bundlePath;
|
|
4882
5298
|
}
|
|
4883
|
-
var writeMarketplaceHooks = (settingsPath, hooks, options) =>
|
|
5299
|
+
var writeMarketplaceHooks = (settingsPath, hooks, options) => Effect10.tryPromise({
|
|
4884
5300
|
try: async () => {
|
|
4885
5301
|
const activeHooks = hooks.filter(
|
|
4886
5302
|
(hook) => hook.enabled !== false && hook.runtime === "claude"
|
|
@@ -4935,131 +5351,18 @@ var writeMarketplaceHooks = (settingsPath, hooks, options) => Effect9.tryPromise
|
|
|
4935
5351
|
},
|
|
4936
5352
|
catch: (cause) => new HookConfigWriteError({ path: settingsPath, cause })
|
|
4937
5353
|
});
|
|
4938
|
-
var writeMarketplaceHooksAsync = (settingsPath, hooks, options) =>
|
|
5354
|
+
var writeMarketplaceHooksAsync = (settingsPath, hooks, options) => Effect10.runPromise(writeMarketplaceHooks(settingsPath, hooks, options));
|
|
4939
5355
|
var removeMarketplaceHooksBySourceAsync = (settingsPath, sourceSlug) => removeMarketplaceHooksBySource(settingsPath, sourceSlug);
|
|
4940
5356
|
var ensureMarketplaceHookBundleFileAsync = (settingsPath, sourceSlug) => ensureMarketplaceHookBundleFile(settingsPath, sourceSlug);
|
|
4941
5357
|
var listInstalledMarketplaceHookSourcesAsync = (settingsPath) => listInstalledMarketplaceHookSources(settingsPath);
|
|
4942
5358
|
var readMarketplaceHookBundleFileAsync = (bundlePath) => readMarketplaceHookBundleFile(bundlePath);
|
|
4943
5359
|
|
|
4944
|
-
// src/lib/marketplace-api.ts
|
|
4945
|
-
init_esm_shims();
|
|
4946
|
-
init_config();
|
|
4947
|
-
import { Data as Data9, Effect as Effect10, pipe as pipe9 } from "effect";
|
|
4948
|
-
var TRAILING_SLASH_REGEX2 = /\/$/;
|
|
4949
|
-
var MarketplaceApiError = class extends Data9.TaggedError("MarketplaceApiError") {
|
|
4950
|
-
};
|
|
4951
|
-
var resolveApiKey2 = (provided) => {
|
|
4952
|
-
if (provided) {
|
|
4953
|
-
return Effect10.succeed(provided);
|
|
4954
|
-
}
|
|
4955
|
-
return pipe9(
|
|
4956
|
-
Effect10.tryPromise({
|
|
4957
|
-
try: () => getApiKeyAsync(),
|
|
4958
|
-
catch: () => new MarketplaceApiError({
|
|
4959
|
-
message: "Failed to load API key",
|
|
4960
|
-
status: 500,
|
|
4961
|
-
code: "CONFIG_ERROR"
|
|
4962
|
-
})
|
|
4963
|
-
}),
|
|
4964
|
-
Effect10.flatMap(
|
|
4965
|
-
(token) => token ? Effect10.succeed(token) : Effect10.fail(
|
|
4966
|
-
new MarketplaceApiError({
|
|
4967
|
-
message: "Not signed in. Run 'braid auth'.",
|
|
4968
|
-
status: 401,
|
|
4969
|
-
code: "AUTH_REQUIRED"
|
|
4970
|
-
})
|
|
4971
|
-
)
|
|
4972
|
-
)
|
|
4973
|
-
);
|
|
4974
|
-
};
|
|
4975
|
-
var resolveServer = (provided) => {
|
|
4976
|
-
if (provided) {
|
|
4977
|
-
return Effect10.succeed(provided.replace(TRAILING_SLASH_REGEX2, ""));
|
|
4978
|
-
}
|
|
4979
|
-
return pipe9(
|
|
4980
|
-
Effect10.tryPromise({
|
|
4981
|
-
try: () => getServerUrlAsync(),
|
|
4982
|
-
catch: () => new MarketplaceApiError({
|
|
4983
|
-
message: "Failed to load server URL",
|
|
4984
|
-
status: 500,
|
|
4985
|
-
code: "CONFIG_ERROR"
|
|
4986
|
-
})
|
|
4987
|
-
}),
|
|
4988
|
-
Effect10.map((server) => server.replace(TRAILING_SLASH_REGEX2, ""))
|
|
4989
|
-
);
|
|
4990
|
-
};
|
|
4991
|
-
var requestJson = (url, options) => pipe9(
|
|
4992
|
-
Effect10.tryPromise({
|
|
4993
|
-
try: () => fetch(url, options),
|
|
4994
|
-
catch: () => new MarketplaceApiError({
|
|
4995
|
-
message: "Network error",
|
|
4996
|
-
status: 503,
|
|
4997
|
-
code: "NETWORK_ERROR"
|
|
4998
|
-
})
|
|
4999
|
-
}),
|
|
5000
|
-
Effect10.flatMap(
|
|
5001
|
-
(response) => Effect10.tryPromise({
|
|
5002
|
-
try: async () => {
|
|
5003
|
-
const payload = await response.json().catch(() => null);
|
|
5004
|
-
if (!response.ok) {
|
|
5005
|
-
throw new MarketplaceApiError({
|
|
5006
|
-
message: payload?.error ?? payload?.message ?? "Request failed",
|
|
5007
|
-
status: response.status,
|
|
5008
|
-
code: payload?.code ?? "REQUEST_ERROR"
|
|
5009
|
-
});
|
|
5010
|
-
}
|
|
5011
|
-
return payload;
|
|
5012
|
-
},
|
|
5013
|
-
catch: (error) => error instanceof MarketplaceApiError ? error : new MarketplaceApiError({
|
|
5014
|
-
message: "Invalid response",
|
|
5015
|
-
status: 500,
|
|
5016
|
-
code: "PARSE_ERROR"
|
|
5017
|
-
})
|
|
5018
|
-
})
|
|
5019
|
-
)
|
|
5020
|
-
);
|
|
5021
|
-
var fetchMarketplaceLibrary = (options) => pipe9(
|
|
5022
|
-
Effect10.all({
|
|
5023
|
-
server: resolveServer(options.server),
|
|
5024
|
-
apiKey: resolveApiKey2(options.apiKey)
|
|
5025
|
-
}),
|
|
5026
|
-
Effect10.flatMap(
|
|
5027
|
-
({ server, apiKey }) => requestJson(
|
|
5028
|
-
`${server}/api/marketplace/library`,
|
|
5029
|
-
{
|
|
5030
|
-
method: "GET",
|
|
5031
|
-
headers: {
|
|
5032
|
-
Authorization: `Bearer ${apiKey}`
|
|
5033
|
-
}
|
|
5034
|
-
}
|
|
5035
|
-
)
|
|
5036
|
-
),
|
|
5037
|
-
Effect10.map((response) => response.items)
|
|
5038
|
-
);
|
|
5039
|
-
var fetchMarketplaceInstallManifest = (slug, options) => pipe9(
|
|
5040
|
-
Effect10.all({
|
|
5041
|
-
server: resolveServer(options.server),
|
|
5042
|
-
apiKey: resolveApiKey2(options.apiKey)
|
|
5043
|
-
}),
|
|
5044
|
-
Effect10.flatMap(
|
|
5045
|
-
({ server, apiKey }) => requestJson(
|
|
5046
|
-
`${server}/api/marketplace/install-manifest/${encodeURIComponent(slug)}`,
|
|
5047
|
-
{
|
|
5048
|
-
method: "GET",
|
|
5049
|
-
headers: {
|
|
5050
|
-
Authorization: `Bearer ${apiKey}`
|
|
5051
|
-
}
|
|
5052
|
-
}
|
|
5053
|
-
)
|
|
5054
|
-
)
|
|
5055
|
-
);
|
|
5056
|
-
var fetchMarketplaceLibraryAsync = (options) => Effect10.runPromise(fetchMarketplaceLibrary(options));
|
|
5057
|
-
var fetchMarketplaceInstallManifestAsync = (slug, options) => Effect10.runPromise(fetchMarketplaceInstallManifest(slug, options));
|
|
5058
|
-
|
|
5059
5360
|
// src/lib/marketplace-installer.ts
|
|
5060
5361
|
init_esm_shims();
|
|
5061
5362
|
import { rm as rm4 } from "fs/promises";
|
|
5062
5363
|
import { join as join10 } from "path";
|
|
5364
|
+
init_config();
|
|
5365
|
+
var TRAILING_SLASH_REGEX3 = /\/$/;
|
|
5063
5366
|
function parseAgentIds(value) {
|
|
5064
5367
|
if (!value) {
|
|
5065
5368
|
return [];
|
|
@@ -5129,7 +5432,7 @@ async function installSkillsForAgent(args) {
|
|
|
5129
5432
|
versionId: args.manifest.versionId
|
|
5130
5433
|
},
|
|
5131
5434
|
version: args.manifest.versionId ?? args.manifest.commitSha ?? "unknown",
|
|
5132
|
-
serverUrl:
|
|
5435
|
+
serverUrl: args.serverUrl
|
|
5133
5436
|
}))
|
|
5134
5437
|
);
|
|
5135
5438
|
args.targets.push(`${args.agent.name} -> ${installPath}`);
|
|
@@ -5218,6 +5521,7 @@ async function installAllForAgent(args) {
|
|
|
5218
5521
|
agent: args.agent,
|
|
5219
5522
|
manifest: args.manifest,
|
|
5220
5523
|
slug: args.slug,
|
|
5524
|
+
serverUrl: args.serverUrl,
|
|
5221
5525
|
skills: args.skills,
|
|
5222
5526
|
global: args.global,
|
|
5223
5527
|
installedSkills: args.installedSkills,
|
|
@@ -5275,6 +5579,7 @@ async function installMarketplaceSkillSet(options) {
|
|
|
5275
5579
|
"No compatible agents found. Use --agents to specify targets."
|
|
5276
5580
|
);
|
|
5277
5581
|
}
|
|
5582
|
+
const serverUrl = (options.serverUrl ?? await getServerUrlAsync().catch(() => "https://braid.cloud")).replace(TRAILING_SLASH_REGEX3, "");
|
|
5278
5583
|
const targets = [];
|
|
5279
5584
|
const installedSkills = /* @__PURE__ */ new Set();
|
|
5280
5585
|
for (const agent of targetAgents) {
|
|
@@ -5282,6 +5587,7 @@ async function installMarketplaceSkillSet(options) {
|
|
|
5282
5587
|
agent,
|
|
5283
5588
|
manifest: options.manifest,
|
|
5284
5589
|
slug: options.slug,
|
|
5590
|
+
serverUrl,
|
|
5285
5591
|
skills: resolvedSkills,
|
|
5286
5592
|
rules: rules2,
|
|
5287
5593
|
agents: agents2,
|
|
@@ -5431,7 +5737,8 @@ async function installLibraryPackAsync(options) {
|
|
|
5431
5737
|
agents: options.agentId,
|
|
5432
5738
|
global: options.scope === "global",
|
|
5433
5739
|
manifest,
|
|
5434
|
-
slug: options.slug
|
|
5740
|
+
slug: options.slug,
|
|
5741
|
+
serverUrl: options.server
|
|
5435
5742
|
});
|
|
5436
5743
|
}
|
|
5437
5744
|
|
|
@@ -5908,7 +6215,8 @@ var MIME_TYPES = {
|
|
|
5908
6215
|
};
|
|
5909
6216
|
var TRAILING_SLASHES3 = /\/+$/;
|
|
5910
6217
|
var MANAGE_AUTH_TIMEOUT_SECONDS = 300;
|
|
5911
|
-
var
|
|
6218
|
+
var SESSION_TOKEN_PREFIX4 = "brs_";
|
|
6219
|
+
var LOOPBACK_HOSTS4 = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "localhost"]);
|
|
5912
6220
|
function getErrorStatus(error) {
|
|
5913
6221
|
if (typeof error === "object" && error !== null && "status" in error && typeof error.status === "number") {
|
|
5914
6222
|
return error.status ?? 500;
|
|
@@ -5985,7 +6293,18 @@ function getContentType(pathname) {
|
|
|
5985
6293
|
const extension = pathname.slice(pathname.lastIndexOf("."));
|
|
5986
6294
|
return MIME_TYPES[extension] ?? "application/octet-stream";
|
|
5987
6295
|
}
|
|
5988
|
-
function
|
|
6296
|
+
function resolvePersistedCliServerUrl2(serverUrl, convexSiteUrl) {
|
|
6297
|
+
try {
|
|
6298
|
+
const convexUrl = new URL(convexSiteUrl);
|
|
6299
|
+
if (LOOPBACK_HOSTS4.has(convexUrl.hostname)) {
|
|
6300
|
+
return convexSiteUrl;
|
|
6301
|
+
}
|
|
6302
|
+
} catch {
|
|
6303
|
+
return serverUrl;
|
|
6304
|
+
}
|
|
6305
|
+
return serverUrl;
|
|
6306
|
+
}
|
|
6307
|
+
function writeJson2(response, status, body) {
|
|
5989
6308
|
response.writeHead(status, {
|
|
5990
6309
|
"content-type": "application/json; charset=utf-8",
|
|
5991
6310
|
"cache-control": "no-store"
|
|
@@ -6009,7 +6328,7 @@ async function serveStaticAsset(serverResponse, assetRoot, pathname) {
|
|
|
6009
6328
|
const assetPath = resolve6(assetRoot, relativePath);
|
|
6010
6329
|
const resolvedRoot = resolve6(assetRoot);
|
|
6011
6330
|
if (!isWithinManageAssetRoot(resolvedRoot, assetPath)) {
|
|
6012
|
-
|
|
6331
|
+
writeJson2(serverResponse, 404, { error: "Not found" });
|
|
6013
6332
|
return true;
|
|
6014
6333
|
}
|
|
6015
6334
|
try {
|
|
@@ -6103,19 +6422,19 @@ async function handleManageApiRoute(request, response, dependencies) {
|
|
|
6103
6422
|
const pathname = new URL(request.url ?? "/", "http://127.0.0.1").pathname;
|
|
6104
6423
|
switch (`${method} ${pathname}`) {
|
|
6105
6424
|
case "GET /api/inventory":
|
|
6106
|
-
|
|
6425
|
+
writeJson2(response, 200, await dependencies.getInventory());
|
|
6107
6426
|
return true;
|
|
6108
6427
|
case "GET /api/library":
|
|
6109
|
-
|
|
6428
|
+
writeJson2(response, 200, await dependencies.listLibrary());
|
|
6110
6429
|
return true;
|
|
6111
6430
|
case "GET /api/auth/session":
|
|
6112
|
-
|
|
6431
|
+
writeJson2(response, 200, {
|
|
6113
6432
|
ok: true,
|
|
6114
6433
|
result: await dependencies.getAuthSession()
|
|
6115
6434
|
});
|
|
6116
6435
|
return true;
|
|
6117
6436
|
case "POST /api/auth/start":
|
|
6118
|
-
|
|
6437
|
+
writeJson2(response, 200, {
|
|
6119
6438
|
ok: true,
|
|
6120
6439
|
result: await dependencies.startAuth()
|
|
6121
6440
|
});
|
|
@@ -6129,7 +6448,7 @@ async function handleManageApiRoute(request, response, dependencies) {
|
|
|
6129
6448
|
"AUTH_REQUEST_REQUIRED"
|
|
6130
6449
|
);
|
|
6131
6450
|
}
|
|
6132
|
-
|
|
6451
|
+
writeJson2(response, 200, {
|
|
6133
6452
|
ok: true,
|
|
6134
6453
|
result: await dependencies.completeAuth({
|
|
6135
6454
|
requestId: payload.requestId
|
|
@@ -6138,14 +6457,14 @@ async function handleManageApiRoute(request, response, dependencies) {
|
|
|
6138
6457
|
return true;
|
|
6139
6458
|
}
|
|
6140
6459
|
case "POST /api/auth/sign-out":
|
|
6141
|
-
|
|
6460
|
+
writeJson2(response, 200, {
|
|
6142
6461
|
ok: true,
|
|
6143
6462
|
result: await dependencies.signOut()
|
|
6144
6463
|
});
|
|
6145
6464
|
return true;
|
|
6146
6465
|
case "POST /api/actions/install": {
|
|
6147
6466
|
const payload = await readJsonBody(request);
|
|
6148
|
-
|
|
6467
|
+
writeJson2(response, 200, {
|
|
6149
6468
|
ok: true,
|
|
6150
6469
|
result: await dependencies.installLibraryPack(payload)
|
|
6151
6470
|
});
|
|
@@ -6153,7 +6472,7 @@ async function handleManageApiRoute(request, response, dependencies) {
|
|
|
6153
6472
|
}
|
|
6154
6473
|
case "POST /api/actions/disable": {
|
|
6155
6474
|
const payload = await readJsonBody(request);
|
|
6156
|
-
|
|
6475
|
+
writeJson2(response, 200, {
|
|
6157
6476
|
ok: true,
|
|
6158
6477
|
result: await dependencies.disableManagedBundle(payload)
|
|
6159
6478
|
});
|
|
@@ -6161,7 +6480,7 @@ async function handleManageApiRoute(request, response, dependencies) {
|
|
|
6161
6480
|
}
|
|
6162
6481
|
case "POST /api/actions/enable": {
|
|
6163
6482
|
const payload = await readJsonBody(request);
|
|
6164
|
-
|
|
6483
|
+
writeJson2(response, 200, {
|
|
6165
6484
|
ok: true,
|
|
6166
6485
|
result: await dependencies.enableManagedBundle(payload)
|
|
6167
6486
|
});
|
|
@@ -6169,7 +6488,7 @@ async function handleManageApiRoute(request, response, dependencies) {
|
|
|
6169
6488
|
}
|
|
6170
6489
|
case "POST /api/actions/remove": {
|
|
6171
6490
|
const payload = await readJsonBody(request);
|
|
6172
|
-
|
|
6491
|
+
writeJson2(response, 200, {
|
|
6173
6492
|
ok: true,
|
|
6174
6493
|
result: await dependencies.removeManagedBundle(payload)
|
|
6175
6494
|
});
|
|
@@ -6191,11 +6510,11 @@ async function handleManageRequest(request, response, assetRoot, dependencies) {
|
|
|
6191
6510
|
return;
|
|
6192
6511
|
}
|
|
6193
6512
|
}
|
|
6194
|
-
|
|
6513
|
+
writeJson2(response, 404, { error: "Not found" });
|
|
6195
6514
|
} catch (error) {
|
|
6196
6515
|
const message = error instanceof Error ? error.message : String(error);
|
|
6197
6516
|
const code = getErrorCode(error);
|
|
6198
|
-
|
|
6517
|
+
writeJson2(response, getErrorStatus(error), {
|
|
6199
6518
|
...code ? { code } : {},
|
|
6200
6519
|
error: message
|
|
6201
6520
|
});
|
|
@@ -6266,6 +6585,10 @@ async function startManageServer(options = {}) {
|
|
|
6266
6585
|
deviceAuth.user_code
|
|
6267
6586
|
);
|
|
6268
6587
|
authRequests.set(requestId, {
|
|
6588
|
+
serverUrl: resolvePersistedCliServerUrl2(
|
|
6589
|
+
serverUrl,
|
|
6590
|
+
authConfig.convexSiteUrl
|
|
6591
|
+
),
|
|
6269
6592
|
convexSiteUrl: authConfig.convexSiteUrl,
|
|
6270
6593
|
deviceCode: deviceAuth.device_code,
|
|
6271
6594
|
expiresIn: deviceAuth.expires_in,
|
|
@@ -6296,7 +6619,10 @@ async function startManageServer(options = {}) {
|
|
|
6296
6619
|
pendingRequest.expiresIn,
|
|
6297
6620
|
MANAGE_AUTH_TIMEOUT_SECONDS
|
|
6298
6621
|
);
|
|
6299
|
-
await persistApiKeyAsync(
|
|
6622
|
+
await persistApiKeyAsync(
|
|
6623
|
+
session.sessionToken,
|
|
6624
|
+
pendingRequest.serverUrl
|
|
6625
|
+
);
|
|
6300
6626
|
return {
|
|
6301
6627
|
authenticated: true,
|
|
6302
6628
|
expiresAt: session.expiresAt,
|
|
@@ -6312,7 +6638,7 @@ async function startManageServer(options = {}) {
|
|
|
6312
6638
|
if (!token) {
|
|
6313
6639
|
return { authenticated: false };
|
|
6314
6640
|
}
|
|
6315
|
-
if (!token.startsWith(
|
|
6641
|
+
if (!token.startsWith(SESSION_TOKEN_PREFIX4)) {
|
|
6316
6642
|
return { authenticated: true };
|
|
6317
6643
|
}
|
|
6318
6644
|
const serverUrl = (options.server ?? config.serverUrl).replace(
|
|
@@ -6337,7 +6663,7 @@ async function startManageServer(options = {}) {
|
|
|
6337
6663
|
const signOut = options.signOut ?? (async () => {
|
|
6338
6664
|
const config = await loadMergedConfigAsync();
|
|
6339
6665
|
const token = config.token;
|
|
6340
|
-
if (token?.startsWith(
|
|
6666
|
+
if (token?.startsWith(SESSION_TOKEN_PREFIX4)) {
|
|
6341
6667
|
try {
|
|
6342
6668
|
const serverUrl = (options.server ?? config.serverUrl).replace(
|
|
6343
6669
|
TRAILING_SLASHES3,
|
|
@@ -6369,7 +6695,7 @@ async function startManageServer(options = {}) {
|
|
|
6369
6695
|
handleManageRequest(request, response, assetRoot, dependencies).catch(
|
|
6370
6696
|
(error) => {
|
|
6371
6697
|
const message = error instanceof Error ? error.message : String(error);
|
|
6372
|
-
|
|
6698
|
+
writeJson2(response, 500, { error: message });
|
|
6373
6699
|
}
|
|
6374
6700
|
);
|
|
6375
6701
|
});
|
|
@@ -6413,7 +6739,7 @@ async function manageCommand(options) {
|
|
|
6413
6739
|
const server = await startManageServer({
|
|
6414
6740
|
apiKey: options.apiKey,
|
|
6415
6741
|
port: parsePort(options.port),
|
|
6416
|
-
projectRoot:
|
|
6742
|
+
projectRoot: process11.cwd(),
|
|
6417
6743
|
server: options.server
|
|
6418
6744
|
});
|
|
6419
6745
|
if (options.open !== false) {
|
|
@@ -6423,17 +6749,17 @@ async function manageCommand(options) {
|
|
|
6423
6749
|
log.info("Press Ctrl+C to stop.");
|
|
6424
6750
|
await new Promise((resolveClose, rejectClose) => {
|
|
6425
6751
|
const shutdown = () => {
|
|
6426
|
-
|
|
6427
|
-
|
|
6752
|
+
process11.off("SIGINT", shutdown);
|
|
6753
|
+
process11.off("SIGTERM", shutdown);
|
|
6428
6754
|
server.close().then(resolveClose).catch(rejectClose);
|
|
6429
6755
|
};
|
|
6430
|
-
|
|
6431
|
-
|
|
6756
|
+
process11.once("SIGINT", shutdown);
|
|
6757
|
+
process11.once("SIGTERM", shutdown);
|
|
6432
6758
|
});
|
|
6433
6759
|
} catch (error) {
|
|
6434
6760
|
const message = error instanceof Error ? error.message : String(error);
|
|
6435
6761
|
log.error(message);
|
|
6436
|
-
|
|
6762
|
+
process11.exit(1);
|
|
6437
6763
|
}
|
|
6438
6764
|
}
|
|
6439
6765
|
|
|
@@ -6441,7 +6767,7 @@ async function manageCommand(options) {
|
|
|
6441
6767
|
init_esm_shims();
|
|
6442
6768
|
import { rm as rm6 } from "fs/promises";
|
|
6443
6769
|
import { join as join13, resolve as resolve7 } from "path";
|
|
6444
|
-
import
|
|
6770
|
+
import process12 from "process";
|
|
6445
6771
|
init_tui();
|
|
6446
6772
|
async function selectInstallScope(options) {
|
|
6447
6773
|
if (options.global != null) {
|
|
@@ -6460,7 +6786,7 @@ async function selectInstallScope(options) {
|
|
|
6460
6786
|
});
|
|
6461
6787
|
if (isCancel(result)) {
|
|
6462
6788
|
cancel("Install cancelled.");
|
|
6463
|
-
|
|
6789
|
+
process12.exit(0);
|
|
6464
6790
|
}
|
|
6465
6791
|
return result;
|
|
6466
6792
|
}
|
|
@@ -6495,7 +6821,7 @@ async function selectInstallAgents(options, global) {
|
|
|
6495
6821
|
});
|
|
6496
6822
|
if (isCancel(selected)) {
|
|
6497
6823
|
cancel("Install cancelled.");
|
|
6498
|
-
|
|
6824
|
+
process12.exit(0);
|
|
6499
6825
|
}
|
|
6500
6826
|
return selected;
|
|
6501
6827
|
}
|
|
@@ -6512,7 +6838,7 @@ async function confirmHooksOptIn(hookCount, options) {
|
|
|
6512
6838
|
});
|
|
6513
6839
|
if (isCancel(result)) {
|
|
6514
6840
|
cancel("Install cancelled.");
|
|
6515
|
-
|
|
6841
|
+
process12.exit(0);
|
|
6516
6842
|
}
|
|
6517
6843
|
return result;
|
|
6518
6844
|
}
|
|
@@ -6537,7 +6863,7 @@ async function marketplaceLibraryCommand(options) {
|
|
|
6537
6863
|
log.error(
|
|
6538
6864
|
error instanceof Error ? error.message : "Failed to fetch library"
|
|
6539
6865
|
);
|
|
6540
|
-
|
|
6866
|
+
process12.exit(1);
|
|
6541
6867
|
}
|
|
6542
6868
|
}
|
|
6543
6869
|
async function resolveAndInstallPack(slug, options, overrides) {
|
|
@@ -6560,7 +6886,8 @@ async function resolveAndInstallPack(slug, options, overrides) {
|
|
|
6560
6886
|
manifest,
|
|
6561
6887
|
agents: agents2,
|
|
6562
6888
|
global,
|
|
6563
|
-
allowHooks: options.allowHooks
|
|
6889
|
+
allowHooks: options.allowHooks,
|
|
6890
|
+
serverUrl: options.server
|
|
6564
6891
|
});
|
|
6565
6892
|
}
|
|
6566
6893
|
async function marketplaceInstallCommand(slug, options) {
|
|
@@ -6571,7 +6898,7 @@ async function marketplaceInstallCommand(slug, options) {
|
|
|
6571
6898
|
log.error(
|
|
6572
6899
|
error instanceof Error ? error.message : "Failed to install pack"
|
|
6573
6900
|
);
|
|
6574
|
-
|
|
6901
|
+
process12.exit(1);
|
|
6575
6902
|
}
|
|
6576
6903
|
}
|
|
6577
6904
|
function addSkillToPack(packMap, slug, versionId, skillName, agent, installPath) {
|
|
@@ -6625,7 +6952,7 @@ async function marketplaceUpdateCommand(slug, options) {
|
|
|
6625
6952
|
const toUpdate = slug ? installed.filter((p) => p.slug === slug) : installed;
|
|
6626
6953
|
if (toUpdate.length === 0) {
|
|
6627
6954
|
log.error(`Pack "${slug}" is not installed.`);
|
|
6628
|
-
|
|
6955
|
+
process12.exit(1);
|
|
6629
6956
|
}
|
|
6630
6957
|
let updated = 0;
|
|
6631
6958
|
for (const pack of toUpdate) {
|
|
@@ -6645,7 +6972,7 @@ async function marketplaceUpdateCommand(slug, options) {
|
|
|
6645
6972
|
log.error(
|
|
6646
6973
|
error instanceof Error ? error.message : "Failed to update packs"
|
|
6647
6974
|
);
|
|
6648
|
-
|
|
6975
|
+
process12.exit(1);
|
|
6649
6976
|
}
|
|
6650
6977
|
}
|
|
6651
6978
|
async function selectPacksToRemove(installed, slug, options) {
|
|
@@ -6671,7 +6998,7 @@ async function selectPacksToRemove(installed, slug, options) {
|
|
|
6671
6998
|
});
|
|
6672
6999
|
if (isCancel(selected)) {
|
|
6673
7000
|
cancel("Remove cancelled.");
|
|
6674
|
-
|
|
7001
|
+
process12.exit(0);
|
|
6675
7002
|
}
|
|
6676
7003
|
return selected;
|
|
6677
7004
|
}
|
|
@@ -6709,7 +7036,7 @@ async function marketplaceRemoveCommand(slug, options) {
|
|
|
6709
7036
|
});
|
|
6710
7037
|
if (isCancel(confirmed) || !confirmed) {
|
|
6711
7038
|
cancel("Remove cancelled.");
|
|
6712
|
-
|
|
7039
|
+
process12.exit(0);
|
|
6713
7040
|
}
|
|
6714
7041
|
}
|
|
6715
7042
|
for (const pack of toRemove) {
|
|
@@ -6720,7 +7047,7 @@ async function marketplaceRemoveCommand(slug, options) {
|
|
|
6720
7047
|
log.error(
|
|
6721
7048
|
error instanceof Error ? error.message : "Failed to remove packs"
|
|
6722
7049
|
);
|
|
6723
|
-
|
|
7050
|
+
process12.exit(1);
|
|
6724
7051
|
}
|
|
6725
7052
|
}
|
|
6726
7053
|
|
|
@@ -6728,19 +7055,6 @@ async function marketplaceRemoveCommand(slug, options) {
|
|
|
6728
7055
|
init_esm_shims();
|
|
6729
7056
|
init_api();
|
|
6730
7057
|
init_tui();
|
|
6731
|
-
import process12 from "process";
|
|
6732
|
-
var writeJson4 = (value) => {
|
|
6733
|
-
process12.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
6734
|
-
`);
|
|
6735
|
-
};
|
|
6736
|
-
var exitWithError3 = (error) => {
|
|
6737
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
6738
|
-
log.error(message);
|
|
6739
|
-
process12.exit(1);
|
|
6740
|
-
};
|
|
6741
|
-
var fail2 = (message) => {
|
|
6742
|
-
throw new Error(message);
|
|
6743
|
-
};
|
|
6744
7058
|
var parseContext = (contextJson) => {
|
|
6745
7059
|
if (!contextJson) {
|
|
6746
7060
|
return void 0;
|
|
@@ -6761,7 +7075,7 @@ var run2 = async (command, args, options) => {
|
|
|
6761
7075
|
apiOptions
|
|
6762
7076
|
);
|
|
6763
7077
|
if (options.json) {
|
|
6764
|
-
|
|
7078
|
+
writeJson(result);
|
|
6765
7079
|
return;
|
|
6766
7080
|
}
|
|
6767
7081
|
log.success(`profiles ${command} completed`);
|
|
@@ -6770,34 +7084,34 @@ async function profilesListCommand(options) {
|
|
|
6770
7084
|
try {
|
|
6771
7085
|
await run2("list", {}, options);
|
|
6772
7086
|
} catch (error) {
|
|
6773
|
-
|
|
7087
|
+
exitCommandError(error, options);
|
|
6774
7088
|
}
|
|
6775
7089
|
}
|
|
6776
7090
|
async function profilesGetCommand(options) {
|
|
6777
7091
|
try {
|
|
6778
7092
|
if (!(options.id || options.name)) {
|
|
6779
|
-
|
|
7093
|
+
fail("profiles get requires --id or --name");
|
|
6780
7094
|
}
|
|
6781
7095
|
await run2("get", { id: options.id, name: options.name }, options);
|
|
6782
7096
|
} catch (error) {
|
|
6783
|
-
|
|
7097
|
+
exitCommandError(error, options);
|
|
6784
7098
|
}
|
|
6785
7099
|
}
|
|
6786
7100
|
async function profilesCreateCommand(options) {
|
|
6787
7101
|
try {
|
|
6788
|
-
const name = options.name ??
|
|
7102
|
+
const name = options.name ?? fail("profiles create requires --name");
|
|
6789
7103
|
await run2(
|
|
6790
7104
|
"create",
|
|
6791
7105
|
{ name, context: parseContext(options.contextJson) },
|
|
6792
7106
|
options
|
|
6793
7107
|
);
|
|
6794
7108
|
} catch (error) {
|
|
6795
|
-
|
|
7109
|
+
exitCommandError(error, options);
|
|
6796
7110
|
}
|
|
6797
7111
|
}
|
|
6798
7112
|
async function profilesUpdateCommand(options) {
|
|
6799
7113
|
try {
|
|
6800
|
-
const id = options.id ??
|
|
7114
|
+
const id = options.id ?? fail("profiles update requires --id");
|
|
6801
7115
|
await run2(
|
|
6802
7116
|
"update",
|
|
6803
7117
|
{
|
|
@@ -6808,26 +7122,26 @@ async function profilesUpdateCommand(options) {
|
|
|
6808
7122
|
options
|
|
6809
7123
|
);
|
|
6810
7124
|
} catch (error) {
|
|
6811
|
-
|
|
7125
|
+
exitCommandError(error, options);
|
|
6812
7126
|
}
|
|
6813
7127
|
}
|
|
6814
7128
|
async function profilesRemoveCommand(options) {
|
|
6815
7129
|
try {
|
|
6816
|
-
const id = options.id ??
|
|
7130
|
+
const id = options.id ?? fail("profiles remove requires --id");
|
|
6817
7131
|
if (!options.yes) {
|
|
6818
|
-
|
|
7132
|
+
fail("profiles remove requires --yes");
|
|
6819
7133
|
}
|
|
6820
7134
|
await run2("remove", { id, yes: true }, options);
|
|
6821
7135
|
} catch (error) {
|
|
6822
|
-
|
|
7136
|
+
exitCommandError(error, options);
|
|
6823
7137
|
}
|
|
6824
7138
|
}
|
|
6825
7139
|
async function profilesSetDefaultCommand(options) {
|
|
6826
7140
|
try {
|
|
6827
|
-
const id = options.id ??
|
|
7141
|
+
const id = options.id ?? fail("profiles set-default requires --id");
|
|
6828
7142
|
await run2("set-default", { id }, options);
|
|
6829
7143
|
} catch (error) {
|
|
6830
|
-
|
|
7144
|
+
exitCommandError(error, options);
|
|
6831
7145
|
}
|
|
6832
7146
|
}
|
|
6833
7147
|
|
|
@@ -6835,14 +7149,6 @@ async function profilesSetDefaultCommand(options) {
|
|
|
6835
7149
|
init_esm_shims();
|
|
6836
7150
|
init_api();
|
|
6837
7151
|
init_tui();
|
|
6838
|
-
import process13 from "process";
|
|
6839
|
-
var writeJson5 = (value) => {
|
|
6840
|
-
process13.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
6841
|
-
`);
|
|
6842
|
-
};
|
|
6843
|
-
var fail3 = (message) => {
|
|
6844
|
-
throw new Error(message);
|
|
6845
|
-
};
|
|
6846
7152
|
var run3 = async (command, args, options) => {
|
|
6847
7153
|
const apiOptions = {
|
|
6848
7154
|
...options.server ? { serverUrl: options.server } : {},
|
|
@@ -6857,39 +7163,34 @@ var run3 = async (command, args, options) => {
|
|
|
6857
7163
|
apiOptions
|
|
6858
7164
|
);
|
|
6859
7165
|
if (options.json) {
|
|
6860
|
-
|
|
7166
|
+
writeJson(result);
|
|
6861
7167
|
return;
|
|
6862
7168
|
}
|
|
6863
7169
|
log.success(`projects ${command} completed`);
|
|
6864
7170
|
};
|
|
6865
|
-
var exitWithError4 = (error) => {
|
|
6866
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
6867
|
-
log.error(message);
|
|
6868
|
-
process13.exit(1);
|
|
6869
|
-
};
|
|
6870
7171
|
async function projectsGetCommand(options) {
|
|
6871
7172
|
try {
|
|
6872
|
-
const id = options.id ??
|
|
7173
|
+
const id = options.id ?? fail("projects get requires --id");
|
|
6873
7174
|
await run3("get", { id }, options);
|
|
6874
7175
|
} catch (error) {
|
|
6875
|
-
|
|
7176
|
+
exitCommandError(error, options);
|
|
6876
7177
|
}
|
|
6877
7178
|
}
|
|
6878
7179
|
async function projectsCreateCommand(options) {
|
|
6879
7180
|
try {
|
|
6880
|
-
const name = options.name ??
|
|
7181
|
+
const name = options.name ?? fail("projects create requires --name");
|
|
6881
7182
|
await run3(
|
|
6882
7183
|
"create",
|
|
6883
7184
|
{ name, description: options.description, orgId: options.orgId },
|
|
6884
7185
|
options
|
|
6885
7186
|
);
|
|
6886
7187
|
} catch (error) {
|
|
6887
|
-
|
|
7188
|
+
exitCommandError(error, options);
|
|
6888
7189
|
}
|
|
6889
7190
|
}
|
|
6890
7191
|
async function projectsUpdateCommand(options) {
|
|
6891
7192
|
try {
|
|
6892
|
-
const id = options.id ??
|
|
7193
|
+
const id = options.id ?? fail("projects update requires --id");
|
|
6893
7194
|
await run3(
|
|
6894
7195
|
"update",
|
|
6895
7196
|
{
|
|
@@ -6900,18 +7201,18 @@ async function projectsUpdateCommand(options) {
|
|
|
6900
7201
|
options
|
|
6901
7202
|
);
|
|
6902
7203
|
} catch (error) {
|
|
6903
|
-
|
|
7204
|
+
exitCommandError(error, options);
|
|
6904
7205
|
}
|
|
6905
7206
|
}
|
|
6906
7207
|
async function projectsRemoveCommand(options) {
|
|
6907
7208
|
try {
|
|
6908
|
-
const id = options.id ??
|
|
7209
|
+
const id = options.id ?? fail("projects remove requires --id");
|
|
6909
7210
|
if (!options.yes) {
|
|
6910
|
-
|
|
7211
|
+
fail("projects remove requires --yes");
|
|
6911
7212
|
}
|
|
6912
7213
|
await run3("remove", { id, yes: true }, options);
|
|
6913
7214
|
} catch (error) {
|
|
6914
|
-
|
|
7215
|
+
exitCommandError(error, options);
|
|
6915
7216
|
}
|
|
6916
7217
|
}
|
|
6917
7218
|
|
|
@@ -6919,11 +7220,6 @@ async function projectsRemoveCommand(options) {
|
|
|
6919
7220
|
init_esm_shims();
|
|
6920
7221
|
init_api();
|
|
6921
7222
|
init_tui();
|
|
6922
|
-
import process14 from "process";
|
|
6923
|
-
var writeJson6 = (value) => {
|
|
6924
|
-
process14.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
6925
|
-
`);
|
|
6926
|
-
};
|
|
6927
7223
|
var parseCsv3 = (input) => {
|
|
6928
7224
|
if (!input) {
|
|
6929
7225
|
return void 0;
|
|
@@ -6931,14 +7227,6 @@ var parseCsv3 = (input) => {
|
|
|
6931
7227
|
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
6932
7228
|
return values.length > 0 ? values : void 0;
|
|
6933
7229
|
};
|
|
6934
|
-
var exitWithError5 = (error) => {
|
|
6935
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
6936
|
-
log.error(message);
|
|
6937
|
-
process14.exit(1);
|
|
6938
|
-
};
|
|
6939
|
-
var fail4 = (message) => {
|
|
6940
|
-
throw new Error(message);
|
|
6941
|
-
};
|
|
6942
7230
|
var run4 = async (command, args, options) => {
|
|
6943
7231
|
const apiOptions = {
|
|
6944
7232
|
...options.server ? { serverUrl: options.server } : {},
|
|
@@ -6953,69 +7241,69 @@ var run4 = async (command, args, options) => {
|
|
|
6953
7241
|
apiOptions
|
|
6954
7242
|
);
|
|
6955
7243
|
if (options.json) {
|
|
6956
|
-
|
|
7244
|
+
writeJson(result);
|
|
6957
7245
|
return;
|
|
6958
7246
|
}
|
|
6959
7247
|
log.success(`references ${command} completed`);
|
|
6960
7248
|
};
|
|
6961
7249
|
async function referencesListCommand(options) {
|
|
6962
7250
|
try {
|
|
6963
|
-
const ruleId = options.ruleId ??
|
|
7251
|
+
const ruleId = options.ruleId ?? fail("references list requires --rule-id");
|
|
6964
7252
|
await run4("list", { ruleId }, options);
|
|
6965
7253
|
} catch (error) {
|
|
6966
|
-
|
|
7254
|
+
exitCommandError(error, options);
|
|
6967
7255
|
}
|
|
6968
7256
|
}
|
|
6969
7257
|
async function referencesGetCommand(options) {
|
|
6970
7258
|
try {
|
|
6971
|
-
const id = options.id ??
|
|
7259
|
+
const id = options.id ?? fail("references get requires --id");
|
|
6972
7260
|
await run4("get", { id }, options);
|
|
6973
7261
|
} catch (error) {
|
|
6974
|
-
|
|
7262
|
+
exitCommandError(error, options);
|
|
6975
7263
|
}
|
|
6976
7264
|
}
|
|
6977
7265
|
async function referencesCreateCommand(options) {
|
|
6978
7266
|
try {
|
|
6979
|
-
const ruleId = options.ruleId ??
|
|
6980
|
-
const file = options.file ??
|
|
7267
|
+
const ruleId = options.ruleId ?? fail("references create requires --rule-id");
|
|
7268
|
+
const file = options.file ?? fail("references create requires --file");
|
|
6981
7269
|
await run4("create", { ruleId, file }, options);
|
|
6982
7270
|
} catch (error) {
|
|
6983
|
-
|
|
7271
|
+
exitCommandError(error, options);
|
|
6984
7272
|
}
|
|
6985
7273
|
}
|
|
6986
7274
|
async function referencesUpdateCommand(options) {
|
|
6987
7275
|
try {
|
|
6988
|
-
const id = options.id ??
|
|
7276
|
+
const id = options.id ?? fail("references update requires --id");
|
|
6989
7277
|
await run4(
|
|
6990
7278
|
"update",
|
|
6991
7279
|
{ id, label: options.label, replaceFile: options.replaceFile },
|
|
6992
7280
|
options
|
|
6993
7281
|
);
|
|
6994
7282
|
} catch (error) {
|
|
6995
|
-
|
|
7283
|
+
exitCommandError(error, options);
|
|
6996
7284
|
}
|
|
6997
7285
|
}
|
|
6998
7286
|
async function referencesRemoveCommand(options) {
|
|
6999
7287
|
try {
|
|
7000
|
-
const id = options.id ??
|
|
7288
|
+
const id = options.id ?? fail("references remove requires --id");
|
|
7001
7289
|
if (!options.yes) {
|
|
7002
|
-
|
|
7290
|
+
fail("references remove requires --yes");
|
|
7003
7291
|
}
|
|
7004
7292
|
await run4("remove", { id, yes: true }, options);
|
|
7005
7293
|
} catch (error) {
|
|
7006
|
-
|
|
7294
|
+
exitCommandError(error, options);
|
|
7007
7295
|
}
|
|
7008
7296
|
}
|
|
7009
7297
|
async function referencesReorderCommand(options) {
|
|
7010
7298
|
try {
|
|
7011
|
-
const ruleId = options.ruleId ??
|
|
7299
|
+
const ruleId = options.ruleId ?? fail("references reorder requires --rule-id");
|
|
7012
7300
|
const orderedIds = parseCsv3(options.orderedIds);
|
|
7013
7301
|
if (!orderedIds || orderedIds.length === 0) {
|
|
7014
|
-
|
|
7302
|
+
fail("references reorder requires --ordered-ids");
|
|
7015
7303
|
}
|
|
7016
7304
|
await run4("reorder", { ruleId, orderedIds }, options);
|
|
7017
7305
|
} catch (error) {
|
|
7018
|
-
|
|
7306
|
+
exitCommandError(error, options);
|
|
7019
7307
|
}
|
|
7020
7308
|
}
|
|
7021
7309
|
|
|
@@ -7023,7 +7311,7 @@ async function referencesReorderCommand(options) {
|
|
|
7023
7311
|
init_esm_shims();
|
|
7024
7312
|
import { rm as rm7 } from "fs/promises";
|
|
7025
7313
|
import { join as join14, resolve as resolve8 } from "path";
|
|
7026
|
-
import
|
|
7314
|
+
import process13 from "process";
|
|
7027
7315
|
init_tui();
|
|
7028
7316
|
async function collectInstalledSkills(detectedAgents, options) {
|
|
7029
7317
|
const skillsToRemove = [];
|
|
@@ -7056,7 +7344,7 @@ async function selectSkillsToRemove(skillsToRemove, options) {
|
|
|
7056
7344
|
if (selected.length === 0) {
|
|
7057
7345
|
log.error(`Skill '${options.skill}' not found.`);
|
|
7058
7346
|
log.info("Run 'braid list' to see installed skills.");
|
|
7059
|
-
|
|
7347
|
+
process13.exit(1);
|
|
7060
7348
|
}
|
|
7061
7349
|
return selected;
|
|
7062
7350
|
}
|
|
@@ -7075,7 +7363,7 @@ async function selectSkillsToRemove(skillsToRemove, options) {
|
|
|
7075
7363
|
});
|
|
7076
7364
|
if (isCancel(result)) {
|
|
7077
7365
|
cancel("Remove cancelled.");
|
|
7078
|
-
|
|
7366
|
+
process13.exit(0);
|
|
7079
7367
|
}
|
|
7080
7368
|
return result;
|
|
7081
7369
|
}
|
|
@@ -7089,7 +7377,7 @@ async function confirmRemoval(selectedCount, options) {
|
|
|
7089
7377
|
});
|
|
7090
7378
|
if (isCancel(confirmed) || !confirmed) {
|
|
7091
7379
|
cancel("Remove cancelled.");
|
|
7092
|
-
|
|
7380
|
+
process13.exit(0);
|
|
7093
7381
|
}
|
|
7094
7382
|
}
|
|
7095
7383
|
async function removeSkill(skill, removeSpinner) {
|
|
@@ -7153,7 +7441,7 @@ async function removeCommand(options) {
|
|
|
7153
7441
|
removeSpinner.stop("Remove failed");
|
|
7154
7442
|
const message = error instanceof Error ? error.message : String(error);
|
|
7155
7443
|
log.error(message);
|
|
7156
|
-
|
|
7444
|
+
process13.exit(1);
|
|
7157
7445
|
}
|
|
7158
7446
|
}
|
|
7159
7447
|
|
|
@@ -7212,6 +7500,7 @@ async function retractCommand(source, _options) {
|
|
|
7212
7500
|
// src/commands/rollback.ts
|
|
7213
7501
|
init_esm_shims();
|
|
7214
7502
|
init_api();
|
|
7503
|
+
init_config();
|
|
7215
7504
|
init_lockfile();
|
|
7216
7505
|
init_tui();
|
|
7217
7506
|
var PUBLIC_SOURCE_REGEX2 = /^@([a-z0-9-]+)\/([a-z0-9-]+)$/;
|
|
@@ -7244,6 +7533,8 @@ async function findPreviousActiveVersion(args) {
|
|
|
7244
7533
|
return null;
|
|
7245
7534
|
}
|
|
7246
7535
|
async function rollbackCommand(source, options) {
|
|
7536
|
+
const config = await loadMergedConfigAsync();
|
|
7537
|
+
const serverUrl = options.server ?? config.serverUrl;
|
|
7247
7538
|
intro(`Rolling back ${source}`);
|
|
7248
7539
|
const rollbackSpinner = spinner();
|
|
7249
7540
|
rollbackSpinner.start("Reading lockfile...");
|
|
@@ -7308,7 +7599,7 @@ async function rollbackCommand(source, options) {
|
|
|
7308
7599
|
slug: publicSource.slug,
|
|
7309
7600
|
currentVersion: parsed.version,
|
|
7310
7601
|
ruleIds: currentValue.ruleIds,
|
|
7311
|
-
server:
|
|
7602
|
+
server: serverUrl
|
|
7312
7603
|
});
|
|
7313
7604
|
if (!result) {
|
|
7314
7605
|
rollbackSpinner.stop("No active version found");
|
|
@@ -7351,7 +7642,6 @@ async function rollbackCommand(source, options) {
|
|
|
7351
7642
|
init_esm_shims();
|
|
7352
7643
|
init_api();
|
|
7353
7644
|
init_tui();
|
|
7354
|
-
import process16 from "process";
|
|
7355
7645
|
var parseCsv4 = (input) => {
|
|
7356
7646
|
if (!input) {
|
|
7357
7647
|
return void 0;
|
|
@@ -7359,18 +7649,6 @@ var parseCsv4 = (input) => {
|
|
|
7359
7649
|
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
7360
7650
|
return values.length > 0 ? values : void 0;
|
|
7361
7651
|
};
|
|
7362
|
-
var writeJson7 = (value) => {
|
|
7363
|
-
process16.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
7364
|
-
`);
|
|
7365
|
-
};
|
|
7366
|
-
var exitWithError6 = (error) => {
|
|
7367
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
7368
|
-
log.error(message);
|
|
7369
|
-
process16.exit(1);
|
|
7370
|
-
};
|
|
7371
|
-
var fail5 = (message) => {
|
|
7372
|
-
throw new Error(message);
|
|
7373
|
-
};
|
|
7374
7652
|
var run5 = async (command, args, options) => {
|
|
7375
7653
|
const apiOptions = {
|
|
7376
7654
|
...options.server ? { serverUrl: options.server } : {},
|
|
@@ -7385,23 +7663,23 @@ var run5 = async (command, args, options) => {
|
|
|
7385
7663
|
apiOptions
|
|
7386
7664
|
);
|
|
7387
7665
|
if (options.json) {
|
|
7388
|
-
|
|
7666
|
+
writeJson(result);
|
|
7389
7667
|
return;
|
|
7390
7668
|
}
|
|
7391
7669
|
log.success(`rules ${command} completed`);
|
|
7392
7670
|
};
|
|
7393
7671
|
async function rulesGetCommand(options) {
|
|
7394
7672
|
try {
|
|
7395
|
-
const id = options.id ??
|
|
7673
|
+
const id = options.id ?? fail("rules get requires --id");
|
|
7396
7674
|
await run5("get", { id }, options);
|
|
7397
7675
|
} catch (error) {
|
|
7398
|
-
|
|
7676
|
+
exitCommandError(error, options);
|
|
7399
7677
|
}
|
|
7400
7678
|
}
|
|
7401
7679
|
async function rulesCreateCommand(options) {
|
|
7402
7680
|
try {
|
|
7403
|
-
const title = options.title ??
|
|
7404
|
-
const content = options.content ??
|
|
7681
|
+
const title = options.title ?? fail("rules create requires --title");
|
|
7682
|
+
const content = options.content ?? fail("rules create requires --content");
|
|
7405
7683
|
await run5(
|
|
7406
7684
|
"create",
|
|
7407
7685
|
{
|
|
@@ -7414,12 +7692,12 @@ async function rulesCreateCommand(options) {
|
|
|
7414
7692
|
options
|
|
7415
7693
|
);
|
|
7416
7694
|
} catch (error) {
|
|
7417
|
-
|
|
7695
|
+
exitCommandError(error, options);
|
|
7418
7696
|
}
|
|
7419
7697
|
}
|
|
7420
7698
|
async function rulesUpdateCommand(options) {
|
|
7421
7699
|
try {
|
|
7422
|
-
const id = options.id ??
|
|
7700
|
+
const id = options.id ?? fail("rules update requires --id");
|
|
7423
7701
|
await run5(
|
|
7424
7702
|
"update",
|
|
7425
7703
|
{
|
|
@@ -7432,120 +7710,120 @@ async function rulesUpdateCommand(options) {
|
|
|
7432
7710
|
options
|
|
7433
7711
|
);
|
|
7434
7712
|
} catch (error) {
|
|
7435
|
-
|
|
7713
|
+
exitCommandError(error, options);
|
|
7436
7714
|
}
|
|
7437
7715
|
}
|
|
7438
7716
|
async function rulesRemoveCommand(options) {
|
|
7439
7717
|
try {
|
|
7440
|
-
const id = options.id ??
|
|
7718
|
+
const id = options.id ?? fail("rules remove requires --id");
|
|
7441
7719
|
if (!options.yes) {
|
|
7442
|
-
|
|
7720
|
+
fail("rules remove requires --yes");
|
|
7443
7721
|
}
|
|
7444
7722
|
await run5("remove", { id, yes: true }, options);
|
|
7445
7723
|
} catch (error) {
|
|
7446
|
-
|
|
7724
|
+
exitCommandError(error, options);
|
|
7447
7725
|
}
|
|
7448
7726
|
}
|
|
7449
7727
|
async function rulesEnableCommand(options) {
|
|
7450
7728
|
try {
|
|
7451
|
-
const id = options.id ??
|
|
7729
|
+
const id = options.id ?? fail("rules enable requires --id");
|
|
7452
7730
|
await run5("enable", { id }, options);
|
|
7453
7731
|
} catch (error) {
|
|
7454
|
-
|
|
7732
|
+
exitCommandError(error, options);
|
|
7455
7733
|
}
|
|
7456
7734
|
}
|
|
7457
7735
|
async function rulesDisableCommand(options) {
|
|
7458
7736
|
try {
|
|
7459
|
-
const id = options.id ??
|
|
7737
|
+
const id = options.id ?? fail("rules disable requires --id");
|
|
7460
7738
|
await run5("disable", { id }, options);
|
|
7461
7739
|
} catch (error) {
|
|
7462
|
-
|
|
7740
|
+
exitCommandError(error, options);
|
|
7463
7741
|
}
|
|
7464
7742
|
}
|
|
7465
7743
|
async function rulesMoveCommand(options) {
|
|
7466
7744
|
try {
|
|
7467
|
-
const id = options.id ??
|
|
7468
|
-
const projectId = options.projectId ??
|
|
7745
|
+
const id = options.id ?? fail("rules move requires --id");
|
|
7746
|
+
const projectId = options.projectId ?? fail("rules move requires --project-id");
|
|
7469
7747
|
await run5("move", { id, projectId }, options);
|
|
7470
7748
|
} catch (error) {
|
|
7471
|
-
|
|
7749
|
+
exitCommandError(error, options);
|
|
7472
7750
|
}
|
|
7473
7751
|
}
|
|
7474
7752
|
async function rulesDuplicateCommand(options) {
|
|
7475
7753
|
try {
|
|
7476
|
-
const id = options.id ??
|
|
7754
|
+
const id = options.id ?? fail("rules duplicate requires --id");
|
|
7477
7755
|
await run5(
|
|
7478
7756
|
"duplicate",
|
|
7479
7757
|
{ id, targetProjectId: options.targetProjectId },
|
|
7480
7758
|
options
|
|
7481
7759
|
);
|
|
7482
7760
|
} catch (error) {
|
|
7483
|
-
|
|
7761
|
+
exitCommandError(error, options);
|
|
7484
7762
|
}
|
|
7485
7763
|
}
|
|
7486
7764
|
async function rulesForkCommand(options) {
|
|
7487
7765
|
try {
|
|
7488
|
-
const id = options.id ??
|
|
7766
|
+
const id = options.id ?? fail("rules fork requires --id");
|
|
7489
7767
|
await run5(
|
|
7490
7768
|
"fork",
|
|
7491
7769
|
{ id, targetProjectId: options.targetProjectId },
|
|
7492
7770
|
options
|
|
7493
7771
|
);
|
|
7494
7772
|
} catch (error) {
|
|
7495
|
-
|
|
7773
|
+
exitCommandError(error, options);
|
|
7496
7774
|
}
|
|
7497
7775
|
}
|
|
7498
7776
|
async function rulesSyncStatusCommand(options) {
|
|
7499
7777
|
try {
|
|
7500
7778
|
await run5("sync-status", { id: options.id }, options);
|
|
7501
7779
|
} catch (error) {
|
|
7502
|
-
|
|
7780
|
+
exitCommandError(error, options);
|
|
7503
7781
|
}
|
|
7504
7782
|
}
|
|
7505
7783
|
async function rulesSyncHistoryCommand(options) {
|
|
7506
7784
|
try {
|
|
7507
|
-
const id = options.id ??
|
|
7785
|
+
const id = options.id ?? fail("rules sync-history requires --id");
|
|
7508
7786
|
await run5("sync-history", { id }, options);
|
|
7509
7787
|
} catch (error) {
|
|
7510
|
-
|
|
7788
|
+
exitCommandError(error, options);
|
|
7511
7789
|
}
|
|
7512
7790
|
}
|
|
7513
7791
|
async function rulesSyncEnableCommand(options) {
|
|
7514
7792
|
try {
|
|
7515
|
-
const id = options.id ??
|
|
7793
|
+
const id = options.id ?? fail("rules sync-enable requires --id");
|
|
7516
7794
|
await run5("sync-enable", { id }, options);
|
|
7517
7795
|
} catch (error) {
|
|
7518
|
-
|
|
7796
|
+
exitCommandError(error, options);
|
|
7519
7797
|
}
|
|
7520
7798
|
}
|
|
7521
7799
|
async function rulesSyncDisableCommand(options) {
|
|
7522
7800
|
try {
|
|
7523
|
-
const id = options.id ??
|
|
7801
|
+
const id = options.id ?? fail("rules sync-disable requires --id");
|
|
7524
7802
|
await run5("sync-disable", { id }, options);
|
|
7525
7803
|
} catch (error) {
|
|
7526
|
-
|
|
7804
|
+
exitCommandError(error, options);
|
|
7527
7805
|
}
|
|
7528
7806
|
}
|
|
7529
7807
|
async function rulesSyncCheckCommand(options) {
|
|
7530
7808
|
try {
|
|
7531
|
-
const id = options.id ??
|
|
7809
|
+
const id = options.id ?? fail("rules sync-check requires --id");
|
|
7532
7810
|
await run5("sync-check", { id }, options);
|
|
7533
7811
|
} catch (error) {
|
|
7534
|
-
|
|
7812
|
+
exitCommandError(error, options);
|
|
7535
7813
|
}
|
|
7536
7814
|
}
|
|
7537
7815
|
async function rulesSyncNowCommand(options) {
|
|
7538
7816
|
try {
|
|
7539
|
-
const id = options.id ??
|
|
7817
|
+
const id = options.id ?? fail("rules sync-now requires --id");
|
|
7540
7818
|
await run5("sync-now", { id }, options);
|
|
7541
7819
|
} catch (error) {
|
|
7542
|
-
|
|
7820
|
+
exitCommandError(error, options);
|
|
7543
7821
|
}
|
|
7544
7822
|
}
|
|
7545
7823
|
|
|
7546
7824
|
// src/commands/scaffold.ts
|
|
7547
7825
|
init_esm_shims();
|
|
7548
|
-
import
|
|
7826
|
+
import process14 from "process";
|
|
7549
7827
|
|
|
7550
7828
|
// src/lib/scaffold.ts
|
|
7551
7829
|
init_esm_shims();
|
|
@@ -8505,11 +8783,11 @@ var normalizeReferenceList = (referenceLabel, availableNamesLabel, values, avail
|
|
|
8505
8783
|
};
|
|
8506
8784
|
var exitCancelled2 = () => {
|
|
8507
8785
|
cancel("Scaffold cancelled.");
|
|
8508
|
-
|
|
8786
|
+
process14.exit(0);
|
|
8509
8787
|
};
|
|
8510
|
-
var
|
|
8788
|
+
var exitWithError = (message) => {
|
|
8511
8789
|
log.error(message);
|
|
8512
|
-
|
|
8790
|
+
process14.exit(1);
|
|
8513
8791
|
};
|
|
8514
8792
|
var requirePromptValue = (value) => {
|
|
8515
8793
|
if (isCancel(value)) {
|
|
@@ -8522,7 +8800,7 @@ var resolveType = async (options) => {
|
|
|
8522
8800
|
return options.type;
|
|
8523
8801
|
}
|
|
8524
8802
|
if (options.yes) {
|
|
8525
|
-
return
|
|
8803
|
+
return exitWithError("--type is required when using --yes");
|
|
8526
8804
|
}
|
|
8527
8805
|
const selected = requirePromptValue(
|
|
8528
8806
|
await select({
|
|
@@ -8552,7 +8830,7 @@ var resolveName = async (options) => {
|
|
|
8552
8830
|
return options.name.trim();
|
|
8553
8831
|
}
|
|
8554
8832
|
if (options.yes) {
|
|
8555
|
-
return
|
|
8833
|
+
return exitWithError("--name is required when using --yes");
|
|
8556
8834
|
}
|
|
8557
8835
|
const value = requirePromptValue(
|
|
8558
8836
|
await text({
|
|
@@ -8638,7 +8916,7 @@ var resolveOptionalReference = async (label, flagValue, options, availableNames)
|
|
|
8638
8916
|
return selected || void 0;
|
|
8639
8917
|
};
|
|
8640
8918
|
var buildScaffoldInput = async (options) => {
|
|
8641
|
-
const context = await inspectScaffoldDirectory(
|
|
8919
|
+
const context = await inspectScaffoldDirectory(process14.cwd());
|
|
8642
8920
|
const availableSkillNames = context.manifest.skills.map(
|
|
8643
8921
|
(entry) => entry.name
|
|
8644
8922
|
);
|
|
@@ -8692,7 +8970,7 @@ var buildScaffoldInput = async (options) => {
|
|
|
8692
8970
|
availableWorkflowNames
|
|
8693
8971
|
) : void 0;
|
|
8694
8972
|
return {
|
|
8695
|
-
cwd:
|
|
8973
|
+
cwd: process14.cwd(),
|
|
8696
8974
|
type,
|
|
8697
8975
|
name,
|
|
8698
8976
|
title,
|
|
@@ -8721,10 +8999,10 @@ var finishScaffoldSuccess = (type, name, createdFiles) => {
|
|
|
8721
8999
|
var isMockedProcessExitError = (error) => error instanceof Error && error.message.startsWith("process.exit:");
|
|
8722
9000
|
var handleScaffoldCommandFailure = (error) => {
|
|
8723
9001
|
if (error instanceof ScaffoldError) {
|
|
8724
|
-
|
|
9002
|
+
exitWithError(error.message);
|
|
8725
9003
|
}
|
|
8726
9004
|
if (error instanceof Error && !isMockedProcessExitError(error)) {
|
|
8727
|
-
|
|
9005
|
+
exitWithError(error.message);
|
|
8728
9006
|
}
|
|
8729
9007
|
throw error;
|
|
8730
9008
|
};
|
|
@@ -9174,10 +9452,16 @@ async function updateCommand(options) {
|
|
|
9174
9452
|
}
|
|
9175
9453
|
|
|
9176
9454
|
// src/index.ts
|
|
9455
|
+
init_tui();
|
|
9177
9456
|
var require2 = createRequire(import.meta.url);
|
|
9178
9457
|
var { version: PACKAGE_VERSION } = require2("../package.json");
|
|
9458
|
+
var COMMANDER_ERROR_PREFIX = /^error:\s*/i;
|
|
9179
9459
|
var program = new Command();
|
|
9180
|
-
program.name("braid").description("Install and manage braid prompt artifacts locally").version(PACKAGE_VERSION)
|
|
9460
|
+
program.name("braid").description("Install and manage braid prompt artifacts locally").version(PACKAGE_VERSION).configureOutput({
|
|
9461
|
+
outputError: (str) => {
|
|
9462
|
+
log.error(str.replace(COMMANDER_ERROR_PREFIX, "").trim());
|
|
9463
|
+
}
|
|
9464
|
+
});
|
|
9181
9465
|
var auth = program.command("auth").description("Configure API key for braid authentication");
|
|
9182
9466
|
auth.command("login", { isDefault: true }).description("Authenticate with braid via browser login or API key").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option(
|
|
9183
9467
|
"--token <token>",
|