@braid-cloud/cli 0.1.6 → 0.1.8
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/LICENSE +2 -2
- package/README.md +79 -18
- package/dist/index.js +604 -85
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -60,7 +60,7 @@ import { homedir } from "os";
|
|
|
60
60
|
import { dirname, join, parse } from "path";
|
|
61
61
|
import process2 from "process";
|
|
62
62
|
import { Data, Effect, pipe } from "effect";
|
|
63
|
-
var CONFIG_DIR, CONFIG_FILE, PROJECT_CONFIG_FILENAME, USER_CONFIG_FILENAME, ConfigReadError, ConfigWriteError, findConfigFile, findProjectConfigFile, findUserConfigFile, loadProjectConfig, loadUserConfig, resolveUserConfigWritePath, saveUserConfig, saveProjectConfig, isValidServerUrl, resolveServerUrlFromConfig, applyConfigSource, applyEnvOverrides, createDefaultMergedConfig, loadMergedConfig, loadConfig, saveConfig, getApiKey, setApiKey, getServerUrl, clearApiKey, loadConfigAsync, loadProjectConfigAsync, loadUserConfigAsync, loadMergedConfigAsync, findProjectConfigFileAsync, findUserConfigFileAsync, saveConfigAsync, saveUserConfigAsync, saveProjectConfigAsync, getApiKeyAsync, setApiKeyAsync, getServerUrlAsync, clearApiKeyAsync;
|
|
63
|
+
var CONFIG_DIR, CONFIG_FILE, PROJECT_CONFIG_FILENAME, USER_CONFIG_FILENAME, ConfigReadError, ConfigWriteError, findConfigFile, findProjectConfigFile, findUserConfigFile, loadProjectConfig, loadUserConfig, resolveUserConfigWritePath, resolveProjectConfigWritePath, saveUserConfig, saveProjectConfig, isValidServerUrl, resolveServerUrlFromConfig, applyConfigSource, applyEnvOverrides, createDefaultMergedConfig, loadMergedConfig, loadConfig, saveConfig, getApiKey, setApiKey, getServerUrl, clearApiKey, loadConfigAsync, loadProjectConfigAsync, loadUserConfigAsync, loadMergedConfigAsync, findProjectConfigFileAsync, findUserConfigFileAsync, saveConfigAsync, saveUserConfigAsync, saveProjectConfigAsync, getApiKeyAsync, setApiKeyAsync, getServerUrlAsync, clearApiKeyAsync;
|
|
64
64
|
var init_config = __esm({
|
|
65
65
|
"src/lib/config.ts"() {
|
|
66
66
|
"use strict";
|
|
@@ -112,6 +112,7 @@ var init_config = __esm({
|
|
|
112
112
|
catch: () => void 0
|
|
113
113
|
}).pipe(Effect.orElseSucceed(() => void 0));
|
|
114
114
|
resolveUserConfigWritePath = (startDir = process2.cwd()) => findUserConfigFile(startDir) ?? join(startDir, USER_CONFIG_FILENAME);
|
|
115
|
+
resolveProjectConfigWritePath = (startDir = process2.cwd()) => findProjectConfigFile(startDir) ?? join(startDir, PROJECT_CONFIG_FILENAME);
|
|
115
116
|
saveUserConfig = (config, startDir = process2.cwd()) => {
|
|
116
117
|
const targetPath = resolveUserConfigWritePath(startDir);
|
|
117
118
|
return pipe(
|
|
@@ -129,7 +130,7 @@ var init_config = __esm({
|
|
|
129
130
|
);
|
|
130
131
|
};
|
|
131
132
|
saveProjectConfig = (config, startDir = process2.cwd()) => {
|
|
132
|
-
const targetPath =
|
|
133
|
+
const targetPath = resolveProjectConfigWritePath(startDir);
|
|
133
134
|
return pipe(
|
|
134
135
|
Effect.tryPromise({
|
|
135
136
|
try: async () => {
|
|
@@ -1085,7 +1086,7 @@ async function scopeCommand(options) {
|
|
|
1085
1086
|
const config = await loadMergedConfigAsync();
|
|
1086
1087
|
const targetFile = await selectTargetFile(options);
|
|
1087
1088
|
const loadSpinner = spinner();
|
|
1088
|
-
loadSpinner.start("Loading scope options from
|
|
1089
|
+
loadSpinner.start("Loading scope options from braid...");
|
|
1089
1090
|
try {
|
|
1090
1091
|
const serverUrl = options.server ?? config.serverUrl;
|
|
1091
1092
|
const apiKey = options.apiKey ?? config.token;
|
|
@@ -1191,7 +1192,7 @@ async function authCommand(options) {
|
|
|
1191
1192
|
}
|
|
1192
1193
|
}
|
|
1193
1194
|
const apiKey = await password({
|
|
1194
|
-
message: "Enter your
|
|
1195
|
+
message: "Enter your braid API key:",
|
|
1195
1196
|
validate: (value) => {
|
|
1196
1197
|
if (!value) {
|
|
1197
1198
|
return "API key is required";
|
|
@@ -1311,24 +1312,83 @@ import { join as join2 } from "path";
|
|
|
1311
1312
|
import process6 from "process";
|
|
1312
1313
|
import { Effect as Effect3, pipe as pipe3 } from "effect";
|
|
1313
1314
|
var home = homedir2();
|
|
1315
|
+
var vscodeExtSettingsPath = (extensionId, filename) => {
|
|
1316
|
+
if (process6.platform === "darwin") {
|
|
1317
|
+
return join2(
|
|
1318
|
+
home,
|
|
1319
|
+
"Library",
|
|
1320
|
+
"Application Support",
|
|
1321
|
+
"Code",
|
|
1322
|
+
"User",
|
|
1323
|
+
"globalStorage",
|
|
1324
|
+
extensionId,
|
|
1325
|
+
"settings",
|
|
1326
|
+
filename
|
|
1327
|
+
);
|
|
1328
|
+
}
|
|
1329
|
+
if (process6.platform === "win32") {
|
|
1330
|
+
const appData = process6.env.APPDATA ?? join2(home, "AppData", "Roaming");
|
|
1331
|
+
return join2(
|
|
1332
|
+
appData,
|
|
1333
|
+
"Code",
|
|
1334
|
+
"User",
|
|
1335
|
+
"globalStorage",
|
|
1336
|
+
extensionId,
|
|
1337
|
+
"settings",
|
|
1338
|
+
filename
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
return join2(
|
|
1342
|
+
home,
|
|
1343
|
+
".config",
|
|
1344
|
+
"Code",
|
|
1345
|
+
"User",
|
|
1346
|
+
"globalStorage",
|
|
1347
|
+
extensionId,
|
|
1348
|
+
"settings",
|
|
1349
|
+
filename
|
|
1350
|
+
);
|
|
1351
|
+
};
|
|
1352
|
+
var claudeDesktopConfigPath = () => {
|
|
1353
|
+
if (process6.platform === "darwin") {
|
|
1354
|
+
return join2(
|
|
1355
|
+
home,
|
|
1356
|
+
"Library",
|
|
1357
|
+
"Application Support",
|
|
1358
|
+
"Claude",
|
|
1359
|
+
"claude_desktop_config.json"
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1362
|
+
if (process6.platform === "win32") {
|
|
1363
|
+
const appData = process6.env.APPDATA ?? join2(home, "AppData", "Roaming");
|
|
1364
|
+
return join2(appData, "Claude", "claude_desktop_config.json");
|
|
1365
|
+
}
|
|
1366
|
+
return join2(home, ".config", "Claude", "claude_desktop_config.json");
|
|
1367
|
+
};
|
|
1314
1368
|
var AGENTS = [
|
|
1315
1369
|
{
|
|
1316
1370
|
id: "amp",
|
|
1317
|
-
name: "Amp
|
|
1371
|
+
name: "Amp",
|
|
1318
1372
|
projectPath: ".agents/skills",
|
|
1319
|
-
globalPath: join2(home, ".config", "agents", "skills")
|
|
1373
|
+
globalPath: join2(home, ".config", "agents", "skills"),
|
|
1374
|
+
mcpProjectConfigPath: ".amp/mcp.json",
|
|
1375
|
+
mcpGlobalConfigPath: join2(home, ".amp", "mcp.json")
|
|
1320
1376
|
},
|
|
1321
1377
|
{
|
|
1322
1378
|
id: "kimi-cli",
|
|
1323
1379
|
name: "Kimi Code CLI",
|
|
1324
1380
|
projectPath: ".agents/skills",
|
|
1325
|
-
globalPath: join2(home, ".config", "agents", "skills")
|
|
1381
|
+
globalPath: join2(home, ".config", "agents", "skills"),
|
|
1382
|
+
mcpProjectConfigPath: ".agents/mcp.json",
|
|
1383
|
+
mcpGlobalConfigPath: join2(home, ".config", "agents", "mcp.json")
|
|
1326
1384
|
},
|
|
1327
1385
|
{
|
|
1328
1386
|
id: "antigravity",
|
|
1329
1387
|
name: "Antigravity",
|
|
1330
1388
|
projectPath: ".agent/skills",
|
|
1331
|
-
globalPath: join2(home, ".gemini", "antigravity", "global_skills")
|
|
1389
|
+
globalPath: join2(home, ".gemini", "antigravity", "global_skills"),
|
|
1390
|
+
mcpProjectConfigPath: ".agent/mcp.json",
|
|
1391
|
+
mcpGlobalConfigPath: join2(home, ".gemini", "antigravity", "mcp.json")
|
|
1332
1392
|
},
|
|
1333
1393
|
{
|
|
1334
1394
|
id: "claude-code",
|
|
@@ -1339,13 +1399,24 @@ var AGENTS = [
|
|
|
1339
1399
|
globalMarkerPath: join2(home, ".claude"),
|
|
1340
1400
|
rulesProjectPath: ".claude/rules",
|
|
1341
1401
|
rulesGlobalPath: join2(home, ".claude", "rules"),
|
|
1342
|
-
ruleFormat: "markdown-dir"
|
|
1402
|
+
ruleFormat: "markdown-dir",
|
|
1403
|
+
mcpProjectConfigPath: ".mcp.json",
|
|
1404
|
+
mcpEntryStyle: "typed-stdio"
|
|
1405
|
+
},
|
|
1406
|
+
{
|
|
1407
|
+
id: "claude-desktop",
|
|
1408
|
+
name: "Claude Desktop",
|
|
1409
|
+
projectPath: "",
|
|
1410
|
+
globalPath: "",
|
|
1411
|
+
mcpGlobalConfigPath: claudeDesktopConfigPath()
|
|
1343
1412
|
},
|
|
1344
1413
|
{
|
|
1345
1414
|
id: "moltbot",
|
|
1346
1415
|
name: "Moltbot",
|
|
1347
1416
|
projectPath: "skills",
|
|
1348
|
-
globalPath: join2(home, ".moltbot", "skills")
|
|
1417
|
+
globalPath: join2(home, ".moltbot", "skills"),
|
|
1418
|
+
mcpProjectConfigPath: "mcp.json",
|
|
1419
|
+
mcpGlobalConfigPath: join2(home, ".moltbot", "mcp.json")
|
|
1349
1420
|
},
|
|
1350
1421
|
{
|
|
1351
1422
|
id: "cline",
|
|
@@ -1353,37 +1424,52 @@ var AGENTS = [
|
|
|
1353
1424
|
projectPath: ".cline/skills",
|
|
1354
1425
|
globalPath: join2(home, ".cline", "skills"),
|
|
1355
1426
|
rulesProjectPath: ".clinerules",
|
|
1356
|
-
ruleFormat: "append-single"
|
|
1427
|
+
ruleFormat: "append-single",
|
|
1428
|
+
mcpGlobalConfigPath: vscodeExtSettingsPath(
|
|
1429
|
+
"saoudrizwan.claude-dev",
|
|
1430
|
+
"cline_mcp_settings.json"
|
|
1431
|
+
),
|
|
1432
|
+
mcpEntryStyle: "cline"
|
|
1357
1433
|
},
|
|
1358
1434
|
{
|
|
1359
1435
|
id: "codebuddy",
|
|
1360
1436
|
name: "CodeBuddy",
|
|
1361
1437
|
projectPath: ".codebuddy/skills",
|
|
1362
|
-
globalPath: join2(home, ".codebuddy", "skills")
|
|
1438
|
+
globalPath: join2(home, ".codebuddy", "skills"),
|
|
1439
|
+
mcpProjectConfigPath: ".codebuddy/mcp.json",
|
|
1440
|
+
mcpGlobalConfigPath: join2(home, ".codebuddy", "mcp.json")
|
|
1363
1441
|
},
|
|
1364
1442
|
{
|
|
1365
1443
|
id: "codex",
|
|
1366
1444
|
name: "Codex",
|
|
1367
1445
|
projectPath: ".codex/skills",
|
|
1368
|
-
globalPath: join2(home, ".codex", "skills")
|
|
1446
|
+
globalPath: join2(home, ".codex", "skills"),
|
|
1447
|
+
mcpProjectConfigPath: ".codex/mcp.json",
|
|
1448
|
+
mcpGlobalConfigPath: join2(home, ".codex", "mcp.json")
|
|
1369
1449
|
},
|
|
1370
1450
|
{
|
|
1371
1451
|
id: "command-code",
|
|
1372
1452
|
name: "Command Code",
|
|
1373
1453
|
projectPath: ".commandcode/skills",
|
|
1374
|
-
globalPath: join2(home, ".commandcode", "skills")
|
|
1454
|
+
globalPath: join2(home, ".commandcode", "skills"),
|
|
1455
|
+
mcpProjectConfigPath: ".commandcode/mcp.json",
|
|
1456
|
+
mcpGlobalConfigPath: join2(home, ".commandcode", "mcp.json")
|
|
1375
1457
|
},
|
|
1376
1458
|
{
|
|
1377
1459
|
id: "continue",
|
|
1378
1460
|
name: "Continue",
|
|
1379
1461
|
projectPath: ".continue/skills",
|
|
1380
|
-
globalPath: join2(home, ".continue", "skills")
|
|
1462
|
+
globalPath: join2(home, ".continue", "skills"),
|
|
1463
|
+
mcpProjectConfigPath: ".continue/mcp.json",
|
|
1464
|
+
mcpGlobalConfigPath: join2(home, ".continue", "mcp.json")
|
|
1381
1465
|
},
|
|
1382
1466
|
{
|
|
1383
1467
|
id: "crush",
|
|
1384
1468
|
name: "Crush",
|
|
1385
1469
|
projectPath: ".crush/skills",
|
|
1386
|
-
globalPath: join2(home, ".config", "crush", "skills")
|
|
1470
|
+
globalPath: join2(home, ".config", "crush", "skills"),
|
|
1471
|
+
mcpProjectConfigPath: ".crush/mcp.json",
|
|
1472
|
+
mcpGlobalConfigPath: join2(home, ".config", "crush", "mcp.json")
|
|
1387
1473
|
},
|
|
1388
1474
|
{
|
|
1389
1475
|
id: "cursor",
|
|
@@ -1391,19 +1477,25 @@ var AGENTS = [
|
|
|
1391
1477
|
projectPath: ".cursor/skills",
|
|
1392
1478
|
globalPath: join2(home, ".cursor", "skills"),
|
|
1393
1479
|
rulesProjectPath: ".cursor/rules",
|
|
1394
|
-
ruleFormat: "mdc"
|
|
1480
|
+
ruleFormat: "mdc",
|
|
1481
|
+
mcpProjectConfigPath: ".cursor/mcp.json",
|
|
1482
|
+
mcpGlobalConfigPath: join2(home, ".cursor", "mcp.json")
|
|
1395
1483
|
},
|
|
1396
1484
|
{
|
|
1397
1485
|
id: "droid",
|
|
1398
1486
|
name: "Droid",
|
|
1399
1487
|
projectPath: ".factory/skills",
|
|
1400
|
-
globalPath: join2(home, ".factory", "skills")
|
|
1488
|
+
globalPath: join2(home, ".factory", "skills"),
|
|
1489
|
+
mcpProjectConfigPath: ".factory/mcp.json",
|
|
1490
|
+
mcpGlobalConfigPath: join2(home, ".factory", "mcp.json")
|
|
1401
1491
|
},
|
|
1402
1492
|
{
|
|
1403
1493
|
id: "gemini-cli",
|
|
1404
1494
|
name: "Gemini CLI",
|
|
1405
1495
|
projectPath: ".gemini/skills",
|
|
1406
|
-
globalPath: join2(home, ".gemini", "skills")
|
|
1496
|
+
globalPath: join2(home, ".gemini", "skills"),
|
|
1497
|
+
mcpProjectConfigPath: ".gemini/mcp.json",
|
|
1498
|
+
mcpGlobalConfigPath: join2(home, ".gemini", "mcp.json")
|
|
1407
1499
|
},
|
|
1408
1500
|
{
|
|
1409
1501
|
id: "github-copilot",
|
|
@@ -1411,79 +1503,108 @@ var AGENTS = [
|
|
|
1411
1503
|
projectPath: ".github/skills",
|
|
1412
1504
|
globalPath: join2(home, ".copilot", "skills"),
|
|
1413
1505
|
rulesProjectPath: ".github/copilot-instructions.md",
|
|
1414
|
-
ruleFormat: "append-single"
|
|
1506
|
+
ruleFormat: "append-single",
|
|
1507
|
+
mcpProjectConfigPath: ".vscode/mcp.json",
|
|
1508
|
+
mcpRootKey: "servers",
|
|
1509
|
+
mcpEntryStyle: "typed-stdio"
|
|
1415
1510
|
},
|
|
1416
1511
|
{
|
|
1417
1512
|
id: "goose",
|
|
1418
1513
|
name: "Goose",
|
|
1419
1514
|
projectPath: ".goose/skills",
|
|
1420
|
-
globalPath: join2(home, ".config", "goose", "skills")
|
|
1515
|
+
globalPath: join2(home, ".config", "goose", "skills"),
|
|
1516
|
+
mcpGlobalConfigPath: join2(home, ".config", "goose", "mcp.json")
|
|
1421
1517
|
},
|
|
1422
1518
|
{
|
|
1423
1519
|
id: "junie",
|
|
1424
1520
|
name: "Junie",
|
|
1425
1521
|
projectPath: ".junie/skills",
|
|
1426
|
-
globalPath: join2(home, ".junie", "skills")
|
|
1522
|
+
globalPath: join2(home, ".junie", "skills"),
|
|
1523
|
+
mcpProjectConfigPath: ".junie/mcp.json",
|
|
1524
|
+
mcpGlobalConfigPath: join2(home, ".junie", "mcp.json")
|
|
1427
1525
|
},
|
|
1428
1526
|
{
|
|
1429
1527
|
id: "kilo",
|
|
1430
1528
|
name: "Kilo Code",
|
|
1431
1529
|
projectPath: ".kilocode/skills",
|
|
1432
|
-
globalPath: join2(home, ".kilocode", "skills")
|
|
1530
|
+
globalPath: join2(home, ".kilocode", "skills"),
|
|
1531
|
+
mcpGlobalConfigPath: vscodeExtSettingsPath(
|
|
1532
|
+
"kilocode.kilo-code",
|
|
1533
|
+
"mcp_settings.json"
|
|
1534
|
+
),
|
|
1535
|
+
mcpEntryStyle: "cline"
|
|
1433
1536
|
},
|
|
1434
1537
|
{
|
|
1435
1538
|
id: "kiro-cli",
|
|
1436
1539
|
name: "Kiro CLI",
|
|
1437
1540
|
projectPath: ".kiro/skills",
|
|
1438
|
-
globalPath: join2(home, ".kiro", "skills")
|
|
1541
|
+
globalPath: join2(home, ".kiro", "skills"),
|
|
1542
|
+
mcpProjectConfigPath: ".kiro/mcp.json",
|
|
1543
|
+
mcpGlobalConfigPath: join2(home, ".kiro", "mcp.json")
|
|
1439
1544
|
},
|
|
1440
1545
|
{
|
|
1441
1546
|
id: "kode",
|
|
1442
1547
|
name: "Kode",
|
|
1443
1548
|
projectPath: ".kode/skills",
|
|
1444
|
-
globalPath: join2(home, ".kode", "skills")
|
|
1549
|
+
globalPath: join2(home, ".kode", "skills"),
|
|
1550
|
+
mcpProjectConfigPath: ".kode/mcp.json",
|
|
1551
|
+
mcpGlobalConfigPath: join2(home, ".kode", "mcp.json")
|
|
1445
1552
|
},
|
|
1446
1553
|
{
|
|
1447
1554
|
id: "mcpjam",
|
|
1448
1555
|
name: "MCPJam",
|
|
1449
1556
|
projectPath: ".mcpjam/skills",
|
|
1450
|
-
globalPath: join2(home, ".mcpjam", "skills")
|
|
1557
|
+
globalPath: join2(home, ".mcpjam", "skills"),
|
|
1558
|
+
mcpProjectConfigPath: ".mcpjam/mcp.json",
|
|
1559
|
+
mcpGlobalConfigPath: join2(home, ".mcpjam", "mcp.json")
|
|
1451
1560
|
},
|
|
1452
1561
|
{
|
|
1453
1562
|
id: "mux",
|
|
1454
1563
|
name: "Mux",
|
|
1455
1564
|
projectPath: ".mux/skills",
|
|
1456
|
-
globalPath: join2(home, ".mux", "skills")
|
|
1565
|
+
globalPath: join2(home, ".mux", "skills"),
|
|
1566
|
+
mcpProjectConfigPath: ".mux/mcp.json",
|
|
1567
|
+
mcpGlobalConfigPath: join2(home, ".mux", "mcp.json")
|
|
1457
1568
|
},
|
|
1458
1569
|
{
|
|
1459
1570
|
id: "opencode",
|
|
1460
1571
|
name: "OpenCode",
|
|
1461
1572
|
projectPath: ".opencode/skills",
|
|
1462
|
-
globalPath: join2(home, ".config", "opencode", "skills")
|
|
1573
|
+
globalPath: join2(home, ".config", "opencode", "skills"),
|
|
1574
|
+
mcpProjectConfigPath: ".opencode/mcp.json",
|
|
1575
|
+
mcpGlobalConfigPath: join2(home, ".config", "opencode", "mcp.json")
|
|
1463
1576
|
},
|
|
1464
1577
|
{
|
|
1465
1578
|
id: "openhands",
|
|
1466
1579
|
name: "OpenHands",
|
|
1467
1580
|
projectPath: ".openhands/skills",
|
|
1468
|
-
globalPath: join2(home, ".openhands", "skills")
|
|
1581
|
+
globalPath: join2(home, ".openhands", "skills"),
|
|
1582
|
+
mcpProjectConfigPath: ".openhands/mcp.json",
|
|
1583
|
+
mcpGlobalConfigPath: join2(home, ".openhands", "mcp.json")
|
|
1469
1584
|
},
|
|
1470
1585
|
{
|
|
1471
1586
|
id: "pi",
|
|
1472
1587
|
name: "Pi",
|
|
1473
1588
|
projectPath: ".pi/skills",
|
|
1474
|
-
globalPath: join2(home, ".pi", "agent", "skills")
|
|
1589
|
+
globalPath: join2(home, ".pi", "agent", "skills"),
|
|
1590
|
+
mcpProjectConfigPath: ".pi/mcp.json",
|
|
1591
|
+
mcpGlobalConfigPath: join2(home, ".pi", "agent", "mcp.json")
|
|
1475
1592
|
},
|
|
1476
1593
|
{
|
|
1477
1594
|
id: "qoder",
|
|
1478
1595
|
name: "Qoder",
|
|
1479
1596
|
projectPath: ".qoder/skills",
|
|
1480
|
-
globalPath: join2(home, ".qoder", "skills")
|
|
1597
|
+
globalPath: join2(home, ".qoder", "skills"),
|
|
1598
|
+
mcpProjectConfigPath: ".qoder/mcp.json",
|
|
1599
|
+
mcpGlobalConfigPath: join2(home, ".qoder", "mcp.json")
|
|
1481
1600
|
},
|
|
1482
1601
|
{
|
|
1483
1602
|
id: "qwen-code",
|
|
1484
1603
|
name: "Qwen Code",
|
|
1485
1604
|
projectPath: ".qwen/skills",
|
|
1486
|
-
globalPath: join2(home, ".qwen", "skills")
|
|
1605
|
+
globalPath: join2(home, ".qwen", "skills"),
|
|
1606
|
+
mcpProjectConfigPath: ".qwen/mcp.json",
|
|
1607
|
+
mcpGlobalConfigPath: join2(home, ".qwen", "mcp.json")
|
|
1487
1608
|
},
|
|
1488
1609
|
{
|
|
1489
1610
|
id: "roo",
|
|
@@ -1492,13 +1613,20 @@ var AGENTS = [
|
|
|
1492
1613
|
globalPath: join2(home, ".roo", "skills"),
|
|
1493
1614
|
rulesProjectPath: ".roo/rules",
|
|
1494
1615
|
rulesGlobalPath: join2(home, ".roo", "rules"),
|
|
1495
|
-
ruleFormat: "markdown-dir"
|
|
1616
|
+
ruleFormat: "markdown-dir",
|
|
1617
|
+
mcpGlobalConfigPath: vscodeExtSettingsPath(
|
|
1618
|
+
"rooveterinaryinc.roo-cline",
|
|
1619
|
+
"mcp_settings.json"
|
|
1620
|
+
),
|
|
1621
|
+
mcpEntryStyle: "cline"
|
|
1496
1622
|
},
|
|
1497
1623
|
{
|
|
1498
1624
|
id: "trae",
|
|
1499
1625
|
name: "Trae",
|
|
1500
1626
|
projectPath: ".trae/skills",
|
|
1501
|
-
globalPath: join2(home, ".trae", "skills")
|
|
1627
|
+
globalPath: join2(home, ".trae", "skills"),
|
|
1628
|
+
mcpProjectConfigPath: ".trae/mcp.json",
|
|
1629
|
+
mcpGlobalConfigPath: join2(home, ".trae", "mcp.json")
|
|
1502
1630
|
},
|
|
1503
1631
|
{
|
|
1504
1632
|
id: "windsurf",
|
|
@@ -1506,25 +1634,32 @@ var AGENTS = [
|
|
|
1506
1634
|
projectPath: ".windsurf/skills",
|
|
1507
1635
|
globalPath: join2(home, ".codeium", "windsurf", "skills"),
|
|
1508
1636
|
rulesProjectPath: ".windsurfrules",
|
|
1509
|
-
ruleFormat: "append-single"
|
|
1637
|
+
ruleFormat: "append-single",
|
|
1638
|
+
mcpGlobalConfigPath: join2(home, ".codeium", "windsurf", "mcp_config.json")
|
|
1510
1639
|
},
|
|
1511
1640
|
{
|
|
1512
1641
|
id: "zencoder",
|
|
1513
1642
|
name: "Zencoder",
|
|
1514
1643
|
projectPath: ".zencoder/skills",
|
|
1515
|
-
globalPath: join2(home, ".zencoder", "skills")
|
|
1644
|
+
globalPath: join2(home, ".zencoder", "skills"),
|
|
1645
|
+
mcpProjectConfigPath: ".zencoder/mcp.json",
|
|
1646
|
+
mcpGlobalConfigPath: join2(home, ".zencoder", "mcp.json")
|
|
1516
1647
|
},
|
|
1517
1648
|
{
|
|
1518
1649
|
id: "neovate",
|
|
1519
1650
|
name: "Neovate",
|
|
1520
1651
|
projectPath: ".neovate/skills",
|
|
1521
|
-
globalPath: join2(home, ".neovate", "skills")
|
|
1652
|
+
globalPath: join2(home, ".neovate", "skills"),
|
|
1653
|
+
mcpProjectConfigPath: ".neovate/mcp.json",
|
|
1654
|
+
mcpGlobalConfigPath: join2(home, ".neovate", "mcp.json")
|
|
1522
1655
|
},
|
|
1523
1656
|
{
|
|
1524
1657
|
id: "pochi",
|
|
1525
1658
|
name: "Pochi",
|
|
1526
1659
|
projectPath: ".pochi/skills",
|
|
1527
|
-
globalPath: join2(home, ".pochi", "skills")
|
|
1660
|
+
globalPath: join2(home, ".pochi", "skills"),
|
|
1661
|
+
mcpProjectConfigPath: ".pochi/mcp.json",
|
|
1662
|
+
mcpGlobalConfigPath: join2(home, ".pochi", "mcp.json")
|
|
1528
1663
|
},
|
|
1529
1664
|
{
|
|
1530
1665
|
id: "zed",
|
|
@@ -1535,7 +1670,10 @@ var AGENTS = [
|
|
|
1535
1670
|
globalMarkerPath: join2(home, ".config", "zed"),
|
|
1536
1671
|
rulesProjectPath: ".zed/rules",
|
|
1537
1672
|
rulesGlobalPath: join2(home, ".config", "zed", "rules"),
|
|
1538
|
-
ruleFormat: "markdown-dir"
|
|
1673
|
+
ruleFormat: "markdown-dir",
|
|
1674
|
+
mcpGlobalConfigPath: join2(home, ".config", "zed", "settings.json"),
|
|
1675
|
+
mcpRootKey: "context_servers",
|
|
1676
|
+
mcpEntryStyle: "zed"
|
|
1539
1677
|
}
|
|
1540
1678
|
];
|
|
1541
1679
|
var directoryExists = (path2) => pipe3(
|
|
@@ -1605,6 +1743,40 @@ var resolveRulesInstallPath = (agent, options) => {
|
|
|
1605
1743
|
const cwd = options.projectRoot ?? process6.cwd();
|
|
1606
1744
|
return join2(cwd, agent.rulesProjectPath);
|
|
1607
1745
|
};
|
|
1746
|
+
var hasMcpConfig = (agent) => Boolean(agent.mcpProjectConfigPath) || Boolean(agent.mcpGlobalConfigPath);
|
|
1747
|
+
var resolveMcpConfigPath = (agent, options) => {
|
|
1748
|
+
if (options.global) {
|
|
1749
|
+
return agent.mcpGlobalConfigPath;
|
|
1750
|
+
}
|
|
1751
|
+
if (agent.mcpProjectConfigPath) {
|
|
1752
|
+
const cwd = options.projectRoot ?? process6.cwd();
|
|
1753
|
+
return join2(cwd, agent.mcpProjectConfigPath);
|
|
1754
|
+
}
|
|
1755
|
+
return agent.mcpGlobalConfigPath;
|
|
1756
|
+
};
|
|
1757
|
+
var buildMcpEntry = (style, env) => {
|
|
1758
|
+
const command = "npx";
|
|
1759
|
+
const args = ["-y", "@braid-cloud/mcp"];
|
|
1760
|
+
const envObj = Object.keys(env).length > 0 ? env : void 0;
|
|
1761
|
+
switch (style) {
|
|
1762
|
+
case "standard":
|
|
1763
|
+
return envObj ? { command, args, env: envObj } : { command, args };
|
|
1764
|
+
case "typed-stdio":
|
|
1765
|
+
return envObj ? { type: "stdio", command, args, env: envObj } : { type: "stdio", command, args };
|
|
1766
|
+
case "zed":
|
|
1767
|
+
return envObj ? { command: { path: command, args, env: envObj } } : { command: { path: command, args } };
|
|
1768
|
+
case "cline":
|
|
1769
|
+
return envObj ? { command, args, env: envObj, disabled: false } : { command, args, disabled: false };
|
|
1770
|
+
default:
|
|
1771
|
+
return envObj ? { command, args, env: envObj } : { command, args };
|
|
1772
|
+
}
|
|
1773
|
+
};
|
|
1774
|
+
var detectMcpAgents = (projectRoot) => Effect3.runPromise(
|
|
1775
|
+
pipe3(
|
|
1776
|
+
detectAgents(projectRoot),
|
|
1777
|
+
Effect3.map((detected) => detected.filter(hasMcpConfig))
|
|
1778
|
+
)
|
|
1779
|
+
);
|
|
1608
1780
|
|
|
1609
1781
|
// src/commands/install.ts
|
|
1610
1782
|
init_api();
|
|
@@ -2219,7 +2391,7 @@ async function installCommand(options) {
|
|
|
2219
2391
|
const sourceDesc = buildSourceDescription(resolved);
|
|
2220
2392
|
intro(`Installing from ${sourceDesc}`);
|
|
2221
2393
|
const installSpinner = spinner();
|
|
2222
|
-
installSpinner.start("Fetching from
|
|
2394
|
+
installSpinner.start("Fetching from braid...");
|
|
2223
2395
|
try {
|
|
2224
2396
|
const fetchOptions = buildFetchOptions(resolved);
|
|
2225
2397
|
const response = await fetchSkillsAsync(fetchOptions);
|
|
@@ -2371,11 +2543,357 @@ async function listCommand(options) {
|
|
|
2371
2543
|
}
|
|
2372
2544
|
}
|
|
2373
2545
|
|
|
2546
|
+
// src/commands/mcp.ts
|
|
2547
|
+
init_esm_shims();
|
|
2548
|
+
import process7 from "process";
|
|
2549
|
+
init_config();
|
|
2550
|
+
|
|
2551
|
+
// src/lib/mcp-config.ts
|
|
2552
|
+
init_esm_shims();
|
|
2553
|
+
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
2554
|
+
import { dirname as dirname4 } from "path";
|
|
2555
|
+
import { Data as Data6, Effect as Effect7, pipe as pipe7 } from "effect";
|
|
2556
|
+
var McpConfigReadError = class extends Data6.TaggedError("McpConfigReadError") {
|
|
2557
|
+
};
|
|
2558
|
+
var McpConfigWriteError = class extends Data6.TaggedError("McpConfigWriteError") {
|
|
2559
|
+
};
|
|
2560
|
+
var readMcpConfig = (path2) => pipe7(
|
|
2561
|
+
Effect7.tryPromise({
|
|
2562
|
+
try: () => readFile4(path2, "utf-8"),
|
|
2563
|
+
catch: (e) => new McpConfigReadError({ path: path2, cause: e })
|
|
2564
|
+
}),
|
|
2565
|
+
Effect7.flatMap(
|
|
2566
|
+
(content) => Effect7.try({
|
|
2567
|
+
try: () => JSON.parse(content),
|
|
2568
|
+
catch: () => ({})
|
|
2569
|
+
})
|
|
2570
|
+
),
|
|
2571
|
+
Effect7.orElseSucceed(() => ({}))
|
|
2572
|
+
);
|
|
2573
|
+
var writeMcpConfig = (path2, config) => Effect7.tryPromise({
|
|
2574
|
+
try: async () => {
|
|
2575
|
+
await mkdir4(dirname4(path2), { recursive: true });
|
|
2576
|
+
await writeFile5(path2, `${JSON.stringify(config, null, 2)}
|
|
2577
|
+
`, "utf-8");
|
|
2578
|
+
},
|
|
2579
|
+
catch: (e) => new McpConfigWriteError({ path: path2, cause: e })
|
|
2580
|
+
});
|
|
2581
|
+
var mergebraidEntry = (config, rootKey, entryName, entry) => {
|
|
2582
|
+
const servers = config[rootKey] ?? {};
|
|
2583
|
+
return {
|
|
2584
|
+
...config,
|
|
2585
|
+
[rootKey]: {
|
|
2586
|
+
...servers,
|
|
2587
|
+
[entryName]: entry
|
|
2588
|
+
}
|
|
2589
|
+
};
|
|
2590
|
+
};
|
|
2591
|
+
var removebraidEntry = (config, rootKey, entryName) => {
|
|
2592
|
+
const servers = { ...config[rootKey] ?? {} };
|
|
2593
|
+
delete servers[entryName];
|
|
2594
|
+
return {
|
|
2595
|
+
...config,
|
|
2596
|
+
[rootKey]: servers
|
|
2597
|
+
};
|
|
2598
|
+
};
|
|
2599
|
+
var hasbraidEntry = (config, rootKey, entryName) => {
|
|
2600
|
+
const servers = config[rootKey];
|
|
2601
|
+
return servers !== void 0 && entryName in servers;
|
|
2602
|
+
};
|
|
2603
|
+
var readMcpConfigAsync = (path2) => Effect7.runPromise(readMcpConfig(path2));
|
|
2604
|
+
var writeMcpConfigAsync = (path2, config) => Effect7.runPromise(writeMcpConfig(path2, config));
|
|
2605
|
+
|
|
2606
|
+
// src/commands/mcp.ts
|
|
2607
|
+
init_tui();
|
|
2608
|
+
var BRAID_ENTRY_NAME = "braid";
|
|
2609
|
+
function maskToken(token) {
|
|
2610
|
+
if (token.length <= 10) {
|
|
2611
|
+
return token;
|
|
2612
|
+
}
|
|
2613
|
+
return `${token.slice(0, 7)}...${token.slice(-4)}`;
|
|
2614
|
+
}
|
|
2615
|
+
function getMcpAgents() {
|
|
2616
|
+
return AGENTS.filter(hasMcpConfig);
|
|
2617
|
+
}
|
|
2618
|
+
function resolveScope(agent, options) {
|
|
2619
|
+
if (options.global) {
|
|
2620
|
+
return "global";
|
|
2621
|
+
}
|
|
2622
|
+
if (agent.mcpProjectConfigPath) {
|
|
2623
|
+
return "project";
|
|
2624
|
+
}
|
|
2625
|
+
return "global";
|
|
2626
|
+
}
|
|
2627
|
+
async function selectTool(mcpAgents, toolFlag) {
|
|
2628
|
+
if (toolFlag) {
|
|
2629
|
+
const agent = mcpAgents.find((a) => a.id === toolFlag);
|
|
2630
|
+
if (!agent) {
|
|
2631
|
+
log.error(`Unknown or unsupported tool: ${toolFlag}`);
|
|
2632
|
+
log.info(`Supported tools: ${mcpAgents.map((a) => a.id).join(", ")}`);
|
|
2633
|
+
process7.exit(1);
|
|
2634
|
+
}
|
|
2635
|
+
return agent;
|
|
2636
|
+
}
|
|
2637
|
+
const detected = await detectMcpAgents();
|
|
2638
|
+
const detectedIds = new Set(detected.map((a) => a.id));
|
|
2639
|
+
const toolChoice = await select({
|
|
2640
|
+
message: "Select tool to configure:",
|
|
2641
|
+
options: mcpAgents.map((agent) => ({
|
|
2642
|
+
value: agent.id,
|
|
2643
|
+
label: agent.name,
|
|
2644
|
+
hint: [
|
|
2645
|
+
agent.mcpProjectConfigPath ?? agent.mcpGlobalConfigPath,
|
|
2646
|
+
detectedIds.has(agent.id) ? "detected" : void 0
|
|
2647
|
+
].filter(Boolean).join(" \u2014 ")
|
|
2648
|
+
}))
|
|
2649
|
+
});
|
|
2650
|
+
if (isCancel(toolChoice)) {
|
|
2651
|
+
cancel("MCP setup cancelled.");
|
|
2652
|
+
process7.exit(0);
|
|
2653
|
+
}
|
|
2654
|
+
const found = mcpAgents.find((a) => a.id === toolChoice);
|
|
2655
|
+
if (!found) {
|
|
2656
|
+
log.error("Agent not found.");
|
|
2657
|
+
process7.exit(1);
|
|
2658
|
+
}
|
|
2659
|
+
return found;
|
|
2660
|
+
}
|
|
2661
|
+
async function selectScope(agent, options) {
|
|
2662
|
+
const initial = resolveScope(agent, options);
|
|
2663
|
+
if (options.global || options.yes || !agent.mcpProjectConfigPath || !agent.mcpGlobalConfigPath) {
|
|
2664
|
+
return initial;
|
|
2665
|
+
}
|
|
2666
|
+
const scopeChoice = await select({
|
|
2667
|
+
message: "Where should this be configured?",
|
|
2668
|
+
options: [
|
|
2669
|
+
{
|
|
2670
|
+
value: "project",
|
|
2671
|
+
label: "Project",
|
|
2672
|
+
hint: agent.mcpProjectConfigPath
|
|
2673
|
+
},
|
|
2674
|
+
{
|
|
2675
|
+
value: "global",
|
|
2676
|
+
label: "Global",
|
|
2677
|
+
hint: agent.mcpGlobalConfigPath
|
|
2678
|
+
}
|
|
2679
|
+
]
|
|
2680
|
+
});
|
|
2681
|
+
if (isCancel(scopeChoice)) {
|
|
2682
|
+
cancel("MCP setup cancelled.");
|
|
2683
|
+
process7.exit(0);
|
|
2684
|
+
}
|
|
2685
|
+
return scopeChoice;
|
|
2686
|
+
}
|
|
2687
|
+
async function resolveToken(options, existingToken) {
|
|
2688
|
+
if (options.auth === false) {
|
|
2689
|
+
return void 0;
|
|
2690
|
+
}
|
|
2691
|
+
if (options.token) {
|
|
2692
|
+
return options.token;
|
|
2693
|
+
}
|
|
2694
|
+
if (existingToken && options.yes) {
|
|
2695
|
+
return existingToken;
|
|
2696
|
+
}
|
|
2697
|
+
if (existingToken) {
|
|
2698
|
+
const authChoice = await select({
|
|
2699
|
+
message: "Authentication:",
|
|
2700
|
+
options: [
|
|
2701
|
+
{
|
|
2702
|
+
value: "existing",
|
|
2703
|
+
label: `Use existing token (${maskToken(existingToken)})`
|
|
2704
|
+
},
|
|
2705
|
+
{ value: "new", label: "Enter a new token" },
|
|
2706
|
+
{
|
|
2707
|
+
value: "skip",
|
|
2708
|
+
label: "Skip \u2014 set BRAID_TOKEN env var later"
|
|
2709
|
+
}
|
|
2710
|
+
]
|
|
2711
|
+
});
|
|
2712
|
+
if (isCancel(authChoice)) {
|
|
2713
|
+
cancel("MCP setup cancelled.");
|
|
2714
|
+
process7.exit(0);
|
|
2715
|
+
}
|
|
2716
|
+
if (authChoice === "existing") {
|
|
2717
|
+
return existingToken;
|
|
2718
|
+
}
|
|
2719
|
+
if (authChoice === "skip") {
|
|
2720
|
+
return void 0;
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
const token = await password({
|
|
2724
|
+
message: "Enter your braid API token:",
|
|
2725
|
+
validate: (value) => {
|
|
2726
|
+
if (!value) {
|
|
2727
|
+
return "Token is required";
|
|
2728
|
+
}
|
|
2729
|
+
if (!value.startsWith("br_")) {
|
|
2730
|
+
return "Token should start with 'br_'";
|
|
2731
|
+
}
|
|
2732
|
+
return void 0;
|
|
2733
|
+
}
|
|
2734
|
+
});
|
|
2735
|
+
if (isCancel(token)) {
|
|
2736
|
+
cancel("MCP setup cancelled.");
|
|
2737
|
+
process7.exit(0);
|
|
2738
|
+
}
|
|
2739
|
+
return token;
|
|
2740
|
+
}
|
|
2741
|
+
function buildEnvVars(token, server) {
|
|
2742
|
+
const env = {};
|
|
2743
|
+
if (token) {
|
|
2744
|
+
env.BRAID_TOKEN = token;
|
|
2745
|
+
}
|
|
2746
|
+
if (server) {
|
|
2747
|
+
env.BRAID_MCP_URL = server;
|
|
2748
|
+
}
|
|
2749
|
+
return env;
|
|
2750
|
+
}
|
|
2751
|
+
async function writeEntry(agent, configPath, env) {
|
|
2752
|
+
const entry = buildMcpEntry(agent.mcpEntryStyle ?? "standard", env);
|
|
2753
|
+
const rootKey = agent.mcpRootKey ?? "mcpServers";
|
|
2754
|
+
const existingConfig = await readMcpConfigAsync(configPath);
|
|
2755
|
+
const updatedConfig = mergebraidEntry(
|
|
2756
|
+
existingConfig,
|
|
2757
|
+
rootKey,
|
|
2758
|
+
BRAID_ENTRY_NAME,
|
|
2759
|
+
entry
|
|
2760
|
+
);
|
|
2761
|
+
await writeMcpConfigAsync(configPath, updatedConfig);
|
|
2762
|
+
}
|
|
2763
|
+
async function addFlow(options) {
|
|
2764
|
+
const config = await loadMergedConfigAsync();
|
|
2765
|
+
const mcpAgents = getMcpAgents();
|
|
2766
|
+
if (mcpAgents.length === 0) {
|
|
2767
|
+
log.error("No agents with MCP configuration support found.");
|
|
2768
|
+
process7.exit(1);
|
|
2769
|
+
}
|
|
2770
|
+
const selectedAgent = await selectTool(mcpAgents, options.tool);
|
|
2771
|
+
const scope = await selectScope(selectedAgent, options);
|
|
2772
|
+
const configPath = resolveMcpConfigPath(selectedAgent, {
|
|
2773
|
+
global: scope === "global"
|
|
2774
|
+
});
|
|
2775
|
+
if (!configPath) {
|
|
2776
|
+
log.error(`No ${scope} config path available for ${selectedAgent.name}.`);
|
|
2777
|
+
process7.exit(1);
|
|
2778
|
+
}
|
|
2779
|
+
const token = await resolveToken(options, config.token);
|
|
2780
|
+
const env = buildEnvVars(token, options.server);
|
|
2781
|
+
if (options.scope) {
|
|
2782
|
+
const { scopeCommand: scopeCommand2 } = await Promise.resolve().then(() => (init_scope(), scope_exports));
|
|
2783
|
+
await scopeCommand2({
|
|
2784
|
+
server: options.server ?? config.serverUrl,
|
|
2785
|
+
...config.token ? { apiKey: config.token } : {}
|
|
2786
|
+
});
|
|
2787
|
+
}
|
|
2788
|
+
const mcpSpinner = spinner();
|
|
2789
|
+
mcpSpinner.start(`Configuring ${selectedAgent.name}...`);
|
|
2790
|
+
try {
|
|
2791
|
+
await writeEntry(selectedAgent, configPath, env);
|
|
2792
|
+
mcpSpinner.stop(`Configured ${selectedAgent.name}`);
|
|
2793
|
+
log.info(`Config written to ${configPath}`);
|
|
2794
|
+
if (!token) {
|
|
2795
|
+
log.info("Set BRAID_TOKEN environment variable before using.");
|
|
2796
|
+
}
|
|
2797
|
+
outro(`Done! Restart ${selectedAgent.name} to activate.`);
|
|
2798
|
+
} catch (error) {
|
|
2799
|
+
mcpSpinner.stop("Configuration failed");
|
|
2800
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2801
|
+
log.error(`Failed to write config: ${message}`);
|
|
2802
|
+
process7.exit(1);
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
async function removeFlow(options) {
|
|
2806
|
+
const mcpAgents = getMcpAgents();
|
|
2807
|
+
const selectedAgent = await selectTool(mcpAgents, options.tool);
|
|
2808
|
+
const scope = resolveScope(selectedAgent, options);
|
|
2809
|
+
const configPath = resolveMcpConfigPath(selectedAgent, {
|
|
2810
|
+
global: scope === "global"
|
|
2811
|
+
});
|
|
2812
|
+
if (!configPath) {
|
|
2813
|
+
log.error(`No ${scope} config path available for ${selectedAgent.name}.`);
|
|
2814
|
+
process7.exit(1);
|
|
2815
|
+
}
|
|
2816
|
+
const removeSpinner = spinner();
|
|
2817
|
+
removeSpinner.start(`Removing braid from ${selectedAgent.name}...`);
|
|
2818
|
+
try {
|
|
2819
|
+
const rootKey = selectedAgent.mcpRootKey ?? "mcpServers";
|
|
2820
|
+
const existingConfig = await readMcpConfigAsync(configPath);
|
|
2821
|
+
if (!hasbraidEntry(existingConfig, rootKey, BRAID_ENTRY_NAME)) {
|
|
2822
|
+
removeSpinner.stop("No braid MCP entry found");
|
|
2823
|
+
log.info(
|
|
2824
|
+
`${selectedAgent.name} doesn't have a braid MCP entry at ${configPath}`
|
|
2825
|
+
);
|
|
2826
|
+
return;
|
|
2827
|
+
}
|
|
2828
|
+
const updatedConfig = removebraidEntry(
|
|
2829
|
+
existingConfig,
|
|
2830
|
+
rootKey,
|
|
2831
|
+
BRAID_ENTRY_NAME
|
|
2832
|
+
);
|
|
2833
|
+
await writeMcpConfigAsync(configPath, updatedConfig);
|
|
2834
|
+
removeSpinner.stop(`Removed braid from ${selectedAgent.name}`);
|
|
2835
|
+
outro(`braid MCP removed from ${configPath}`);
|
|
2836
|
+
} catch (error) {
|
|
2837
|
+
removeSpinner.stop("Removal failed");
|
|
2838
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2839
|
+
log.error(`Failed to remove config: ${message}`);
|
|
2840
|
+
process7.exit(1);
|
|
2841
|
+
}
|
|
2842
|
+
}
|
|
2843
|
+
async function statusFlow() {
|
|
2844
|
+
const mcpAgents = getMcpAgents();
|
|
2845
|
+
const statusSpinner = spinner();
|
|
2846
|
+
statusSpinner.start("Checking MCP configuration status...");
|
|
2847
|
+
const results = [];
|
|
2848
|
+
for (const agent of mcpAgents) {
|
|
2849
|
+
const rootKey = agent.mcpRootKey ?? "mcpServers";
|
|
2850
|
+
for (const scope of ["project", "global"]) {
|
|
2851
|
+
const configPath = resolveMcpConfigPath(agent, {
|
|
2852
|
+
global: scope === "global"
|
|
2853
|
+
});
|
|
2854
|
+
if (!configPath) {
|
|
2855
|
+
continue;
|
|
2856
|
+
}
|
|
2857
|
+
const config = await readMcpConfigAsync(configPath);
|
|
2858
|
+
if (hasbraidEntry(config, rootKey, BRAID_ENTRY_NAME)) {
|
|
2859
|
+
results.push({
|
|
2860
|
+
name: agent.name,
|
|
2861
|
+
path: configPath,
|
|
2862
|
+
scope
|
|
2863
|
+
});
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
statusSpinner.stop(`Found ${results.length} configured tool(s)`);
|
|
2868
|
+
if (results.length === 0) {
|
|
2869
|
+
log.info("No tools have braid MCP configured.");
|
|
2870
|
+
log.info("Run 'braid mcp' to set up MCP for your AI tools.");
|
|
2871
|
+
return;
|
|
2872
|
+
}
|
|
2873
|
+
for (const result of results) {
|
|
2874
|
+
log.info(` ${result.name} (${result.scope}) \u2192 ${result.path}`);
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
async function mcpCommand(options) {
|
|
2878
|
+
if (options.status) {
|
|
2879
|
+
intro("braid mcp status");
|
|
2880
|
+
await statusFlow();
|
|
2881
|
+
return;
|
|
2882
|
+
}
|
|
2883
|
+
if (options.remove) {
|
|
2884
|
+
intro("braid mcp remove");
|
|
2885
|
+
await removeFlow(options);
|
|
2886
|
+
return;
|
|
2887
|
+
}
|
|
2888
|
+
intro("braid mcp");
|
|
2889
|
+
await addFlow(options);
|
|
2890
|
+
}
|
|
2891
|
+
|
|
2374
2892
|
// src/commands/remove.ts
|
|
2375
2893
|
init_esm_shims();
|
|
2376
2894
|
import { rm } from "fs/promises";
|
|
2377
2895
|
import { join as join4, resolve as resolve3 } from "path";
|
|
2378
|
-
import
|
|
2896
|
+
import process8 from "process";
|
|
2379
2897
|
init_tui();
|
|
2380
2898
|
async function collectInstalledSkills(detectedAgents, options) {
|
|
2381
2899
|
const skillsToRemove = [];
|
|
@@ -2408,7 +2926,7 @@ async function selectSkillsToRemove(skillsToRemove, options) {
|
|
|
2408
2926
|
if (selected.length === 0) {
|
|
2409
2927
|
log.error(`Skill '${options.skill}' not found.`);
|
|
2410
2928
|
log.info("Run 'braid list' to see installed skills.");
|
|
2411
|
-
|
|
2929
|
+
process8.exit(1);
|
|
2412
2930
|
}
|
|
2413
2931
|
return selected;
|
|
2414
2932
|
}
|
|
@@ -2427,7 +2945,7 @@ async function selectSkillsToRemove(skillsToRemove, options) {
|
|
|
2427
2945
|
});
|
|
2428
2946
|
if (isCancel(result)) {
|
|
2429
2947
|
cancel("Remove cancelled.");
|
|
2430
|
-
|
|
2948
|
+
process8.exit(0);
|
|
2431
2949
|
}
|
|
2432
2950
|
return result;
|
|
2433
2951
|
}
|
|
@@ -2441,7 +2959,7 @@ async function confirmRemoval(selectedCount, options) {
|
|
|
2441
2959
|
});
|
|
2442
2960
|
if (isCancel(confirmed) || !confirmed) {
|
|
2443
2961
|
cancel("Remove cancelled.");
|
|
2444
|
-
|
|
2962
|
+
process8.exit(0);
|
|
2445
2963
|
}
|
|
2446
2964
|
}
|
|
2447
2965
|
async function removeSkill(skill, removeSpinner) {
|
|
@@ -2505,7 +3023,7 @@ async function removeCommand(options) {
|
|
|
2505
3023
|
removeSpinner.stop("Remove failed");
|
|
2506
3024
|
const message = error instanceof Error ? error.message : String(error);
|
|
2507
3025
|
log.error(message);
|
|
2508
|
-
|
|
3026
|
+
process8.exit(1);
|
|
2509
3027
|
}
|
|
2510
3028
|
}
|
|
2511
3029
|
|
|
@@ -2522,11 +3040,11 @@ import {
|
|
|
2522
3040
|
outro as outro2,
|
|
2523
3041
|
spinner as spinner3
|
|
2524
3042
|
} from "@clack/prompts";
|
|
2525
|
-
import { Data as
|
|
3043
|
+
import { Data as Data7, Effect as Effect8, pipe as pipe8 } from "effect";
|
|
2526
3044
|
init_api();
|
|
2527
|
-
var UpdateError = class extends
|
|
3045
|
+
var UpdateError = class extends Data7.TaggedError("UpdateError") {
|
|
2528
3046
|
};
|
|
2529
|
-
var UserCancelledError = class extends
|
|
3047
|
+
var UserCancelledError = class extends Data7.TaggedError("UserCancelledError") {
|
|
2530
3048
|
};
|
|
2531
3049
|
async function resolveValidInstallPath(agent, options) {
|
|
2532
3050
|
const installPath = resolveInstallPath(agent, {
|
|
@@ -2538,7 +3056,7 @@ async function resolveValidInstallPath(agent, options) {
|
|
|
2538
3056
|
const exists = await directoryExistsAsync(installPath);
|
|
2539
3057
|
return exists ? installPath : null;
|
|
2540
3058
|
}
|
|
2541
|
-
var collectSourcesFromAgent = (agent, options, sourcesToUpdate) =>
|
|
3059
|
+
var collectSourcesFromAgent = (agent, options, sourcesToUpdate) => Effect8.tryPromise({
|
|
2542
3060
|
try: async () => {
|
|
2543
3061
|
const installPath = await resolveValidInstallPath(agent, options);
|
|
2544
3062
|
if (!installPath) {
|
|
@@ -2569,10 +3087,10 @@ var collectSourcesFromAgent = (agent, options, sourcesToUpdate) => Effect7.tryPr
|
|
|
2569
3087
|
},
|
|
2570
3088
|
catch: () => new UpdateError({ message: "Failed to collect sources" })
|
|
2571
3089
|
});
|
|
2572
|
-
var collectSources = (detectedAgents, options) =>
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
(sourcesToUpdate) =>
|
|
3090
|
+
var collectSources = (detectedAgents, options) => pipe8(
|
|
3091
|
+
Effect8.succeed(/* @__PURE__ */ new Map()),
|
|
3092
|
+
Effect8.tap(
|
|
3093
|
+
(sourcesToUpdate) => Effect8.forEach(
|
|
2576
3094
|
detectedAgents,
|
|
2577
3095
|
(agent) => collectSourcesFromAgent(agent, options, sourcesToUpdate),
|
|
2578
3096
|
{ concurrency: 1 }
|
|
@@ -2581,9 +3099,9 @@ var collectSources = (detectedAgents, options) => pipe7(
|
|
|
2581
3099
|
);
|
|
2582
3100
|
var selectSources = (sourcesToUpdate, options) => {
|
|
2583
3101
|
if (options.yes) {
|
|
2584
|
-
return
|
|
3102
|
+
return Effect8.succeed(sourcesToUpdate);
|
|
2585
3103
|
}
|
|
2586
|
-
return
|
|
3104
|
+
return Effect8.tryPromise({
|
|
2587
3105
|
try: async () => {
|
|
2588
3106
|
const sources = Array.from(sourcesToUpdate.entries()).map(
|
|
2589
3107
|
([key, source]) => ({
|
|
@@ -2634,7 +3152,7 @@ var buildFetchOptionsForSource = (source, options) => {
|
|
|
2634
3152
|
}
|
|
2635
3153
|
return fetchOptions;
|
|
2636
3154
|
};
|
|
2637
|
-
var updateAgentSkills = (agentId, agentName, installPath, response, serverUrl, updateSpinner) =>
|
|
3155
|
+
var updateAgentSkills = (agentId, agentName, installPath, response, serverUrl, updateSpinner) => Effect8.tryPromise({
|
|
2638
3156
|
try: async () => {
|
|
2639
3157
|
updateSpinner.start(`Updating ${agentName}...`);
|
|
2640
3158
|
const result = await writeSkillsAsync(
|
|
@@ -2672,15 +3190,15 @@ var updateSource = (source, options, updateSpinner) => {
|
|
|
2672
3190
|
const serverUrl = options.server ?? source.serverUrl;
|
|
2673
3191
|
const fetchOptions = buildFetchOptionsForSource(source, options);
|
|
2674
3192
|
if (fetchOptions === null) {
|
|
2675
|
-
return
|
|
3193
|
+
return Effect8.fail(
|
|
2676
3194
|
new UpdateError({
|
|
2677
3195
|
message: "Skills installed with legacy metadata format. Please reinstall using 'braid install --profile <name>' or 'braid install --projects <names>'.",
|
|
2678
3196
|
source: sourceDesc
|
|
2679
3197
|
})
|
|
2680
3198
|
);
|
|
2681
3199
|
}
|
|
2682
|
-
return
|
|
2683
|
-
|
|
3200
|
+
return pipe8(
|
|
3201
|
+
Effect8.tryPromise({
|
|
2684
3202
|
try: async () => {
|
|
2685
3203
|
updateSpinner.start(`Fetching latest skills from ${sourceDesc}...`);
|
|
2686
3204
|
const response = await fetchSkillsAsync(fetchOptions);
|
|
@@ -2694,9 +3212,9 @@ var updateSource = (source, options, updateSpinner) => {
|
|
|
2694
3212
|
source: sourceDesc
|
|
2695
3213
|
})
|
|
2696
3214
|
}),
|
|
2697
|
-
|
|
2698
|
-
(response) =>
|
|
2699
|
-
|
|
3215
|
+
Effect8.flatMap(
|
|
3216
|
+
(response) => pipe8(
|
|
3217
|
+
Effect8.forEach(
|
|
2700
3218
|
source.agents,
|
|
2701
3219
|
({ agentId, agentName, installPath }) => updateAgentSkills(
|
|
2702
3220
|
agentId,
|
|
@@ -2708,7 +3226,7 @@ var updateSource = (source, options, updateSpinner) => {
|
|
|
2708
3226
|
),
|
|
2709
3227
|
{ concurrency: 1 }
|
|
2710
3228
|
),
|
|
2711
|
-
|
|
3229
|
+
Effect8.map((results) => ({
|
|
2712
3230
|
updated: results.reduce((sum, r) => sum + r.updated, 0),
|
|
2713
3231
|
errors: results.reduce((sum, r) => sum + r.errors, 0)
|
|
2714
3232
|
}))
|
|
@@ -2716,22 +3234,22 @@ var updateSource = (source, options, updateSpinner) => {
|
|
|
2716
3234
|
)
|
|
2717
3235
|
);
|
|
2718
3236
|
};
|
|
2719
|
-
var updateAllSources = (sources, options, updateSpinner) =>
|
|
2720
|
-
|
|
3237
|
+
var updateAllSources = (sources, options, updateSpinner) => pipe8(
|
|
3238
|
+
Effect8.forEach(
|
|
2721
3239
|
Array.from(sources.values()),
|
|
2722
|
-
(source) =>
|
|
3240
|
+
(source) => pipe8(
|
|
2723
3241
|
updateSource(source, options, updateSpinner),
|
|
2724
|
-
|
|
3242
|
+
Effect8.catchAll((error) => {
|
|
2725
3243
|
updateSpinner.stop(
|
|
2726
3244
|
`Failed to update from ${getSourceDesc(source)}`
|
|
2727
3245
|
);
|
|
2728
3246
|
log3.error(` ${error.message}`);
|
|
2729
|
-
return
|
|
3247
|
+
return Effect8.succeed({ updated: 0, errors: 1 });
|
|
2730
3248
|
})
|
|
2731
3249
|
),
|
|
2732
3250
|
{ concurrency: 1 }
|
|
2733
3251
|
),
|
|
2734
|
-
|
|
3252
|
+
Effect8.map((results) => ({
|
|
2735
3253
|
totalUpdated: results.reduce((sum, r) => sum + r.updated, 0),
|
|
2736
3254
|
totalErrors: results.reduce((sum, r) => sum + r.errors, 0)
|
|
2737
3255
|
}))
|
|
@@ -2770,28 +3288,28 @@ var handleProgramExit = (result, updateSpinner) => {
|
|
|
2770
3288
|
async function updateCommand(options) {
|
|
2771
3289
|
const updateSpinner = spinner3();
|
|
2772
3290
|
updateSpinner.start("Scanning for installed skills...");
|
|
2773
|
-
const program2 =
|
|
2774
|
-
|
|
3291
|
+
const program2 = pipe8(
|
|
3292
|
+
Effect8.tryPromise({
|
|
2775
3293
|
try: () => detectAgentsAsync(),
|
|
2776
3294
|
catch: () => new UpdateError({ message: "Failed to detect agents" })
|
|
2777
3295
|
}),
|
|
2778
|
-
|
|
3296
|
+
Effect8.filterOrFail(
|
|
2779
3297
|
(agents) => agents.length > 0,
|
|
2780
3298
|
() => new UpdateError({ message: "No AI coding agents detected." })
|
|
2781
3299
|
),
|
|
2782
|
-
|
|
2783
|
-
|
|
3300
|
+
Effect8.flatMap((detectedAgents) => collectSources(detectedAgents, options)),
|
|
3301
|
+
Effect8.tap((sources) => {
|
|
2784
3302
|
updateSpinner.stop(`Found ${sources.size} source(s) to update`);
|
|
2785
3303
|
}),
|
|
2786
|
-
|
|
3304
|
+
Effect8.filterOrFail(
|
|
2787
3305
|
(sources) => sources.size > 0,
|
|
2788
3306
|
() => new UpdateError({ message: "No skills installed via braid." })
|
|
2789
3307
|
),
|
|
2790
|
-
|
|
2791
|
-
|
|
3308
|
+
Effect8.flatMap((sources) => selectSources(sources, options)),
|
|
3309
|
+
Effect8.flatMap(
|
|
2792
3310
|
(selectedSources) => updateAllSources(selectedSources, options, updateSpinner)
|
|
2793
3311
|
),
|
|
2794
|
-
|
|
3312
|
+
Effect8.tap(({ totalUpdated, totalErrors }) => {
|
|
2795
3313
|
if (totalErrors > 0) {
|
|
2796
3314
|
outro2(`Updated ${totalUpdated} skills with ${totalErrors} errors.`);
|
|
2797
3315
|
} else {
|
|
@@ -2799,7 +3317,7 @@ async function updateCommand(options) {
|
|
|
2799
3317
|
}
|
|
2800
3318
|
})
|
|
2801
3319
|
);
|
|
2802
|
-
const result = await
|
|
3320
|
+
const result = await Effect8.runPromiseExit(program2);
|
|
2803
3321
|
handleProgramExit(result, updateSpinner);
|
|
2804
3322
|
}
|
|
2805
3323
|
|
|
@@ -2808,10 +3326,10 @@ var require2 = createRequire(import.meta.url);
|
|
|
2808
3326
|
var { version: PACKAGE_VERSION } = require2("../package.json");
|
|
2809
3327
|
var program = new Command();
|
|
2810
3328
|
program.name("braid").description(
|
|
2811
|
-
"Install
|
|
3329
|
+
"Install braid prompts as agent skills to your local development environment"
|
|
2812
3330
|
).version(PACKAGE_VERSION);
|
|
2813
|
-
var auth = program.command("auth").description("Configure API key for
|
|
2814
|
-
auth.command("login", { isDefault: true }).description("Configure API key").option("-s, --server <url>", "
|
|
3331
|
+
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);
|
|
2815
3333
|
auth.command("status").description("Show current authentication status").action(authStatusCommand);
|
|
2816
3334
|
auth.command("logout").description("Remove stored API key").action(authLogoutCommand);
|
|
2817
3335
|
program.command("install").alias("add").description("Install skills from a profile or project").option("-p, --profile <name>", "Profile name to install from").option(
|
|
@@ -2829,7 +3347,7 @@ program.command("install").alias("add").description("Install skills from a profi
|
|
|
2829
3347
|
).option("--no-include-org-globals", "Exclude organization's global prompts").option(
|
|
2830
3348
|
"-a, --agents <list>",
|
|
2831
3349
|
"Comma-separated list of agents (e.g., claude-code,opencode)"
|
|
2832
|
-
).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>", "
|
|
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(installCommand);
|
|
2833
3351
|
program.command("scope").description("Interactively configure braid.json or braid.user.json scope").option("--file <target>", "Config file target: user or project").option(
|
|
2834
3352
|
"--organization <type>",
|
|
2835
3353
|
"Scope organization for non-interactive mode: personal or organization"
|
|
@@ -2851,9 +3369,10 @@ program.command("scope").description("Interactively configure braid.json or brai
|
|
|
2851
3369
|
).option(
|
|
2852
3370
|
"--include-org-global",
|
|
2853
3371
|
"Include org global rules in non-interactive mode"
|
|
2854
|
-
).option("-s, --server <url>", "
|
|
3372
|
+
).option("-s, --server <url>", "braid server URL (for review apps, local dev)").action(scopeCommand);
|
|
2855
3373
|
program.command("list").alias("ls").description("List installed skills").option("-g, --global", "List skills in global directories only").action(listCommand);
|
|
2856
|
-
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>", "
|
|
3374
|
+
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);
|
|
2857
3375
|
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);
|
|
2858
3377
|
program.parse();
|
|
2859
3378
|
//# sourceMappingURL=index.js.map
|