@braid-cloud/cli 0.1.18 → 0.1.20
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 +1366 -1078
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
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(),
|
|
@@ -498,89 +523,226 @@ var init_config = __esm({
|
|
|
498
523
|
}
|
|
499
524
|
});
|
|
500
525
|
|
|
501
|
-
// src/lib/
|
|
502
|
-
import {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
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"() {
|
|
506
703
|
"use strict";
|
|
507
704
|
init_esm_shims();
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
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";
|
|
528
729
|
}
|
|
529
730
|
};
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
NetworkError = class extends Data3.TaggedError("NetworkError") {
|
|
535
|
-
};
|
|
536
|
-
resolveApiKey = (optionsApiKey) => {
|
|
537
|
-
if (optionsApiKey) {
|
|
538
|
-
return Effect4.succeed(optionsApiKey);
|
|
731
|
+
DeviceAuthDeniedError = class extends Error {
|
|
732
|
+
constructor() {
|
|
733
|
+
super("Device authorization was denied");
|
|
734
|
+
this.name = "DeviceAuthDeniedError";
|
|
539
735
|
}
|
|
540
|
-
return pipe4(
|
|
541
|
-
Effect4.tryPromise({
|
|
542
|
-
try: () => getApiKeyAsync(),
|
|
543
|
-
catch: () => new NetworkError({ message: "Failed to read config" })
|
|
544
|
-
}),
|
|
545
|
-
Effect4.flatMap(
|
|
546
|
-
(key) => key ? Effect4.succeed(key) : Effect4.fail(
|
|
547
|
-
new AuthenticationError({
|
|
548
|
-
message: 'No API key configured. Run "braid auth" to authenticate.'
|
|
549
|
-
})
|
|
550
|
-
)
|
|
551
|
-
)
|
|
552
|
-
);
|
|
553
736
|
};
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
new NetworkError({
|
|
559
|
-
message: `Untrusted server URL '${optionsServerUrl}'. Set ${ALLOW_UNTRUSTED_SERVER_ENV}=true to override.`
|
|
560
|
-
})
|
|
561
|
-
);
|
|
562
|
-
}
|
|
563
|
-
return Effect4.succeed(optionsServerUrl);
|
|
737
|
+
DeviceAuthExpiredError = class extends Error {
|
|
738
|
+
constructor() {
|
|
739
|
+
super("Device authorization code has expired");
|
|
740
|
+
this.name = "DeviceAuthExpiredError";
|
|
564
741
|
}
|
|
565
|
-
return pipe4(
|
|
566
|
-
Effect4.tryPromise({
|
|
567
|
-
try: () => getServerUrlAsync(),
|
|
568
|
-
catch: () => new NetworkError({ message: "Failed to read config" })
|
|
569
|
-
}),
|
|
570
|
-
Effect4.flatMap((serverUrl) => {
|
|
571
|
-
if (isTruthy(process.env[ALLOW_UNTRUSTED_SERVER_ENV]) || isTrustedApiServerUrl(serverUrl)) {
|
|
572
|
-
return Effect4.succeed(serverUrl);
|
|
573
|
-
}
|
|
574
|
-
return Effect4.fail(
|
|
575
|
-
new NetworkError({
|
|
576
|
-
message: `Untrusted server URL '${serverUrl}'. Set ${ALLOW_UNTRUSTED_SERVER_ENV}=true to override.`
|
|
577
|
-
})
|
|
578
|
-
);
|
|
579
|
-
})
|
|
580
|
-
);
|
|
581
742
|
};
|
|
582
|
-
|
|
583
|
-
|
|
743
|
+
sleep = (ms) => new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
744
|
+
normalizeBaseUrl2 = (rawUrl) => {
|
|
745
|
+
const trimmed = rawUrl.replace(TRAILING_SLASHES2, "");
|
|
584
746
|
try {
|
|
585
747
|
const url = new URL(trimmed);
|
|
586
748
|
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
@@ -588,13 +750,296 @@ var init_api = __esm({
|
|
|
588
750
|
return trimmed;
|
|
589
751
|
}
|
|
590
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, resolvePublicRequestServerUrl, 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
|
+
resolvePublicRequestServerUrl = (serverUrl, apiKey) => resolveApiRequestServerUrl(serverUrl, apiKey);
|
|
993
|
+
normalizeApiServerBaseUrl = (serverUrl) => {
|
|
994
|
+
const trimmed = serverUrl.replace(TRAILING_SLASH_REGEX, "");
|
|
995
|
+
try {
|
|
996
|
+
const url = new URL(trimmed);
|
|
997
|
+
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
998
|
+
} catch {
|
|
999
|
+
return trimmed;
|
|
1000
|
+
}
|
|
1001
|
+
};
|
|
1002
|
+
readJsonResponseAsync = async (response) => {
|
|
1003
|
+
const raw = await response.text();
|
|
1004
|
+
if (raw.trim().length === 0) {
|
|
1005
|
+
if (response.ok) {
|
|
1006
|
+
throw new Error("Empty API response");
|
|
1007
|
+
}
|
|
1008
|
+
return null;
|
|
1009
|
+
}
|
|
1010
|
+
try {
|
|
1011
|
+
return JSON.parse(raw);
|
|
1012
|
+
} catch (error) {
|
|
1013
|
+
if (!response.ok) {
|
|
1014
|
+
return null;
|
|
1015
|
+
}
|
|
1016
|
+
throw error;
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
readJsonResponse = (response) => Effect4.tryPromise({
|
|
1020
|
+
try: () => readJsonResponseAsync(response),
|
|
1021
|
+
catch: () => new NetworkError({ message: "Failed to parse API response" })
|
|
1022
|
+
});
|
|
1023
|
+
getApiErrorResponse = (json) => {
|
|
1024
|
+
if (typeof json !== "object" || json === null || Array.isArray(json)) {
|
|
1025
|
+
return {};
|
|
1026
|
+
}
|
|
1027
|
+
return json;
|
|
1028
|
+
};
|
|
1029
|
+
isAuthenticationErrorResponse = (response, json) => {
|
|
1030
|
+
if (response.status === 401) {
|
|
1031
|
+
return true;
|
|
1032
|
+
}
|
|
1033
|
+
const errorResponse = getApiErrorResponse(json);
|
|
1034
|
+
return RAW_AUTH_ERROR_PATTERN.test(errorResponse.error ?? "");
|
|
1035
|
+
};
|
|
591
1036
|
parseResponse = (response, json) => {
|
|
592
1037
|
if (!response.ok) {
|
|
593
|
-
const errorResponse = json;
|
|
594
|
-
if (response
|
|
1038
|
+
const errorResponse = getApiErrorResponse(json);
|
|
1039
|
+
if (isAuthenticationErrorResponse(response, json)) {
|
|
595
1040
|
return Effect4.fail(
|
|
596
1041
|
new AuthenticationError({
|
|
597
|
-
message: errorResponse.error
|
|
1042
|
+
message: normalizeAuthenticationErrorMessage(errorResponse.error)
|
|
598
1043
|
})
|
|
599
1044
|
);
|
|
600
1045
|
}
|
|
@@ -653,10 +1098,10 @@ var init_api = __esm({
|
|
|
653
1098
|
Effect4.tryPromise({
|
|
654
1099
|
try: () => fetch(url.toString(), {
|
|
655
1100
|
method: "GET",
|
|
656
|
-
headers: {
|
|
1101
|
+
headers: mergeAutomationHeaders({
|
|
657
1102
|
"Content-Type": "application/json",
|
|
658
1103
|
...apiKey ? { Authorization: `Bearer ${apiKey}` } : {}
|
|
659
|
-
}
|
|
1104
|
+
})
|
|
660
1105
|
}),
|
|
661
1106
|
catch: (e) => new NetworkError({
|
|
662
1107
|
message: `Failed to connect to ${serverUrl}`,
|
|
@@ -666,7 +1111,7 @@ var init_api = __esm({
|
|
|
666
1111
|
Effect4.flatMap(
|
|
667
1112
|
(response) => pipe4(
|
|
668
1113
|
Effect4.tryPromise({
|
|
669
|
-
try: () => response
|
|
1114
|
+
try: () => readJsonResponseAsync(response),
|
|
670
1115
|
catch: () => new NetworkError({ message: "Failed to parse API response" })
|
|
671
1116
|
}),
|
|
672
1117
|
Effect4.flatMap((json) => parseResponse(response, json))
|
|
@@ -675,11 +1120,11 @@ var init_api = __esm({
|
|
|
675
1120
|
);
|
|
676
1121
|
parseScopeOptionsResponse = (response, json) => {
|
|
677
1122
|
if (!response.ok) {
|
|
678
|
-
const errorResponse = json;
|
|
679
|
-
if (response
|
|
1123
|
+
const errorResponse = getApiErrorResponse(json);
|
|
1124
|
+
if (isAuthenticationErrorResponse(response, json)) {
|
|
680
1125
|
return Effect4.fail(
|
|
681
1126
|
new AuthenticationError({
|
|
682
|
-
message: errorResponse.error
|
|
1127
|
+
message: normalizeAuthenticationErrorMessage(errorResponse.error)
|
|
683
1128
|
})
|
|
684
1129
|
);
|
|
685
1130
|
}
|
|
@@ -698,33 +1143,37 @@ var init_api = __esm({
|
|
|
698
1143
|
apiKey: resolveApiKey(options.apiKey),
|
|
699
1144
|
serverUrl: resolveServerUrl(options.serverUrl)
|
|
700
1145
|
}),
|
|
701
|
-
Effect4.flatMap(
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
Effect4.
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
headers: {
|
|
708
|
-
Authorization: `Bearer ${apiKey}`,
|
|
709
|
-
"Content-Type": "application/json"
|
|
710
|
-
}
|
|
711
|
-
}),
|
|
712
|
-
catch: (e) => new NetworkError({
|
|
713
|
-
message: `Failed to connect to ${serverUrl}`,
|
|
714
|
-
cause: e
|
|
715
|
-
})
|
|
716
|
-
}),
|
|
717
|
-
Effect4.flatMap(
|
|
718
|
-
(response) => pipe4(
|
|
1146
|
+
Effect4.flatMap(
|
|
1147
|
+
({ apiKey, serverUrl }) => pipe4(
|
|
1148
|
+
resolveApiRequestServerUrl(serverUrl, apiKey),
|
|
1149
|
+
Effect4.flatMap((apiServerUrl) => {
|
|
1150
|
+
const url = buildApiUrl(apiServerUrl, "/api/skills/scope-options");
|
|
1151
|
+
return pipe4(
|
|
719
1152
|
Effect4.tryPromise({
|
|
720
|
-
try: () =>
|
|
721
|
-
|
|
1153
|
+
try: () => fetch(url.toString(), {
|
|
1154
|
+
method: "GET",
|
|
1155
|
+
headers: mergeAutomationHeaders({
|
|
1156
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1157
|
+
"Content-Type": "application/json"
|
|
1158
|
+
})
|
|
1159
|
+
}),
|
|
1160
|
+
catch: (e) => new NetworkError({
|
|
1161
|
+
message: `Failed to connect to ${apiServerUrl}`,
|
|
1162
|
+
cause: e
|
|
1163
|
+
})
|
|
722
1164
|
}),
|
|
723
|
-
Effect4.flatMap(
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
1165
|
+
Effect4.flatMap(
|
|
1166
|
+
(response) => pipe4(
|
|
1167
|
+
readJsonResponse(response),
|
|
1168
|
+
Effect4.flatMap(
|
|
1169
|
+
(json) => parseScopeOptionsResponse(response, json)
|
|
1170
|
+
)
|
|
1171
|
+
)
|
|
1172
|
+
)
|
|
1173
|
+
);
|
|
1174
|
+
})
|
|
1175
|
+
)
|
|
1176
|
+
)
|
|
728
1177
|
);
|
|
729
1178
|
buildLibraryOptionsUrl = (serverUrl, options) => {
|
|
730
1179
|
const url = buildApiUrl(serverUrl, "/api/skills/library-options");
|
|
@@ -758,41 +1207,57 @@ var init_api = __esm({
|
|
|
758
1207
|
}),
|
|
759
1208
|
Effect4.flatMap(
|
|
760
1209
|
({ apiKey, serverUrl }) => pipe4(
|
|
761
|
-
|
|
762
|
-
try: () => fetch(buildLibraryOptionsUrl(serverUrl, options).toString(), {
|
|
763
|
-
method: "GET",
|
|
764
|
-
headers: {
|
|
765
|
-
Authorization: `Bearer ${apiKey}`,
|
|
766
|
-
"Content-Type": "application/json"
|
|
767
|
-
}
|
|
768
|
-
}),
|
|
769
|
-
catch: (e) => new NetworkError({
|
|
770
|
-
message: `Failed to connect to ${serverUrl}`,
|
|
771
|
-
cause: e
|
|
772
|
-
})
|
|
773
|
-
}),
|
|
1210
|
+
resolveApiRequestServerUrl(serverUrl, apiKey),
|
|
774
1211
|
Effect4.flatMap(
|
|
775
|
-
(
|
|
1212
|
+
(apiServerUrl) => pipe4(
|
|
776
1213
|
Effect4.tryPromise({
|
|
777
|
-
try: () =>
|
|
778
|
-
|
|
1214
|
+
try: () => fetch(
|
|
1215
|
+
buildLibraryOptionsUrl(apiServerUrl, options).toString(),
|
|
1216
|
+
{
|
|
1217
|
+
method: "GET",
|
|
1218
|
+
headers: mergeAutomationHeaders({
|
|
1219
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1220
|
+
"Content-Type": "application/json"
|
|
1221
|
+
})
|
|
1222
|
+
}
|
|
1223
|
+
),
|
|
1224
|
+
catch: (e) => new NetworkError({
|
|
1225
|
+
message: `Failed to connect to ${apiServerUrl}`,
|
|
1226
|
+
cause: e
|
|
1227
|
+
})
|
|
779
1228
|
}),
|
|
780
|
-
Effect4.flatMap(
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
1229
|
+
Effect4.flatMap(
|
|
1230
|
+
(response) => pipe4(
|
|
1231
|
+
readJsonResponse(response),
|
|
1232
|
+
Effect4.flatMap(
|
|
1233
|
+
(json) => {
|
|
1234
|
+
if (!response.ok) {
|
|
1235
|
+
return pipe4(
|
|
1236
|
+
parseResponse(response, json),
|
|
1237
|
+
Effect4.flatMap(
|
|
1238
|
+
() => Effect4.fail(
|
|
1239
|
+
new ApiError({
|
|
1240
|
+
message: "API request failed",
|
|
1241
|
+
code: "UNKNOWN_ERROR",
|
|
1242
|
+
status: response.status
|
|
1243
|
+
})
|
|
1244
|
+
)
|
|
1245
|
+
),
|
|
1246
|
+
Effect4.catchTag(
|
|
1247
|
+
"AuthenticationError",
|
|
1248
|
+
(error) => Effect4.fail(error)
|
|
1249
|
+
),
|
|
1250
|
+
Effect4.catchTag(
|
|
1251
|
+
"ApiError",
|
|
1252
|
+
(error) => Effect4.fail(error)
|
|
1253
|
+
)
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
return Effect4.succeed(json);
|
|
1257
|
+
}
|
|
1258
|
+
)
|
|
1259
|
+
)
|
|
1260
|
+
)
|
|
796
1261
|
)
|
|
797
1262
|
)
|
|
798
1263
|
)
|
|
@@ -803,10 +1268,15 @@ var init_api = __esm({
|
|
|
803
1268
|
apiKey: options.demo ? Effect4.succeed(options.apiKey) : resolveApiKey(options.apiKey),
|
|
804
1269
|
serverUrl: resolveServerUrl(options.serverUrl)
|
|
805
1270
|
}),
|
|
806
|
-
Effect4.flatMap(
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
1271
|
+
Effect4.flatMap(
|
|
1272
|
+
({ apiKey, serverUrl }) => pipe4(
|
|
1273
|
+
resolveApiRequestServerUrl(serverUrl, apiKey),
|
|
1274
|
+
Effect4.flatMap((apiServerUrl) => {
|
|
1275
|
+
const url = buildExportUrl(apiServerUrl, options);
|
|
1276
|
+
return executeApiRequest(url, apiKey, apiServerUrl);
|
|
1277
|
+
})
|
|
1278
|
+
)
|
|
1279
|
+
)
|
|
810
1280
|
);
|
|
811
1281
|
runLifecycleCommand = (request, options = {}) => pipe4(
|
|
812
1282
|
Effect4.all({
|
|
@@ -814,45 +1284,56 @@ var init_api = __esm({
|
|
|
814
1284
|
serverUrl: resolveServerUrl(options.serverUrl)
|
|
815
1285
|
}),
|
|
816
1286
|
Effect4.flatMap(
|
|
817
|
-
({ apiKey, serverUrl }) =>
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
{
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
1287
|
+
({ apiKey, serverUrl }) => pipe4(
|
|
1288
|
+
resolveApiRequestServerUrl(serverUrl, apiKey),
|
|
1289
|
+
Effect4.flatMap(
|
|
1290
|
+
(apiServerUrl) => Effect4.tryPromise({
|
|
1291
|
+
try: async () => {
|
|
1292
|
+
const response = await fetch(
|
|
1293
|
+
buildApiUrl(apiServerUrl, "/api/lifecycle").toString(),
|
|
1294
|
+
{
|
|
1295
|
+
method: "POST",
|
|
1296
|
+
headers: mergeAutomationHeaders({
|
|
1297
|
+
"Content-Type": "application/json",
|
|
1298
|
+
...apiKey ? { Authorization: `Bearer ${apiKey}` } : {}
|
|
1299
|
+
}),
|
|
1300
|
+
body: JSON.stringify({ ...request, demo: options.demo })
|
|
1301
|
+
}
|
|
1302
|
+
);
|
|
1303
|
+
const json = await readJsonResponseAsync(response).catch(() => {
|
|
1304
|
+
throw new NetworkError({
|
|
1305
|
+
message: "Failed to parse API response"
|
|
1306
|
+
});
|
|
1307
|
+
});
|
|
1308
|
+
if (!response.ok) {
|
|
1309
|
+
const errorResponse = getApiErrorResponse(json);
|
|
1310
|
+
if (isAuthenticationErrorResponse(response, json)) {
|
|
1311
|
+
throw new AuthenticationError({
|
|
1312
|
+
message: normalizeAuthenticationErrorMessage(
|
|
1313
|
+
errorResponse.error
|
|
1314
|
+
)
|
|
1315
|
+
});
|
|
1316
|
+
}
|
|
1317
|
+
throw new ApiError({
|
|
1318
|
+
message: errorResponse.error || "API request failed",
|
|
1319
|
+
code: errorResponse.code || "UNKNOWN_ERROR",
|
|
1320
|
+
status: response.status
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
return json;
|
|
1324
|
+
},
|
|
1325
|
+
catch: (error) => {
|
|
1326
|
+
if (error instanceof ApiError || error instanceof AuthenticationError || error instanceof NetworkError) {
|
|
1327
|
+
return error;
|
|
1328
|
+
}
|
|
1329
|
+
return new NetworkError({
|
|
1330
|
+
message: `Failed to connect to ${apiServerUrl}`,
|
|
1331
|
+
cause: error
|
|
836
1332
|
});
|
|
837
1333
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
status: response.status
|
|
842
|
-
});
|
|
843
|
-
}
|
|
844
|
-
return json;
|
|
845
|
-
},
|
|
846
|
-
catch: (error) => {
|
|
847
|
-
if (error instanceof ApiError || error instanceof AuthenticationError || error instanceof NetworkError) {
|
|
848
|
-
return error;
|
|
849
|
-
}
|
|
850
|
-
return new NetworkError({
|
|
851
|
-
message: `Failed to connect to ${serverUrl}`,
|
|
852
|
-
cause: error
|
|
853
|
-
});
|
|
854
|
-
}
|
|
855
|
-
})
|
|
1334
|
+
})
|
|
1335
|
+
)
|
|
1336
|
+
)
|
|
856
1337
|
)
|
|
857
1338
|
);
|
|
858
1339
|
DEFAULT_PUBLIC_SERVER_URL = "https://braid.cloud";
|
|
@@ -879,7 +1360,7 @@ var init_api = __esm({
|
|
|
879
1360
|
})
|
|
880
1361
|
);
|
|
881
1362
|
}
|
|
882
|
-
const errorResponse = json;
|
|
1363
|
+
const errorResponse = getApiErrorResponse(json);
|
|
883
1364
|
return Effect4.fail(
|
|
884
1365
|
new ApiError({
|
|
885
1366
|
message: errorResponse.error || "API request failed",
|
|
@@ -888,72 +1369,84 @@ var init_api = __esm({
|
|
|
888
1369
|
})
|
|
889
1370
|
);
|
|
890
1371
|
};
|
|
891
|
-
fetchPublicMetadata = (handle, slug, serverUrl, version) => {
|
|
892
|
-
const
|
|
1372
|
+
fetchPublicMetadata = (handle, slug, serverUrl, version, apiKey) => {
|
|
1373
|
+
const requestedBaseUrl = (serverUrl ?? DEFAULT_PUBLIC_SERVER_URL).replace(
|
|
893
1374
|
TRAILING_SLASH_REGEX,
|
|
894
1375
|
""
|
|
895
1376
|
);
|
|
896
|
-
const url = new URL(`${baseUrl}/api/public/@${handle}/${slug}`);
|
|
897
|
-
if (version !== void 0) {
|
|
898
|
-
url.searchParams.set("version", String(version));
|
|
899
|
-
}
|
|
900
1377
|
return pipe4(
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
Effect4.flatMap(
|
|
909
|
-
(response) => pipe4(
|
|
1378
|
+
resolvePublicRequestServerUrl(requestedBaseUrl, apiKey),
|
|
1379
|
+
Effect4.flatMap((baseUrl) => {
|
|
1380
|
+
const url = new URL(`${baseUrl}/api/public/@${handle}/${slug}`);
|
|
1381
|
+
if (version !== void 0) {
|
|
1382
|
+
url.searchParams.set("version", String(version));
|
|
1383
|
+
}
|
|
1384
|
+
return pipe4(
|
|
910
1385
|
Effect4.tryPromise({
|
|
911
|
-
try: () =>
|
|
912
|
-
|
|
1386
|
+
try: () => fetch(url.toString(), {
|
|
1387
|
+
method: "GET",
|
|
1388
|
+
headers: mergeAutomationHeaders()
|
|
1389
|
+
}),
|
|
1390
|
+
catch: (e) => new NetworkError({
|
|
1391
|
+
message: `Failed to connect to ${baseUrl}`,
|
|
1392
|
+
cause: e
|
|
1393
|
+
})
|
|
913
1394
|
}),
|
|
914
1395
|
Effect4.flatMap(
|
|
915
|
-
(
|
|
1396
|
+
(response) => pipe4(
|
|
1397
|
+
readJsonResponse(response),
|
|
1398
|
+
Effect4.flatMap(
|
|
1399
|
+
(json) => handlePublicApiResponse(response, json)
|
|
1400
|
+
)
|
|
1401
|
+
)
|
|
916
1402
|
)
|
|
917
|
-
)
|
|
918
|
-
)
|
|
1403
|
+
);
|
|
1404
|
+
})
|
|
919
1405
|
);
|
|
920
1406
|
};
|
|
921
|
-
fetchPublicExport = (handle, slug, ruleIds, serverUrl, version) => {
|
|
922
|
-
const
|
|
1407
|
+
fetchPublicExport = (handle, slug, ruleIds, serverUrl, version, apiKey) => {
|
|
1408
|
+
const requestedBaseUrl = (serverUrl ?? DEFAULT_PUBLIC_SERVER_URL).replace(
|
|
923
1409
|
TRAILING_SLASH_REGEX,
|
|
924
1410
|
""
|
|
925
1411
|
);
|
|
926
|
-
const url = new URL(`${baseUrl}/api/public/@${handle}/${slug}/export`);
|
|
927
|
-
if (ruleIds && ruleIds.length > 0) {
|
|
928
|
-
url.searchParams.set("ruleIds", ruleIds.join(","));
|
|
929
|
-
}
|
|
930
|
-
if (version !== void 0) {
|
|
931
|
-
url.searchParams.set("version", String(version));
|
|
932
|
-
}
|
|
933
1412
|
return pipe4(
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1413
|
+
resolvePublicRequestServerUrl(requestedBaseUrl, apiKey),
|
|
1414
|
+
Effect4.flatMap((baseUrl) => {
|
|
1415
|
+
const url = new URL(`${baseUrl}/api/public/@${handle}/${slug}/export`);
|
|
1416
|
+
if (ruleIds && ruleIds.length > 0) {
|
|
1417
|
+
url.searchParams.set("ruleIds", ruleIds.join(","));
|
|
1418
|
+
}
|
|
1419
|
+
if (version !== void 0) {
|
|
1420
|
+
url.searchParams.set("version", String(version));
|
|
1421
|
+
}
|
|
1422
|
+
return pipe4(
|
|
943
1423
|
Effect4.tryPromise({
|
|
944
|
-
try: () =>
|
|
945
|
-
|
|
1424
|
+
try: () => fetch(url.toString(), {
|
|
1425
|
+
method: "GET",
|
|
1426
|
+
headers: mergeAutomationHeaders()
|
|
1427
|
+
}),
|
|
1428
|
+
catch: (e) => new NetworkError({
|
|
1429
|
+
message: `Failed to connect to ${baseUrl}`,
|
|
1430
|
+
cause: e
|
|
1431
|
+
})
|
|
946
1432
|
}),
|
|
947
1433
|
Effect4.flatMap(
|
|
948
|
-
(
|
|
1434
|
+
(response) => pipe4(
|
|
1435
|
+
readJsonResponse(response),
|
|
1436
|
+
Effect4.flatMap(
|
|
1437
|
+
(json) => handlePublicApiResponse(response, json)
|
|
1438
|
+
)
|
|
1439
|
+
)
|
|
949
1440
|
)
|
|
950
|
-
)
|
|
951
|
-
)
|
|
1441
|
+
);
|
|
1442
|
+
})
|
|
952
1443
|
);
|
|
953
1444
|
};
|
|
954
|
-
fetchPublicMetadataAsync = (handle, slug, serverUrl, version) => Effect4.runPromise(
|
|
955
|
-
|
|
956
|
-
|
|
1445
|
+
fetchPublicMetadataAsync = (handle, slug, serverUrl, version, apiKey) => Effect4.runPromise(
|
|
1446
|
+
fetchPublicMetadata(handle, slug, serverUrl, version, apiKey)
|
|
1447
|
+
);
|
|
1448
|
+
fetchPublicExportAsync = (handle, slug, ruleIds, serverUrl, version, apiKey) => Effect4.runPromise(
|
|
1449
|
+
fetchPublicExport(handle, slug, ruleIds, serverUrl, version, apiKey)
|
|
957
1450
|
);
|
|
958
1451
|
validateApiKey = (apiKey, serverUrl) => pipe4(
|
|
959
1452
|
Effect4.try({
|
|
@@ -975,10 +1468,10 @@ var init_api = __esm({
|
|
|
975
1468
|
url.searchParams.set("profile", "default");
|
|
976
1469
|
const response = await fetch(url.toString(), {
|
|
977
1470
|
method: "GET",
|
|
978
|
-
headers: {
|
|
1471
|
+
headers: mergeAutomationHeaders({
|
|
979
1472
|
Authorization: `Bearer ${apiKey}`,
|
|
980
1473
|
"Content-Type": "application/json"
|
|
981
|
-
}
|
|
1474
|
+
})
|
|
982
1475
|
});
|
|
983
1476
|
return response.status !== 401;
|
|
984
1477
|
},
|
|
@@ -998,7 +1491,7 @@ var init_api = __esm({
|
|
|
998
1491
|
});
|
|
999
1492
|
|
|
1000
1493
|
// src/lib/tui.ts
|
|
1001
|
-
import
|
|
1494
|
+
import process7 from "process";
|
|
1002
1495
|
import {
|
|
1003
1496
|
cancel as clackCancel,
|
|
1004
1497
|
confirm as clackConfirm,
|
|
@@ -1023,19 +1516,19 @@ function spinner() {
|
|
|
1023
1516
|
return {
|
|
1024
1517
|
start: (message) => {
|
|
1025
1518
|
if (message) {
|
|
1026
|
-
|
|
1519
|
+
process7.stdout.write(`${message}
|
|
1027
1520
|
`);
|
|
1028
1521
|
}
|
|
1029
1522
|
},
|
|
1030
1523
|
stop: (message) => {
|
|
1031
1524
|
if (message) {
|
|
1032
|
-
|
|
1525
|
+
process7.stdout.write(`${message}
|
|
1033
1526
|
`);
|
|
1034
1527
|
}
|
|
1035
1528
|
},
|
|
1036
1529
|
message: (message) => {
|
|
1037
1530
|
if (message) {
|
|
1038
|
-
|
|
1531
|
+
process7.stdout.write(`${message}
|
|
1039
1532
|
`);
|
|
1040
1533
|
}
|
|
1041
1534
|
}
|
|
@@ -1045,7 +1538,7 @@ function intro(message) {
|
|
|
1045
1538
|
if (isTTY) {
|
|
1046
1539
|
clackIntro(message);
|
|
1047
1540
|
} else {
|
|
1048
|
-
|
|
1541
|
+
process7.stdout.write(`
|
|
1049
1542
|
${message}
|
|
1050
1543
|
`);
|
|
1051
1544
|
}
|
|
@@ -1054,7 +1547,7 @@ function outro(message) {
|
|
|
1054
1547
|
if (isTTY) {
|
|
1055
1548
|
clackOutro(message);
|
|
1056
1549
|
} else {
|
|
1057
|
-
|
|
1550
|
+
process7.stdout.write(`${message}
|
|
1058
1551
|
|
|
1059
1552
|
`);
|
|
1060
1553
|
}
|
|
@@ -1064,7 +1557,7 @@ var init_tui = __esm({
|
|
|
1064
1557
|
"src/lib/tui.ts"() {
|
|
1065
1558
|
"use strict";
|
|
1066
1559
|
init_esm_shims();
|
|
1067
|
-
isTTY = Boolean(
|
|
1560
|
+
isTTY = Boolean(process7.stdout.isTTY);
|
|
1068
1561
|
cancel = clackCancel;
|
|
1069
1562
|
confirm = clackConfirm;
|
|
1070
1563
|
isCancel = clackIsCancel;
|
|
@@ -1174,10 +1667,10 @@ var scope_exports = {};
|
|
|
1174
1667
|
__export(scope_exports, {
|
|
1175
1668
|
scopeCommand: () => scopeCommand
|
|
1176
1669
|
});
|
|
1177
|
-
import
|
|
1670
|
+
import process9 from "process";
|
|
1178
1671
|
function exitCancelled(message) {
|
|
1179
1672
|
cancel(message);
|
|
1180
|
-
|
|
1673
|
+
process9.exit(0);
|
|
1181
1674
|
}
|
|
1182
1675
|
async function selectTargetFile(options) {
|
|
1183
1676
|
if (options.file) {
|
|
@@ -1529,7 +2022,7 @@ async function scopeCommand(options) {
|
|
|
1529
2022
|
} catch (error) {
|
|
1530
2023
|
loadSpinner.stop("Failed to load scope options");
|
|
1531
2024
|
log.error(error instanceof Error ? error.message : String(error));
|
|
1532
|
-
|
|
2025
|
+
process9.exit(1);
|
|
1533
2026
|
}
|
|
1534
2027
|
}
|
|
1535
2028
|
var init_scope = __esm({
|
|
@@ -1568,7 +2061,7 @@ __export(lockfile_exports, {
|
|
|
1568
2061
|
});
|
|
1569
2062
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
1570
2063
|
import { join as join6 } from "path";
|
|
1571
|
-
import { Data as
|
|
2064
|
+
import { Data as Data5, Effect as Effect6, pipe as pipe6 } from "effect";
|
|
1572
2065
|
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;
|
|
1573
2066
|
var init_lockfile = __esm({
|
|
1574
2067
|
"src/lib/lockfile.ts"() {
|
|
@@ -1578,13 +2071,13 @@ var init_lockfile = __esm({
|
|
|
1578
2071
|
LOCKFILE_VERSION = 1;
|
|
1579
2072
|
MARKETPLACE_KEY_REGEX = /^@([a-z0-9-]+)\/([a-z0-9-]+)@(\d+)$/;
|
|
1580
2073
|
ORG_KEY_REGEX = /^([a-z0-9-]+)\/([a-z0-9-]+)@(\d+)$/;
|
|
1581
|
-
LockfileReadError = class extends
|
|
2074
|
+
LockfileReadError = class extends Data5.TaggedError("LockfileReadError") {
|
|
1582
2075
|
};
|
|
1583
|
-
LockfileWriteError = class extends
|
|
2076
|
+
LockfileWriteError = class extends Data5.TaggedError("LockfileWriteError") {
|
|
1584
2077
|
};
|
|
1585
|
-
LockfileVersionError = class extends
|
|
2078
|
+
LockfileVersionError = class extends Data5.TaggedError("LockfileVersionError") {
|
|
1586
2079
|
};
|
|
1587
|
-
LockfileCorruptError = class extends
|
|
2080
|
+
LockfileCorruptError = class extends Data5.TaggedError("LockfileCorruptError") {
|
|
1588
2081
|
};
|
|
1589
2082
|
getLockfilePath = (dir) => join6(dir, LOCKFILE_FILENAME);
|
|
1590
2083
|
emptyLockfile = () => ({
|
|
@@ -1593,27 +2086,27 @@ var init_lockfile = __esm({
|
|
|
1593
2086
|
});
|
|
1594
2087
|
readLockfile = (dir) => {
|
|
1595
2088
|
const lockfilePath = getLockfilePath(dir);
|
|
1596
|
-
return
|
|
1597
|
-
|
|
2089
|
+
return pipe6(
|
|
2090
|
+
Effect6.tryPromise({
|
|
1598
2091
|
try: () => readFile3(lockfilePath, "utf-8"),
|
|
1599
2092
|
catch: () => new LockfileReadError({ path: lockfilePath, cause: "not found" })
|
|
1600
2093
|
}),
|
|
1601
|
-
|
|
2094
|
+
Effect6.catchTag(
|
|
1602
2095
|
"LockfileReadError",
|
|
1603
|
-
() =>
|
|
2096
|
+
() => Effect6.succeed(null)
|
|
1604
2097
|
),
|
|
1605
|
-
|
|
2098
|
+
Effect6.flatMap((content) => {
|
|
1606
2099
|
if (content === null) {
|
|
1607
|
-
return
|
|
2100
|
+
return Effect6.succeed(null);
|
|
1608
2101
|
}
|
|
1609
|
-
return
|
|
1610
|
-
|
|
2102
|
+
return pipe6(
|
|
2103
|
+
Effect6.try({
|
|
1611
2104
|
try: () => JSON.parse(content),
|
|
1612
2105
|
catch: (cause) => new LockfileCorruptError({ path: lockfilePath, cause })
|
|
1613
2106
|
}),
|
|
1614
|
-
|
|
2107
|
+
Effect6.flatMap((parsed) => {
|
|
1615
2108
|
if (parsed.lockfileVersion !== LOCKFILE_VERSION) {
|
|
1616
|
-
return
|
|
2109
|
+
return Effect6.fail(
|
|
1617
2110
|
new LockfileVersionError({
|
|
1618
2111
|
path: lockfilePath,
|
|
1619
2112
|
expected: LOCKFILE_VERSION,
|
|
@@ -1621,7 +2114,7 @@ var init_lockfile = __esm({
|
|
|
1621
2114
|
})
|
|
1622
2115
|
);
|
|
1623
2116
|
}
|
|
1624
|
-
return
|
|
2117
|
+
return Effect6.succeed(parsed);
|
|
1625
2118
|
})
|
|
1626
2119
|
);
|
|
1627
2120
|
})
|
|
@@ -1629,7 +2122,7 @@ var init_lockfile = __esm({
|
|
|
1629
2122
|
};
|
|
1630
2123
|
writeLockfile = (dir, lockfile) => {
|
|
1631
2124
|
const lockfilePath = getLockfilePath(dir);
|
|
1632
|
-
return
|
|
2125
|
+
return Effect6.tryPromise({
|
|
1633
2126
|
try: () => writeFile4(
|
|
1634
2127
|
lockfilePath,
|
|
1635
2128
|
`${JSON.stringify(lockfile, null, 2)}
|
|
@@ -1646,26 +2139,26 @@ var init_lockfile = __esm({
|
|
|
1646
2139
|
}
|
|
1647
2140
|
return entry;
|
|
1648
2141
|
};
|
|
1649
|
-
upsertLockfileEntry = (dir, key, entry) =>
|
|
2142
|
+
upsertLockfileEntry = (dir, key, entry) => pipe6(
|
|
1650
2143
|
readLockfile(dir),
|
|
1651
|
-
|
|
1652
|
-
|
|
2144
|
+
Effect6.map((existing) => existing ?? emptyLockfile()),
|
|
2145
|
+
Effect6.map((lockfile) => ({
|
|
1653
2146
|
...lockfile,
|
|
1654
2147
|
resolved: {
|
|
1655
2148
|
...lockfile.resolved,
|
|
1656
2149
|
[key]: entry
|
|
1657
2150
|
}
|
|
1658
2151
|
})),
|
|
1659
|
-
|
|
2152
|
+
Effect6.flatMap((lockfile) => writeLockfile(dir, lockfile))
|
|
1660
2153
|
);
|
|
1661
|
-
removeLockfileEntry = (dir, key) =>
|
|
2154
|
+
removeLockfileEntry = (dir, key) => pipe6(
|
|
1662
2155
|
readLockfile(dir),
|
|
1663
|
-
|
|
1664
|
-
|
|
2156
|
+
Effect6.map((existing) => existing ?? emptyLockfile()),
|
|
2157
|
+
Effect6.map((lockfile) => {
|
|
1665
2158
|
const { [key]: _removed, ...rest } = lockfile.resolved;
|
|
1666
2159
|
return { ...lockfile, resolved: rest };
|
|
1667
2160
|
}),
|
|
1668
|
-
|
|
2161
|
+
Effect6.flatMap((lockfile) => writeLockfile(dir, lockfile))
|
|
1669
2162
|
);
|
|
1670
2163
|
buildLockfileKey = (source, handle, slug, version) => {
|
|
1671
2164
|
const prefix = source === "marketplace" ? `@${handle}` : handle;
|
|
@@ -1692,10 +2185,10 @@ var init_lockfile = __esm({
|
|
|
1692
2185
|
}
|
|
1693
2186
|
return null;
|
|
1694
2187
|
};
|
|
1695
|
-
readLockfileAsync = (dir) =>
|
|
1696
|
-
writeLockfileAsync = (dir, lockfile) =>
|
|
1697
|
-
upsertLockfileEntryAsync = (dir, key, entry) =>
|
|
1698
|
-
removeLockfileEntryAsync = (dir, key) =>
|
|
2188
|
+
readLockfileAsync = (dir) => Effect6.runPromise(readLockfile(dir));
|
|
2189
|
+
writeLockfileAsync = (dir, lockfile) => Effect6.runPromise(writeLockfile(dir, lockfile));
|
|
2190
|
+
upsertLockfileEntryAsync = (dir, key, entry) => Effect6.runPromise(upsertLockfileEntry(dir, key, entry));
|
|
2191
|
+
removeLockfileEntryAsync = (dir, key) => Effect6.runPromise(removeLockfileEntry(dir, key));
|
|
1699
2192
|
}
|
|
1700
2193
|
});
|
|
1701
2194
|
|
|
@@ -2271,15 +2764,262 @@ var resolveHookConfigPath = (agent, options) => {
|
|
|
2271
2764
|
if (options.global) {
|
|
2272
2765
|
return agent.hookGlobalConfigPath;
|
|
2273
2766
|
}
|
|
2274
|
-
if (!agent.hookProjectConfigPath) {
|
|
2275
|
-
return void 0;
|
|
2767
|
+
if (!agent.hookProjectConfigPath) {
|
|
2768
|
+
return void 0;
|
|
2769
|
+
}
|
|
2770
|
+
const cwd = options.projectRoot ?? process2.cwd();
|
|
2771
|
+
return join(cwd, agent.hookProjectConfigPath);
|
|
2772
|
+
};
|
|
2773
|
+
|
|
2774
|
+
// src/commands/agents.ts
|
|
2775
|
+
init_api();
|
|
2776
|
+
|
|
2777
|
+
// src/lib/command-output.ts
|
|
2778
|
+
init_esm_shims();
|
|
2779
|
+
init_api();
|
|
2780
|
+
import process8 from "process";
|
|
2781
|
+
|
|
2782
|
+
// src/lib/marketplace-api.ts
|
|
2783
|
+
init_esm_shims();
|
|
2784
|
+
init_automation_headers();
|
|
2785
|
+
init_config();
|
|
2786
|
+
init_device_auth();
|
|
2787
|
+
import { Data as Data4, Effect as Effect5, pipe as pipe5 } from "effect";
|
|
2788
|
+
var TRAILING_SLASH_REGEX2 = /\/$/;
|
|
2789
|
+
var SESSION_TOKEN_PREFIX2 = "brs_";
|
|
2790
|
+
var MarketplaceApiError = class extends Data4.TaggedError("MarketplaceApiError") {
|
|
2791
|
+
};
|
|
2792
|
+
var isLocalHost2 = (hostname2) => hostname2 === "localhost" || hostname2 === "127.0.0.1" || hostname2 === "::1";
|
|
2793
|
+
var isConvexSiteHost2 = (hostname2) => hostname2.endsWith(".convex.site");
|
|
2794
|
+
var isSessionApiServerUrl2 = (serverUrl) => {
|
|
2795
|
+
try {
|
|
2796
|
+
const hostname2 = new URL(serverUrl).hostname;
|
|
2797
|
+
return isConvexSiteHost2(hostname2) || isLocalHost2(hostname2);
|
|
2798
|
+
} catch {
|
|
2799
|
+
return false;
|
|
2800
|
+
}
|
|
2801
|
+
};
|
|
2802
|
+
var resolveApiKey2 = (provided) => {
|
|
2803
|
+
if (provided) {
|
|
2804
|
+
return Effect5.succeed(provided);
|
|
2805
|
+
}
|
|
2806
|
+
return pipe5(
|
|
2807
|
+
Effect5.tryPromise({
|
|
2808
|
+
try: () => getApiKeyAsync(),
|
|
2809
|
+
catch: () => new MarketplaceApiError({
|
|
2810
|
+
message: "Failed to load API key",
|
|
2811
|
+
status: 500,
|
|
2812
|
+
code: "CONFIG_ERROR"
|
|
2813
|
+
})
|
|
2814
|
+
}),
|
|
2815
|
+
Effect5.flatMap(
|
|
2816
|
+
(token) => token ? Effect5.succeed(token) : Effect5.fail(
|
|
2817
|
+
new MarketplaceApiError({
|
|
2818
|
+
message: "Not signed in. Run 'braid auth'.",
|
|
2819
|
+
status: 401,
|
|
2820
|
+
code: "AUTH_REQUIRED"
|
|
2821
|
+
})
|
|
2822
|
+
)
|
|
2823
|
+
)
|
|
2824
|
+
);
|
|
2825
|
+
};
|
|
2826
|
+
var resolveServer = (provided) => {
|
|
2827
|
+
if (provided) {
|
|
2828
|
+
return Effect5.succeed(provided.replace(TRAILING_SLASH_REGEX2, ""));
|
|
2829
|
+
}
|
|
2830
|
+
return pipe5(
|
|
2831
|
+
Effect5.tryPromise({
|
|
2832
|
+
try: () => getServerUrlAsync(),
|
|
2833
|
+
catch: () => new MarketplaceApiError({
|
|
2834
|
+
message: "Failed to load server URL",
|
|
2835
|
+
status: 500,
|
|
2836
|
+
code: "CONFIG_ERROR"
|
|
2837
|
+
})
|
|
2838
|
+
}),
|
|
2839
|
+
Effect5.map((server) => server.replace(TRAILING_SLASH_REGEX2, ""))
|
|
2840
|
+
);
|
|
2841
|
+
};
|
|
2842
|
+
var resolveRequestServer = (server, apiKey) => {
|
|
2843
|
+
if (!apiKey.startsWith(SESSION_TOKEN_PREFIX2) || isSessionApiServerUrl2(server)) {
|
|
2844
|
+
return Effect5.succeed(server);
|
|
2845
|
+
}
|
|
2846
|
+
return Effect5.tryPromise({
|
|
2847
|
+
try: async () => {
|
|
2848
|
+
const authConfig = await fetchAuthConfig(server);
|
|
2849
|
+
return authConfig.convexSiteUrl.replace(TRAILING_SLASH_REGEX2, "");
|
|
2850
|
+
},
|
|
2851
|
+
catch: () => new MarketplaceApiError({
|
|
2852
|
+
message: `Failed to resolve marketplace API server for ${server}`,
|
|
2853
|
+
status: 500,
|
|
2854
|
+
code: "CONFIG_ERROR"
|
|
2855
|
+
})
|
|
2856
|
+
});
|
|
2857
|
+
};
|
|
2858
|
+
var requestJson = (url, options, requestOptions = {}) => pipe5(
|
|
2859
|
+
Effect5.tryPromise({
|
|
2860
|
+
try: () => fetch(url, options),
|
|
2861
|
+
catch: () => new MarketplaceApiError({
|
|
2862
|
+
message: "Network error",
|
|
2863
|
+
status: 503,
|
|
2864
|
+
code: "NETWORK_ERROR"
|
|
2865
|
+
})
|
|
2866
|
+
}),
|
|
2867
|
+
Effect5.flatMap(
|
|
2868
|
+
(response) => Effect5.tryPromise({
|
|
2869
|
+
try: async () => {
|
|
2870
|
+
const payload = await response.json().catch(() => null);
|
|
2871
|
+
if (!response.ok) {
|
|
2872
|
+
const normalizedMessage = requestOptions.normalizeErrorMessage?.({
|
|
2873
|
+
payload,
|
|
2874
|
+
response,
|
|
2875
|
+
url
|
|
2876
|
+
});
|
|
2877
|
+
throw new MarketplaceApiError({
|
|
2878
|
+
message: normalizedMessage ?? (response.status === 404 ? requestOptions.notFoundMessage : void 0) ?? payload?.error ?? payload?.message ?? `Request failed (HTTP ${response.status} from ${new URL(url).origin})`,
|
|
2879
|
+
status: response.status,
|
|
2880
|
+
code: payload?.code ?? "REQUEST_ERROR"
|
|
2881
|
+
});
|
|
2882
|
+
}
|
|
2883
|
+
return payload;
|
|
2884
|
+
},
|
|
2885
|
+
catch: (error) => error instanceof MarketplaceApiError ? error : new MarketplaceApiError({
|
|
2886
|
+
message: "Invalid response",
|
|
2887
|
+
status: 500,
|
|
2888
|
+
code: "PARSE_ERROR"
|
|
2889
|
+
})
|
|
2890
|
+
})
|
|
2891
|
+
)
|
|
2892
|
+
);
|
|
2893
|
+
var fetchMarketplaceLibrary = (options) => pipe5(
|
|
2894
|
+
Effect5.all({
|
|
2895
|
+
server: resolveServer(options.server),
|
|
2896
|
+
apiKey: resolveApiKey2(options.apiKey)
|
|
2897
|
+
}),
|
|
2898
|
+
Effect5.flatMap(
|
|
2899
|
+
({ server, apiKey }) => Effect5.all({
|
|
2900
|
+
apiKey: Effect5.succeed(apiKey),
|
|
2901
|
+
server: resolveRequestServer(server, apiKey)
|
|
2902
|
+
})
|
|
2903
|
+
),
|
|
2904
|
+
Effect5.flatMap(
|
|
2905
|
+
({ server, apiKey }) => requestJson(
|
|
2906
|
+
`${server}/api/marketplace/library`,
|
|
2907
|
+
{
|
|
2908
|
+
method: "GET",
|
|
2909
|
+
headers: mergeAutomationHeaders({
|
|
2910
|
+
Authorization: `Bearer ${apiKey}`
|
|
2911
|
+
})
|
|
2912
|
+
}
|
|
2913
|
+
)
|
|
2914
|
+
),
|
|
2915
|
+
Effect5.map((response) => response.items)
|
|
2916
|
+
);
|
|
2917
|
+
var fetchMarketplaceInstallManifest = (slug, options) => pipe5(
|
|
2918
|
+
Effect5.all({
|
|
2919
|
+
server: resolveServer(options.server),
|
|
2920
|
+
apiKey: resolveApiKey2(options.apiKey)
|
|
2921
|
+
}),
|
|
2922
|
+
Effect5.flatMap(
|
|
2923
|
+
({ server, apiKey }) => Effect5.all({
|
|
2924
|
+
apiKey: Effect5.succeed(apiKey),
|
|
2925
|
+
server: resolveRequestServer(server, apiKey)
|
|
2926
|
+
})
|
|
2927
|
+
),
|
|
2928
|
+
Effect5.flatMap(
|
|
2929
|
+
({ server, apiKey }) => requestJson(
|
|
2930
|
+
`${server}/api/marketplace/install-manifest/${encodeURIComponent(slug)}`,
|
|
2931
|
+
{
|
|
2932
|
+
method: "GET",
|
|
2933
|
+
headers: mergeAutomationHeaders({
|
|
2934
|
+
Authorization: `Bearer ${apiKey}`
|
|
2935
|
+
})
|
|
2936
|
+
},
|
|
2937
|
+
{
|
|
2938
|
+
normalizeErrorMessage: ({ payload }) => payload?.error === "Not entitled" ? "Pack not found or no longer available in your library." : void 0,
|
|
2939
|
+
notFoundMessage: "Pack not found or no longer available in your library."
|
|
2940
|
+
}
|
|
2941
|
+
)
|
|
2942
|
+
)
|
|
2943
|
+
);
|
|
2944
|
+
var fetchMarketplaceLibraryAsync = (options) => Effect5.runPromise(fetchMarketplaceLibrary(options));
|
|
2945
|
+
var fetchMarketplaceInstallManifestAsync = (slug, options) => Effect5.runPromise(fetchMarketplaceInstallManifest(slug, options));
|
|
2946
|
+
|
|
2947
|
+
// src/lib/command-output.ts
|
|
2948
|
+
init_tui();
|
|
2949
|
+
var CommandValidationError = class extends Error {
|
|
2950
|
+
code = "CLI_VALIDATION_ERROR";
|
|
2951
|
+
constructor(message) {
|
|
2952
|
+
super(message);
|
|
2953
|
+
this.name = "CommandValidationError";
|
|
2954
|
+
}
|
|
2955
|
+
};
|
|
2956
|
+
var writeJson = (value) => {
|
|
2957
|
+
process8.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
2958
|
+
`);
|
|
2959
|
+
};
|
|
2960
|
+
var toJsonErrorOutput = (error) => {
|
|
2961
|
+
if (error instanceof ApiError) {
|
|
2962
|
+
return {
|
|
2963
|
+
error: error.message,
|
|
2964
|
+
code: error.code,
|
|
2965
|
+
status: error.status
|
|
2966
|
+
};
|
|
2967
|
+
}
|
|
2968
|
+
if (error instanceof AuthenticationError) {
|
|
2969
|
+
return {
|
|
2970
|
+
error: error.message,
|
|
2971
|
+
code: "AUTH_REQUIRED",
|
|
2972
|
+
status: 401
|
|
2973
|
+
};
|
|
2974
|
+
}
|
|
2975
|
+
if (error instanceof NetworkError) {
|
|
2976
|
+
return {
|
|
2977
|
+
error: error.message,
|
|
2978
|
+
code: "NETWORK_ERROR",
|
|
2979
|
+
status: 503
|
|
2980
|
+
};
|
|
2981
|
+
}
|
|
2982
|
+
if (error instanceof MarketplaceApiError) {
|
|
2983
|
+
return {
|
|
2984
|
+
error: error.message,
|
|
2985
|
+
code: error.code,
|
|
2986
|
+
status: error.status
|
|
2987
|
+
};
|
|
2988
|
+
}
|
|
2989
|
+
if (error instanceof CommandValidationError || error instanceof SyntaxError) {
|
|
2990
|
+
return {
|
|
2991
|
+
error: error.message,
|
|
2992
|
+
code: "CLI_VALIDATION_ERROR",
|
|
2993
|
+
status: 400
|
|
2994
|
+
};
|
|
2995
|
+
}
|
|
2996
|
+
if (error instanceof Error) {
|
|
2997
|
+
return {
|
|
2998
|
+
error: error.message,
|
|
2999
|
+
code: "CLI_ERROR",
|
|
3000
|
+
status: 500
|
|
3001
|
+
};
|
|
3002
|
+
}
|
|
3003
|
+
return {
|
|
3004
|
+
error: String(error),
|
|
3005
|
+
code: "CLI_ERROR",
|
|
3006
|
+
status: 500
|
|
3007
|
+
};
|
|
3008
|
+
};
|
|
3009
|
+
var fail = (message) => {
|
|
3010
|
+
throw new CommandValidationError(message);
|
|
3011
|
+
};
|
|
3012
|
+
var exitCommandError = (error, options) => {
|
|
3013
|
+
if (options?.json) {
|
|
3014
|
+
writeJson(toJsonErrorOutput(error));
|
|
3015
|
+
process8.exit(1);
|
|
2276
3016
|
}
|
|
2277
|
-
const
|
|
2278
|
-
|
|
3017
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3018
|
+
log.error(message);
|
|
3019
|
+
process8.exit(1);
|
|
2279
3020
|
};
|
|
2280
3021
|
|
|
2281
3022
|
// src/commands/agents.ts
|
|
2282
|
-
init_api();
|
|
2283
3023
|
init_tui();
|
|
2284
3024
|
var parseCsv = (input) => {
|
|
2285
3025
|
if (!input) {
|
|
@@ -2288,18 +3028,6 @@ var parseCsv = (input) => {
|
|
|
2288
3028
|
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
2289
3029
|
return values.length > 0 ? values : void 0;
|
|
2290
3030
|
};
|
|
2291
|
-
var writeJson = (value) => {
|
|
2292
|
-
process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
2293
|
-
`);
|
|
2294
|
-
};
|
|
2295
|
-
var fail = (message) => {
|
|
2296
|
-
throw new Error(message);
|
|
2297
|
-
};
|
|
2298
|
-
var exitWithError = (error) => {
|
|
2299
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
2300
|
-
log.error(message);
|
|
2301
|
-
process.exit(1);
|
|
2302
|
-
};
|
|
2303
3031
|
var run = (command, args, options) => {
|
|
2304
3032
|
const apiOptions = {
|
|
2305
3033
|
...options.server ? { serverUrl: options.server } : {},
|
|
@@ -2403,7 +3131,7 @@ async function agentsListCommand(options) {
|
|
|
2403
3131
|
log.success("sub-agents list completed");
|
|
2404
3132
|
writeJson(result);
|
|
2405
3133
|
} catch (error) {
|
|
2406
|
-
|
|
3134
|
+
exitCommandError(error, { json: options.json });
|
|
2407
3135
|
}
|
|
2408
3136
|
}
|
|
2409
3137
|
async function agentsGetCommand(options) {
|
|
@@ -2417,7 +3145,7 @@ async function agentsGetCommand(options) {
|
|
|
2417
3145
|
log.success("sub-agents get completed");
|
|
2418
3146
|
writeJson(result);
|
|
2419
3147
|
} catch (error) {
|
|
2420
|
-
|
|
3148
|
+
exitCommandError(error, { json: options.json });
|
|
2421
3149
|
}
|
|
2422
3150
|
}
|
|
2423
3151
|
async function agentsCreateCommand(options) {
|
|
@@ -2445,7 +3173,7 @@ async function agentsCreateCommand(options) {
|
|
|
2445
3173
|
}
|
|
2446
3174
|
log.success("sub-agents create completed");
|
|
2447
3175
|
} catch (error) {
|
|
2448
|
-
|
|
3176
|
+
exitCommandError(error, { json: options.json });
|
|
2449
3177
|
}
|
|
2450
3178
|
}
|
|
2451
3179
|
async function agentsUpdateCommand(options) {
|
|
@@ -2470,7 +3198,7 @@ async function agentsUpdateCommand(options) {
|
|
|
2470
3198
|
}
|
|
2471
3199
|
log.success("sub-agents update completed");
|
|
2472
3200
|
} catch (error) {
|
|
2473
|
-
|
|
3201
|
+
exitCommandError(error, { json: options.json });
|
|
2474
3202
|
}
|
|
2475
3203
|
}
|
|
2476
3204
|
async function agentsRemoveCommand(options) {
|
|
@@ -2486,7 +3214,7 @@ async function agentsRemoveCommand(options) {
|
|
|
2486
3214
|
}
|
|
2487
3215
|
log.success("sub-agents remove completed");
|
|
2488
3216
|
} catch (error) {
|
|
2489
|
-
|
|
3217
|
+
exitCommandError(error, { json: options.json });
|
|
2490
3218
|
}
|
|
2491
3219
|
}
|
|
2492
3220
|
async function agentsInstallCommand(options) {
|
|
@@ -2511,365 +3239,57 @@ async function agentsInstallCommand(options) {
|
|
|
2511
3239
|
target,
|
|
2512
3240
|
[spec],
|
|
2513
3241
|
installPath
|
|
2514
|
-
);
|
|
2515
|
-
summary.push({
|
|
2516
|
-
platform: target.id,
|
|
2517
|
-
installPath,
|
|
2518
|
-
written: result.written.length,
|
|
2519
|
-
warnings: result.warnings,
|
|
2520
|
-
errors: result.errors
|
|
2521
|
-
});
|
|
2522
|
-
}
|
|
2523
|
-
if (options.json) {
|
|
2524
|
-
writeJson(summary);
|
|
2525
|
-
return;
|
|
2526
|
-
}
|
|
2527
|
-
for (const item of summary) {
|
|
2528
|
-
log.info(
|
|
2529
|
-
`${item.platform}: ${item.written} file(s) written${item.installPath ? ` to ${item.installPath}` : ""}`
|
|
2530
|
-
);
|
|
2531
|
-
for (const warning of item.warnings) {
|
|
2532
|
-
log.warn(` warning: ${warning}`);
|
|
2533
|
-
}
|
|
2534
|
-
for (const error of item.errors) {
|
|
2535
|
-
log.error(` error (${error.agent}): ${error.error}`);
|
|
2536
|
-
}
|
|
2537
|
-
}
|
|
2538
|
-
log.success("sub-agents install completed");
|
|
2539
|
-
} catch (error) {
|
|
2540
|
-
exitWithError(error);
|
|
2541
|
-
}
|
|
2542
|
-
}
|
|
2543
|
-
|
|
2544
|
-
// src/commands/auth.ts
|
|
2545
|
-
init_esm_shims();
|
|
2546
|
-
init_api();
|
|
2547
|
-
init_config();
|
|
2548
|
-
import process8 from "process";
|
|
2549
|
-
|
|
2550
|
-
// src/lib/device-auth.ts
|
|
2551
|
-
init_esm_shims();
|
|
2552
|
-
init_braid_workspace();
|
|
2553
|
-
import { execFile } from "child_process";
|
|
2554
|
-
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
2555
|
-
import { hostname, platform } from "os";
|
|
2556
|
-
import { join as join4 } from "path";
|
|
2557
|
-
import process6 from "process";
|
|
2558
|
-
var TRAILING_SLASHES2 = /\/+$/;
|
|
2559
|
-
var LEGACY_BRAID_AUTH_HOSTS = /* @__PURE__ */ new Set([
|
|
2560
|
-
"api.braid.cloud",
|
|
2561
|
-
"braid.cloud",
|
|
2562
|
-
"www.braid.cloud"
|
|
2563
|
-
]);
|
|
2564
|
-
var BRAID_APP_HOST = "app.braid.cloud";
|
|
2565
|
-
var DEFAULT_BRAID_AUTH_HOSTS = /* @__PURE__ */ new Set([
|
|
2566
|
-
...LEGACY_BRAID_AUTH_HOSTS,
|
|
2567
|
-
BRAID_APP_HOST
|
|
2568
|
-
]);
|
|
2569
|
-
var LOOPBACK_HOSTS2 = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "localhost"]);
|
|
2570
|
-
var LOCAL_AUTH_ENV_FILES = [
|
|
2571
|
-
["apps", "web", ".env.local"],
|
|
2572
|
-
["apps", "convex", ".env.local"]
|
|
2573
|
-
];
|
|
2574
|
-
var LOCAL_AUTH_ENV_KEYS = ["APP_URL", "SITE_URL"];
|
|
2575
|
-
var NEWLINE_REGEX2 = /\r?\n/;
|
|
2576
|
-
var DeviceAuthTimeoutError = class extends Error {
|
|
2577
|
-
constructor() {
|
|
2578
|
-
super("Device authorization timed out");
|
|
2579
|
-
this.name = "DeviceAuthTimeoutError";
|
|
2580
|
-
}
|
|
2581
|
-
};
|
|
2582
|
-
var DeviceAuthDeniedError = class extends Error {
|
|
2583
|
-
constructor() {
|
|
2584
|
-
super("Device authorization was denied");
|
|
2585
|
-
this.name = "DeviceAuthDeniedError";
|
|
2586
|
-
}
|
|
2587
|
-
};
|
|
2588
|
-
var DeviceAuthExpiredError = class extends Error {
|
|
2589
|
-
constructor() {
|
|
2590
|
-
super("Device authorization code has expired");
|
|
2591
|
-
this.name = "DeviceAuthExpiredError";
|
|
2592
|
-
}
|
|
2593
|
-
};
|
|
2594
|
-
var sleep = (ms) => new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
2595
|
-
var normalizeBaseUrl2 = (rawUrl) => {
|
|
2596
|
-
const trimmed = rawUrl.replace(TRAILING_SLASHES2, "");
|
|
2597
|
-
try {
|
|
2598
|
-
const url = new URL(trimmed);
|
|
2599
|
-
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
2600
|
-
} catch {
|
|
2601
|
-
return trimmed;
|
|
2602
|
-
}
|
|
2603
|
-
};
|
|
2604
|
-
var normalizeLoopbackBaseUrl = (rawUrl) => {
|
|
2605
|
-
const normalized = normalizeBaseUrl2(rawUrl);
|
|
2606
|
-
try {
|
|
2607
|
-
const url = new URL(normalized);
|
|
2608
|
-
if (isLoopbackHost(url.hostname)) {
|
|
2609
|
-
url.hostname = "localhost";
|
|
2610
|
-
}
|
|
2611
|
-
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
2612
|
-
} catch {
|
|
2613
|
-
return normalized;
|
|
2614
|
-
}
|
|
2615
|
-
};
|
|
2616
|
-
var isLoopbackHost = (hostname2) => LOOPBACK_HOSTS2.has(hostname2);
|
|
2617
|
-
var isLoopbackUrl = (rawUrl) => {
|
|
2618
|
-
try {
|
|
2619
|
-
return isLoopbackHost(new URL(rawUrl).hostname);
|
|
2620
|
-
} catch {
|
|
2621
|
-
return false;
|
|
2622
|
-
}
|
|
2623
|
-
};
|
|
2624
|
-
var stripQuotes2 = (value) => {
|
|
2625
|
-
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
2626
|
-
return value.slice(1, -1);
|
|
2627
|
-
}
|
|
2628
|
-
return value;
|
|
2629
|
-
};
|
|
2630
|
-
var parseDotenv2 = (content) => {
|
|
2631
|
-
const result = {};
|
|
2632
|
-
for (const rawLine of content.split(NEWLINE_REGEX2)) {
|
|
2633
|
-
const line = rawLine.trim();
|
|
2634
|
-
if (!line || line.startsWith("#")) {
|
|
2635
|
-
continue;
|
|
2636
|
-
}
|
|
2637
|
-
const separatorIndex = line.indexOf("=");
|
|
2638
|
-
if (separatorIndex <= 0) {
|
|
2639
|
-
continue;
|
|
2640
|
-
}
|
|
2641
|
-
const key = line.slice(0, separatorIndex).trim();
|
|
2642
|
-
const value = line.slice(separatorIndex + 1).trim();
|
|
2643
|
-
result[key] = stripQuotes2(value);
|
|
2644
|
-
}
|
|
2645
|
-
return result;
|
|
2646
|
-
};
|
|
2647
|
-
var resolveLocalAuthWebBaseUrlFromEnv = (env) => {
|
|
2648
|
-
for (const key of LOCAL_AUTH_ENV_KEYS) {
|
|
2649
|
-
const value = env[key];
|
|
2650
|
-
if (value && isLoopbackUrl(value)) {
|
|
2651
|
-
return normalizeLoopbackBaseUrl(value);
|
|
2652
|
-
}
|
|
2653
|
-
}
|
|
2654
|
-
return void 0;
|
|
2655
|
-
};
|
|
2656
|
-
var resolveLocalAuthWebBaseUrlFromFiles = () => {
|
|
2657
|
-
const workspaceRoot = findBraidWorkspaceRoot();
|
|
2658
|
-
if (!workspaceRoot) {
|
|
2659
|
-
return void 0;
|
|
2660
|
-
}
|
|
2661
|
-
for (const envFile of LOCAL_AUTH_ENV_FILES) {
|
|
2662
|
-
const envPath = join4(workspaceRoot, ...envFile);
|
|
2663
|
-
if (!existsSync3(envPath)) {
|
|
2664
|
-
continue;
|
|
2665
|
-
}
|
|
2666
|
-
const localAppUrl = resolveLocalAuthWebBaseUrlFromEnv(
|
|
2667
|
-
parseDotenv2(readFileSync3(envPath, "utf8"))
|
|
2668
|
-
);
|
|
2669
|
-
if (localAppUrl) {
|
|
2670
|
-
return localAppUrl;
|
|
2671
|
-
}
|
|
2672
|
-
}
|
|
2673
|
-
return void 0;
|
|
2674
|
-
};
|
|
2675
|
-
var resolveLocalAuthWebBaseUrl = () => resolveLocalAuthWebBaseUrlFromEnv(process6.env) ?? resolveLocalAuthWebBaseUrlFromFiles();
|
|
2676
|
-
var normalizeServerBaseUrl = (serverUrl) => {
|
|
2677
|
-
const trimmed = normalizeBaseUrl2(serverUrl);
|
|
2678
|
-
try {
|
|
2679
|
-
const url = new URL(trimmed);
|
|
2680
|
-
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
2681
|
-
} catch {
|
|
2682
|
-
return trimmed;
|
|
2683
|
-
}
|
|
2684
|
-
};
|
|
2685
|
-
var resolveCanonicalAuthWebBaseUrl = (serverUrl) => {
|
|
2686
|
-
const normalized = normalizeServerBaseUrl(serverUrl);
|
|
2687
|
-
try {
|
|
2688
|
-
const url = new URL(normalized);
|
|
2689
|
-
if (LEGACY_BRAID_AUTH_HOSTS.has(url.hostname)) {
|
|
2690
|
-
url.hostname = BRAID_APP_HOST;
|
|
2691
|
-
url.pathname = "/";
|
|
2692
|
-
}
|
|
2693
|
-
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
2694
|
-
} catch {
|
|
2695
|
-
return normalized;
|
|
2696
|
-
}
|
|
2697
|
-
};
|
|
2698
|
-
var isHostedBraidAuthServer = (serverUrl) => {
|
|
2699
|
-
try {
|
|
2700
|
-
return DEFAULT_BRAID_AUTH_HOSTS.has(
|
|
2701
|
-
new URL(normalizeServerBaseUrl(serverUrl)).hostname
|
|
2702
|
-
);
|
|
2703
|
-
} catch {
|
|
2704
|
-
return false;
|
|
2705
|
-
}
|
|
2706
|
-
};
|
|
2707
|
-
function resolveAuthWebBaseUrl(serverUrl) {
|
|
2708
|
-
const canonicalBaseUrl = resolveCanonicalAuthWebBaseUrl(serverUrl);
|
|
2709
|
-
try {
|
|
2710
|
-
const url = new URL(canonicalBaseUrl);
|
|
2711
|
-
const localAuthBaseUrl = resolveLocalAuthWebBaseUrl();
|
|
2712
|
-
if (localAuthBaseUrl && (DEFAULT_BRAID_AUTH_HOSTS.has(url.hostname) || isLoopbackHost(url.hostname))) {
|
|
2713
|
-
return localAuthBaseUrl;
|
|
2714
|
-
}
|
|
2715
|
-
return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
2716
|
-
} catch {
|
|
2717
|
-
return canonicalBaseUrl;
|
|
2718
|
-
}
|
|
2719
|
-
}
|
|
2720
|
-
function buildAuthVerificationUrlFromBaseUrl(authBaseUrl, userCode) {
|
|
2721
|
-
return `${authBaseUrl.replace(TRAILING_SLASHES2, "")}/cli/authorize?user_code=${encodeURIComponent(userCode)}`;
|
|
2722
|
-
}
|
|
2723
|
-
async function fetchAuthConfigFromBaseUrl(authBaseUrl) {
|
|
2724
|
-
const response = await fetch(`${authBaseUrl}/api/cli/auth-config`);
|
|
2725
|
-
if (!response.ok) {
|
|
2726
|
-
const body = await response.text();
|
|
2727
|
-
throw new Error(
|
|
2728
|
-
`Failed to fetch auth config (${response.status}): ${body}`
|
|
2729
|
-
);
|
|
2730
|
-
}
|
|
2731
|
-
return {
|
|
2732
|
-
...await response.json(),
|
|
2733
|
-
verificationBaseUrl: authBaseUrl
|
|
2734
|
-
};
|
|
2735
|
-
}
|
|
2736
|
-
async function fetchAuthConfig(serverUrl) {
|
|
2737
|
-
const authBaseUrl = resolveAuthWebBaseUrl(serverUrl).replace(
|
|
2738
|
-
TRAILING_SLASHES2,
|
|
2739
|
-
""
|
|
2740
|
-
);
|
|
2741
|
-
const canonicalAuthBaseUrl = resolveCanonicalAuthWebBaseUrl(
|
|
2742
|
-
serverUrl
|
|
2743
|
-
).replace(TRAILING_SLASHES2, "");
|
|
2744
|
-
try {
|
|
2745
|
-
return await fetchAuthConfigFromBaseUrl(authBaseUrl);
|
|
2746
|
-
} catch (error) {
|
|
2747
|
-
if (authBaseUrl !== canonicalAuthBaseUrl && isHostedBraidAuthServer(serverUrl)) {
|
|
2748
|
-
return fetchAuthConfigFromBaseUrl(canonicalAuthBaseUrl);
|
|
2749
|
-
}
|
|
2750
|
-
throw error;
|
|
2751
|
-
}
|
|
2752
|
-
}
|
|
2753
|
-
async function initiateDeviceAuth(convexSiteUrl, deviceInfo) {
|
|
2754
|
-
const url = `${convexSiteUrl.replace(TRAILING_SLASHES2, "")}/api/cli/device/authorize`;
|
|
2755
|
-
const response = await fetch(url, {
|
|
2756
|
-
method: "POST",
|
|
2757
|
-
headers: { "Content-Type": "application/json" },
|
|
2758
|
-
body: JSON.stringify(deviceInfo)
|
|
2759
|
-
});
|
|
2760
|
-
if (!response.ok) {
|
|
2761
|
-
const body = await response.text();
|
|
2762
|
-
throw new Error(
|
|
2763
|
-
`Failed to initiate device authorization (${response.status}): ${body}`
|
|
2764
|
-
);
|
|
2765
|
-
}
|
|
2766
|
-
return response.json();
|
|
2767
|
-
}
|
|
2768
|
-
async function pollForSession(convexSiteUrl, deviceCode, interval, expiresIn, timeoutSeconds) {
|
|
2769
|
-
const tokenUrl = `${convexSiteUrl.replace(TRAILING_SLASHES2, "")}/api/cli/device/token`;
|
|
2770
|
-
const deadline = Date.now() + Math.min(expiresIn, timeoutSeconds) * 1e3;
|
|
2771
|
-
let currentInterval = interval;
|
|
2772
|
-
while (Date.now() < deadline) {
|
|
2773
|
-
await sleep(currentInterval * 1e3);
|
|
2774
|
-
const response = await fetch(tokenUrl, {
|
|
2775
|
-
method: "POST",
|
|
2776
|
-
headers: { "Content-Type": "application/json" },
|
|
2777
|
-
body: JSON.stringify({ device_code: deviceCode })
|
|
2778
|
-
});
|
|
2779
|
-
if (response.ok) {
|
|
2780
|
-
const result = await response.json();
|
|
2781
|
-
return {
|
|
2782
|
-
sessionToken: result.session_token,
|
|
2783
|
-
expiresAt: result.expires_at,
|
|
2784
|
-
user: result.user
|
|
2785
|
-
};
|
|
2786
|
-
}
|
|
2787
|
-
let errorCode;
|
|
2788
|
-
try {
|
|
2789
|
-
const errorBody = await response.json();
|
|
2790
|
-
errorCode = errorBody.error;
|
|
2791
|
-
} catch {
|
|
2792
|
-
throw new Error(`Device auth polling error: HTTP ${response.status}`);
|
|
2793
|
-
}
|
|
2794
|
-
if (errorCode === "authorization_pending") {
|
|
2795
|
-
continue;
|
|
2796
|
-
}
|
|
2797
|
-
if (errorCode === "slow_down") {
|
|
2798
|
-
currentInterval += 5;
|
|
2799
|
-
continue;
|
|
2800
|
-
}
|
|
2801
|
-
if (errorCode === "expired_token") {
|
|
2802
|
-
throw new DeviceAuthExpiredError();
|
|
2803
|
-
}
|
|
2804
|
-
if (errorCode === "access_denied") {
|
|
2805
|
-
throw new DeviceAuthDeniedError();
|
|
2806
|
-
}
|
|
2807
|
-
throw new Error(
|
|
2808
|
-
`Device auth polling error: ${errorCode ?? `HTTP ${response.status}`}`
|
|
2809
|
-
);
|
|
2810
|
-
}
|
|
2811
|
-
throw new DeviceAuthTimeoutError();
|
|
2812
|
-
}
|
|
2813
|
-
async function fetchSessionInfo(convexSiteUrl, sessionToken) {
|
|
2814
|
-
const url = `${convexSiteUrl.replace(TRAILING_SLASHES2, "")}/api/cli/sessions/me`;
|
|
2815
|
-
const response = await fetch(url, {
|
|
2816
|
-
method: "GET",
|
|
2817
|
-
headers: {
|
|
2818
|
-
Authorization: `Bearer ${sessionToken}`
|
|
2819
|
-
}
|
|
2820
|
-
});
|
|
2821
|
-
if (response.status === 404) {
|
|
2822
|
-
return null;
|
|
2823
|
-
}
|
|
2824
|
-
if (!response.ok) {
|
|
2825
|
-
const body = await response.text();
|
|
2826
|
-
throw new Error(
|
|
2827
|
-
`Failed to fetch session info (${response.status}): ${body}`
|
|
2828
|
-
);
|
|
2829
|
-
}
|
|
2830
|
-
return response.json();
|
|
2831
|
-
}
|
|
2832
|
-
async function revokeSession(convexSiteUrl, sessionToken) {
|
|
2833
|
-
const url = `${convexSiteUrl.replace(TRAILING_SLASHES2, "")}/api/cli/sessions/me`;
|
|
2834
|
-
const response = await fetch(url, {
|
|
2835
|
-
method: "DELETE",
|
|
2836
|
-
headers: {
|
|
2837
|
-
Authorization: `Bearer ${sessionToken}`
|
|
3242
|
+
);
|
|
3243
|
+
summary.push({
|
|
3244
|
+
platform: target.id,
|
|
3245
|
+
installPath,
|
|
3246
|
+
written: result.written.length,
|
|
3247
|
+
warnings: result.warnings,
|
|
3248
|
+
errors: result.errors
|
|
3249
|
+
});
|
|
2838
3250
|
}
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
}
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
}
|
|
2856
|
-
|
|
2857
|
-
} else {
|
|
2858
|
-
execFile("xdg-open", [url], noop);
|
|
3251
|
+
if (options.json) {
|
|
3252
|
+
writeJson(summary);
|
|
3253
|
+
return;
|
|
3254
|
+
}
|
|
3255
|
+
for (const item of summary) {
|
|
3256
|
+
log.info(
|
|
3257
|
+
`${item.platform}: ${item.written} file(s) written${item.installPath ? ` to ${item.installPath}` : ""}`
|
|
3258
|
+
);
|
|
3259
|
+
for (const warning of item.warnings) {
|
|
3260
|
+
log.warn(` warning: ${warning}`);
|
|
3261
|
+
}
|
|
3262
|
+
for (const error of item.errors) {
|
|
3263
|
+
log.error(` error (${error.agent}): ${error.error}`);
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3266
|
+
log.success("sub-agents install completed");
|
|
3267
|
+
} catch (error) {
|
|
3268
|
+
exitCommandError(error, { json: options.json });
|
|
2859
3269
|
}
|
|
2860
3270
|
}
|
|
2861
|
-
function getDeviceInfo() {
|
|
2862
|
-
return {
|
|
2863
|
-
deviceName: hostname(),
|
|
2864
|
-
deviceOs: platform(),
|
|
2865
|
-
deviceHostname: hostname()
|
|
2866
|
-
};
|
|
2867
|
-
}
|
|
2868
3271
|
|
|
2869
3272
|
// src/commands/auth.ts
|
|
3273
|
+
init_esm_shims();
|
|
3274
|
+
init_api();
|
|
3275
|
+
init_config();
|
|
3276
|
+
init_device_auth();
|
|
2870
3277
|
init_tui();
|
|
2871
|
-
|
|
3278
|
+
import process10 from "process";
|
|
3279
|
+
var SESSION_TOKEN_PREFIX3 = "brs_";
|
|
3280
|
+
var LOOPBACK_HOSTS3 = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "localhost"]);
|
|
2872
3281
|
var DEFAULT_TIMEOUT_SECONDS = 300;
|
|
3282
|
+
var resolvePersistedCliServerUrl = (serverUrl, convexSiteUrl) => {
|
|
3283
|
+
try {
|
|
3284
|
+
const convexUrl = new URL(convexSiteUrl);
|
|
3285
|
+
if (LOOPBACK_HOSTS3.has(convexUrl.hostname)) {
|
|
3286
|
+
return convexSiteUrl;
|
|
3287
|
+
}
|
|
3288
|
+
} catch {
|
|
3289
|
+
return serverUrl;
|
|
3290
|
+
}
|
|
3291
|
+
return serverUrl;
|
|
3292
|
+
};
|
|
2873
3293
|
async function configureDefaultScopeAsync(serverUrl) {
|
|
2874
3294
|
const shouldConfigureScope = await confirm({
|
|
2875
3295
|
message: "Configure organization and scope defaults now?",
|
|
@@ -2904,9 +3324,9 @@ async function manualTokenFlow(apiKey, serverUrl, options) {
|
|
|
2904
3324
|
log.error(
|
|
2905
3325
|
"The API key could not be validated. Please check your key and try again."
|
|
2906
3326
|
);
|
|
2907
|
-
|
|
3327
|
+
process10.exit(1);
|
|
2908
3328
|
}
|
|
2909
|
-
await persistApiKeyAsync(apiKey);
|
|
3329
|
+
await persistApiKeyAsync(apiKey, serverUrl);
|
|
2910
3330
|
stopAuthSpinner("API key validated and saved");
|
|
2911
3331
|
if (options.scope !== false) {
|
|
2912
3332
|
await configureDefaultScopeAsync(serverUrl);
|
|
@@ -2919,7 +3339,7 @@ async function manualTokenFlow(apiKey, serverUrl, options) {
|
|
|
2919
3339
|
stopAuthSpinner("Validation failed");
|
|
2920
3340
|
const message = error instanceof Error ? error.message : String(error);
|
|
2921
3341
|
log.error(`Failed to validate API key: ${message}`);
|
|
2922
|
-
|
|
3342
|
+
process10.exit(1);
|
|
2923
3343
|
}
|
|
2924
3344
|
}
|
|
2925
3345
|
function handlePollingError(error) {
|
|
@@ -2933,7 +3353,7 @@ function handlePollingError(error) {
|
|
|
2933
3353
|
const message = error instanceof Error ? error.message : String(error);
|
|
2934
3354
|
log.error(`Authentication failed: ${message}`);
|
|
2935
3355
|
}
|
|
2936
|
-
|
|
3356
|
+
process10.exit(1);
|
|
2937
3357
|
}
|
|
2938
3358
|
async function deviceFlow(serverUrl, timeoutSeconds, options) {
|
|
2939
3359
|
const configSpinner = spinner();
|
|
@@ -2946,7 +3366,7 @@ async function deviceFlow(serverUrl, timeoutSeconds, options) {
|
|
|
2946
3366
|
configSpinner.stop("Failed to fetch auth configuration");
|
|
2947
3367
|
const message = error instanceof Error ? error.message : String(error);
|
|
2948
3368
|
log.error(`Could not connect to server: ${message}`);
|
|
2949
|
-
|
|
3369
|
+
process10.exit(1);
|
|
2950
3370
|
}
|
|
2951
3371
|
const deviceSpinner = spinner();
|
|
2952
3372
|
deviceSpinner.start("Initiating device authorization...");
|
|
@@ -2961,7 +3381,7 @@ async function deviceFlow(serverUrl, timeoutSeconds, options) {
|
|
|
2961
3381
|
deviceSpinner.stop("Failed to initiate device authorization");
|
|
2962
3382
|
const message = error instanceof Error ? error.message : String(error);
|
|
2963
3383
|
log.error(`Device authorization failed: ${message}`);
|
|
2964
|
-
|
|
3384
|
+
process10.exit(1);
|
|
2965
3385
|
}
|
|
2966
3386
|
const verificationUrl = buildAuthVerificationUrlFromBaseUrl(
|
|
2967
3387
|
authConfig.verificationBaseUrl,
|
|
@@ -2995,9 +3415,13 @@ async function deviceFlow(serverUrl, timeoutSeconds, options) {
|
|
|
2995
3415
|
pollSpinner.stop("Authentication failed");
|
|
2996
3416
|
handlePollingError(error);
|
|
2997
3417
|
}
|
|
2998
|
-
|
|
3418
|
+
const persistedServerUrl = resolvePersistedCliServerUrl(
|
|
3419
|
+
serverUrl,
|
|
3420
|
+
authConfig.convexSiteUrl
|
|
3421
|
+
);
|
|
3422
|
+
await persistApiKeyAsync(session.sessionToken, persistedServerUrl);
|
|
2999
3423
|
if (options.scope !== false) {
|
|
3000
|
-
await configureDefaultScopeAsync(
|
|
3424
|
+
await configureDefaultScopeAsync(persistedServerUrl);
|
|
3001
3425
|
}
|
|
3002
3426
|
log.success(`Session saved to ${CONFIG_FILE}`);
|
|
3003
3427
|
outro(
|
|
@@ -3025,12 +3449,12 @@ async function authCommand(options) {
|
|
|
3025
3449
|
const timeoutSeconds = options.timeout ? Number.parseInt(options.timeout, 10) : DEFAULT_TIMEOUT_SECONDS;
|
|
3026
3450
|
if (Number.isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
|
|
3027
3451
|
log.error("Invalid timeout value. Must be a positive number of seconds.");
|
|
3028
|
-
|
|
3452
|
+
process10.exit(1);
|
|
3029
3453
|
}
|
|
3030
3454
|
await deviceFlow(serverUrl, timeoutSeconds, options);
|
|
3031
3455
|
}
|
|
3032
3456
|
async function displayTokenSource(masked) {
|
|
3033
|
-
if (
|
|
3457
|
+
if (process10.env.BRAID_API_KEY) {
|
|
3034
3458
|
log.info(`Authenticated with key: ${masked}`);
|
|
3035
3459
|
log.info("Source: BRAID_API_KEY environment variable");
|
|
3036
3460
|
return;
|
|
@@ -3111,7 +3535,7 @@ async function authStatusCommand() {
|
|
|
3111
3535
|
);
|
|
3112
3536
|
return;
|
|
3113
3537
|
}
|
|
3114
|
-
if (config.token.startsWith(
|
|
3538
|
+
if (config.token.startsWith(SESSION_TOKEN_PREFIX3)) {
|
|
3115
3539
|
await displaySessionInfo(config.token);
|
|
3116
3540
|
await displayProjectConfig();
|
|
3117
3541
|
displayResolvedSettings(config);
|
|
@@ -3134,7 +3558,7 @@ async function revokeSessionIfActive(token) {
|
|
|
3134
3558
|
async function authLogoutCommand() {
|
|
3135
3559
|
const config = await loadMergedConfigAsync();
|
|
3136
3560
|
const { clearApiKeyAsync: clearApiKeyAsync2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
3137
|
-
if (config.token?.startsWith(
|
|
3561
|
+
if (config.token?.startsWith(SESSION_TOKEN_PREFIX3)) {
|
|
3138
3562
|
await revokeSessionIfActive(config.token);
|
|
3139
3563
|
}
|
|
3140
3564
|
await clearApiKeyAsync2();
|
|
@@ -3146,7 +3570,6 @@ init_esm_shims();
|
|
|
3146
3570
|
init_api();
|
|
3147
3571
|
init_config();
|
|
3148
3572
|
init_tui();
|
|
3149
|
-
import process9 from "process";
|
|
3150
3573
|
var parseCsv2 = (input) => {
|
|
3151
3574
|
if (!input) {
|
|
3152
3575
|
return void 0;
|
|
@@ -3154,15 +3577,6 @@ var parseCsv2 = (input) => {
|
|
|
3154
3577
|
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
3155
3578
|
return values.length > 0 ? values : void 0;
|
|
3156
3579
|
};
|
|
3157
|
-
var writeJson2 = (value) => {
|
|
3158
|
-
process9.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
3159
|
-
`);
|
|
3160
|
-
};
|
|
3161
|
-
var exitWithError2 = (error) => {
|
|
3162
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
3163
|
-
log.error(message);
|
|
3164
|
-
process9.exit(1);
|
|
3165
|
-
};
|
|
3166
3580
|
var applyCommonOptions = (base, options) => ({
|
|
3167
3581
|
...base,
|
|
3168
3582
|
...options.server ? { serverUrl: options.server } : {},
|
|
@@ -3189,7 +3603,7 @@ async function projectsListCommand(options) {
|
|
|
3189
3603
|
applyCommonOptions({}, options)
|
|
3190
3604
|
);
|
|
3191
3605
|
if (options.json) {
|
|
3192
|
-
|
|
3606
|
+
writeJson(result);
|
|
3193
3607
|
return;
|
|
3194
3608
|
}
|
|
3195
3609
|
log.info("Personal projects:");
|
|
@@ -3211,7 +3625,7 @@ Organization: ${orgProjects.orgName} (${orgProjects.orgId})`);
|
|
|
3211
3625
|
}
|
|
3212
3626
|
}
|
|
3213
3627
|
} catch (error) {
|
|
3214
|
-
|
|
3628
|
+
exitCommandError(error, { json: options.json });
|
|
3215
3629
|
}
|
|
3216
3630
|
}
|
|
3217
3631
|
var buildRulesRequest = async (options) => {
|
|
@@ -3232,7 +3646,7 @@ async function rulesListCommand(options) {
|
|
|
3232
3646
|
await buildRulesRequest(options)
|
|
3233
3647
|
);
|
|
3234
3648
|
if (options.json) {
|
|
3235
|
-
|
|
3649
|
+
writeJson(result);
|
|
3236
3650
|
return;
|
|
3237
3651
|
}
|
|
3238
3652
|
if (result.rules.length === 0) {
|
|
@@ -3243,7 +3657,7 @@ async function rulesListCommand(options) {
|
|
|
3243
3657
|
log.info(`${rule.id} ${rule.title}`);
|
|
3244
3658
|
}
|
|
3245
3659
|
} catch (error) {
|
|
3246
|
-
|
|
3660
|
+
exitCommandError(error, { json: options.json });
|
|
3247
3661
|
}
|
|
3248
3662
|
}
|
|
3249
3663
|
var buildSkillsRequest = async (options) => {
|
|
@@ -3263,7 +3677,7 @@ async function skillsListCommand(options) {
|
|
|
3263
3677
|
try {
|
|
3264
3678
|
const result = await fetchSkillsAsync(await buildSkillsRequest(options));
|
|
3265
3679
|
if (options.json) {
|
|
3266
|
-
|
|
3680
|
+
writeJson(result);
|
|
3267
3681
|
return;
|
|
3268
3682
|
}
|
|
3269
3683
|
if (result.skills.length === 0) {
|
|
@@ -3274,7 +3688,7 @@ async function skillsListCommand(options) {
|
|
|
3274
3688
|
log.info(`${skill.name}`);
|
|
3275
3689
|
}
|
|
3276
3690
|
} catch (error) {
|
|
3277
|
-
|
|
3691
|
+
exitCommandError(error, { json: options.json });
|
|
3278
3692
|
}
|
|
3279
3693
|
}
|
|
3280
3694
|
|
|
@@ -3421,11 +3835,11 @@ init_lockfile();
|
|
|
3421
3835
|
init_esm_shims();
|
|
3422
3836
|
import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
3423
3837
|
import { dirname as dirname6, join as join7 } from "path";
|
|
3424
|
-
import { Data as
|
|
3838
|
+
import { Data as Data6, Effect as Effect7, pipe as pipe7 } from "effect";
|
|
3425
3839
|
var METADATA_FILENAME2 = ".braid-metadata.json";
|
|
3426
|
-
var MetadataReadError = class extends
|
|
3840
|
+
var MetadataReadError = class extends Data6.TaggedError("MetadataReadError") {
|
|
3427
3841
|
};
|
|
3428
|
-
var MetadataWriteError = class extends
|
|
3842
|
+
var MetadataWriteError = class extends Data6.TaggedError("MetadataWriteError") {
|
|
3429
3843
|
};
|
|
3430
3844
|
var normalizeInstalledSkill = (skill) => ({
|
|
3431
3845
|
kind: skill.kind ?? "skill",
|
|
@@ -3441,18 +3855,18 @@ var normalizeMetadata = (metadata) => ({
|
|
|
3441
3855
|
var getMetadataPath = (skillsDir) => join7(dirname6(skillsDir), METADATA_FILENAME2);
|
|
3442
3856
|
var readMetadata = (skillsDir) => {
|
|
3443
3857
|
const metadataPath = getMetadataPath(skillsDir);
|
|
3444
|
-
return
|
|
3445
|
-
|
|
3858
|
+
return pipe7(
|
|
3859
|
+
Effect7.tryPromise({
|
|
3446
3860
|
try: () => readFile4(metadataPath, "utf-8"),
|
|
3447
3861
|
catch: (e) => new MetadataReadError({ path: metadataPath, cause: e })
|
|
3448
3862
|
}),
|
|
3449
|
-
|
|
3450
|
-
(content) =>
|
|
3863
|
+
Effect7.flatMap(
|
|
3864
|
+
(content) => Effect7.try({
|
|
3451
3865
|
try: () => normalizeMetadata(JSON.parse(content)),
|
|
3452
3866
|
catch: () => normalizeMetadata(void 0)
|
|
3453
3867
|
})
|
|
3454
3868
|
),
|
|
3455
|
-
|
|
3869
|
+
Effect7.orElseSucceed(() => normalizeMetadata(void 0))
|
|
3456
3870
|
);
|
|
3457
3871
|
};
|
|
3458
3872
|
var readRawJson = async (path2) => {
|
|
@@ -3469,7 +3883,7 @@ var readRawJson = async (path2) => {
|
|
|
3469
3883
|
};
|
|
3470
3884
|
var writeMetadata = (skillsDir, metadata) => {
|
|
3471
3885
|
const metadataPath = getMetadataPath(skillsDir);
|
|
3472
|
-
return
|
|
3886
|
+
return Effect7.tryPromise({
|
|
3473
3887
|
try: async () => {
|
|
3474
3888
|
const existing = await readRawJson(metadataPath);
|
|
3475
3889
|
const merged = { ...existing, skills: metadata.skills };
|
|
@@ -3478,9 +3892,9 @@ var writeMetadata = (skillsDir, metadata) => {
|
|
|
3478
3892
|
catch: (e) => new MetadataWriteError({ path: metadataPath, cause: e })
|
|
3479
3893
|
});
|
|
3480
3894
|
};
|
|
3481
|
-
var updateMetadata = (skillsDir, newSkills) =>
|
|
3895
|
+
var updateMetadata = (skillsDir, newSkills) => pipe7(
|
|
3482
3896
|
readMetadata(skillsDir),
|
|
3483
|
-
|
|
3897
|
+
Effect7.map((existing) => {
|
|
3484
3898
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3485
3899
|
const updatedSkills = [...existing.skills];
|
|
3486
3900
|
for (const skill of newSkills) {
|
|
@@ -3503,35 +3917,35 @@ var updateMetadata = (skillsDir, newSkills) => pipe6(
|
|
|
3503
3917
|
}
|
|
3504
3918
|
return { skills: updatedSkills };
|
|
3505
3919
|
}),
|
|
3506
|
-
|
|
3920
|
+
Effect7.flatMap((metadata) => writeMetadata(skillsDir, metadata))
|
|
3507
3921
|
);
|
|
3508
|
-
var removeFromMetadata = (skillsDir, skillName) =>
|
|
3922
|
+
var removeFromMetadata = (skillsDir, skillName) => pipe7(
|
|
3509
3923
|
readMetadata(skillsDir),
|
|
3510
|
-
|
|
3924
|
+
Effect7.map((metadata) => ({
|
|
3511
3925
|
skills: metadata.skills.filter((s) => s.name !== skillName)
|
|
3512
3926
|
})),
|
|
3513
|
-
|
|
3927
|
+
Effect7.flatMap((metadata) => writeMetadata(skillsDir, metadata))
|
|
3514
3928
|
);
|
|
3515
|
-
var readMetadataAsync = (skillsDir) =>
|
|
3516
|
-
var updateMetadataAsync = (skillsDir, newSkills) =>
|
|
3517
|
-
var removeFromMetadataAsync = (skillsDir, skillName) =>
|
|
3929
|
+
var readMetadataAsync = (skillsDir) => Effect7.runPromise(readMetadata(skillsDir));
|
|
3930
|
+
var updateMetadataAsync = (skillsDir, newSkills) => Effect7.runPromise(updateMetadata(skillsDir, newSkills));
|
|
3931
|
+
var removeFromMetadataAsync = (skillsDir, skillName) => Effect7.runPromise(removeFromMetadata(skillsDir, skillName));
|
|
3518
3932
|
|
|
3519
3933
|
// src/lib/rule-writer.ts
|
|
3520
3934
|
init_esm_shims();
|
|
3521
3935
|
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile6 } from "fs/promises";
|
|
3522
3936
|
import { dirname as dirname7, resolve as resolve3, sep as sep2 } from "path";
|
|
3523
|
-
import { Data as
|
|
3524
|
-
var RuleWriteError = class extends
|
|
3937
|
+
import { Data as Data7, Effect as Effect8, pipe as pipe8 } from "effect";
|
|
3938
|
+
var RuleWriteError = class extends Data7.TaggedError("RuleWriteError") {
|
|
3525
3939
|
};
|
|
3526
|
-
var createDirectory = (dir) =>
|
|
3940
|
+
var createDirectory = (dir) => Effect8.tryPromise({
|
|
3527
3941
|
try: () => mkdir4(dir, { recursive: true }),
|
|
3528
3942
|
catch: (e) => new RuleWriteError({ path: dir, operation: "mkdir", cause: e })
|
|
3529
3943
|
});
|
|
3530
|
-
var writeTextFile = (fullPath, content) =>
|
|
3944
|
+
var writeTextFile = (fullPath, content) => Effect8.tryPromise({
|
|
3531
3945
|
try: () => writeFile6(fullPath, content, "utf-8"),
|
|
3532
3946
|
catch: (e) => new RuleWriteError({ path: fullPath, operation: "write", cause: e })
|
|
3533
3947
|
});
|
|
3534
|
-
var readTextFile = (fullPath) =>
|
|
3948
|
+
var readTextFile = (fullPath) => Effect8.tryPromise({
|
|
3535
3949
|
try: () => readFile5(fullPath, "utf-8"),
|
|
3536
3950
|
catch: (e) => new RuleWriteError({ path: fullPath, operation: "read", cause: e })
|
|
3537
3951
|
});
|
|
@@ -3539,7 +3953,7 @@ var assertRulePathWithinBase = (basePath, ruleName) => {
|
|
|
3539
3953
|
const resolvedBase = resolve3(basePath);
|
|
3540
3954
|
const resolvedFull = resolve3(basePath, ruleName);
|
|
3541
3955
|
if (resolvedFull !== resolvedBase && !resolvedFull.startsWith(resolvedBase + sep2)) {
|
|
3542
|
-
return
|
|
3956
|
+
return Effect8.fail(
|
|
3543
3957
|
new RuleWriteError({
|
|
3544
3958
|
path: ruleName,
|
|
3545
3959
|
operation: "write",
|
|
@@ -3549,7 +3963,7 @@ var assertRulePathWithinBase = (basePath, ruleName) => {
|
|
|
3549
3963
|
})
|
|
3550
3964
|
);
|
|
3551
3965
|
}
|
|
3552
|
-
return
|
|
3966
|
+
return Effect8.succeed(resolvedFull);
|
|
3553
3967
|
};
|
|
3554
3968
|
var BRAID_SECTION_START = "<!-- braid:rules:start -->";
|
|
3555
3969
|
var BRAID_SECTION_END = "<!-- braid:rules:end -->";
|
|
@@ -3582,30 +3996,30 @@ function buildAppendContent(rules2) {
|
|
|
3582
3996
|
lines.push(BRAID_SECTION_END);
|
|
3583
3997
|
return lines.join("\n");
|
|
3584
3998
|
}
|
|
3585
|
-
var writeMdcRules = (basePath, rules2) =>
|
|
3999
|
+
var writeMdcRules = (basePath, rules2) => pipe8(
|
|
3586
4000
|
createDirectory(basePath),
|
|
3587
|
-
|
|
3588
|
-
() =>
|
|
4001
|
+
Effect8.flatMap(
|
|
4002
|
+
() => Effect8.forEach(
|
|
3589
4003
|
rules2,
|
|
3590
|
-
(rule) =>
|
|
4004
|
+
(rule) => pipe8(
|
|
3591
4005
|
assertRulePathWithinBase(basePath, `${rule.name}.mdc`),
|
|
3592
|
-
|
|
4006
|
+
Effect8.flatMap(
|
|
3593
4007
|
(filePath) => writeTextFile(filePath, buildMdcContent(rule))
|
|
3594
4008
|
)
|
|
3595
4009
|
),
|
|
3596
4010
|
{ concurrency: "unbounded" }
|
|
3597
4011
|
)
|
|
3598
4012
|
),
|
|
3599
|
-
|
|
4013
|
+
Effect8.asVoid
|
|
3600
4014
|
);
|
|
3601
|
-
var writeMarkdownDirRules = (basePath, rules2) =>
|
|
4015
|
+
var writeMarkdownDirRules = (basePath, rules2) => pipe8(
|
|
3602
4016
|
createDirectory(basePath),
|
|
3603
|
-
|
|
3604
|
-
() =>
|
|
4017
|
+
Effect8.flatMap(
|
|
4018
|
+
() => Effect8.forEach(
|
|
3605
4019
|
rules2,
|
|
3606
|
-
(rule) =>
|
|
4020
|
+
(rule) => pipe8(
|
|
3607
4021
|
assertRulePathWithinBase(basePath, `${rule.name}.md`),
|
|
3608
|
-
|
|
4022
|
+
Effect8.flatMap(
|
|
3609
4023
|
(filePath) => writeTextFile(filePath, `# ${rule.title}
|
|
3610
4024
|
|
|
3611
4025
|
${rule.content}`)
|
|
@@ -3614,17 +4028,17 @@ ${rule.content}`)
|
|
|
3614
4028
|
{ concurrency: "unbounded" }
|
|
3615
4029
|
)
|
|
3616
4030
|
),
|
|
3617
|
-
|
|
4031
|
+
Effect8.asVoid
|
|
3618
4032
|
);
|
|
3619
|
-
var writeAppendSingleRules = (filePath, rules2) =>
|
|
4033
|
+
var writeAppendSingleRules = (filePath, rules2) => pipe8(
|
|
3620
4034
|
createDirectory(dirname7(filePath)),
|
|
3621
|
-
|
|
3622
|
-
() =>
|
|
4035
|
+
Effect8.flatMap(
|
|
4036
|
+
() => pipe8(
|
|
3623
4037
|
readTextFile(filePath),
|
|
3624
|
-
|
|
4038
|
+
Effect8.orElseSucceed(() => "")
|
|
3625
4039
|
)
|
|
3626
4040
|
),
|
|
3627
|
-
|
|
4041
|
+
Effect8.flatMap((existing) => {
|
|
3628
4042
|
const braidContent = buildAppendContent(rules2);
|
|
3629
4043
|
const startIdx = existing.indexOf(BRAID_SECTION_START);
|
|
3630
4044
|
const endIdx = existing.indexOf(BRAID_SECTION_END);
|
|
@@ -3648,21 +4062,21 @@ var writeRulesForFormat = (basePath, rules2, format) => {
|
|
|
3648
4062
|
case "append-single":
|
|
3649
4063
|
return writeAppendSingleRules(basePath, rules2);
|
|
3650
4064
|
default:
|
|
3651
|
-
return
|
|
4065
|
+
return Effect8.void;
|
|
3652
4066
|
}
|
|
3653
4067
|
};
|
|
3654
4068
|
var writeRulesForAgent = (agent, rules2, rulesPath) => {
|
|
3655
4069
|
if (!agent.ruleFormat || rules2.length === 0) {
|
|
3656
|
-
return
|
|
4070
|
+
return Effect8.succeed({ written: 0, errors: [] });
|
|
3657
4071
|
}
|
|
3658
|
-
return
|
|
4072
|
+
return pipe8(
|
|
3659
4073
|
writeRulesForFormat(rulesPath, rules2, agent.ruleFormat),
|
|
3660
|
-
|
|
4074
|
+
Effect8.map(() => ({
|
|
3661
4075
|
written: rules2.length,
|
|
3662
4076
|
errors: []
|
|
3663
4077
|
})),
|
|
3664
|
-
|
|
3665
|
-
(error) =>
|
|
4078
|
+
Effect8.catch(
|
|
4079
|
+
(error) => Effect8.succeed({
|
|
3666
4080
|
written: 0,
|
|
3667
4081
|
errors: [
|
|
3668
4082
|
{
|
|
@@ -3674,29 +4088,29 @@ var writeRulesForAgent = (agent, rules2, rulesPath) => {
|
|
|
3674
4088
|
)
|
|
3675
4089
|
);
|
|
3676
4090
|
};
|
|
3677
|
-
var writeRulesForAgentAsync = (agent, rules2, rulesPath) =>
|
|
4091
|
+
var writeRulesForAgentAsync = (agent, rules2, rulesPath) => Effect8.runPromise(writeRulesForAgent(agent, rules2, rulesPath));
|
|
3678
4092
|
|
|
3679
4093
|
// src/lib/skill-writer.ts
|
|
3680
4094
|
init_esm_shims();
|
|
3681
4095
|
import { createHash as createHash2 } from "crypto";
|
|
3682
4096
|
import { chmod, mkdir as mkdir5, rm as rm2, symlink, writeFile as writeFile7 } from "fs/promises";
|
|
3683
4097
|
import { dirname as dirname8, join as join8, resolve as resolve4, sep as sep3 } from "path";
|
|
3684
|
-
import { Data as
|
|
3685
|
-
var WriteError = class extends
|
|
4098
|
+
import { Data as Data8, Effect as Effect9, pipe as pipe9 } from "effect";
|
|
4099
|
+
var WriteError = class extends Data8.TaggedError("WriteError") {
|
|
3686
4100
|
};
|
|
3687
|
-
var createDirectory2 = (dir, fullPath) =>
|
|
4101
|
+
var createDirectory2 = (dir, fullPath) => Effect9.tryPromise({
|
|
3688
4102
|
try: () => mkdir5(dir, { recursive: true }),
|
|
3689
4103
|
catch: (e) => new WriteError({ path: fullPath, operation: "mkdir", cause: e })
|
|
3690
4104
|
});
|
|
3691
|
-
var writeTextFile2 = (fullPath, content) =>
|
|
4105
|
+
var writeTextFile2 = (fullPath, content) => Effect9.tryPromise({
|
|
3692
4106
|
try: () => writeFile7(fullPath, content, "utf-8"),
|
|
3693
4107
|
catch: (e) => new WriteError({ path: fullPath, operation: "write", cause: e })
|
|
3694
4108
|
});
|
|
3695
|
-
var writeBinaryFile = (fullPath, content) =>
|
|
4109
|
+
var writeBinaryFile = (fullPath, content) => Effect9.tryPromise({
|
|
3696
4110
|
try: () => writeFile7(fullPath, content),
|
|
3697
4111
|
catch: (e) => new WriteError({ path: fullPath, operation: "write", cause: e })
|
|
3698
4112
|
});
|
|
3699
|
-
var makeExecutable = (fullPath) =>
|
|
4113
|
+
var makeExecutable = (fullPath) => Effect9.tryPromise({
|
|
3700
4114
|
try: () => chmod(fullPath, 493),
|
|
3701
4115
|
catch: (e) => new WriteError({ path: fullPath, operation: "chmod", cause: e })
|
|
3702
4116
|
});
|
|
@@ -3704,7 +4118,7 @@ var assertWithinBase2 = (basePath, untrustedPath) => {
|
|
|
3704
4118
|
const resolvedBase = resolve4(basePath);
|
|
3705
4119
|
const resolvedFull = resolve4(basePath, untrustedPath);
|
|
3706
4120
|
if (resolvedFull !== resolvedBase && !resolvedFull.startsWith(resolvedBase + sep3)) {
|
|
3707
|
-
return
|
|
4121
|
+
return Effect9.fail(
|
|
3708
4122
|
new WriteError({
|
|
3709
4123
|
path: untrustedPath,
|
|
3710
4124
|
operation: "write",
|
|
@@ -3714,7 +4128,7 @@ var assertWithinBase2 = (basePath, untrustedPath) => {
|
|
|
3714
4128
|
})
|
|
3715
4129
|
);
|
|
3716
4130
|
}
|
|
3717
|
-
return
|
|
4131
|
+
return Effect9.succeed(resolvedFull);
|
|
3718
4132
|
};
|
|
3719
4133
|
var COMPATIBILITY_REGEX = /^compatibility:\s*.+$/m;
|
|
3720
4134
|
var rewriteCompatibility = (content, agentId) => {
|
|
@@ -3757,22 +4171,22 @@ var isScriptFile = (path2) => {
|
|
|
3757
4171
|
return inScriptsDir && scriptExtensions.some((ext) => lowerPath.endsWith(ext));
|
|
3758
4172
|
};
|
|
3759
4173
|
var writeFileContent = (fullPath, file, agentId) => isBinaryFile(file.path) ? writeBinaryFile(fullPath, decodeFileContentBinary(file)) : writeTextFile2(fullPath, decodeFileContent(file, agentId));
|
|
3760
|
-
var setExecutableIfScript = (fullPath, file, agentId) => isScriptFile(file.path) && decodeFileContent(file, agentId).startsWith("#!") ? makeExecutable(fullPath) :
|
|
3761
|
-
var writeSkillFile = (basePath, file, agentId) =>
|
|
4174
|
+
var setExecutableIfScript = (fullPath, file, agentId) => isScriptFile(file.path) && decodeFileContent(file, agentId).startsWith("#!") ? makeExecutable(fullPath) : Effect9.void;
|
|
4175
|
+
var writeSkillFile = (basePath, file, agentId) => pipe9(
|
|
3762
4176
|
assertWithinBase2(basePath, file.path),
|
|
3763
|
-
|
|
4177
|
+
Effect9.flatMap((fullPath) => {
|
|
3764
4178
|
const dir = dirname8(fullPath);
|
|
3765
|
-
return
|
|
4179
|
+
return pipe9(
|
|
3766
4180
|
createDirectory2(dir, fullPath),
|
|
3767
|
-
|
|
3768
|
-
|
|
4181
|
+
Effect9.flatMap(() => writeFileContent(fullPath, file, agentId)),
|
|
4182
|
+
Effect9.flatMap(() => setExecutableIfScript(fullPath, file, agentId))
|
|
3769
4183
|
);
|
|
3770
4184
|
})
|
|
3771
4185
|
);
|
|
3772
|
-
var writeSkillAtPath = (skillPath, skill, agentId) =>
|
|
4186
|
+
var writeSkillAtPath = (skillPath, skill, agentId) => pipe9(
|
|
3773
4187
|
createDirectory2(skillPath, skillPath),
|
|
3774
|
-
|
|
3775
|
-
() =>
|
|
4188
|
+
Effect9.flatMap(
|
|
4189
|
+
() => Effect9.forEach(
|
|
3776
4190
|
skill.files,
|
|
3777
4191
|
(file) => writeSkillFile(skillPath, file, agentId),
|
|
3778
4192
|
{
|
|
@@ -3780,16 +4194,16 @@ var writeSkillAtPath = (skillPath, skill, agentId) => pipe8(
|
|
|
3780
4194
|
}
|
|
3781
4195
|
)
|
|
3782
4196
|
),
|
|
3783
|
-
|
|
4197
|
+
Effect9.map(() => void 0)
|
|
3784
4198
|
);
|
|
3785
|
-
var writeSkill = (basePath, skill, agentId) =>
|
|
4199
|
+
var writeSkill = (basePath, skill, agentId) => pipe9(
|
|
3786
4200
|
assertWithinBase2(basePath, skill.name),
|
|
3787
|
-
|
|
4201
|
+
Effect9.flatMap((skillDir) => writeSkillAtPath(skillDir, skill, agentId))
|
|
3788
4202
|
);
|
|
3789
|
-
var writeSkillSymlink = (basePath, skill, agentId, options) =>
|
|
4203
|
+
var writeSkillSymlink = (basePath, skill, agentId, options) => pipe9(
|
|
3790
4204
|
assertWithinBase2(basePath, skill.name),
|
|
3791
|
-
|
|
3792
|
-
(installPath) =>
|
|
4205
|
+
Effect9.flatMap(
|
|
4206
|
+
(installPath) => Effect9.tryPromise({
|
|
3793
4207
|
try: async () => {
|
|
3794
4208
|
if (!options.storeRoot) {
|
|
3795
4209
|
throw new Error("storeRoot is required for shared-store installs");
|
|
@@ -3799,7 +4213,7 @@ var writeSkillSymlink = (basePath, skill, agentId, options) => pipe8(
|
|
|
3799
4213
|
skill,
|
|
3800
4214
|
agentId
|
|
3801
4215
|
);
|
|
3802
|
-
await
|
|
4216
|
+
await Effect9.runPromise(
|
|
3803
4217
|
writeSkillAtPath(storedBundlePath, skill, agentId)
|
|
3804
4218
|
);
|
|
3805
4219
|
const destinationPath = await resolveManagedBundlePathAsync(
|
|
@@ -3826,14 +4240,14 @@ var writeSkillSymlink = (basePath, skill, agentId, options) => pipe8(
|
|
|
3826
4240
|
);
|
|
3827
4241
|
var hashSkill = (skill, agentId) => createHash2("sha256").update(JSON.stringify({ agentId, skill })).digest("hex").slice(0, 16);
|
|
3828
4242
|
var resolveStorePath = (storeRoot, skill, agentId) => join8(storeRoot, `${skill.name}-${hashSkill(skill, agentId)}`);
|
|
3829
|
-
var writeSkills = (basePath, skills2, agentId, options = {}) =>
|
|
3830
|
-
|
|
4243
|
+
var writeSkills = (basePath, skills2, agentId, options = {}) => pipe9(
|
|
4244
|
+
Effect9.forEach(
|
|
3831
4245
|
skills2,
|
|
3832
|
-
(skill) =>
|
|
4246
|
+
(skill) => pipe9(
|
|
3833
4247
|
options.storeRoot ? writeSkillSymlink(basePath, skill, agentId, options) : writeSkill(basePath, skill, agentId),
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
(error) =>
|
|
4248
|
+
Effect9.map(() => ({ success: true, skill: skill.name })),
|
|
4249
|
+
Effect9.catch(
|
|
4250
|
+
(error) => Effect9.succeed({
|
|
3837
4251
|
success: false,
|
|
3838
4252
|
skill: skill.name,
|
|
3839
4253
|
error: error.cause instanceof Error ? error.cause.message : String(error.cause)
|
|
@@ -3842,14 +4256,14 @@ var writeSkills = (basePath, skills2, agentId, options = {}) => pipe8(
|
|
|
3842
4256
|
),
|
|
3843
4257
|
{ concurrency: "unbounded" }
|
|
3844
4258
|
),
|
|
3845
|
-
|
|
4259
|
+
Effect9.map((results) => ({
|
|
3846
4260
|
written: results.filter((r) => r.success).map((r) => r.skill),
|
|
3847
4261
|
errors: results.filter(
|
|
3848
4262
|
(r) => !r.success
|
|
3849
4263
|
).map((r) => ({ skill: r.skill, error: r.error }))
|
|
3850
4264
|
}))
|
|
3851
4265
|
);
|
|
3852
|
-
var writeSkillsAsync = (basePath, skills2, agentId, options) =>
|
|
4266
|
+
var writeSkillsAsync = (basePath, skills2, agentId, options) => Effect9.runPromise(writeSkills(basePath, skills2, agentId, options));
|
|
3853
4267
|
|
|
3854
4268
|
// src/commands/install.ts
|
|
3855
4269
|
init_tui();
|
|
@@ -4219,7 +4633,7 @@ function showInstallOutro(totalWritten, totalErrors, suffix) {
|
|
|
4219
4633
|
outro(`Successfully installed ${totalWritten} items${suffix}.`);
|
|
4220
4634
|
}
|
|
4221
4635
|
}
|
|
4222
|
-
async function fetchPublicContent(handle, slug, version, lockedRuleIds, options, installSpinner) {
|
|
4636
|
+
async function fetchPublicContent(handle, slug, version, lockedRuleIds, apiKey, options, installSpinner) {
|
|
4223
4637
|
if (version !== void 0 && lockedRuleIds) {
|
|
4224
4638
|
installSpinner.stop(`Installing pinned version v${version}`);
|
|
4225
4639
|
installSpinner.start("Downloading content...");
|
|
@@ -4229,7 +4643,8 @@ async function fetchPublicContent(handle, slug, version, lockedRuleIds, options,
|
|
|
4229
4643
|
slug,
|
|
4230
4644
|
lockedRuleIds,
|
|
4231
4645
|
options.server,
|
|
4232
|
-
version
|
|
4646
|
+
version,
|
|
4647
|
+
apiKey
|
|
4233
4648
|
),
|
|
4234
4649
|
ruleIds: lockedRuleIds
|
|
4235
4650
|
};
|
|
@@ -4238,7 +4653,8 @@ async function fetchPublicContent(handle, slug, version, lockedRuleIds, options,
|
|
|
4238
4653
|
handle,
|
|
4239
4654
|
slug,
|
|
4240
4655
|
options.server,
|
|
4241
|
-
version
|
|
4656
|
+
version,
|
|
4657
|
+
apiKey
|
|
4242
4658
|
);
|
|
4243
4659
|
installSpinner.stop("Found public content");
|
|
4244
4660
|
displayPublicMetadata(metadata);
|
|
@@ -4250,7 +4666,8 @@ async function fetchPublicContent(handle, slug, version, lockedRuleIds, options,
|
|
|
4250
4666
|
slug,
|
|
4251
4667
|
ruleIds,
|
|
4252
4668
|
options.server,
|
|
4253
|
-
version
|
|
4669
|
+
version,
|
|
4670
|
+
apiKey
|
|
4254
4671
|
),
|
|
4255
4672
|
ruleIds
|
|
4256
4673
|
};
|
|
@@ -4299,6 +4716,7 @@ async function writeLockfileAfterInstall(handle, slug, version, contentHash, rul
|
|
|
4299
4716
|
}
|
|
4300
4717
|
}
|
|
4301
4718
|
async function publicInstallCommand(source, options) {
|
|
4719
|
+
const config = await loadMergedConfigAsync();
|
|
4302
4720
|
const parsed = parsePublicSource(source);
|
|
4303
4721
|
if (!parsed) {
|
|
4304
4722
|
log.error(`Invalid public source: ${source}`);
|
|
@@ -4322,6 +4740,7 @@ async function publicInstallCommand(source, options) {
|
|
|
4322
4740
|
log.info(`Using locked version: v${version}`);
|
|
4323
4741
|
}
|
|
4324
4742
|
const versionSuffix = version !== void 0 ? `@${version}` : "";
|
|
4743
|
+
const serverUrl = options.server ?? config.serverUrl;
|
|
4325
4744
|
intro(`Installing from @${handle}/${slug}${versionSuffix}`);
|
|
4326
4745
|
const installSpinner = spinner();
|
|
4327
4746
|
installSpinner.start("Fetching public content...");
|
|
@@ -4331,7 +4750,11 @@ async function publicInstallCommand(source, options) {
|
|
|
4331
4750
|
slug,
|
|
4332
4751
|
version,
|
|
4333
4752
|
lockedRuleIds,
|
|
4334
|
-
|
|
4753
|
+
config.token,
|
|
4754
|
+
{
|
|
4755
|
+
...options,
|
|
4756
|
+
server: serverUrl
|
|
4757
|
+
},
|
|
4335
4758
|
installSpinner
|
|
4336
4759
|
);
|
|
4337
4760
|
installSpinner.stop(`Downloaded ${summarizeContent(response)}`);
|
|
@@ -4339,11 +4762,13 @@ async function publicInstallCommand(source, options) {
|
|
|
4339
4762
|
log.warn("No content to install.");
|
|
4340
4763
|
process.exit(0);
|
|
4341
4764
|
}
|
|
4342
|
-
const serverUrl = options.server ?? "https://braid.cloud";
|
|
4343
4765
|
const { totalWritten, totalErrors } = await installToSelectedAgents(
|
|
4344
4766
|
response,
|
|
4345
4767
|
serverUrl,
|
|
4346
|
-
|
|
4768
|
+
{
|
|
4769
|
+
...options,
|
|
4770
|
+
server: serverUrl
|
|
4771
|
+
},
|
|
4347
4772
|
installSpinner
|
|
4348
4773
|
);
|
|
4349
4774
|
if (totalWritten > 0 && version !== void 0) {
|
|
@@ -4540,7 +4965,8 @@ async function listCommand(options) {
|
|
|
4540
4965
|
|
|
4541
4966
|
// src/commands/manage.ts
|
|
4542
4967
|
init_esm_shims();
|
|
4543
|
-
|
|
4968
|
+
init_device_auth();
|
|
4969
|
+
import process11 from "process";
|
|
4544
4970
|
|
|
4545
4971
|
// src/lib/manage-server.ts
|
|
4546
4972
|
init_esm_shims();
|
|
@@ -4550,6 +4976,7 @@ import { createServer } from "http";
|
|
|
4550
4976
|
import { isAbsolute, relative as relative2, resolve as resolve6 } from "path";
|
|
4551
4977
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4552
4978
|
init_config();
|
|
4979
|
+
init_device_auth();
|
|
4553
4980
|
|
|
4554
4981
|
// src/lib/manage-actions.ts
|
|
4555
4982
|
init_esm_shims();
|
|
@@ -4560,8 +4987,8 @@ import { basename as basename2, dirname as dirname10, join as join11, relative }
|
|
|
4560
4987
|
init_esm_shims();
|
|
4561
4988
|
import { mkdir as mkdir6, readFile as readFile6, rm as rm3, writeFile as writeFile8 } from "fs/promises";
|
|
4562
4989
|
import { dirname as dirname9, join as join9 } from "path";
|
|
4563
|
-
import { Data as
|
|
4564
|
-
var HookConfigWriteError = class extends
|
|
4990
|
+
import { Data as Data9, Effect as Effect10 } from "effect";
|
|
4991
|
+
var HookConfigWriteError = class extends Data9.TaggedError("HookConfigWriteError") {
|
|
4565
4992
|
};
|
|
4566
4993
|
var HOOK_METADATA_FILENAME = ".braid-metadata.json";
|
|
4567
4994
|
function stableStringify(value) {
|
|
@@ -4886,7 +5313,7 @@ async function ensureMarketplaceHookBundleFile(settingsPath, sourceSlug) {
|
|
|
4886
5313
|
});
|
|
4887
5314
|
return bundlePath;
|
|
4888
5315
|
}
|
|
4889
|
-
var writeMarketplaceHooks = (settingsPath, hooks, options) =>
|
|
5316
|
+
var writeMarketplaceHooks = (settingsPath, hooks, options) => Effect10.tryPromise({
|
|
4890
5317
|
try: async () => {
|
|
4891
5318
|
const activeHooks = hooks.filter(
|
|
4892
5319
|
(hook) => hook.enabled !== false && hook.runtime === "claude"
|
|
@@ -4941,131 +5368,18 @@ var writeMarketplaceHooks = (settingsPath, hooks, options) => Effect9.tryPromise
|
|
|
4941
5368
|
},
|
|
4942
5369
|
catch: (cause) => new HookConfigWriteError({ path: settingsPath, cause })
|
|
4943
5370
|
});
|
|
4944
|
-
var writeMarketplaceHooksAsync = (settingsPath, hooks, options) =>
|
|
5371
|
+
var writeMarketplaceHooksAsync = (settingsPath, hooks, options) => Effect10.runPromise(writeMarketplaceHooks(settingsPath, hooks, options));
|
|
4945
5372
|
var removeMarketplaceHooksBySourceAsync = (settingsPath, sourceSlug) => removeMarketplaceHooksBySource(settingsPath, sourceSlug);
|
|
4946
5373
|
var ensureMarketplaceHookBundleFileAsync = (settingsPath, sourceSlug) => ensureMarketplaceHookBundleFile(settingsPath, sourceSlug);
|
|
4947
5374
|
var listInstalledMarketplaceHookSourcesAsync = (settingsPath) => listInstalledMarketplaceHookSources(settingsPath);
|
|
4948
5375
|
var readMarketplaceHookBundleFileAsync = (bundlePath) => readMarketplaceHookBundleFile(bundlePath);
|
|
4949
5376
|
|
|
4950
|
-
// src/lib/marketplace-api.ts
|
|
4951
|
-
init_esm_shims();
|
|
4952
|
-
init_config();
|
|
4953
|
-
import { Data as Data9, Effect as Effect10, pipe as pipe9 } from "effect";
|
|
4954
|
-
var TRAILING_SLASH_REGEX2 = /\/$/;
|
|
4955
|
-
var MarketplaceApiError = class extends Data9.TaggedError("MarketplaceApiError") {
|
|
4956
|
-
};
|
|
4957
|
-
var resolveApiKey2 = (provided) => {
|
|
4958
|
-
if (provided) {
|
|
4959
|
-
return Effect10.succeed(provided);
|
|
4960
|
-
}
|
|
4961
|
-
return pipe9(
|
|
4962
|
-
Effect10.tryPromise({
|
|
4963
|
-
try: () => getApiKeyAsync(),
|
|
4964
|
-
catch: () => new MarketplaceApiError({
|
|
4965
|
-
message: "Failed to load API key",
|
|
4966
|
-
status: 500,
|
|
4967
|
-
code: "CONFIG_ERROR"
|
|
4968
|
-
})
|
|
4969
|
-
}),
|
|
4970
|
-
Effect10.flatMap(
|
|
4971
|
-
(token) => token ? Effect10.succeed(token) : Effect10.fail(
|
|
4972
|
-
new MarketplaceApiError({
|
|
4973
|
-
message: "Not signed in. Run 'braid auth'.",
|
|
4974
|
-
status: 401,
|
|
4975
|
-
code: "AUTH_REQUIRED"
|
|
4976
|
-
})
|
|
4977
|
-
)
|
|
4978
|
-
)
|
|
4979
|
-
);
|
|
4980
|
-
};
|
|
4981
|
-
var resolveServer = (provided) => {
|
|
4982
|
-
if (provided) {
|
|
4983
|
-
return Effect10.succeed(provided.replace(TRAILING_SLASH_REGEX2, ""));
|
|
4984
|
-
}
|
|
4985
|
-
return pipe9(
|
|
4986
|
-
Effect10.tryPromise({
|
|
4987
|
-
try: () => getServerUrlAsync(),
|
|
4988
|
-
catch: () => new MarketplaceApiError({
|
|
4989
|
-
message: "Failed to load server URL",
|
|
4990
|
-
status: 500,
|
|
4991
|
-
code: "CONFIG_ERROR"
|
|
4992
|
-
})
|
|
4993
|
-
}),
|
|
4994
|
-
Effect10.map((server) => server.replace(TRAILING_SLASH_REGEX2, ""))
|
|
4995
|
-
);
|
|
4996
|
-
};
|
|
4997
|
-
var requestJson = (url, options) => pipe9(
|
|
4998
|
-
Effect10.tryPromise({
|
|
4999
|
-
try: () => fetch(url, options),
|
|
5000
|
-
catch: () => new MarketplaceApiError({
|
|
5001
|
-
message: "Network error",
|
|
5002
|
-
status: 503,
|
|
5003
|
-
code: "NETWORK_ERROR"
|
|
5004
|
-
})
|
|
5005
|
-
}),
|
|
5006
|
-
Effect10.flatMap(
|
|
5007
|
-
(response) => Effect10.tryPromise({
|
|
5008
|
-
try: async () => {
|
|
5009
|
-
const payload = await response.json().catch(() => null);
|
|
5010
|
-
if (!response.ok) {
|
|
5011
|
-
throw new MarketplaceApiError({
|
|
5012
|
-
message: payload?.error ?? payload?.message ?? `Request failed (HTTP ${response.status} from ${new URL(url).origin})`,
|
|
5013
|
-
status: response.status,
|
|
5014
|
-
code: payload?.code ?? "REQUEST_ERROR"
|
|
5015
|
-
});
|
|
5016
|
-
}
|
|
5017
|
-
return payload;
|
|
5018
|
-
},
|
|
5019
|
-
catch: (error) => error instanceof MarketplaceApiError ? error : new MarketplaceApiError({
|
|
5020
|
-
message: "Invalid response",
|
|
5021
|
-
status: 500,
|
|
5022
|
-
code: "PARSE_ERROR"
|
|
5023
|
-
})
|
|
5024
|
-
})
|
|
5025
|
-
)
|
|
5026
|
-
);
|
|
5027
|
-
var fetchMarketplaceLibrary = (options) => pipe9(
|
|
5028
|
-
Effect10.all({
|
|
5029
|
-
server: resolveServer(options.server),
|
|
5030
|
-
apiKey: resolveApiKey2(options.apiKey)
|
|
5031
|
-
}),
|
|
5032
|
-
Effect10.flatMap(
|
|
5033
|
-
({ server, apiKey }) => requestJson(
|
|
5034
|
-
`${server}/api/marketplace/library`,
|
|
5035
|
-
{
|
|
5036
|
-
method: "GET",
|
|
5037
|
-
headers: {
|
|
5038
|
-
Authorization: `Bearer ${apiKey}`
|
|
5039
|
-
}
|
|
5040
|
-
}
|
|
5041
|
-
)
|
|
5042
|
-
),
|
|
5043
|
-
Effect10.map((response) => response.items)
|
|
5044
|
-
);
|
|
5045
|
-
var fetchMarketplaceInstallManifest = (slug, options) => pipe9(
|
|
5046
|
-
Effect10.all({
|
|
5047
|
-
server: resolveServer(options.server),
|
|
5048
|
-
apiKey: resolveApiKey2(options.apiKey)
|
|
5049
|
-
}),
|
|
5050
|
-
Effect10.flatMap(
|
|
5051
|
-
({ server, apiKey }) => requestJson(
|
|
5052
|
-
`${server}/api/marketplace/install-manifest/${encodeURIComponent(slug)}`,
|
|
5053
|
-
{
|
|
5054
|
-
method: "GET",
|
|
5055
|
-
headers: {
|
|
5056
|
-
Authorization: `Bearer ${apiKey}`
|
|
5057
|
-
}
|
|
5058
|
-
}
|
|
5059
|
-
)
|
|
5060
|
-
)
|
|
5061
|
-
);
|
|
5062
|
-
var fetchMarketplaceLibraryAsync = (options) => Effect10.runPromise(fetchMarketplaceLibrary(options));
|
|
5063
|
-
var fetchMarketplaceInstallManifestAsync = (slug, options) => Effect10.runPromise(fetchMarketplaceInstallManifest(slug, options));
|
|
5064
|
-
|
|
5065
5377
|
// src/lib/marketplace-installer.ts
|
|
5066
5378
|
init_esm_shims();
|
|
5067
5379
|
import { rm as rm4 } from "fs/promises";
|
|
5068
5380
|
import { join as join10 } from "path";
|
|
5381
|
+
init_config();
|
|
5382
|
+
var TRAILING_SLASH_REGEX3 = /\/$/;
|
|
5069
5383
|
function parseAgentIds(value) {
|
|
5070
5384
|
if (!value) {
|
|
5071
5385
|
return [];
|
|
@@ -5135,7 +5449,7 @@ async function installSkillsForAgent(args) {
|
|
|
5135
5449
|
versionId: args.manifest.versionId
|
|
5136
5450
|
},
|
|
5137
5451
|
version: args.manifest.versionId ?? args.manifest.commitSha ?? "unknown",
|
|
5138
|
-
serverUrl:
|
|
5452
|
+
serverUrl: args.serverUrl
|
|
5139
5453
|
}))
|
|
5140
5454
|
);
|
|
5141
5455
|
args.targets.push(`${args.agent.name} -> ${installPath}`);
|
|
@@ -5224,6 +5538,7 @@ async function installAllForAgent(args) {
|
|
|
5224
5538
|
agent: args.agent,
|
|
5225
5539
|
manifest: args.manifest,
|
|
5226
5540
|
slug: args.slug,
|
|
5541
|
+
serverUrl: args.serverUrl,
|
|
5227
5542
|
skills: args.skills,
|
|
5228
5543
|
global: args.global,
|
|
5229
5544
|
installedSkills: args.installedSkills,
|
|
@@ -5281,6 +5596,7 @@ async function installMarketplaceSkillSet(options) {
|
|
|
5281
5596
|
"No compatible agents found. Use --agents to specify targets."
|
|
5282
5597
|
);
|
|
5283
5598
|
}
|
|
5599
|
+
const serverUrl = (options.serverUrl ?? await getServerUrlAsync().catch(() => "https://braid.cloud")).replace(TRAILING_SLASH_REGEX3, "");
|
|
5284
5600
|
const targets = [];
|
|
5285
5601
|
const installedSkills = /* @__PURE__ */ new Set();
|
|
5286
5602
|
for (const agent of targetAgents) {
|
|
@@ -5288,6 +5604,7 @@ async function installMarketplaceSkillSet(options) {
|
|
|
5288
5604
|
agent,
|
|
5289
5605
|
manifest: options.manifest,
|
|
5290
5606
|
slug: options.slug,
|
|
5607
|
+
serverUrl,
|
|
5291
5608
|
skills: resolvedSkills,
|
|
5292
5609
|
rules: rules2,
|
|
5293
5610
|
agents: agents2,
|
|
@@ -5437,7 +5754,8 @@ async function installLibraryPackAsync(options) {
|
|
|
5437
5754
|
agents: options.agentId,
|
|
5438
5755
|
global: options.scope === "global",
|
|
5439
5756
|
manifest,
|
|
5440
|
-
slug: options.slug
|
|
5757
|
+
slug: options.slug,
|
|
5758
|
+
serverUrl: options.server
|
|
5441
5759
|
});
|
|
5442
5760
|
}
|
|
5443
5761
|
|
|
@@ -5914,7 +6232,8 @@ var MIME_TYPES = {
|
|
|
5914
6232
|
};
|
|
5915
6233
|
var TRAILING_SLASHES3 = /\/+$/;
|
|
5916
6234
|
var MANAGE_AUTH_TIMEOUT_SECONDS = 300;
|
|
5917
|
-
var
|
|
6235
|
+
var SESSION_TOKEN_PREFIX4 = "brs_";
|
|
6236
|
+
var LOOPBACK_HOSTS4 = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "localhost"]);
|
|
5918
6237
|
function getErrorStatus(error) {
|
|
5919
6238
|
if (typeof error === "object" && error !== null && "status" in error && typeof error.status === "number") {
|
|
5920
6239
|
return error.status ?? 500;
|
|
@@ -5991,7 +6310,18 @@ function getContentType(pathname) {
|
|
|
5991
6310
|
const extension = pathname.slice(pathname.lastIndexOf("."));
|
|
5992
6311
|
return MIME_TYPES[extension] ?? "application/octet-stream";
|
|
5993
6312
|
}
|
|
5994
|
-
function
|
|
6313
|
+
function resolvePersistedCliServerUrl2(serverUrl, convexSiteUrl) {
|
|
6314
|
+
try {
|
|
6315
|
+
const convexUrl = new URL(convexSiteUrl);
|
|
6316
|
+
if (LOOPBACK_HOSTS4.has(convexUrl.hostname)) {
|
|
6317
|
+
return convexSiteUrl;
|
|
6318
|
+
}
|
|
6319
|
+
} catch {
|
|
6320
|
+
return serverUrl;
|
|
6321
|
+
}
|
|
6322
|
+
return serverUrl;
|
|
6323
|
+
}
|
|
6324
|
+
function writeJson2(response, status, body) {
|
|
5995
6325
|
response.writeHead(status, {
|
|
5996
6326
|
"content-type": "application/json; charset=utf-8",
|
|
5997
6327
|
"cache-control": "no-store"
|
|
@@ -6015,7 +6345,7 @@ async function serveStaticAsset(serverResponse, assetRoot, pathname) {
|
|
|
6015
6345
|
const assetPath = resolve6(assetRoot, relativePath);
|
|
6016
6346
|
const resolvedRoot = resolve6(assetRoot);
|
|
6017
6347
|
if (!isWithinManageAssetRoot(resolvedRoot, assetPath)) {
|
|
6018
|
-
|
|
6348
|
+
writeJson2(serverResponse, 404, { error: "Not found" });
|
|
6019
6349
|
return true;
|
|
6020
6350
|
}
|
|
6021
6351
|
try {
|
|
@@ -6109,19 +6439,19 @@ async function handleManageApiRoute(request, response, dependencies) {
|
|
|
6109
6439
|
const pathname = new URL(request.url ?? "/", "http://127.0.0.1").pathname;
|
|
6110
6440
|
switch (`${method} ${pathname}`) {
|
|
6111
6441
|
case "GET /api/inventory":
|
|
6112
|
-
|
|
6442
|
+
writeJson2(response, 200, await dependencies.getInventory());
|
|
6113
6443
|
return true;
|
|
6114
6444
|
case "GET /api/library":
|
|
6115
|
-
|
|
6445
|
+
writeJson2(response, 200, await dependencies.listLibrary());
|
|
6116
6446
|
return true;
|
|
6117
6447
|
case "GET /api/auth/session":
|
|
6118
|
-
|
|
6448
|
+
writeJson2(response, 200, {
|
|
6119
6449
|
ok: true,
|
|
6120
6450
|
result: await dependencies.getAuthSession()
|
|
6121
6451
|
});
|
|
6122
6452
|
return true;
|
|
6123
6453
|
case "POST /api/auth/start":
|
|
6124
|
-
|
|
6454
|
+
writeJson2(response, 200, {
|
|
6125
6455
|
ok: true,
|
|
6126
6456
|
result: await dependencies.startAuth()
|
|
6127
6457
|
});
|
|
@@ -6135,7 +6465,7 @@ async function handleManageApiRoute(request, response, dependencies) {
|
|
|
6135
6465
|
"AUTH_REQUEST_REQUIRED"
|
|
6136
6466
|
);
|
|
6137
6467
|
}
|
|
6138
|
-
|
|
6468
|
+
writeJson2(response, 200, {
|
|
6139
6469
|
ok: true,
|
|
6140
6470
|
result: await dependencies.completeAuth({
|
|
6141
6471
|
requestId: payload.requestId
|
|
@@ -6144,14 +6474,14 @@ async function handleManageApiRoute(request, response, dependencies) {
|
|
|
6144
6474
|
return true;
|
|
6145
6475
|
}
|
|
6146
6476
|
case "POST /api/auth/sign-out":
|
|
6147
|
-
|
|
6477
|
+
writeJson2(response, 200, {
|
|
6148
6478
|
ok: true,
|
|
6149
6479
|
result: await dependencies.signOut()
|
|
6150
6480
|
});
|
|
6151
6481
|
return true;
|
|
6152
6482
|
case "POST /api/actions/install": {
|
|
6153
6483
|
const payload = await readJsonBody(request);
|
|
6154
|
-
|
|
6484
|
+
writeJson2(response, 200, {
|
|
6155
6485
|
ok: true,
|
|
6156
6486
|
result: await dependencies.installLibraryPack(payload)
|
|
6157
6487
|
});
|
|
@@ -6159,7 +6489,7 @@ async function handleManageApiRoute(request, response, dependencies) {
|
|
|
6159
6489
|
}
|
|
6160
6490
|
case "POST /api/actions/disable": {
|
|
6161
6491
|
const payload = await readJsonBody(request);
|
|
6162
|
-
|
|
6492
|
+
writeJson2(response, 200, {
|
|
6163
6493
|
ok: true,
|
|
6164
6494
|
result: await dependencies.disableManagedBundle(payload)
|
|
6165
6495
|
});
|
|
@@ -6167,7 +6497,7 @@ async function handleManageApiRoute(request, response, dependencies) {
|
|
|
6167
6497
|
}
|
|
6168
6498
|
case "POST /api/actions/enable": {
|
|
6169
6499
|
const payload = await readJsonBody(request);
|
|
6170
|
-
|
|
6500
|
+
writeJson2(response, 200, {
|
|
6171
6501
|
ok: true,
|
|
6172
6502
|
result: await dependencies.enableManagedBundle(payload)
|
|
6173
6503
|
});
|
|
@@ -6175,7 +6505,7 @@ async function handleManageApiRoute(request, response, dependencies) {
|
|
|
6175
6505
|
}
|
|
6176
6506
|
case "POST /api/actions/remove": {
|
|
6177
6507
|
const payload = await readJsonBody(request);
|
|
6178
|
-
|
|
6508
|
+
writeJson2(response, 200, {
|
|
6179
6509
|
ok: true,
|
|
6180
6510
|
result: await dependencies.removeManagedBundle(payload)
|
|
6181
6511
|
});
|
|
@@ -6197,11 +6527,11 @@ async function handleManageRequest(request, response, assetRoot, dependencies) {
|
|
|
6197
6527
|
return;
|
|
6198
6528
|
}
|
|
6199
6529
|
}
|
|
6200
|
-
|
|
6530
|
+
writeJson2(response, 404, { error: "Not found" });
|
|
6201
6531
|
} catch (error) {
|
|
6202
6532
|
const message = error instanceof Error ? error.message : String(error);
|
|
6203
6533
|
const code = getErrorCode(error);
|
|
6204
|
-
|
|
6534
|
+
writeJson2(response, getErrorStatus(error), {
|
|
6205
6535
|
...code ? { code } : {},
|
|
6206
6536
|
error: message
|
|
6207
6537
|
});
|
|
@@ -6272,6 +6602,10 @@ async function startManageServer(options = {}) {
|
|
|
6272
6602
|
deviceAuth.user_code
|
|
6273
6603
|
);
|
|
6274
6604
|
authRequests.set(requestId, {
|
|
6605
|
+
serverUrl: resolvePersistedCliServerUrl2(
|
|
6606
|
+
serverUrl,
|
|
6607
|
+
authConfig.convexSiteUrl
|
|
6608
|
+
),
|
|
6275
6609
|
convexSiteUrl: authConfig.convexSiteUrl,
|
|
6276
6610
|
deviceCode: deviceAuth.device_code,
|
|
6277
6611
|
expiresIn: deviceAuth.expires_in,
|
|
@@ -6304,7 +6638,7 @@ async function startManageServer(options = {}) {
|
|
|
6304
6638
|
);
|
|
6305
6639
|
await persistApiKeyAsync(
|
|
6306
6640
|
session.sessionToken,
|
|
6307
|
-
pendingRequest.
|
|
6641
|
+
pendingRequest.serverUrl
|
|
6308
6642
|
);
|
|
6309
6643
|
return {
|
|
6310
6644
|
authenticated: true,
|
|
@@ -6321,7 +6655,7 @@ async function startManageServer(options = {}) {
|
|
|
6321
6655
|
if (!token) {
|
|
6322
6656
|
return { authenticated: false };
|
|
6323
6657
|
}
|
|
6324
|
-
if (!token.startsWith(
|
|
6658
|
+
if (!token.startsWith(SESSION_TOKEN_PREFIX4)) {
|
|
6325
6659
|
return { authenticated: true };
|
|
6326
6660
|
}
|
|
6327
6661
|
const serverUrl = (options.server ?? config.serverUrl).replace(
|
|
@@ -6346,7 +6680,7 @@ async function startManageServer(options = {}) {
|
|
|
6346
6680
|
const signOut = options.signOut ?? (async () => {
|
|
6347
6681
|
const config = await loadMergedConfigAsync();
|
|
6348
6682
|
const token = config.token;
|
|
6349
|
-
if (token?.startsWith(
|
|
6683
|
+
if (token?.startsWith(SESSION_TOKEN_PREFIX4)) {
|
|
6350
6684
|
try {
|
|
6351
6685
|
const serverUrl = (options.server ?? config.serverUrl).replace(
|
|
6352
6686
|
TRAILING_SLASHES3,
|
|
@@ -6378,7 +6712,7 @@ async function startManageServer(options = {}) {
|
|
|
6378
6712
|
handleManageRequest(request, response, assetRoot, dependencies).catch(
|
|
6379
6713
|
(error) => {
|
|
6380
6714
|
const message = error instanceof Error ? error.message : String(error);
|
|
6381
|
-
|
|
6715
|
+
writeJson2(response, 500, { error: message });
|
|
6382
6716
|
}
|
|
6383
6717
|
);
|
|
6384
6718
|
});
|
|
@@ -6422,7 +6756,7 @@ async function manageCommand(options) {
|
|
|
6422
6756
|
const server = await startManageServer({
|
|
6423
6757
|
apiKey: options.apiKey,
|
|
6424
6758
|
port: parsePort(options.port),
|
|
6425
|
-
projectRoot:
|
|
6759
|
+
projectRoot: process11.cwd(),
|
|
6426
6760
|
server: options.server
|
|
6427
6761
|
});
|
|
6428
6762
|
if (options.open !== false) {
|
|
@@ -6432,17 +6766,17 @@ async function manageCommand(options) {
|
|
|
6432
6766
|
log.info("Press Ctrl+C to stop.");
|
|
6433
6767
|
await new Promise((resolveClose, rejectClose) => {
|
|
6434
6768
|
const shutdown = () => {
|
|
6435
|
-
|
|
6436
|
-
|
|
6769
|
+
process11.off("SIGINT", shutdown);
|
|
6770
|
+
process11.off("SIGTERM", shutdown);
|
|
6437
6771
|
server.close().then(resolveClose).catch(rejectClose);
|
|
6438
6772
|
};
|
|
6439
|
-
|
|
6440
|
-
|
|
6773
|
+
process11.once("SIGINT", shutdown);
|
|
6774
|
+
process11.once("SIGTERM", shutdown);
|
|
6441
6775
|
});
|
|
6442
6776
|
} catch (error) {
|
|
6443
6777
|
const message = error instanceof Error ? error.message : String(error);
|
|
6444
6778
|
log.error(message);
|
|
6445
|
-
|
|
6779
|
+
process11.exit(1);
|
|
6446
6780
|
}
|
|
6447
6781
|
}
|
|
6448
6782
|
|
|
@@ -6450,7 +6784,7 @@ async function manageCommand(options) {
|
|
|
6450
6784
|
init_esm_shims();
|
|
6451
6785
|
import { rm as rm6 } from "fs/promises";
|
|
6452
6786
|
import { join as join13, resolve as resolve7 } from "path";
|
|
6453
|
-
import
|
|
6787
|
+
import process12 from "process";
|
|
6454
6788
|
init_tui();
|
|
6455
6789
|
async function selectInstallScope(options) {
|
|
6456
6790
|
if (options.global != null) {
|
|
@@ -6469,7 +6803,7 @@ async function selectInstallScope(options) {
|
|
|
6469
6803
|
});
|
|
6470
6804
|
if (isCancel(result)) {
|
|
6471
6805
|
cancel("Install cancelled.");
|
|
6472
|
-
|
|
6806
|
+
process12.exit(0);
|
|
6473
6807
|
}
|
|
6474
6808
|
return result;
|
|
6475
6809
|
}
|
|
@@ -6504,7 +6838,7 @@ async function selectInstallAgents(options, global) {
|
|
|
6504
6838
|
});
|
|
6505
6839
|
if (isCancel(selected)) {
|
|
6506
6840
|
cancel("Install cancelled.");
|
|
6507
|
-
|
|
6841
|
+
process12.exit(0);
|
|
6508
6842
|
}
|
|
6509
6843
|
return selected;
|
|
6510
6844
|
}
|
|
@@ -6521,7 +6855,7 @@ async function confirmHooksOptIn(hookCount, options) {
|
|
|
6521
6855
|
});
|
|
6522
6856
|
if (isCancel(result)) {
|
|
6523
6857
|
cancel("Install cancelled.");
|
|
6524
|
-
|
|
6858
|
+
process12.exit(0);
|
|
6525
6859
|
}
|
|
6526
6860
|
return result;
|
|
6527
6861
|
}
|
|
@@ -6546,7 +6880,7 @@ async function marketplaceLibraryCommand(options) {
|
|
|
6546
6880
|
log.error(
|
|
6547
6881
|
error instanceof Error ? error.message : "Failed to fetch library"
|
|
6548
6882
|
);
|
|
6549
|
-
|
|
6883
|
+
process12.exit(1);
|
|
6550
6884
|
}
|
|
6551
6885
|
}
|
|
6552
6886
|
async function resolveAndInstallPack(slug, options, overrides) {
|
|
@@ -6569,7 +6903,8 @@ async function resolveAndInstallPack(slug, options, overrides) {
|
|
|
6569
6903
|
manifest,
|
|
6570
6904
|
agents: agents2,
|
|
6571
6905
|
global,
|
|
6572
|
-
allowHooks: options.allowHooks
|
|
6906
|
+
allowHooks: options.allowHooks,
|
|
6907
|
+
serverUrl: options.server
|
|
6573
6908
|
});
|
|
6574
6909
|
}
|
|
6575
6910
|
async function marketplaceInstallCommand(slug, options) {
|
|
@@ -6580,7 +6915,7 @@ async function marketplaceInstallCommand(slug, options) {
|
|
|
6580
6915
|
log.error(
|
|
6581
6916
|
error instanceof Error ? error.message : "Failed to install pack"
|
|
6582
6917
|
);
|
|
6583
|
-
|
|
6918
|
+
process12.exit(1);
|
|
6584
6919
|
}
|
|
6585
6920
|
}
|
|
6586
6921
|
function addSkillToPack(packMap, slug, versionId, skillName, agent, installPath) {
|
|
@@ -6634,7 +6969,7 @@ async function marketplaceUpdateCommand(slug, options) {
|
|
|
6634
6969
|
const toUpdate = slug ? installed.filter((p) => p.slug === slug) : installed;
|
|
6635
6970
|
if (toUpdate.length === 0) {
|
|
6636
6971
|
log.error(`Pack "${slug}" is not installed.`);
|
|
6637
|
-
|
|
6972
|
+
process12.exit(1);
|
|
6638
6973
|
}
|
|
6639
6974
|
let updated = 0;
|
|
6640
6975
|
for (const pack of toUpdate) {
|
|
@@ -6654,7 +6989,7 @@ async function marketplaceUpdateCommand(slug, options) {
|
|
|
6654
6989
|
log.error(
|
|
6655
6990
|
error instanceof Error ? error.message : "Failed to update packs"
|
|
6656
6991
|
);
|
|
6657
|
-
|
|
6992
|
+
process12.exit(1);
|
|
6658
6993
|
}
|
|
6659
6994
|
}
|
|
6660
6995
|
async function selectPacksToRemove(installed, slug, options) {
|
|
@@ -6680,7 +7015,7 @@ async function selectPacksToRemove(installed, slug, options) {
|
|
|
6680
7015
|
});
|
|
6681
7016
|
if (isCancel(selected)) {
|
|
6682
7017
|
cancel("Remove cancelled.");
|
|
6683
|
-
|
|
7018
|
+
process12.exit(0);
|
|
6684
7019
|
}
|
|
6685
7020
|
return selected;
|
|
6686
7021
|
}
|
|
@@ -6718,7 +7053,7 @@ async function marketplaceRemoveCommand(slug, options) {
|
|
|
6718
7053
|
});
|
|
6719
7054
|
if (isCancel(confirmed) || !confirmed) {
|
|
6720
7055
|
cancel("Remove cancelled.");
|
|
6721
|
-
|
|
7056
|
+
process12.exit(0);
|
|
6722
7057
|
}
|
|
6723
7058
|
}
|
|
6724
7059
|
for (const pack of toRemove) {
|
|
@@ -6729,7 +7064,7 @@ async function marketplaceRemoveCommand(slug, options) {
|
|
|
6729
7064
|
log.error(
|
|
6730
7065
|
error instanceof Error ? error.message : "Failed to remove packs"
|
|
6731
7066
|
);
|
|
6732
|
-
|
|
7067
|
+
process12.exit(1);
|
|
6733
7068
|
}
|
|
6734
7069
|
}
|
|
6735
7070
|
|
|
@@ -6737,19 +7072,6 @@ async function marketplaceRemoveCommand(slug, options) {
|
|
|
6737
7072
|
init_esm_shims();
|
|
6738
7073
|
init_api();
|
|
6739
7074
|
init_tui();
|
|
6740
|
-
import process12 from "process";
|
|
6741
|
-
var writeJson4 = (value) => {
|
|
6742
|
-
process12.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
6743
|
-
`);
|
|
6744
|
-
};
|
|
6745
|
-
var exitWithError3 = (error) => {
|
|
6746
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
6747
|
-
log.error(message);
|
|
6748
|
-
process12.exit(1);
|
|
6749
|
-
};
|
|
6750
|
-
var fail2 = (message) => {
|
|
6751
|
-
throw new Error(message);
|
|
6752
|
-
};
|
|
6753
7075
|
var parseContext = (contextJson) => {
|
|
6754
7076
|
if (!contextJson) {
|
|
6755
7077
|
return void 0;
|
|
@@ -6770,7 +7092,7 @@ var run2 = async (command, args, options) => {
|
|
|
6770
7092
|
apiOptions
|
|
6771
7093
|
);
|
|
6772
7094
|
if (options.json) {
|
|
6773
|
-
|
|
7095
|
+
writeJson(result);
|
|
6774
7096
|
return;
|
|
6775
7097
|
}
|
|
6776
7098
|
log.success(`profiles ${command} completed`);
|
|
@@ -6779,34 +7101,34 @@ async function profilesListCommand(options) {
|
|
|
6779
7101
|
try {
|
|
6780
7102
|
await run2("list", {}, options);
|
|
6781
7103
|
} catch (error) {
|
|
6782
|
-
|
|
7104
|
+
exitCommandError(error, options);
|
|
6783
7105
|
}
|
|
6784
7106
|
}
|
|
6785
7107
|
async function profilesGetCommand(options) {
|
|
6786
7108
|
try {
|
|
6787
7109
|
if (!(options.id || options.name)) {
|
|
6788
|
-
|
|
7110
|
+
fail("profiles get requires --id or --name");
|
|
6789
7111
|
}
|
|
6790
7112
|
await run2("get", { id: options.id, name: options.name }, options);
|
|
6791
7113
|
} catch (error) {
|
|
6792
|
-
|
|
7114
|
+
exitCommandError(error, options);
|
|
6793
7115
|
}
|
|
6794
7116
|
}
|
|
6795
7117
|
async function profilesCreateCommand(options) {
|
|
6796
7118
|
try {
|
|
6797
|
-
const name = options.name ??
|
|
7119
|
+
const name = options.name ?? fail("profiles create requires --name");
|
|
6798
7120
|
await run2(
|
|
6799
7121
|
"create",
|
|
6800
7122
|
{ name, context: parseContext(options.contextJson) },
|
|
6801
7123
|
options
|
|
6802
7124
|
);
|
|
6803
7125
|
} catch (error) {
|
|
6804
|
-
|
|
7126
|
+
exitCommandError(error, options);
|
|
6805
7127
|
}
|
|
6806
7128
|
}
|
|
6807
7129
|
async function profilesUpdateCommand(options) {
|
|
6808
7130
|
try {
|
|
6809
|
-
const id = options.id ??
|
|
7131
|
+
const id = options.id ?? fail("profiles update requires --id");
|
|
6810
7132
|
await run2(
|
|
6811
7133
|
"update",
|
|
6812
7134
|
{
|
|
@@ -6817,26 +7139,26 @@ async function profilesUpdateCommand(options) {
|
|
|
6817
7139
|
options
|
|
6818
7140
|
);
|
|
6819
7141
|
} catch (error) {
|
|
6820
|
-
|
|
7142
|
+
exitCommandError(error, options);
|
|
6821
7143
|
}
|
|
6822
7144
|
}
|
|
6823
7145
|
async function profilesRemoveCommand(options) {
|
|
6824
7146
|
try {
|
|
6825
|
-
const id = options.id ??
|
|
7147
|
+
const id = options.id ?? fail("profiles remove requires --id");
|
|
6826
7148
|
if (!options.yes) {
|
|
6827
|
-
|
|
7149
|
+
fail("profiles remove requires --yes");
|
|
6828
7150
|
}
|
|
6829
7151
|
await run2("remove", { id, yes: true }, options);
|
|
6830
7152
|
} catch (error) {
|
|
6831
|
-
|
|
7153
|
+
exitCommandError(error, options);
|
|
6832
7154
|
}
|
|
6833
7155
|
}
|
|
6834
7156
|
async function profilesSetDefaultCommand(options) {
|
|
6835
7157
|
try {
|
|
6836
|
-
const id = options.id ??
|
|
7158
|
+
const id = options.id ?? fail("profiles set-default requires --id");
|
|
6837
7159
|
await run2("set-default", { id }, options);
|
|
6838
7160
|
} catch (error) {
|
|
6839
|
-
|
|
7161
|
+
exitCommandError(error, options);
|
|
6840
7162
|
}
|
|
6841
7163
|
}
|
|
6842
7164
|
|
|
@@ -6844,14 +7166,6 @@ async function profilesSetDefaultCommand(options) {
|
|
|
6844
7166
|
init_esm_shims();
|
|
6845
7167
|
init_api();
|
|
6846
7168
|
init_tui();
|
|
6847
|
-
import process13 from "process";
|
|
6848
|
-
var writeJson5 = (value) => {
|
|
6849
|
-
process13.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
6850
|
-
`);
|
|
6851
|
-
};
|
|
6852
|
-
var fail3 = (message) => {
|
|
6853
|
-
throw new Error(message);
|
|
6854
|
-
};
|
|
6855
7169
|
var run3 = async (command, args, options) => {
|
|
6856
7170
|
const apiOptions = {
|
|
6857
7171
|
...options.server ? { serverUrl: options.server } : {},
|
|
@@ -6866,39 +7180,34 @@ var run3 = async (command, args, options) => {
|
|
|
6866
7180
|
apiOptions
|
|
6867
7181
|
);
|
|
6868
7182
|
if (options.json) {
|
|
6869
|
-
|
|
7183
|
+
writeJson(result);
|
|
6870
7184
|
return;
|
|
6871
7185
|
}
|
|
6872
7186
|
log.success(`projects ${command} completed`);
|
|
6873
7187
|
};
|
|
6874
|
-
var exitWithError4 = (error) => {
|
|
6875
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
6876
|
-
log.error(message);
|
|
6877
|
-
process13.exit(1);
|
|
6878
|
-
};
|
|
6879
7188
|
async function projectsGetCommand(options) {
|
|
6880
7189
|
try {
|
|
6881
|
-
const id = options.id ??
|
|
7190
|
+
const id = options.id ?? fail("projects get requires --id");
|
|
6882
7191
|
await run3("get", { id }, options);
|
|
6883
7192
|
} catch (error) {
|
|
6884
|
-
|
|
7193
|
+
exitCommandError(error, options);
|
|
6885
7194
|
}
|
|
6886
7195
|
}
|
|
6887
7196
|
async function projectsCreateCommand(options) {
|
|
6888
7197
|
try {
|
|
6889
|
-
const name = options.name ??
|
|
7198
|
+
const name = options.name ?? fail("projects create requires --name");
|
|
6890
7199
|
await run3(
|
|
6891
7200
|
"create",
|
|
6892
7201
|
{ name, description: options.description, orgId: options.orgId },
|
|
6893
7202
|
options
|
|
6894
7203
|
);
|
|
6895
7204
|
} catch (error) {
|
|
6896
|
-
|
|
7205
|
+
exitCommandError(error, options);
|
|
6897
7206
|
}
|
|
6898
7207
|
}
|
|
6899
7208
|
async function projectsUpdateCommand(options) {
|
|
6900
7209
|
try {
|
|
6901
|
-
const id = options.id ??
|
|
7210
|
+
const id = options.id ?? fail("projects update requires --id");
|
|
6902
7211
|
await run3(
|
|
6903
7212
|
"update",
|
|
6904
7213
|
{
|
|
@@ -6909,18 +7218,18 @@ async function projectsUpdateCommand(options) {
|
|
|
6909
7218
|
options
|
|
6910
7219
|
);
|
|
6911
7220
|
} catch (error) {
|
|
6912
|
-
|
|
7221
|
+
exitCommandError(error, options);
|
|
6913
7222
|
}
|
|
6914
7223
|
}
|
|
6915
7224
|
async function projectsRemoveCommand(options) {
|
|
6916
7225
|
try {
|
|
6917
|
-
const id = options.id ??
|
|
7226
|
+
const id = options.id ?? fail("projects remove requires --id");
|
|
6918
7227
|
if (!options.yes) {
|
|
6919
|
-
|
|
7228
|
+
fail("projects remove requires --yes");
|
|
6920
7229
|
}
|
|
6921
7230
|
await run3("remove", { id, yes: true }, options);
|
|
6922
7231
|
} catch (error) {
|
|
6923
|
-
|
|
7232
|
+
exitCommandError(error, options);
|
|
6924
7233
|
}
|
|
6925
7234
|
}
|
|
6926
7235
|
|
|
@@ -6928,11 +7237,6 @@ async function projectsRemoveCommand(options) {
|
|
|
6928
7237
|
init_esm_shims();
|
|
6929
7238
|
init_api();
|
|
6930
7239
|
init_tui();
|
|
6931
|
-
import process14 from "process";
|
|
6932
|
-
var writeJson6 = (value) => {
|
|
6933
|
-
process14.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
6934
|
-
`);
|
|
6935
|
-
};
|
|
6936
7240
|
var parseCsv3 = (input) => {
|
|
6937
7241
|
if (!input) {
|
|
6938
7242
|
return void 0;
|
|
@@ -6940,14 +7244,6 @@ var parseCsv3 = (input) => {
|
|
|
6940
7244
|
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
6941
7245
|
return values.length > 0 ? values : void 0;
|
|
6942
7246
|
};
|
|
6943
|
-
var exitWithError5 = (error) => {
|
|
6944
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
6945
|
-
log.error(message);
|
|
6946
|
-
process14.exit(1);
|
|
6947
|
-
};
|
|
6948
|
-
var fail4 = (message) => {
|
|
6949
|
-
throw new Error(message);
|
|
6950
|
-
};
|
|
6951
7247
|
var run4 = async (command, args, options) => {
|
|
6952
7248
|
const apiOptions = {
|
|
6953
7249
|
...options.server ? { serverUrl: options.server } : {},
|
|
@@ -6962,69 +7258,69 @@ var run4 = async (command, args, options) => {
|
|
|
6962
7258
|
apiOptions
|
|
6963
7259
|
);
|
|
6964
7260
|
if (options.json) {
|
|
6965
|
-
|
|
7261
|
+
writeJson(result);
|
|
6966
7262
|
return;
|
|
6967
7263
|
}
|
|
6968
7264
|
log.success(`references ${command} completed`);
|
|
6969
7265
|
};
|
|
6970
7266
|
async function referencesListCommand(options) {
|
|
6971
7267
|
try {
|
|
6972
|
-
const ruleId = options.ruleId ??
|
|
7268
|
+
const ruleId = options.ruleId ?? fail("references list requires --rule-id");
|
|
6973
7269
|
await run4("list", { ruleId }, options);
|
|
6974
7270
|
} catch (error) {
|
|
6975
|
-
|
|
7271
|
+
exitCommandError(error, options);
|
|
6976
7272
|
}
|
|
6977
7273
|
}
|
|
6978
7274
|
async function referencesGetCommand(options) {
|
|
6979
7275
|
try {
|
|
6980
|
-
const id = options.id ??
|
|
7276
|
+
const id = options.id ?? fail("references get requires --id");
|
|
6981
7277
|
await run4("get", { id }, options);
|
|
6982
7278
|
} catch (error) {
|
|
6983
|
-
|
|
7279
|
+
exitCommandError(error, options);
|
|
6984
7280
|
}
|
|
6985
7281
|
}
|
|
6986
7282
|
async function referencesCreateCommand(options) {
|
|
6987
7283
|
try {
|
|
6988
|
-
const ruleId = options.ruleId ??
|
|
6989
|
-
const file = options.file ??
|
|
7284
|
+
const ruleId = options.ruleId ?? fail("references create requires --rule-id");
|
|
7285
|
+
const file = options.file ?? fail("references create requires --file");
|
|
6990
7286
|
await run4("create", { ruleId, file }, options);
|
|
6991
7287
|
} catch (error) {
|
|
6992
|
-
|
|
7288
|
+
exitCommandError(error, options);
|
|
6993
7289
|
}
|
|
6994
7290
|
}
|
|
6995
7291
|
async function referencesUpdateCommand(options) {
|
|
6996
7292
|
try {
|
|
6997
|
-
const id = options.id ??
|
|
7293
|
+
const id = options.id ?? fail("references update requires --id");
|
|
6998
7294
|
await run4(
|
|
6999
7295
|
"update",
|
|
7000
7296
|
{ id, label: options.label, replaceFile: options.replaceFile },
|
|
7001
7297
|
options
|
|
7002
7298
|
);
|
|
7003
7299
|
} catch (error) {
|
|
7004
|
-
|
|
7300
|
+
exitCommandError(error, options);
|
|
7005
7301
|
}
|
|
7006
7302
|
}
|
|
7007
7303
|
async function referencesRemoveCommand(options) {
|
|
7008
7304
|
try {
|
|
7009
|
-
const id = options.id ??
|
|
7305
|
+
const id = options.id ?? fail("references remove requires --id");
|
|
7010
7306
|
if (!options.yes) {
|
|
7011
|
-
|
|
7307
|
+
fail("references remove requires --yes");
|
|
7012
7308
|
}
|
|
7013
7309
|
await run4("remove", { id, yes: true }, options);
|
|
7014
7310
|
} catch (error) {
|
|
7015
|
-
|
|
7311
|
+
exitCommandError(error, options);
|
|
7016
7312
|
}
|
|
7017
7313
|
}
|
|
7018
7314
|
async function referencesReorderCommand(options) {
|
|
7019
7315
|
try {
|
|
7020
|
-
const ruleId = options.ruleId ??
|
|
7316
|
+
const ruleId = options.ruleId ?? fail("references reorder requires --rule-id");
|
|
7021
7317
|
const orderedIds = parseCsv3(options.orderedIds);
|
|
7022
7318
|
if (!orderedIds || orderedIds.length === 0) {
|
|
7023
|
-
|
|
7319
|
+
fail("references reorder requires --ordered-ids");
|
|
7024
7320
|
}
|
|
7025
7321
|
await run4("reorder", { ruleId, orderedIds }, options);
|
|
7026
7322
|
} catch (error) {
|
|
7027
|
-
|
|
7323
|
+
exitCommandError(error, options);
|
|
7028
7324
|
}
|
|
7029
7325
|
}
|
|
7030
7326
|
|
|
@@ -7032,7 +7328,7 @@ async function referencesReorderCommand(options) {
|
|
|
7032
7328
|
init_esm_shims();
|
|
7033
7329
|
import { rm as rm7 } from "fs/promises";
|
|
7034
7330
|
import { join as join14, resolve as resolve8 } from "path";
|
|
7035
|
-
import
|
|
7331
|
+
import process13 from "process";
|
|
7036
7332
|
init_tui();
|
|
7037
7333
|
async function collectInstalledSkills(detectedAgents, options) {
|
|
7038
7334
|
const skillsToRemove = [];
|
|
@@ -7065,7 +7361,7 @@ async function selectSkillsToRemove(skillsToRemove, options) {
|
|
|
7065
7361
|
if (selected.length === 0) {
|
|
7066
7362
|
log.error(`Skill '${options.skill}' not found.`);
|
|
7067
7363
|
log.info("Run 'braid list' to see installed skills.");
|
|
7068
|
-
|
|
7364
|
+
process13.exit(1);
|
|
7069
7365
|
}
|
|
7070
7366
|
return selected;
|
|
7071
7367
|
}
|
|
@@ -7084,7 +7380,7 @@ async function selectSkillsToRemove(skillsToRemove, options) {
|
|
|
7084
7380
|
});
|
|
7085
7381
|
if (isCancel(result)) {
|
|
7086
7382
|
cancel("Remove cancelled.");
|
|
7087
|
-
|
|
7383
|
+
process13.exit(0);
|
|
7088
7384
|
}
|
|
7089
7385
|
return result;
|
|
7090
7386
|
}
|
|
@@ -7098,7 +7394,7 @@ async function confirmRemoval(selectedCount, options) {
|
|
|
7098
7394
|
});
|
|
7099
7395
|
if (isCancel(confirmed) || !confirmed) {
|
|
7100
7396
|
cancel("Remove cancelled.");
|
|
7101
|
-
|
|
7397
|
+
process13.exit(0);
|
|
7102
7398
|
}
|
|
7103
7399
|
}
|
|
7104
7400
|
async function removeSkill(skill, removeSpinner) {
|
|
@@ -7162,7 +7458,7 @@ async function removeCommand(options) {
|
|
|
7162
7458
|
removeSpinner.stop("Remove failed");
|
|
7163
7459
|
const message = error instanceof Error ? error.message : String(error);
|
|
7164
7460
|
log.error(message);
|
|
7165
|
-
|
|
7461
|
+
process13.exit(1);
|
|
7166
7462
|
}
|
|
7167
7463
|
}
|
|
7168
7464
|
|
|
@@ -7221,6 +7517,7 @@ async function retractCommand(source, _options) {
|
|
|
7221
7517
|
// src/commands/rollback.ts
|
|
7222
7518
|
init_esm_shims();
|
|
7223
7519
|
init_api();
|
|
7520
|
+
init_config();
|
|
7224
7521
|
init_lockfile();
|
|
7225
7522
|
init_tui();
|
|
7226
7523
|
var PUBLIC_SOURCE_REGEX2 = /^@([a-z0-9-]+)\/([a-z0-9-]+)$/;
|
|
@@ -7239,7 +7536,8 @@ async function findPreviousActiveVersion(args) {
|
|
|
7239
7536
|
args.slug,
|
|
7240
7537
|
args.ruleIds,
|
|
7241
7538
|
args.server,
|
|
7242
|
-
v
|
|
7539
|
+
v,
|
|
7540
|
+
args.apiKey
|
|
7243
7541
|
);
|
|
7244
7542
|
return { version: v, response };
|
|
7245
7543
|
} catch (error) {
|
|
@@ -7253,6 +7551,8 @@ async function findPreviousActiveVersion(args) {
|
|
|
7253
7551
|
return null;
|
|
7254
7552
|
}
|
|
7255
7553
|
async function rollbackCommand(source, options) {
|
|
7554
|
+
const config = await loadMergedConfigAsync();
|
|
7555
|
+
const serverUrl = options.server ?? config.serverUrl;
|
|
7256
7556
|
intro(`Rolling back ${source}`);
|
|
7257
7557
|
const rollbackSpinner = spinner();
|
|
7258
7558
|
rollbackSpinner.start("Reading lockfile...");
|
|
@@ -7317,7 +7617,8 @@ async function rollbackCommand(source, options) {
|
|
|
7317
7617
|
slug: publicSource.slug,
|
|
7318
7618
|
currentVersion: parsed.version,
|
|
7319
7619
|
ruleIds: currentValue.ruleIds,
|
|
7320
|
-
server:
|
|
7620
|
+
server: serverUrl,
|
|
7621
|
+
apiKey: config.token
|
|
7321
7622
|
});
|
|
7322
7623
|
if (!result) {
|
|
7323
7624
|
rollbackSpinner.stop("No active version found");
|
|
@@ -7360,7 +7661,6 @@ async function rollbackCommand(source, options) {
|
|
|
7360
7661
|
init_esm_shims();
|
|
7361
7662
|
init_api();
|
|
7362
7663
|
init_tui();
|
|
7363
|
-
import process16 from "process";
|
|
7364
7664
|
var parseCsv4 = (input) => {
|
|
7365
7665
|
if (!input) {
|
|
7366
7666
|
return void 0;
|
|
@@ -7368,18 +7668,6 @@ var parseCsv4 = (input) => {
|
|
|
7368
7668
|
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
7369
7669
|
return values.length > 0 ? values : void 0;
|
|
7370
7670
|
};
|
|
7371
|
-
var writeJson7 = (value) => {
|
|
7372
|
-
process16.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
7373
|
-
`);
|
|
7374
|
-
};
|
|
7375
|
-
var exitWithError6 = (error) => {
|
|
7376
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
7377
|
-
log.error(message);
|
|
7378
|
-
process16.exit(1);
|
|
7379
|
-
};
|
|
7380
|
-
var fail5 = (message) => {
|
|
7381
|
-
throw new Error(message);
|
|
7382
|
-
};
|
|
7383
7671
|
var run5 = async (command, args, options) => {
|
|
7384
7672
|
const apiOptions = {
|
|
7385
7673
|
...options.server ? { serverUrl: options.server } : {},
|
|
@@ -7394,23 +7682,23 @@ var run5 = async (command, args, options) => {
|
|
|
7394
7682
|
apiOptions
|
|
7395
7683
|
);
|
|
7396
7684
|
if (options.json) {
|
|
7397
|
-
|
|
7685
|
+
writeJson(result);
|
|
7398
7686
|
return;
|
|
7399
7687
|
}
|
|
7400
7688
|
log.success(`rules ${command} completed`);
|
|
7401
7689
|
};
|
|
7402
7690
|
async function rulesGetCommand(options) {
|
|
7403
7691
|
try {
|
|
7404
|
-
const id = options.id ??
|
|
7692
|
+
const id = options.id ?? fail("rules get requires --id");
|
|
7405
7693
|
await run5("get", { id }, options);
|
|
7406
7694
|
} catch (error) {
|
|
7407
|
-
|
|
7695
|
+
exitCommandError(error, options);
|
|
7408
7696
|
}
|
|
7409
7697
|
}
|
|
7410
7698
|
async function rulesCreateCommand(options) {
|
|
7411
7699
|
try {
|
|
7412
|
-
const title = options.title ??
|
|
7413
|
-
const content = options.content ??
|
|
7700
|
+
const title = options.title ?? fail("rules create requires --title");
|
|
7701
|
+
const content = options.content ?? fail("rules create requires --content");
|
|
7414
7702
|
await run5(
|
|
7415
7703
|
"create",
|
|
7416
7704
|
{
|
|
@@ -7423,12 +7711,12 @@ async function rulesCreateCommand(options) {
|
|
|
7423
7711
|
options
|
|
7424
7712
|
);
|
|
7425
7713
|
} catch (error) {
|
|
7426
|
-
|
|
7714
|
+
exitCommandError(error, options);
|
|
7427
7715
|
}
|
|
7428
7716
|
}
|
|
7429
7717
|
async function rulesUpdateCommand(options) {
|
|
7430
7718
|
try {
|
|
7431
|
-
const id = options.id ??
|
|
7719
|
+
const id = options.id ?? fail("rules update requires --id");
|
|
7432
7720
|
await run5(
|
|
7433
7721
|
"update",
|
|
7434
7722
|
{
|
|
@@ -7441,120 +7729,120 @@ async function rulesUpdateCommand(options) {
|
|
|
7441
7729
|
options
|
|
7442
7730
|
);
|
|
7443
7731
|
} catch (error) {
|
|
7444
|
-
|
|
7732
|
+
exitCommandError(error, options);
|
|
7445
7733
|
}
|
|
7446
7734
|
}
|
|
7447
7735
|
async function rulesRemoveCommand(options) {
|
|
7448
7736
|
try {
|
|
7449
|
-
const id = options.id ??
|
|
7737
|
+
const id = options.id ?? fail("rules remove requires --id");
|
|
7450
7738
|
if (!options.yes) {
|
|
7451
|
-
|
|
7739
|
+
fail("rules remove requires --yes");
|
|
7452
7740
|
}
|
|
7453
7741
|
await run5("remove", { id, yes: true }, options);
|
|
7454
7742
|
} catch (error) {
|
|
7455
|
-
|
|
7743
|
+
exitCommandError(error, options);
|
|
7456
7744
|
}
|
|
7457
7745
|
}
|
|
7458
7746
|
async function rulesEnableCommand(options) {
|
|
7459
7747
|
try {
|
|
7460
|
-
const id = options.id ??
|
|
7748
|
+
const id = options.id ?? fail("rules enable requires --id");
|
|
7461
7749
|
await run5("enable", { id }, options);
|
|
7462
7750
|
} catch (error) {
|
|
7463
|
-
|
|
7751
|
+
exitCommandError(error, options);
|
|
7464
7752
|
}
|
|
7465
7753
|
}
|
|
7466
7754
|
async function rulesDisableCommand(options) {
|
|
7467
7755
|
try {
|
|
7468
|
-
const id = options.id ??
|
|
7756
|
+
const id = options.id ?? fail("rules disable requires --id");
|
|
7469
7757
|
await run5("disable", { id }, options);
|
|
7470
7758
|
} catch (error) {
|
|
7471
|
-
|
|
7759
|
+
exitCommandError(error, options);
|
|
7472
7760
|
}
|
|
7473
7761
|
}
|
|
7474
7762
|
async function rulesMoveCommand(options) {
|
|
7475
7763
|
try {
|
|
7476
|
-
const id = options.id ??
|
|
7477
|
-
const projectId = options.projectId ??
|
|
7764
|
+
const id = options.id ?? fail("rules move requires --id");
|
|
7765
|
+
const projectId = options.projectId ?? fail("rules move requires --project-id");
|
|
7478
7766
|
await run5("move", { id, projectId }, options);
|
|
7479
7767
|
} catch (error) {
|
|
7480
|
-
|
|
7768
|
+
exitCommandError(error, options);
|
|
7481
7769
|
}
|
|
7482
7770
|
}
|
|
7483
7771
|
async function rulesDuplicateCommand(options) {
|
|
7484
7772
|
try {
|
|
7485
|
-
const id = options.id ??
|
|
7773
|
+
const id = options.id ?? fail("rules duplicate requires --id");
|
|
7486
7774
|
await run5(
|
|
7487
7775
|
"duplicate",
|
|
7488
7776
|
{ id, targetProjectId: options.targetProjectId },
|
|
7489
7777
|
options
|
|
7490
7778
|
);
|
|
7491
7779
|
} catch (error) {
|
|
7492
|
-
|
|
7780
|
+
exitCommandError(error, options);
|
|
7493
7781
|
}
|
|
7494
7782
|
}
|
|
7495
7783
|
async function rulesForkCommand(options) {
|
|
7496
7784
|
try {
|
|
7497
|
-
const id = options.id ??
|
|
7785
|
+
const id = options.id ?? fail("rules fork requires --id");
|
|
7498
7786
|
await run5(
|
|
7499
7787
|
"fork",
|
|
7500
7788
|
{ id, targetProjectId: options.targetProjectId },
|
|
7501
7789
|
options
|
|
7502
7790
|
);
|
|
7503
7791
|
} catch (error) {
|
|
7504
|
-
|
|
7792
|
+
exitCommandError(error, options);
|
|
7505
7793
|
}
|
|
7506
7794
|
}
|
|
7507
7795
|
async function rulesSyncStatusCommand(options) {
|
|
7508
7796
|
try {
|
|
7509
7797
|
await run5("sync-status", { id: options.id }, options);
|
|
7510
7798
|
} catch (error) {
|
|
7511
|
-
|
|
7799
|
+
exitCommandError(error, options);
|
|
7512
7800
|
}
|
|
7513
7801
|
}
|
|
7514
7802
|
async function rulesSyncHistoryCommand(options) {
|
|
7515
7803
|
try {
|
|
7516
|
-
const id = options.id ??
|
|
7804
|
+
const id = options.id ?? fail("rules sync-history requires --id");
|
|
7517
7805
|
await run5("sync-history", { id }, options);
|
|
7518
7806
|
} catch (error) {
|
|
7519
|
-
|
|
7807
|
+
exitCommandError(error, options);
|
|
7520
7808
|
}
|
|
7521
7809
|
}
|
|
7522
7810
|
async function rulesSyncEnableCommand(options) {
|
|
7523
7811
|
try {
|
|
7524
|
-
const id = options.id ??
|
|
7812
|
+
const id = options.id ?? fail("rules sync-enable requires --id");
|
|
7525
7813
|
await run5("sync-enable", { id }, options);
|
|
7526
7814
|
} catch (error) {
|
|
7527
|
-
|
|
7815
|
+
exitCommandError(error, options);
|
|
7528
7816
|
}
|
|
7529
7817
|
}
|
|
7530
7818
|
async function rulesSyncDisableCommand(options) {
|
|
7531
7819
|
try {
|
|
7532
|
-
const id = options.id ??
|
|
7820
|
+
const id = options.id ?? fail("rules sync-disable requires --id");
|
|
7533
7821
|
await run5("sync-disable", { id }, options);
|
|
7534
7822
|
} catch (error) {
|
|
7535
|
-
|
|
7823
|
+
exitCommandError(error, options);
|
|
7536
7824
|
}
|
|
7537
7825
|
}
|
|
7538
7826
|
async function rulesSyncCheckCommand(options) {
|
|
7539
7827
|
try {
|
|
7540
|
-
const id = options.id ??
|
|
7828
|
+
const id = options.id ?? fail("rules sync-check requires --id");
|
|
7541
7829
|
await run5("sync-check", { id }, options);
|
|
7542
7830
|
} catch (error) {
|
|
7543
|
-
|
|
7831
|
+
exitCommandError(error, options);
|
|
7544
7832
|
}
|
|
7545
7833
|
}
|
|
7546
7834
|
async function rulesSyncNowCommand(options) {
|
|
7547
7835
|
try {
|
|
7548
|
-
const id = options.id ??
|
|
7836
|
+
const id = options.id ?? fail("rules sync-now requires --id");
|
|
7549
7837
|
await run5("sync-now", { id }, options);
|
|
7550
7838
|
} catch (error) {
|
|
7551
|
-
|
|
7839
|
+
exitCommandError(error, options);
|
|
7552
7840
|
}
|
|
7553
7841
|
}
|
|
7554
7842
|
|
|
7555
7843
|
// src/commands/scaffold.ts
|
|
7556
7844
|
init_esm_shims();
|
|
7557
|
-
import
|
|
7845
|
+
import process14 from "process";
|
|
7558
7846
|
|
|
7559
7847
|
// src/lib/scaffold.ts
|
|
7560
7848
|
init_esm_shims();
|
|
@@ -8514,11 +8802,11 @@ var normalizeReferenceList = (referenceLabel, availableNamesLabel, values, avail
|
|
|
8514
8802
|
};
|
|
8515
8803
|
var exitCancelled2 = () => {
|
|
8516
8804
|
cancel("Scaffold cancelled.");
|
|
8517
|
-
|
|
8805
|
+
process14.exit(0);
|
|
8518
8806
|
};
|
|
8519
|
-
var
|
|
8807
|
+
var exitWithError = (message) => {
|
|
8520
8808
|
log.error(message);
|
|
8521
|
-
|
|
8809
|
+
process14.exit(1);
|
|
8522
8810
|
};
|
|
8523
8811
|
var requirePromptValue = (value) => {
|
|
8524
8812
|
if (isCancel(value)) {
|
|
@@ -8531,7 +8819,7 @@ var resolveType = async (options) => {
|
|
|
8531
8819
|
return options.type;
|
|
8532
8820
|
}
|
|
8533
8821
|
if (options.yes) {
|
|
8534
|
-
return
|
|
8822
|
+
return exitWithError("--type is required when using --yes");
|
|
8535
8823
|
}
|
|
8536
8824
|
const selected = requirePromptValue(
|
|
8537
8825
|
await select({
|
|
@@ -8561,7 +8849,7 @@ var resolveName = async (options) => {
|
|
|
8561
8849
|
return options.name.trim();
|
|
8562
8850
|
}
|
|
8563
8851
|
if (options.yes) {
|
|
8564
|
-
return
|
|
8852
|
+
return exitWithError("--name is required when using --yes");
|
|
8565
8853
|
}
|
|
8566
8854
|
const value = requirePromptValue(
|
|
8567
8855
|
await text({
|
|
@@ -8647,7 +8935,7 @@ var resolveOptionalReference = async (label, flagValue, options, availableNames)
|
|
|
8647
8935
|
return selected || void 0;
|
|
8648
8936
|
};
|
|
8649
8937
|
var buildScaffoldInput = async (options) => {
|
|
8650
|
-
const context = await inspectScaffoldDirectory(
|
|
8938
|
+
const context = await inspectScaffoldDirectory(process14.cwd());
|
|
8651
8939
|
const availableSkillNames = context.manifest.skills.map(
|
|
8652
8940
|
(entry) => entry.name
|
|
8653
8941
|
);
|
|
@@ -8701,7 +8989,7 @@ var buildScaffoldInput = async (options) => {
|
|
|
8701
8989
|
availableWorkflowNames
|
|
8702
8990
|
) : void 0;
|
|
8703
8991
|
return {
|
|
8704
|
-
cwd:
|
|
8992
|
+
cwd: process14.cwd(),
|
|
8705
8993
|
type,
|
|
8706
8994
|
name,
|
|
8707
8995
|
title,
|
|
@@ -8730,10 +9018,10 @@ var finishScaffoldSuccess = (type, name, createdFiles) => {
|
|
|
8730
9018
|
var isMockedProcessExitError = (error) => error instanceof Error && error.message.startsWith("process.exit:");
|
|
8731
9019
|
var handleScaffoldCommandFailure = (error) => {
|
|
8732
9020
|
if (error instanceof ScaffoldError) {
|
|
8733
|
-
|
|
9021
|
+
exitWithError(error.message);
|
|
8734
9022
|
}
|
|
8735
9023
|
if (error instanceof Error && !isMockedProcessExitError(error)) {
|
|
8736
|
-
|
|
9024
|
+
exitWithError(error.message);
|
|
8737
9025
|
}
|
|
8738
9026
|
throw error;
|
|
8739
9027
|
};
|