@braid-cloud/cli 0.1.16 → 0.1.18
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 +1 -1
- package/dist/index.js +460 -141
- package/dist/index.js.map +1 -1
- package/dist/manage-ui/assets/index-BBmBYWoe.css +2 -0
- package/dist/manage-ui/assets/{index-BFp1kLOE.js → index-RfQhJisb.js} +1 -1
- package/dist/manage-ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/manage-ui/assets/index-De7GJyM1.css +0 -2
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ var init_esm_shims = __esm({
|
|
|
20
20
|
|
|
21
21
|
// src/lib/braid-workspace.ts
|
|
22
22
|
import { existsSync, readFileSync } from "fs";
|
|
23
|
-
import { dirname as
|
|
23
|
+
import { dirname as dirname3, join as join2 } from "path";
|
|
24
24
|
import process3 from "process";
|
|
25
25
|
function readPackageName(packagePath) {
|
|
26
26
|
if (!existsSync(packagePath)) {
|
|
@@ -44,7 +44,7 @@ function findBraidWorkspaceRoot(startDir = process3.cwd()) {
|
|
|
44
44
|
if (isBraidWorkspaceRoot(currentDir)) {
|
|
45
45
|
return currentDir;
|
|
46
46
|
}
|
|
47
|
-
const parentDir =
|
|
47
|
+
const parentDir = dirname3(currentDir);
|
|
48
48
|
if (parentDir === currentDir) {
|
|
49
49
|
return void 0;
|
|
50
50
|
}
|
|
@@ -107,7 +107,7 @@ __export(config_exports, {
|
|
|
107
107
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
108
108
|
import { mkdir as mkdir2, readFile, writeFile as writeFile2 } from "fs/promises";
|
|
109
109
|
import { homedir as homedir2 } from "os";
|
|
110
|
-
import { dirname as
|
|
110
|
+
import { dirname as dirname4, join as join3, parse } from "path";
|
|
111
111
|
import process4 from "process";
|
|
112
112
|
import { Data as Data2, Effect as Effect3, pipe as pipe3 } from "effect";
|
|
113
113
|
var CONFIG_DIR, CONFIG_FILE, PROJECT_CONFIG_FILENAME, USER_CONFIG_FILENAME, CONVEX_CLOUD_SUFFIX_REGEX, LOCAL_CONVEX_PORT_REGEX, LOCAL_SERVER_ENV_FILES, LOOPBACK_HOSTS, NEWLINE_REGEX, TRAILING_SLASHES, ConfigReadError, ConfigWriteError, findConfigFile, findProjectConfigFile, findUserConfigFile, stripQuotes, parseDotenv, normalizeBaseUrl, resolveConvexSiteUrl, resolveLocalServerUrlFromEnv, resolveLocalServerUrlFromFiles, resolveLocalServerUrl, loadProjectConfig, loadUserConfig, resolveUserConfigWritePath, resolveProjectConfigWritePath, saveUserConfig, saveProjectConfig, isValidServerUrl, resolveServerUrlFromConfig, applyConfigSource, applyEnvOverrides, createDefaultMergedConfig, loadMergedConfig, loadConfig, saveConfig, getApiKey, setApiKey, getServerUrl, clearApiKey, getDemoContext, setDemoContext, clearDemoContext, loadConfigAsync, loadProjectConfigAsync, loadUserConfigAsync, loadMergedConfigAsync, findProjectConfigFileAsync, findUserConfigFileAsync, saveConfigAsync, saveUserConfigAsync, saveProjectConfigAsync, getApiKeyAsync, setApiKeyAsync, persistApiKeyAsync, getServerUrlAsync, clearApiKeyAsync, getDemoContextAsync, setDemoContextAsync, clearDemoContextAsync;
|
|
@@ -256,7 +256,7 @@ var init_config = __esm({
|
|
|
256
256
|
return pipe3(
|
|
257
257
|
Effect3.tryPromise({
|
|
258
258
|
try: async () => {
|
|
259
|
-
await mkdir2(
|
|
259
|
+
await mkdir2(dirname4(targetPath), { recursive: true, mode: 448 });
|
|
260
260
|
await writeFile2(targetPath, JSON.stringify(config, null, 2), {
|
|
261
261
|
encoding: "utf-8",
|
|
262
262
|
mode: 384
|
|
@@ -272,7 +272,7 @@ var init_config = __esm({
|
|
|
272
272
|
return pipe3(
|
|
273
273
|
Effect3.tryPromise({
|
|
274
274
|
try: async () => {
|
|
275
|
-
await mkdir2(
|
|
275
|
+
await mkdir2(dirname4(targetPath), { recursive: true, mode: 448 });
|
|
276
276
|
await writeFile2(targetPath, JSON.stringify(config, null, 2), {
|
|
277
277
|
encoding: "utf-8",
|
|
278
278
|
mode: 384
|
|
@@ -392,7 +392,7 @@ var init_config = __esm({
|
|
|
392
392
|
saveConfig = (config) => pipe3(
|
|
393
393
|
Effect3.tryPromise({
|
|
394
394
|
try: async () => {
|
|
395
|
-
await mkdir2(
|
|
395
|
+
await mkdir2(dirname4(CONFIG_FILE), { recursive: true, mode: 448 });
|
|
396
396
|
await writeFile2(CONFIG_FILE, JSON.stringify(config, null, 2), {
|
|
397
397
|
encoding: "utf-8",
|
|
398
398
|
mode: 384
|
|
@@ -478,8 +478,13 @@ var init_config = __esm({
|
|
|
478
478
|
saveProjectConfigAsync = (config, startDir) => Effect3.runPromise(saveProjectConfig(config, startDir));
|
|
479
479
|
getApiKeyAsync = () => Effect3.runPromise(getApiKey());
|
|
480
480
|
setApiKeyAsync = (apiKey) => Effect3.runPromise(setApiKey(apiKey));
|
|
481
|
-
persistApiKeyAsync = async (apiKey) => {
|
|
482
|
-
await
|
|
481
|
+
persistApiKeyAsync = async (apiKey, serverUrl) => {
|
|
482
|
+
const config = await loadConfigAsync();
|
|
483
|
+
await saveConfigAsync({
|
|
484
|
+
...config,
|
|
485
|
+
apiKey,
|
|
486
|
+
...serverUrl ? { serverUrl } : {}
|
|
487
|
+
});
|
|
483
488
|
const existingUserConfig = await loadUserConfigAsync();
|
|
484
489
|
if (existingUserConfig?.token) {
|
|
485
490
|
await saveUserConfigAsync({ ...existingUserConfig, token: apiKey });
|
|
@@ -510,7 +515,8 @@ var init_api = __esm({
|
|
|
510
515
|
const parsed = new URL(serverUrl);
|
|
511
516
|
const hostname2 = parsed.hostname;
|
|
512
517
|
const isBraidHost = hostname2 === "braid.cloud" || hostname2.endsWith(".braid.cloud");
|
|
513
|
-
|
|
518
|
+
const isConvexSite = hostname2.endsWith(".convex.site");
|
|
519
|
+
if (parsed.protocol === "https:" && (isBraidHost || isConvexSite)) {
|
|
514
520
|
return true;
|
|
515
521
|
}
|
|
516
522
|
if (parsed.protocol === "http:" && isLocalHost(hostname2)) {
|
|
@@ -1941,7 +1947,7 @@ var writeAgentsForPlatformAsync = (platform2, specs, installPath) => Effect.runP
|
|
|
1941
1947
|
init_esm_shims();
|
|
1942
1948
|
import { access, constants } from "fs/promises";
|
|
1943
1949
|
import { homedir } from "os";
|
|
1944
|
-
import { join } from "path";
|
|
1950
|
+
import { dirname as dirname2, join } from "path";
|
|
1945
1951
|
import process2 from "process";
|
|
1946
1952
|
import { Effect as Effect2, pipe as pipe2 } from "effect";
|
|
1947
1953
|
var home = homedir();
|
|
@@ -2585,7 +2591,7 @@ var DeviceAuthExpiredError = class extends Error {
|
|
|
2585
2591
|
this.name = "DeviceAuthExpiredError";
|
|
2586
2592
|
}
|
|
2587
2593
|
};
|
|
2588
|
-
var sleep = (ms) => new Promise((
|
|
2594
|
+
var sleep = (ms) => new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
2589
2595
|
var normalizeBaseUrl2 = (rawUrl) => {
|
|
2590
2596
|
const trimmed = rawUrl.replace(TRAILING_SLASHES2, "");
|
|
2591
2597
|
try {
|
|
@@ -2989,7 +2995,7 @@ async function deviceFlow(serverUrl, timeoutSeconds, options) {
|
|
|
2989
2995
|
pollSpinner.stop("Authentication failed");
|
|
2990
2996
|
handlePollingError(error);
|
|
2991
2997
|
}
|
|
2992
|
-
await persistApiKeyAsync(session.sessionToken);
|
|
2998
|
+
await persistApiKeyAsync(session.sessionToken, authConfig.convexSiteUrl);
|
|
2993
2999
|
if (options.scope !== false) {
|
|
2994
3000
|
await configureDefaultScopeAsync(authConfig.convexSiteUrl);
|
|
2995
3001
|
}
|
|
@@ -3288,7 +3294,7 @@ import {
|
|
|
3288
3294
|
writeFile as writeFile3
|
|
3289
3295
|
} from "fs/promises";
|
|
3290
3296
|
import { homedir as homedir3 } from "os";
|
|
3291
|
-
import { basename, dirname as
|
|
3297
|
+
import { basename, dirname as dirname5, join as join5, resolve as resolve2 } from "path";
|
|
3292
3298
|
var BRAID_CONFIG_DIR = join5(homedir3(), ".config", "braid");
|
|
3293
3299
|
var DEFAULT_STORE_ROOT = join5(BRAID_CONFIG_DIR, "store", "skills");
|
|
3294
3300
|
var DEFAULT_DISABLED_ROOT = join5(BRAID_CONFIG_DIR, ".disabled");
|
|
@@ -3397,7 +3403,7 @@ var enableBundleAsync = async (originalPath, options = {}) => {
|
|
|
3397
3403
|
if (!record) {
|
|
3398
3404
|
throw new Error(`No disabled bundle found for ${originalPath}`);
|
|
3399
3405
|
}
|
|
3400
|
-
await mkdir3(
|
|
3406
|
+
await mkdir3(dirname5(record.originalPath), { recursive: true });
|
|
3401
3407
|
await rm(record.originalPath, { recursive: true, force: true });
|
|
3402
3408
|
await rename(record.payloadPath, record.originalPath);
|
|
3403
3409
|
await rm(record.disabledPath, { recursive: true, force: true });
|
|
@@ -3414,9 +3420,9 @@ init_lockfile();
|
|
|
3414
3420
|
// src/lib/metadata.ts
|
|
3415
3421
|
init_esm_shims();
|
|
3416
3422
|
import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
3417
|
-
import { join as join7 } from "path";
|
|
3423
|
+
import { dirname as dirname6, join as join7 } from "path";
|
|
3418
3424
|
import { Data as Data5, Effect as Effect6, pipe as pipe6 } from "effect";
|
|
3419
|
-
var METADATA_FILENAME2 = ".
|
|
3425
|
+
var METADATA_FILENAME2 = ".braid-metadata.json";
|
|
3420
3426
|
var MetadataReadError = class extends Data5.TaggedError("MetadataReadError") {
|
|
3421
3427
|
};
|
|
3422
3428
|
var MetadataWriteError = class extends Data5.TaggedError("MetadataWriteError") {
|
|
@@ -3432,7 +3438,7 @@ var normalizeInstalledSkill = (skill) => ({
|
|
|
3432
3438
|
var normalizeMetadata = (metadata) => ({
|
|
3433
3439
|
skills: Array.isArray(metadata?.skills) ? metadata.skills.map(normalizeInstalledSkill) : []
|
|
3434
3440
|
});
|
|
3435
|
-
var getMetadataPath = (skillsDir) => join7(skillsDir, METADATA_FILENAME2);
|
|
3441
|
+
var getMetadataPath = (skillsDir) => join7(dirname6(skillsDir), METADATA_FILENAME2);
|
|
3436
3442
|
var readMetadata = (skillsDir) => {
|
|
3437
3443
|
const metadataPath = getMetadataPath(skillsDir);
|
|
3438
3444
|
return pipe6(
|
|
@@ -3449,10 +3455,26 @@ var readMetadata = (skillsDir) => {
|
|
|
3449
3455
|
Effect6.orElseSucceed(() => normalizeMetadata(void 0))
|
|
3450
3456
|
);
|
|
3451
3457
|
};
|
|
3458
|
+
var readRawJson = async (path2) => {
|
|
3459
|
+
try {
|
|
3460
|
+
const content = await readFile4(path2, "utf-8");
|
|
3461
|
+
const parsed = JSON.parse(content);
|
|
3462
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
3463
|
+
return parsed;
|
|
3464
|
+
}
|
|
3465
|
+
} catch (_) {
|
|
3466
|
+
return {};
|
|
3467
|
+
}
|
|
3468
|
+
return {};
|
|
3469
|
+
};
|
|
3452
3470
|
var writeMetadata = (skillsDir, metadata) => {
|
|
3453
3471
|
const metadataPath = getMetadataPath(skillsDir);
|
|
3454
3472
|
return Effect6.tryPromise({
|
|
3455
|
-
try: () =>
|
|
3473
|
+
try: async () => {
|
|
3474
|
+
const existing = await readRawJson(metadataPath);
|
|
3475
|
+
const merged = { ...existing, skills: metadata.skills };
|
|
3476
|
+
await writeFile5(metadataPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
3477
|
+
},
|
|
3456
3478
|
catch: (e) => new MetadataWriteError({ path: metadataPath, cause: e })
|
|
3457
3479
|
});
|
|
3458
3480
|
};
|
|
@@ -3497,7 +3519,7 @@ var removeFromMetadataAsync = (skillsDir, skillName) => Effect6.runPromise(remov
|
|
|
3497
3519
|
// src/lib/rule-writer.ts
|
|
3498
3520
|
init_esm_shims();
|
|
3499
3521
|
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile6 } from "fs/promises";
|
|
3500
|
-
import { dirname as
|
|
3522
|
+
import { dirname as dirname7, resolve as resolve3, sep as sep2 } from "path";
|
|
3501
3523
|
import { Data as Data6, Effect as Effect7, pipe as pipe7 } from "effect";
|
|
3502
3524
|
var RuleWriteError = class extends Data6.TaggedError("RuleWriteError") {
|
|
3503
3525
|
};
|
|
@@ -3595,7 +3617,7 @@ ${rule.content}`)
|
|
|
3595
3617
|
Effect7.asVoid
|
|
3596
3618
|
);
|
|
3597
3619
|
var writeAppendSingleRules = (filePath, rules2) => pipe7(
|
|
3598
|
-
createDirectory(
|
|
3620
|
+
createDirectory(dirname7(filePath)),
|
|
3599
3621
|
Effect7.flatMap(
|
|
3600
3622
|
() => pipe7(
|
|
3601
3623
|
readTextFile(filePath),
|
|
@@ -3658,7 +3680,7 @@ var writeRulesForAgentAsync = (agent, rules2, rulesPath) => Effect7.runPromise(w
|
|
|
3658
3680
|
init_esm_shims();
|
|
3659
3681
|
import { createHash as createHash2 } from "crypto";
|
|
3660
3682
|
import { chmod, mkdir as mkdir5, rm as rm2, symlink, writeFile as writeFile7 } from "fs/promises";
|
|
3661
|
-
import { dirname as
|
|
3683
|
+
import { dirname as dirname8, join as join8, resolve as resolve4, sep as sep3 } from "path";
|
|
3662
3684
|
import { Data as Data7, Effect as Effect8, pipe as pipe8 } from "effect";
|
|
3663
3685
|
var WriteError = class extends Data7.TaggedError("WriteError") {
|
|
3664
3686
|
};
|
|
@@ -3739,7 +3761,7 @@ var setExecutableIfScript = (fullPath, file, agentId) => isScriptFile(file.path)
|
|
|
3739
3761
|
var writeSkillFile = (basePath, file, agentId) => pipe8(
|
|
3740
3762
|
assertWithinBase2(basePath, file.path),
|
|
3741
3763
|
Effect8.flatMap((fullPath) => {
|
|
3742
|
-
const dir =
|
|
3764
|
+
const dir = dirname8(fullPath);
|
|
3743
3765
|
return pipe8(
|
|
3744
3766
|
createDirectory2(dir, fullPath),
|
|
3745
3767
|
Effect8.flatMap(() => writeFileContent(fullPath, file, agentId)),
|
|
@@ -3786,7 +3808,7 @@ var writeSkillSymlink = (basePath, skill, agentId, options) => pipe8(
|
|
|
3786
3808
|
disabledRoot: options.disabledRoot
|
|
3787
3809
|
}
|
|
3788
3810
|
);
|
|
3789
|
-
await mkdir5(
|
|
3811
|
+
await mkdir5(dirname8(destinationPath), { recursive: true });
|
|
3790
3812
|
await rm2(destinationPath, { recursive: true, force: true });
|
|
3791
3813
|
await symlink(
|
|
3792
3814
|
storedBundlePath,
|
|
@@ -4531,17 +4553,17 @@ init_config();
|
|
|
4531
4553
|
|
|
4532
4554
|
// src/lib/manage-actions.ts
|
|
4533
4555
|
init_esm_shims();
|
|
4534
|
-
import { rm as
|
|
4535
|
-
import { basename as basename2, dirname as
|
|
4556
|
+
import { rm as rm5 } from "fs/promises";
|
|
4557
|
+
import { basename as basename2, dirname as dirname10, join as join11, relative } from "path";
|
|
4536
4558
|
|
|
4537
4559
|
// src/lib/hook-writer.ts
|
|
4538
4560
|
init_esm_shims();
|
|
4539
4561
|
import { mkdir as mkdir6, readFile as readFile6, rm as rm3, writeFile as writeFile8 } from "fs/promises";
|
|
4540
|
-
import { dirname as
|
|
4562
|
+
import { dirname as dirname9, join as join9 } from "path";
|
|
4541
4563
|
import { Data as Data8, Effect as Effect9 } from "effect";
|
|
4542
4564
|
var HookConfigWriteError = class extends Data8.TaggedError("HookConfigWriteError") {
|
|
4543
4565
|
};
|
|
4544
|
-
var HOOK_METADATA_FILENAME = ".braid-
|
|
4566
|
+
var HOOK_METADATA_FILENAME = ".braid-metadata.json";
|
|
4545
4567
|
function stableStringify(value) {
|
|
4546
4568
|
return JSON.stringify(value, (_key, currentValue) => {
|
|
4547
4569
|
if (currentValue && typeof currentValue === "object" && !Array.isArray(currentValue)) {
|
|
@@ -4582,7 +4604,7 @@ async function readJsonFile(path2) {
|
|
|
4582
4604
|
}
|
|
4583
4605
|
}
|
|
4584
4606
|
async function writeJsonFile(path2, value) {
|
|
4585
|
-
await mkdir6(
|
|
4607
|
+
await mkdir6(dirname9(path2), { recursive: true, mode: 448 });
|
|
4586
4608
|
await writeFile8(path2, `${JSON.stringify(value, null, 2)}
|
|
4587
4609
|
`, {
|
|
4588
4610
|
encoding: "utf-8",
|
|
@@ -4681,7 +4703,7 @@ function addHookHandlers(config, hook) {
|
|
|
4681
4703
|
return writeMatcherGroups(config, hook.event, groups);
|
|
4682
4704
|
}
|
|
4683
4705
|
function getHookMetadataPath(settingsPath) {
|
|
4684
|
-
return join9(
|
|
4706
|
+
return join9(dirname9(settingsPath), HOOK_METADATA_FILENAME);
|
|
4685
4707
|
}
|
|
4686
4708
|
async function readHookMetadata(settingsPath) {
|
|
4687
4709
|
const metadataPath = getHookMetadataPath(settingsPath);
|
|
@@ -4690,9 +4712,9 @@ async function readHookMetadata(settingsPath) {
|
|
|
4690
4712
|
return { hooks };
|
|
4691
4713
|
}
|
|
4692
4714
|
async function writeHookMetadata(settingsPath, metadata) {
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
});
|
|
4715
|
+
const metadataPath = getHookMetadataPath(settingsPath);
|
|
4716
|
+
const existing = await readJsonFile(metadataPath);
|
|
4717
|
+
await writeJsonFile(metadataPath, { ...existing, hooks: metadata.hooks });
|
|
4696
4718
|
}
|
|
4697
4719
|
function buildMarketplaceHookSource(sourceSlug) {
|
|
4698
4720
|
return {
|
|
@@ -4790,7 +4812,7 @@ async function listInstalledMarketplaceHookSources(settingsPath) {
|
|
|
4790
4812
|
);
|
|
4791
4813
|
}
|
|
4792
4814
|
function buildMarketplaceHookBundlePath(settingsPath, sourceSlug) {
|
|
4793
|
-
return join9(
|
|
4815
|
+
return join9(dirname9(settingsPath), ".braid-hooks", `${sourceSlug}.json`);
|
|
4794
4816
|
}
|
|
4795
4817
|
function buildMarketplaceHookBundle(hooks, options) {
|
|
4796
4818
|
return {
|
|
@@ -4987,7 +5009,7 @@ var requestJson = (url, options) => pipe9(
|
|
|
4987
5009
|
const payload = await response.json().catch(() => null);
|
|
4988
5010
|
if (!response.ok) {
|
|
4989
5011
|
throw new MarketplaceApiError({
|
|
4990
|
-
message: payload?.error ?? payload?.message ??
|
|
5012
|
+
message: payload?.error ?? payload?.message ?? `Request failed (HTTP ${response.status} from ${new URL(url).origin})`,
|
|
4991
5013
|
status: response.status,
|
|
4992
5014
|
code: payload?.code ?? "REQUEST_ERROR"
|
|
4993
5015
|
});
|
|
@@ -5042,6 +5064,8 @@ var fetchMarketplaceInstallManifestAsync = (slug, options) => Effect10.runPromis
|
|
|
5042
5064
|
|
|
5043
5065
|
// src/lib/marketplace-installer.ts
|
|
5044
5066
|
init_esm_shims();
|
|
5067
|
+
import { rm as rm4 } from "fs/promises";
|
|
5068
|
+
import { join as join10 } from "path";
|
|
5045
5069
|
function parseAgentIds(value) {
|
|
5046
5070
|
if (!value) {
|
|
5047
5071
|
return [];
|
|
@@ -5184,6 +5208,58 @@ async function installHooksForAgent(args) {
|
|
|
5184
5208
|
args.targets.push(`${args.agent.name} hooks -> ${hookConfigPath}`);
|
|
5185
5209
|
return true;
|
|
5186
5210
|
}
|
|
5211
|
+
async function pruneStaleMarketplaceSkills(installPath, slug, currentSkillNames) {
|
|
5212
|
+
const metadata = await readMetadataAsync(installPath);
|
|
5213
|
+
const stale = metadata.skills.filter(
|
|
5214
|
+
(skill) => skill.source.type === "marketplace" && skill.source.slug === slug && !currentSkillNames.has(skill.name)
|
|
5215
|
+
);
|
|
5216
|
+
for (const skill of stale) {
|
|
5217
|
+
const skillPath = join10(installPath, skill.name);
|
|
5218
|
+
await rm4(skillPath, { recursive: true, force: true });
|
|
5219
|
+
await removeFromMetadataAsync(installPath, skill.name);
|
|
5220
|
+
}
|
|
5221
|
+
}
|
|
5222
|
+
async function installAllForAgent(args) {
|
|
5223
|
+
await installSkillsForAgent({
|
|
5224
|
+
agent: args.agent,
|
|
5225
|
+
manifest: args.manifest,
|
|
5226
|
+
slug: args.slug,
|
|
5227
|
+
skills: args.skills,
|
|
5228
|
+
global: args.global,
|
|
5229
|
+
installedSkills: args.installedSkills,
|
|
5230
|
+
targets: args.targets
|
|
5231
|
+
});
|
|
5232
|
+
await installRulesForAgent({
|
|
5233
|
+
agent: args.agent,
|
|
5234
|
+
rules: args.rules,
|
|
5235
|
+
global: args.global,
|
|
5236
|
+
targets: args.targets
|
|
5237
|
+
});
|
|
5238
|
+
await installAgentsForAgent({
|
|
5239
|
+
agent: args.agent,
|
|
5240
|
+
agents: args.agents,
|
|
5241
|
+
global: args.global,
|
|
5242
|
+
targets: args.targets
|
|
5243
|
+
});
|
|
5244
|
+
if (args.installHooks) {
|
|
5245
|
+
await installHooksForAgent({
|
|
5246
|
+
agent: args.agent,
|
|
5247
|
+
hooks: args.hooks,
|
|
5248
|
+
slug: args.slug,
|
|
5249
|
+
manifest: args.manifest,
|
|
5250
|
+
global: args.global,
|
|
5251
|
+
targets: args.targets
|
|
5252
|
+
});
|
|
5253
|
+
}
|
|
5254
|
+
const installPath = resolveInstallPath(args.agent, { global: args.global });
|
|
5255
|
+
if (installPath) {
|
|
5256
|
+
await pruneStaleMarketplaceSkills(
|
|
5257
|
+
installPath,
|
|
5258
|
+
args.slug,
|
|
5259
|
+
args.installedSkills
|
|
5260
|
+
);
|
|
5261
|
+
}
|
|
5262
|
+
}
|
|
5187
5263
|
async function installMarketplaceSkillSet(options) {
|
|
5188
5264
|
if (options.manifest.blocked) {
|
|
5189
5265
|
throw new Error(
|
|
@@ -5195,12 +5271,8 @@ async function installMarketplaceSkillSet(options) {
|
|
|
5195
5271
|
const hooks = options.manifest.manifest?.hooks ?? [];
|
|
5196
5272
|
const agents2 = options.manifest.manifest?.agents ?? [];
|
|
5197
5273
|
const workflows = options.manifest.manifest?.workflows ?? [];
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
"Marketplace packs with hooks require explicit opt-in. Re-run with --allow-hooks after reviewing the hook commands."
|
|
5201
|
-
);
|
|
5202
|
-
}
|
|
5203
|
-
if (resolvedSkills.length === 0 && rules2.length === 0 && hooks.length === 0 && agents2.length === 0 && workflows.length === 0) {
|
|
5274
|
+
const installHooks = hooks.length > 0 && options.allowHooks === true;
|
|
5275
|
+
if (resolvedSkills.length === 0 && rules2.length === 0 && (!installHooks || hooks.length === 0) && agents2.length === 0 && workflows.length === 0) {
|
|
5204
5276
|
throw new Error("No installable content found in manifest");
|
|
5205
5277
|
}
|
|
5206
5278
|
const targetAgents = await resolveTargetAgents(options.agents);
|
|
@@ -5212,33 +5284,17 @@ async function installMarketplaceSkillSet(options) {
|
|
|
5212
5284
|
const targets = [];
|
|
5213
5285
|
const installedSkills = /* @__PURE__ */ new Set();
|
|
5214
5286
|
for (const agent of targetAgents) {
|
|
5215
|
-
await
|
|
5287
|
+
await installAllForAgent({
|
|
5216
5288
|
agent,
|
|
5217
5289
|
manifest: options.manifest,
|
|
5218
5290
|
slug: options.slug,
|
|
5219
5291
|
skills: resolvedSkills,
|
|
5220
|
-
global: options.global,
|
|
5221
|
-
installedSkills,
|
|
5222
|
-
targets
|
|
5223
|
-
});
|
|
5224
|
-
await installRulesForAgent({
|
|
5225
|
-
agent,
|
|
5226
5292
|
rules: rules2,
|
|
5227
|
-
global: options.global,
|
|
5228
|
-
targets
|
|
5229
|
-
});
|
|
5230
|
-
await installAgentsForAgent({
|
|
5231
|
-
agent,
|
|
5232
5293
|
agents: agents2,
|
|
5233
|
-
global: options.global,
|
|
5234
|
-
targets
|
|
5235
|
-
});
|
|
5236
|
-
await installHooksForAgent({
|
|
5237
|
-
agent,
|
|
5238
5294
|
hooks,
|
|
5239
|
-
|
|
5240
|
-
manifest: options.manifest,
|
|
5295
|
+
installHooks,
|
|
5241
5296
|
global: options.global,
|
|
5297
|
+
installedSkills,
|
|
5242
5298
|
targets
|
|
5243
5299
|
});
|
|
5244
5300
|
}
|
|
@@ -5257,12 +5313,12 @@ function isMarketplaceHookBundlePath(originalPath) {
|
|
|
5257
5313
|
return getHookBundleRoot(originalPath) !== null;
|
|
5258
5314
|
}
|
|
5259
5315
|
function getHookBundleRoot(originalPath) {
|
|
5260
|
-
let currentPath =
|
|
5316
|
+
let currentPath = dirname10(originalPath);
|
|
5261
5317
|
while (true) {
|
|
5262
5318
|
if (basename2(currentPath) === ".braid-hooks") {
|
|
5263
|
-
return
|
|
5319
|
+
return dirname10(currentPath);
|
|
5264
5320
|
}
|
|
5265
|
-
const parentPath =
|
|
5321
|
+
const parentPath = dirname10(currentPath);
|
|
5266
5322
|
if (parentPath === currentPath) {
|
|
5267
5323
|
return null;
|
|
5268
5324
|
}
|
|
@@ -5274,7 +5330,7 @@ function getHookBundleRelativePath(originalPath) {
|
|
|
5274
5330
|
if (!bundleRoot) {
|
|
5275
5331
|
throw new Error(`Invalid marketplace hook bundle path: ${originalPath}`);
|
|
5276
5332
|
}
|
|
5277
|
-
return relative(
|
|
5333
|
+
return relative(join11(bundleRoot, ".braid-hooks"), originalPath);
|
|
5278
5334
|
}
|
|
5279
5335
|
function getHookSourceSlug(originalPath) {
|
|
5280
5336
|
const relativePath = getHookBundleRelativePath(originalPath);
|
|
@@ -5293,7 +5349,7 @@ function getHookSettingsPath(originalPath) {
|
|
|
5293
5349
|
if (!bundleRoot) {
|
|
5294
5350
|
throw new Error(`Invalid marketplace hook bundle path: ${originalPath}`);
|
|
5295
5351
|
}
|
|
5296
|
-
return
|
|
5352
|
+
return join11(bundleRoot, "settings.json");
|
|
5297
5353
|
}
|
|
5298
5354
|
async function disableManagedBundleAsync(options) {
|
|
5299
5355
|
if (options.surface === "hooks") {
|
|
@@ -5350,7 +5406,7 @@ async function removeManagedBundleAsync(options) {
|
|
|
5350
5406
|
}
|
|
5351
5407
|
);
|
|
5352
5408
|
await removeMarketplaceHooksBySourceAsync(
|
|
5353
|
-
|
|
5409
|
+
join11(options.installRoot, "settings.json"),
|
|
5354
5410
|
options.bundleName
|
|
5355
5411
|
);
|
|
5356
5412
|
if (disabledRecord2) {
|
|
@@ -5364,7 +5420,7 @@ async function removeManagedBundleAsync(options) {
|
|
|
5364
5420
|
disabledRoot: options.disabledRoot
|
|
5365
5421
|
}
|
|
5366
5422
|
);
|
|
5367
|
-
await
|
|
5423
|
+
await rm5(options.originalPath, { recursive: true, force: true });
|
|
5368
5424
|
if (disabledRecord) {
|
|
5369
5425
|
await removePathAsync(disabledRecord.disabledPath);
|
|
5370
5426
|
}
|
|
@@ -5388,7 +5444,7 @@ async function installLibraryPackAsync(options) {
|
|
|
5388
5444
|
// src/lib/manage-inventory.ts
|
|
5389
5445
|
init_esm_shims();
|
|
5390
5446
|
import { access as access2, constants as constants2, lstat, readdir as readdir2 } from "fs/promises";
|
|
5391
|
-
import { basename as basename3, delimiter, dirname as
|
|
5447
|
+
import { basename as basename3, delimiter, dirname as dirname11, join as join12, resolve as resolve5 } from "path";
|
|
5392
5448
|
var MANAGE_PROVIDER_COMMANDS = {
|
|
5393
5449
|
amp: ["amp"],
|
|
5394
5450
|
"claude-code": ["claude"],
|
|
@@ -5436,7 +5492,7 @@ function getCommandExtensions() {
|
|
|
5436
5492
|
function getCommandCandidates(command, pathValue) {
|
|
5437
5493
|
return pathValue.split(delimiter).flatMap(
|
|
5438
5494
|
(segment) => segment ? getCommandExtensions().map(
|
|
5439
|
-
(extension) =>
|
|
5495
|
+
(extension) => join12(segment, `${command}${extension}`)
|
|
5440
5496
|
) : []
|
|
5441
5497
|
);
|
|
5442
5498
|
}
|
|
@@ -5552,9 +5608,9 @@ async function listSurfaceEntries(rootPath, surface) {
|
|
|
5552
5608
|
}
|
|
5553
5609
|
return entry.isDirectory() || entry.isFile() || entry.isSymbolicLink();
|
|
5554
5610
|
}).map((entry) => ({
|
|
5555
|
-
currentPath:
|
|
5611
|
+
currentPath: join12(rootPath, entry.name),
|
|
5556
5612
|
name: entry.name,
|
|
5557
|
-
originalPath:
|
|
5613
|
+
originalPath: join12(rootPath, entry.name)
|
|
5558
5614
|
}));
|
|
5559
5615
|
}
|
|
5560
5616
|
function toBundleKey(path2) {
|
|
@@ -5603,7 +5659,7 @@ async function collectSkillBundles(args) {
|
|
|
5603
5659
|
});
|
|
5604
5660
|
}
|
|
5605
5661
|
for (const metadataEntry of metadata.skills) {
|
|
5606
|
-
const originalPath =
|
|
5662
|
+
const originalPath = join12(args.rootPath, metadataEntry.name);
|
|
5607
5663
|
const bundleKey = toBundleKey(originalPath);
|
|
5608
5664
|
if (bundles.has(bundleKey)) {
|
|
5609
5665
|
continue;
|
|
@@ -5684,7 +5740,7 @@ async function collectHookBundles(args) {
|
|
|
5684
5740
|
return [];
|
|
5685
5741
|
}
|
|
5686
5742
|
const settingsPath = args.settingsPath;
|
|
5687
|
-
const installRoot =
|
|
5743
|
+
const installRoot = dirname11(settingsPath);
|
|
5688
5744
|
const sources = await listInstalledMarketplaceHookSourcesAsync(settingsPath);
|
|
5689
5745
|
const disabledRecords = getDisabledRecordsForSurface({
|
|
5690
5746
|
agent: args.agent,
|
|
@@ -5788,7 +5844,7 @@ async function collectScopeInventory(args) {
|
|
|
5788
5844
|
},
|
|
5789
5845
|
hooks: {
|
|
5790
5846
|
bundles: hooks,
|
|
5791
|
-
rootPath: hookSettingsPath ?
|
|
5847
|
+
rootPath: hookSettingsPath ? dirname11(hookSettingsPath) : null,
|
|
5792
5848
|
surface: "hooks"
|
|
5793
5849
|
},
|
|
5794
5850
|
rules: {
|
|
@@ -6246,7 +6302,10 @@ async function startManageServer(options = {}) {
|
|
|
6246
6302
|
pendingRequest.expiresIn,
|
|
6247
6303
|
MANAGE_AUTH_TIMEOUT_SECONDS
|
|
6248
6304
|
);
|
|
6249
|
-
await persistApiKeyAsync(
|
|
6305
|
+
await persistApiKeyAsync(
|
|
6306
|
+
session.sessionToken,
|
|
6307
|
+
pendingRequest.convexSiteUrl
|
|
6308
|
+
);
|
|
6250
6309
|
return {
|
|
6251
6310
|
authenticated: true,
|
|
6252
6311
|
expiresAt: session.expiresAt,
|
|
@@ -6389,39 +6448,288 @@ async function manageCommand(options) {
|
|
|
6389
6448
|
|
|
6390
6449
|
// src/commands/marketplace.ts
|
|
6391
6450
|
init_esm_shims();
|
|
6451
|
+
import { rm as rm6 } from "fs/promises";
|
|
6452
|
+
import { join as join13, resolve as resolve7 } from "path";
|
|
6453
|
+
import process11 from "process";
|
|
6392
6454
|
init_tui();
|
|
6393
|
-
async function
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6455
|
+
async function selectInstallScope(options) {
|
|
6456
|
+
if (options.global != null) {
|
|
6457
|
+
return options.global;
|
|
6458
|
+
}
|
|
6459
|
+
if (options.yes) {
|
|
6460
|
+
return false;
|
|
6461
|
+
}
|
|
6462
|
+
const result = await select({
|
|
6463
|
+
message: "Install location:",
|
|
6464
|
+
options: [
|
|
6465
|
+
{ value: false, label: "Project", hint: "local to this directory" },
|
|
6466
|
+
{ value: true, label: "Global", hint: "available everywhere" }
|
|
6467
|
+
],
|
|
6468
|
+
initialValue: false
|
|
6397
6469
|
});
|
|
6398
|
-
if (
|
|
6399
|
-
|
|
6400
|
-
|
|
6470
|
+
if (isCancel(result)) {
|
|
6471
|
+
cancel("Install cancelled.");
|
|
6472
|
+
process11.exit(0);
|
|
6401
6473
|
}
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6474
|
+
return result;
|
|
6475
|
+
}
|
|
6476
|
+
async function selectInstallAgents(options, global) {
|
|
6477
|
+
const detected = await detectAgentsAsync();
|
|
6478
|
+
const available = detected.map((d) => getAgentById(d.id)).filter((a) => a != null);
|
|
6479
|
+
if (available.length === 0) {
|
|
6480
|
+
throw new Error(
|
|
6481
|
+
"No compatible agents found. Use --agents to specify targets."
|
|
6407
6482
|
);
|
|
6408
6483
|
}
|
|
6484
|
+
if (options.agents) {
|
|
6485
|
+
const ids = options.agents.split(",").map((s) => s.trim());
|
|
6486
|
+
const matched = ids.map((id) => getAgentById(id)).filter((a) => a != null);
|
|
6487
|
+
if (matched.length === 0) {
|
|
6488
|
+
throw new Error(`No agents matched: ${options.agents}`);
|
|
6489
|
+
}
|
|
6490
|
+
return matched;
|
|
6491
|
+
}
|
|
6492
|
+
if (options.yes || available.length === 1) {
|
|
6493
|
+
return available.length === 1 ? available : available;
|
|
6494
|
+
}
|
|
6495
|
+
const selected = await multiselect({
|
|
6496
|
+
message: "Select agents to install to:",
|
|
6497
|
+
options: available.map((agent) => ({
|
|
6498
|
+
value: agent,
|
|
6499
|
+
label: agent.name,
|
|
6500
|
+
hint: global ? agent.globalPath : agent.projectPath
|
|
6501
|
+
})),
|
|
6502
|
+
initialValues: [],
|
|
6503
|
+
required: true
|
|
6504
|
+
});
|
|
6505
|
+
if (isCancel(selected)) {
|
|
6506
|
+
cancel("Install cancelled.");
|
|
6507
|
+
process11.exit(0);
|
|
6508
|
+
}
|
|
6509
|
+
return selected;
|
|
6409
6510
|
}
|
|
6410
|
-
async function
|
|
6511
|
+
async function confirmHooksOptIn(hookCount, options) {
|
|
6512
|
+
if (options.allowHooks) {
|
|
6513
|
+
return true;
|
|
6514
|
+
}
|
|
6515
|
+
if (options.yes) {
|
|
6516
|
+
return false;
|
|
6517
|
+
}
|
|
6518
|
+
const result = await confirm({
|
|
6519
|
+
message: `This pack includes ${hookCount} hook${hookCount === 1 ? "" : "s"} that run shell commands. Allow hooks?`,
|
|
6520
|
+
initialValue: false
|
|
6521
|
+
});
|
|
6522
|
+
if (isCancel(result)) {
|
|
6523
|
+
cancel("Install cancelled.");
|
|
6524
|
+
process11.exit(0);
|
|
6525
|
+
}
|
|
6526
|
+
return result;
|
|
6527
|
+
}
|
|
6528
|
+
async function marketplaceLibraryCommand(options) {
|
|
6529
|
+
try {
|
|
6530
|
+
const items = await fetchMarketplaceLibraryAsync({
|
|
6531
|
+
server: options.server,
|
|
6532
|
+
apiKey: options.apiKey
|
|
6533
|
+
});
|
|
6534
|
+
if (items.length === 0) {
|
|
6535
|
+
log.info("No marketplace packs in your library yet.");
|
|
6536
|
+
return;
|
|
6537
|
+
}
|
|
6538
|
+
for (const item of items) {
|
|
6539
|
+
const scan = item.scanVerdict ?? "clean";
|
|
6540
|
+
const commit = item.commitSha ?? "unknown";
|
|
6541
|
+
log.info(
|
|
6542
|
+
`${item.slug} | ${item.title} | scan=${scan} | commit=${commit} | install=braid marketplace install ${item.slug}`
|
|
6543
|
+
);
|
|
6544
|
+
}
|
|
6545
|
+
} catch (error) {
|
|
6546
|
+
log.error(
|
|
6547
|
+
error instanceof Error ? error.message : "Failed to fetch library"
|
|
6548
|
+
);
|
|
6549
|
+
process11.exit(1);
|
|
6550
|
+
}
|
|
6551
|
+
}
|
|
6552
|
+
async function resolveAndInstallPack(slug, options, overrides) {
|
|
6411
6553
|
const manifest = await fetchMarketplaceInstallManifestAsync(slug, {
|
|
6412
6554
|
server: options.server,
|
|
6413
6555
|
apiKey: options.apiKey
|
|
6414
6556
|
});
|
|
6415
|
-
const
|
|
6557
|
+
const global = overrides?.global ?? await selectInstallScope(options);
|
|
6558
|
+
const hooks = manifest.manifest?.hooks ?? [];
|
|
6559
|
+
if (hooks.length > 0) {
|
|
6560
|
+
const allowed = await confirmHooksOptIn(hooks.length, options);
|
|
6561
|
+
if (!allowed) {
|
|
6562
|
+
log.warn("Hooks skipped. Re-run with --allow-hooks to include them.");
|
|
6563
|
+
}
|
|
6564
|
+
options.allowHooks = allowed;
|
|
6565
|
+
}
|
|
6566
|
+
const agents2 = overrides?.agents ?? (await selectInstallAgents(options, global)).map((a) => a.id).join(",");
|
|
6567
|
+
await installMarketplaceSkillSet({
|
|
6416
6568
|
slug,
|
|
6417
6569
|
manifest,
|
|
6418
|
-
agents:
|
|
6419
|
-
global
|
|
6570
|
+
agents: agents2,
|
|
6571
|
+
global,
|
|
6420
6572
|
allowHooks: options.allowHooks
|
|
6421
6573
|
});
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6574
|
+
}
|
|
6575
|
+
async function marketplaceInstallCommand(slug, options) {
|
|
6576
|
+
try {
|
|
6577
|
+
await resolveAndInstallPack(slug, options);
|
|
6578
|
+
log.success(`Installed marketplace pack ${slug}`);
|
|
6579
|
+
} catch (error) {
|
|
6580
|
+
log.error(
|
|
6581
|
+
error instanceof Error ? error.message : "Failed to install pack"
|
|
6582
|
+
);
|
|
6583
|
+
process11.exit(1);
|
|
6584
|
+
}
|
|
6585
|
+
}
|
|
6586
|
+
function addSkillToPack(packMap, slug, versionId, skillName, agent, installPath) {
|
|
6587
|
+
let pack = packMap.get(slug);
|
|
6588
|
+
if (!pack) {
|
|
6589
|
+
pack = { slug, versionId, skills: [], agents: [] };
|
|
6590
|
+
packMap.set(slug, pack);
|
|
6591
|
+
}
|
|
6592
|
+
if (!pack.skills.includes(skillName)) {
|
|
6593
|
+
pack.skills.push(skillName);
|
|
6594
|
+
}
|
|
6595
|
+
if (!pack.agents.some((a) => a.agent.id === agent.id)) {
|
|
6596
|
+
pack.agents.push({ agent, installPath });
|
|
6597
|
+
}
|
|
6598
|
+
}
|
|
6599
|
+
async function findInstalledMarketplacePacks(options) {
|
|
6600
|
+
const detected = await detectAgentsAsync();
|
|
6601
|
+
const agents2 = detected.map((d) => getAgentById(d.id)).filter((a) => a != null);
|
|
6602
|
+
const packMap = /* @__PURE__ */ new Map();
|
|
6603
|
+
for (const agent of agents2) {
|
|
6604
|
+
const installPath = resolveInstallPath(agent, {
|
|
6605
|
+
global: options.global ?? false
|
|
6606
|
+
});
|
|
6607
|
+
if (!installPath) {
|
|
6608
|
+
continue;
|
|
6609
|
+
}
|
|
6610
|
+
const metadata = await readMetadataAsync(installPath);
|
|
6611
|
+
for (const skill of metadata.skills) {
|
|
6612
|
+
if (skill.source.type !== "marketplace") {
|
|
6613
|
+
continue;
|
|
6614
|
+
}
|
|
6615
|
+
addSkillToPack(
|
|
6616
|
+
packMap,
|
|
6617
|
+
skill.source.slug,
|
|
6618
|
+
skill.source.versionId ?? skill.version,
|
|
6619
|
+
skill.name,
|
|
6620
|
+
agent,
|
|
6621
|
+
installPath
|
|
6622
|
+
);
|
|
6623
|
+
}
|
|
6624
|
+
}
|
|
6625
|
+
return [...packMap.values()];
|
|
6626
|
+
}
|
|
6627
|
+
async function marketplaceUpdateCommand(slug, options) {
|
|
6628
|
+
try {
|
|
6629
|
+
const installed = await findInstalledMarketplacePacks(options);
|
|
6630
|
+
if (installed.length === 0) {
|
|
6631
|
+
log.info("No marketplace packs installed.");
|
|
6632
|
+
return;
|
|
6633
|
+
}
|
|
6634
|
+
const toUpdate = slug ? installed.filter((p) => p.slug === slug) : installed;
|
|
6635
|
+
if (toUpdate.length === 0) {
|
|
6636
|
+
log.error(`Pack "${slug}" is not installed.`);
|
|
6637
|
+
process11.exit(1);
|
|
6638
|
+
}
|
|
6639
|
+
let updated = 0;
|
|
6640
|
+
for (const pack of toUpdate) {
|
|
6641
|
+
const agentIds = pack.agents.map((a) => a.agent.id).join(",");
|
|
6642
|
+
const isGlobal = options.global ?? false;
|
|
6643
|
+
await resolveAndInstallPack(pack.slug, options, {
|
|
6644
|
+
agents: agentIds,
|
|
6645
|
+
global: isGlobal
|
|
6646
|
+
});
|
|
6647
|
+
log.success(`Updated ${pack.slug}`);
|
|
6648
|
+
updated++;
|
|
6649
|
+
}
|
|
6650
|
+
if (updated === 0) {
|
|
6651
|
+
log.info("All packs are up to date.");
|
|
6652
|
+
}
|
|
6653
|
+
} catch (error) {
|
|
6654
|
+
log.error(
|
|
6655
|
+
error instanceof Error ? error.message : "Failed to update packs"
|
|
6656
|
+
);
|
|
6657
|
+
process11.exit(1);
|
|
6658
|
+
}
|
|
6659
|
+
}
|
|
6660
|
+
async function selectPacksToRemove(installed, slug, options) {
|
|
6661
|
+
if (slug) {
|
|
6662
|
+
const matched = installed.filter((p) => p.slug === slug);
|
|
6663
|
+
if (matched.length === 0) {
|
|
6664
|
+
throw new Error(`Pack "${slug}" is not installed.`);
|
|
6665
|
+
}
|
|
6666
|
+
return matched;
|
|
6667
|
+
}
|
|
6668
|
+
if (options.yes) {
|
|
6669
|
+
return installed;
|
|
6670
|
+
}
|
|
6671
|
+
const selected = await multiselect({
|
|
6672
|
+
message: "Select packs to remove:",
|
|
6673
|
+
options: installed.map((p) => ({
|
|
6674
|
+
value: p,
|
|
6675
|
+
label: p.slug,
|
|
6676
|
+
hint: `${p.skills.length} skill${p.skills.length === 1 ? "" : "s"}`
|
|
6677
|
+
})),
|
|
6678
|
+
initialValues: [],
|
|
6679
|
+
required: true
|
|
6680
|
+
});
|
|
6681
|
+
if (isCancel(selected)) {
|
|
6682
|
+
cancel("Remove cancelled.");
|
|
6683
|
+
process11.exit(0);
|
|
6684
|
+
}
|
|
6685
|
+
return selected;
|
|
6686
|
+
}
|
|
6687
|
+
async function removePackFiles(pack, options) {
|
|
6688
|
+
for (const { agent, installPath } of pack.agents) {
|
|
6689
|
+
for (const skillName of pack.skills) {
|
|
6690
|
+
const skillPath = resolve7(join13(installPath, skillName));
|
|
6691
|
+
if (!skillPath.startsWith(`${resolve7(installPath)}/`)) {
|
|
6692
|
+
continue;
|
|
6693
|
+
}
|
|
6694
|
+
await rm6(skillPath, { recursive: true, force: true });
|
|
6695
|
+
await removeFromMetadataAsync(installPath, skillName);
|
|
6696
|
+
}
|
|
6697
|
+
const hookConfigPath = resolveHookConfigPath(agent, {
|
|
6698
|
+
global: options.global ?? false
|
|
6699
|
+
});
|
|
6700
|
+
if (hookConfigPath) {
|
|
6701
|
+
await removeMarketplaceHooksBySourceAsync(hookConfigPath, pack.slug);
|
|
6702
|
+
}
|
|
6703
|
+
}
|
|
6704
|
+
}
|
|
6705
|
+
async function marketplaceRemoveCommand(slug, options) {
|
|
6706
|
+
try {
|
|
6707
|
+
const installed = await findInstalledMarketplacePacks(options);
|
|
6708
|
+
if (installed.length === 0) {
|
|
6709
|
+
log.info("No marketplace packs installed.");
|
|
6710
|
+
return;
|
|
6711
|
+
}
|
|
6712
|
+
const toRemove = await selectPacksToRemove(installed, slug, options);
|
|
6713
|
+
if (!options.yes) {
|
|
6714
|
+
const slugList = toRemove.map((p) => p.slug).join(", ");
|
|
6715
|
+
const confirmed = await confirm({
|
|
6716
|
+
message: `Remove ${toRemove.length} pack${toRemove.length === 1 ? "" : "s"} (${slugList})?`,
|
|
6717
|
+
initialValue: false
|
|
6718
|
+
});
|
|
6719
|
+
if (isCancel(confirmed) || !confirmed) {
|
|
6720
|
+
cancel("Remove cancelled.");
|
|
6721
|
+
process11.exit(0);
|
|
6722
|
+
}
|
|
6723
|
+
}
|
|
6724
|
+
for (const pack of toRemove) {
|
|
6725
|
+
await removePackFiles(pack, options);
|
|
6726
|
+
log.success(`Removed ${pack.slug}`);
|
|
6727
|
+
}
|
|
6728
|
+
} catch (error) {
|
|
6729
|
+
log.error(
|
|
6730
|
+
error instanceof Error ? error.message : "Failed to remove packs"
|
|
6731
|
+
);
|
|
6732
|
+
process11.exit(1);
|
|
6425
6733
|
}
|
|
6426
6734
|
}
|
|
6427
6735
|
|
|
@@ -6429,15 +6737,15 @@ async function marketplaceInstallCommand(slug, options) {
|
|
|
6429
6737
|
init_esm_shims();
|
|
6430
6738
|
init_api();
|
|
6431
6739
|
init_tui();
|
|
6432
|
-
import
|
|
6740
|
+
import process12 from "process";
|
|
6433
6741
|
var writeJson4 = (value) => {
|
|
6434
|
-
|
|
6742
|
+
process12.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
6435
6743
|
`);
|
|
6436
6744
|
};
|
|
6437
6745
|
var exitWithError3 = (error) => {
|
|
6438
6746
|
const message = error instanceof Error ? error.message : String(error);
|
|
6439
6747
|
log.error(message);
|
|
6440
|
-
|
|
6748
|
+
process12.exit(1);
|
|
6441
6749
|
};
|
|
6442
6750
|
var fail2 = (message) => {
|
|
6443
6751
|
throw new Error(message);
|
|
@@ -6536,9 +6844,9 @@ async function profilesSetDefaultCommand(options) {
|
|
|
6536
6844
|
init_esm_shims();
|
|
6537
6845
|
init_api();
|
|
6538
6846
|
init_tui();
|
|
6539
|
-
import
|
|
6847
|
+
import process13 from "process";
|
|
6540
6848
|
var writeJson5 = (value) => {
|
|
6541
|
-
|
|
6849
|
+
process13.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
6542
6850
|
`);
|
|
6543
6851
|
};
|
|
6544
6852
|
var fail3 = (message) => {
|
|
@@ -6566,7 +6874,7 @@ var run3 = async (command, args, options) => {
|
|
|
6566
6874
|
var exitWithError4 = (error) => {
|
|
6567
6875
|
const message = error instanceof Error ? error.message : String(error);
|
|
6568
6876
|
log.error(message);
|
|
6569
|
-
|
|
6877
|
+
process13.exit(1);
|
|
6570
6878
|
};
|
|
6571
6879
|
async function projectsGetCommand(options) {
|
|
6572
6880
|
try {
|
|
@@ -6620,9 +6928,9 @@ async function projectsRemoveCommand(options) {
|
|
|
6620
6928
|
init_esm_shims();
|
|
6621
6929
|
init_api();
|
|
6622
6930
|
init_tui();
|
|
6623
|
-
import
|
|
6931
|
+
import process14 from "process";
|
|
6624
6932
|
var writeJson6 = (value) => {
|
|
6625
|
-
|
|
6933
|
+
process14.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
6626
6934
|
`);
|
|
6627
6935
|
};
|
|
6628
6936
|
var parseCsv3 = (input) => {
|
|
@@ -6635,7 +6943,7 @@ var parseCsv3 = (input) => {
|
|
|
6635
6943
|
var exitWithError5 = (error) => {
|
|
6636
6944
|
const message = error instanceof Error ? error.message : String(error);
|
|
6637
6945
|
log.error(message);
|
|
6638
|
-
|
|
6946
|
+
process14.exit(1);
|
|
6639
6947
|
};
|
|
6640
6948
|
var fail4 = (message) => {
|
|
6641
6949
|
throw new Error(message);
|
|
@@ -6722,9 +7030,9 @@ async function referencesReorderCommand(options) {
|
|
|
6722
7030
|
|
|
6723
7031
|
// src/commands/remove.ts
|
|
6724
7032
|
init_esm_shims();
|
|
6725
|
-
import { rm as
|
|
6726
|
-
import { join as
|
|
6727
|
-
import
|
|
7033
|
+
import { rm as rm7 } from "fs/promises";
|
|
7034
|
+
import { join as join14, resolve as resolve8 } from "path";
|
|
7035
|
+
import process15 from "process";
|
|
6728
7036
|
init_tui();
|
|
6729
7037
|
async function collectInstalledSkills(detectedAgents, options) {
|
|
6730
7038
|
const skillsToRemove = [];
|
|
@@ -6745,7 +7053,7 @@ async function collectInstalledSkills(detectedAgents, options) {
|
|
|
6745
7053
|
name: skill.name,
|
|
6746
7054
|
agentName: agent.name,
|
|
6747
7055
|
installPath,
|
|
6748
|
-
skillPath:
|
|
7056
|
+
skillPath: join14(installPath, skill.name)
|
|
6749
7057
|
});
|
|
6750
7058
|
}
|
|
6751
7059
|
}
|
|
@@ -6757,7 +7065,7 @@ async function selectSkillsToRemove(skillsToRemove, options) {
|
|
|
6757
7065
|
if (selected.length === 0) {
|
|
6758
7066
|
log.error(`Skill '${options.skill}' not found.`);
|
|
6759
7067
|
log.info("Run 'braid list' to see installed skills.");
|
|
6760
|
-
|
|
7068
|
+
process15.exit(1);
|
|
6761
7069
|
}
|
|
6762
7070
|
return selected;
|
|
6763
7071
|
}
|
|
@@ -6776,7 +7084,7 @@ async function selectSkillsToRemove(skillsToRemove, options) {
|
|
|
6776
7084
|
});
|
|
6777
7085
|
if (isCancel(result)) {
|
|
6778
7086
|
cancel("Remove cancelled.");
|
|
6779
|
-
|
|
7087
|
+
process15.exit(0);
|
|
6780
7088
|
}
|
|
6781
7089
|
return result;
|
|
6782
7090
|
}
|
|
@@ -6790,20 +7098,20 @@ async function confirmRemoval(selectedCount, options) {
|
|
|
6790
7098
|
});
|
|
6791
7099
|
if (isCancel(confirmed) || !confirmed) {
|
|
6792
7100
|
cancel("Remove cancelled.");
|
|
6793
|
-
|
|
7101
|
+
process15.exit(0);
|
|
6794
7102
|
}
|
|
6795
7103
|
}
|
|
6796
7104
|
async function removeSkill(skill, removeSpinner) {
|
|
6797
7105
|
removeSpinner.start(`Removing ${skill.name} from ${skill.agentName}...`);
|
|
6798
7106
|
try {
|
|
6799
|
-
const resolvedSkillPath =
|
|
6800
|
-
const resolvedInstallPath =
|
|
7107
|
+
const resolvedSkillPath = resolve8(skill.skillPath);
|
|
7108
|
+
const resolvedInstallPath = resolve8(skill.installPath);
|
|
6801
7109
|
if (!resolvedSkillPath.startsWith(`${resolvedInstallPath}/`)) {
|
|
6802
7110
|
removeSpinner.stop(`Unsafe path for ${skill.name}`);
|
|
6803
7111
|
log.warn(" Skill path escapes install directory, skipping.");
|
|
6804
7112
|
return false;
|
|
6805
7113
|
}
|
|
6806
|
-
await
|
|
7114
|
+
await rm7(resolvedSkillPath, { recursive: true, force: true });
|
|
6807
7115
|
await removeFromMetadataAsync(skill.installPath, skill.name);
|
|
6808
7116
|
removeSpinner.stop(`Removed ${skill.name} from ${skill.agentName}`);
|
|
6809
7117
|
return true;
|
|
@@ -6854,7 +7162,7 @@ async function removeCommand(options) {
|
|
|
6854
7162
|
removeSpinner.stop("Remove failed");
|
|
6855
7163
|
const message = error instanceof Error ? error.message : String(error);
|
|
6856
7164
|
log.error(message);
|
|
6857
|
-
|
|
7165
|
+
process15.exit(1);
|
|
6858
7166
|
}
|
|
6859
7167
|
}
|
|
6860
7168
|
|
|
@@ -7052,7 +7360,7 @@ async function rollbackCommand(source, options) {
|
|
|
7052
7360
|
init_esm_shims();
|
|
7053
7361
|
init_api();
|
|
7054
7362
|
init_tui();
|
|
7055
|
-
import
|
|
7363
|
+
import process16 from "process";
|
|
7056
7364
|
var parseCsv4 = (input) => {
|
|
7057
7365
|
if (!input) {
|
|
7058
7366
|
return void 0;
|
|
@@ -7061,13 +7369,13 @@ var parseCsv4 = (input) => {
|
|
|
7061
7369
|
return values.length > 0 ? values : void 0;
|
|
7062
7370
|
};
|
|
7063
7371
|
var writeJson7 = (value) => {
|
|
7064
|
-
|
|
7372
|
+
process16.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
7065
7373
|
`);
|
|
7066
7374
|
};
|
|
7067
7375
|
var exitWithError6 = (error) => {
|
|
7068
7376
|
const message = error instanceof Error ? error.message : String(error);
|
|
7069
7377
|
log.error(message);
|
|
7070
|
-
|
|
7378
|
+
process16.exit(1);
|
|
7071
7379
|
};
|
|
7072
7380
|
var fail5 = (message) => {
|
|
7073
7381
|
throw new Error(message);
|
|
@@ -7246,7 +7554,7 @@ async function rulesSyncNowCommand(options) {
|
|
|
7246
7554
|
|
|
7247
7555
|
// src/commands/scaffold.ts
|
|
7248
7556
|
init_esm_shims();
|
|
7249
|
-
import
|
|
7557
|
+
import process17 from "process";
|
|
7250
7558
|
|
|
7251
7559
|
// src/lib/scaffold.ts
|
|
7252
7560
|
init_esm_shims();
|
|
@@ -7256,11 +7564,11 @@ import {
|
|
|
7256
7564
|
mkdir as mkdir7,
|
|
7257
7565
|
readdir as readdir3,
|
|
7258
7566
|
readFile as readFile8,
|
|
7259
|
-
rm as
|
|
7567
|
+
rm as rm8,
|
|
7260
7568
|
stat,
|
|
7261
7569
|
writeFile as writeFile9
|
|
7262
7570
|
} from "fs/promises";
|
|
7263
|
-
import { dirname as
|
|
7571
|
+
import { dirname as dirname12, join as join15 } from "path";
|
|
7264
7572
|
var BRAID_PACK_FILENAME = "braid-pack.json";
|
|
7265
7573
|
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
7266
7574
|
var MAX_DURATION_MS = 18e5;
|
|
@@ -7392,7 +7700,7 @@ var directoryContainsMatchingFile = async (absoluteDirectoryPath, matcher) => {
|
|
|
7392
7700
|
);
|
|
7393
7701
|
}
|
|
7394
7702
|
for (const entry of entries) {
|
|
7395
|
-
const absoluteEntryPath =
|
|
7703
|
+
const absoluteEntryPath = join15(absoluteDirectoryPath, entry.name);
|
|
7396
7704
|
if (entry.isDirectory()) {
|
|
7397
7705
|
if (await directoryContainsMatchingFile(absoluteEntryPath, matcher)) {
|
|
7398
7706
|
return true;
|
|
@@ -7448,19 +7756,19 @@ var directoryContainsHookArtifact = async (absoluteDirectoryPath) => directoryCo
|
|
|
7448
7756
|
}
|
|
7449
7757
|
);
|
|
7450
7758
|
var hasUnmanifestedPackContent = async (cwd) => {
|
|
7451
|
-
if (await manifestExists(
|
|
7759
|
+
if (await manifestExists(join15(cwd, "SKILL.md"))) {
|
|
7452
7760
|
return true;
|
|
7453
7761
|
}
|
|
7454
|
-
if (await directoryContainsSkillArtifact(
|
|
7762
|
+
if (await directoryContainsSkillArtifact(join15(cwd, "skills"))) {
|
|
7455
7763
|
return true;
|
|
7456
7764
|
}
|
|
7457
|
-
if (await directoryContainsAgentArtifact(
|
|
7765
|
+
if (await directoryContainsAgentArtifact(join15(cwd, "agents"))) {
|
|
7458
7766
|
return true;
|
|
7459
7767
|
}
|
|
7460
|
-
if (await directoryContainsHookArtifact(
|
|
7768
|
+
if (await directoryContainsHookArtifact(join15(cwd, "hooks"))) {
|
|
7461
7769
|
return true;
|
|
7462
7770
|
}
|
|
7463
|
-
return directoryContainsWorkflowArtifact(
|
|
7771
|
+
return directoryContainsWorkflowArtifact(join15(cwd, "workflows"));
|
|
7464
7772
|
};
|
|
7465
7773
|
var parseManifestEntries = (manifest, key, parser) => {
|
|
7466
7774
|
const value = manifest[key];
|
|
@@ -7986,7 +8294,7 @@ var writeTextFile3 = async (absolutePath, relativePath, content) => {
|
|
|
7986
8294
|
var restoreManifest = async (absoluteManifestPath, previousContent) => {
|
|
7987
8295
|
try {
|
|
7988
8296
|
if (previousContent === void 0) {
|
|
7989
|
-
await
|
|
8297
|
+
await rm8(absoluteManifestPath, { force: true });
|
|
7990
8298
|
return;
|
|
7991
8299
|
}
|
|
7992
8300
|
await writeFile9(absoluteManifestPath, previousContent, "utf-8");
|
|
@@ -8010,8 +8318,8 @@ var prepareScaffoldOperation = async (normalizedInput) => {
|
|
|
8010
8318
|
normalizedInput.type,
|
|
8011
8319
|
normalizedInput.name
|
|
8012
8320
|
);
|
|
8013
|
-
const absoluteManifestPath =
|
|
8014
|
-
const absoluteArtifactPath =
|
|
8321
|
+
const absoluteManifestPath = join15(normalizedInput.cwd, BRAID_PACK_FILENAME);
|
|
8322
|
+
const absoluteArtifactPath = join15(normalizedInput.cwd, filePath);
|
|
8015
8323
|
const manifestKey = MANIFEST_KEY_BY_TYPE[normalizedInput.type];
|
|
8016
8324
|
const previousManifestContent = context.state === "manifest-pack" ? await readManifestFile(absoluteManifestPath) : void 0;
|
|
8017
8325
|
const existingEntry = context.manifest[manifestKey].find(
|
|
@@ -8063,7 +8371,7 @@ var writeArtifactWithRollback = async ({
|
|
|
8063
8371
|
previousManifestContent
|
|
8064
8372
|
}) => {
|
|
8065
8373
|
try {
|
|
8066
|
-
await mkdir7(
|
|
8374
|
+
await mkdir7(dirname12(absoluteArtifactPath), { recursive: true });
|
|
8067
8375
|
await writeTextFile3(absoluteArtifactPath, filePath, artifactContent);
|
|
8068
8376
|
} catch (error) {
|
|
8069
8377
|
const artifactError = error instanceof ScaffoldError ? error : toIoError(filePath, error);
|
|
@@ -8090,10 +8398,10 @@ var ScaffoldError = class extends Error {
|
|
|
8090
8398
|
}
|
|
8091
8399
|
};
|
|
8092
8400
|
var inspectScaffoldDirectory = async (cwd) => {
|
|
8093
|
-
const manifestPath =
|
|
8401
|
+
const manifestPath = join15(cwd, BRAID_PACK_FILENAME);
|
|
8094
8402
|
const hasManifest = await manifestExists(manifestPath);
|
|
8095
8403
|
if (!hasManifest) {
|
|
8096
|
-
if (await manifestExists(
|
|
8404
|
+
if (await manifestExists(join15(cwd, "SKILL.md"))) {
|
|
8097
8405
|
throw new ScaffoldError(
|
|
8098
8406
|
"invalid_repo_state",
|
|
8099
8407
|
"Invalid repo state: root SKILL.md requires migration to braid-pack.json before scaffolding."
|
|
@@ -8206,11 +8514,11 @@ var normalizeReferenceList = (referenceLabel, availableNamesLabel, values, avail
|
|
|
8206
8514
|
};
|
|
8207
8515
|
var exitCancelled2 = () => {
|
|
8208
8516
|
cancel("Scaffold cancelled.");
|
|
8209
|
-
|
|
8517
|
+
process17.exit(0);
|
|
8210
8518
|
};
|
|
8211
8519
|
var exitWithError7 = (message) => {
|
|
8212
8520
|
log.error(message);
|
|
8213
|
-
|
|
8521
|
+
process17.exit(1);
|
|
8214
8522
|
};
|
|
8215
8523
|
var requirePromptValue = (value) => {
|
|
8216
8524
|
if (isCancel(value)) {
|
|
@@ -8339,7 +8647,7 @@ var resolveOptionalReference = async (label, flagValue, options, availableNames)
|
|
|
8339
8647
|
return selected || void 0;
|
|
8340
8648
|
};
|
|
8341
8649
|
var buildScaffoldInput = async (options) => {
|
|
8342
|
-
const context = await inspectScaffoldDirectory(
|
|
8650
|
+
const context = await inspectScaffoldDirectory(process17.cwd());
|
|
8343
8651
|
const availableSkillNames = context.manifest.skills.map(
|
|
8344
8652
|
(entry) => entry.name
|
|
8345
8653
|
);
|
|
@@ -8393,7 +8701,7 @@ var buildScaffoldInput = async (options) => {
|
|
|
8393
8701
|
availableWorkflowNames
|
|
8394
8702
|
) : void 0;
|
|
8395
8703
|
return {
|
|
8396
|
-
cwd:
|
|
8704
|
+
cwd: process17.cwd(),
|
|
8397
8705
|
type,
|
|
8398
8706
|
name,
|
|
8399
8707
|
title,
|
|
@@ -8485,8 +8793,8 @@ init_scope();
|
|
|
8485
8793
|
|
|
8486
8794
|
// src/commands/update.ts
|
|
8487
8795
|
init_esm_shims();
|
|
8488
|
-
import { rm as
|
|
8489
|
-
import { join as
|
|
8796
|
+
import { rm as rm9 } from "fs/promises";
|
|
8797
|
+
import { join as join16, resolve as resolve9 } from "path";
|
|
8490
8798
|
import {
|
|
8491
8799
|
cancel as cancel2,
|
|
8492
8800
|
isCancel as isCancel2,
|
|
@@ -8631,12 +8939,12 @@ var areSameSourceProjects = (left, right) => {
|
|
|
8631
8939
|
};
|
|
8632
8940
|
var isSameInstalledSource = (source, target) => source.type === target.type && source.name === target.name && areSameSourceProjects(source.orgProjects, target.orgProjects) && areSameSourceProjects(source.personalProjects, target.personalProjects);
|
|
8633
8941
|
var removeInstalledBundle = async (installPath, bundleName) => {
|
|
8634
|
-
const resolvedInstallPath =
|
|
8635
|
-
const resolvedBundlePath =
|
|
8942
|
+
const resolvedInstallPath = resolve9(installPath);
|
|
8943
|
+
const resolvedBundlePath = resolve9(join16(installPath, bundleName));
|
|
8636
8944
|
if (!resolvedBundlePath.startsWith(`${resolvedInstallPath}/`)) {
|
|
8637
8945
|
throw new Error(`Unsafe bundle path for ${bundleName}`);
|
|
8638
8946
|
}
|
|
8639
|
-
await
|
|
8947
|
+
await rm9(resolvedBundlePath, { recursive: true, force: true });
|
|
8640
8948
|
const disabledRecord = await findDisabledBundleByOriginalPathAsync(
|
|
8641
8949
|
resolvedBundlePath,
|
|
8642
8950
|
{
|
|
@@ -8875,10 +9183,16 @@ async function updateCommand(options) {
|
|
|
8875
9183
|
}
|
|
8876
9184
|
|
|
8877
9185
|
// src/index.ts
|
|
9186
|
+
init_tui();
|
|
8878
9187
|
var require2 = createRequire(import.meta.url);
|
|
8879
9188
|
var { version: PACKAGE_VERSION } = require2("../package.json");
|
|
9189
|
+
var COMMANDER_ERROR_PREFIX = /^error:\s*/i;
|
|
8880
9190
|
var program = new Command();
|
|
8881
|
-
program.name("braid").description("Install and manage braid prompt artifacts locally").version(PACKAGE_VERSION)
|
|
9191
|
+
program.name("braid").description("Install and manage braid prompt artifacts locally").version(PACKAGE_VERSION).configureOutput({
|
|
9192
|
+
outputError: (str) => {
|
|
9193
|
+
log.error(str.replace(COMMANDER_ERROR_PREFIX, "").trim());
|
|
9194
|
+
}
|
|
9195
|
+
});
|
|
8882
9196
|
var auth = program.command("auth").description("Configure API key for braid authentication");
|
|
8883
9197
|
auth.command("login", { isDefault: true }).description("Authenticate with braid via browser login or API key").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option(
|
|
8884
9198
|
"--token <token>",
|
|
@@ -8954,6 +9268,11 @@ marketplace.command("install").description("Install a marketplace pack by slug")
|
|
|
8954
9268
|
"--allow-hooks",
|
|
8955
9269
|
"Allow marketplace packs to install executable Claude Code hooks"
|
|
8956
9270
|
).option("-y, --yes", "Skip confirmation prompts").action((slug, options) => marketplaceInstallCommand(slug, options));
|
|
9271
|
+
marketplace.command("update").description("Update installed marketplace packs to their latest version").argument("[slug]", "Pack slug (updates all if omitted)").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("-g, --global", "Update packs in global agent directories").option(
|
|
9272
|
+
"--allow-hooks",
|
|
9273
|
+
"Allow marketplace packs to install executable Claude Code hooks"
|
|
9274
|
+
).option("-y, --yes", "Skip confirmation prompts").action((slug, options) => marketplaceUpdateCommand(slug, options));
|
|
9275
|
+
marketplace.command("remove").description("Remove installed marketplace packs").argument("[slug]", "Pack slug (prompts for selection if omitted)").option("-g, --global", "Remove from global agent directories").option("-y, --yes", "Skip confirmation prompts").action((slug, options) => marketplaceRemoveCommand(slug, options));
|
|
8957
9276
|
var projects = program.command("projects").description("Discover available projects from braid");
|
|
8958
9277
|
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);
|
|
8959
9278
|
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);
|