@braid-cloud/cli 0.1.8 → 0.1.10
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 +48 -34
- package/dist/index.js +1093 -104
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -322,7 +322,7 @@ var init_config = __esm({
|
|
|
322
322
|
|
|
323
323
|
// src/lib/api.ts
|
|
324
324
|
import { Data as Data2, Effect as Effect2, pipe as pipe2 } from "effect";
|
|
325
|
-
var TRAILING_SLASH_REGEX, ApiError, AuthenticationError, NetworkError, resolveApiKey, resolveServerUrl, parseResponse, buildApiUrl, buildExportUrl, executeApiRequest, parseScopeOptionsResponse, fetchScopeOptions, buildRuleOptionsUrl, fetchRuleOptions, fetchSkills, validateApiKey, fetchSkillsAsync, validateApiKeyAsync, fetchScopeOptionsAsync, fetchRuleOptionsAsync;
|
|
325
|
+
var TRAILING_SLASH_REGEX, ApiError, AuthenticationError, NetworkError, resolveApiKey, resolveServerUrl, parseResponse, buildApiUrl, buildExportUrl, executeApiRequest, parseScopeOptionsResponse, fetchScopeOptions, buildRuleOptionsUrl, fetchRuleOptions, fetchSkills, runLifecycleCommand, DEFAULT_PUBLIC_SERVER_URL, NotFoundError, RateLimitedError, handlePublicApiResponse, fetchPublicMetadata, fetchPublicExport, fetchPublicMetadataAsync, fetchPublicExportAsync, validateApiKey, fetchSkillsAsync, validateApiKeyAsync, fetchScopeOptionsAsync, fetchRuleOptionsAsync, runLifecycleCommandAsync;
|
|
326
326
|
var init_api = __esm({
|
|
327
327
|
"src/lib/api.ts"() {
|
|
328
328
|
"use strict";
|
|
@@ -579,6 +579,145 @@ var init_api = __esm({
|
|
|
579
579
|
return executeApiRequest(url, apiKey, serverUrl);
|
|
580
580
|
})
|
|
581
581
|
);
|
|
582
|
+
runLifecycleCommand = (request, options = {}) => pipe2(
|
|
583
|
+
Effect2.all({
|
|
584
|
+
apiKey: resolveApiKey(options.apiKey),
|
|
585
|
+
serverUrl: resolveServerUrl(options.serverUrl)
|
|
586
|
+
}),
|
|
587
|
+
Effect2.flatMap(
|
|
588
|
+
({ apiKey, serverUrl }) => Effect2.tryPromise({
|
|
589
|
+
try: async () => {
|
|
590
|
+
const response = await fetch(
|
|
591
|
+
buildApiUrl(serverUrl, "/api/lifecycle").toString(),
|
|
592
|
+
{
|
|
593
|
+
method: "POST",
|
|
594
|
+
headers: {
|
|
595
|
+
Authorization: `Bearer ${apiKey}`,
|
|
596
|
+
"Content-Type": "application/json"
|
|
597
|
+
},
|
|
598
|
+
body: JSON.stringify(request)
|
|
599
|
+
}
|
|
600
|
+
);
|
|
601
|
+
const json = await response.json();
|
|
602
|
+
if (!response.ok) {
|
|
603
|
+
const errorResponse = json;
|
|
604
|
+
if (response.status === 401) {
|
|
605
|
+
throw new AuthenticationError({
|
|
606
|
+
message: errorResponse.error || "Invalid or expired API key. Run 'braid auth' to re-authenticate."
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
throw new ApiError({
|
|
610
|
+
message: errorResponse.error || "API request failed",
|
|
611
|
+
code: errorResponse.code || "UNKNOWN_ERROR",
|
|
612
|
+
status: response.status
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
return json;
|
|
616
|
+
},
|
|
617
|
+
catch: (error) => {
|
|
618
|
+
if (error instanceof ApiError || error instanceof AuthenticationError || error instanceof NetworkError) {
|
|
619
|
+
return error;
|
|
620
|
+
}
|
|
621
|
+
return new NetworkError({
|
|
622
|
+
message: `Failed to connect to ${serverUrl}`,
|
|
623
|
+
cause: error
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
})
|
|
627
|
+
)
|
|
628
|
+
);
|
|
629
|
+
DEFAULT_PUBLIC_SERVER_URL = "https://braid.cloud";
|
|
630
|
+
NotFoundError = class extends Data2.TaggedError("NotFoundError") {
|
|
631
|
+
};
|
|
632
|
+
RateLimitedError = class extends Data2.TaggedError("RateLimitedError") {
|
|
633
|
+
};
|
|
634
|
+
handlePublicApiResponse = (response, json) => {
|
|
635
|
+
if (response.ok) {
|
|
636
|
+
return Effect2.succeed(json);
|
|
637
|
+
}
|
|
638
|
+
if (response.status === 404) {
|
|
639
|
+
return Effect2.fail(
|
|
640
|
+
new NotFoundError({ message: "Public content not found" })
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
if (response.status === 429) {
|
|
644
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
645
|
+
const retryMs = retryAfter ? Number(retryAfter) * 1e3 : null;
|
|
646
|
+
return Effect2.fail(
|
|
647
|
+
new RateLimitedError({
|
|
648
|
+
message: "Rate limited. Please try again later.",
|
|
649
|
+
...retryMs !== null ? { retryAfterMs: retryMs } : {}
|
|
650
|
+
})
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
const errorResponse = json;
|
|
654
|
+
return Effect2.fail(
|
|
655
|
+
new ApiError({
|
|
656
|
+
message: errorResponse.error || "API request failed",
|
|
657
|
+
code: errorResponse.code || "UNKNOWN_ERROR",
|
|
658
|
+
status: response.status
|
|
659
|
+
})
|
|
660
|
+
);
|
|
661
|
+
};
|
|
662
|
+
fetchPublicMetadata = (handle, slug, serverUrl) => {
|
|
663
|
+
const baseUrl = (serverUrl ?? DEFAULT_PUBLIC_SERVER_URL).replace(
|
|
664
|
+
TRAILING_SLASH_REGEX,
|
|
665
|
+
""
|
|
666
|
+
);
|
|
667
|
+
const url = `${baseUrl}/api/public/@${handle}/${slug}`;
|
|
668
|
+
return pipe2(
|
|
669
|
+
Effect2.tryPromise({
|
|
670
|
+
try: () => fetch(url, { method: "GET" }),
|
|
671
|
+
catch: (e) => new NetworkError({
|
|
672
|
+
message: `Failed to connect to ${baseUrl}`,
|
|
673
|
+
cause: e
|
|
674
|
+
})
|
|
675
|
+
}),
|
|
676
|
+
Effect2.flatMap(
|
|
677
|
+
(response) => pipe2(
|
|
678
|
+
Effect2.tryPromise({
|
|
679
|
+
try: () => response.json(),
|
|
680
|
+
catch: () => new NetworkError({ message: "Failed to parse API response" })
|
|
681
|
+
}),
|
|
682
|
+
Effect2.flatMap(
|
|
683
|
+
(json) => handlePublicApiResponse(response, json)
|
|
684
|
+
)
|
|
685
|
+
)
|
|
686
|
+
)
|
|
687
|
+
);
|
|
688
|
+
};
|
|
689
|
+
fetchPublicExport = (handle, slug, ruleIds, serverUrl) => {
|
|
690
|
+
const baseUrl = (serverUrl ?? DEFAULT_PUBLIC_SERVER_URL).replace(
|
|
691
|
+
TRAILING_SLASH_REGEX,
|
|
692
|
+
""
|
|
693
|
+
);
|
|
694
|
+
const url = new URL(`${baseUrl}/api/public/@${handle}/${slug}/export`);
|
|
695
|
+
if (ruleIds && ruleIds.length > 0) {
|
|
696
|
+
url.searchParams.set("ruleIds", ruleIds.join(","));
|
|
697
|
+
}
|
|
698
|
+
return pipe2(
|
|
699
|
+
Effect2.tryPromise({
|
|
700
|
+
try: () => fetch(url.toString(), { method: "GET" }),
|
|
701
|
+
catch: (e) => new NetworkError({
|
|
702
|
+
message: `Failed to connect to ${baseUrl}`,
|
|
703
|
+
cause: e
|
|
704
|
+
})
|
|
705
|
+
}),
|
|
706
|
+
Effect2.flatMap(
|
|
707
|
+
(response) => pipe2(
|
|
708
|
+
Effect2.tryPromise({
|
|
709
|
+
try: () => response.json(),
|
|
710
|
+
catch: () => new NetworkError({ message: "Failed to parse API response" })
|
|
711
|
+
}),
|
|
712
|
+
Effect2.flatMap(
|
|
713
|
+
(json) => handlePublicApiResponse(response, json)
|
|
714
|
+
)
|
|
715
|
+
)
|
|
716
|
+
)
|
|
717
|
+
);
|
|
718
|
+
};
|
|
719
|
+
fetchPublicMetadataAsync = (handle, slug, serverUrl) => Effect2.runPromise(fetchPublicMetadata(handle, slug, serverUrl));
|
|
720
|
+
fetchPublicExportAsync = (handle, slug, ruleIds, serverUrl) => Effect2.runPromise(fetchPublicExport(handle, slug, ruleIds, serverUrl));
|
|
582
721
|
validateApiKey = (apiKey, serverUrl) => pipe2(
|
|
583
722
|
Effect2.tryPromise({
|
|
584
723
|
try: async () => {
|
|
@@ -604,6 +743,7 @@ var init_api = __esm({
|
|
|
604
743
|
validateApiKeyAsync = (apiKey, serverUrl) => Effect2.runPromise(validateApiKey(apiKey, serverUrl));
|
|
605
744
|
fetchScopeOptionsAsync = (options = {}) => Effect2.runPromise(fetchScopeOptions(options));
|
|
606
745
|
fetchRuleOptionsAsync = (options = {}) => Effect2.runPromise(fetchRuleOptions(options));
|
|
746
|
+
runLifecycleCommandAsync = (request, options = {}) => Effect2.runPromise(runLifecycleCommand(request, options));
|
|
607
747
|
}
|
|
608
748
|
});
|
|
609
749
|
|
|
@@ -922,10 +1062,10 @@ async function selectProjects(organizationContext, scopeOptions) {
|
|
|
922
1062
|
}
|
|
923
1063
|
return selected.length > 0 ? selected : void 0;
|
|
924
1064
|
}
|
|
925
|
-
async function pickRuleIds(message,
|
|
1065
|
+
async function pickRuleIds(message, rules2) {
|
|
926
1066
|
const selected = await multiselect({
|
|
927
1067
|
message,
|
|
928
|
-
options:
|
|
1068
|
+
options: rules2.map((rule) => ({
|
|
929
1069
|
value: rule.id,
|
|
930
1070
|
label: rule.title,
|
|
931
1071
|
hint: rule.id
|
|
@@ -1191,7 +1331,7 @@ async function authCommand(options) {
|
|
|
1191
1331
|
return;
|
|
1192
1332
|
}
|
|
1193
1333
|
}
|
|
1194
|
-
const apiKey = await password({
|
|
1334
|
+
const apiKey = options.token ? options.token : await password({
|
|
1195
1335
|
message: "Enter your braid API key:",
|
|
1196
1336
|
validate: (value) => {
|
|
1197
1337
|
if (!value) {
|
|
@@ -1233,7 +1373,9 @@ async function authCommand(options) {
|
|
|
1233
1373
|
await saveUserConfigAsync({ ...existingUserConfig, token: apiKey });
|
|
1234
1374
|
}
|
|
1235
1375
|
stopAuthSpinner("API key validated and saved");
|
|
1236
|
-
|
|
1376
|
+
if (options.scope !== false) {
|
|
1377
|
+
await configureDefaultScopeAsync(serverUrl);
|
|
1378
|
+
}
|
|
1237
1379
|
log.success(`Config saved to ${CONFIG_FILE}`);
|
|
1238
1380
|
outro(
|
|
1239
1381
|
"You're authenticated! Run 'braid install --profile <name>' to install skills."
|
|
@@ -1301,6 +1443,142 @@ async function authLogoutCommand() {
|
|
|
1301
1443
|
log.success("Logged out. API key removed from config.");
|
|
1302
1444
|
}
|
|
1303
1445
|
|
|
1446
|
+
// src/commands/discover.ts
|
|
1447
|
+
init_esm_shims();
|
|
1448
|
+
init_api();
|
|
1449
|
+
init_config();
|
|
1450
|
+
init_tui();
|
|
1451
|
+
import process6 from "process";
|
|
1452
|
+
var parseCsv = (input) => {
|
|
1453
|
+
if (!input) {
|
|
1454
|
+
return void 0;
|
|
1455
|
+
}
|
|
1456
|
+
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
1457
|
+
return values.length > 0 ? values : void 0;
|
|
1458
|
+
};
|
|
1459
|
+
var writeJson = (value) => {
|
|
1460
|
+
process6.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
1461
|
+
`);
|
|
1462
|
+
};
|
|
1463
|
+
var exitWithError = (error) => {
|
|
1464
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1465
|
+
log.error(message);
|
|
1466
|
+
process6.exit(1);
|
|
1467
|
+
};
|
|
1468
|
+
var applyCommonOptions = (base, options) => ({
|
|
1469
|
+
...base,
|
|
1470
|
+
...options.server ? { serverUrl: options.server } : {},
|
|
1471
|
+
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
1472
|
+
});
|
|
1473
|
+
var applyOptionalString = (target, key, value) => {
|
|
1474
|
+
if (value) {
|
|
1475
|
+
target[key] = value;
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
var applyOptionalArray = (target, key, value) => {
|
|
1479
|
+
if (value && value.length > 0) {
|
|
1480
|
+
target[key] = value;
|
|
1481
|
+
}
|
|
1482
|
+
};
|
|
1483
|
+
var applyOptionalBoolean = (target, key, value) => {
|
|
1484
|
+
if (value !== void 0) {
|
|
1485
|
+
target[key] = value;
|
|
1486
|
+
}
|
|
1487
|
+
};
|
|
1488
|
+
async function projectsListCommand(options) {
|
|
1489
|
+
try {
|
|
1490
|
+
const result = await fetchScopeOptionsAsync(
|
|
1491
|
+
applyCommonOptions({}, options)
|
|
1492
|
+
);
|
|
1493
|
+
if (options.json) {
|
|
1494
|
+
writeJson(result);
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
log.info("Personal projects:");
|
|
1498
|
+
if (result.personalProjects.length === 0) {
|
|
1499
|
+
log.info(" (none)");
|
|
1500
|
+
}
|
|
1501
|
+
for (const project of result.personalProjects) {
|
|
1502
|
+
log.info(` ${project.id} ${project.name}`);
|
|
1503
|
+
}
|
|
1504
|
+
for (const orgProjects of result.orgProjects) {
|
|
1505
|
+
log.info(`
|
|
1506
|
+
Organization: ${orgProjects.orgName} (${orgProjects.orgId})`);
|
|
1507
|
+
if (orgProjects.projects.length === 0) {
|
|
1508
|
+
log.info(" (none)");
|
|
1509
|
+
continue;
|
|
1510
|
+
}
|
|
1511
|
+
for (const project of orgProjects.projects) {
|
|
1512
|
+
log.info(` ${project.id} ${project.name}`);
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
} catch (error) {
|
|
1516
|
+
exitWithError(error);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
var buildRulesRequest = async (options) => {
|
|
1520
|
+
const config = await loadMergedConfigAsync();
|
|
1521
|
+
const orgProjects = parseCsv(options.orgProjects) ?? config.orgProjects;
|
|
1522
|
+
const personalProjects = parseCsv(options.personalProjects) ?? config.personalProjects;
|
|
1523
|
+
const request = applyCommonOptions({}, options);
|
|
1524
|
+
applyOptionalString(request, "orgId", options.orgId ?? config.org);
|
|
1525
|
+
applyOptionalArray(request, "orgProjects", orgProjects);
|
|
1526
|
+
applyOptionalArray(request, "personalProjects", personalProjects);
|
|
1527
|
+
applyOptionalBoolean(request, "includeUserGlobal", options.includeUserGlobal);
|
|
1528
|
+
applyOptionalBoolean(request, "includeOrgGlobal", options.includeOrgGlobal);
|
|
1529
|
+
return request;
|
|
1530
|
+
};
|
|
1531
|
+
async function rulesListCommand(options) {
|
|
1532
|
+
try {
|
|
1533
|
+
const result = await fetchRuleOptionsAsync(
|
|
1534
|
+
await buildRulesRequest(options)
|
|
1535
|
+
);
|
|
1536
|
+
if (options.json) {
|
|
1537
|
+
writeJson(result);
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1540
|
+
if (result.rules.length === 0) {
|
|
1541
|
+
log.info("No rules found.");
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
for (const rule of result.rules) {
|
|
1545
|
+
log.info(`${rule.id} ${rule.title}`);
|
|
1546
|
+
}
|
|
1547
|
+
} catch (error) {
|
|
1548
|
+
exitWithError(error);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
var buildSkillsRequest = async (options) => {
|
|
1552
|
+
const config = await loadMergedConfigAsync();
|
|
1553
|
+
const orgProjects = parseCsv(options.orgProjects) ?? config.orgProjects;
|
|
1554
|
+
const personalProjects = parseCsv(options.personalProjects) ?? config.personalProjects;
|
|
1555
|
+
const request = applyCommonOptions({}, options);
|
|
1556
|
+
applyOptionalString(request, "profile", options.profile ?? config.profile);
|
|
1557
|
+
applyOptionalArray(request, "orgProjects", orgProjects);
|
|
1558
|
+
applyOptionalArray(request, "personalProjects", personalProjects);
|
|
1559
|
+
applyOptionalBoolean(request, "includeUserGlobal", options.includeUserGlobal);
|
|
1560
|
+
applyOptionalBoolean(request, "includeOrgGlobal", options.includeOrgGlobal);
|
|
1561
|
+
return request;
|
|
1562
|
+
};
|
|
1563
|
+
async function skillsListCommand(options) {
|
|
1564
|
+
try {
|
|
1565
|
+
const result = await fetchSkillsAsync(await buildSkillsRequest(options));
|
|
1566
|
+
if (options.json) {
|
|
1567
|
+
writeJson(result);
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
if (result.skills.length === 0) {
|
|
1571
|
+
log.info("No skills found.");
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
for (const skill of result.skills) {
|
|
1575
|
+
log.info(`${skill.name}`);
|
|
1576
|
+
}
|
|
1577
|
+
} catch (error) {
|
|
1578
|
+
exitWithError(error);
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1304
1582
|
// src/commands/install.ts
|
|
1305
1583
|
init_esm_shims();
|
|
1306
1584
|
|
|
@@ -1309,11 +1587,11 @@ init_esm_shims();
|
|
|
1309
1587
|
import { access, constants } from "fs/promises";
|
|
1310
1588
|
import { homedir as homedir2 } from "os";
|
|
1311
1589
|
import { join as join2 } from "path";
|
|
1312
|
-
import
|
|
1590
|
+
import process7 from "process";
|
|
1313
1591
|
import { Effect as Effect3, pipe as pipe3 } from "effect";
|
|
1314
1592
|
var home = homedir2();
|
|
1315
1593
|
var vscodeExtSettingsPath = (extensionId, filename) => {
|
|
1316
|
-
if (
|
|
1594
|
+
if (process7.platform === "darwin") {
|
|
1317
1595
|
return join2(
|
|
1318
1596
|
home,
|
|
1319
1597
|
"Library",
|
|
@@ -1326,8 +1604,8 @@ var vscodeExtSettingsPath = (extensionId, filename) => {
|
|
|
1326
1604
|
filename
|
|
1327
1605
|
);
|
|
1328
1606
|
}
|
|
1329
|
-
if (
|
|
1330
|
-
const appData =
|
|
1607
|
+
if (process7.platform === "win32") {
|
|
1608
|
+
const appData = process7.env.APPDATA ?? join2(home, "AppData", "Roaming");
|
|
1331
1609
|
return join2(
|
|
1332
1610
|
appData,
|
|
1333
1611
|
"Code",
|
|
@@ -1350,7 +1628,7 @@ var vscodeExtSettingsPath = (extensionId, filename) => {
|
|
|
1350
1628
|
);
|
|
1351
1629
|
};
|
|
1352
1630
|
var claudeDesktopConfigPath = () => {
|
|
1353
|
-
if (
|
|
1631
|
+
if (process7.platform === "darwin") {
|
|
1354
1632
|
return join2(
|
|
1355
1633
|
home,
|
|
1356
1634
|
"Library",
|
|
@@ -1359,8 +1637,8 @@ var claudeDesktopConfigPath = () => {
|
|
|
1359
1637
|
"claude_desktop_config.json"
|
|
1360
1638
|
);
|
|
1361
1639
|
}
|
|
1362
|
-
if (
|
|
1363
|
-
const appData =
|
|
1640
|
+
if (process7.platform === "win32") {
|
|
1641
|
+
const appData = process7.env.APPDATA ?? join2(home, "AppData", "Roaming");
|
|
1364
1642
|
return join2(appData, "Claude", "claude_desktop_config.json");
|
|
1365
1643
|
}
|
|
1366
1644
|
return join2(home, ".config", "Claude", "claude_desktop_config.json");
|
|
@@ -1685,7 +1963,7 @@ var directoryExists = (path2) => pipe3(
|
|
|
1685
1963
|
Effect3.orElseSucceed(() => false)
|
|
1686
1964
|
);
|
|
1687
1965
|
var detectAgents = (projectRoot) => {
|
|
1688
|
-
const cwd = projectRoot ??
|
|
1966
|
+
const cwd = projectRoot ?? process7.cwd();
|
|
1689
1967
|
return pipe3(
|
|
1690
1968
|
Effect3.forEach(
|
|
1691
1969
|
AGENTS,
|
|
@@ -1730,7 +2008,7 @@ var resolveInstallPath = (agent, options) => {
|
|
|
1730
2008
|
if (!agent.projectPath) {
|
|
1731
2009
|
return void 0;
|
|
1732
2010
|
}
|
|
1733
|
-
const cwd = options.projectRoot ??
|
|
2011
|
+
const cwd = options.projectRoot ?? process7.cwd();
|
|
1734
2012
|
return join2(cwd, agent.projectPath);
|
|
1735
2013
|
};
|
|
1736
2014
|
var resolveRulesInstallPath = (agent, options) => {
|
|
@@ -1740,7 +2018,7 @@ var resolveRulesInstallPath = (agent, options) => {
|
|
|
1740
2018
|
if (!agent.rulesProjectPath) {
|
|
1741
2019
|
return void 0;
|
|
1742
2020
|
}
|
|
1743
|
-
const cwd = options.projectRoot ??
|
|
2021
|
+
const cwd = options.projectRoot ?? process7.cwd();
|
|
1744
2022
|
return join2(cwd, agent.rulesProjectPath);
|
|
1745
2023
|
};
|
|
1746
2024
|
var hasMcpConfig = (agent) => Boolean(agent.mcpProjectConfigPath) || Boolean(agent.mcpGlobalConfigPath);
|
|
@@ -1749,7 +2027,7 @@ var resolveMcpConfigPath = (agent, options) => {
|
|
|
1749
2027
|
return agent.mcpGlobalConfigPath;
|
|
1750
2028
|
}
|
|
1751
2029
|
if (agent.mcpProjectConfigPath) {
|
|
1752
|
-
const cwd = options.projectRoot ??
|
|
2030
|
+
const cwd = options.projectRoot ?? process7.cwd();
|
|
1753
2031
|
return join2(cwd, agent.mcpProjectConfigPath);
|
|
1754
2032
|
}
|
|
1755
2033
|
return agent.mcpGlobalConfigPath;
|
|
@@ -1908,9 +2186,9 @@ function buildMdcContent(rule) {
|
|
|
1908
2186
|
lines.push(rule.content);
|
|
1909
2187
|
return lines.join("\n");
|
|
1910
2188
|
}
|
|
1911
|
-
function buildAppendContent(
|
|
2189
|
+
function buildAppendContent(rules2) {
|
|
1912
2190
|
const lines = [BRAID_SECTION_START, ""];
|
|
1913
|
-
for (const rule of
|
|
2191
|
+
for (const rule of rules2) {
|
|
1914
2192
|
lines.push(`## ${rule.title}`);
|
|
1915
2193
|
lines.push("");
|
|
1916
2194
|
lines.push(rule.content);
|
|
@@ -1919,11 +2197,11 @@ function buildAppendContent(rules) {
|
|
|
1919
2197
|
lines.push(BRAID_SECTION_END);
|
|
1920
2198
|
return lines.join("\n");
|
|
1921
2199
|
}
|
|
1922
|
-
var writeMdcRules = (basePath,
|
|
2200
|
+
var writeMdcRules = (basePath, rules2) => pipe5(
|
|
1923
2201
|
createDirectory(basePath),
|
|
1924
2202
|
Effect5.flatMap(
|
|
1925
2203
|
() => Effect5.forEach(
|
|
1926
|
-
|
|
2204
|
+
rules2,
|
|
1927
2205
|
(rule) => pipe5(
|
|
1928
2206
|
assertRulePathWithinBase(basePath, `${rule.name}.mdc`),
|
|
1929
2207
|
Effect5.flatMap(
|
|
@@ -1935,11 +2213,11 @@ var writeMdcRules = (basePath, rules) => pipe5(
|
|
|
1935
2213
|
),
|
|
1936
2214
|
Effect5.asVoid
|
|
1937
2215
|
);
|
|
1938
|
-
var writeMarkdownDirRules = (basePath,
|
|
2216
|
+
var writeMarkdownDirRules = (basePath, rules2) => pipe5(
|
|
1939
2217
|
createDirectory(basePath),
|
|
1940
2218
|
Effect5.flatMap(
|
|
1941
2219
|
() => Effect5.forEach(
|
|
1942
|
-
|
|
2220
|
+
rules2,
|
|
1943
2221
|
(rule) => pipe5(
|
|
1944
2222
|
assertRulePathWithinBase(basePath, `${rule.name}.md`),
|
|
1945
2223
|
Effect5.flatMap(
|
|
@@ -1953,7 +2231,7 @@ ${rule.content}`)
|
|
|
1953
2231
|
),
|
|
1954
2232
|
Effect5.asVoid
|
|
1955
2233
|
);
|
|
1956
|
-
var writeAppendSingleRules = (filePath,
|
|
2234
|
+
var writeAppendSingleRules = (filePath, rules2) => pipe5(
|
|
1957
2235
|
createDirectory(dirname2(filePath)),
|
|
1958
2236
|
Effect5.flatMap(
|
|
1959
2237
|
() => pipe5(
|
|
@@ -1962,7 +2240,7 @@ var writeAppendSingleRules = (filePath, rules) => pipe5(
|
|
|
1962
2240
|
)
|
|
1963
2241
|
),
|
|
1964
2242
|
Effect5.flatMap((existing) => {
|
|
1965
|
-
const braidContent = buildAppendContent(
|
|
2243
|
+
const braidContent = buildAppendContent(rules2);
|
|
1966
2244
|
const startIdx = existing.indexOf(BRAID_SECTION_START);
|
|
1967
2245
|
const endIdx = existing.indexOf(BRAID_SECTION_END);
|
|
1968
2246
|
let newContent;
|
|
@@ -1976,26 +2254,26 @@ ${braidContent}` : braidContent;
|
|
|
1976
2254
|
return writeTextFile(filePath, newContent);
|
|
1977
2255
|
})
|
|
1978
2256
|
);
|
|
1979
|
-
var writeRulesForFormat = (basePath,
|
|
2257
|
+
var writeRulesForFormat = (basePath, rules2, format) => {
|
|
1980
2258
|
switch (format) {
|
|
1981
2259
|
case "mdc":
|
|
1982
|
-
return writeMdcRules(basePath,
|
|
2260
|
+
return writeMdcRules(basePath, rules2);
|
|
1983
2261
|
case "markdown-dir":
|
|
1984
|
-
return writeMarkdownDirRules(basePath,
|
|
2262
|
+
return writeMarkdownDirRules(basePath, rules2);
|
|
1985
2263
|
case "append-single":
|
|
1986
|
-
return writeAppendSingleRules(basePath,
|
|
2264
|
+
return writeAppendSingleRules(basePath, rules2);
|
|
1987
2265
|
default:
|
|
1988
2266
|
return Effect5.void;
|
|
1989
2267
|
}
|
|
1990
2268
|
};
|
|
1991
|
-
var writeRulesForAgent = (agent,
|
|
1992
|
-
if (!agent.ruleFormat ||
|
|
2269
|
+
var writeRulesForAgent = (agent, rules2, rulesPath) => {
|
|
2270
|
+
if (!agent.ruleFormat || rules2.length === 0) {
|
|
1993
2271
|
return Effect5.succeed({ written: 0, errors: [] });
|
|
1994
2272
|
}
|
|
1995
2273
|
return pipe5(
|
|
1996
|
-
writeRulesForFormat(rulesPath,
|
|
2274
|
+
writeRulesForFormat(rulesPath, rules2, agent.ruleFormat),
|
|
1997
2275
|
Effect5.map(() => ({
|
|
1998
|
-
written:
|
|
2276
|
+
written: rules2.length,
|
|
1999
2277
|
errors: []
|
|
2000
2278
|
})),
|
|
2001
2279
|
Effect5.catchAll(
|
|
@@ -2011,7 +2289,7 @@ var writeRulesForAgent = (agent, rules, rulesPath) => {
|
|
|
2011
2289
|
)
|
|
2012
2290
|
);
|
|
2013
2291
|
};
|
|
2014
|
-
var writeRulesForAgentAsync = (agent,
|
|
2292
|
+
var writeRulesForAgentAsync = (agent, rules2, rulesPath) => Effect5.runPromise(writeRulesForAgent(agent, rules2, rulesPath));
|
|
2015
2293
|
|
|
2016
2294
|
// src/lib/skill-writer.ts
|
|
2017
2295
|
init_esm_shims();
|
|
@@ -2120,9 +2398,9 @@ var writeSkill = (basePath, skill, agentId) => pipe6(
|
|
|
2120
2398
|
)
|
|
2121
2399
|
)
|
|
2122
2400
|
);
|
|
2123
|
-
var writeSkills = (basePath,
|
|
2401
|
+
var writeSkills = (basePath, skills2, agentId) => pipe6(
|
|
2124
2402
|
Effect6.forEach(
|
|
2125
|
-
|
|
2403
|
+
skills2,
|
|
2126
2404
|
(skill) => pipe6(
|
|
2127
2405
|
writeSkill(basePath, skill, agentId),
|
|
2128
2406
|
Effect6.map(() => ({ success: true, skill: skill.name })),
|
|
@@ -2143,7 +2421,7 @@ var writeSkills = (basePath, skills, agentId) => pipe6(
|
|
|
2143
2421
|
).map((r) => ({ skill: r.skill, error: r.error }))
|
|
2144
2422
|
}))
|
|
2145
2423
|
);
|
|
2146
|
-
var writeSkillsAsync = (basePath,
|
|
2424
|
+
var writeSkillsAsync = (basePath, skills2, agentId) => Effect6.runPromise(writeSkills(basePath, skills2, agentId));
|
|
2147
2425
|
|
|
2148
2426
|
// src/commands/install.ts
|
|
2149
2427
|
init_tui();
|
|
@@ -2220,9 +2498,9 @@ function buildFetchOptions(resolved) {
|
|
|
2220
2498
|
}
|
|
2221
2499
|
return fetchOptions;
|
|
2222
2500
|
}
|
|
2223
|
-
function displaySkillsAndExit(
|
|
2501
|
+
function displaySkillsAndExit(skills2) {
|
|
2224
2502
|
log.info("\nSkills:");
|
|
2225
|
-
for (const skill of
|
|
2503
|
+
for (const skill of skills2) {
|
|
2226
2504
|
const fileCount = skill.files.length;
|
|
2227
2505
|
log.info(
|
|
2228
2506
|
` ${skill.name} (${fileCount} file${fileCount !== 1 ? "s" : ""})`
|
|
@@ -2330,14 +2608,14 @@ async function installSkillsToAgent(agent, response, installPath) {
|
|
|
2330
2608
|
return { written: result.written.length, errors: result.errors.length };
|
|
2331
2609
|
}
|
|
2332
2610
|
async function installRulesToAgent(agent, response, options) {
|
|
2333
|
-
const
|
|
2611
|
+
const rules2 = response.rules ?? [];
|
|
2334
2612
|
const rulesPath = resolveRulesInstallPath(agent, {
|
|
2335
2613
|
global: options.global === true
|
|
2336
2614
|
});
|
|
2337
|
-
if (
|
|
2615
|
+
if (rules2.length === 0 || !rulesPath || !agent.ruleFormat) {
|
|
2338
2616
|
return { written: 0, errors: 0 };
|
|
2339
2617
|
}
|
|
2340
|
-
const result = await writeRulesForAgentAsync(agent,
|
|
2618
|
+
const result = await writeRulesForAgentAsync(agent, rules2, rulesPath);
|
|
2341
2619
|
for (const err of result.errors) {
|
|
2342
2620
|
log.warn(` Failed rules: ${err.agent} - ${err.error}`);
|
|
2343
2621
|
}
|
|
@@ -2358,17 +2636,17 @@ async function installToAgent(agent, response, serverUrl, options, installSpinne
|
|
|
2358
2636
|
global: options.global === true
|
|
2359
2637
|
});
|
|
2360
2638
|
installSpinner.start(`Installing to ${agent.name}...`);
|
|
2361
|
-
const
|
|
2362
|
-
const
|
|
2363
|
-
const totalWritten =
|
|
2364
|
-
const totalErrors =
|
|
2639
|
+
const skills2 = installPath ? await installSkillsToAgent(agent, response, installPath) : { written: 0, errors: 0 };
|
|
2640
|
+
const rules2 = await installRulesToAgent(agent, response, options);
|
|
2641
|
+
const totalWritten = skills2.written + rules2.written;
|
|
2642
|
+
const totalErrors = skills2.errors + rules2.errors;
|
|
2365
2643
|
if (totalErrors > 0) {
|
|
2366
2644
|
installSpinner.stop(
|
|
2367
2645
|
`${agent.name}: ${totalWritten} installed, ${totalErrors} failed`
|
|
2368
2646
|
);
|
|
2369
2647
|
} else {
|
|
2370
2648
|
installSpinner.stop(
|
|
2371
|
-
formatInstallSummary(agent.name,
|
|
2649
|
+
formatInstallSummary(agent.name, skills2.written, rules2.written)
|
|
2372
2650
|
);
|
|
2373
2651
|
}
|
|
2374
2652
|
if (response.skills.length > 0 && installPath) {
|
|
@@ -2384,7 +2662,180 @@ async function installToAgent(agent, response, serverUrl, options, installSpinne
|
|
|
2384
2662
|
}
|
|
2385
2663
|
return { written: totalWritten, errors: totalErrors };
|
|
2386
2664
|
}
|
|
2387
|
-
|
|
2665
|
+
var PUBLIC_SOURCE_REGEX = /^@([a-z0-9-]+)\/([a-z0-9-]+)$/;
|
|
2666
|
+
function parsePublicSource(source) {
|
|
2667
|
+
const match = source.match(PUBLIC_SOURCE_REGEX);
|
|
2668
|
+
if (!(match?.[1] && match[2])) {
|
|
2669
|
+
return null;
|
|
2670
|
+
}
|
|
2671
|
+
return { handle: match[1], slug: match[2] };
|
|
2672
|
+
}
|
|
2673
|
+
function displayPublicMetadata(metadata) {
|
|
2674
|
+
if (metadata.type === "project") {
|
|
2675
|
+
const { project, rules: rules2 } = metadata;
|
|
2676
|
+
log.info(`
|
|
2677
|
+
Project: ${project.name}`);
|
|
2678
|
+
if (project.description) {
|
|
2679
|
+
log.info(` ${project.description}`);
|
|
2680
|
+
}
|
|
2681
|
+
log.info(` ${rules2.length} rule(s) available`);
|
|
2682
|
+
} else {
|
|
2683
|
+
const { rule } = metadata;
|
|
2684
|
+
log.info(`
|
|
2685
|
+
Rule: ${rule.title}`);
|
|
2686
|
+
log.info(` Type: ${rule.type}`);
|
|
2687
|
+
if (rule.tags.length > 0) {
|
|
2688
|
+
log.info(` Tags: ${rule.tags.join(", ")}`);
|
|
2689
|
+
}
|
|
2690
|
+
if (rule.description) {
|
|
2691
|
+
log.info(` ${rule.description}`);
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
async function selectPublicRules(metadata, options) {
|
|
2696
|
+
if (metadata.type !== "project") {
|
|
2697
|
+
return null;
|
|
2698
|
+
}
|
|
2699
|
+
if (options.yes) {
|
|
2700
|
+
return metadata.rules.map((r) => r.id);
|
|
2701
|
+
}
|
|
2702
|
+
const selected = await multiselect({
|
|
2703
|
+
message: "Select rules to install:",
|
|
2704
|
+
options: metadata.rules.map((r) => ({
|
|
2705
|
+
value: r.id,
|
|
2706
|
+
label: r.title,
|
|
2707
|
+
hint: r.type
|
|
2708
|
+
})),
|
|
2709
|
+
initialValues: metadata.rules.map((r) => r.id),
|
|
2710
|
+
required: true
|
|
2711
|
+
});
|
|
2712
|
+
if (isCancel(selected)) {
|
|
2713
|
+
cancel("Install cancelled.");
|
|
2714
|
+
process.exit(0);
|
|
2715
|
+
}
|
|
2716
|
+
return selected;
|
|
2717
|
+
}
|
|
2718
|
+
async function confirmRuleInstall(metadata, options) {
|
|
2719
|
+
if (metadata.type !== "rule") {
|
|
2720
|
+
return true;
|
|
2721
|
+
}
|
|
2722
|
+
if (options.yes) {
|
|
2723
|
+
return true;
|
|
2724
|
+
}
|
|
2725
|
+
const confirmed = await confirm({
|
|
2726
|
+
message: `Install "${metadata.rule.title}"?`
|
|
2727
|
+
});
|
|
2728
|
+
if (isCancel(confirmed)) {
|
|
2729
|
+
cancel("Install cancelled.");
|
|
2730
|
+
process.exit(0);
|
|
2731
|
+
}
|
|
2732
|
+
return confirmed === true;
|
|
2733
|
+
}
|
|
2734
|
+
function summarizeContent(response) {
|
|
2735
|
+
const ruleCount = response.rules?.length ?? 0;
|
|
2736
|
+
const skillCount = response.skills.length;
|
|
2737
|
+
const parts = [];
|
|
2738
|
+
if (skillCount > 0) {
|
|
2739
|
+
parts.push(`${skillCount} skills`);
|
|
2740
|
+
}
|
|
2741
|
+
if (ruleCount > 0) {
|
|
2742
|
+
parts.push(`${ruleCount} rules`);
|
|
2743
|
+
}
|
|
2744
|
+
return parts.join(", ") || "nothing";
|
|
2745
|
+
}
|
|
2746
|
+
function hasNoContent(response) {
|
|
2747
|
+
return response.skills.length === 0 && (response.rules?.length ?? 0) === 0;
|
|
2748
|
+
}
|
|
2749
|
+
async function installToSelectedAgents(response, serverUrl, options, installSpinner) {
|
|
2750
|
+
const agentResolution = await resolveAgents(options, installSpinner);
|
|
2751
|
+
const selectedAgents = await selectAgents(
|
|
2752
|
+
agentResolution.availableAgents,
|
|
2753
|
+
agentResolution.preselectedAgents,
|
|
2754
|
+
options
|
|
2755
|
+
);
|
|
2756
|
+
let totalWritten = 0;
|
|
2757
|
+
let totalErrors = 0;
|
|
2758
|
+
for (const agent of selectedAgents) {
|
|
2759
|
+
const result = await installToAgent(
|
|
2760
|
+
agent,
|
|
2761
|
+
response,
|
|
2762
|
+
serverUrl,
|
|
2763
|
+
options,
|
|
2764
|
+
installSpinner
|
|
2765
|
+
);
|
|
2766
|
+
totalWritten += result.written;
|
|
2767
|
+
totalErrors += result.errors;
|
|
2768
|
+
}
|
|
2769
|
+
return { totalWritten, totalErrors };
|
|
2770
|
+
}
|
|
2771
|
+
function showInstallOutro(totalWritten, totalErrors, suffix) {
|
|
2772
|
+
if (totalErrors > 0) {
|
|
2773
|
+
outro(`Installed ${totalWritten} items with ${totalErrors} errors.`);
|
|
2774
|
+
} else {
|
|
2775
|
+
outro(`Successfully installed ${totalWritten} items${suffix}.`);
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
async function fetchPublicContent(handle, slug, options, installSpinner) {
|
|
2779
|
+
const metadata = await fetchPublicMetadataAsync(handle, slug, options.server);
|
|
2780
|
+
installSpinner.stop("Found public content");
|
|
2781
|
+
displayPublicMetadata(metadata);
|
|
2782
|
+
let ruleIds;
|
|
2783
|
+
if (metadata.type === "project") {
|
|
2784
|
+
const selected = await selectPublicRules(metadata, options);
|
|
2785
|
+
ruleIds = selected ?? void 0;
|
|
2786
|
+
} else {
|
|
2787
|
+
const confirmed = await confirmRuleInstall(metadata, options);
|
|
2788
|
+
if (!confirmed) {
|
|
2789
|
+
outro("Install cancelled.");
|
|
2790
|
+
process.exit(0);
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
installSpinner.start("Downloading content...");
|
|
2794
|
+
return fetchPublicExportAsync(handle, slug, ruleIds, options.server);
|
|
2795
|
+
}
|
|
2796
|
+
async function publicInstallCommand(source, options) {
|
|
2797
|
+
const parsed = parsePublicSource(source);
|
|
2798
|
+
if (!parsed) {
|
|
2799
|
+
log.error(`Invalid public source: ${source}`);
|
|
2800
|
+
log.info("Expected format: @handle/slug (e.g., @acme/coding-standards)");
|
|
2801
|
+
process.exit(1);
|
|
2802
|
+
}
|
|
2803
|
+
const { handle, slug } = parsed;
|
|
2804
|
+
intro(`Installing from @${handle}/${slug}`);
|
|
2805
|
+
const installSpinner = spinner();
|
|
2806
|
+
installSpinner.start("Fetching public content...");
|
|
2807
|
+
try {
|
|
2808
|
+
const response = await fetchPublicContent(
|
|
2809
|
+
handle,
|
|
2810
|
+
slug,
|
|
2811
|
+
options,
|
|
2812
|
+
installSpinner
|
|
2813
|
+
);
|
|
2814
|
+
installSpinner.stop(`Downloaded ${summarizeContent(response)}`);
|
|
2815
|
+
if (hasNoContent(response)) {
|
|
2816
|
+
log.warn("No content to install.");
|
|
2817
|
+
process.exit(0);
|
|
2818
|
+
}
|
|
2819
|
+
const serverUrl = options.server ?? "https://braid.cloud";
|
|
2820
|
+
const { totalWritten, totalErrors } = await installToSelectedAgents(
|
|
2821
|
+
response,
|
|
2822
|
+
serverUrl,
|
|
2823
|
+
options,
|
|
2824
|
+
installSpinner
|
|
2825
|
+
);
|
|
2826
|
+
showInstallOutro(totalWritten, totalErrors, ` from @${handle}/${slug}`);
|
|
2827
|
+
} catch (error) {
|
|
2828
|
+
installSpinner.stop("Install failed");
|
|
2829
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2830
|
+
log.error(message);
|
|
2831
|
+
process.exit(1);
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
async function installCommand(sourceOrOptions, maybeOptions) {
|
|
2835
|
+
if (typeof sourceOrOptions === "string") {
|
|
2836
|
+
return handlePublicSource(sourceOrOptions, maybeOptions ?? {});
|
|
2837
|
+
}
|
|
2838
|
+
const options = sourceOrOptions;
|
|
2388
2839
|
const config = await loadMergedConfigAsync();
|
|
2389
2840
|
const resolved = resolveInstallConfig(options, config);
|
|
2390
2841
|
validateInstallOptions(resolved);
|
|
@@ -2395,17 +2846,8 @@ async function installCommand(options) {
|
|
|
2395
2846
|
try {
|
|
2396
2847
|
const fetchOptions = buildFetchOptions(resolved);
|
|
2397
2848
|
const response = await fetchSkillsAsync(fetchOptions);
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
const foundParts = [];
|
|
2401
|
-
if (skillCount > 0) {
|
|
2402
|
-
foundParts.push(`${skillCount} skills`);
|
|
2403
|
-
}
|
|
2404
|
-
if (ruleCount > 0) {
|
|
2405
|
-
foundParts.push(`${ruleCount} rules`);
|
|
2406
|
-
}
|
|
2407
|
-
installSpinner.stop(`Found ${foundParts.join(", ") || "nothing"}`);
|
|
2408
|
-
if (skillCount === 0 && ruleCount === 0) {
|
|
2849
|
+
installSpinner.stop(`Found ${summarizeContent(response)}`);
|
|
2850
|
+
if (hasNoContent(response)) {
|
|
2409
2851
|
log.warn(
|
|
2410
2852
|
"No skills or rules found. Check that your profile/project has enabled prompts."
|
|
2411
2853
|
);
|
|
@@ -2414,32 +2856,13 @@ async function installCommand(options) {
|
|
|
2414
2856
|
if (options.list) {
|
|
2415
2857
|
displaySkillsAndExit(response.skills);
|
|
2416
2858
|
}
|
|
2417
|
-
const
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2859
|
+
const { totalWritten, totalErrors } = await installToSelectedAgents(
|
|
2860
|
+
response,
|
|
2861
|
+
resolved.serverUrl,
|
|
2862
|
+
options,
|
|
2863
|
+
installSpinner
|
|
2422
2864
|
);
|
|
2423
|
-
|
|
2424
|
-
let totalErrors = 0;
|
|
2425
|
-
for (const agent of selectedAgents) {
|
|
2426
|
-
const result = await installToAgent(
|
|
2427
|
-
agent,
|
|
2428
|
-
response,
|
|
2429
|
-
resolved.serverUrl,
|
|
2430
|
-
options,
|
|
2431
|
-
installSpinner
|
|
2432
|
-
);
|
|
2433
|
-
totalWritten += result.written;
|
|
2434
|
-
totalErrors += result.errors;
|
|
2435
|
-
}
|
|
2436
|
-
if (totalErrors > 0) {
|
|
2437
|
-
outro(`Installed ${totalWritten} items with ${totalErrors} errors.`);
|
|
2438
|
-
} else {
|
|
2439
|
-
outro(
|
|
2440
|
-
`Successfully installed ${totalWritten} items to ${selectedAgents.length} agent(s).`
|
|
2441
|
-
);
|
|
2442
|
-
}
|
|
2865
|
+
showInstallOutro(totalWritten, totalErrors, ` to ${totalWritten} agent(s)`);
|
|
2443
2866
|
log.info("Run 'braid list' to see installed skills.");
|
|
2444
2867
|
} catch (error) {
|
|
2445
2868
|
installSpinner.stop("Install failed");
|
|
@@ -2448,6 +2871,15 @@ async function installCommand(options) {
|
|
|
2448
2871
|
process.exit(1);
|
|
2449
2872
|
}
|
|
2450
2873
|
}
|
|
2874
|
+
function handlePublicSource(source, options) {
|
|
2875
|
+
const publicParsed = parsePublicSource(source);
|
|
2876
|
+
if (publicParsed) {
|
|
2877
|
+
return publicInstallCommand(source, options);
|
|
2878
|
+
}
|
|
2879
|
+
log.error(`Unknown source: ${source}`);
|
|
2880
|
+
log.info("Public sources use format: @handle/slug");
|
|
2881
|
+
process.exit(1);
|
|
2882
|
+
}
|
|
2451
2883
|
|
|
2452
2884
|
// src/commands/list.ts
|
|
2453
2885
|
init_esm_shims();
|
|
@@ -2545,7 +2977,7 @@ async function listCommand(options) {
|
|
|
2545
2977
|
|
|
2546
2978
|
// src/commands/mcp.ts
|
|
2547
2979
|
init_esm_shims();
|
|
2548
|
-
import
|
|
2980
|
+
import process8 from "process";
|
|
2549
2981
|
init_config();
|
|
2550
2982
|
|
|
2551
2983
|
// src/lib/mcp-config.ts
|
|
@@ -2630,7 +3062,7 @@ async function selectTool(mcpAgents, toolFlag) {
|
|
|
2630
3062
|
if (!agent) {
|
|
2631
3063
|
log.error(`Unknown or unsupported tool: ${toolFlag}`);
|
|
2632
3064
|
log.info(`Supported tools: ${mcpAgents.map((a) => a.id).join(", ")}`);
|
|
2633
|
-
|
|
3065
|
+
process8.exit(1);
|
|
2634
3066
|
}
|
|
2635
3067
|
return agent;
|
|
2636
3068
|
}
|
|
@@ -2649,12 +3081,12 @@ async function selectTool(mcpAgents, toolFlag) {
|
|
|
2649
3081
|
});
|
|
2650
3082
|
if (isCancel(toolChoice)) {
|
|
2651
3083
|
cancel("MCP setup cancelled.");
|
|
2652
|
-
|
|
3084
|
+
process8.exit(0);
|
|
2653
3085
|
}
|
|
2654
3086
|
const found = mcpAgents.find((a) => a.id === toolChoice);
|
|
2655
3087
|
if (!found) {
|
|
2656
3088
|
log.error("Agent not found.");
|
|
2657
|
-
|
|
3089
|
+
process8.exit(1);
|
|
2658
3090
|
}
|
|
2659
3091
|
return found;
|
|
2660
3092
|
}
|
|
@@ -2680,7 +3112,7 @@ async function selectScope(agent, options) {
|
|
|
2680
3112
|
});
|
|
2681
3113
|
if (isCancel(scopeChoice)) {
|
|
2682
3114
|
cancel("MCP setup cancelled.");
|
|
2683
|
-
|
|
3115
|
+
process8.exit(0);
|
|
2684
3116
|
}
|
|
2685
3117
|
return scopeChoice;
|
|
2686
3118
|
}
|
|
@@ -2711,7 +3143,7 @@ async function resolveToken(options, existingToken) {
|
|
|
2711
3143
|
});
|
|
2712
3144
|
if (isCancel(authChoice)) {
|
|
2713
3145
|
cancel("MCP setup cancelled.");
|
|
2714
|
-
|
|
3146
|
+
process8.exit(0);
|
|
2715
3147
|
}
|
|
2716
3148
|
if (authChoice === "existing") {
|
|
2717
3149
|
return existingToken;
|
|
@@ -2734,7 +3166,7 @@ async function resolveToken(options, existingToken) {
|
|
|
2734
3166
|
});
|
|
2735
3167
|
if (isCancel(token)) {
|
|
2736
3168
|
cancel("MCP setup cancelled.");
|
|
2737
|
-
|
|
3169
|
+
process8.exit(0);
|
|
2738
3170
|
}
|
|
2739
3171
|
return token;
|
|
2740
3172
|
}
|
|
@@ -2765,7 +3197,7 @@ async function addFlow(options) {
|
|
|
2765
3197
|
const mcpAgents = getMcpAgents();
|
|
2766
3198
|
if (mcpAgents.length === 0) {
|
|
2767
3199
|
log.error("No agents with MCP configuration support found.");
|
|
2768
|
-
|
|
3200
|
+
process8.exit(1);
|
|
2769
3201
|
}
|
|
2770
3202
|
const selectedAgent = await selectTool(mcpAgents, options.tool);
|
|
2771
3203
|
const scope = await selectScope(selectedAgent, options);
|
|
@@ -2774,7 +3206,7 @@ async function addFlow(options) {
|
|
|
2774
3206
|
});
|
|
2775
3207
|
if (!configPath) {
|
|
2776
3208
|
log.error(`No ${scope} config path available for ${selectedAgent.name}.`);
|
|
2777
|
-
|
|
3209
|
+
process8.exit(1);
|
|
2778
3210
|
}
|
|
2779
3211
|
const token = await resolveToken(options, config.token);
|
|
2780
3212
|
const env = buildEnvVars(token, options.server);
|
|
@@ -2799,7 +3231,7 @@ async function addFlow(options) {
|
|
|
2799
3231
|
mcpSpinner.stop("Configuration failed");
|
|
2800
3232
|
const message = error instanceof Error ? error.message : String(error);
|
|
2801
3233
|
log.error(`Failed to write config: ${message}`);
|
|
2802
|
-
|
|
3234
|
+
process8.exit(1);
|
|
2803
3235
|
}
|
|
2804
3236
|
}
|
|
2805
3237
|
async function removeFlow(options) {
|
|
@@ -2811,7 +3243,7 @@ async function removeFlow(options) {
|
|
|
2811
3243
|
});
|
|
2812
3244
|
if (!configPath) {
|
|
2813
3245
|
log.error(`No ${scope} config path available for ${selectedAgent.name}.`);
|
|
2814
|
-
|
|
3246
|
+
process8.exit(1);
|
|
2815
3247
|
}
|
|
2816
3248
|
const removeSpinner = spinner();
|
|
2817
3249
|
removeSpinner.start(`Removing braid from ${selectedAgent.name}...`);
|
|
@@ -2837,7 +3269,7 @@ async function removeFlow(options) {
|
|
|
2837
3269
|
removeSpinner.stop("Removal failed");
|
|
2838
3270
|
const message = error instanceof Error ? error.message : String(error);
|
|
2839
3271
|
log.error(`Failed to remove config: ${message}`);
|
|
2840
|
-
|
|
3272
|
+
process8.exit(1);
|
|
2841
3273
|
}
|
|
2842
3274
|
}
|
|
2843
3275
|
async function statusFlow() {
|
|
@@ -2874,7 +3306,27 @@ async function statusFlow() {
|
|
|
2874
3306
|
log.info(` ${result.name} (${result.scope}) \u2192 ${result.path}`);
|
|
2875
3307
|
}
|
|
2876
3308
|
}
|
|
3309
|
+
function helpCommandsFlow() {
|
|
3310
|
+
log.info("MCP manual command reference:");
|
|
3311
|
+
log.info(" braid projects list --json");
|
|
3312
|
+
log.info(" braid rules list --json");
|
|
3313
|
+
log.info(" braid skills list --profile <name> --json");
|
|
3314
|
+
log.info("");
|
|
3315
|
+
log.info("Common local management commands:");
|
|
3316
|
+
log.info(" braid install --yes --profile <name>");
|
|
3317
|
+
log.info(" braid update --yes");
|
|
3318
|
+
log.info(" braid list");
|
|
3319
|
+
log.info(" braid remove --yes --all");
|
|
3320
|
+
log.info(
|
|
3321
|
+
" braid scope --file user --organization personal --source profile --profile <name>"
|
|
3322
|
+
);
|
|
3323
|
+
}
|
|
2877
3324
|
async function mcpCommand(options) {
|
|
3325
|
+
if (options.helpCommands) {
|
|
3326
|
+
intro("braid mcp help");
|
|
3327
|
+
helpCommandsFlow();
|
|
3328
|
+
return;
|
|
3329
|
+
}
|
|
2878
3330
|
if (options.status) {
|
|
2879
3331
|
intro("braid mcp status");
|
|
2880
3332
|
await statusFlow();
|
|
@@ -2889,11 +3341,306 @@ async function mcpCommand(options) {
|
|
|
2889
3341
|
await addFlow(options);
|
|
2890
3342
|
}
|
|
2891
3343
|
|
|
3344
|
+
// src/commands/profiles.ts
|
|
3345
|
+
init_esm_shims();
|
|
3346
|
+
init_api();
|
|
3347
|
+
init_tui();
|
|
3348
|
+
import process9 from "process";
|
|
3349
|
+
var writeJson2 = (value) => {
|
|
3350
|
+
process9.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
3351
|
+
`);
|
|
3352
|
+
};
|
|
3353
|
+
var exitWithError2 = (error) => {
|
|
3354
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3355
|
+
log.error(message);
|
|
3356
|
+
process9.exit(1);
|
|
3357
|
+
};
|
|
3358
|
+
var fail = (message) => {
|
|
3359
|
+
throw new Error(message);
|
|
3360
|
+
};
|
|
3361
|
+
var parseContext = (contextJson) => {
|
|
3362
|
+
if (!contextJson) {
|
|
3363
|
+
return void 0;
|
|
3364
|
+
}
|
|
3365
|
+
return JSON.parse(contextJson);
|
|
3366
|
+
};
|
|
3367
|
+
var run = async (command, args, options) => {
|
|
3368
|
+
const apiOptions = {
|
|
3369
|
+
...options.server ? { serverUrl: options.server } : {},
|
|
3370
|
+
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
3371
|
+
};
|
|
3372
|
+
const result = await runLifecycleCommandAsync(
|
|
3373
|
+
{
|
|
3374
|
+
domain: "profiles",
|
|
3375
|
+
command,
|
|
3376
|
+
args
|
|
3377
|
+
},
|
|
3378
|
+
apiOptions
|
|
3379
|
+
);
|
|
3380
|
+
if (options.json) {
|
|
3381
|
+
writeJson2(result);
|
|
3382
|
+
return;
|
|
3383
|
+
}
|
|
3384
|
+
log.success(`profiles ${command} completed`);
|
|
3385
|
+
};
|
|
3386
|
+
async function profilesListCommand(options) {
|
|
3387
|
+
try {
|
|
3388
|
+
await run("list", {}, options);
|
|
3389
|
+
} catch (error) {
|
|
3390
|
+
exitWithError2(error);
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
async function profilesGetCommand(options) {
|
|
3394
|
+
try {
|
|
3395
|
+
if (!(options.id || options.name)) {
|
|
3396
|
+
fail("profiles get requires --id or --name");
|
|
3397
|
+
}
|
|
3398
|
+
await run("get", { id: options.id, name: options.name }, options);
|
|
3399
|
+
} catch (error) {
|
|
3400
|
+
exitWithError2(error);
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
async function profilesCreateCommand(options) {
|
|
3404
|
+
try {
|
|
3405
|
+
const name = options.name ?? fail("profiles create requires --name");
|
|
3406
|
+
await run(
|
|
3407
|
+
"create",
|
|
3408
|
+
{ name, context: parseContext(options.contextJson) },
|
|
3409
|
+
options
|
|
3410
|
+
);
|
|
3411
|
+
} catch (error) {
|
|
3412
|
+
exitWithError2(error);
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
async function profilesUpdateCommand(options) {
|
|
3416
|
+
try {
|
|
3417
|
+
const id = options.id ?? fail("profiles update requires --id");
|
|
3418
|
+
await run(
|
|
3419
|
+
"update",
|
|
3420
|
+
{
|
|
3421
|
+
id,
|
|
3422
|
+
name: options.name,
|
|
3423
|
+
context: parseContext(options.contextJson)
|
|
3424
|
+
},
|
|
3425
|
+
options
|
|
3426
|
+
);
|
|
3427
|
+
} catch (error) {
|
|
3428
|
+
exitWithError2(error);
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
async function profilesRemoveCommand(options) {
|
|
3432
|
+
try {
|
|
3433
|
+
const id = options.id ?? fail("profiles remove requires --id");
|
|
3434
|
+
if (!options.yes) {
|
|
3435
|
+
fail("profiles remove requires --yes");
|
|
3436
|
+
}
|
|
3437
|
+
await run("remove", { id, yes: true }, options);
|
|
3438
|
+
} catch (error) {
|
|
3439
|
+
exitWithError2(error);
|
|
3440
|
+
}
|
|
3441
|
+
}
|
|
3442
|
+
async function profilesSetDefaultCommand(options) {
|
|
3443
|
+
try {
|
|
3444
|
+
const id = options.id ?? fail("profiles set-default requires --id");
|
|
3445
|
+
await run("set-default", { id }, options);
|
|
3446
|
+
} catch (error) {
|
|
3447
|
+
exitWithError2(error);
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
|
|
3451
|
+
// src/commands/projects.ts
|
|
3452
|
+
init_esm_shims();
|
|
3453
|
+
init_api();
|
|
3454
|
+
init_tui();
|
|
3455
|
+
import process10 from "process";
|
|
3456
|
+
var writeJson3 = (value) => {
|
|
3457
|
+
process10.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
3458
|
+
`);
|
|
3459
|
+
};
|
|
3460
|
+
var fail2 = (message) => {
|
|
3461
|
+
throw new Error(message);
|
|
3462
|
+
};
|
|
3463
|
+
var run2 = async (command, args, options) => {
|
|
3464
|
+
const apiOptions = {
|
|
3465
|
+
...options.server ? { serverUrl: options.server } : {},
|
|
3466
|
+
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
3467
|
+
};
|
|
3468
|
+
const result = await runLifecycleCommandAsync(
|
|
3469
|
+
{
|
|
3470
|
+
domain: "projects",
|
|
3471
|
+
command,
|
|
3472
|
+
args
|
|
3473
|
+
},
|
|
3474
|
+
apiOptions
|
|
3475
|
+
);
|
|
3476
|
+
if (options.json) {
|
|
3477
|
+
writeJson3(result);
|
|
3478
|
+
return;
|
|
3479
|
+
}
|
|
3480
|
+
log.success(`projects ${command} completed`);
|
|
3481
|
+
};
|
|
3482
|
+
var exitWithError3 = (error) => {
|
|
3483
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3484
|
+
log.error(message);
|
|
3485
|
+
process10.exit(1);
|
|
3486
|
+
};
|
|
3487
|
+
async function projectsGetCommand(options) {
|
|
3488
|
+
try {
|
|
3489
|
+
const id = options.id ?? fail2("projects get requires --id");
|
|
3490
|
+
await run2("get", { id }, options);
|
|
3491
|
+
} catch (error) {
|
|
3492
|
+
exitWithError3(error);
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3495
|
+
async function projectsCreateCommand(options) {
|
|
3496
|
+
try {
|
|
3497
|
+
const name = options.name ?? fail2("projects create requires --name");
|
|
3498
|
+
await run2(
|
|
3499
|
+
"create",
|
|
3500
|
+
{ name, description: options.description, orgId: options.orgId },
|
|
3501
|
+
options
|
|
3502
|
+
);
|
|
3503
|
+
} catch (error) {
|
|
3504
|
+
exitWithError3(error);
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
async function projectsUpdateCommand(options) {
|
|
3508
|
+
try {
|
|
3509
|
+
const id = options.id ?? fail2("projects update requires --id");
|
|
3510
|
+
await run2(
|
|
3511
|
+
"update",
|
|
3512
|
+
{
|
|
3513
|
+
id,
|
|
3514
|
+
name: options.name,
|
|
3515
|
+
description: options.description
|
|
3516
|
+
},
|
|
3517
|
+
options
|
|
3518
|
+
);
|
|
3519
|
+
} catch (error) {
|
|
3520
|
+
exitWithError3(error);
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3523
|
+
async function projectsRemoveCommand(options) {
|
|
3524
|
+
try {
|
|
3525
|
+
const id = options.id ?? fail2("projects remove requires --id");
|
|
3526
|
+
if (!options.yes) {
|
|
3527
|
+
fail2("projects remove requires --yes");
|
|
3528
|
+
}
|
|
3529
|
+
await run2("remove", { id, yes: true }, options);
|
|
3530
|
+
} catch (error) {
|
|
3531
|
+
exitWithError3(error);
|
|
3532
|
+
}
|
|
3533
|
+
}
|
|
3534
|
+
|
|
3535
|
+
// src/commands/references.ts
|
|
3536
|
+
init_esm_shims();
|
|
3537
|
+
init_api();
|
|
3538
|
+
init_tui();
|
|
3539
|
+
import process11 from "process";
|
|
3540
|
+
var writeJson4 = (value) => {
|
|
3541
|
+
process11.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
3542
|
+
`);
|
|
3543
|
+
};
|
|
3544
|
+
var parseCsv2 = (input) => {
|
|
3545
|
+
if (!input) {
|
|
3546
|
+
return void 0;
|
|
3547
|
+
}
|
|
3548
|
+
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
3549
|
+
return values.length > 0 ? values : void 0;
|
|
3550
|
+
};
|
|
3551
|
+
var exitWithError4 = (error) => {
|
|
3552
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3553
|
+
log.error(message);
|
|
3554
|
+
process11.exit(1);
|
|
3555
|
+
};
|
|
3556
|
+
var fail3 = (message) => {
|
|
3557
|
+
throw new Error(message);
|
|
3558
|
+
};
|
|
3559
|
+
var run3 = async (command, args, options) => {
|
|
3560
|
+
const apiOptions = {
|
|
3561
|
+
...options.server ? { serverUrl: options.server } : {},
|
|
3562
|
+
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
3563
|
+
};
|
|
3564
|
+
const result = await runLifecycleCommandAsync(
|
|
3565
|
+
{
|
|
3566
|
+
domain: "references",
|
|
3567
|
+
command,
|
|
3568
|
+
args
|
|
3569
|
+
},
|
|
3570
|
+
apiOptions
|
|
3571
|
+
);
|
|
3572
|
+
if (options.json) {
|
|
3573
|
+
writeJson4(result);
|
|
3574
|
+
return;
|
|
3575
|
+
}
|
|
3576
|
+
log.success(`references ${command} completed`);
|
|
3577
|
+
};
|
|
3578
|
+
async function referencesListCommand(options) {
|
|
3579
|
+
try {
|
|
3580
|
+
const ruleId = options.ruleId ?? fail3("references list requires --rule-id");
|
|
3581
|
+
await run3("list", { ruleId }, options);
|
|
3582
|
+
} catch (error) {
|
|
3583
|
+
exitWithError4(error);
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
async function referencesGetCommand(options) {
|
|
3587
|
+
try {
|
|
3588
|
+
const id = options.id ?? fail3("references get requires --id");
|
|
3589
|
+
await run3("get", { id }, options);
|
|
3590
|
+
} catch (error) {
|
|
3591
|
+
exitWithError4(error);
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
3594
|
+
async function referencesCreateCommand(options) {
|
|
3595
|
+
try {
|
|
3596
|
+
const ruleId = options.ruleId ?? fail3("references create requires --rule-id");
|
|
3597
|
+
const file = options.file ?? fail3("references create requires --file");
|
|
3598
|
+
await run3("create", { ruleId, file }, options);
|
|
3599
|
+
} catch (error) {
|
|
3600
|
+
exitWithError4(error);
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
async function referencesUpdateCommand(options) {
|
|
3604
|
+
try {
|
|
3605
|
+
const id = options.id ?? fail3("references update requires --id");
|
|
3606
|
+
await run3(
|
|
3607
|
+
"update",
|
|
3608
|
+
{ id, label: options.label, replaceFile: options.replaceFile },
|
|
3609
|
+
options
|
|
3610
|
+
);
|
|
3611
|
+
} catch (error) {
|
|
3612
|
+
exitWithError4(error);
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
async function referencesRemoveCommand(options) {
|
|
3616
|
+
try {
|
|
3617
|
+
const id = options.id ?? fail3("references remove requires --id");
|
|
3618
|
+
if (!options.yes) {
|
|
3619
|
+
fail3("references remove requires --yes");
|
|
3620
|
+
}
|
|
3621
|
+
await run3("remove", { id, yes: true }, options);
|
|
3622
|
+
} catch (error) {
|
|
3623
|
+
exitWithError4(error);
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
async function referencesReorderCommand(options) {
|
|
3627
|
+
try {
|
|
3628
|
+
const ruleId = options.ruleId ?? fail3("references reorder requires --rule-id");
|
|
3629
|
+
const orderedIds = parseCsv2(options.orderedIds);
|
|
3630
|
+
if (!orderedIds || orderedIds.length === 0) {
|
|
3631
|
+
fail3("references reorder requires --ordered-ids");
|
|
3632
|
+
}
|
|
3633
|
+
await run3("reorder", { ruleId, orderedIds }, options);
|
|
3634
|
+
} catch (error) {
|
|
3635
|
+
exitWithError4(error);
|
|
3636
|
+
}
|
|
3637
|
+
}
|
|
3638
|
+
|
|
2892
3639
|
// src/commands/remove.ts
|
|
2893
3640
|
init_esm_shims();
|
|
2894
3641
|
import { rm } from "fs/promises";
|
|
2895
3642
|
import { join as join4, resolve as resolve3 } from "path";
|
|
2896
|
-
import
|
|
3643
|
+
import process12 from "process";
|
|
2897
3644
|
init_tui();
|
|
2898
3645
|
async function collectInstalledSkills(detectedAgents, options) {
|
|
2899
3646
|
const skillsToRemove = [];
|
|
@@ -2926,7 +3673,7 @@ async function selectSkillsToRemove(skillsToRemove, options) {
|
|
|
2926
3673
|
if (selected.length === 0) {
|
|
2927
3674
|
log.error(`Skill '${options.skill}' not found.`);
|
|
2928
3675
|
log.info("Run 'braid list' to see installed skills.");
|
|
2929
|
-
|
|
3676
|
+
process12.exit(1);
|
|
2930
3677
|
}
|
|
2931
3678
|
return selected;
|
|
2932
3679
|
}
|
|
@@ -2945,7 +3692,7 @@ async function selectSkillsToRemove(skillsToRemove, options) {
|
|
|
2945
3692
|
});
|
|
2946
3693
|
if (isCancel(result)) {
|
|
2947
3694
|
cancel("Remove cancelled.");
|
|
2948
|
-
|
|
3695
|
+
process12.exit(0);
|
|
2949
3696
|
}
|
|
2950
3697
|
return result;
|
|
2951
3698
|
}
|
|
@@ -2959,7 +3706,7 @@ async function confirmRemoval(selectedCount, options) {
|
|
|
2959
3706
|
});
|
|
2960
3707
|
if (isCancel(confirmed) || !confirmed) {
|
|
2961
3708
|
cancel("Remove cancelled.");
|
|
2962
|
-
|
|
3709
|
+
process12.exit(0);
|
|
2963
3710
|
}
|
|
2964
3711
|
}
|
|
2965
3712
|
async function removeSkill(skill, removeSpinner) {
|
|
@@ -3023,7 +3770,203 @@ async function removeCommand(options) {
|
|
|
3023
3770
|
removeSpinner.stop("Remove failed");
|
|
3024
3771
|
const message = error instanceof Error ? error.message : String(error);
|
|
3025
3772
|
log.error(message);
|
|
3026
|
-
|
|
3773
|
+
process12.exit(1);
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
|
|
3777
|
+
// src/commands/rules.ts
|
|
3778
|
+
init_esm_shims();
|
|
3779
|
+
init_api();
|
|
3780
|
+
init_tui();
|
|
3781
|
+
import process13 from "process";
|
|
3782
|
+
var parseCsv3 = (input) => {
|
|
3783
|
+
if (!input) {
|
|
3784
|
+
return void 0;
|
|
3785
|
+
}
|
|
3786
|
+
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
3787
|
+
return values.length > 0 ? values : void 0;
|
|
3788
|
+
};
|
|
3789
|
+
var writeJson5 = (value) => {
|
|
3790
|
+
process13.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
3791
|
+
`);
|
|
3792
|
+
};
|
|
3793
|
+
var exitWithError5 = (error) => {
|
|
3794
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3795
|
+
log.error(message);
|
|
3796
|
+
process13.exit(1);
|
|
3797
|
+
};
|
|
3798
|
+
var fail4 = (message) => {
|
|
3799
|
+
throw new Error(message);
|
|
3800
|
+
};
|
|
3801
|
+
var run4 = async (command, args, options) => {
|
|
3802
|
+
const apiOptions = {
|
|
3803
|
+
...options.server ? { serverUrl: options.server } : {},
|
|
3804
|
+
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
3805
|
+
};
|
|
3806
|
+
const result = await runLifecycleCommandAsync(
|
|
3807
|
+
{
|
|
3808
|
+
domain: "rules",
|
|
3809
|
+
command,
|
|
3810
|
+
args
|
|
3811
|
+
},
|
|
3812
|
+
apiOptions
|
|
3813
|
+
);
|
|
3814
|
+
if (options.json) {
|
|
3815
|
+
writeJson5(result);
|
|
3816
|
+
return;
|
|
3817
|
+
}
|
|
3818
|
+
log.success(`rules ${command} completed`);
|
|
3819
|
+
};
|
|
3820
|
+
async function rulesGetCommand(options) {
|
|
3821
|
+
try {
|
|
3822
|
+
const id = options.id ?? fail4("rules get requires --id");
|
|
3823
|
+
await run4("get", { id }, options);
|
|
3824
|
+
} catch (error) {
|
|
3825
|
+
exitWithError5(error);
|
|
3826
|
+
}
|
|
3827
|
+
}
|
|
3828
|
+
async function rulesCreateCommand(options) {
|
|
3829
|
+
try {
|
|
3830
|
+
const title = options.title ?? fail4("rules create requires --title");
|
|
3831
|
+
const content = options.content ?? fail4("rules create requires --content");
|
|
3832
|
+
await run4(
|
|
3833
|
+
"create",
|
|
3834
|
+
{
|
|
3835
|
+
title,
|
|
3836
|
+
content,
|
|
3837
|
+
projectId: options.projectId,
|
|
3838
|
+
tags: parseCsv3(options.tags),
|
|
3839
|
+
priority: options.priority
|
|
3840
|
+
},
|
|
3841
|
+
options
|
|
3842
|
+
);
|
|
3843
|
+
} catch (error) {
|
|
3844
|
+
exitWithError5(error);
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3847
|
+
async function rulesUpdateCommand(options) {
|
|
3848
|
+
try {
|
|
3849
|
+
const id = options.id ?? fail4("rules update requires --id");
|
|
3850
|
+
await run4(
|
|
3851
|
+
"update",
|
|
3852
|
+
{
|
|
3853
|
+
id,
|
|
3854
|
+
title: options.title,
|
|
3855
|
+
content: options.content,
|
|
3856
|
+
tags: parseCsv3(options.tags),
|
|
3857
|
+
priority: options.priority
|
|
3858
|
+
},
|
|
3859
|
+
options
|
|
3860
|
+
);
|
|
3861
|
+
} catch (error) {
|
|
3862
|
+
exitWithError5(error);
|
|
3863
|
+
}
|
|
3864
|
+
}
|
|
3865
|
+
async function rulesRemoveCommand(options) {
|
|
3866
|
+
try {
|
|
3867
|
+
const id = options.id ?? fail4("rules remove requires --id");
|
|
3868
|
+
if (!options.yes) {
|
|
3869
|
+
fail4("rules remove requires --yes");
|
|
3870
|
+
}
|
|
3871
|
+
await run4("remove", { id, yes: true }, options);
|
|
3872
|
+
} catch (error) {
|
|
3873
|
+
exitWithError5(error);
|
|
3874
|
+
}
|
|
3875
|
+
}
|
|
3876
|
+
async function rulesEnableCommand(options) {
|
|
3877
|
+
try {
|
|
3878
|
+
const id = options.id ?? fail4("rules enable requires --id");
|
|
3879
|
+
await run4("enable", { id }, options);
|
|
3880
|
+
} catch (error) {
|
|
3881
|
+
exitWithError5(error);
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3884
|
+
async function rulesDisableCommand(options) {
|
|
3885
|
+
try {
|
|
3886
|
+
const id = options.id ?? fail4("rules disable requires --id");
|
|
3887
|
+
await run4("disable", { id }, options);
|
|
3888
|
+
} catch (error) {
|
|
3889
|
+
exitWithError5(error);
|
|
3890
|
+
}
|
|
3891
|
+
}
|
|
3892
|
+
async function rulesMoveCommand(options) {
|
|
3893
|
+
try {
|
|
3894
|
+
const id = options.id ?? fail4("rules move requires --id");
|
|
3895
|
+
const projectId = options.projectId ?? fail4("rules move requires --project-id");
|
|
3896
|
+
await run4("move", { id, projectId }, options);
|
|
3897
|
+
} catch (error) {
|
|
3898
|
+
exitWithError5(error);
|
|
3899
|
+
}
|
|
3900
|
+
}
|
|
3901
|
+
async function rulesDuplicateCommand(options) {
|
|
3902
|
+
try {
|
|
3903
|
+
const id = options.id ?? fail4("rules duplicate requires --id");
|
|
3904
|
+
await run4(
|
|
3905
|
+
"duplicate",
|
|
3906
|
+
{ id, targetProjectId: options.targetProjectId },
|
|
3907
|
+
options
|
|
3908
|
+
);
|
|
3909
|
+
} catch (error) {
|
|
3910
|
+
exitWithError5(error);
|
|
3911
|
+
}
|
|
3912
|
+
}
|
|
3913
|
+
async function rulesForkCommand(options) {
|
|
3914
|
+
try {
|
|
3915
|
+
const id = options.id ?? fail4("rules fork requires --id");
|
|
3916
|
+
await run4(
|
|
3917
|
+
"fork",
|
|
3918
|
+
{ id, targetProjectId: options.targetProjectId },
|
|
3919
|
+
options
|
|
3920
|
+
);
|
|
3921
|
+
} catch (error) {
|
|
3922
|
+
exitWithError5(error);
|
|
3923
|
+
}
|
|
3924
|
+
}
|
|
3925
|
+
async function rulesSyncStatusCommand(options) {
|
|
3926
|
+
try {
|
|
3927
|
+
await run4("sync-status", { id: options.id }, options);
|
|
3928
|
+
} catch (error) {
|
|
3929
|
+
exitWithError5(error);
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
async function rulesSyncHistoryCommand(options) {
|
|
3933
|
+
try {
|
|
3934
|
+
const id = options.id ?? fail4("rules sync-history requires --id");
|
|
3935
|
+
await run4("sync-history", { id }, options);
|
|
3936
|
+
} catch (error) {
|
|
3937
|
+
exitWithError5(error);
|
|
3938
|
+
}
|
|
3939
|
+
}
|
|
3940
|
+
async function rulesSyncEnableCommand(options) {
|
|
3941
|
+
try {
|
|
3942
|
+
const id = options.id ?? fail4("rules sync-enable requires --id");
|
|
3943
|
+
await run4("sync-enable", { id }, options);
|
|
3944
|
+
} catch (error) {
|
|
3945
|
+
exitWithError5(error);
|
|
3946
|
+
}
|
|
3947
|
+
}
|
|
3948
|
+
async function rulesSyncDisableCommand(options) {
|
|
3949
|
+
try {
|
|
3950
|
+
const id = options.id ?? fail4("rules sync-disable requires --id");
|
|
3951
|
+
await run4("sync-disable", { id }, options);
|
|
3952
|
+
} catch (error) {
|
|
3953
|
+
exitWithError5(error);
|
|
3954
|
+
}
|
|
3955
|
+
}
|
|
3956
|
+
async function rulesSyncCheckCommand(options) {
|
|
3957
|
+
try {
|
|
3958
|
+
const id = options.id ?? fail4("rules sync-check requires --id");
|
|
3959
|
+
await run4("sync-check", { id }, options);
|
|
3960
|
+
} catch (error) {
|
|
3961
|
+
exitWithError5(error);
|
|
3962
|
+
}
|
|
3963
|
+
}
|
|
3964
|
+
async function rulesSyncNowCommand(options) {
|
|
3965
|
+
try {
|
|
3966
|
+
const id = options.id ?? fail4("rules sync-now requires --id");
|
|
3967
|
+
await run4("sync-now", { id }, options);
|
|
3968
|
+
} catch (error) {
|
|
3969
|
+
exitWithError5(error);
|
|
3027
3970
|
}
|
|
3028
3971
|
}
|
|
3029
3972
|
|
|
@@ -3329,10 +4272,12 @@ program.name("braid").description(
|
|
|
3329
4272
|
"Install braid prompts as agent skills to your local development environment"
|
|
3330
4273
|
).version(PACKAGE_VERSION);
|
|
3331
4274
|
var auth = program.command("auth").description("Configure API key for braid authentication");
|
|
3332
|
-
auth.command("login", { isDefault: true }).description("Configure API key").option("-s, --server <url>", "braid server URL (for review apps, local dev)").action(authCommand);
|
|
4275
|
+
auth.command("login", { isDefault: true }).description("Configure API key").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--token <token>", "API key for non-interactive login").option("--no-scope", "Skip scope setup after login").action(authCommand);
|
|
3333
4276
|
auth.command("status").description("Show current authentication status").action(authStatusCommand);
|
|
3334
4277
|
auth.command("logout").description("Remove stored API key").action(authLogoutCommand);
|
|
3335
|
-
program.command("install").alias("add").description(
|
|
4278
|
+
program.command("install").alias("add").description(
|
|
4279
|
+
"Install skills from a profile, project, or public source (@handle/slug)"
|
|
4280
|
+
).argument("[source]", "Public source to install from (e.g., @handle/slug)").option("-p, --profile <name>", "Profile name to install from").option(
|
|
3336
4281
|
"--org-projects <ids>",
|
|
3337
4282
|
"Comma-separated organization project IDs to install from"
|
|
3338
4283
|
).option(
|
|
@@ -3347,7 +4292,12 @@ program.command("install").alias("add").description("Install skills from a profi
|
|
|
3347
4292
|
).option("--no-include-org-globals", "Exclude organization's global prompts").option(
|
|
3348
4293
|
"-a, --agents <list>",
|
|
3349
4294
|
"Comma-separated list of agents (e.g., claude-code,opencode)"
|
|
3350
|
-
).option("-g, --global", "Install to global agent directories").option("-y, --yes", "Skip confirmation prompts").option("-l, --list", "Preview skills without installing").option("-s, --server <url>", "braid server URL (for review apps, local dev)").action(
|
|
4295
|
+
).option("-g, --global", "Install to global agent directories").option("-y, --yes", "Skip confirmation prompts").option("-l, --list", "Preview skills without installing").option("-s, --server <url>", "braid server URL (for review apps, local dev)").action((source, options) => {
|
|
4296
|
+
if (source) {
|
|
4297
|
+
return installCommand(source, options);
|
|
4298
|
+
}
|
|
4299
|
+
return installCommand(options);
|
|
4300
|
+
});
|
|
3351
4301
|
program.command("scope").description("Interactively configure braid.json or braid.user.json scope").option("--file <target>", "Config file target: user or project").option(
|
|
3352
4302
|
"--organization <type>",
|
|
3353
4303
|
"Scope organization for non-interactive mode: personal or organization"
|
|
@@ -3371,8 +4321,47 @@ program.command("scope").description("Interactively configure braid.json or brai
|
|
|
3371
4321
|
"Include org global rules in non-interactive mode"
|
|
3372
4322
|
).option("-s, --server <url>", "braid server URL (for review apps, local dev)").action(scopeCommand);
|
|
3373
4323
|
program.command("list").alias("ls").description("List installed skills").option("-g, --global", "List skills in global directories only").action(listCommand);
|
|
4324
|
+
var projects = program.command("projects").description("Discover available projects from braid");
|
|
4325
|
+
projects.command("list").description("List available personal and org projects").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(projectsListCommand);
|
|
4326
|
+
projects.command("get").description("Get a project by id").requiredOption("--id <id>", "Project ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(projectsGetCommand);
|
|
4327
|
+
projects.command("create").description("Create a project").requiredOption("--name <name>", "Project name").option("--description <description>", "Project description").option("--org-id <id>", "Organization ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(projectsCreateCommand);
|
|
4328
|
+
projects.command("update").description("Update a project").requiredOption("--id <id>", "Project ID").option("--name <name>", "Project name").option("--description <description>", "Project description").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(projectsUpdateCommand);
|
|
4329
|
+
projects.command("remove").description("Remove a project").requiredOption("--id <id>", "Project ID").option("-y, --yes", "Confirm destructive action").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(projectsRemoveCommand);
|
|
4330
|
+
var rules = program.command("rules").description("Discover available rules from braid");
|
|
4331
|
+
rules.command("list").description("List available rules for a scope").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--org-id <id>", "Organization ID").option("--org-projects <ids>", "Comma-separated organization project IDs").option("--personal-projects <ids>", "Comma-separated personal project IDs").option("--include-user-global", "Include personal global rules").option("--include-org-global", "Include org global rules").option("--json", "Output JSON").action(rulesListCommand);
|
|
4332
|
+
rules.command("get").description("Get a rule by id").requiredOption("--id <id>", "Rule ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesGetCommand);
|
|
4333
|
+
rules.command("create").description("Create a rule").requiredOption("--title <title>", "Rule title").requiredOption("--content <content>", "Rule content").option("--project-id <id>", "Project ID").option("--tags <list>", "Comma-separated tags").option("--priority <priority>", "Priority").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesCreateCommand);
|
|
4334
|
+
rules.command("update").description("Update a rule").requiredOption("--id <id>", "Rule ID").option("--title <title>", "Rule title").option("--content <content>", "Rule content").option("--tags <list>", "Comma-separated tags").option("--priority <priority>", "Priority").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesUpdateCommand);
|
|
4335
|
+
rules.command("remove").description("Remove a rule").requiredOption("--id <id>", "Rule ID").option("-y, --yes", "Confirm destructive action").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesRemoveCommand);
|
|
4336
|
+
rules.command("enable").description("Enable a rule").requiredOption("--id <id>", "Rule ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesEnableCommand);
|
|
4337
|
+
rules.command("disable").description("Disable a rule").requiredOption("--id <id>", "Rule ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesDisableCommand);
|
|
4338
|
+
rules.command("move").description("Move a rule to a project").requiredOption("--id <id>", "Rule ID").requiredOption("--project-id <id>", "Project ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesMoveCommand);
|
|
4339
|
+
rules.command("duplicate").description("Duplicate a rule").requiredOption("--id <id>", "Rule ID").option("--target-project-id <id>", "Target project ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesDuplicateCommand);
|
|
4340
|
+
rules.command("fork").description("Fork a rule").requiredOption("--id <id>", "Rule ID").option("--target-project-id <id>", "Target project ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesForkCommand);
|
|
4341
|
+
rules.command("sync-status").description("Show sync status for one rule or all").option("--id <id>", "Rule ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesSyncStatusCommand);
|
|
4342
|
+
rules.command("sync-history").description("Show sync history for a rule").requiredOption("--id <id>", "Rule ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesSyncHistoryCommand);
|
|
4343
|
+
rules.command("sync-enable").description("Enable sync for a rule").requiredOption("--id <id>", "Rule ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesSyncEnableCommand);
|
|
4344
|
+
rules.command("sync-disable").description("Disable sync for a rule").requiredOption("--id <id>", "Rule ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesSyncDisableCommand);
|
|
4345
|
+
rules.command("sync-check").description("Check for upstream updates").requiredOption("--id <id>", "Rule ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesSyncCheckCommand);
|
|
4346
|
+
rules.command("sync-now").description("Run sync now").requiredOption("--id <id>", "Rule ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(rulesSyncNowCommand);
|
|
4347
|
+
var skills = program.command("skills").description("Discover available skills from braid");
|
|
4348
|
+
skills.command("list").description("List available skills for a profile or project scope").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("-p, --profile <name>", "Profile name").option("--org-projects <ids>", "Comma-separated organization project IDs").option("--personal-projects <ids>", "Comma-separated personal project IDs").option("--include-user-global", "Include personal global rules").option("--include-org-global", "Include org global rules").option("--json", "Output JSON").action(skillsListCommand);
|
|
4349
|
+
var profiles = program.command("profiles").description("Manage scope profiles");
|
|
4350
|
+
profiles.command("list").description("List profiles").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(profilesListCommand);
|
|
4351
|
+
profiles.command("get").description("Get profile by id or name").option("--id <id>", "Profile ID").option("--name <name>", "Profile name").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(profilesGetCommand);
|
|
4352
|
+
profiles.command("create").description("Create profile").requiredOption("--name <name>", "Profile name").option("--context-json <json>", "Context JSON").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(profilesCreateCommand);
|
|
4353
|
+
profiles.command("update").description("Update profile").requiredOption("--id <id>", "Profile ID").option("--name <name>", "Profile name").option("--context-json <json>", "Context JSON").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(profilesUpdateCommand);
|
|
4354
|
+
profiles.command("remove").description("Remove profile").requiredOption("--id <id>", "Profile ID").option("-y, --yes", "Confirm destructive action").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(profilesRemoveCommand);
|
|
4355
|
+
profiles.command("set-default").description("Set default profile").requiredOption("--id <id>", "Profile ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(profilesSetDefaultCommand);
|
|
4356
|
+
var references = program.command("references").description("Manage rule references");
|
|
4357
|
+
references.command("list").description("List references for a rule").requiredOption("--rule-id <id>", "Rule ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(referencesListCommand);
|
|
4358
|
+
references.command("get").description("Get a reference by id").requiredOption("--id <id>", "Reference ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(referencesGetCommand);
|
|
4359
|
+
references.command("create").description("Create a reference from file").requiredOption("--rule-id <id>", "Rule ID").requiredOption("--file <path>", "Reference file path").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(referencesCreateCommand);
|
|
4360
|
+
references.command("update").description("Update reference metadata").requiredOption("--id <id>", "Reference ID").option("--label <label>", "Reference label").option("--replace-file <path>", "Replace reference with file").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(referencesUpdateCommand);
|
|
4361
|
+
references.command("remove").description("Remove reference").requiredOption("--id <id>", "Reference ID").option("-y, --yes", "Confirm destructive action").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(referencesRemoveCommand);
|
|
4362
|
+
references.command("reorder").description("Reorder references").requiredOption("--rule-id <id>", "Rule ID").requiredOption("--ordered-ids <ids>", "Comma-separated reference IDs").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(referencesReorderCommand);
|
|
3374
4363
|
program.command("update").alias("up").description("Update installed skills to the latest version").option("-g, --global", "Update skills in global directories only").option("-y, --yes", "Skip confirmation prompts").option("-s, --server <url>", "braid server URL (for review apps, local dev)").action(updateCommand);
|
|
3375
4364
|
program.command("remove").alias("rm").description("Remove installed skills").option("-a, --all", "Remove all installed skills").option("-g, --global", "Remove skills from global directories only").option("-y, --yes", "Skip confirmation prompts").option("--skill <name>", "Remove a specific skill by name").action(removeCommand);
|
|
3376
|
-
program.command("mcp").description("Configure braid MCP in your AI coding tools").option("-t, --tool <name>", "Tool to configure").option("-g, --global", "Use global config instead of project").option("--token <token>", "API token to embed").option("--no-auth", "Skip authentication setup").option("--scope", "Run interactive scope configuration").option("--remove", "Remove braid MCP from a tool").option("--status", "Show which tools have braid MCP configured").option("-y, --yes", "Skip confirmation prompts").option("-s, --server <url>", "Custom MCP server URL").action(mcpCommand);
|
|
4365
|
+
program.command("mcp").description("Configure braid MCP in your AI coding tools").option("-t, --tool <name>", "Tool to configure").option("-g, --global", "Use global config instead of project").option("--token <token>", "API token to embed").option("--no-auth", "Skip authentication setup").option("--scope", "Run interactive scope configuration").option("--remove", "Remove braid MCP from a tool").option("--status", "Show which tools have braid MCP configured").option("--help-commands", "Show MCP manual command reference").option("-y, --yes", "Skip confirmation prompts").option("-s, --server <url>", "Custom MCP server URL").action(mcpCommand);
|
|
3377
4366
|
program.parse();
|
|
3378
4367
|
//# sourceMappingURL=index.js.map
|